chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (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 / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (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 / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user