Files
WeHub Mirror 6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
WeHub snapshot of cb28d14c6f2c081de7a0d8729a8c816c9adef67a
2026-08-10 11:17:50 +08:00

204 lines
6.2 KiB
TypeScript

import {
materializeLargeValueRefSync,
materializeLargeValueRefSyncOrThrow,
} from '@/lib/execution/payloads/cache'
import {
isLargeArrayManifest,
type LargeArrayManifest,
} from '@/lib/execution/payloads/large-array-manifest-metadata'
import { assertNoLargeValueRefs, isLargeValueRef } from '@/lib/execution/payloads/large-value-ref'
import type { ExecutionState, LoopScope } from '@/executor/execution/state'
import type { ExecutionContext } from '@/executor/types'
export interface PathNavigationExecutionContext {
workflowId: string
workspaceId?: string
executionId?: string
largeValueExecutionIds?: string[]
largeValueKeys?: string[]
fileKeys?: string[]
allowLargeValueWorkflowScope?: boolean
userId?: string
metadata?: { requestId?: string }
base64MaxBytes?: number
}
export interface PathNavigationContext {
executionContext: PathNavigationExecutionContext
allowLargeValueRefs?: boolean
}
export interface ResolutionContext {
executionContext: ExecutionContext
executionState: ExecutionState
currentNodeId: string
loopScope?: LoopScope
allowLargeValueRefs?: boolean
inputPath?: readonly string[]
onResolvedSecretReference?: () => void
}
export interface Resolver {
canResolve(reference: string): boolean
resolve(reference: string, context: ResolutionContext): any
resolveAsync?(reference: string, context: ResolutionContext): Promise<any>
}
export type AsyncPathNavigator = (
obj: any,
path: string[],
context: PathNavigationContext
) => Promise<any>
/**
* Sentinel value indicating a reference was resolved to a known block
* that produced no output (e.g., the block exists in the workflow but
* didn't execute on this path). Distinct from `undefined`, which means
* the reference couldn't be matched to any block at all.
*/
export const RESOLVED_EMPTY = Symbol('RESOLVED_EMPTY')
export function splitLeadingBracketPath(part: string): { property: string; pathParts: string[] } {
const bracketMatch = part.match(/^([^[]+)((?:\[\d+\])+)$/)
if (!bracketMatch) {
return { property: part, pathParts: [] }
}
const indices = bracketMatch[2].match(/\[(\d+)\]/g) ?? []
return {
property: bracketMatch[1],
pathParts: indices.map((indexMatch) => indexMatch.slice(1, -1)),
}
}
function readManifestIndexSync(
manifest: LargeArrayManifest,
index: number,
executionContext?: ExecutionContext
): unknown {
if (!Number.isInteger(index) || index < 0 || index >= manifest.totalCount) {
return undefined
}
let offset = 0
for (const chunk of manifest.chunks) {
const nextOffset = offset + chunk.count
if (index < nextOffset) {
const materialized = materializeLargeValueRefSync(chunk.ref, executionContext)
if (materialized === undefined) {
return undefined
}
if (!Array.isArray(materialized)) {
throw new Error('Large array manifest chunk must materialize to an array.')
}
if (materialized.length !== chunk.count) {
throw new Error('Large array manifest chunk count does not match materialized data.')
}
return materialized[index - offset]
}
offset = nextOffset
}
return undefined
}
function navigateManifestMetadataOrIndexSync(
manifest: LargeArrayManifest,
part: string,
executionContext?: ExecutionContext
): unknown {
if (part === 'length' || part === 'totalCount') {
return manifest.totalCount
}
if (part === 'chunkCount' || part === 'byteSize' || part === 'preview') {
return manifest[part]
}
if (/^\d+$/.test(part)) {
return readManifestIndexSync(manifest, Number.parseInt(part, 10), executionContext)
}
return undefined
}
/**
* Navigate through nested object properties using a path array.
* Supports dot notation and array indices.
*
* @example
* navigatePath({a: {b: {c: 1}}}, ['a', 'b', 'c']) => 1
* navigatePath({items: [{name: 'test'}]}, ['items', '0', 'name']) => 'test'
*/
export function navigatePath(
obj: any,
path: string[],
options: { allowLargeValueRefs?: boolean; executionContext?: ExecutionContext } = {}
): any {
let current = obj
for (const part of path) {
if (isLargeValueRef(current)) {
current = materializeLargeValueRefSyncOrThrow(current, options.executionContext)
}
if (current === null || current === undefined) {
return undefined
}
if (isLargeArrayManifest(current)) {
current = navigateManifestMetadataOrIndexSync(current, part, options.executionContext)
continue
}
const arrayMatch = part.match(/^([^[]+)(\[.+)$/)
if (arrayMatch) {
const [, prop, bracketsPart] = arrayMatch
current =
typeof current === 'object' && current !== null
? (current as Record<string, unknown>)[prop]
: undefined
if (isLargeValueRef(current)) {
current = materializeLargeValueRefSyncOrThrow(current, options.executionContext)
}
if (current === undefined || current === null) {
return undefined
}
const indices = bracketsPart.match(/\[(\d+)\]/g)
if (indices) {
for (const indexMatch of indices) {
if (current === null || current === undefined) {
return undefined
}
if (isLargeValueRef(current)) {
current = materializeLargeValueRefSyncOrThrow(current, options.executionContext)
}
if (isLargeArrayManifest(current)) {
current = navigateManifestMetadataOrIndexSync(
current,
indexMatch.slice(1, -1),
options.executionContext
)
continue
}
const idx = Number.parseInt(indexMatch.slice(1, -1), 10)
current = Array.isArray(current) ? current[idx] : undefined
}
}
} else if (/^\d+$/.test(part)) {
const index = Number.parseInt(part, 10)
current = isLargeArrayManifest(current)
? readManifestIndexSync(current, index, options.executionContext)
: Array.isArray(current)
? current[index]
: undefined
} else {
current =
typeof current === 'object' && current !== null
? (current as Record<string, unknown>)[part]
: undefined
}
}
if (!options.allowLargeValueRefs) {
assertNoLargeValueRefs(current)
}
return current
}