deepline 0.3.228 → 0.3.230
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +18 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/contracts.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/sheet-column-storage.ts +252 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/sheet-contract.ts +29 -8
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +19 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +297 -69
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +38 -2
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +8 -3
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +39 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +293 -4
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +29 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +56 -11
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/progress-sidecar.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +380 -183
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +187 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-work-counters.ts +52 -2
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +30 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +118 -6
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +135 -21
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -0
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +16 -2
- package/dist/bundling-sources/shared_libs/plays/execution-pipeline.ts +72 -0
- package/dist/bundling-sources/shared_libs/plays/launch/prepare.ts +1 -3
- package/dist/bundling-sources/shared_libs/plays/sheet-filter.ts +9 -13
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +28 -31
- package/dist/cli/index.js +102 -2
- package/dist/cli/index.mjs +102 -2
- package/dist/{compiler-manifest-Dpd2hEet.d.mts → compiler-manifest-n8ZtPv2h.d.mts} +31 -21
- package/dist/{compiler-manifest-Dpd2hEet.d.ts → compiler-manifest-n8ZtPv2h.d.ts} +31 -21
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +98 -2
- package/dist/index.mjs +98 -2
- package/dist/install-integrity.json +4 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -79,12 +79,17 @@ import {
|
|
|
79
79
|
import type { PlayStaticPipeline } from '../../plays/static-pipeline';
|
|
80
80
|
import {
|
|
81
81
|
LOG_TAIL_LIMIT,
|
|
82
|
+
normalizePlayRunLedgerTerminalWorkCounterSegment,
|
|
82
83
|
type AcceptedPlayRunLedgerEvent,
|
|
83
84
|
type PlayRunLedgerEvent,
|
|
84
85
|
type PlayRunLedgerIngressEvent,
|
|
86
|
+
type PlayRunLedgerTerminalWorkCounterSegment,
|
|
85
87
|
} from '../run-ledger';
|
|
86
88
|
import { stableStringify } from '../../plays/row-identity';
|
|
87
|
-
import {
|
|
89
|
+
import {
|
|
90
|
+
runtimeWorkCountersFromResources,
|
|
91
|
+
runtimeWorkCountersFromStats,
|
|
92
|
+
} from '../runtime-work-counters';
|
|
88
93
|
import {
|
|
89
94
|
isCtxFetchHttpFailureDiagnostic,
|
|
90
95
|
parseCtxFetchHttpFailureDiagnostic,
|
|
@@ -9456,6 +9461,28 @@ export type PostgresSchedulerDirectRunnerTerminalOutcome =
|
|
|
9456
9461
|
| 'wake_required'
|
|
9457
9462
|
| 'not_found';
|
|
9458
9463
|
|
|
9464
|
+
function terminalWorkCounterSegmentFromRunnerResult(
|
|
9465
|
+
result: unknown,
|
|
9466
|
+
attempt: number,
|
|
9467
|
+
): PlayRunLedgerTerminalWorkCounterSegment | undefined {
|
|
9468
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) {
|
|
9469
|
+
return undefined;
|
|
9470
|
+
}
|
|
9471
|
+
const stats = (result as { stats?: unknown }).stats;
|
|
9472
|
+
if (!stats || typeof stats !== 'object' || Array.isArray(stats)) {
|
|
9473
|
+
return undefined;
|
|
9474
|
+
}
|
|
9475
|
+
const segment = (stats as { runtimeWorkCounterSegment?: unknown })
|
|
9476
|
+
.runtimeWorkCounterSegment;
|
|
9477
|
+
if (!segment || typeof segment !== 'object' || Array.isArray(segment)) {
|
|
9478
|
+
return undefined;
|
|
9479
|
+
}
|
|
9480
|
+
return normalizePlayRunLedgerTerminalWorkCounterSegment({
|
|
9481
|
+
...segment,
|
|
9482
|
+
attempt,
|
|
9483
|
+
});
|
|
9484
|
+
}
|
|
9485
|
+
|
|
9459
9486
|
/**
|
|
9460
9487
|
* Reduce an ordinary detached-runner completion at terminal ingress.
|
|
9461
9488
|
*
|
|
@@ -9522,6 +9549,10 @@ export async function directCompletePostgresSchedulerRunnerTerminal(
|
|
|
9522
9549
|
input.terminalLogOutbox,
|
|
9523
9550
|
);
|
|
9524
9551
|
const runtimeTiming = extractRunnerRuntimeTiming(input.result);
|
|
9552
|
+
const terminalWorkCounterSegment = terminalWorkCounterSegmentFromRunnerResult(
|
|
9553
|
+
input.result,
|
|
9554
|
+
input.attempt,
|
|
9555
|
+
);
|
|
9525
9556
|
// `workCompletedAtMs` is useful lifecycle telemetry, but it comes from the
|
|
9526
9557
|
// sandbox process where play code can alter Date.now. Billing must stop on
|
|
9527
9558
|
// the first database receipt, whose clock and first-write semantics are
|
|
@@ -9767,7 +9798,8 @@ export async function directCompletePostgresSchedulerRunnerTerminal(
|
|
|
9767
9798
|
'output', $6::jsonb,
|
|
9768
9799
|
'terminalLogLines', $7::jsonb,
|
|
9769
9800
|
'terminalProgressEvents', $8::jsonb,
|
|
9770
|
-
'resultSummary', $16::jsonb
|
|
9801
|
+
'resultSummary', $16::jsonb,
|
|
9802
|
+
'terminalWorkCounterSegment', $17::jsonb
|
|
9771
9803
|
),
|
|
9772
9804
|
${causalOutboxCreatedAt('run_terminal.run_id', options)}
|
|
9773
9805
|
FROM run_terminal
|
|
@@ -9802,6 +9834,7 @@ export async function directCompletePostgresSchedulerRunnerTerminal(
|
|
|
9802
9834
|
input.engineWake.wakeChannel,
|
|
9803
9835
|
input.allowCappedCompletion === true,
|
|
9804
9836
|
stringifyPostgresJson(resultSummary),
|
|
9837
|
+
stringifyPostgresJson(terminalWorkCounterSegment ?? null),
|
|
9805
9838
|
],
|
|
9806
9839
|
);
|
|
9807
9840
|
if (completed.rows.length > 0) return 'completed';
|
|
@@ -11815,6 +11848,7 @@ export async function completePostgresSchedulerAttempt(
|
|
|
11815
11848
|
rowOutcomes?: unknown;
|
|
11816
11849
|
runtimeTiming?: PlayRunnerRuntimeTiming | null;
|
|
11817
11850
|
terminalLogLines?: readonly string[] | null;
|
|
11851
|
+
terminalWorkCounterSegment?: PlayRunLedgerTerminalWorkCounterSegment;
|
|
11818
11852
|
},
|
|
11819
11853
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
11820
11854
|
): Promise<boolean> {
|
|
@@ -12002,7 +12036,8 @@ export async function completePostgresSchedulerAttempt(
|
|
|
12002
12036
|
jsonb_build_object(
|
|
12003
12037
|
'output', $9::jsonb,
|
|
12004
12038
|
'terminalLogLines', $8::jsonb,
|
|
12005
|
-
'resultSummary', $10::jsonb
|
|
12039
|
+
'resultSummary', $10::jsonb,
|
|
12040
|
+
'terminalWorkCounterSegment', $11::jsonb
|
|
12006
12041
|
),
|
|
12007
12042
|
${causalOutboxCreatedAt('run_terminal.run_id', options)}
|
|
12008
12043
|
FROM run_terminal
|
|
@@ -12024,6 +12059,7 @@ export async function completePostgresSchedulerAttempt(
|
|
|
12024
12059
|
JSON.stringify(terminalLogLines),
|
|
12025
12060
|
stringifyPostgresJson(ledgerTerminalResult ?? null),
|
|
12026
12061
|
stringifyPostgresJson(resultSummary),
|
|
12062
|
+
stringifyPostgresJson(input.terminalWorkCounterSegment ?? null),
|
|
12027
12063
|
],
|
|
12028
12064
|
);
|
|
12029
12065
|
if (completed.rows.length === 0) {
|
|
@@ -12070,6 +12106,10 @@ export async function failPostgresSchedulerAttempt(
|
|
|
12070
12106
|
const resultSummary = terminalRowOutcomesSummary(
|
|
12071
12107
|
(input.result as { rowOutcomes?: unknown } | null)?.rowOutcomes,
|
|
12072
12108
|
);
|
|
12109
|
+
const terminalWorkCounterSegment = terminalWorkCounterSegmentFromRunnerResult(
|
|
12110
|
+
input.result,
|
|
12111
|
+
input.attempt,
|
|
12112
|
+
);
|
|
12073
12113
|
// Keep the recovery tail separate from result: large failures are represented
|
|
12074
12114
|
// by a result reference, but their customer guidance must still be logged.
|
|
12075
12115
|
const terminalLogLines = (input.terminalLogLines ?? [])
|
|
@@ -12311,7 +12351,8 @@ export async function failPostgresSchedulerAttempt(
|
|
|
12311
12351
|
'error', $4::jsonb ->> 'message',
|
|
12312
12352
|
'result', $8::jsonb,
|
|
12313
12353
|
'terminalLogLines', $12::jsonb,
|
|
12314
|
-
'resultSummary', $13::jsonb
|
|
12354
|
+
'resultSummary', $13::jsonb,
|
|
12355
|
+
'terminalWorkCounterSegment', $14::jsonb
|
|
12315
12356
|
),
|
|
12316
12357
|
${causalOutboxCreatedAt('run_terminal.run_id', options)}
|
|
12317
12358
|
FROM run_terminal
|
|
@@ -12336,6 +12377,7 @@ export async function failPostgresSchedulerAttempt(
|
|
|
12336
12377
|
input.preserveRunnerTerminal === true,
|
|
12337
12378
|
JSON.stringify(terminalLogLines),
|
|
12338
12379
|
stringifyPostgresJson(resultSummary),
|
|
12380
|
+
stringifyPostgresJson(terminalWorkCounterSegment ?? null),
|
|
12339
12381
|
],
|
|
12340
12382
|
);
|
|
12341
12383
|
return failed.rows.length > 0;
|
|
@@ -13111,10 +13153,11 @@ export function attachRunnerWorkProgressMetadata(
|
|
|
13111
13153
|
// Keep the two scalar counts when the detailed runtimeResources record
|
|
13112
13154
|
// exceeds its metadata budget. Compact status must not scan a call log to
|
|
13113
13155
|
// reconstruct physical work.
|
|
13114
|
-
const
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13156
|
+
const stats = (runnerResult as { stats?: { runtimeResources?: unknown } })
|
|
13157
|
+
.stats;
|
|
13158
|
+
const runtimeCounters =
|
|
13159
|
+
runtimeWorkCountersFromStats(stats) ??
|
|
13160
|
+
runtimeWorkCountersFromResources(stats?.runtimeResources);
|
|
13118
13161
|
const outputWarnings = Array.isArray(
|
|
13119
13162
|
(runnerResult as { outputWarnings?: unknown }).outputWarnings,
|
|
13120
13163
|
)
|
|
@@ -13294,6 +13337,10 @@ export async function executePostgresSchedulerClaim(
|
|
|
13294
13337
|
output: terminalOutput,
|
|
13295
13338
|
rowOutcomes: (output as { rowOutcomes?: unknown } | null)?.rowOutcomes,
|
|
13296
13339
|
runtimeTiming: extractRunnerRuntimeTiming(output),
|
|
13340
|
+
terminalWorkCounterSegment: terminalWorkCounterSegmentFromRunnerResult(
|
|
13341
|
+
output,
|
|
13342
|
+
claim.attempt,
|
|
13343
|
+
),
|
|
13297
13344
|
terminalLogLines: terminalLogLinesForOutbox(
|
|
13298
13345
|
output,
|
|
13299
13346
|
options.terminalLogOutbox,
|
|
@@ -16928,6 +16975,10 @@ export function buildRunLedgerEventsFromPostgresSchedulerOutbox(
|
|
|
16928
16975
|
];
|
|
16929
16976
|
}
|
|
16930
16977
|
if (event.eventType === 'run.completed') {
|
|
16978
|
+
const terminalWorkCounterSegment =
|
|
16979
|
+
normalizePlayRunLedgerTerminalWorkCounterSegment(
|
|
16980
|
+
payloadField(event.payload, 'terminalWorkCounterSegment'),
|
|
16981
|
+
);
|
|
16931
16982
|
const progressEvents = ledgerEventsPayloadField(
|
|
16932
16983
|
event.payload,
|
|
16933
16984
|
'terminalProgressEvents',
|
|
@@ -16953,6 +17004,7 @@ export function buildRunLedgerEventsFromPostgresSchedulerOutbox(
|
|
|
16953
17004
|
runId: event.runId,
|
|
16954
17005
|
occurredAt,
|
|
16955
17006
|
source: 'system',
|
|
17007
|
+
...(terminalWorkCounterSegment ? { terminalWorkCounterSegment } : {}),
|
|
16956
17008
|
result: terminalRunResultForLedger(
|
|
16957
17009
|
payloadField(event.payload, 'output'),
|
|
16958
17010
|
),
|
|
@@ -16963,6 +17015,10 @@ export function buildRunLedgerEventsFromPostgresSchedulerOutbox(
|
|
|
16963
17015
|
];
|
|
16964
17016
|
}
|
|
16965
17017
|
if (event.eventType === 'run.failed') {
|
|
17018
|
+
const terminalWorkCounterSegment =
|
|
17019
|
+
normalizePlayRunLedgerTerminalWorkCounterSegment(
|
|
17020
|
+
payloadField(event.payload, 'terminalWorkCounterSegment'),
|
|
17021
|
+
);
|
|
16966
17022
|
const progressEvents = ledgerEventsPayloadField(
|
|
16967
17023
|
event.payload,
|
|
16968
17024
|
'terminalProgressEvents',
|
|
@@ -16991,6 +17047,7 @@ export function buildRunLedgerEventsFromPostgresSchedulerOutbox(
|
|
|
16991
17047
|
runId: event.runId,
|
|
16992
17048
|
occurredAt,
|
|
16993
17049
|
source: 'system',
|
|
17050
|
+
...(terminalWorkCounterSegment ? { terminalWorkCounterSegment } : {}),
|
|
16994
17051
|
error: stringPayloadField(event.payload, 'error'),
|
|
16995
17052
|
...(result === null || result === undefined ? {} : { result }),
|
|
16996
17053
|
...(resultSummary === undefined || resultSummary === null
|
|
@@ -17210,17 +17267,18 @@ export async function listPostgresSchedulerOutboxMaterializationPlans(
|
|
|
17210
17267
|
}
|
|
17211
17268
|
|
|
17212
17269
|
/**
|
|
17213
|
-
* Where the projector gets its runtime-API executor token
|
|
17214
|
-
* supplied per-event via `runtimeApi`.
|
|
17270
|
+
* Where the projector gets its runtime-API executor token.
|
|
17215
17271
|
*
|
|
17216
17272
|
* - `local_mint`: sign the token in-process with `BETTER_AUTH_SECRET`. ONLY the
|
|
17217
17273
|
* app (Vercel) legitimately holds the signing key, so this is app-side only
|
|
17218
17274
|
* (read-model heal path). It is the AUTHORITATIVE projector.
|
|
17219
|
-
* - `gateway`: prove the active outbox lease to the launch-pinned
|
|
17220
|
-
* receive a short-lived executor JWT
|
|
17221
|
-
*
|
|
17222
|
-
*
|
|
17223
|
-
*
|
|
17275
|
+
* - `gateway`: always prove the active outbox lease to the launch-pinned
|
|
17276
|
+
* deployment and receive a short-lived executor JWT
|
|
17277
|
+
* (`requestRunLedgerDispatchToken`), even if the caller supplied a
|
|
17278
|
+
* `runtimeApi`. The Fly worker has no signing key and MUST use this. A
|
|
17279
|
+
* supplied context contributes transport options only; its executor token
|
|
17280
|
+
* cannot bypass the lease-scoped gateway hop. Delivery failures use the same
|
|
17281
|
+
* structured retry-or-block policy as the app-side projector.
|
|
17224
17282
|
*
|
|
17225
17283
|
* Explicit by design: the old code sniffed `process.env.BETTER_AUTH_SECRET` to
|
|
17226
17284
|
* pick the branch, so the worker's projection silently depended on the secret
|
|
@@ -17262,15 +17320,20 @@ export function postgresSchedulerCancellationOutboxLease(runId: string): {
|
|
|
17262
17320
|
}
|
|
17263
17321
|
|
|
17264
17322
|
export type RunLedgerOutboxDispatchInput = {
|
|
17323
|
+
/**
|
|
17324
|
+
* Optional runtime context. `gateway` authority always replaces its
|
|
17325
|
+
* credentials with a fresh lease-scoped token and keeps only supported
|
|
17326
|
+
* transport options; `local_mint` and the default authority preserve the
|
|
17327
|
+
* explicit context as before.
|
|
17328
|
+
*/
|
|
17265
17329
|
runtimeApi?: WorkerRuntimeApiContext | null;
|
|
17266
17330
|
limit?: number;
|
|
17267
17331
|
runId?: string | null;
|
|
17268
17332
|
leaseOwner?: string | null;
|
|
17269
17333
|
leaseSeconds?: number;
|
|
17270
17334
|
/**
|
|
17271
|
-
* Token authority for
|
|
17272
|
-
*
|
|
17273
|
-
* pass `gateway`.
|
|
17335
|
+
* Token authority for the outbox dispatch. Defaults to `local_mint` for the
|
|
17336
|
+
* app-side authoritative projector. The Fly worker MUST pass `gateway`.
|
|
17274
17337
|
*/
|
|
17275
17338
|
tokenAuthority?: RunLedgerOutboxTokenAuthority;
|
|
17276
17339
|
};
|
|
@@ -17568,7 +17631,24 @@ export async function dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope(
|
|
|
17568
17631
|
|
|
17569
17632
|
try {
|
|
17570
17633
|
const first = events[0]!;
|
|
17634
|
+
const tokenAuthority = input.tokenAuthority ?? 'local_mint';
|
|
17635
|
+
const gatewayRuntimeApi =
|
|
17636
|
+
tokenAuthority === 'gateway'
|
|
17637
|
+
? await withClient((client) =>
|
|
17638
|
+
loadPostgresSchedulerRuntimeApiForRun(
|
|
17639
|
+
client,
|
|
17640
|
+
first.runId,
|
|
17641
|
+
first.leaseOwner
|
|
17642
|
+
? { eventId: first.eventId, leaseOwner: first.leaseOwner }
|
|
17643
|
+
: null,
|
|
17644
|
+
tokenAuthority,
|
|
17645
|
+
options,
|
|
17646
|
+
input.runtimeApi?.signal,
|
|
17647
|
+
),
|
|
17648
|
+
)
|
|
17649
|
+
: null;
|
|
17571
17650
|
const resolvedRuntimeApi =
|
|
17651
|
+
gatewayRuntimeApi ??
|
|
17572
17652
|
input.runtimeApi ??
|
|
17573
17653
|
(await withClient((client) =>
|
|
17574
17654
|
loadPostgresSchedulerRuntimeApiForRun(
|
|
@@ -17577,11 +17657,36 @@ export async function dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope(
|
|
|
17577
17657
|
first.leaseOwner
|
|
17578
17658
|
? { eventId: first.eventId, leaseOwner: first.leaseOwner }
|
|
17579
17659
|
: null,
|
|
17580
|
-
|
|
17660
|
+
tokenAuthority,
|
|
17581
17661
|
options,
|
|
17582
17662
|
),
|
|
17583
17663
|
));
|
|
17584
|
-
const runtimeApi = {
|
|
17664
|
+
const runtimeApi = {
|
|
17665
|
+
...resolvedRuntimeApi,
|
|
17666
|
+
...(gatewayRuntimeApi && input.runtimeApi
|
|
17667
|
+
? {
|
|
17668
|
+
...(input.runtimeApi.fetch
|
|
17669
|
+
? { fetch: input.runtimeApi.fetch }
|
|
17670
|
+
: {}),
|
|
17671
|
+
...(input.runtimeApi.requestTimeoutMs !== undefined
|
|
17672
|
+
? { requestTimeoutMs: input.runtimeApi.requestTimeoutMs }
|
|
17673
|
+
: {}),
|
|
17674
|
+
...(input.runtimeApi.onResponseMeta
|
|
17675
|
+
? { onResponseMeta: input.runtimeApi.onResponseMeta }
|
|
17676
|
+
: {}),
|
|
17677
|
+
...(input.runtimeApi.runtimeTestFaultHeader !== undefined
|
|
17678
|
+
? {
|
|
17679
|
+
runtimeTestFaultHeader:
|
|
17680
|
+
input.runtimeApi.runtimeTestFaultHeader,
|
|
17681
|
+
}
|
|
17682
|
+
: {}),
|
|
17683
|
+
...(input.runtimeApi.signal
|
|
17684
|
+
? { signal: input.runtimeApi.signal }
|
|
17685
|
+
: {}),
|
|
17686
|
+
}
|
|
17687
|
+
: {}),
|
|
17688
|
+
retryPolicy: 'none' as const,
|
|
17689
|
+
};
|
|
17585
17690
|
const renewDelivery = () =>
|
|
17586
17691
|
withClient((client) =>
|
|
17587
17692
|
renewPostgresRunLedgerDelivery(
|
|
@@ -17839,6 +17944,7 @@ async function loadPostgresSchedulerRuntimeApiForRun(
|
|
|
17839
17944
|
dispatchLease: { eventId: string; leaseOwner: string } | null,
|
|
17840
17945
|
tokenAuthority: RunLedgerOutboxTokenAuthority,
|
|
17841
17946
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
17947
|
+
signal?: AbortSignal,
|
|
17842
17948
|
): Promise<WorkerRuntimeApiContext> {
|
|
17843
17949
|
const result = await client.query<{ launch_json: unknown }>(
|
|
17844
17950
|
`
|
|
@@ -17879,6 +17985,7 @@ async function loadPostgresSchedulerRuntimeApiForRun(
|
|
|
17879
17985
|
eventId: dispatchLease.eventId,
|
|
17880
17986
|
leaseOwner: dispatchLease.leaseOwner,
|
|
17881
17987
|
schedulerSchema: options?.schema ?? null,
|
|
17988
|
+
signal,
|
|
17882
17989
|
});
|
|
17883
17990
|
}
|
|
17884
17991
|
return {
|
|
@@ -17893,6 +18000,7 @@ async function requestRunLedgerDispatchToken(input: {
|
|
|
17893
18000
|
eventId: string;
|
|
17894
18001
|
leaseOwner: string;
|
|
17895
18002
|
schedulerSchema: string | null;
|
|
18003
|
+
signal?: AbortSignal;
|
|
17896
18004
|
}): Promise<string> {
|
|
17897
18005
|
const internalToken = process.env.DEEPLINE_INTERNAL_TOKEN?.trim();
|
|
17898
18006
|
if (!internalToken || !input.eventId || !input.leaseOwner) {
|
|
@@ -17904,10 +18012,16 @@ async function requestRunLedgerDispatchToken(input: {
|
|
|
17904
18012
|
const vercelProtectionHeaders = await vercelProtectionBypassHeaders({
|
|
17905
18013
|
baseUrl: runtimeApiBaseUrlFromLaunch(input.launch),
|
|
17906
18014
|
token: input.launch.vercelProtectionBypassToken,
|
|
18015
|
+
signal: input.signal,
|
|
17907
18016
|
});
|
|
17908
18017
|
const response = await fetch(url, {
|
|
17909
18018
|
method: 'POST',
|
|
17910
|
-
signal:
|
|
18019
|
+
signal: input.signal
|
|
18020
|
+
? AbortSignal.any([
|
|
18021
|
+
input.signal,
|
|
18022
|
+
AbortSignal.timeout(RUN_LEDGER_DISPATCH_TOKEN_TIMEOUT_MS),
|
|
18023
|
+
])
|
|
18024
|
+
: AbortSignal.timeout(RUN_LEDGER_DISPATCH_TOKEN_TIMEOUT_MS),
|
|
17911
18025
|
headers: {
|
|
17912
18026
|
'content-type': 'application/json',
|
|
17913
18027
|
'x-deepline-internal-token': internalToken,
|
|
@@ -1767,6 +1767,7 @@ function createDatasetFromSerializedToolList(
|
|
|
1767
1767
|
residentRows: isPartialPreview ? null : sourceRows,
|
|
1768
1768
|
sourceLabel: serialized.sourceLabel ?? null,
|
|
1769
1769
|
tableNamespace: serialized.tableNamespace ?? null,
|
|
1770
|
+
columnTypes: serialized.columnTypes,
|
|
1770
1771
|
workProgress: serialized._metadata?.workProgress,
|
|
1771
1772
|
resolvers: {
|
|
1772
1773
|
count: async () => serialized.count,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PlayExecutionFileRef } from './file-refs';
|
|
2
|
+
import type { PlayDatasetColumnTypes } from '../play-data-plane/contracts';
|
|
2
3
|
|
|
3
4
|
const PLAY_DATASET_BRAND = Symbol.for('deepline.play.dataset');
|
|
4
5
|
const NODE_INSPECT_CUSTOM = Symbol.for('nodejs.util.inspect.custom');
|
|
@@ -47,6 +48,7 @@ export interface SerializedPlayDataset<T> {
|
|
|
47
48
|
sourceLabel?: string | null;
|
|
48
49
|
tableNamespace?: string | null;
|
|
49
50
|
columns?: string[];
|
|
51
|
+
columnTypes?: PlayDatasetColumnTypes;
|
|
50
52
|
_metadata?: {
|
|
51
53
|
workProgress?: PlayDatasetWorkProgressSummary;
|
|
52
54
|
};
|
|
@@ -107,8 +109,7 @@ export type PlayDatasetTransformOptions = {
|
|
|
107
109
|
* `materialize(limit)` or async iteration only when the dataset is intentionally
|
|
108
110
|
* small and bounded. `PlayDataset` intentionally does not expose `.rows`,
|
|
109
111
|
* `.toArray()`, `.length`, numeric indexing, spread, or synchronous iteration;
|
|
110
|
-
*
|
|
111
|
-
* behavior depend on whether rows happen to be resident.
|
|
112
|
+
* these hide loading costs or make behavior depend on row residency.
|
|
112
113
|
*
|
|
113
114
|
* @sdkReference runtime 190
|
|
114
115
|
*/
|
|
@@ -124,6 +125,8 @@ export interface PlayDataset<T> extends AsyncIterable<T> {
|
|
|
124
125
|
readonly sourceLabel?: string | null;
|
|
125
126
|
/** Runtime table name. */
|
|
126
127
|
readonly tableNamespace?: string | null;
|
|
128
|
+
/** Advisory source types; transformed fields must infer from their values. */
|
|
129
|
+
readonly columnTypes?: PlayDatasetColumnTypes;
|
|
127
130
|
/** Row count. */
|
|
128
131
|
count(): Promise<number>;
|
|
129
132
|
/** Preview rows. */
|
|
@@ -161,6 +164,7 @@ export interface PlayDataset<T> extends AsyncIterable<T> {
|
|
|
161
164
|
sourceLabel?: string | null;
|
|
162
165
|
tableNamespace?: string | null;
|
|
163
166
|
columns?: string[];
|
|
167
|
+
columnTypes?: PlayDatasetColumnTypes;
|
|
164
168
|
_metadata?: {
|
|
165
169
|
workProgress?: PlayDatasetWorkProgressSummary;
|
|
166
170
|
};
|
|
@@ -335,6 +339,7 @@ export function deserializePlayDatasetCell<T>(
|
|
|
335
339
|
residentRows: rows,
|
|
336
340
|
sourceLabel: dataset.sourceLabel ?? null,
|
|
337
341
|
tableNamespace: dataset.tableNamespace ?? null,
|
|
342
|
+
columnTypes: dataset.columnTypes,
|
|
338
343
|
workProgress: dataset._metadata?.workProgress,
|
|
339
344
|
resolvers: {
|
|
340
345
|
count: async () => rows.length,
|
|
@@ -374,6 +379,7 @@ export function deserializeLegacyPlayDataset<T>(
|
|
|
374
379
|
residentRows: complete ? rows : null,
|
|
375
380
|
sourceLabel: dataset.sourceLabel ?? null,
|
|
376
381
|
tableNamespace: dataset.tableNamespace ?? null,
|
|
382
|
+
columnTypes: dataset.columnTypes,
|
|
377
383
|
workProgress: dataset._metadata?.workProgress,
|
|
378
384
|
resolvers: {
|
|
379
385
|
count: async () => dataset.count,
|
|
@@ -417,6 +423,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
417
423
|
readonly backing?: PlayDatasetBacking;
|
|
418
424
|
readonly sourceLabel?: string | null;
|
|
419
425
|
readonly tableNamespace?: string | null;
|
|
426
|
+
readonly columnTypes?: PlayDatasetColumnTypes;
|
|
420
427
|
private readonly previewRows: readonly T[];
|
|
421
428
|
private readonly previewColumns?: string[];
|
|
422
429
|
private readonly workProgress?: PlayDatasetWorkProgressSummary;
|
|
@@ -435,6 +442,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
435
442
|
residentRows?: readonly T[] | null;
|
|
436
443
|
sourceLabel?: string | null;
|
|
437
444
|
tableNamespace?: string | null;
|
|
445
|
+
columnTypes?: PlayDatasetColumnTypes;
|
|
438
446
|
workProgress?: PlayDatasetWorkProgressSummary;
|
|
439
447
|
resolvers: PlayDatasetResolvers<T>;
|
|
440
448
|
}) {
|
|
@@ -449,6 +457,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
449
457
|
this.previewColumns = inferPreviewColumns(this.previewRows);
|
|
450
458
|
this.sourceLabel = input.sourceLabel ?? null;
|
|
451
459
|
this.tableNamespace = input.tableNamespace ?? null;
|
|
460
|
+
this.columnTypes = input.columnTypes;
|
|
452
461
|
this.workProgress = input.workProgress;
|
|
453
462
|
this.resolvers = input.resolvers;
|
|
454
463
|
}
|
|
@@ -592,6 +601,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
592
601
|
...(this.sourceLabel ? { sourceLabel: this.sourceLabel } : {}),
|
|
593
602
|
...(this.tableNamespace ? { tableNamespace: this.tableNamespace } : {}),
|
|
594
603
|
...(this.previewColumns ? { columns: this.previewColumns } : {}),
|
|
604
|
+
...(this.columnTypes ? { columnTypes: this.columnTypes } : {}),
|
|
595
605
|
...(this.workProgress
|
|
596
606
|
? { _metadata: { workProgress: this.workProgress } }
|
|
597
607
|
: {}),
|
|
@@ -721,6 +731,7 @@ function createTransformedPlayDataset<T, U>(
|
|
|
721
731
|
backing: source.backing,
|
|
722
732
|
sourceLabel,
|
|
723
733
|
tableNamespace: options?.key ?? null,
|
|
734
|
+
columnTypes: transform.kind === 'map' ? undefined : source.columnTypes,
|
|
724
735
|
resolvers: {
|
|
725
736
|
count,
|
|
726
737
|
peek: async (limit) => collect(limit),
|
|
@@ -747,6 +758,7 @@ export function createDeferredPlayDataset<T>(input: {
|
|
|
747
758
|
residentRows?: readonly T[] | null;
|
|
748
759
|
sourceLabel?: string | null;
|
|
749
760
|
tableNamespace?: string | null;
|
|
761
|
+
columnTypes?: PlayDatasetColumnTypes;
|
|
750
762
|
workProgress?: PlayDatasetWorkProgressSummary;
|
|
751
763
|
resolvers: PlayDatasetResolvers<T>;
|
|
752
764
|
}): PlayDataset<T> {
|
|
@@ -835,6 +847,7 @@ export function createPlayDataset<T>(
|
|
|
835
847
|
sourceLabel?: string | null;
|
|
836
848
|
tableNamespace?: string | null;
|
|
837
849
|
datasetId?: string;
|
|
850
|
+
columnTypes?: PlayDatasetColumnTypes;
|
|
838
851
|
},
|
|
839
852
|
): PlayDataset<T> {
|
|
840
853
|
// Test/dev helper only. Production play execution should construct
|
|
@@ -850,6 +863,7 @@ export function createPlayDataset<T>(
|
|
|
850
863
|
residentRows: materializedRows,
|
|
851
864
|
sourceLabel: metadata?.sourceLabel ?? null,
|
|
852
865
|
tableNamespace: metadata?.tableNamespace ?? null,
|
|
866
|
+
columnTypes: metadata?.columnTypes,
|
|
853
867
|
resolvers: {
|
|
854
868
|
count: async () => materializedRows.length,
|
|
855
869
|
peek: async (limit) => materializedRows.slice(0, Math.max(0, limit)),
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { PlayStaticPipeline } from './static-pipeline';
|
|
2
|
+
import { staticPipelineStorageCodec } from './static-pipeline-storage-codec';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An in-process execution snapshot, deliberately distinct from display graphs
|
|
6
|
+
* and Convex's bounded V1 mirror. Never serialize this wrapper: durable/wire
|
|
7
|
+
* contracts continue to carry the original pipeline fields.
|
|
8
|
+
*/
|
|
9
|
+
export class PlayExecutionPipeline {
|
|
10
|
+
readonly #pipeline: PlayStaticPipeline | null;
|
|
11
|
+
|
|
12
|
+
private constructor(pipeline: PlayStaticPipeline | null) {
|
|
13
|
+
this.#pipeline = pipeline;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Read the entire storage carrier, so an existing V2 can never be dropped. */
|
|
17
|
+
static fromStored(record: {
|
|
18
|
+
staticPipeline?: unknown;
|
|
19
|
+
staticPipelineV2?: unknown;
|
|
20
|
+
}): PlayExecutionPipeline {
|
|
21
|
+
return new PlayExecutionPipeline(staticPipelineStorageCodec.read(record));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Only for complete compiler/admitted-artifact graphs, never a stored field. */
|
|
25
|
+
static fromAdmitted(pipeline: unknown): PlayExecutionPipeline {
|
|
26
|
+
if (
|
|
27
|
+
pipeline != null &&
|
|
28
|
+
(typeof pipeline !== 'object' ||
|
|
29
|
+
!('fields' in pipeline) ||
|
|
30
|
+
!Array.isArray(pipeline.fields) ||
|
|
31
|
+
!('substeps' in pipeline) ||
|
|
32
|
+
!Array.isArray(pipeline.substeps))
|
|
33
|
+
) {
|
|
34
|
+
throw new Error('Invalid Play execution pipeline snapshot.');
|
|
35
|
+
}
|
|
36
|
+
// Do not compile or normalize retained contracts under current authoring
|
|
37
|
+
// rules. In particular, preserve additive fields and historical contracts.
|
|
38
|
+
return new PlayExecutionPipeline(
|
|
39
|
+
(pipeline as PlayStaticPipeline | null | undefined) ?? null,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get pipeline(): PlayStaticPipeline | null {
|
|
44
|
+
return this.#pipeline;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Reject accidental raw/serialized inputs before launch has side effects. */
|
|
49
|
+
export function readPlayExecutionPipeline(
|
|
50
|
+
snapshot: PlayExecutionPipeline | undefined,
|
|
51
|
+
): PlayStaticPipeline | null {
|
|
52
|
+
if (snapshot === undefined) return null;
|
|
53
|
+
if (!(snapshot instanceof PlayExecutionPipeline)) {
|
|
54
|
+
throw new Error('Play launch requires a PlayExecutionPipeline snapshot.');
|
|
55
|
+
}
|
|
56
|
+
return snapshot.pipeline;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Execution readers cannot see (and accidentally forward) the stored mirror. */
|
|
60
|
+
export function readStoredPlayExecutionSnapshot<
|
|
61
|
+
T extends { staticPipeline?: unknown; staticPipelineV2?: unknown },
|
|
62
|
+
>(
|
|
63
|
+
record: T,
|
|
64
|
+
): Omit<T, 'staticPipeline' | 'staticPipelineV2'> & {
|
|
65
|
+
executionPipeline: PlayExecutionPipeline;
|
|
66
|
+
} {
|
|
67
|
+
const { staticPipeline: _v1, staticPipelineV2: _v2, ...metadata } = record;
|
|
68
|
+
return {
|
|
69
|
+
...metadata,
|
|
70
|
+
executionPipeline: PlayExecutionPipeline.fromStored(record),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -61,7 +61,6 @@ export function buildPlayRunContractSnapshot(input: {
|
|
|
61
61
|
artifactStorageKey: string;
|
|
62
62
|
artifact: Pick<PlayBundleArtifact, 'compatibility'>;
|
|
63
63
|
validatedSnapshot: PlayRunLaunchValidationSnapshot;
|
|
64
|
-
transportStaticPipeline?: unknown;
|
|
65
64
|
}): PreparedPlayRunContractSnapshot {
|
|
66
65
|
// The runtime backend is launch infrastructure, not an artifact contract.
|
|
67
66
|
// Copy the admitted artifact compatibility so resumed work cannot acquire
|
|
@@ -69,8 +68,7 @@ export function buildPlayRunContractSnapshot(input: {
|
|
|
69
68
|
const compatibility = normalizePlayContractCompatibility(
|
|
70
69
|
input.artifact.compatibility,
|
|
71
70
|
);
|
|
72
|
-
const staticPipeline =
|
|
73
|
-
input.transportStaticPipeline ?? input.validatedSnapshot.staticPipeline;
|
|
71
|
+
const staticPipeline = input.validatedSnapshot.staticPipeline;
|
|
74
72
|
return {
|
|
75
73
|
source: input.source ?? 'published',
|
|
76
74
|
revisionVersion: null,
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// Full-table view basic filters. A tiny, deliberately closed predicate model
|
|
2
2
|
// that compiles mechanically to a parameterized SQL WHERE clause against a
|
|
3
|
-
// runtime sheet's physical
|
|
3
|
+
// runtime sheet's physical user-data columns.
|
|
4
4
|
//
|
|
5
5
|
// This is NOT free-text SQL: operators come from a closed enum, columns must
|
|
6
6
|
// be on a caller-supplied allowlist (the sheet's real columns), and every value
|
|
7
7
|
// is bound as a query parameter. Multiple filters AND together. No OR groups.
|
|
8
8
|
//
|
|
9
|
-
// Sheet user-data columns
|
|
10
|
-
//
|
|
11
|
-
// text; numeric comparisons cast that text to numeric.
|
|
9
|
+
// Sheet user-data columns may be native scalars or JSONB. Normalize each cell
|
|
10
|
+
// through to_jsonb before applying the shared scalar and numeric predicates.
|
|
12
11
|
|
|
13
12
|
// ── The operator set, and why it grew ────────────────────────────────────────
|
|
14
13
|
//
|
|
@@ -204,7 +203,7 @@ function coerceFilterNumber(value: unknown, index: number): number {
|
|
|
204
203
|
// → 19991, an object → its JSON text. The single-arg `#>> '{}'` path returns the
|
|
205
204
|
// whole value as text (Postgres jsonb → text).
|
|
206
205
|
function columnAsText(quotedColumn: string): string {
|
|
207
|
-
return `(${quotedColumn} #>> '{}')`;
|
|
206
|
+
return `(to_jsonb(${quotedColumn}) #>> '{}')`;
|
|
208
207
|
}
|
|
209
208
|
|
|
210
209
|
function quoteIdentifier(value: string): string {
|
|
@@ -302,9 +301,10 @@ export function compileSheetFilterWhere(input: {
|
|
|
302
301
|
const num = coerceFilterNumber(filter.value, index);
|
|
303
302
|
const sqlOp = NUMERIC_SQL_OPERATOR[filter.op];
|
|
304
303
|
// Guard the numeric cast to jsonb numbers only, so a stray non-numeric
|
|
305
|
-
// cell can never abort the whole query with a cast error.
|
|
304
|
+
// cell can never abort the whole query with a cast error. CASE also
|
|
305
|
+
// prevents PostgreSQL from reordering a numeric cast before its guard.
|
|
306
306
|
clauses.push(
|
|
307
|
-
`(jsonb_typeof(${quoted}) = 'number'
|
|
307
|
+
`((CASE WHEN jsonb_typeof(to_jsonb(${quoted})) = 'number' THEN ${asText}::numeric END) ${sqlOp} $${paramIdx})`,
|
|
308
308
|
);
|
|
309
309
|
params.push(num);
|
|
310
310
|
paramIdx += 1;
|
|
@@ -317,12 +317,8 @@ export function compileSheetFilterWhere(input: {
|
|
|
317
317
|
// range control means by it. The guard is the same one the scalar
|
|
318
318
|
// comparisons use: a non-numeric cell simply does not match, rather
|
|
319
319
|
// than aborting the query on a cast.
|
|
320
|
-
const body =
|
|
321
|
-
clauses.push(
|
|
322
|
-
`(jsonb_typeof(${quoted}) = 'number' AND ${
|
|
323
|
-
filter.op === 'between' ? body : `NOT (${body})`
|
|
324
|
-
})`,
|
|
325
|
-
);
|
|
320
|
+
const body = `(CASE WHEN jsonb_typeof(to_jsonb(${quoted})) = 'number' THEN ${asText}::numeric END) BETWEEN $${paramIdx} AND $${paramIdx + 1}`;
|
|
321
|
+
clauses.push(`(${filter.op === 'between' ? body : `NOT (${body})`})`);
|
|
326
322
|
params.push(min, max);
|
|
327
323
|
paramIdx += 2;
|
|
328
324
|
break;
|