@tangle-network/agent-provider-tangle 1.1.6 → 1.1.8
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/README.md +5 -0
- package/dist/tangle-contract-safety.d.ts +3 -0
- package/dist/tangle-contract-safety.js +22 -6
- package/dist/tangle-events.js +5 -59
- package/dist/tangle-prompt.js +7 -2
- package/dist/tangle-result-values.js +5 -1
- package/dist/tangle-workspace-branching.js +8 -844
- package/dist/tangle-workspace-markers.d.ts +27 -0
- package/dist/tangle-workspace-markers.js +277 -0
- package/dist/tangle-workspace-recovery.d.ts +68 -0
- package/dist/tangle-workspace-recovery.js +530 -0
- package/package.json +6 -2
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WorkspaceCheckpointRequest, WorkspaceForkRequest } from "@tangle-network/agent-interface";
|
|
2
|
+
export interface CheckpointMarker {
|
|
3
|
+
version: 1;
|
|
4
|
+
kind: "checkpoint";
|
|
5
|
+
idempotencyKey: string;
|
|
6
|
+
requestDigest: `sha256:${string}`;
|
|
7
|
+
request: WorkspaceCheckpointRequest;
|
|
8
|
+
/** True only for markers written by the pre-128-byte-tag release. */
|
|
9
|
+
legacy?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ForkMarker {
|
|
12
|
+
version: 1;
|
|
13
|
+
kind: "fork";
|
|
14
|
+
idempotencyKey: string;
|
|
15
|
+
requestDigest: `sha256:${string}`;
|
|
16
|
+
request: WorkspaceForkRequest;
|
|
17
|
+
/** New markers identify children created from the durable checkpoint. */
|
|
18
|
+
materialization?: "snapshot";
|
|
19
|
+
}
|
|
20
|
+
export declare function checkpointMarkerTags(request: WorkspaceCheckpointRequest): string[];
|
|
21
|
+
/** Rebuild the exact tags used by the release before the current safe format. */
|
|
22
|
+
export declare function legacyCheckpointMarkerTags(request: WorkspaceCheckpointRequest): string[];
|
|
23
|
+
export declare function forkMarkerMetadata(request: WorkspaceForkRequest, materialization?: "snapshot" | undefined): Record<string, unknown>;
|
|
24
|
+
export declare function markerBelongsToSource(marker: ForkMarker, provider: string, sourceEnvironmentId: string): boolean;
|
|
25
|
+
export declare function checkpointMarkerBelongsToSource(marker: CheckpointMarker, provider: string, sourceEnvironmentId: string): boolean;
|
|
26
|
+
export declare function checkpointMarkerFromTags(tags: string[] | undefined, key?: string): CheckpointMarker | undefined;
|
|
27
|
+
export declare function forkMarkerFromMetadata(metadata: Record<string, unknown> | undefined, key?: string): ForkMarker | undefined;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { WorkspaceCheckpointRequestSchema, WorkspaceForkRequestSchema, sha256Bytes, } from "@tangle-network/agent-interface";
|
|
2
|
+
import { assertBoundedJson, cloneJson, safeString, } 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
|
+
export function checkpointMarkerTags(request) {
|
|
19
|
+
const marker = {
|
|
20
|
+
version: 1,
|
|
21
|
+
kind: "checkpoint",
|
|
22
|
+
idempotencyKey: request.idempotencyKey,
|
|
23
|
+
requestDigest: request.requestDigest,
|
|
24
|
+
request,
|
|
25
|
+
};
|
|
26
|
+
const encoded = encodeJson(marker);
|
|
27
|
+
if (encoded === undefined)
|
|
28
|
+
throw new Error("workspace marker is not JSON serializable");
|
|
29
|
+
const base = `${MARKER_PREFIX}-checkpoint`;
|
|
30
|
+
const chunks = splitIntoChunks(encoded, MARKER_CHUNK_SIZE);
|
|
31
|
+
if (chunks.length > MAX_MARKER_CHUNKS) {
|
|
32
|
+
throw new Error("workspace marker exceeds the recovery bound");
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
`${base}-key-${markerKeyDigest(request.idempotencyKey).replace(":", "-")}`,
|
|
36
|
+
`${base}-digest-${request.requestDigest.replace(":", "-")}`,
|
|
37
|
+
...chunks.map((chunk, index) => `${base}-material-${index}-${chunks.length}-${chunk}`),
|
|
38
|
+
].map((tag) => {
|
|
39
|
+
if (Buffer.byteLength(tag, "utf8") > MAX_MARKER_TAG_LENGTH) {
|
|
40
|
+
throw new Error("workspace marker tag exceeds the platform bound");
|
|
41
|
+
}
|
|
42
|
+
return tag;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Rebuild the exact tags used by the release before the current safe format. */
|
|
46
|
+
export function legacyCheckpointMarkerTags(request) {
|
|
47
|
+
const marker = {
|
|
48
|
+
version: 1,
|
|
49
|
+
kind: "checkpoint",
|
|
50
|
+
idempotencyKey: request.idempotencyKey,
|
|
51
|
+
requestDigest: request.requestDigest,
|
|
52
|
+
request,
|
|
53
|
+
};
|
|
54
|
+
const encoded = encodeJson(marker);
|
|
55
|
+
if (encoded === undefined)
|
|
56
|
+
throw new Error("workspace marker is not JSON serializable");
|
|
57
|
+
const base = `${LEGACY_MARKER_PREFIX}:checkpoint`;
|
|
58
|
+
const chunks = splitIntoChunks(encoded, LEGACY_MARKER_CHUNK_SIZE);
|
|
59
|
+
if (chunks.length > MAX_MARKER_CHUNKS) {
|
|
60
|
+
throw new Error("workspace marker exceeds the recovery bound");
|
|
61
|
+
}
|
|
62
|
+
return [
|
|
63
|
+
`${base}:key:${encodeText(request.idempotencyKey)}`,
|
|
64
|
+
`${base}:digest:${request.requestDigest}`,
|
|
65
|
+
...chunks.map((chunk, index) => `${base}:material:${index}:${chunks.length}:${chunk}`),
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
export function forkMarkerMetadata(request, materialization = "snapshot") {
|
|
69
|
+
if (request.metadata && Object.hasOwn(request.metadata, FORK_METADATA_KEY)) {
|
|
70
|
+
throw new Error(`fork metadata reserves ${FORK_METADATA_KEY}`);
|
|
71
|
+
}
|
|
72
|
+
const marker = {
|
|
73
|
+
version: 1,
|
|
74
|
+
kind: "fork",
|
|
75
|
+
idempotencyKey: request.idempotencyKey,
|
|
76
|
+
requestDigest: request.requestDigest,
|
|
77
|
+
request,
|
|
78
|
+
...(materialization === "snapshot" ? { materialization } : {}),
|
|
79
|
+
};
|
|
80
|
+
assertBoundedJson(marker);
|
|
81
|
+
return {
|
|
82
|
+
...(request.metadata === undefined ? {} : cloneJson(request.metadata)),
|
|
83
|
+
[FORK_METADATA_KEY]: marker,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function markerBelongsToSource(marker, provider, sourceEnvironmentId) {
|
|
87
|
+
return (marker.request.checkpoint.provider === provider &&
|
|
88
|
+
marker.request.checkpoint.source.environmentId === sourceEnvironmentId);
|
|
89
|
+
}
|
|
90
|
+
export function checkpointMarkerBelongsToSource(marker, provider, sourceEnvironmentId) {
|
|
91
|
+
return (marker.request.source.provider === provider &&
|
|
92
|
+
marker.request.source.environmentId === sourceEnvironmentId);
|
|
93
|
+
}
|
|
94
|
+
export function checkpointMarkerFromTags(tags, key) {
|
|
95
|
+
if (!Array.isArray(tags) ||
|
|
96
|
+
tags.length > MAX_MARKER_CHUNKS + 3 ||
|
|
97
|
+
!tags.every((tag) => safeString(tag) !== undefined)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const currentBase = `${MARKER_PREFIX}-checkpoint`;
|
|
101
|
+
const legacyBase = `${LEGACY_MARKER_PREFIX}:checkpoint`;
|
|
102
|
+
const hasCurrentTags = tags.some((tag) => tag.startsWith(`${currentBase}-`));
|
|
103
|
+
const hasLegacyTags = tags.some((tag) => tag.startsWith(`${legacyBase}:`));
|
|
104
|
+
if (hasCurrentTags === hasLegacyTags)
|
|
105
|
+
return undefined;
|
|
106
|
+
if (hasLegacyTags)
|
|
107
|
+
return legacyCheckpointMarkerFromTags(tags, key, legacyBase);
|
|
108
|
+
if (tags.some((tag) => Buffer.byteLength(tag, "utf8") > MAX_MARKER_TAG_LENGTH)) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return currentCheckpointMarkerFromTags(tags, key, currentBase);
|
|
112
|
+
}
|
|
113
|
+
function currentCheckpointMarkerFromTags(tags, key, base) {
|
|
114
|
+
const keyTag = tags.find((tag) => tag.startsWith(`${base}-key-`));
|
|
115
|
+
if (keyTag &&
|
|
116
|
+
key !== undefined &&
|
|
117
|
+
keyTag.slice(`${base}-key-`.length) !==
|
|
118
|
+
markerKeyDigest(key).replace(":", "-")) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const chunks = tags
|
|
122
|
+
.map((tag) => {
|
|
123
|
+
const match = tag.match(new RegExp(`^${escapeRegExp(base)}-material-(\\d+)-(\\d+)-([A-Za-z0-9_-]+)$`));
|
|
124
|
+
return match
|
|
125
|
+
? { index: Number(match[1]), total: Number(match[2]), chunk: match[3] }
|
|
126
|
+
: undefined;
|
|
127
|
+
})
|
|
128
|
+
.filter((value) => value !== undefined)
|
|
129
|
+
.sort((left, right) => left.index - right.index);
|
|
130
|
+
if (chunks.length === 0 ||
|
|
131
|
+
chunks[0].total < 1 ||
|
|
132
|
+
chunks[0].total > MAX_MARKER_CHUNKS ||
|
|
133
|
+
chunks[0].total !== chunks.length ||
|
|
134
|
+
chunks.some((chunk, index) => !Number.isSafeInteger(chunk.index) ||
|
|
135
|
+
!Number.isSafeInteger(chunk.total) ||
|
|
136
|
+
chunk.index !== index ||
|
|
137
|
+
chunk.total !== chunks[0].total)) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
const decoded = decodeJson(chunks.map((chunk) => chunk.chunk).join(""));
|
|
141
|
+
return checkpointMarkerFromUnknown(decoded, key);
|
|
142
|
+
}
|
|
143
|
+
function legacyCheckpointMarkerFromTags(tags, key, base) {
|
|
144
|
+
const keyTag = tags.find((tag) => tag.startsWith(`${base}:key:`));
|
|
145
|
+
if (keyTag &&
|
|
146
|
+
key !== undefined &&
|
|
147
|
+
decodeText(keyTag.slice(`${base}:key:`.length)) !== key) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
const chunks = tags
|
|
151
|
+
.map((tag) => {
|
|
152
|
+
const match = tag.match(new RegExp(`^${escapeRegExp(base)}:material:(\\d+):(\\d+):([A-Za-z0-9_-]+)$`));
|
|
153
|
+
return match
|
|
154
|
+
? { index: Number(match[1]), total: Number(match[2]), chunk: match[3] }
|
|
155
|
+
: undefined;
|
|
156
|
+
})
|
|
157
|
+
.filter((value) => value !== undefined)
|
|
158
|
+
.sort((left, right) => left.index - right.index);
|
|
159
|
+
if (chunks.length === 0 ||
|
|
160
|
+
chunks[0].total < 1 ||
|
|
161
|
+
chunks[0].total > MAX_MARKER_CHUNKS ||
|
|
162
|
+
chunks[0].total !== chunks.length ||
|
|
163
|
+
chunks.some((chunk, index) => !Number.isSafeInteger(chunk.index) ||
|
|
164
|
+
!Number.isSafeInteger(chunk.total) ||
|
|
165
|
+
chunk.index !== index ||
|
|
166
|
+
chunk.total !== chunks[0].total)) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
const decoded = decodeJson(chunks.map((chunk) => chunk.chunk).join(""));
|
|
170
|
+
return checkpointMarkerFromUnknown(decoded, key, true);
|
|
171
|
+
}
|
|
172
|
+
function checkpointMarkerFromUnknown(value, key, legacy = false) {
|
|
173
|
+
if (!value || typeof value !== "object")
|
|
174
|
+
return undefined;
|
|
175
|
+
const parsed = value;
|
|
176
|
+
if (parsed.version !== 1 ||
|
|
177
|
+
parsed.kind !== "checkpoint" ||
|
|
178
|
+
typeof parsed.idempotencyKey !== "string" ||
|
|
179
|
+
typeof parsed.requestDigest !== "string")
|
|
180
|
+
return undefined;
|
|
181
|
+
if (key !== undefined && parsed.idempotencyKey !== key)
|
|
182
|
+
return undefined;
|
|
183
|
+
const request = WorkspaceCheckpointRequestSchema.safeParse(parsed.request);
|
|
184
|
+
if (!request.success ||
|
|
185
|
+
request.data.idempotencyKey !== parsed.idempotencyKey ||
|
|
186
|
+
request.data.requestDigest !== parsed.requestDigest)
|
|
187
|
+
return undefined;
|
|
188
|
+
return {
|
|
189
|
+
version: 1,
|
|
190
|
+
kind: "checkpoint",
|
|
191
|
+
idempotencyKey: parsed.idempotencyKey,
|
|
192
|
+
requestDigest: parsed.requestDigest,
|
|
193
|
+
request: request.data,
|
|
194
|
+
...(legacy ? { legacy: true } : {}),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export function forkMarkerFromMetadata(metadata, key) {
|
|
198
|
+
if (!metadata ||
|
|
199
|
+
typeof metadata !== "object" ||
|
|
200
|
+
!Object.hasOwn(metadata, FORK_METADATA_KEY)) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
const value = metadata[FORK_METADATA_KEY];
|
|
204
|
+
if (!value || typeof value !== "object")
|
|
205
|
+
return undefined;
|
|
206
|
+
const parsed = value;
|
|
207
|
+
if (parsed.version !== 1 ||
|
|
208
|
+
parsed.kind !== "fork" ||
|
|
209
|
+
typeof parsed.idempotencyKey !== "string" ||
|
|
210
|
+
typeof parsed.requestDigest !== "string")
|
|
211
|
+
return undefined;
|
|
212
|
+
if (parsed.materialization !== undefined &&
|
|
213
|
+
parsed.materialization !== "snapshot") {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
if (key !== undefined && parsed.idempotencyKey !== key)
|
|
217
|
+
return undefined;
|
|
218
|
+
const request = WorkspaceForkRequestSchema.safeParse(parsed.request);
|
|
219
|
+
if (!request.success ||
|
|
220
|
+
request.data.idempotencyKey !== parsed.idempotencyKey ||
|
|
221
|
+
request.data.requestDigest !== parsed.requestDigest)
|
|
222
|
+
return undefined;
|
|
223
|
+
return {
|
|
224
|
+
version: 1,
|
|
225
|
+
kind: "fork",
|
|
226
|
+
idempotencyKey: parsed.idempotencyKey,
|
|
227
|
+
requestDigest: parsed.requestDigest,
|
|
228
|
+
request: request.data,
|
|
229
|
+
...(parsed.materialization === "snapshot"
|
|
230
|
+
? { materialization: "snapshot" }
|
|
231
|
+
: {}),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function encodeText(value) {
|
|
235
|
+
return Buffer.from(value, "utf8").toString("base64url");
|
|
236
|
+
}
|
|
237
|
+
function decodeText(value) {
|
|
238
|
+
try {
|
|
239
|
+
const decoded = Buffer.from(value, "base64url").toString("utf8");
|
|
240
|
+
return encodeText(decoded) === value ? decoded : undefined;
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function markerKeyDigest(value) {
|
|
247
|
+
return sha256Bytes(Buffer.from(value, "utf8"));
|
|
248
|
+
}
|
|
249
|
+
function encodeJson(value) {
|
|
250
|
+
try {
|
|
251
|
+
const serialized = JSON.stringify(value);
|
|
252
|
+
if (serialized === undefined)
|
|
253
|
+
return undefined;
|
|
254
|
+
return encodeText(serialized);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function decodeJson(value) {
|
|
261
|
+
try {
|
|
262
|
+
return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function splitIntoChunks(value, chunkSize) {
|
|
269
|
+
const chunks = [];
|
|
270
|
+
for (let index = 0; index < value.length; index += chunkSize) {
|
|
271
|
+
chunks.push(value.slice(index, index + chunkSize));
|
|
272
|
+
}
|
|
273
|
+
return chunks;
|
|
274
|
+
}
|
|
275
|
+
function escapeRegExp(value) {
|
|
276
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
277
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { WorkspaceCheckpointRef, WorkspaceCheckpointRequest } from "@tangle-network/agent-interface";
|
|
2
|
+
import type { SandboxClientLike, SandboxInstanceLike, SandboxSnapshotInfoLike, SandboxSnapshotResultLike, SandboxWorkspaceOperationLookupLike } from "./tangle-types.js";
|
|
3
|
+
import type { ForkMarker } from "./tangle-workspace-markers.js";
|
|
4
|
+
export interface CheckpointRecord {
|
|
5
|
+
request: WorkspaceCheckpointRequest;
|
|
6
|
+
checkpoint: WorkspaceCheckpointRef;
|
|
7
|
+
snapshotId: string;
|
|
8
|
+
}
|
|
9
|
+
interface RecoveredForkChild {
|
|
10
|
+
child: SandboxInstanceLike;
|
|
11
|
+
createdAt: Date | string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/** Normalize remote checkpoint recovery before each caller chooses its output. */
|
|
14
|
+
type CheckpointReconciliation = {
|
|
15
|
+
state: "found";
|
|
16
|
+
record: CheckpointRecord;
|
|
17
|
+
} | {
|
|
18
|
+
state: "conflict";
|
|
19
|
+
existingRequestDigest: `sha256:${string}`;
|
|
20
|
+
} | {
|
|
21
|
+
state: "undecided";
|
|
22
|
+
reason: "inventory_unavailable" | "metadata_invalid";
|
|
23
|
+
} | {
|
|
24
|
+
state: "retired";
|
|
25
|
+
} | {
|
|
26
|
+
state: "absent";
|
|
27
|
+
};
|
|
28
|
+
export declare function checkpointRecordFromSnapshot(request: WorkspaceCheckpointRequest, snapshot: SandboxSnapshotResultLike | SandboxSnapshotInfoLike): CheckpointRecord | undefined;
|
|
29
|
+
export declare function validSnapshotResult(result: SandboxSnapshotResultLike | undefined): result is SandboxSnapshotResultLike;
|
|
30
|
+
/** Normalize one remote checkpoint recovery attempt for every caller. */
|
|
31
|
+
export declare function reconcileCheckpoint(box: SandboxInstanceLike, provider: string, request: Pick<WorkspaceCheckpointRequest, "idempotencyKey" | "requestDigest">, signal?: AbortSignal): Promise<CheckpointReconciliation>;
|
|
32
|
+
/**
|
|
33
|
+
* Confirm that one snapshot id is a settled checkpoint this provider created.
|
|
34
|
+
*
|
|
35
|
+
* `expected` binds the answer to a specific checkpoint reference. A reference
|
|
36
|
+
* that does not match its marker is absent, not unknown: the caller supplied a
|
|
37
|
+
* checkpoint this source never produced.
|
|
38
|
+
*/
|
|
39
|
+
export declare function findManagedCheckpoint(box: SandboxInstanceLike, provider: string, id: string, expected?: WorkspaceCheckpointRef, signal?: AbortSignal): Promise<true | false | "unknown">;
|
|
40
|
+
export declare function findForkByKey(client: SandboxClientLike, box: SandboxInstanceLike, provider: string, key: string, signal?: AbortSignal): Promise<(RecoveredForkChild & {
|
|
41
|
+
marker: ForkMarker;
|
|
42
|
+
}) | null | undefined>;
|
|
43
|
+
export declare function findForkChildById(client: SandboxClientLike, box: SandboxInstanceLike, provider: string, id: string, signal?: AbortSignal): Promise<SandboxInstanceLike | null | undefined>;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a complete child identity when an acknowledgement omits durable data.
|
|
46
|
+
*
|
|
47
|
+
* A branch response can precede a richer registry read during a rolling
|
|
48
|
+
* deployment. Recover the exact child when its creation time or provider
|
|
49
|
+
* marker is absent. Never invent either field from the request.
|
|
50
|
+
*/
|
|
51
|
+
export declare function completeForkChild(client: SandboxClientLike, child: SandboxInstanceLike, signal?: AbortSignal): Promise<SandboxInstanceLike | undefined>;
|
|
52
|
+
export declare function findBlockingForks(box: SandboxInstanceLike, client: SandboxClientLike, provider: string, checkpointId: string, signal?: AbortSignal): Promise<string[] | undefined>;
|
|
53
|
+
/**
|
|
54
|
+
* Read a fork ledger answer for a key that left no marked resource behind.
|
|
55
|
+
*
|
|
56
|
+
* `absent` is the settled answer: a decided operation with no inventory marker
|
|
57
|
+
* means the child was cleaned after creation, and the provider must not
|
|
58
|
+
* resurrect it from the ledger. Every other state is undecided for the caller.
|
|
59
|
+
*/
|
|
60
|
+
export declare function lookupOutcomeFromSandbox(lookup: SandboxWorkspaceOperationLookupLike | undefined, kind: "fork"): {
|
|
61
|
+
absent: true;
|
|
62
|
+
} | {
|
|
63
|
+
absent: false;
|
|
64
|
+
message: string;
|
|
65
|
+
retryable: boolean;
|
|
66
|
+
};
|
|
67
|
+
export declare function isoDate(value: Date | string): string;
|
|
68
|
+
export {};
|