deepline 0.1.211 → 0.1.213
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/apps/play-runner-workers/src/entry.ts +317 -340
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +23 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +1 -1
- package/dist/bundling-sources/sdk/src/client.ts +118 -3
- package/dist/bundling-sources/sdk/src/index.ts +2 -0
- package/dist/bundling-sources/sdk/src/play.ts +8 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +11 -1
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/sdk/src/types.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +302 -30
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-placement.ts +14 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +57 -23
- package/dist/bundling-sources/shared_libs/play-runtime/completed-receipt-cache.ts +166 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +164 -121
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-contract.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +42 -1
- package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -4
- package/dist/bundling-sources/shared_libs/play-runtime/db-session.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +163 -7
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-auth-session.ts +93 -0
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +14 -2
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +4 -2
- package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +16 -1
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +21 -1
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-state-sink.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +80 -3
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +128 -6
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +94 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +91 -6
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +19 -10
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +540 -92
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-postgres-admission.ts +162 -0
- package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +18 -4
- package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +16 -17
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +29 -9
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +22 -1
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +1 -0
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +79 -1
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +2 -4
- package/dist/cli/index.js +637 -229
- package/dist/cli/index.mjs +637 -229
- package/dist/{compiler-manifest-j6z8qzpd.d.mts → compiler-manifest-BhgZ23A4.d.mts} +1 -0
- package/dist/{compiler-manifest-j6z8qzpd.d.ts → compiler-manifest-BhgZ23A4.d.ts} +1 -0
- package/dist/index.d.mts +84 -11
- package/dist/index.d.ts +84 -11
- package/dist/index.js +225 -43
- package/dist/index.mjs +225 -43
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +65 -4
- package/package.json +1 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A completed receipt is an immutable cache fact. Execution coordination is a
|
|
3
|
+
* separate, short-lived concern and must never be represented by a "running"
|
|
4
|
+
* receipt.
|
|
5
|
+
*/
|
|
6
|
+
export type CompletedReceipt<T> = {
|
|
7
|
+
key: string;
|
|
8
|
+
output: T;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
expiresAt?: string | null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type CompletedReceiptCache<T> = {
|
|
14
|
+
get(key: string): Promise<CompletedReceipt<T> | null>;
|
|
15
|
+
/**
|
|
16
|
+
* Insert only when the key is absent. On conflict, return the already stored
|
|
17
|
+
* immutable fact. Implementations should use INSERT ... ON CONFLICT DO
|
|
18
|
+
* NOTHING followed by a point read.
|
|
19
|
+
*/
|
|
20
|
+
putIfAbsent(receipt: CompletedReceipt<T>): Promise<CompletedReceipt<T>>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type ReceiptExecutionLock = {
|
|
24
|
+
receiptKey: string;
|
|
25
|
+
ownerExecutionId: string;
|
|
26
|
+
expiresAt: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type ReceiptExecutionLockStore = {
|
|
30
|
+
tryAcquire(input: {
|
|
31
|
+
receiptKey: string;
|
|
32
|
+
ownerExecutionId: string;
|
|
33
|
+
expiresAt: string;
|
|
34
|
+
}): Promise<ReceiptExecutionLock | null>;
|
|
35
|
+
release(input: {
|
|
36
|
+
receiptKey: string;
|
|
37
|
+
ownerExecutionId: string;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type ReceiptMissCoordination =
|
|
42
|
+
| { kind: 'provider_idempotency' }
|
|
43
|
+
| {
|
|
44
|
+
kind: 'execution_lock';
|
|
45
|
+
store: ReceiptExecutionLockStore;
|
|
46
|
+
ownerExecutionId: string;
|
|
47
|
+
lockTtlMs: number;
|
|
48
|
+
waitTimeoutMs: number;
|
|
49
|
+
pollIntervalMs?: number;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export class ReceiptExecutionLockTimeoutError extends Error {
|
|
53
|
+
constructor(receiptKey: string, waitTimeoutMs: number) {
|
|
54
|
+
super(
|
|
55
|
+
`Timed out waiting ${waitTimeoutMs}ms for receipt execution lock ${receiptKey}.`,
|
|
56
|
+
);
|
|
57
|
+
this.name = 'ReceiptExecutionLockTimeoutError';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const MAX_EXECUTION_LOCK_TTL_MS = 10 * 60_000;
|
|
62
|
+
|
|
63
|
+
function assertBoundedLockPolicy(
|
|
64
|
+
policy: Extract<ReceiptMissCoordination, { kind: 'execution_lock' }>,
|
|
65
|
+
): void {
|
|
66
|
+
if (
|
|
67
|
+
!Number.isFinite(policy.lockTtlMs) ||
|
|
68
|
+
policy.lockTtlMs <= 0 ||
|
|
69
|
+
policy.lockTtlMs > MAX_EXECUTION_LOCK_TTL_MS
|
|
70
|
+
) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Receipt execution lock TTL must be between 1 and ${MAX_EXECUTION_LOCK_TTL_MS}ms.`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (!Number.isFinite(policy.waitTimeoutMs) || policy.waitTimeoutMs <= 0) {
|
|
76
|
+
throw new Error('Receipt execution lock wait timeout must be positive.');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function sleep(ms: number): Promise<void> {
|
|
81
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function executeAndPublish<T>(input: {
|
|
85
|
+
receiptKey: string;
|
|
86
|
+
cache: CompletedReceiptCache<T>;
|
|
87
|
+
execute: () => Promise<T>;
|
|
88
|
+
now: () => number;
|
|
89
|
+
receiptTtlMs?: number | null;
|
|
90
|
+
}): Promise<T> {
|
|
91
|
+
const output = await input.execute();
|
|
92
|
+
const now = input.now();
|
|
93
|
+
const receipt = await input.cache.putIfAbsent({
|
|
94
|
+
key: input.receiptKey,
|
|
95
|
+
output,
|
|
96
|
+
createdAt: new Date(now).toISOString(),
|
|
97
|
+
...(input.receiptTtlMs
|
|
98
|
+
? { expiresAt: new Date(now + input.receiptTtlMs).toISOString() }
|
|
99
|
+
: {}),
|
|
100
|
+
});
|
|
101
|
+
return receipt.output;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Execute one semantic operation against an immutable completed-receipt cache.
|
|
106
|
+
*
|
|
107
|
+
* Providers with native idempotency do not need a Deepline execution lock:
|
|
108
|
+
* concurrent misses may dispatch with the same provider idempotency key, then
|
|
109
|
+
* converge on the first immutable cache insert. A separate temporary lock is
|
|
110
|
+
* reserved for actions explicitly classified as dangerous non-idempotent side
|
|
111
|
+
* effects. Ordinary enrichment misses may do bounded duplicate work and
|
|
112
|
+
* converge on the first published receipt.
|
|
113
|
+
*/
|
|
114
|
+
export async function executeWithCompletedReceiptCache<T>(input: {
|
|
115
|
+
receiptKey: string;
|
|
116
|
+
cache: CompletedReceiptCache<T>;
|
|
117
|
+
missCoordination: ReceiptMissCoordination;
|
|
118
|
+
execute: () => Promise<T>;
|
|
119
|
+
now?: () => number;
|
|
120
|
+
receiptTtlMs?: number | null;
|
|
121
|
+
}): Promise<T> {
|
|
122
|
+
const cached = await input.cache.get(input.receiptKey);
|
|
123
|
+
if (cached) return cached.output;
|
|
124
|
+
|
|
125
|
+
const now = input.now ?? Date.now;
|
|
126
|
+
if (input.missCoordination.kind === 'provider_idempotency') {
|
|
127
|
+
return await executeAndPublish({ ...input, now });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const policy = input.missCoordination;
|
|
131
|
+
assertBoundedLockPolicy(policy);
|
|
132
|
+
const deadline = now() + policy.waitTimeoutMs;
|
|
133
|
+
const pollIntervalMs = Math.max(1, policy.pollIntervalMs ?? 100);
|
|
134
|
+
|
|
135
|
+
while (true) {
|
|
136
|
+
const lock = await policy.store.tryAcquire({
|
|
137
|
+
receiptKey: input.receiptKey,
|
|
138
|
+
ownerExecutionId: policy.ownerExecutionId,
|
|
139
|
+
expiresAt: new Date(now() + policy.lockTtlMs).toISOString(),
|
|
140
|
+
});
|
|
141
|
+
if (lock) {
|
|
142
|
+
try {
|
|
143
|
+
// The previous owner may have published between our cache read and
|
|
144
|
+
// lock acquisition. Never execute after that terminal fact exists.
|
|
145
|
+
const afterAcquire = await input.cache.get(input.receiptKey);
|
|
146
|
+
if (afterAcquire) return afterAcquire.output;
|
|
147
|
+
return await executeAndPublish({ ...input, now });
|
|
148
|
+
} finally {
|
|
149
|
+
await policy.store.release({
|
|
150
|
+
receiptKey: input.receiptKey,
|
|
151
|
+
ownerExecutionId: policy.ownerExecutionId,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const completed = await input.cache.get(input.receiptKey);
|
|
157
|
+
if (completed) return completed.output;
|
|
158
|
+
if (now() >= deadline) {
|
|
159
|
+
throw new ReceiptExecutionLockTimeoutError(
|
|
160
|
+
input.receiptKey,
|
|
161
|
+
policy.waitTimeoutMs,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
await sleep(Math.min(pollIntervalMs, Math.max(1, deadline - now())));
|
|
165
|
+
}
|
|
166
|
+
}
|