@tangle-network/agent-provider-tangle 0.13.3 → 0.14.0

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.
@@ -0,0 +1,1287 @@
1
+ import { ConfidentialAttestationSchema, ConfidentialExecutionRequestSchema, ForkedEnvironmentRefSchema, WorkspaceCheckpointRefSchema, WorkspaceCheckpointRequestSchema, WorkspaceCleanupAcknowledgementSchema, WorkspaceCleanupRequestSchema, WorkspaceForkRequestSchema, WorkspaceOperationLookupRequestSchema, WorkspaceCheckpointResultSchema, WorkspaceCheckpointLookupResultSchema, WorkspaceForkResultSchema, WorkspaceForkLookupResultSchema, canonicalCandidateDigest, confidentialExecutionVerified, sha256Bytes, } from "@tangle-network/agent-interface";
2
+ import { awaitWithSignal, boundedIdentifier, boundedString, assertBoundedJson, MAX_LIST_RESULTS, MAX_STRING_LENGTH, SANDBOX_LIST_PAGE_SIZE, } from "./tangle-contract-safety.js";
3
+ /**
4
+ * Namespace used for provider recovery metadata.
5
+ *
6
+ * The values are identity markers, not security evidence. A marker can tell
7
+ * the provider which request produced a resource, but only the Sandbox
8
+ * operation ledger and the external verifier can prove an outcome.
9
+ */
10
+ const MARKER_PREFIX = "tangle-agent-ws-v1";
11
+ /** Marker namespace used by releases before the 128-byte tag limit. */
12
+ const LEGACY_MARKER_PREFIX = "tangle-agent-sdk:workspace:v1";
13
+ const FORK_METADATA_KEY = "__tangle_agent_workspace_v1";
14
+ const MAX_MARKER_TAG_LENGTH = 128;
15
+ const MARKER_CHUNK_SIZE = 80;
16
+ const LEGACY_MARKER_CHUNK_SIZE = 240;
17
+ const MAX_MARKER_CHUNKS = 512;
18
+ /**
19
+ * Carry the verifier only when the caller supplied one. Every option type that
20
+ * accepts it is exact-optional, so an explicit `undefined` is not an absent key.
21
+ */
22
+ export function confidentialVerifierOption(verifier) {
23
+ return verifier === undefined ? {} : { confidentialAttestationVerifier: verifier };
24
+ }
25
+ /**
26
+ * Build the exact workspace contract over the managed Sandbox operations.
27
+ *
28
+ * The adapter requires list and lookup surfaces in addition to create and
29
+ * delete methods. Without recovery, it cannot safely claim durable branching.
30
+ */
31
+ export function createTangleWorkspaceBranching(options) {
32
+ const { box, client, provider } = options;
33
+ boundedIdentifier(provider, "Tangle workspace branching provider");
34
+ boundedIdentifier(box.id, "Tangle workspace branching environment id");
35
+ if (!supportsWorkspaceBranching(box, client))
36
+ return undefined;
37
+ const checkpoints = new Map();
38
+ const forks = new Map();
39
+ const cleanup = new Map();
40
+ /**
41
+ * Answer what this provider already knows about one checkpoint key.
42
+ *
43
+ * The in-process record answers first; otherwise the Sandbox inventory and
44
+ * operation ledger rebuild it after a restart. `absent` means the key has no
45
+ * resource this provider created, which is the only state where a caller may
46
+ * go on to create one.
47
+ */
48
+ const resolveCheckpoint = async (request, signal) => {
49
+ const local = checkpoints.get(request.idempotencyKey);
50
+ if (local) {
51
+ return local.request.requestDigest === request.requestDigest
52
+ ? { state: "known", record: local }
53
+ : { state: "conflict", existingRequestDigest: local.request.requestDigest };
54
+ }
55
+ const recovered = await findCheckpointByKey(box, request.idempotencyKey, signal);
56
+ if (recovered === undefined) {
57
+ return { state: "undecided", message: "Sandbox checkpoint inventory is unavailable" };
58
+ }
59
+ if (!recovered)
60
+ return { state: "absent" };
61
+ if (recovered.marker.requestDigest !== request.requestDigest) {
62
+ return { state: "conflict", existingRequestDigest: recovered.marker.requestDigest };
63
+ }
64
+ const record = checkpointRecordFromSnapshot(recovered.marker.request, recovered.snapshot);
65
+ if (!record) {
66
+ return { state: "undecided", message: "Sandbox checkpoint metadata is invalid" };
67
+ }
68
+ checkpoints.set(request.idempotencyKey, record);
69
+ return { state: "known", record };
70
+ };
71
+ /** The fork equivalent of {@link resolveCheckpoint}. */
72
+ const resolveFork = async (request, signal) => {
73
+ const local = forks.get(request.idempotencyKey);
74
+ if (local) {
75
+ return local.request.requestDigest === request.requestDigest
76
+ ? { state: "known", record: local }
77
+ : { state: "conflict", existingRequestDigest: local.request.requestDigest };
78
+ }
79
+ const recovered = await findForkByKey(client, box, provider, request.idempotencyKey, signal);
80
+ if (recovered === undefined) {
81
+ return { state: "undecided", message: "Sandbox child inventory is unavailable" };
82
+ }
83
+ if (!recovered)
84
+ return { state: "absent" };
85
+ if (recovered.marker.requestDigest !== request.requestDigest) {
86
+ return { state: "conflict", existingRequestDigest: recovered.marker.requestDigest };
87
+ }
88
+ const child = await completeForkChild(client, recovered.child, signal);
89
+ if (!child) {
90
+ return { state: "undecided", message: "Sandbox fork child identity is incomplete" };
91
+ }
92
+ const environment = await environmentFromChild(recovered.marker.request, child, provider, child.createdAt, options.confidentialAttestationVerifier, signal);
93
+ if (!environment) {
94
+ return { state: "undecided", message: "Sandbox fork child identity is incomplete" };
95
+ }
96
+ const record = { request: recovered.marker.request, environment, child: recovered.child };
97
+ forks.set(request.idempotencyKey, record);
98
+ return { state: "known", record };
99
+ };
100
+ const checkpoint = async (input, operation) => {
101
+ const request = WorkspaceCheckpointRequestSchema.parse(input);
102
+ assertCheckpointSource(request, provider, box.id);
103
+ const known = await resolveCheckpoint(request, operation?.signal);
104
+ if (known.state === "conflict") {
105
+ return checkpointConflict(request, known.existingRequestDigest);
106
+ }
107
+ if (known.state === "undecided") {
108
+ return checkpointUnknown(request, `${known.message}; retry after reconciliation`, true);
109
+ }
110
+ if (known.state === "known") {
111
+ return checkpointSuccess(request, known.record.checkpoint, "replayed");
112
+ }
113
+ const tags = checkpointMarkerTags(request);
114
+ let result;
115
+ try {
116
+ result = await awaitWithSignal(box.snapshot?.({ tags, idempotencyKey: request.idempotencyKey }), operation?.signal);
117
+ }
118
+ catch (error) {
119
+ operation?.signal?.throwIfAborted();
120
+ const conflict = await checkpointConflictFromRemote(box, request, operation?.signal);
121
+ return (conflict ??
122
+ checkpointUnknown(request, `Sandbox checkpoint outcome is unresolved: ${safeError(error)}`, true));
123
+ }
124
+ if (!result || !validSnapshotResult(result)) {
125
+ return checkpointUnknown(request, "Sandbox checkpoint returned no complete idempotent acknowledgement", true);
126
+ }
127
+ if (result.idempotency === undefined ||
128
+ (result.idempotency.outcome !== "created" &&
129
+ result.idempotency.outcome !== "replayed") ||
130
+ safeString(result.idempotency.requestDigest) === undefined) {
131
+ return checkpointUnknown(request, "Sandbox checkpoint did not report idempotency state", true);
132
+ }
133
+ const resultMarker = checkpointMarkerFromTags(result.tags, request.idempotencyKey);
134
+ if (resultMarker && resultMarker.requestDigest !== request.requestDigest) {
135
+ return checkpointConflict(request, resultMarker.requestDigest);
136
+ }
137
+ if (!resultMarker) {
138
+ return checkpointUnknown(request, "Sandbox checkpoint acknowledgement omitted its provider recovery marker", true);
139
+ }
140
+ const record = checkpointRecordFromSnapshot(request, result);
141
+ if (!record) {
142
+ return checkpointUnknown(request, "Sandbox checkpoint acknowledgement contains invalid metadata", true);
143
+ }
144
+ checkpoints.set(request.idempotencyKey, record);
145
+ return checkpointSuccess(request, record.checkpoint, result.idempotency.outcome);
146
+ };
147
+ const lookupCheckpoint = async (input, operation) => {
148
+ const request = WorkspaceOperationLookupRequestSchema.parse(input);
149
+ const known = await resolveCheckpoint(request, operation?.signal);
150
+ if (known.state === "conflict") {
151
+ return checkpointLookupConflict(request, known.existingRequestDigest);
152
+ }
153
+ if (known.state === "undecided") {
154
+ return checkpointLookupUnknown(request, known.message, true);
155
+ }
156
+ if (known.state === "known") {
157
+ return checkpointFound(request, known.record.checkpoint);
158
+ }
159
+ try {
160
+ const lookup = await awaitWithSignal(box.getSnapshotOperation?.(request.idempotencyKey, { tags: [] }), operation?.signal);
161
+ const settled = lookupOutcomeFromSandbox(lookup, "checkpoint");
162
+ return settled.absent
163
+ ? checkpointNotFound(request)
164
+ : checkpointLookupUnknown(request, settled.message, settled.retryable);
165
+ }
166
+ catch (error) {
167
+ operation?.signal?.throwIfAborted();
168
+ return checkpointLookupUnknown(request, `Sandbox checkpoint lookup failed: ${safeError(error)}`, true);
169
+ }
170
+ };
171
+ const deleteCheckpoint = async (input, operation) => {
172
+ const request = WorkspaceCleanupRequestSchema.parse(input);
173
+ if (request.kind !== "checkpoint") {
174
+ throw new Error("Tangle checkpoint cleanup received a fork request");
175
+ }
176
+ assertCleanupProvider(request, provider);
177
+ const previous = cleanup.get(request.operationId);
178
+ if (previous) {
179
+ if (previous.requestDigest !== request.requestDigest) {
180
+ return cleanupConflict(request, previous.requestDigest);
181
+ }
182
+ if (previous.acknowledgement.status === "in_use") {
183
+ // A dependency response binds the operation id, but it is not
184
+ // terminal. Re-scan children so the same request can converge after
185
+ // callers destroy the blocking fork.
186
+ }
187
+ else if (previous.acknowledgement.status === "deleted") {
188
+ return cleanupAlreadyAbsent(request);
189
+ }
190
+ else {
191
+ return previous.acknowledgement;
192
+ }
193
+ }
194
+ const blocking = await findBlockingForks(box, client, provider, request.targetId, operation?.signal);
195
+ if (blocking === undefined) {
196
+ return cleanupUnknown(request, "Sandbox child inventory is unavailable; deletion was not attempted", true);
197
+ }
198
+ if (blocking.length > 0) {
199
+ const acknowledgement = cleanupInUse(request, blocking);
200
+ cleanup.set(request.operationId, {
201
+ requestDigest: request.requestDigest,
202
+ acknowledgement,
203
+ });
204
+ return acknowledgement;
205
+ }
206
+ const known = await findManagedCheckpoint(box, provider, request.targetId, undefined, operation?.signal);
207
+ if (known === "unknown") {
208
+ return cleanupUnknown(request, "Sandbox checkpoint inventory is unavailable; deletion was not attempted", true);
209
+ }
210
+ if (known === false) {
211
+ const acknowledgement = cleanupAlreadyAbsent(request);
212
+ cleanup.set(request.operationId, {
213
+ requestDigest: request.requestDigest,
214
+ acknowledgement,
215
+ });
216
+ return acknowledgement;
217
+ }
218
+ let result;
219
+ try {
220
+ result = await awaitWithSignal(box.deleteSnapshot?.(request.targetId), operation?.signal);
221
+ }
222
+ catch (error) {
223
+ operation?.signal?.throwIfAborted();
224
+ return cleanupTransportFailure(request, `Sandbox checkpoint deletion failed: ${safeError(error)}`, true);
225
+ }
226
+ const outcome = result &&
227
+ result.snapshotId === request.targetId &&
228
+ (result.outcome === "deleted" || result.outcome === "already_absent")
229
+ ? result.outcome
230
+ : "unknown";
231
+ if (outcome !== "deleted" && outcome !== "already_absent") {
232
+ return cleanupUnknown(request, "Sandbox did not attest checkpoint deletion", true);
233
+ }
234
+ const acknowledgement = outcome === "deleted"
235
+ ? cleanupDeleted(request)
236
+ : cleanupAlreadyAbsent(request);
237
+ forgetRecords(checkpoints, (record) => record.snapshotId === request.targetId);
238
+ cleanup.set(request.operationId, {
239
+ requestDigest: request.requestDigest,
240
+ acknowledgement,
241
+ });
242
+ return acknowledgement;
243
+ };
244
+ const fork = async (input, operation) => {
245
+ const request = WorkspaceForkRequestSchema.parse(input);
246
+ assertForkSource(request, provider, box.id);
247
+ if (request.confidential?.requested === true &&
248
+ (typeof options.confidentialAttestationVerifier !== "function" ||
249
+ typeof box.getTeeAttestation !== "function")) {
250
+ return forkUnknown(request, "Confidential fork requires a trusted verifier and Sandbox attestation support", false);
251
+ }
252
+ const known = await resolveFork(request, operation?.signal);
253
+ if (known.state === "conflict") {
254
+ return forkConflict(request, known.existingRequestDigest);
255
+ }
256
+ if (known.state === "undecided") {
257
+ return forkUnknown(request, `${known.message}; retry after reconciliation`, true);
258
+ }
259
+ if (known.state === "known") {
260
+ return forkSuccess(request, known.record.environment, "replayed");
261
+ }
262
+ const checkpoint = [...checkpoints.values()].some((record) => canonicalCandidateDigest(record.checkpoint) ===
263
+ canonicalCandidateDigest(request.checkpoint))
264
+ ? true
265
+ : await findManagedCheckpoint(box, provider, request.checkpoint.checkpointId, request.checkpoint, operation?.signal);
266
+ if (checkpoint !== true) {
267
+ return forkUnknown(request, checkpoint === false
268
+ ? "Requested checkpoint is absent"
269
+ : "Sandbox checkpoint inventory is unavailable", true);
270
+ }
271
+ const metadata = forkMarkerMetadata(request);
272
+ let result;
273
+ try {
274
+ result = await awaitWithSignal(box.fork?.(1, {
275
+ metadata,
276
+ idempotencyKey: request.idempotencyKey,
277
+ }), operation?.signal);
278
+ }
279
+ catch (error) {
280
+ operation?.signal?.throwIfAborted();
281
+ const conflict = await forkConflictFromRemote(client, box, provider, request, options.confidentialAttestationVerifier, operation?.signal);
282
+ return (conflict ??
283
+ forkUnknown(request, `Sandbox fork outcome is unresolved: ${safeError(error)}`, true));
284
+ }
285
+ if (!result ||
286
+ !validForkResult(result) ||
287
+ result.idempotency === undefined ||
288
+ (result.idempotency.outcome !== "created" &&
289
+ result.idempotency.outcome !== "replayed") ||
290
+ safeString(result.idempotency.requestDigest) === undefined) {
291
+ return forkUnknown(request, "Sandbox fork returned no complete idempotent acknowledgement", true);
292
+ }
293
+ if (result.children.length !== 1 || result.complete !== true) {
294
+ return forkUnknown(request, "Sandbox fork did not materialize exactly one complete child", true);
295
+ }
296
+ const returnedChild = result.children[0];
297
+ const child = await completeForkChild(client, returnedChild, operation?.signal);
298
+ if (!child) {
299
+ return forkUnknown(request, "Sandbox fork returned a child without a complete identity", true);
300
+ }
301
+ const childMarker = forkMarkerFromMetadata(child.metadata, request.idempotencyKey);
302
+ if (childMarker && childMarker.requestDigest !== request.requestDigest) {
303
+ return forkConflict(request, childMarker.requestDigest);
304
+ }
305
+ if (!childMarker) {
306
+ return forkUnknown(request, "Sandbox fork acknowledgement omitted its provider recovery marker", true);
307
+ }
308
+ const environment = await environmentFromChild(request, child, provider, child.createdAt, options.confidentialAttestationVerifier, operation?.signal);
309
+ if (!environment) {
310
+ return forkUnknown(request, "Sandbox fork returned a child without a valid identity", true);
311
+ }
312
+ const record = { request, environment, child };
313
+ forks.set(request.idempotencyKey, record);
314
+ return forkSuccess(request, environment, result.idempotency.outcome);
315
+ };
316
+ const lookupFork = async (input, operation) => {
317
+ const request = WorkspaceOperationLookupRequestSchema.parse(input);
318
+ const known = await resolveFork(request, operation?.signal);
319
+ if (known.state === "conflict") {
320
+ return forkLookupConflict(request, known.existingRequestDigest);
321
+ }
322
+ if (known.state === "undecided") {
323
+ return forkLookupUnknown(request, known.message, true);
324
+ }
325
+ if (known.state === "known") {
326
+ return forkFound(request, known.record.environment);
327
+ }
328
+ try {
329
+ const lookup = await awaitWithSignal(box.getForkOperation?.(request.idempotencyKey, {
330
+ count: 1,
331
+ metadata: {},
332
+ }), operation?.signal);
333
+ const settled = lookupOutcomeFromSandbox(lookup, "fork");
334
+ return settled.absent
335
+ ? forkNotFound(request)
336
+ : forkLookupUnknown(request, settled.message, settled.retryable);
337
+ }
338
+ catch (error) {
339
+ operation?.signal?.throwIfAborted();
340
+ return forkLookupUnknown(request, `Sandbox fork lookup failed: ${safeError(error)}`, true);
341
+ }
342
+ };
343
+ const destroyFork = async (input, operation) => {
344
+ const request = WorkspaceCleanupRequestSchema.parse(input);
345
+ if (request.kind !== "fork") {
346
+ throw new Error("Tangle fork cleanup received a checkpoint request");
347
+ }
348
+ assertCleanupProvider(request, provider);
349
+ const previous = cleanup.get(request.operationId);
350
+ if (previous) {
351
+ if (previous.requestDigest !== request.requestDigest) {
352
+ return cleanupConflict(request, previous.requestDigest);
353
+ }
354
+ if (previous.acknowledgement.status === "deleted") {
355
+ return cleanupAlreadyAbsent(request);
356
+ }
357
+ return previous.acknowledgement;
358
+ }
359
+ const localFork = [...forks.values()].find((record) => record.environment.environmentId === request.targetId);
360
+ const child = localFork?.child ??
361
+ (await findForkChildById(client, box, provider, request.targetId, operation?.signal));
362
+ if (child === undefined) {
363
+ return cleanupUnknown(request, "Sandbox child inventory is unavailable; destruction was not attempted", true);
364
+ }
365
+ if (child === null) {
366
+ const acknowledgement = cleanupAlreadyAbsent(request);
367
+ cleanup.set(request.operationId, {
368
+ requestDigest: request.requestDigest,
369
+ acknowledgement,
370
+ });
371
+ return acknowledgement;
372
+ }
373
+ let result;
374
+ try {
375
+ result = (await awaitWithSignal(child.delete?.(), operation?.signal));
376
+ }
377
+ catch (error) {
378
+ operation?.signal?.throwIfAborted();
379
+ return cleanupTransportFailure(request, `Sandbox fork destruction failed: ${safeError(error)}`, true);
380
+ }
381
+ const outcome = result &&
382
+ result.sandboxId === request.targetId &&
383
+ (result.outcome === "destroyed" || result.outcome === "already_absent")
384
+ ? result.outcome
385
+ : "unknown";
386
+ if (outcome !== "destroyed" && outcome !== "already_absent") {
387
+ return cleanupUnknown(request, "Sandbox did not attest fork destruction", true);
388
+ }
389
+ const acknowledgement = outcome === "destroyed"
390
+ ? cleanupDeleted(request)
391
+ : cleanupAlreadyAbsent(request);
392
+ forgetRecords(forks, (record) => record.environment.environmentId === request.targetId);
393
+ cleanup.set(request.operationId, {
394
+ requestDigest: request.requestDigest,
395
+ acknowledgement,
396
+ });
397
+ return acknowledgement;
398
+ };
399
+ return {
400
+ checkpoint,
401
+ lookupCheckpoint,
402
+ deleteCheckpoint,
403
+ fork,
404
+ lookupFork,
405
+ destroyFork,
406
+ };
407
+ }
408
+ /** Capability support requires every operation used by recovery and cleanup. */
409
+ export function supportsWorkspaceBranching(box, client) {
410
+ return (typeof client.list === "function" &&
411
+ typeof client.get === "function" &&
412
+ typeof box.snapshot === "function" &&
413
+ typeof box.listSnapshots === "function" &&
414
+ typeof box.deleteSnapshot === "function" &&
415
+ typeof box.getSnapshotOperation === "function" &&
416
+ typeof box.fork === "function" &&
417
+ typeof box.getForkOperation === "function");
418
+ }
419
+ /** Drop every in-process record for a resource the platform no longer holds. */
420
+ function forgetRecords(records, matches) {
421
+ for (const [key, record] of records) {
422
+ if (matches(record))
423
+ records.delete(key);
424
+ }
425
+ }
426
+ function assertCheckpointSource(request, provider, environmentId) {
427
+ if (request.source.provider !== provider ||
428
+ request.source.environmentId !== environmentId) {
429
+ throw new Error("Tangle checkpoint source does not belong to this environment");
430
+ }
431
+ }
432
+ function assertForkSource(request, provider, environmentId) {
433
+ if (request.checkpoint.provider !== provider ||
434
+ request.checkpoint.source.provider !== provider ||
435
+ request.checkpoint.source.environmentId !== environmentId) {
436
+ throw new Error("Tangle fork checkpoint does not belong to this environment");
437
+ }
438
+ }
439
+ function assertCleanupProvider(request, provider) {
440
+ if (request.provider !== provider) {
441
+ throw new Error("Tangle cleanup provider does not match this provider");
442
+ }
443
+ }
444
+ function checkpointRecordFromSnapshot(request, snapshot) {
445
+ try {
446
+ const createdAt = isoDate(snapshot.createdAt);
447
+ const checkpoint = WorkspaceCheckpointRefSchema.parse({
448
+ checkpointId: boundedIdentifier(snapshot.snapshotId, "Tangle checkpoint id"),
449
+ provider: request.source.provider,
450
+ source: request.source,
451
+ idempotencyKey: request.idempotencyKey,
452
+ requestDigest: request.requestDigest,
453
+ createdAt,
454
+ ...(request.metadata === undefined
455
+ ? {}
456
+ : { metadata: cloneJson(request.metadata) }),
457
+ });
458
+ return {
459
+ request,
460
+ checkpoint,
461
+ snapshotId: checkpoint.checkpointId,
462
+ };
463
+ }
464
+ catch {
465
+ return undefined;
466
+ }
467
+ }
468
+ async function environmentFromChild(request, child, provider, createdAt, verifier, signal) {
469
+ signal?.throwIfAborted();
470
+ const environmentId = safeIdentifier(child.id);
471
+ if (!environmentId || environmentId === request.checkpoint.source.environmentId) {
472
+ return undefined;
473
+ }
474
+ if (createdAt === undefined)
475
+ return undefined;
476
+ let normalizedCreatedAt;
477
+ try {
478
+ normalizedCreatedAt = isoDate(createdAt);
479
+ }
480
+ catch {
481
+ return undefined;
482
+ }
483
+ let metadata;
484
+ try {
485
+ metadata =
486
+ request.metadata === undefined ? undefined : cloneJson(request.metadata);
487
+ }
488
+ catch {
489
+ return undefined;
490
+ }
491
+ let attestation;
492
+ if (request.confidential?.requested === true &&
493
+ typeof verifier === "function") {
494
+ attestation = await confidentialAttestationForChild(request, child, provider, verifier, signal);
495
+ }
496
+ const environment = ForkedEnvironmentRefSchema.safeParse({
497
+ provider,
498
+ environmentId,
499
+ sourceEnvironmentId: request.checkpoint.source.environmentId,
500
+ source: request.checkpoint.source,
501
+ sourceCheckpointId: request.checkpoint.checkpointId,
502
+ idempotencyKey: request.idempotencyKey,
503
+ requestDigest: request.requestDigest,
504
+ createdAt: normalizedCreatedAt,
505
+ placement: request.placement,
506
+ confidentialRequested: request.confidential?.requested === true,
507
+ ...(attestation === undefined ? {} : { confidentialAttestation: attestation }),
508
+ ...(attestation === undefined ? {} : { confidential: true }),
509
+ ...(metadata === undefined ? {} : { metadata }),
510
+ });
511
+ signal?.throwIfAborted();
512
+ return environment.success ? environment.data : undefined;
513
+ }
514
+ async function confidentialAttestationForChild(request, child, provider, verifier, signal) {
515
+ const confidential = ConfidentialExecutionRequestSchema.parse(request.confidential);
516
+ if (!confidential.requested || typeof child.getTeeAttestation !== "function") {
517
+ return undefined;
518
+ }
519
+ let response;
520
+ try {
521
+ response = await awaitWithSignal(child.getTeeAttestation({ attestationNonce: confidential.nonce }), signal);
522
+ }
523
+ catch {
524
+ signal?.throwIfAborted();
525
+ return undefined;
526
+ }
527
+ if (!response ||
528
+ response.sandbox_id !== child.id ||
529
+ !validTeeReport(response.attestation) ||
530
+ safeIdentifier(response.attestationNonce) === undefined ||
531
+ response.attestationNonce !== confidential.nonce) {
532
+ return undefined;
533
+ }
534
+ const measurement = sha256Bytes(Uint8Array.from(response.attestation.measurement));
535
+ const quote = encodeJson(response.attestation);
536
+ if (quote === undefined)
537
+ return undefined;
538
+ let verifiedAt;
539
+ try {
540
+ verifiedAt = new Date(response.attestation.timestamp * 1_000).toISOString();
541
+ }
542
+ catch {
543
+ return undefined;
544
+ }
545
+ const expected = {
546
+ provider,
547
+ environmentId: child.id,
548
+ source: request.checkpoint.source,
549
+ requestDigest: request.requestDigest,
550
+ confidentialRequested: true,
551
+ };
552
+ const material = {
553
+ provider,
554
+ requested: true,
555
+ nonce: confidential.nonce,
556
+ measurement,
557
+ environmentId: child.id,
558
+ source: request.checkpoint.source,
559
+ requestDigest: request.requestDigest,
560
+ profileDigest: confidential.profileDigest,
561
+ policy: confidential.policy,
562
+ quote,
563
+ verifiedAt,
564
+ };
565
+ let verification;
566
+ try {
567
+ const provisional = {
568
+ ...material,
569
+ providerKeyId: "unverified",
570
+ providerSignature: "unverified",
571
+ };
572
+ const provisionalResult = ConfidentialAttestationSchema.safeParse(provisional);
573
+ if (!provisionalResult.success)
574
+ return undefined;
575
+ verification = await verifier({
576
+ report: response.attestation,
577
+ expected,
578
+ attestation: provisionalResult.data,
579
+ });
580
+ }
581
+ catch {
582
+ return undefined;
583
+ }
584
+ if (verification === null ||
585
+ !verification ||
586
+ !safeIdentifier(verification.providerKeyId) ||
587
+ !safeString(verification.providerSignature) ||
588
+ verification.providerSignature === quote ||
589
+ (verification.measurement !== undefined && verification.measurement !== measurement)) {
590
+ return undefined;
591
+ }
592
+ const attestation = ConfidentialAttestationSchema.safeParse({
593
+ ...material,
594
+ providerKeyId: verification.providerKeyId,
595
+ providerSignature: verification.providerSignature,
596
+ });
597
+ if (!attestation.success)
598
+ return undefined;
599
+ // Run the canonical binding checks as a final local fail-closed assertion.
600
+ return confidentialExecutionVerified({
601
+ request: confidential,
602
+ environment: expected,
603
+ attestation: attestation.data,
604
+ verifyProviderAttestation: () => true,
605
+ })
606
+ ? attestation.data
607
+ : undefined;
608
+ }
609
+ function validTeeReport(report) {
610
+ return !!report &&
611
+ safeString(report.tee_type) !== undefined &&
612
+ Array.isArray(report.evidence) &&
613
+ report.evidence.length <= MAX_STRING_LENGTH &&
614
+ report.evidence.every((value) => Number.isInteger(value) && value >= 0 && value <= 255) &&
615
+ Array.isArray(report.measurement) &&
616
+ report.measurement.length <= MAX_STRING_LENGTH &&
617
+ report.measurement.every((value) => Number.isInteger(value) && value >= 0 && value <= 255) &&
618
+ Number.isFinite(report.timestamp) &&
619
+ report.timestamp > 0;
620
+ }
621
+ function validSnapshotResult(result) {
622
+ return !!result &&
623
+ safeIdentifier(result.snapshotId) !== undefined &&
624
+ validDate(result.createdAt) &&
625
+ Array.isArray(result.tags) &&
626
+ result.tags.every((tag) => safeString(tag) !== undefined);
627
+ }
628
+ function validSnapshotInfo(snapshot, sandboxId) {
629
+ return (validSnapshotResult(snapshot) &&
630
+ safeIdentifier(snapshot.sandboxId) !== undefined &&
631
+ (sandboxId === undefined || snapshot.sandboxId === sandboxId));
632
+ }
633
+ function validForkResult(result) {
634
+ return !!result &&
635
+ Array.isArray(result.children) &&
636
+ result.children.every((child) => child !== null &&
637
+ typeof child === "object" &&
638
+ safeIdentifier(child.id) !== undefined) &&
639
+ result.requestedCount === 1 &&
640
+ result.materializedCount === result.children.length &&
641
+ typeof result.complete === "boolean";
642
+ }
643
+ function checkpointMarkerTags(request) {
644
+ const marker = {
645
+ version: 1,
646
+ kind: "checkpoint",
647
+ idempotencyKey: request.idempotencyKey,
648
+ requestDigest: request.requestDigest,
649
+ request,
650
+ };
651
+ return markerTags("checkpoint", request.idempotencyKey, request.requestDigest, marker);
652
+ }
653
+ /** Rebuild the exact tags used by the release before the current safe format. */
654
+ function legacyCheckpointMarkerTags(request) {
655
+ const marker = {
656
+ version: 1,
657
+ kind: "checkpoint",
658
+ idempotencyKey: request.idempotencyKey,
659
+ requestDigest: request.requestDigest,
660
+ request,
661
+ };
662
+ const encoded = encodeJson(marker);
663
+ if (encoded === undefined)
664
+ throw new Error("workspace marker is not JSON serializable");
665
+ const base = `${LEGACY_MARKER_PREFIX}:checkpoint`;
666
+ const chunks = splitIntoChunks(encoded, LEGACY_MARKER_CHUNK_SIZE);
667
+ if (chunks.length > MAX_MARKER_CHUNKS) {
668
+ throw new Error("workspace marker exceeds the recovery bound");
669
+ }
670
+ return [
671
+ `${base}:key:${encodeText(request.idempotencyKey)}`,
672
+ `${base}:digest:${request.requestDigest}`,
673
+ ...chunks.map((chunk, index) => `${base}:material:${index}:${chunks.length}:${chunk}`),
674
+ ];
675
+ }
676
+ function forkMarkerMetadata(request) {
677
+ if (request.metadata && Object.hasOwn(request.metadata, FORK_METADATA_KEY)) {
678
+ throw new Error(`fork metadata reserves ${FORK_METADATA_KEY}`);
679
+ }
680
+ const marker = {
681
+ version: 1,
682
+ kind: "fork",
683
+ idempotencyKey: request.idempotencyKey,
684
+ requestDigest: request.requestDigest,
685
+ request,
686
+ };
687
+ assertBoundedJson(marker);
688
+ return {
689
+ ...(request.metadata === undefined ? {} : cloneJson(request.metadata)),
690
+ [FORK_METADATA_KEY]: marker,
691
+ };
692
+ }
693
+ /**
694
+ * Ask the Sandbox operation ledger whether a marked checkpoint settled.
695
+ *
696
+ * A marker only names a candidate resource. Nothing is returned to a caller
697
+ * until the ledger reports the operation succeeded.
698
+ */
699
+ async function checkpointOperationSucceeded(box, marker, signal) {
700
+ const lookup = await awaitWithSignal(box.getSnapshotOperation?.(marker.idempotencyKey, {
701
+ tags: marker.legacy
702
+ ? legacyCheckpointMarkerTags(marker.request)
703
+ : checkpointMarkerTags(marker.request),
704
+ }), signal);
705
+ return (lookup?.outcome === "found" &&
706
+ lookup.kind === "checkpoint" &&
707
+ lookup.state === "succeeded");
708
+ }
709
+ /** The fork equivalent of {@link checkpointOperationSucceeded}. */
710
+ async function forkOperationSucceeded(box, marker, signal) {
711
+ const lookup = await awaitWithSignal(box.getForkOperation?.(marker.idempotencyKey, {
712
+ count: 1,
713
+ metadata: forkMarkerMetadata(marker.request),
714
+ }), signal);
715
+ return (lookup?.outcome === "found" &&
716
+ lookup.kind === "fork" &&
717
+ lookup.state === "succeeded");
718
+ }
719
+ function markerTags(kind, idempotencyKey, requestDigest, marker) {
720
+ const encoded = encodeJson(marker);
721
+ if (encoded === undefined)
722
+ throw new Error("workspace marker is not JSON serializable");
723
+ const base = `${MARKER_PREFIX}-${kind}`;
724
+ const chunks = split(encoded);
725
+ if (chunks.length > MAX_MARKER_CHUNKS) {
726
+ throw new Error("workspace marker exceeds the recovery bound");
727
+ }
728
+ return [
729
+ `${base}-key-${markerKeyDigest(idempotencyKey).replace(":", "-")}`,
730
+ `${base}-digest-${requestDigest.replace(":", "-")}`,
731
+ ...chunks.map((chunk, index) => `${base}-material-${index}-${chunks.length}-${chunk}`),
732
+ ].map((tag) => {
733
+ if (Buffer.byteLength(tag, "utf8") > MAX_MARKER_TAG_LENGTH) {
734
+ throw new Error("workspace marker tag exceeds the platform bound");
735
+ }
736
+ return tag;
737
+ });
738
+ }
739
+ async function findCheckpointByKey(box, key, signal) {
740
+ let snapshots;
741
+ try {
742
+ const listed = await awaitWithSignal(box.listSnapshots?.(), signal);
743
+ if (!Array.isArray(listed))
744
+ return undefined;
745
+ snapshots = listed;
746
+ }
747
+ catch {
748
+ signal?.throwIfAborted();
749
+ return undefined;
750
+ }
751
+ if (!Array.isArray(snapshots) || snapshots.length > MAX_LIST_RESULTS) {
752
+ return undefined;
753
+ }
754
+ let unresolved = false;
755
+ for (const snapshot of snapshots) {
756
+ if (!validSnapshotInfo(snapshot, box.id))
757
+ return undefined;
758
+ const marker = checkpointMarkerFromTags(snapshot.tags, key);
759
+ if (!marker)
760
+ continue;
761
+ try {
762
+ if (await checkpointOperationSucceeded(box, marker, signal)) {
763
+ return { snapshot, marker };
764
+ }
765
+ unresolved = true;
766
+ }
767
+ catch {
768
+ signal?.throwIfAborted();
769
+ return undefined;
770
+ }
771
+ }
772
+ return unresolved ? undefined : null;
773
+ }
774
+ /**
775
+ * Confirm that one snapshot id is a settled checkpoint this provider created.
776
+ *
777
+ * `expected` binds the answer to a specific checkpoint reference. A reference
778
+ * that does not match its marker is absent, not unknown: the caller supplied a
779
+ * checkpoint this source never produced.
780
+ */
781
+ async function findManagedCheckpoint(box, provider, id, expected, signal) {
782
+ try {
783
+ const snapshots = await awaitWithSignal(box.listSnapshots?.(), signal);
784
+ if (!Array.isArray(snapshots) || snapshots.length > MAX_LIST_RESULTS) {
785
+ return "unknown";
786
+ }
787
+ const snapshot = snapshots.find((candidate) => candidate.snapshotId === id);
788
+ if (!snapshot)
789
+ return false;
790
+ if (!validSnapshotInfo(snapshot, box.id))
791
+ return "unknown";
792
+ const marker = checkpointMarkerFromTags(snapshot.tags, expected?.idempotencyKey);
793
+ if (!marker)
794
+ return expected ? false : "unknown";
795
+ if (marker.request.source.provider !== provider ||
796
+ marker.request.source.environmentId !== box.id) {
797
+ return expected ? false : "unknown";
798
+ }
799
+ if (expected &&
800
+ (marker.requestDigest !== expected.requestDigest ||
801
+ canonicalCandidateDigest(marker.request.source) !==
802
+ canonicalCandidateDigest(expected.source))) {
803
+ return false;
804
+ }
805
+ return (await checkpointOperationSucceeded(box, marker, signal)) ? true : "unknown";
806
+ }
807
+ catch {
808
+ signal?.throwIfAborted();
809
+ return "unknown";
810
+ }
811
+ }
812
+ async function findForkByKey(client, box, provider, key, signal) {
813
+ const candidates = await listMarkedForkChildren(client, box, provider, key, signal);
814
+ if (candidates === undefined)
815
+ return undefined;
816
+ let unresolved = false;
817
+ for (const candidate of candidates) {
818
+ try {
819
+ if (await forkOperationSucceeded(box, candidate.marker, signal))
820
+ return candidate;
821
+ unresolved = true;
822
+ }
823
+ catch {
824
+ signal?.throwIfAborted();
825
+ return undefined;
826
+ }
827
+ }
828
+ return unresolved ? undefined : null;
829
+ }
830
+ async function findForkChildById(client, box, provider, id, signal) {
831
+ try {
832
+ if (typeof client.get !== "function")
833
+ return undefined;
834
+ const child = await awaitWithSignal(client.get(id, signal ? { signal } : undefined), signal);
835
+ if (child === null)
836
+ return null;
837
+ if (child.id !== id)
838
+ return undefined;
839
+ const marker = forkMarkerFromMetadata(child.metadata);
840
+ if (!marker || !markerBelongsToSource(marker, provider, box.id))
841
+ return undefined;
842
+ return (await forkOperationSucceeded(box, marker, signal)) ? child : undefined;
843
+ }
844
+ catch {
845
+ signal?.throwIfAborted();
846
+ return undefined;
847
+ }
848
+ }
849
+ /**
850
+ * Resolve a complete child identity when an inventory entry omits its time.
851
+ *
852
+ * The current Sandbox SDK includes `createdAt` on branch children. A provider
853
+ * wrapper may omit it, so recover the same child by id before claiming a
854
+ * durable environment instead of inventing a timestamp.
855
+ */
856
+ async function completeForkChild(client, child, signal) {
857
+ if (child.createdAt !== undefined)
858
+ return child;
859
+ if (typeof client.get !== "function" || safeIdentifier(child.id) === undefined) {
860
+ return undefined;
861
+ }
862
+ try {
863
+ const resolved = await awaitWithSignal(client.get(child.id, signal ? { signal } : undefined), signal);
864
+ if (!resolved || resolved.id !== child.id || resolved.createdAt === undefined) {
865
+ return undefined;
866
+ }
867
+ return resolved;
868
+ }
869
+ catch {
870
+ signal?.throwIfAborted();
871
+ return undefined;
872
+ }
873
+ }
874
+ async function findBlockingForks(box, client, provider, checkpointId, signal) {
875
+ const candidates = await listMarkedForkChildren(client, box, provider, undefined, signal);
876
+ if (candidates === undefined)
877
+ return undefined;
878
+ const blocking = new Set();
879
+ for (const { child, marker } of candidates) {
880
+ if (marker.request.checkpoint.checkpointId !== checkpointId)
881
+ continue;
882
+ try {
883
+ // A candidate that cannot be confirmed leaves the dependency set
884
+ // unknown, so cleanup must not proceed on a partial answer.
885
+ if (!(await forkOperationSucceeded(box, marker, signal)))
886
+ return undefined;
887
+ blocking.add(child.id);
888
+ }
889
+ catch {
890
+ signal?.throwIfAborted();
891
+ return undefined;
892
+ }
893
+ }
894
+ return [...blocking].sort();
895
+ }
896
+ /**
897
+ * Read the complete account inventory through Sandbox offset pages.
898
+ *
899
+ * Sandbox returns only an array, so a short page is the terminal marker. A
900
+ * full page requires another request; stopping there would make recovery
901
+ * report a false absence. Duplicate ids or an inventory above the safety
902
+ * bound make completeness unknowable and therefore fail closed.
903
+ */
904
+ async function listAllSandboxChildren(client, signal) {
905
+ if (typeof client.list !== "function")
906
+ return undefined;
907
+ const children = [];
908
+ const seen = new Set();
909
+ let offset = 0;
910
+ while (true) {
911
+ signal?.throwIfAborted();
912
+ let page;
913
+ try {
914
+ const listed = await awaitWithSignal(client.list({
915
+ scope: "all",
916
+ limit: SANDBOX_LIST_PAGE_SIZE,
917
+ offset,
918
+ }), signal);
919
+ if (!Array.isArray(listed) || listed.length > SANDBOX_LIST_PAGE_SIZE) {
920
+ return undefined;
921
+ }
922
+ page = listed;
923
+ }
924
+ catch {
925
+ signal?.throwIfAborted();
926
+ return undefined;
927
+ }
928
+ for (const child of page) {
929
+ if (!child ||
930
+ typeof child !== "object" ||
931
+ safeIdentifier(child.id) === undefined ||
932
+ seen.has(child.id)) {
933
+ return undefined;
934
+ }
935
+ seen.add(child.id);
936
+ }
937
+ if (children.length + page.length > MAX_LIST_RESULTS)
938
+ return undefined;
939
+ children.push(...page);
940
+ if (page.length < SANDBOX_LIST_PAGE_SIZE)
941
+ return children;
942
+ if (offset > Number.MAX_SAFE_INTEGER - SANDBOX_LIST_PAGE_SIZE) {
943
+ return undefined;
944
+ }
945
+ offset += SANDBOX_LIST_PAGE_SIZE;
946
+ }
947
+ }
948
+ /**
949
+ * Read every account child that carries a fork marker this source produced.
950
+ *
951
+ * The scan is the shared front half of fork recovery and cleanup. It returns
952
+ * undefined when the inventory itself cannot be trusted, so both callers fail
953
+ * closed on the same condition.
954
+ */
955
+ async function listMarkedForkChildren(client, box, provider, key, signal) {
956
+ const children = await listAllSandboxChildren(client, signal);
957
+ if (children === undefined)
958
+ return undefined;
959
+ const marked = [];
960
+ for (const child of children) {
961
+ if (!child || typeof child !== "object" || safeIdentifier(child.id) === undefined) {
962
+ return undefined;
963
+ }
964
+ if (child.id === box.id)
965
+ continue;
966
+ const marker = forkMarkerFromMetadata(child.metadata, key);
967
+ if (!marker || !markerBelongsToSource(marker, provider, box.id))
968
+ continue;
969
+ marked.push({ child, marker });
970
+ }
971
+ return marked;
972
+ }
973
+ function markerBelongsToSource(marker, provider, sourceEnvironmentId) {
974
+ return (marker.request.checkpoint.provider === provider &&
975
+ marker.request.checkpoint.source.environmentId === sourceEnvironmentId);
976
+ }
977
+ function checkpointMarkerFromTags(tags, key) {
978
+ if (!Array.isArray(tags) ||
979
+ tags.length > MAX_MARKER_CHUNKS + 3 ||
980
+ !tags.every((tag) => safeString(tag) !== undefined)) {
981
+ return undefined;
982
+ }
983
+ const currentBase = `${MARKER_PREFIX}-checkpoint`;
984
+ const legacyBase = `${LEGACY_MARKER_PREFIX}:checkpoint`;
985
+ const hasCurrentTags = tags.some((tag) => tag.startsWith(`${currentBase}-`));
986
+ const hasLegacyTags = tags.some((tag) => tag.startsWith(`${legacyBase}:`));
987
+ if (hasCurrentTags === hasLegacyTags)
988
+ return undefined;
989
+ if (hasLegacyTags)
990
+ return legacyCheckpointMarkerFromTags(tags, key, legacyBase);
991
+ if (tags.some((tag) => Buffer.byteLength(tag, "utf8") > MAX_MARKER_TAG_LENGTH)) {
992
+ return undefined;
993
+ }
994
+ return currentCheckpointMarkerFromTags(tags, key, currentBase);
995
+ }
996
+ function currentCheckpointMarkerFromTags(tags, key, base) {
997
+ const keyTag = tags.find((tag) => tag.startsWith(`${base}-key-`));
998
+ if (keyTag &&
999
+ key !== undefined &&
1000
+ keyTag.slice(`${base}-key-`.length) !== markerKeyDigest(key).replace(":", "-")) {
1001
+ return undefined;
1002
+ }
1003
+ const chunks = tags
1004
+ .map((tag) => {
1005
+ const match = tag.match(new RegExp(`^${escapeRegExp(base)}-material-(\\d+)-(\\d+)-([A-Za-z0-9_-]+)$`));
1006
+ return match ? { index: Number(match[1]), total: Number(match[2]), chunk: match[3] } : undefined;
1007
+ })
1008
+ .filter((value) => value !== undefined)
1009
+ .sort((left, right) => left.index - right.index);
1010
+ if (chunks.length === 0 ||
1011
+ chunks[0].total < 1 ||
1012
+ chunks[0].total > MAX_MARKER_CHUNKS ||
1013
+ chunks[0].total !== chunks.length ||
1014
+ chunks.some((chunk, index) => !Number.isSafeInteger(chunk.index) ||
1015
+ !Number.isSafeInteger(chunk.total) ||
1016
+ chunk.index !== index ||
1017
+ chunk.total !== chunks[0].total)) {
1018
+ return undefined;
1019
+ }
1020
+ const decoded = decodeJson(chunks.map((chunk) => chunk.chunk).join(""));
1021
+ return checkpointMarkerFromUnknown(decoded, key);
1022
+ }
1023
+ function legacyCheckpointMarkerFromTags(tags, key, base) {
1024
+ const keyTag = tags.find((tag) => tag.startsWith(`${base}:key:`));
1025
+ if (keyTag &&
1026
+ key !== undefined &&
1027
+ decodeText(keyTag.slice(`${base}:key:`.length)) !== key) {
1028
+ return undefined;
1029
+ }
1030
+ const chunks = tags
1031
+ .map((tag) => {
1032
+ const match = tag.match(new RegExp(`^${escapeRegExp(base)}:material:(\\d+):(\\d+):([A-Za-z0-9_-]+)$`));
1033
+ return match
1034
+ ? { index: Number(match[1]), total: Number(match[2]), chunk: match[3] }
1035
+ : undefined;
1036
+ })
1037
+ .filter((value) => value !== undefined)
1038
+ .sort((left, right) => left.index - right.index);
1039
+ if (chunks.length === 0 ||
1040
+ chunks[0].total < 1 ||
1041
+ chunks[0].total > MAX_MARKER_CHUNKS ||
1042
+ chunks[0].total !== chunks.length ||
1043
+ chunks.some((chunk, index) => !Number.isSafeInteger(chunk.index) ||
1044
+ !Number.isSafeInteger(chunk.total) ||
1045
+ chunk.index !== index ||
1046
+ chunk.total !== chunks[0].total)) {
1047
+ return undefined;
1048
+ }
1049
+ const decoded = decodeJson(chunks.map((chunk) => chunk.chunk).join(""));
1050
+ return checkpointMarkerFromUnknown(decoded, key, true);
1051
+ }
1052
+ function checkpointMarkerFromUnknown(value, key, legacy = false) {
1053
+ if (!value || typeof value !== "object")
1054
+ return undefined;
1055
+ const parsed = value;
1056
+ if (parsed.version !== 1 || parsed.kind !== "checkpoint" || typeof parsed.idempotencyKey !== "string" || typeof parsed.requestDigest !== "string")
1057
+ return undefined;
1058
+ if (key !== undefined && parsed.idempotencyKey !== key)
1059
+ return undefined;
1060
+ const request = WorkspaceCheckpointRequestSchema.safeParse(parsed.request);
1061
+ if (!request.success || request.data.idempotencyKey !== parsed.idempotencyKey || request.data.requestDigest !== parsed.requestDigest)
1062
+ return undefined;
1063
+ return {
1064
+ version: 1,
1065
+ kind: "checkpoint",
1066
+ idempotencyKey: parsed.idempotencyKey,
1067
+ requestDigest: parsed.requestDigest,
1068
+ request: request.data,
1069
+ ...(legacy ? { legacy: true } : {}),
1070
+ };
1071
+ }
1072
+ function forkMarkerFromMetadata(metadata, key) {
1073
+ if (!metadata ||
1074
+ typeof metadata !== "object" ||
1075
+ !Object.hasOwn(metadata, FORK_METADATA_KEY)) {
1076
+ return undefined;
1077
+ }
1078
+ const value = metadata[FORK_METADATA_KEY];
1079
+ if (!value || typeof value !== "object")
1080
+ return undefined;
1081
+ const parsed = value;
1082
+ if (parsed.version !== 1 || parsed.kind !== "fork" || typeof parsed.idempotencyKey !== "string" || typeof parsed.requestDigest !== "string")
1083
+ return undefined;
1084
+ if (key !== undefined && parsed.idempotencyKey !== key)
1085
+ return undefined;
1086
+ const request = WorkspaceForkRequestSchema.safeParse(parsed.request);
1087
+ if (!request.success || request.data.idempotencyKey !== parsed.idempotencyKey || request.data.requestDigest !== parsed.requestDigest)
1088
+ return undefined;
1089
+ return { version: 1, kind: "fork", idempotencyKey: parsed.idempotencyKey, requestDigest: parsed.requestDigest, request: request.data };
1090
+ }
1091
+ /**
1092
+ * Turn a failed create into a conflict only from provider-owned material.
1093
+ *
1094
+ * The Sandbox operation ledger also reports a conflicting digest, but that
1095
+ * digest covers the Sandbox request body, not this interface's identity, so it
1096
+ * is never presented as an interface digest.
1097
+ */
1098
+ async function checkpointConflictFromRemote(box, request, signal) {
1099
+ signal?.throwIfAborted();
1100
+ const recovered = await findCheckpointByKey(box, request.idempotencyKey, signal);
1101
+ signal?.throwIfAborted();
1102
+ if (!recovered)
1103
+ return undefined;
1104
+ if (recovered.marker.requestDigest !== request.requestDigest) {
1105
+ return checkpointConflict(request, recovered.marker.requestDigest);
1106
+ }
1107
+ const record = checkpointRecordFromSnapshot(recovered.marker.request, recovered.snapshot);
1108
+ return record === undefined
1109
+ ? undefined
1110
+ : checkpointSuccess(request, record.checkpoint, "replayed");
1111
+ }
1112
+ /** The fork equivalent of {@link checkpointConflictFromRemote}. */
1113
+ async function forkConflictFromRemote(client, box, provider, request, verifier, signal) {
1114
+ const recovered = await findForkByKey(client, box, provider, request.idempotencyKey, signal);
1115
+ if (!recovered)
1116
+ return undefined;
1117
+ if (recovered.marker.requestDigest !== request.requestDigest) {
1118
+ return forkConflict(request, recovered.marker.requestDigest);
1119
+ }
1120
+ const child = await completeForkChild(client, recovered.child, signal);
1121
+ if (!child)
1122
+ return undefined;
1123
+ const environment = await environmentFromChild(recovered.marker.request, child, provider, child.createdAt, verifier, signal);
1124
+ return environment === undefined
1125
+ ? undefined
1126
+ : forkSuccess(request, environment, "replayed");
1127
+ }
1128
+ /**
1129
+ * Read a ledger answer for a key that left no marked resource behind.
1130
+ *
1131
+ * `absent` is the settled answer: a decided operation with no inventory marker
1132
+ * means the resource was cleaned after creation, and the provider must not
1133
+ * resurrect it from the ledger. Every other state is undecided for the caller.
1134
+ */
1135
+ function lookupOutcomeFromSandbox(lookup, kind) {
1136
+ if (!lookup || lookup.kind !== kind) {
1137
+ return { absent: false, message: `Sandbox returned no ${kind} lookup`, retryable: true };
1138
+ }
1139
+ if (lookup.outcome === "conflict") {
1140
+ return {
1141
+ absent: false,
1142
+ message: "Sandbox found a conflicting operation without provider identity",
1143
+ retryable: false,
1144
+ };
1145
+ }
1146
+ if (lookup.outcome !== "not_found" && (lookup.outcome === "unknown" || lookup.state !== "succeeded")) {
1147
+ return { absent: false, message: `Sandbox ${kind} operation is not decided`, retryable: true };
1148
+ }
1149
+ return { absent: true };
1150
+ }
1151
+ function checkpointSuccess(request, checkpoint, status) {
1152
+ return WorkspaceCheckpointResultSchema.parse({ status, idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, checkpoint });
1153
+ }
1154
+ function checkpointConflict(request, existingRequestDigest) {
1155
+ return WorkspaceCheckpointResultSchema.parse({ status: "conflict", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, existingRequestDigest });
1156
+ }
1157
+ function checkpointUnknown(request, message, retryable) {
1158
+ return WorkspaceCheckpointResultSchema.parse({ status: "unknown", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, message: boundedString(message, "Tangle checkpoint error"), retryable });
1159
+ }
1160
+ function checkpointFound(request, checkpoint) {
1161
+ return WorkspaceCheckpointLookupResultSchema.parse({ status: "found", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, checkpoint });
1162
+ }
1163
+ function checkpointNotFound(request) {
1164
+ return WorkspaceCheckpointLookupResultSchema.parse({ status: "not_found", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest });
1165
+ }
1166
+ function checkpointLookupConflict(request, existingRequestDigest) {
1167
+ return WorkspaceCheckpointLookupResultSchema.parse({ status: "conflict", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, existingRequestDigest });
1168
+ }
1169
+ function checkpointLookupUnknown(request, message, retryable) {
1170
+ return WorkspaceCheckpointLookupResultSchema.parse({ status: "unknown", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, message: boundedString(message, "Tangle checkpoint lookup error"), retryable });
1171
+ }
1172
+ function forkSuccess(request, environment, status) {
1173
+ return WorkspaceForkResultSchema.parse({ status, idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, environment });
1174
+ }
1175
+ function forkConflict(request, existingRequestDigest) {
1176
+ return WorkspaceForkResultSchema.parse({ status: "conflict", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, existingRequestDigest });
1177
+ }
1178
+ function forkUnknown(request, message, retryable) {
1179
+ return WorkspaceForkResultSchema.parse({ status: "unknown", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, message: boundedString(message, "Tangle fork error"), retryable });
1180
+ }
1181
+ function forkFound(request, environment) {
1182
+ return WorkspaceForkLookupResultSchema.parse({ status: "found", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, environment });
1183
+ }
1184
+ function forkNotFound(request) {
1185
+ return WorkspaceForkLookupResultSchema.parse({ status: "not_found", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest });
1186
+ }
1187
+ function forkLookupConflict(request, existingRequestDigest) {
1188
+ return WorkspaceForkLookupResultSchema.parse({ status: "conflict", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, existingRequestDigest });
1189
+ }
1190
+ function forkLookupUnknown(request, message, retryable) {
1191
+ return WorkspaceForkLookupResultSchema.parse({ status: "unknown", idempotencyKey: request.idempotencyKey, requestDigest: request.requestDigest, message: boundedString(message, "Tangle fork lookup error"), retryable });
1192
+ }
1193
+ function cleanupDeleted(request) {
1194
+ return WorkspaceCleanupAcknowledgementSchema.parse({ ...request, status: "deleted" });
1195
+ }
1196
+ function cleanupAlreadyAbsent(request) {
1197
+ return WorkspaceCleanupAcknowledgementSchema.parse({ ...request, status: "already_absent" });
1198
+ }
1199
+ function cleanupConflict(request, existingRequestDigest) {
1200
+ return WorkspaceCleanupAcknowledgementSchema.parse({ ...request, status: "conflict", existingRequestDigest, message: "Cleanup operation id is bound to another target" });
1201
+ }
1202
+ function cleanupInUse(request, blockingTargetIds) {
1203
+ return WorkspaceCleanupAcknowledgementSchema.parse({ ...request, status: "in_use", blockingTargetIds, message: "Checkpoint is still referenced by forked environments" });
1204
+ }
1205
+ function cleanupUnknown(request, message, retryable) {
1206
+ return WorkspaceCleanupAcknowledgementSchema.parse({ ...request, status: "unknown", message: boundedString(message, "Tangle cleanup error"), retryable });
1207
+ }
1208
+ function cleanupTransportFailure(request, message, retryable) {
1209
+ return WorkspaceCleanupAcknowledgementSchema.parse({ ...request, status: "transport_failure", message: boundedString(message, "Tangle cleanup transport error"), retryable });
1210
+ }
1211
+ function isoDate(value) {
1212
+ const date = value instanceof Date ? value : new Date(value);
1213
+ if (!Number.isFinite(date.getTime()))
1214
+ throw new Error("Sandbox returned an invalid workspace timestamp");
1215
+ return date.toISOString();
1216
+ }
1217
+ function validDate(value) {
1218
+ if (value === undefined)
1219
+ return false;
1220
+ const date = value instanceof Date ? value : new Date(value);
1221
+ return Number.isFinite(date.getTime());
1222
+ }
1223
+ function cloneJson(value) {
1224
+ assertBoundedJson(value);
1225
+ return structuredClone(value);
1226
+ }
1227
+ function safeIdentifier(value) {
1228
+ if (typeof value !== "string" || value.length === 0 || value.length > 512 || value.trim() !== value)
1229
+ return undefined;
1230
+ return value;
1231
+ }
1232
+ function safeString(value) {
1233
+ if (typeof value !== "string" || value.length === 0 || value.length > MAX_STRING_LENGTH)
1234
+ return undefined;
1235
+ return value;
1236
+ }
1237
+ function safeError(error) {
1238
+ const message = error instanceof Error ? error.message : "transport error";
1239
+ return message.slice(0, MAX_STRING_LENGTH);
1240
+ }
1241
+ function encodeText(value) {
1242
+ return Buffer.from(value, "utf8").toString("base64url");
1243
+ }
1244
+ function decodeText(value) {
1245
+ try {
1246
+ const decoded = Buffer.from(value, "base64url").toString("utf8");
1247
+ return encodeText(decoded) === value ? decoded : undefined;
1248
+ }
1249
+ catch {
1250
+ return undefined;
1251
+ }
1252
+ }
1253
+ function markerKeyDigest(value) {
1254
+ return sha256Bytes(Buffer.from(value, "utf8"));
1255
+ }
1256
+ function encodeJson(value) {
1257
+ try {
1258
+ const serialized = JSON.stringify(value);
1259
+ if (serialized === undefined)
1260
+ return undefined;
1261
+ return encodeText(serialized);
1262
+ }
1263
+ catch {
1264
+ return undefined;
1265
+ }
1266
+ }
1267
+ function decodeJson(value) {
1268
+ try {
1269
+ return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
1270
+ }
1271
+ catch {
1272
+ return undefined;
1273
+ }
1274
+ }
1275
+ function split(value) {
1276
+ return splitIntoChunks(value, MARKER_CHUNK_SIZE);
1277
+ }
1278
+ function splitIntoChunks(value, chunkSize) {
1279
+ const chunks = [];
1280
+ for (let index = 0; index < value.length; index += chunkSize) {
1281
+ chunks.push(value.slice(index, index + chunkSize));
1282
+ }
1283
+ return chunks;
1284
+ }
1285
+ function escapeRegExp(value) {
1286
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1287
+ }