@opengeni/sdk 1.0.1 → 2.3.0-canary.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.
- package/README.md +117 -2
- package/dist/artifacts.js +5 -5
- package/dist/automations-client.d.ts +17 -0
- package/dist/automations.d.ts +3 -0
- package/dist/automations.js +78 -0
- package/dist/automations.js.map +1 -0
- package/dist/{chunk-YGH5P47G.js → chunk-6IPZY27S.js} +744 -57
- package/dist/chunk-6IPZY27S.js.map +1 -0
- package/dist/{chunk-TYZ4JL4J.js → chunk-AGUKZAXR.js} +2 -2
- package/dist/{chunk-A5DC5WEM.js → chunk-C2H7HBNP.js} +22 -2
- package/dist/chunk-C2H7HBNP.js.map +1 -0
- package/dist/{chunk-GU6JF75T.js → chunk-C4DJPZRU.js} +1 -1
- package/dist/{chunk-GU6JF75T.js.map → chunk-C4DJPZRU.js.map} +1 -1
- package/dist/{chunk-ST5DDKJP.js → chunk-GW3EJ2GP.js} +52 -1
- package/dist/chunk-GW3EJ2GP.js.map +1 -0
- package/dist/{chunk-4DV37UUA.js → chunk-TW5MNHUX.js} +16 -2
- package/dist/chunk-TW5MNHUX.js.map +1 -0
- package/dist/{chunk-VWE2QIVO.js → chunk-XNG7YGR3.js} +23 -6
- package/dist/chunk-XNG7YGR3.js.map +1 -0
- package/dist/client.d.ts +159 -26
- package/dist/codex-realtime-controller.d.ts +1 -0
- package/dist/codex-realtime-controller.js +2 -2
- package/dist/company-brain.d.ts +32 -0
- package/dist/company-profile.d.ts +1 -1
- package/dist/core.js +4 -4
- package/dist/editable-artifacts/browser-session.d.ts +7 -3
- package/dist/editable-artifacts/controller.d.ts +4 -1
- package/dist/editable-artifacts/errors.d.ts +1 -1
- package/dist/editable-artifacts/http-live-transport.d.ts +6 -2
- package/dist/editable-artifacts/index.d.ts +2 -0
- package/dist/editable-artifacts/open-failure.d.ts +9 -0
- package/dist/editable-artifacts/types.d.ts +4 -3
- package/dist/editable-artifacts/worker/kernel-adapter.d.ts +1 -1
- package/dist/editable-artifacts-worker.js +44 -17
- package/dist/editable-artifacts-worker.js.map +1 -1
- package/dist/editable-artifacts.js +222 -119
- package/dist/editable-artifacts.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +61 -12
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +23 -0
- package/dist/interaction.js +4 -1
- package/dist/organization-private-session-settings.d.ts +6 -0
- package/dist/organization-private-session-settings.js +22 -0
- package/dist/organization-private-session-settings.js.map +1 -0
- package/dist/pr-review-client.d.ts +15 -0
- package/dist/pr-review.d.ts +4 -0
- package/dist/pr-review.js +56 -0
- package/dist/pr-review.js.map +1 -0
- package/dist/preference-registry.d.ts +8 -0
- package/dist/realtime.js +2 -2
- package/dist/retained-artifacts.d.ts +5 -1
- package/dist/types.d.ts +1023 -13
- package/dist/workspace-instruction-policies.d.ts +22 -0
- package/dist/workspace-learning.d.ts +124 -0
- package/package.json +14 -2
- package/src/automations-client.ts +118 -0
- package/src/automations.ts +15 -0
- package/src/client.ts +1049 -71
- package/src/codex-realtime-controller.ts +21 -0
- package/src/company-brain.ts +99 -0
- package/src/company-profile.ts +4 -1
- package/src/editable-artifacts/browser-session.ts +36 -22
- package/src/editable-artifacts/controller.ts +66 -45
- package/src/editable-artifacts/errors.ts +2 -0
- package/src/editable-artifacts/http-live-transport.ts +62 -37
- package/src/editable-artifacts/index.ts +6 -0
- package/src/editable-artifacts/open-failure.ts +79 -0
- package/src/editable-artifacts/storage.ts +31 -40
- package/src/editable-artifacts/types.ts +4 -3
- package/src/editable-artifacts/worker/kernel-adapter.ts +23 -7
- package/src/editable-artifacts/worker/runtime.ts +26 -13
- package/src/editable-artifacts/worker/wire-codec.ts +23 -5
- package/src/errors.ts +1 -1
- package/src/index.ts +134 -0
- package/src/interaction.ts +95 -0
- package/src/organization-private-session-settings.ts +33 -0
- package/src/pr-review-client.ts +84 -0
- package/src/pr-review.ts +15 -0
- package/src/preference-registry.ts +9 -0
- package/src/retained-artifacts.ts +101 -0
- package/src/stream.ts +13 -2
- package/src/types.ts +1174 -12
- package/src/workspace-instruction-policies.ts +24 -0
- package/src/workspace-learning.ts +138 -0
- package/dist/chunk-4DV37UUA.js.map +0 -1
- package/dist/chunk-A5DC5WEM.js.map +0 -1
- package/dist/chunk-ST5DDKJP.js.map +0 -1
- package/dist/chunk-VWE2QIVO.js.map +0 -1
- package/dist/chunk-YGH5P47G.js.map +0 -1
- /package/dist/{chunk-TYZ4JL4J.js.map → chunk-AGUKZAXR.js.map} +0 -0
|
@@ -50,6 +50,7 @@ export const CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS = 20_000;
|
|
|
50
50
|
// OpenGeni policy: rotate conservatively without asserting an upstream lifetime.
|
|
51
51
|
const DEFAULT_CONNECTION_ROTATION_INTERVAL_MS = 15 * 60_000;
|
|
52
52
|
const DEFAULT_RECONNECT_BACKOFF_MS = [250, 1_000, 2_000, 5_000] as const;
|
|
53
|
+
const MAX_BROWSER_TIMEOUT_MS = 2_147_483_647;
|
|
53
54
|
const OWNER_RECORD_VERSION = 1;
|
|
54
55
|
const OWNER_DELEGATION_REPLAY_VERSION = 1;
|
|
55
56
|
const OWNER_DELEGATION_REPLAY_MAX_CALLS = 4_096;
|
|
@@ -224,6 +225,7 @@ export type CreateCodexRealtimeControllerOptions = {
|
|
|
224
225
|
createPeerConnection?: (() => RTCPeerConnection) | undefined;
|
|
225
226
|
getUserMedia?: ((constraints: MediaStreamConstraints) => Promise<MediaStream>) | undefined;
|
|
226
227
|
randomUUID?: (() => string) | undefined;
|
|
228
|
+
now?: (() => Date) | undefined;
|
|
227
229
|
setInterval?: ((callback: () => void, delayMs: number) => unknown) | undefined;
|
|
228
230
|
clearInterval?: ((handle: unknown) => void) | undefined;
|
|
229
231
|
setTimeout?: ((callback: () => void, delayMs: number) => unknown) | undefined;
|
|
@@ -316,6 +318,7 @@ export function createCodexRealtimeController(
|
|
|
316
318
|
);
|
|
317
319
|
const model = options.model ?? "gpt-live-1-boulder-alpha";
|
|
318
320
|
const randomUUID = options.randomUUID ?? defaultRandomUUID;
|
|
321
|
+
const now = options.now ?? (() => new Date());
|
|
319
322
|
const scheduleInterval =
|
|
320
323
|
options.setInterval ?? ((callback, delay) => globalThis.setInterval(callback, delay));
|
|
321
324
|
const unscheduleInterval =
|
|
@@ -362,6 +365,7 @@ export function createCodexRealtimeController(
|
|
|
362
365
|
let rotationTimer: unknown = null;
|
|
363
366
|
let reconnectTimer: unknown = null;
|
|
364
367
|
let negotiationTimer: unknown = null;
|
|
368
|
+
let lostOwnerExpiryTimer: unknown = null;
|
|
365
369
|
let closed = false;
|
|
366
370
|
let stopping = false;
|
|
367
371
|
let generation = 0;
|
|
@@ -456,11 +460,13 @@ export function createCodexRealtimeController(
|
|
|
456
460
|
if (rotationTimer !== null) unscheduleTimeout(rotationTimer);
|
|
457
461
|
if (reconnectTimer !== null) unscheduleTimeout(reconnectTimer);
|
|
458
462
|
if (negotiationTimer !== null) unscheduleTimeout(negotiationTimer);
|
|
463
|
+
if (lostOwnerExpiryTimer !== null) unscheduleTimeout(lostOwnerExpiryTimer);
|
|
459
464
|
heartbeatTimer = null;
|
|
460
465
|
syncTimer = null;
|
|
461
466
|
rotationTimer = null;
|
|
462
467
|
reconnectTimer = null;
|
|
463
468
|
negotiationTimer = null;
|
|
469
|
+
lostOwnerExpiryTimer = null;
|
|
464
470
|
};
|
|
465
471
|
|
|
466
472
|
const stopNegotiationTimers = (): void => {
|
|
@@ -1255,6 +1261,12 @@ export function createCodexRealtimeController(
|
|
|
1255
1261
|
if (!record || record.operationId !== lifecycle.operationId) {
|
|
1256
1262
|
closeBrowserResources();
|
|
1257
1263
|
owner = null;
|
|
1264
|
+
const leaseExpiresAt = Date.parse(lifecycle.leaseExpiresAt);
|
|
1265
|
+
const remainingLeaseMs = leaseExpiresAt - now().getTime();
|
|
1266
|
+
if (Number.isFinite(remainingLeaseMs) && remainingLeaseMs <= 0) {
|
|
1267
|
+
transitionEnded("Realtime lease expired");
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1258
1270
|
const message =
|
|
1259
1271
|
"Realtime is active in another browser owner. It can resume after that owner stops or its lease expires.";
|
|
1260
1272
|
publish({
|
|
@@ -1265,6 +1277,15 @@ export function createCodexRealtimeController(
|
|
|
1265
1277
|
diagnostic: diagnostic("lost_owner", message, false),
|
|
1266
1278
|
error: message,
|
|
1267
1279
|
});
|
|
1280
|
+
if (Number.isFinite(remainingLeaseMs) && remainingLeaseMs <= MAX_BROWSER_TIMEOUT_MS) {
|
|
1281
|
+
const observedRealtimeId = lifecycle.realtimeId;
|
|
1282
|
+
lostOwnerExpiryTimer = scheduleTimeout(() => {
|
|
1283
|
+
lostOwnerExpiryTimer = null;
|
|
1284
|
+
if (state.status === "lost_owner" && state.realtimeId === observedRealtimeId) {
|
|
1285
|
+
transitionEnded("Realtime lease expired");
|
|
1286
|
+
}
|
|
1287
|
+
}, remainingLeaseMs);
|
|
1288
|
+
}
|
|
1268
1289
|
return;
|
|
1269
1290
|
}
|
|
1270
1291
|
if (connectionTask || state.status === "starting") return;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CompanyBrainContextReceiptPage as ContractCompanyBrainContextReceiptPage,
|
|
3
|
+
CompanyBrainKnowledgeProposalPage as ContractCompanyBrainKnowledgeProposalPage,
|
|
4
|
+
CompanyBrainOkfPackage as ContractCompanyBrainOkfPackage,
|
|
5
|
+
KnowledgeBrowseRequest as ContractKnowledgeBrowseRequest,
|
|
6
|
+
KnowledgeBrowseResponse as ContractKnowledgeBrowseResponse,
|
|
7
|
+
KnowledgeGetResponse as ContractKnowledgeGetResponse,
|
|
8
|
+
KnowledgeRecord as ContractKnowledgeRecord,
|
|
9
|
+
KnowledgeSearchRequest as ContractKnowledgeSearchRequest,
|
|
10
|
+
KnowledgeSearchResponse as ContractKnowledgeSearchResponse,
|
|
11
|
+
} from "@opengeni/contracts";
|
|
12
|
+
|
|
13
|
+
export type CompanyBrainOkfPackage = ContractCompanyBrainOkfPackage;
|
|
14
|
+
export type CompanyBrainContextReceiptPage = ContractCompanyBrainContextReceiptPage;
|
|
15
|
+
export type CompanyBrainKnowledgeProposalPage = ContractCompanyBrainKnowledgeProposalPage;
|
|
16
|
+
export type CompanyBrainKnowledgeSearchRequest = ContractKnowledgeSearchRequest;
|
|
17
|
+
export type CompanyBrainKnowledgeSearchResponse = ContractKnowledgeSearchResponse;
|
|
18
|
+
export type CompanyBrainKnowledgeBrowseRequest = ContractKnowledgeBrowseRequest;
|
|
19
|
+
export type CompanyBrainKnowledgeBrowseResponse = ContractKnowledgeBrowseResponse;
|
|
20
|
+
export type CompanyBrainKnowledgeGetResponse = ContractKnowledgeGetResponse;
|
|
21
|
+
export type CompanyBrainKnowledgeRecord = ContractKnowledgeRecord;
|
|
22
|
+
|
|
23
|
+
export type CompanyBrainContextReceiptListOptions = {
|
|
24
|
+
attemptId?: string;
|
|
25
|
+
cursor?: string;
|
|
26
|
+
limit?: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type CompanyBrainKnowledgeProposalListOptions = {
|
|
30
|
+
limit?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type CompanyBrainInspectorTransport = {
|
|
34
|
+
requestJson<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function inspectorPath(workspaceId: string, suffix: string): string {
|
|
38
|
+
return `/v1/workspaces/${workspaceId}/company-brain/${suffix}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Human-authorized, permission-first Knowledge search for Company Brain inspectors. */
|
|
42
|
+
export function searchCompanyBrainKnowledge(
|
|
43
|
+
client: CompanyBrainInspectorTransport,
|
|
44
|
+
workspaceId: string,
|
|
45
|
+
request: CompanyBrainKnowledgeSearchRequest,
|
|
46
|
+
): Promise<CompanyBrainKnowledgeSearchResponse> {
|
|
47
|
+
return client.requestJson("POST", inspectorPath(workspaceId, "knowledge/search"), request);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getCompanyBrainKnowledge(
|
|
51
|
+
client: CompanyBrainInspectorTransport,
|
|
52
|
+
workspaceId: string,
|
|
53
|
+
recordId: string,
|
|
54
|
+
): Promise<CompanyBrainKnowledgeGetResponse> {
|
|
55
|
+
return client.requestJson(
|
|
56
|
+
"GET",
|
|
57
|
+
`${inspectorPath(workspaceId, "knowledge/record")}?id=${encodeURIComponent(recordId)}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function browseCompanyBrainKnowledge(
|
|
62
|
+
client: CompanyBrainInspectorTransport,
|
|
63
|
+
workspaceId: string,
|
|
64
|
+
request: CompanyBrainKnowledgeBrowseRequest = {},
|
|
65
|
+
): Promise<CompanyBrainKnowledgeBrowseResponse> {
|
|
66
|
+
return client.requestJson("POST", inspectorPath(workspaceId, "knowledge/browse"), request);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function listCompanyBrainContextReceipts(
|
|
70
|
+
client: CompanyBrainInspectorTransport,
|
|
71
|
+
workspaceId: string,
|
|
72
|
+
options: CompanyBrainContextReceiptListOptions = {},
|
|
73
|
+
): Promise<CompanyBrainContextReceiptPage> {
|
|
74
|
+
const params = new URLSearchParams();
|
|
75
|
+
if (options.attemptId) params.set("attemptId", options.attemptId);
|
|
76
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
77
|
+
if (options.limit !== undefined) params.set("limit", String(options.limit));
|
|
78
|
+
const query = params.toString();
|
|
79
|
+
return client.requestJson(
|
|
80
|
+
"GET",
|
|
81
|
+
`${inspectorPath(workspaceId, "context-receipts")}${query ? `?${query}` : ""}`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function listCompanyBrainKnowledgeProposals(
|
|
86
|
+
client: CompanyBrainInspectorTransport,
|
|
87
|
+
workspaceId: string,
|
|
88
|
+
options: CompanyBrainKnowledgeProposalListOptions = {},
|
|
89
|
+
): Promise<CompanyBrainKnowledgeProposalPage> {
|
|
90
|
+
const query =
|
|
91
|
+
options.limit === undefined ? "" : `?limit=${encodeURIComponent(String(options.limit))}`;
|
|
92
|
+
return client.requestJson("GET", `${inspectorPath(workspaceId, "knowledge-proposals")}${query}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type CompanyBrainOkfDownload = {
|
|
96
|
+
content: string;
|
|
97
|
+
contentType: string;
|
|
98
|
+
filename: string;
|
|
99
|
+
};
|
package/src/company-profile.ts
CHANGED
|
@@ -21,7 +21,10 @@ export type CompanyProfileRevision = CompanyProfileRevisionIdentity & {
|
|
|
21
21
|
accountId: string;
|
|
22
22
|
intent: "active" | "proposal";
|
|
23
23
|
profile: CompanyProfileContent;
|
|
24
|
-
provenance: {
|
|
24
|
+
provenance: {
|
|
25
|
+
source: "human" | "agent_admin" | "durable_learning" | "migration";
|
|
26
|
+
sourceId: string | null;
|
|
27
|
+
};
|
|
25
28
|
supersedesRevisionId: string | null;
|
|
26
29
|
createdBySubjectId: string;
|
|
27
30
|
createdAt: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { EDITABLE_ARTIFACT_LIVE_WIRE_VERSION } from "@opengeni/contracts/editable-artifact-live";
|
|
2
|
+
import {
|
|
3
|
+
EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
|
|
4
|
+
currentEditableArtifactCompatibility,
|
|
5
|
+
} from "@opengeni/contracts/editable-artifacts";
|
|
4
6
|
|
|
5
7
|
import type { EditableArtifactCacheAuthority } from "./controller";
|
|
6
8
|
import {
|
|
@@ -10,6 +12,7 @@ import {
|
|
|
10
12
|
import { createEditableArtifactSession, type EditableArtifactSession } from "./session";
|
|
11
13
|
import type { EditableArtifactStoragePort } from "./storage";
|
|
12
14
|
import type { EditableArtifactModality } from "./types";
|
|
15
|
+
import type { EditableArtifactOpenFailureReporter } from "./open-failure";
|
|
13
16
|
import {
|
|
14
17
|
createBrowserEditableArtifactWorkerKernel,
|
|
15
18
|
type CreateBrowserEditableArtifactWorkerKernelOptions,
|
|
@@ -20,10 +23,11 @@ export type EditableArtifactBrowserRuntime = Omit<
|
|
|
20
23
|
"modality" | "kernelVersion" | "protocolVersion" | "modelSchemaVersion" | "commandVersion"
|
|
21
24
|
> &
|
|
22
25
|
Readonly<{
|
|
23
|
-
/** Exact
|
|
26
|
+
/** Exact package/executable build identity; the API records but does not compatibility-gate it. */
|
|
24
27
|
kernelVersion: string;
|
|
25
28
|
modelSchemaVersion: number;
|
|
26
|
-
|
|
29
|
+
/** Exact OGATX001 intent protocol version. */
|
|
30
|
+
protocolVersion: number;
|
|
27
31
|
commandVersion: number;
|
|
28
32
|
}>;
|
|
29
33
|
|
|
@@ -36,11 +40,21 @@ export type CreateBrowserEditableArtifactSessionOptions = Readonly<{
|
|
|
36
40
|
runtime: EditableArtifactBrowserRuntime;
|
|
37
41
|
transport?: Omit<
|
|
38
42
|
CreateEditableArtifactHttpLiveTransportOptions,
|
|
39
|
-
|
|
43
|
+
| "baseUrl"
|
|
44
|
+
| "workspaceId"
|
|
45
|
+
| "modality"
|
|
46
|
+
| "liveProtocolVersion"
|
|
47
|
+
| "kernelVersion"
|
|
48
|
+
| "modelSchemaVersion"
|
|
49
|
+
| "snapshotVersion"
|
|
50
|
+
| "commandProtocolVersion"
|
|
51
|
+
| "committedTransactionProtocolVersion"
|
|
40
52
|
>;
|
|
41
53
|
storage?: EditableArtifactStoragePort;
|
|
42
54
|
/** Reuse the replica used to create the artifact when opening it immediately. */
|
|
43
55
|
replicaId?: string;
|
|
56
|
+
/** Receives bounded categories/codes only; never workbook or formula content. */
|
|
57
|
+
onOpenFailure?: EditableArtifactOpenFailureReporter;
|
|
44
58
|
}>;
|
|
45
59
|
|
|
46
60
|
/**
|
|
@@ -53,17 +67,23 @@ export function createBrowserEditableArtifactSession(
|
|
|
53
67
|
const baseUrl = canonicalBaseUrl(options.baseUrl);
|
|
54
68
|
const workspaceId = boundedIdentity(options.workspaceId, "workspaceId");
|
|
55
69
|
assertCacheAuthority(options.storageAuthority, baseUrl, workspaceId);
|
|
56
|
-
const protocolVersion = positiveVersion(options.runtime.protocolVersion
|
|
70
|
+
const protocolVersion = positiveVersion(options.runtime.protocolVersion, "protocolVersion");
|
|
71
|
+
if (protocolVersion !== EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION) {
|
|
72
|
+
throw new TypeError("protocolVersion is incompatible with the current intent protocol");
|
|
73
|
+
}
|
|
57
74
|
const modelSchemaVersion = positiveVersion(
|
|
58
75
|
options.runtime.modelSchemaVersion,
|
|
59
76
|
"modelSchemaVersion",
|
|
60
77
|
);
|
|
61
78
|
const kernelVersion = boundedIdentity(options.runtime.kernelVersion, "kernelVersion", 512);
|
|
62
79
|
const commandVersion = positiveVersion(options.runtime.commandVersion, "commandVersion");
|
|
63
|
-
const
|
|
64
|
-
if (
|
|
80
|
+
const current = currentEditableArtifactCompatibility(options.artifact.modality);
|
|
81
|
+
if (
|
|
82
|
+
modelSchemaVersion !== current.modelSchemaVersion ||
|
|
83
|
+
commandVersion !== current.commandProtocolVersion
|
|
84
|
+
) {
|
|
65
85
|
throw new TypeError(
|
|
66
|
-
`
|
|
86
|
+
`runtime versions are incompatible with current ${options.artifact.modality} compatibility`,
|
|
67
87
|
);
|
|
68
88
|
}
|
|
69
89
|
const {
|
|
@@ -87,9 +107,13 @@ export function createBrowserEditableArtifactSession(
|
|
|
87
107
|
...options.transport,
|
|
88
108
|
baseUrl,
|
|
89
109
|
workspaceId,
|
|
90
|
-
|
|
110
|
+
modality: options.artifact.modality,
|
|
111
|
+
liveProtocolVersion: EDITABLE_ARTIFACT_LIVE_WIRE_VERSION,
|
|
91
112
|
kernelVersion,
|
|
92
113
|
modelSchemaVersion,
|
|
114
|
+
snapshotVersion: current.snapshotVersion,
|
|
115
|
+
commandProtocolVersion: current.commandProtocolVersion,
|
|
116
|
+
committedTransactionProtocolVersion: current.committedTransactionProtocolVersion,
|
|
93
117
|
});
|
|
94
118
|
return createEditableArtifactSession({
|
|
95
119
|
artifactId: options.artifact.id,
|
|
@@ -102,6 +126,7 @@ export function createBrowserEditableArtifactSession(
|
|
|
102
126
|
modelSchemaVersion,
|
|
103
127
|
commandVersion,
|
|
104
128
|
protocolVersion,
|
|
129
|
+
...(options.onOpenFailure ? { onOpenFailure: options.onOpenFailure } : {}),
|
|
105
130
|
...(replicaId ? { writerReplicaIdFactory: () => replicaId } : {}),
|
|
106
131
|
ownsWorker: true,
|
|
107
132
|
});
|
|
@@ -121,17 +146,6 @@ export function createEditableArtifactReplicaId(): string {
|
|
|
121
146
|
}
|
|
122
147
|
}
|
|
123
148
|
|
|
124
|
-
function commandVersionFor(modality: EditableArtifactModality): number {
|
|
125
|
-
switch (modality) {
|
|
126
|
-
case "spreadsheet":
|
|
127
|
-
return SPREADSHEET_ARTIFACT_COMMAND_VERSION;
|
|
128
|
-
case "document":
|
|
129
|
-
return DOCUMENT_ARTIFACT_COMMAND_VERSION;
|
|
130
|
-
case "presentation":
|
|
131
|
-
return PRESENTATION_ARTIFACT_COMMAND_VERSION;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
149
|
function canonicalBaseUrl(value: string | URL): URL {
|
|
136
150
|
const url = new URL(value);
|
|
137
151
|
if (url.username || url.password || url.search || url.hash) {
|
|
@@ -2,16 +2,24 @@ import {
|
|
|
2
2
|
decodeEditableArtifactMutationIntent,
|
|
3
3
|
EDITABLE_ARTIFACT_COMMAND_MAX_BYTES,
|
|
4
4
|
EDITABLE_ARTIFACT_INTENT_MAX_BYTES,
|
|
5
|
+
EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
|
|
5
6
|
EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES,
|
|
6
7
|
hashEditableArtifactMutationIntentBytes,
|
|
7
8
|
} from "@opengeni/contracts/editable-artifacts";
|
|
8
9
|
import {
|
|
10
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
9
11
|
decodeCommittedTransactionSummary,
|
|
10
12
|
MAX_COMMITTED_TRANSACTION_BYTES,
|
|
11
13
|
} from "@opengeni/contracts/editable-artifact-committed-transaction";
|
|
12
14
|
import { editableArtifactCodecFor } from "@opengeni/contracts/editable-artifact-codec-registry";
|
|
15
|
+
import { EDITABLE_ARTIFACT_LIVE_WIRE_VERSION } from "@opengeni/contracts/editable-artifact-live";
|
|
13
16
|
import { decodeEditableArtifactSerializedCommit } from "@opengeni/contracts/editable-artifact-serialized-commit";
|
|
17
|
+
import { SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION } from "@opengeni/contracts/editable-artifact-versions";
|
|
14
18
|
import { EditableArtifactSyncError } from "./errors";
|
|
19
|
+
import {
|
|
20
|
+
classifyEditableArtifactOpenFailure,
|
|
21
|
+
type EditableArtifactOpenFailureReporter,
|
|
22
|
+
} from "./open-failure";
|
|
15
23
|
import { EditableArtifactStorageConflictError } from "./storage";
|
|
16
24
|
import type { EditableArtifactStoragePort, EditableArtifactStorageScope } from "./storage";
|
|
17
25
|
import type {
|
|
@@ -42,7 +50,6 @@ import type {
|
|
|
42
50
|
EditableArtifactWorkerKernel,
|
|
43
51
|
} from "./types";
|
|
44
52
|
|
|
45
|
-
const DEFAULT_PROTOCOL_VERSION = 1;
|
|
46
53
|
const DEFAULT_REPLAY_PAGE_SIZE = 256;
|
|
47
54
|
const DEFAULT_MAX_QUEUE_MESSAGES = 512;
|
|
48
55
|
const DEFAULT_MAX_QUEUE_BYTES = 8 * 1024 * 1024;
|
|
@@ -70,7 +77,7 @@ export type CreateEditableArtifactSyncControllerOptions = {
|
|
|
70
77
|
kernelVersion: string;
|
|
71
78
|
modelSchemaVersion: number;
|
|
72
79
|
commandVersion: number;
|
|
73
|
-
protocolVersion
|
|
80
|
+
protocolVersion: number;
|
|
74
81
|
replayPageSize?: number;
|
|
75
82
|
maxQueuedMessages?: number;
|
|
76
83
|
maxQueuedBytes?: number;
|
|
@@ -87,6 +94,8 @@ export type CreateEditableArtifactSyncControllerOptions = {
|
|
|
87
94
|
maxReconnectAttempts?: number;
|
|
88
95
|
scheduler?: EditableArtifactSyncScheduler;
|
|
89
96
|
clientTransactionIdFactory?: () => string;
|
|
97
|
+
/** Receives bounded categories/codes only; never workbook or formula content. */
|
|
98
|
+
onOpenFailure?: EditableArtifactOpenFailureReporter;
|
|
90
99
|
/** Tests/embedded runtimes may inject; defaults to a fresh per-controller UUID. */
|
|
91
100
|
writerReplicaIdFactory?: () => string;
|
|
92
101
|
};
|
|
@@ -186,6 +195,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
186
195
|
private readonly maxReconnectAttempts: number;
|
|
187
196
|
private readonly scheduler: EditableArtifactSyncScheduler;
|
|
188
197
|
private readonly clientTransactionIdFactory: () => string;
|
|
198
|
+
private readonly onOpenFailure: EditableArtifactOpenFailureReporter | undefined;
|
|
189
199
|
|
|
190
200
|
private readonly abortController = new AbortController();
|
|
191
201
|
private readonly listeners = new Set<EditableArtifactSyncListener>();
|
|
@@ -258,10 +268,10 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
258
268
|
);
|
|
259
269
|
this.modelSchemaVersion = positiveSafeInteger(options.modelSchemaVersion, "modelSchemaVersion");
|
|
260
270
|
this.commandVersion = positiveSafeInteger(options.commandVersion, "commandVersion");
|
|
261
|
-
this.protocolVersion = positiveSafeInteger(
|
|
262
|
-
|
|
263
|
-
"protocolVersion"
|
|
264
|
-
|
|
271
|
+
this.protocolVersion = positiveSafeInteger(options.protocolVersion, "protocolVersion");
|
|
272
|
+
if (this.protocolVersion !== EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION) {
|
|
273
|
+
throw new TypeError("protocolVersion is incompatible with the current intent protocol");
|
|
274
|
+
}
|
|
265
275
|
this.replayPageSize = positiveSafeInteger(
|
|
266
276
|
options.replayPageSize ?? DEFAULT_REPLAY_PAGE_SIZE,
|
|
267
277
|
"replayPageSize",
|
|
@@ -324,6 +334,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
324
334
|
this.scheduler = options.scheduler ?? defaultScheduler;
|
|
325
335
|
this.clientTransactionIdFactory =
|
|
326
336
|
options.clientTransactionIdFactory ?? (() => crypto.randomUUID());
|
|
337
|
+
this.onOpenFailure = options.onOpenFailure;
|
|
327
338
|
}
|
|
328
339
|
|
|
329
340
|
start(): void {
|
|
@@ -331,6 +342,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
331
342
|
this.runTask = this.run().catch((error: unknown) => {
|
|
332
343
|
if (this.abortController.signal.aborted) return;
|
|
333
344
|
const failure = asError(error);
|
|
345
|
+
this.reportOpenFailure(failure);
|
|
334
346
|
if (failure instanceof EditableArtifactSyncError && failure.code === "unsupported_protocol") {
|
|
335
347
|
this.lastError = failure;
|
|
336
348
|
this.setState("unsupported");
|
|
@@ -664,7 +676,8 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
664
676
|
try {
|
|
665
677
|
await this.restoreReplica(stored);
|
|
666
678
|
await this.replacePendingOverlay();
|
|
667
|
-
} catch {
|
|
679
|
+
} catch (error) {
|
|
680
|
+
this.reportOpenFailure(error);
|
|
668
681
|
await this.kernel.reset();
|
|
669
682
|
this.replica = null;
|
|
670
683
|
this.retainedTailTransactions = 0;
|
|
@@ -680,8 +693,8 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
680
693
|
stored.snapshot,
|
|
681
694
|
this.artifactId,
|
|
682
695
|
this.modality,
|
|
683
|
-
|
|
684
|
-
|
|
696
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
697
|
+
SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
685
698
|
this.modelSchemaVersion,
|
|
686
699
|
this.maxSnapshotBytes,
|
|
687
700
|
);
|
|
@@ -706,7 +719,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
706
719
|
transaction,
|
|
707
720
|
this.artifactId,
|
|
708
721
|
this.modality,
|
|
709
|
-
|
|
722
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
710
723
|
this.maxCommittedTransactionBytes,
|
|
711
724
|
);
|
|
712
725
|
if (transaction.startSequence !== cursor + 1) {
|
|
@@ -776,6 +789,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
776
789
|
delayMs = this.reconnectDelayMs;
|
|
777
790
|
}
|
|
778
791
|
const failure = asError(error);
|
|
792
|
+
this.reportOpenFailure(failure);
|
|
779
793
|
this.lastError = failure;
|
|
780
794
|
if (failure instanceof EditableArtifactSyncError && failure.requiresSnapshot) {
|
|
781
795
|
this.requireSnapshot = true;
|
|
@@ -956,14 +970,11 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
956
970
|
if (bootstrap.modality !== this.modality) {
|
|
957
971
|
throw invalidBootstrap("bootstrap modality does not match the controller");
|
|
958
972
|
}
|
|
959
|
-
this.
|
|
960
|
-
if (
|
|
961
|
-
bootstrap.kernelVersion !== this.kernelVersion ||
|
|
962
|
-
bootstrap.modelSchemaVersion !== this.modelSchemaVersion
|
|
963
|
-
) {
|
|
973
|
+
this.requireLiveProtocol(bootstrap.liveProtocolVersion);
|
|
974
|
+
if (bootstrap.modelSchemaVersion !== this.modelSchemaVersion) {
|
|
964
975
|
throw new EditableArtifactSyncError(
|
|
965
976
|
"unsupported_protocol",
|
|
966
|
-
`artifact
|
|
977
|
+
`artifact schema ${bootstrap.modelSchemaVersion} is incompatible with ${this.modelSchemaVersion}`,
|
|
967
978
|
);
|
|
968
979
|
}
|
|
969
980
|
requireSha256(bootstrap.headStateHash, "bootstrap.headStateHash");
|
|
@@ -1035,8 +1046,8 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1035
1046
|
snapshot,
|
|
1036
1047
|
this.artifactId,
|
|
1037
1048
|
this.modality,
|
|
1038
|
-
|
|
1039
|
-
|
|
1049
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
1050
|
+
SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
1040
1051
|
this.modelSchemaVersion,
|
|
1041
1052
|
this.maxSnapshotBytes,
|
|
1042
1053
|
);
|
|
@@ -1136,7 +1147,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1136
1147
|
transaction,
|
|
1137
1148
|
this.artifactId,
|
|
1138
1149
|
this.modality,
|
|
1139
|
-
|
|
1150
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
1140
1151
|
this.maxCommittedTransactionBytes,
|
|
1141
1152
|
);
|
|
1142
1153
|
pageBytes += estimateCommittedTransactionBytes(transaction);
|
|
@@ -1167,7 +1178,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1167
1178
|
message,
|
|
1168
1179
|
this.artifactId,
|
|
1169
1180
|
this.modality,
|
|
1170
|
-
|
|
1181
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
1171
1182
|
this.maxCommittedTransactionBytes,
|
|
1172
1183
|
);
|
|
1173
1184
|
bytes = estimateLiveMessageBytes(message);
|
|
@@ -1271,7 +1282,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1271
1282
|
transaction,
|
|
1272
1283
|
this.artifactId,
|
|
1273
1284
|
this.modality,
|
|
1274
|
-
|
|
1285
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
1275
1286
|
this.maxCommittedTransactionBytes,
|
|
1276
1287
|
);
|
|
1277
1288
|
if (embeddedPending) {
|
|
@@ -1568,7 +1579,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1568
1579
|
receipt.committed,
|
|
1569
1580
|
this.artifactId,
|
|
1570
1581
|
this.modality,
|
|
1571
|
-
|
|
1582
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
1572
1583
|
this.maxCommittedTransactionBytes,
|
|
1573
1584
|
);
|
|
1574
1585
|
this.recordAcceptedMapping(receipt);
|
|
@@ -1641,7 +1652,7 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1641
1652
|
"sync ticket is not bound to the requested writer replica",
|
|
1642
1653
|
);
|
|
1643
1654
|
}
|
|
1644
|
-
this.
|
|
1655
|
+
this.requireLiveProtocol(ticket.protocolVersion);
|
|
1645
1656
|
boundedNonEmpty(ticket.token, "ticket.token", MAX_TICKET_BYTES);
|
|
1646
1657
|
const expiresAt = Date.parse(ticket.expiresAt);
|
|
1647
1658
|
if (!Number.isFinite(expiresAt)) {
|
|
@@ -1758,11 +1769,11 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1758
1769
|
);
|
|
1759
1770
|
}
|
|
1760
1771
|
|
|
1761
|
-
private
|
|
1762
|
-
if (actual !==
|
|
1772
|
+
private requireLiveProtocol(actual: number): void {
|
|
1773
|
+
if (actual !== EDITABLE_ARTIFACT_LIVE_WIRE_VERSION) {
|
|
1763
1774
|
throw new EditableArtifactSyncError(
|
|
1764
1775
|
"unsupported_protocol",
|
|
1765
|
-
`
|
|
1776
|
+
`live protocol ${actual} is incompatible with ${EDITABLE_ARTIFACT_LIVE_WIRE_VERSION}`,
|
|
1766
1777
|
);
|
|
1767
1778
|
}
|
|
1768
1779
|
}
|
|
@@ -1794,6 +1805,16 @@ class EditableArtifactSyncControllerImpl implements EditableArtifactSyncControll
|
|
|
1794
1805
|
this.liveWaiters.clear();
|
|
1795
1806
|
}
|
|
1796
1807
|
|
|
1808
|
+
private reportOpenFailure(error: unknown): void {
|
|
1809
|
+
const event = classifyEditableArtifactOpenFailure(error);
|
|
1810
|
+
if (event === null || this.onOpenFailure === undefined) return;
|
|
1811
|
+
try {
|
|
1812
|
+
this.onOpenFailure(event);
|
|
1813
|
+
} catch {
|
|
1814
|
+
// Observability must never change recovery or availability behavior.
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1797
1818
|
private fail(error: Error): void {
|
|
1798
1819
|
this.lastError = error;
|
|
1799
1820
|
this.setState("failed");
|
|
@@ -1971,7 +1992,7 @@ function validateCommittedTransaction(
|
|
|
1971
1992
|
transaction: EditableArtifactCommittedTransaction,
|
|
1972
1993
|
artifactId: EditableArtifactId,
|
|
1973
1994
|
modality: EditableArtifactModality,
|
|
1974
|
-
|
|
1995
|
+
operationProtocolVersion: number,
|
|
1975
1996
|
maxCommittedTransactionBytes: number,
|
|
1976
1997
|
): Readonly<{
|
|
1977
1998
|
clientTransactionId: string;
|
|
@@ -2000,10 +2021,10 @@ function validateCommittedTransaction(
|
|
|
2000
2021
|
throw invalidSequence("transaction committedTransactionBytes exceeds the configured bound");
|
|
2001
2022
|
}
|
|
2002
2023
|
if (transaction.modality === "spreadsheet") {
|
|
2003
|
-
if (transaction.
|
|
2024
|
+
if (transaction.operationProtocolVersion !== operationProtocolVersion) {
|
|
2004
2025
|
throw new EditableArtifactSyncError(
|
|
2005
2026
|
"unsupported_protocol",
|
|
2006
|
-
`transaction protocol ${transaction.
|
|
2027
|
+
`transaction operation protocol ${transaction.operationProtocolVersion} is incompatible with ${operationProtocolVersion}`,
|
|
2007
2028
|
);
|
|
2008
2029
|
}
|
|
2009
2030
|
validateFrontier(transaction.causalFrontier, "causalFrontier");
|
|
@@ -2015,7 +2036,7 @@ function validateCommittedTransaction(
|
|
|
2015
2036
|
}
|
|
2016
2037
|
if (
|
|
2017
2038
|
summary.transactionId !== transaction.transactionId ||
|
|
2018
|
-
summary.operationProtocolVersion !== transaction.
|
|
2039
|
+
summary.operationProtocolVersion !== transaction.operationProtocolVersion ||
|
|
2019
2040
|
summary.priorStateHash !== transaction.priorStateHash ||
|
|
2020
2041
|
summary.stateHash !== transaction.stateHash ||
|
|
2021
2042
|
!frontiersEqual(summary.resultingCausalFrontier, transaction.causalFrontier)
|
|
@@ -2061,8 +2082,8 @@ function validateSnapshot(
|
|
|
2061
2082
|
snapshot: EditableArtifactStoredReplica["snapshot"],
|
|
2062
2083
|
artifactId: EditableArtifactId,
|
|
2063
2084
|
modality: EditableArtifactModality,
|
|
2064
|
-
|
|
2065
|
-
|
|
2085
|
+
operationProtocolVersion: number,
|
|
2086
|
+
snapshotVersion: number,
|
|
2066
2087
|
modelSchemaVersion: number,
|
|
2067
2088
|
maxSnapshotBytes: number,
|
|
2068
2089
|
): void {
|
|
@@ -2076,22 +2097,22 @@ function validateSnapshot(
|
|
|
2076
2097
|
positiveSafeInteger(snapshot.modelSchemaVersion, "snapshot.modelSchemaVersion");
|
|
2077
2098
|
if (snapshot.modality === "spreadsheet") {
|
|
2078
2099
|
validateFrontier(snapshot.causalFrontier, "snapshot.causalFrontier");
|
|
2079
|
-
if (
|
|
2100
|
+
if (
|
|
2101
|
+
snapshot.operationProtocolVersion !== operationProtocolVersion ||
|
|
2102
|
+
snapshot.snapshotVersion !== snapshotVersion
|
|
2103
|
+
) {
|
|
2080
2104
|
throw new EditableArtifactSyncError(
|
|
2081
2105
|
"unsupported_protocol",
|
|
2082
|
-
`snapshot
|
|
2106
|
+
`snapshot operation/state versions ${snapshot.operationProtocolVersion}/${snapshot.snapshotVersion} are incompatible with ${operationProtocolVersion}/${snapshotVersion}`,
|
|
2083
2107
|
);
|
|
2084
2108
|
}
|
|
2085
2109
|
} else {
|
|
2086
2110
|
requireNativeRevision(snapshot.nativeRevision, "snapshot.nativeRevision");
|
|
2087
2111
|
}
|
|
2088
|
-
if (
|
|
2089
|
-
snapshot.kernelVersion !== kernelVersion ||
|
|
2090
|
-
snapshot.modelSchemaVersion !== modelSchemaVersion
|
|
2091
|
-
) {
|
|
2112
|
+
if (snapshot.modelSchemaVersion !== modelSchemaVersion) {
|
|
2092
2113
|
throw new EditableArtifactSyncError(
|
|
2093
2114
|
"unsupported_protocol",
|
|
2094
|
-
`snapshot
|
|
2115
|
+
`snapshot schema ${snapshot.modelSchemaVersion} is incompatible with ${modelSchemaVersion}`,
|
|
2095
2116
|
);
|
|
2096
2117
|
}
|
|
2097
2118
|
if (!(snapshot.bytes instanceof Uint8Array)) {
|
|
@@ -2131,7 +2152,7 @@ function validateLiveMessage(
|
|
|
2131
2152
|
message: EditableArtifactLiveMessage,
|
|
2132
2153
|
artifactId: EditableArtifactId,
|
|
2133
2154
|
modality: EditableArtifactModality,
|
|
2134
|
-
|
|
2155
|
+
operationProtocolVersion: number,
|
|
2135
2156
|
maxCommittedTransactionBytes: number,
|
|
2136
2157
|
): void {
|
|
2137
2158
|
if (!message || typeof message !== "object") {
|
|
@@ -2142,7 +2163,7 @@ function validateLiveMessage(
|
|
|
2142
2163
|
message.transaction,
|
|
2143
2164
|
artifactId,
|
|
2144
2165
|
modality,
|
|
2145
|
-
|
|
2166
|
+
operationProtocolVersion,
|
|
2146
2167
|
maxCommittedTransactionBytes,
|
|
2147
2168
|
);
|
|
2148
2169
|
return;
|
|
@@ -2198,7 +2219,7 @@ function estimateCommittedTransactionBytes(
|
|
|
2198
2219
|
function requireStateHash(actual: string, expected: string, source: string): void {
|
|
2199
2220
|
if (actual !== expected) {
|
|
2200
2221
|
throw new EditableArtifactSyncError(
|
|
2201
|
-
"
|
|
2222
|
+
"authored_causal_mismatch",
|
|
2202
2223
|
`${source} produced state hash ${actual}; expected ${expected}`,
|
|
2203
2224
|
{ retryable: true, requiresSnapshot: true },
|
|
2204
2225
|
);
|
|
@@ -2209,7 +2230,7 @@ function requireDigest(actual: string, expected: string, source: string): void {
|
|
|
2209
2230
|
requireSha256(actual, `${source} computed digest`);
|
|
2210
2231
|
if (actual !== expected) {
|
|
2211
2232
|
throw new EditableArtifactSyncError(
|
|
2212
|
-
"
|
|
2233
|
+
"byte_corruption",
|
|
2213
2234
|
`${source} bytes produced digest ${actual}; expected ${expected}`,
|
|
2214
2235
|
{ retryable: true, requiresSnapshot: true },
|
|
2215
2236
|
);
|
|
@@ -2230,7 +2251,7 @@ function requireFrontier(
|
|
|
2230
2251
|
)
|
|
2231
2252
|
) {
|
|
2232
2253
|
throw new EditableArtifactSyncError(
|
|
2233
|
-
"
|
|
2254
|
+
"authored_causal_mismatch",
|
|
2234
2255
|
`${source} causal frontier does not match the authoritative barrier`,
|
|
2235
2256
|
{ retryable: true, requiresSnapshot: true },
|
|
2236
2257
|
);
|
|
@@ -2416,7 +2437,7 @@ function requireNativeRevisionEqual(actual: number, expected: number, source: st
|
|
|
2416
2437
|
requireNativeRevision(expected, `${source} expected native revision`);
|
|
2417
2438
|
if (actual !== expected) {
|
|
2418
2439
|
throw new EditableArtifactSyncError(
|
|
2419
|
-
"
|
|
2440
|
+
"authored_causal_mismatch",
|
|
2420
2441
|
`${source} native revision ${actual} does not match ${expected}`,
|
|
2421
2442
|
{ retryable: true, requiresSnapshot: true },
|
|
2422
2443
|
);
|