deepline 0.3.149 → 0.3.151
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/client.ts +347 -12
- package/dist/bundling-sources/sdk/src/http.ts +28 -2
- package/dist/bundling-sources/sdk/src/index.ts +4 -0
- package/dist/bundling-sources/sdk/src/play.ts +55 -5
- 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/r2.ts +33 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +98 -3
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-contract.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +7 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +363 -67
- package/dist/cli/index.js +393 -17
- package/dist/cli/index.mjs +399 -20
- package/dist/index.d.mts +61 -2
- package/dist/index.d.ts +61 -2
- package/dist/index.js +236 -13
- package/dist/index.mjs +236 -13
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createWriteStream } from 'node:fs';
|
|
2
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { stat } from 'node:fs/promises';
|
|
4
4
|
import { Readable } from 'node:stream';
|
|
5
5
|
import { pipeline } from 'node:stream/promises';
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
LEGACY_RUNTIME_RECEIPT_WIRE_HEADER,
|
|
48
48
|
} from './/runtime-contract';
|
|
49
49
|
import { PLAY_RUNTIME_API_COMPAT_PATH } from './/runtime-api-paths';
|
|
50
|
+
import { buildRunLedgerEventsIdempotencyKey } from './run-ledger-projection-contract';
|
|
50
51
|
import {
|
|
51
52
|
RUNTIME_API_ACCEPTS_HEADER,
|
|
52
53
|
gzipRuntimeApiRequestBody,
|
|
@@ -157,15 +158,21 @@ type RuntimeApiRequest =
|
|
|
157
158
|
action: 'create_db_session';
|
|
158
159
|
} & CreateDbSessionRequest)
|
|
159
160
|
| {
|
|
160
|
-
action: 'append_run_events';
|
|
161
|
+
action: 'append_run_events' | 'project_run_events';
|
|
161
162
|
playId: string;
|
|
162
163
|
events: PlayRunLedgerIngressEvent[];
|
|
163
164
|
idempotencyKey?: string;
|
|
165
|
+
deliveryIdempotencyKey?: string;
|
|
166
|
+
deliveryLeaseOwner?: string;
|
|
164
167
|
}
|
|
165
168
|
| {
|
|
166
169
|
action: 'start_run';
|
|
170
|
+
deliveryLeaseOwner?: string;
|
|
167
171
|
idempotencyKey?: string;
|
|
168
172
|
playName: string;
|
|
173
|
+
playReference?: string | null;
|
|
174
|
+
definitionScope?: 'org' | 'system';
|
|
175
|
+
revisionId?: string | null;
|
|
169
176
|
runId: string;
|
|
170
177
|
artifactStorageKey?: string | null;
|
|
171
178
|
artifactHash?: string | null;
|
|
@@ -200,6 +207,7 @@ type RuntimeApiRequest =
|
|
|
200
207
|
}
|
|
201
208
|
| {
|
|
202
209
|
action: 'project_run_created';
|
|
210
|
+
deliveryLeaseOwner?: string;
|
|
203
211
|
idempotencyKey: string;
|
|
204
212
|
playName: string;
|
|
205
213
|
playReference?: string | null;
|
|
@@ -736,7 +744,8 @@ function isRetryableAppRuntimeResponse(input: {
|
|
|
736
744
|
// projection. Do not make every 403 retryable: only this exact Vercel HTML
|
|
737
745
|
// response on a replay-safe action is an intermediary failure.
|
|
738
746
|
if (
|
|
739
|
-
input.action === 'append_run_events'
|
|
747
|
+
(input.action === 'append_run_events' ||
|
|
748
|
+
input.action === 'project_run_events') &&
|
|
740
749
|
isVercelSecurityCheckpointResponse(input)
|
|
741
750
|
) {
|
|
742
751
|
return true;
|
|
@@ -964,6 +973,9 @@ function isRetryableAppRuntimeAction(
|
|
|
964
973
|
): boolean {
|
|
965
974
|
return (
|
|
966
975
|
action === 'append_run_events' ||
|
|
976
|
+
// Classification remains replay-safe for the durable outbox even though
|
|
977
|
+
// projectRunEventsViaAppRuntime disables in-process transport retries.
|
|
978
|
+
action === 'project_run_events' ||
|
|
967
979
|
action === 'apply_row_updates' ||
|
|
968
980
|
action === 'compute_billing_finalize' ||
|
|
969
981
|
action === 'compute_billing_record_item' ||
|
|
@@ -2312,6 +2324,85 @@ async function appendRunEventsViaAppRuntimeRaw(
|
|
|
2312
2324
|
});
|
|
2313
2325
|
}
|
|
2314
2326
|
|
|
2327
|
+
/** Leased delivery only. Every transport piece has its own stable receipt. */
|
|
2328
|
+
export async function projectRunEventsViaAppRuntime(
|
|
2329
|
+
context: WorkerRuntimeApiContext,
|
|
2330
|
+
input: {
|
|
2331
|
+
playId: string;
|
|
2332
|
+
events: PlayRunLedgerIngressEvent[];
|
|
2333
|
+
idempotencyKey: string;
|
|
2334
|
+
deliveryLeaseOwner: string;
|
|
2335
|
+
beforeBatch: () => Promise<void>;
|
|
2336
|
+
},
|
|
2337
|
+
): Promise<void> {
|
|
2338
|
+
const batches = partitionRunEventsForAppRuntime(input.events);
|
|
2339
|
+
const receiptBatch = runLedgerReceiptBatchIndex(batches);
|
|
2340
|
+
for (const [index, events] of batches.entries()) {
|
|
2341
|
+
await input.beforeBatch();
|
|
2342
|
+
// Retain the original receipt for the terminal (or final) piece so an acknowledged
|
|
2343
|
+
// legacy delivery stays acknowledged across the reader rollout.
|
|
2344
|
+
const idempotencyKey =
|
|
2345
|
+
index === receiptBatch
|
|
2346
|
+
? input.idempotencyKey
|
|
2347
|
+
: buildRunLedgerEventsIdempotencyKey({
|
|
2348
|
+
runId: input.playId,
|
|
2349
|
+
deliveryDigest: createHash('sha256')
|
|
2350
|
+
.update(JSON.stringify([input.idempotencyKey, index, events]))
|
|
2351
|
+
.digest('hex'),
|
|
2352
|
+
});
|
|
2353
|
+
const request = {
|
|
2354
|
+
playId: input.playId,
|
|
2355
|
+
events,
|
|
2356
|
+
idempotencyKey,
|
|
2357
|
+
deliveryIdempotencyKey: input.idempotencyKey,
|
|
2358
|
+
deliveryLeaseOwner: input.deliveryLeaseOwner,
|
|
2359
|
+
};
|
|
2360
|
+
// The durable outbox owns recovery; this helper does not retry OCCs or
|
|
2361
|
+
// other delivery failures inside an already-leased invocation.
|
|
2362
|
+
const deliveryContext = { ...context, retryPolicy: 'none' as const };
|
|
2363
|
+
try {
|
|
2364
|
+
await postAppRuntimeApi(deliveryContext, {
|
|
2365
|
+
action: 'project_run_events',
|
|
2366
|
+
...request,
|
|
2367
|
+
});
|
|
2368
|
+
} catch (error) {
|
|
2369
|
+
if (
|
|
2370
|
+
!(error instanceof AppRuntimeApiResponseError) ||
|
|
2371
|
+
!isLegacyProjectRunCreatedUnsupportedActionResponse({
|
|
2372
|
+
status: error.status,
|
|
2373
|
+
body: error.detail,
|
|
2374
|
+
})
|
|
2375
|
+
)
|
|
2376
|
+
throw error;
|
|
2377
|
+
// Launch-pinned old apps already implement equivalent keyed projection.
|
|
2378
|
+
// A real auth refusal never selects this compatibility adapter.
|
|
2379
|
+
// The capability probe was a network round trip. Re-check ownership
|
|
2380
|
+
// before the legacy request too; reclamation must stop a stale sender.
|
|
2381
|
+
await input.beforeBatch();
|
|
2382
|
+
await postAppRuntimeApi(deliveryContext, {
|
|
2383
|
+
action: 'append_run_events',
|
|
2384
|
+
...request,
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
function runLedgerReceiptBatchIndex(
|
|
2391
|
+
batches: PlayRunLedgerIngressEvent[][],
|
|
2392
|
+
): number {
|
|
2393
|
+
for (let index = batches.length - 1; index >= 0; index -= 1) {
|
|
2394
|
+
if (
|
|
2395
|
+
batches[index]!.some((event) =>
|
|
2396
|
+
['run.completed', 'run.failed', 'run.cancelled'].includes(
|
|
2397
|
+
event.key ?? event.type ?? '',
|
|
2398
|
+
),
|
|
2399
|
+
)
|
|
2400
|
+
)
|
|
2401
|
+
return index;
|
|
2402
|
+
}
|
|
2403
|
+
return batches.length - 1;
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2315
2406
|
/**
|
|
2316
2407
|
* Append Run Ledger events through the bounded transport used by every runtime
|
|
2317
2408
|
* producer. Scheduler terminal outbox events can carry a complete log replay,
|
|
@@ -2368,7 +2459,11 @@ export async function appendRunEventsViaAppRuntime(
|
|
|
2368
2459
|
export async function startRunViaAppRuntime(
|
|
2369
2460
|
context: WorkerRuntimeApiContext,
|
|
2370
2461
|
input: {
|
|
2462
|
+
deliveryLeaseOwner?: string;
|
|
2371
2463
|
playName: string;
|
|
2464
|
+
playReference?: string | null;
|
|
2465
|
+
definitionScope?: 'org' | 'system';
|
|
2466
|
+
revisionId?: string | null;
|
|
2372
2467
|
runId: string;
|
|
2373
2468
|
artifactStorageKey?: string | null;
|
|
2374
2469
|
artifactHash?: string | null;
|
|
@@ -10,6 +10,13 @@ const UUID_PATTERN =
|
|
|
10
10
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
11
11
|
const SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
|
|
12
12
|
|
|
13
|
+
export class RunLedgerProjectionLeaseLostError extends Error {
|
|
14
|
+
constructor() {
|
|
15
|
+
super('Run Ledger projection requires the current outbox delivery lease.');
|
|
16
|
+
this.name = 'RunLedgerProjectionLeaseLostError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
function requireRunId(runId: string): void {
|
|
14
21
|
if (!runId.trim()) {
|
|
15
22
|
throw new Error('Run Ledger projection idempotency key requires a run id.');
|
|
@@ -760,6 +760,12 @@ function mergeMonotonicStepProgress(input: {
|
|
|
760
760
|
}): PlayRunLedgerStepProgress {
|
|
761
761
|
const current = input.current ?? {};
|
|
762
762
|
const next = input.next;
|
|
763
|
+
const supersededRows = maxProgressNumber(
|
|
764
|
+
current.supersededRows,
|
|
765
|
+
next.supersededRows === undefined
|
|
766
|
+
? undefined
|
|
767
|
+
: Math.max(0, next.supersededRows),
|
|
768
|
+
);
|
|
763
769
|
return {
|
|
764
770
|
...current,
|
|
765
771
|
...next,
|
|
@@ -786,11 +792,7 @@ function mergeMonotonicStepProgress(input: {
|
|
|
786
792
|
),
|
|
787
793
|
}
|
|
788
794
|
: {}),
|
|
789
|
-
...(
|
|
790
|
-
? { supersededRows: Math.max(0, next.supersededRows) }
|
|
791
|
-
: current.supersededRows !== undefined
|
|
792
|
-
? { supersededRows: current.supersededRows }
|
|
793
|
-
: {}),
|
|
795
|
+
...(supersededRows !== undefined ? { supersededRows } : {}),
|
|
794
796
|
};
|
|
795
797
|
}
|
|
796
798
|
|
|
@@ -35,6 +35,7 @@ export const RUNTIME_OPERATION_CAPABILITIES = {
|
|
|
35
35
|
create_db_session: 'db.session',
|
|
36
36
|
repair_runtime_storage_grants: 'sheet.write',
|
|
37
37
|
append_run_events: 'run.progress',
|
|
38
|
+
project_run_events: 'run.progress',
|
|
38
39
|
save_results: 'run.progress',
|
|
39
40
|
start_run: 'run.progress',
|
|
40
41
|
record_first_claim_latency: 'run.progress',
|
|
@@ -56,6 +57,10 @@ export const RUNTIME_OPERATION_CONTRACT: DeployedOperationContract =
|
|
|
56
57
|
id: 'runtime-api-actions',
|
|
57
58
|
actions: RUNTIME_OPERATION_CAPABILITIES,
|
|
58
59
|
olderReceiver: {
|
|
60
|
+
project_run_events: {
|
|
61
|
+
kind: 'equivalent-fallback',
|
|
62
|
+
action: 'append_run_events',
|
|
63
|
+
},
|
|
59
64
|
// The runner retains the complete result before attempting this
|
|
60
65
|
// compact completion. An older app receiver reports the action as
|
|
61
66
|
// unsupported, and the adapter retries the established full-payload
|
|
@@ -250,7 +250,7 @@ export type PlaySchedulerRunHandle = {
|
|
|
250
250
|
signal?: AbortSignal;
|
|
251
251
|
}): AsyncIterable<PlaySchedulerProgressEvent>;
|
|
252
252
|
/** Cooperatively cancel the run. */
|
|
253
|
-
cancel(): Promise<void>;
|
|
253
|
+
cancel(reason?: string): Promise<void>;
|
|
254
254
|
/** Inject an external event (HITL, webhook). */
|
|
255
255
|
signal(payload: PlaySchedulerSignalPayload): Promise<void>;
|
|
256
256
|
/** Block until terminal state and return final envelope. */
|
|
@@ -216,14 +216,14 @@ function absurdRunHandle(input: {
|
|
|
216
216
|
return error;
|
|
217
217
|
};
|
|
218
218
|
|
|
219
|
-
const requestCancellation = async () => {
|
|
219
|
+
const requestCancellation = async (reason?: string) => {
|
|
220
220
|
await runCancellationSingleFlight(cancellationKey, async () => {
|
|
221
221
|
// First move the durable engine task into its cancellation lane. If the
|
|
222
222
|
// scheduler tables are briefly locked, the worker reconciler can finish
|
|
223
223
|
// the terminal write later without another user request piling up.
|
|
224
224
|
await cancelAbsurdTask();
|
|
225
225
|
try {
|
|
226
|
-
await delegate.cancel();
|
|
226
|
+
await delegate.cancel(reason);
|
|
227
227
|
} catch (error) {
|
|
228
228
|
throw cancellationPendingError(error);
|
|
229
229
|
}
|