@opengeni/core 0.21.10 → 0.28.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.
Files changed (132) hide show
  1. package/dist/access/index.d.ts +1 -1
  2. package/dist/application/new-session-drafts.d.ts +1 -1
  3. package/dist/application/session-commands.d.ts +2 -2
  4. package/dist/billing/limits.d.ts +1 -1
  5. package/dist/canonical-human-identities.d.ts +12 -0
  6. package/dist/canonical-human-identities.js +23 -0
  7. package/dist/canonical-human-identities.js.map +1 -0
  8. package/dist/chunk-6WKPWE5S.js +2380 -0
  9. package/dist/chunk-6WKPWE5S.js.map +1 -0
  10. package/dist/chunk-IBOEYG6N.js +34 -0
  11. package/dist/chunk-IBOEYG6N.js.map +1 -0
  12. package/dist/chunk-JJU6I5XD.js +2713 -0
  13. package/dist/chunk-JJU6I5XD.js.map +1 -0
  14. package/dist/chunk-NYPMQ7NO.js +2270 -0
  15. package/dist/chunk-NYPMQ7NO.js.map +1 -0
  16. package/dist/dependencies.d.ts +30 -6
  17. package/dist/domain/capabilities.d.ts +28 -3
  18. package/dist/domain/company-profile-durable-learning-adapter.d.ts +39 -0
  19. package/dist/domain/conversation-integrations.d.ts +225 -0
  20. package/dist/domain/durable-learning-slack-publication.d.ts +72 -0
  21. package/dist/domain/editable-artifacts/agent-application.d.ts +192 -0
  22. package/dist/domain/editable-artifacts/durable-export-postgres.d.ts +4 -0
  23. package/dist/domain/editable-artifacts/durable-export.d.ts +212 -0
  24. package/dist/domain/editable-artifacts/errors.d.ts +47 -0
  25. package/dist/domain/editable-artifacts/hash.d.ts +11 -0
  26. package/dist/domain/editable-artifacts/in-memory.d.ts +99 -0
  27. package/dist/domain/editable-artifacts/index.d.ts +14 -0
  28. package/dist/domain/editable-artifacts/ports.d.ts +341 -0
  29. package/dist/domain/editable-artifacts/postgres-adapters.d.ts +13 -0
  30. package/dist/domain/editable-artifacts/service.d.ts +105 -0
  31. package/dist/domain/editable-artifacts/snapshot-compaction.d.ts +44 -0
  32. package/dist/domain/editable-artifacts/snapshot-verifier-genesis.d.ts +50 -0
  33. package/dist/domain/editable-artifacts/snapshot-verifier-materialization.d.ts +21 -0
  34. package/dist/domain/editable-artifacts/snapshot-verifier.d.ts +118 -0
  35. package/dist/domain/editable-artifacts/types.d.ts +410 -0
  36. package/dist/domain/fiken.d.ts +35 -0
  37. package/dist/domain/memory-slack-delivery.d.ts +19 -0
  38. package/dist/domain/packs.d.ts +29 -1
  39. package/dist/domain/personal-connection-delegations.d.ts +9 -1
  40. package/dist/domain/scheduled-tasks.d.ts +2 -2
  41. package/dist/domain/session-tool-policy.d.ts +2 -2
  42. package/dist/domain/sessions.d.ts +24 -8
  43. package/dist/domain/skill-imports.d.ts +32 -0
  44. package/dist/domain/slack-publication-secret-safety.d.ts +8 -0
  45. package/dist/domain/timeline-annotations.d.ts +5 -0
  46. package/dist/domain/video-generation-capabilities.d.ts +10 -0
  47. package/dist/domain/video-generation.d.ts +47 -0
  48. package/dist/editable-artifact-live/application.d.ts +69 -0
  49. package/dist/editable-artifact-live/errors.d.ts +1 -0
  50. package/dist/editable-artifact-live/index.d.ts +8 -0
  51. package/dist/editable-artifact-live/outbox-dispatcher.d.ts +162 -0
  52. package/dist/editable-artifact-live/ports.d.ts +100 -0
  53. package/dist/editable-artifact-live/server.d.ts +71 -0
  54. package/dist/editable-artifact-live/ticket.d.ts +40 -0
  55. package/dist/editable-artifact-live/types.d.ts +213 -0
  56. package/dist/editable-artifact-live/wire.d.ts +34 -0
  57. package/dist/editable-artifact-live.d.ts +2 -0
  58. package/dist/editable-artifact-live.js +58 -0
  59. package/dist/editable-artifact-live.js.map +1 -0
  60. package/dist/editable-artifacts.d.ts +2 -0
  61. package/dist/editable-artifacts.js +179 -0
  62. package/dist/editable-artifacts.js.map +1 -0
  63. package/dist/index.d.ts +37 -26
  64. package/dist/index.js +4145 -959
  65. package/dist/index.js.map +1 -1
  66. package/dist/managed-session.d.ts +6 -2
  67. package/dist/rigs/index.d.ts +1 -1
  68. package/dist/rigs/provider-images.d.ts +31 -0
  69. package/dist/sandbox/fleet.d.ts +8 -5
  70. package/dist/sandbox/routing.d.ts +1 -0
  71. package/dist/session-authorization.d.ts +4 -2
  72. package/dist/transcription.d.ts +5 -0
  73. package/dist/workflow-wake-contract.d.ts +7 -0
  74. package/package.json +22 -10
  75. package/src/access/index.ts +14 -2
  76. package/src/application/new-session-drafts.ts +2 -0
  77. package/src/application/session-commands.ts +188 -107
  78. package/src/canonical-human-identities.ts +27 -0
  79. package/src/dependencies.ts +34 -2
  80. package/src/domain/capabilities.ts +729 -408
  81. package/src/domain/company-profile-durable-learning-adapter.ts +221 -0
  82. package/src/domain/conversation-integrations.ts +1238 -0
  83. package/src/domain/durable-learning-slack-publication.ts +202 -0
  84. package/src/domain/editable-artifacts/agent-application.ts +687 -0
  85. package/src/domain/editable-artifacts/durable-export-postgres.ts +139 -0
  86. package/src/domain/editable-artifacts/durable-export.ts +734 -0
  87. package/src/domain/editable-artifacts/errors.ts +115 -0
  88. package/src/domain/editable-artifacts/hash.ts +131 -0
  89. package/src/domain/editable-artifacts/in-memory.ts +1662 -0
  90. package/src/domain/editable-artifacts/index.ts +14 -0
  91. package/src/domain/editable-artifacts/ports.ts +462 -0
  92. package/src/domain/editable-artifacts/postgres-adapters.ts +49 -0
  93. package/src/domain/editable-artifacts/service.ts +2402 -0
  94. package/src/domain/editable-artifacts/snapshot-compaction.ts +246 -0
  95. package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +235 -0
  96. package/src/domain/editable-artifacts/snapshot-verifier-materialization.ts +74 -0
  97. package/src/domain/editable-artifacts/snapshot-verifier.ts +687 -0
  98. package/src/domain/editable-artifacts/types.ts +835 -0
  99. package/src/domain/fiken.ts +88 -0
  100. package/src/domain/insights.ts +163 -50
  101. package/src/domain/memory-slack-delivery.ts +204 -0
  102. package/src/domain/memory-slack-publication.ts +5 -2
  103. package/src/domain/packs.ts +266 -5
  104. package/src/domain/personal-connection-delegations.ts +97 -6
  105. package/src/domain/scheduled-tasks.ts +171 -29
  106. package/src/domain/session-tool-policy.ts +8 -2
  107. package/src/domain/sessions.ts +395 -148
  108. package/src/domain/skill-imports.ts +350 -0
  109. package/src/domain/slack-publication-secret-safety.ts +42 -0
  110. package/src/domain/timeline-annotations.ts +204 -0
  111. package/src/domain/video-generation-capabilities.ts +104 -0
  112. package/src/domain/video-generation.ts +249 -0
  113. package/src/editable-artifact-live/application.ts +182 -0
  114. package/src/editable-artifact-live/errors.ts +4 -0
  115. package/src/editable-artifact-live/index.ts +8 -0
  116. package/src/editable-artifact-live/outbox-dispatcher.ts +916 -0
  117. package/src/editable-artifact-live/ports.ts +139 -0
  118. package/src/editable-artifact-live/server.ts +1707 -0
  119. package/src/editable-artifact-live/ticket.ts +217 -0
  120. package/src/editable-artifact-live/types.ts +286 -0
  121. package/src/editable-artifact-live/wire.ts +95 -0
  122. package/src/editable-artifact-live.ts +2 -0
  123. package/src/editable-artifacts.ts +2 -0
  124. package/src/index.ts +15 -0
  125. package/src/managed-session.ts +19 -2
  126. package/src/rigs/index.ts +26 -19
  127. package/src/rigs/provider-images.ts +110 -0
  128. package/src/sandbox/fleet.ts +72 -66
  129. package/src/sandbox/routing.ts +6 -3
  130. package/src/session-authorization.ts +187 -52
  131. package/src/transcription.ts +5 -0
  132. package/src/workflow-wake-contract.ts +8 -0
@@ -0,0 +1,2380 @@
1
+ import {
2
+ EditableArtifactDomainError,
3
+ EditableArtifactIdempotencyConflictError,
4
+ EditableArtifactNotFoundError,
5
+ EditableArtifactOutboxLeaseConflictError,
6
+ EditableArtifactSnapshotVerificationError,
7
+ EditableArtifactStaleBaseError,
8
+ MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES,
9
+ assertBoundedArtifactTitle,
10
+ assertBoundedKernelVersion,
11
+ assertIsoTimestamp,
12
+ assertNonnegativeSafeInteger,
13
+ assertPositiveSafeInteger,
14
+ causalFrontiersEqual,
15
+ editableArtifactActorKey,
16
+ editableArtifactCausalFrontier,
17
+ editableArtifactClientTransactionId,
18
+ editableArtifactContentHash,
19
+ editableArtifactId,
20
+ editableArtifactOperationId,
21
+ editableArtifactOutboxId,
22
+ editableArtifactReceiptId,
23
+ editableArtifactRequestHash,
24
+ editableArtifactScope,
25
+ editableArtifactSnapshotId,
26
+ editableArtifactStateHash,
27
+ validateEditableArtifactActor
28
+ } from "./chunk-JJU6I5XD.js";
29
+
30
+ // src/domain/editable-artifacts/durable-export.ts
31
+ import { createHash } from "crypto";
32
+ var EDITABLE_ARTIFACT_EXPORT_MAX_DOWNLOAD_BYTES = 512 * 1024 * 1024;
33
+ var EDITABLE_ARTIFACT_EXPORT_MAX_OPTIONS_BYTES = 256 * 1024;
34
+ var EditableArtifactDurableExportError = class extends Error {
35
+ constructor(code) {
36
+ super(code);
37
+ this.code = code;
38
+ this.name = "EditableArtifactDurableExportError";
39
+ }
40
+ };
41
+ var MAX_AUTHORIZATION_RETRIES = 4;
42
+ var PORTABLE_ID = /^[0-9a-f]{32}$/u;
43
+ var IDEMPOTENCY_KEY = /^[A-Za-z0-9._:-]{1,200}$/u;
44
+ var SHA256 = /^sha256:[0-9a-f]{64}$/u;
45
+ var PROFILE_TEXT = /^[\x21-\x7e]+$/u;
46
+ var EditableArtifactDurableExportService = class {
47
+ constructor(dependencies) {
48
+ this.dependencies = dependencies;
49
+ }
50
+ async pinVersion(input) {
51
+ const context = normalizeContext(input);
52
+ const idempotencyKey = portableIdempotencyKey(input.idempotencyKey);
53
+ const name = versionName(input.name);
54
+ const snapshot = await this.dependencies.exactSnapshots.ensure({
55
+ ...context,
56
+ ...input.signal ? { signal: input.signal } : {}
57
+ });
58
+ if (snapshot.scope.accountId !== context.scope.accountId || snapshot.scope.workspaceId !== context.scope.workspaceId || snapshot.artifactId !== context.artifactId) {
59
+ throw new EditableArtifactDurableExportError("unavailable");
60
+ }
61
+ const requestHash = hashPublicRequest("pin-version", [idempotencyKey, name]);
62
+ const authorityKey = editableArtifactActorKey(context.actor);
63
+ const receiptId = stableId(this.dependencies.ids.next("receipt"), "receipt id");
64
+ const versionId = stableId(this.dependencies.ids.next("version"), "version id");
65
+ for (let attempt = 0; attempt < MAX_AUTHORIZATION_RETRIES; attempt += 1) {
66
+ const revision = await this.requireExportPermission(context);
67
+ const result = await this.dependencies.store.pinVersion({
68
+ ...context,
69
+ expectedAuthorizationRevision: revision,
70
+ authorityKey,
71
+ receiptId,
72
+ versionId,
73
+ idempotencyKey,
74
+ requestHash,
75
+ name,
76
+ snapshot
77
+ });
78
+ if (result.kind === "result") {
79
+ return Object.freeze({ version: result.version, replayed: result.replayed });
80
+ }
81
+ }
82
+ throw new EditableArtifactDurableExportError("conflict");
83
+ }
84
+ async enqueueMaterialization(input) {
85
+ const context = normalizeContext(input);
86
+ const idempotencyKey = portableIdempotencyKey(input.idempotencyKey);
87
+ const versionId = stableId(input.versionId, "version id");
88
+ const format = materializationFormat(input.format);
89
+ const options = exactOptions(input.options ?? Object.freeze({}));
90
+ const version = await this.getVersion(context, versionId);
91
+ const profile = await this.dependencies.profiles.resolve({
92
+ modality: version.modality,
93
+ format,
94
+ options
95
+ });
96
+ if (!profile) throw new EditableArtifactDurableExportError("unsupported_format");
97
+ validateProfile(profile, version.modality, format);
98
+ const requestHash = hashPublicRequest("materialize", [
99
+ idempotencyKey,
100
+ versionId,
101
+ format,
102
+ canonicalJson(options)
103
+ ]);
104
+ const authorityKey = editableArtifactActorKey(context.actor);
105
+ const receiptId = stableId(this.dependencies.ids.next("receipt"), "receipt id");
106
+ const jobId = stableId(this.dependencies.ids.next("materialization_job"), "job id");
107
+ for (let attempt = 0; attempt < MAX_AUTHORIZATION_RETRIES; attempt += 1) {
108
+ const revision = await this.requireExportPermission(context);
109
+ const result = await this.dependencies.store.enqueueMaterialization({
110
+ ...context,
111
+ expectedAuthorizationRevision: revision,
112
+ authorityKey,
113
+ receiptId,
114
+ jobId,
115
+ idempotencyKey,
116
+ requestHash,
117
+ versionId,
118
+ profile
119
+ });
120
+ if (result.kind === "result") {
121
+ return Object.freeze({ job: result.job, replayed: result.replayed });
122
+ }
123
+ }
124
+ throw new EditableArtifactDurableExportError("conflict");
125
+ }
126
+ async getMaterialization(input) {
127
+ const context = normalizeContext(input);
128
+ const jobId = stableId(input.jobId, "job id");
129
+ for (let attempt = 0; attempt < MAX_AUTHORIZATION_RETRIES; attempt += 1) {
130
+ const revision = await this.requireExportPermission(context);
131
+ const result = await this.dependencies.store.readMaterialization({
132
+ ...context,
133
+ expectedAuthorizationRevision: revision,
134
+ jobId
135
+ });
136
+ if (result.kind === "authorization_stale") continue;
137
+ if (!result.job) throw new EditableArtifactDurableExportError("not_found");
138
+ return result.job;
139
+ }
140
+ throw new EditableArtifactDurableExportError("conflict");
141
+ }
142
+ async openMaterializationDownload(input) {
143
+ const context = normalizeContext(input);
144
+ const jobId = stableId(input.jobId, "job id");
145
+ for (let attempt = 0; attempt < MAX_AUTHORIZATION_RETRIES; attempt += 1) {
146
+ const revision = await this.requireExportPermission(context);
147
+ const result = await this.dependencies.store.readMaterializationDownload({
148
+ ...context,
149
+ expectedAuthorizationRevision: revision,
150
+ jobId
151
+ });
152
+ if (result.kind === "authorization_stale") continue;
153
+ if (!result.job) throw new EditableArtifactDurableExportError("not_found");
154
+ const materialization = result.job.result;
155
+ if (result.job.state !== "succeeded" || !materialization || !result.objectReference) {
156
+ throw new EditableArtifactDurableExportError("not_ready");
157
+ }
158
+ let object;
159
+ try {
160
+ object = await this.dependencies.materializationObjects.open({
161
+ opaqueReference: result.objectReference,
162
+ maxBytes: EDITABLE_ARTIFACT_EXPORT_MAX_DOWNLOAD_BYTES,
163
+ expectedByteSize: materialization.byteSize,
164
+ ...input.signal ? { signal: input.signal } : {}
165
+ });
166
+ } catch {
167
+ throw new EditableArtifactDurableExportError("unavailable");
168
+ }
169
+ if (object.contentType !== void 0 && object.contentType !== materialization.mimeType) {
170
+ await object.close();
171
+ throw new EditableArtifactDurableExportError("unavailable");
172
+ }
173
+ return Object.freeze({
174
+ artifactId: context.artifactId,
175
+ jobId,
176
+ format: result.job.format,
177
+ byteSize: materialization.byteSize,
178
+ contentHash: materialization.contentHash,
179
+ mimeType: materialization.mimeType,
180
+ chunks: (chunkInput = {}) => object.chunks(chunkInput.signal ? { signal: chunkInput.signal } : {}),
181
+ assertUnchanged: async (signal) => await object.assertUnchanged(signal),
182
+ close: async () => await object.close()
183
+ });
184
+ }
185
+ throw new EditableArtifactDurableExportError("conflict");
186
+ }
187
+ async getVersion(context, versionId) {
188
+ for (let attempt = 0; attempt < MAX_AUTHORIZATION_RETRIES; attempt += 1) {
189
+ const revision = await this.requireExportPermission(context);
190
+ const result = await this.dependencies.store.readVersion({
191
+ ...context,
192
+ expectedAuthorizationRevision: revision,
193
+ versionId
194
+ });
195
+ if (result.kind === "authorization_stale") continue;
196
+ if (!result.version) throw new EditableArtifactDurableExportError("not_found");
197
+ return result.version;
198
+ }
199
+ throw new EditableArtifactDurableExportError("conflict");
200
+ }
201
+ async requireExportPermission(context) {
202
+ const decision = await this.dependencies.authorization.authorize({
203
+ ...context,
204
+ permission: "export"
205
+ });
206
+ if (!decision.allowed) throw new EditableArtifactDurableExportError("forbidden");
207
+ if (!Number.isSafeInteger(decision.revision) || decision.revision < 1) {
208
+ throw new EditableArtifactDurableExportError("unavailable");
209
+ }
210
+ return decision.revision;
211
+ }
212
+ };
213
+ function editableArtifactMaterializationMimeType(format) {
214
+ switch (format) {
215
+ case "xlsx":
216
+ return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
217
+ case "pptx":
218
+ return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
219
+ case "docx":
220
+ return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
221
+ case "pdf":
222
+ return "application/pdf";
223
+ case "png":
224
+ return "image/png";
225
+ case "webp":
226
+ return "image/webp";
227
+ }
228
+ }
229
+ function editableArtifactFormatMatchesModality(modality, format) {
230
+ return modality === "spreadsheet" && ["xlsx", "pdf", "png", "webp"].includes(format) || modality === "presentation" && ["pptx", "pdf", "png", "webp"].includes(format) || modality === "document" && ["docx", "pdf", "png", "webp"].includes(format);
231
+ }
232
+ function normalizeContext(input) {
233
+ const scope = editableArtifactScope(input.scope);
234
+ const artifactId = editableArtifactId(input.artifactId);
235
+ validateEditableArtifactActor(input.actor);
236
+ return Object.freeze({
237
+ scope,
238
+ artifactId,
239
+ actor: Object.freeze({ ...input.actor })
240
+ });
241
+ }
242
+ function stableId(value, _label) {
243
+ if (!PORTABLE_ID.test(value) || /^0+$/u.test(value)) {
244
+ throw new EditableArtifactDurableExportError("invalid_request");
245
+ }
246
+ return value;
247
+ }
248
+ function portableIdempotencyKey(value) {
249
+ if (!IDEMPOTENCY_KEY.test(value)) {
250
+ throw new EditableArtifactDurableExportError("invalid_request");
251
+ }
252
+ return value;
253
+ }
254
+ function versionName(value) {
255
+ if (typeof value !== "string" || value.trim() !== value || /[\u0000-\u001f\u007f]/u.test(value) || new TextEncoder().encode(value).byteLength < 1 || new TextEncoder().encode(value).byteLength > 256 || !wellFormedText(value)) {
256
+ throw new EditableArtifactDurableExportError("invalid_request");
257
+ }
258
+ return value;
259
+ }
260
+ function materializationFormat(value) {
261
+ if (!["xlsx", "pptx", "docx", "pdf", "png", "webp"].includes(value)) {
262
+ throw new EditableArtifactDurableExportError("invalid_request");
263
+ }
264
+ return value;
265
+ }
266
+ function exactOptions(value) {
267
+ if (!plainRecord(value)) throw new EditableArtifactDurableExportError("invalid_request");
268
+ const canonical = canonicalJson(value);
269
+ if (new TextEncoder().encode(canonical).byteLength > EDITABLE_ARTIFACT_EXPORT_MAX_OPTIONS_BYTES) {
270
+ throw new EditableArtifactDurableExportError("invalid_request");
271
+ }
272
+ return Object.freeze({ ...value });
273
+ }
274
+ function canonicalJson(value) {
275
+ const keys = Object.keys(value).sort(compareCodeUnits);
276
+ const normalized = {};
277
+ for (const key of keys) {
278
+ if (!wellFormedText(key) || !jsonValue(value[key])) {
279
+ throw new EditableArtifactDurableExportError("invalid_request");
280
+ }
281
+ normalized[key] = value[key];
282
+ }
283
+ const encoded = JSON.stringify(normalized);
284
+ if (encoded === void 0) throw new EditableArtifactDurableExportError("invalid_request");
285
+ return encoded;
286
+ }
287
+ function validateProfile(profile, modality, format) {
288
+ if (!plainRecord(profile) || profile.modality !== modality || profile.format !== format || !editableArtifactFormatMatchesModality(modality, format) || !boundedProfileText(profile.codecId, 128) || !boundedProfileText(profile.codecVersion, 128) || !boundedProfileText(profile.kernelVersion, 512) || !SHA256.test(profile.fontRegistryHash) || !SHA256.test(profile.policyHash) || profile.normalizedOptions.trim() !== profile.normalizedOptions || new TextEncoder().encode(profile.normalizedOptions).byteLength > EDITABLE_ARTIFACT_EXPORT_MAX_OPTIONS_BYTES) {
289
+ throw new EditableArtifactDurableExportError("unavailable");
290
+ }
291
+ let decoded;
292
+ try {
293
+ decoded = JSON.parse(profile.normalizedOptions);
294
+ } catch {
295
+ throw new EditableArtifactDurableExportError("unavailable");
296
+ }
297
+ if (!plainRecord(decoded) || canonicalJson(decoded) !== profile.normalizedOptions) {
298
+ throw new EditableArtifactDurableExportError("unavailable");
299
+ }
300
+ }
301
+ function boundedProfileText(value, maximumBytes) {
302
+ return typeof value === "string" && PROFILE_TEXT.test(value) && new TextEncoder().encode(value).byteLength <= maximumBytes;
303
+ }
304
+ function hashPublicRequest(kind, fields) {
305
+ const digest = createHash("sha256");
306
+ digest.update("OpenGeni editable artifact durable export\0v1\0", "utf8");
307
+ digest.update(kind, "utf8");
308
+ digest.update("\0", "utf8");
309
+ for (const field of fields) {
310
+ const bytes = Buffer.from(field, "utf8");
311
+ const length = Buffer.allocUnsafe(4);
312
+ length.writeUInt32BE(bytes.byteLength);
313
+ digest.update(length);
314
+ digest.update(bytes);
315
+ }
316
+ return `sha256:${digest.digest("hex")}`;
317
+ }
318
+ function plainRecord(value) {
319
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
320
+ const prototype = Object.getPrototypeOf(value);
321
+ return prototype === Object.prototype || prototype === null;
322
+ }
323
+ function jsonValue(value, depth = 0) {
324
+ if (depth > 32) return false;
325
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
326
+ return typeof value !== "string" || wellFormedText(value);
327
+ }
328
+ if (typeof value === "number") return Number.isFinite(value);
329
+ if (Array.isArray(value))
330
+ return value.length <= 1e4 && value.every((item) => jsonValue(item, depth + 1));
331
+ if (!plainRecord(value) || Object.keys(value).length > 1e4) return false;
332
+ return Object.entries(value).every(
333
+ ([key, item]) => wellFormedText(key) && jsonValue(item, depth + 1)
334
+ );
335
+ }
336
+ function wellFormedText(value) {
337
+ if (value.includes("\0")) return false;
338
+ for (let index = 0; index < value.length; index += 1) {
339
+ const unit = value.charCodeAt(index);
340
+ if (unit >= 55296 && unit <= 56319) {
341
+ const next = value.charCodeAt(index + 1);
342
+ if (!Number.isFinite(next) || next < 56320 || next > 57343) return false;
343
+ index += 1;
344
+ } else if (unit >= 56320 && unit <= 57343) {
345
+ return false;
346
+ }
347
+ }
348
+ return true;
349
+ }
350
+ function compareCodeUnits(left, right) {
351
+ return left < right ? -1 : left > right ? 1 : 0;
352
+ }
353
+ function validateEditableArtifactPinnedVersion(version) {
354
+ const scope = editableArtifactScope(version.scope);
355
+ const artifactId = editableArtifactId(version.artifactId);
356
+ const id = stableId(version.id, "version id");
357
+ const snapshotId = editableArtifactSnapshotId(version.snapshotId);
358
+ if (!Number.isSafeInteger(version.headSequence) || version.headSequence < 0) {
359
+ throw new EditableArtifactDurableExportError("unavailable");
360
+ }
361
+ const stateHash = editableArtifactStateHash(version.stateHash);
362
+ versionName(version.name);
363
+ assertIsoTimestamp(version.createdAt, "version creation time");
364
+ if (version.pinned !== true || !wellFormedText(version.createdBySubjectId)) {
365
+ throw new EditableArtifactDurableExportError("unavailable");
366
+ }
367
+ if (version.modality === "spreadsheet" && (!Array.isArray(version.causalFrontier) || version.nativeRevision !== null) || version.modality !== "spreadsheet" && (version.causalFrontier !== null || !Number.isSafeInteger(version.nativeRevision) || version.nativeRevision < 0)) {
368
+ throw new EditableArtifactDurableExportError("unavailable");
369
+ }
370
+ return Object.freeze({
371
+ ...version,
372
+ scope,
373
+ artifactId,
374
+ id,
375
+ snapshotId,
376
+ stateHash,
377
+ causalFrontier: version.causalFrontier === null ? null : Object.freeze(version.causalFrontier.map((entry) => Object.freeze({ ...entry })))
378
+ });
379
+ }
380
+ function validateEditableArtifactMaterializationJob(job) {
381
+ const scope = editableArtifactScope(job.scope);
382
+ const artifactId = editableArtifactId(job.artifactId);
383
+ const id = stableId(job.id, "job id");
384
+ const versionId = stableId(job.versionId, "version id");
385
+ const inputSnapshotId = stableId(job.inputSnapshotId, "snapshot id");
386
+ const stateHash = editableArtifactStateHash(job.stateHash);
387
+ const format = materializationFormat(job.format);
388
+ if (!Number.isSafeInteger(job.targetHeadSequence) || job.targetHeadSequence < 0 || !Number.isSafeInteger(job.attemptCount) || job.attemptCount < 0 || !["pending", "running", "succeeded", "failed"].includes(job.state)) {
389
+ throw new EditableArtifactDurableExportError("unavailable");
390
+ }
391
+ assertIsoTimestamp(job.createdAt, "job creation time");
392
+ if (job.startedAt !== null) assertIsoTimestamp(job.startedAt, "job start time");
393
+ if (job.completedAt !== null) assertIsoTimestamp(job.completedAt, "job completion time");
394
+ let result = null;
395
+ if (job.result) {
396
+ result = Object.freeze({
397
+ ...job.result,
398
+ id: stableId(job.result.id, "result id"),
399
+ contentHash: editableArtifactContentHash(job.result.contentHash),
400
+ mimeType: editableArtifactMaterializationMimeType(format)
401
+ });
402
+ if (job.result.mimeType !== result.mimeType || !Number.isSafeInteger(job.result.byteSize) || job.result.byteSize < 1 || job.result.byteSize > EDITABLE_ARTIFACT_EXPORT_MAX_DOWNLOAD_BYTES) {
403
+ throw new EditableArtifactDurableExportError("unavailable");
404
+ }
405
+ assertIsoTimestamp(job.result.verifiedAt, "result verification time");
406
+ assertIsoTimestamp(job.result.createdAt, "result creation time");
407
+ }
408
+ if (job.state === "succeeded" !== (result !== null)) {
409
+ throw new EditableArtifactDurableExportError("unavailable");
410
+ }
411
+ return Object.freeze({
412
+ ...job,
413
+ scope,
414
+ artifactId,
415
+ id,
416
+ versionId,
417
+ inputSnapshotId,
418
+ stateHash,
419
+ format,
420
+ result
421
+ });
422
+ }
423
+
424
+ // src/domain/editable-artifacts/agent-application.ts
425
+ import { createHash as createHash2 } from "crypto";
426
+ import {
427
+ COMMITTED_TRANSACTION_PROTOCOL_VERSION,
428
+ EDITABLE_ARTIFACT_MODEL_SCHEMA_VERSION
429
+ } from "@opengeni/contracts/editable-artifact-versions";
430
+ import {
431
+ DOCUMENT_ARTIFACT_COMMAND_VERSION,
432
+ EDITABLE_ARTIFACT_INTENT_VERSION,
433
+ PRESENTATION_ARTIFACT_COMMAND_VERSION,
434
+ SPREADSHEET_ARTIFACT_COMMAND_VERSION,
435
+ decodeEditableArtifactMutationIntent,
436
+ decodeDocumentArtifactQueryResponse,
437
+ decodePresentationArtifactQueryResponse,
438
+ decodeSpreadsheetArtifactKernelProjection,
439
+ encodeDocumentArtifactCommandBatch,
440
+ encodeDocumentArtifactQuery,
441
+ encodePresentationArtifactCommandBatch,
442
+ encodePresentationArtifactQuery,
443
+ encodeSpreadsheetArtifactCommandBatch,
444
+ encodeSpreadsheetArtifactKernelQuery,
445
+ hashEditableArtifactMutationIntent
446
+ } from "@opengeni/contracts/editable-artifacts";
447
+ var EditableArtifactOfficeImportError = class extends Error {
448
+ constructor(code) {
449
+ super(code);
450
+ this.code = code;
451
+ this.name = "EditableArtifactOfficeImportError";
452
+ }
453
+ };
454
+ var EditableArtifactAgentApplication = class {
455
+ constructor(dependencies) {
456
+ this.dependencies = dependencies;
457
+ }
458
+ async list(input) {
459
+ const context = agentContext(input);
460
+ const limit = boundedLimit(input.limit ?? 64);
461
+ const ids = await this.dependencies.associations.listArtifactIds({
462
+ scope: context.scope,
463
+ sessionId: context.sessionId,
464
+ limit
465
+ });
466
+ const artifacts = [];
467
+ for (const artifactId of ids) {
468
+ try {
469
+ const artifact = await this.dependencies.domain.getArtifact({
470
+ scope: context.scope,
471
+ actor: context.actor,
472
+ artifactId
473
+ });
474
+ artifacts.push(projectArtifact(artifact));
475
+ } catch (error) {
476
+ if (error instanceof EditableArtifactNotFoundError || error instanceof EditableArtifactDomainError && error.code === "forbidden") {
477
+ continue;
478
+ }
479
+ throw error;
480
+ }
481
+ }
482
+ return Object.freeze(artifacts);
483
+ }
484
+ async create(input) {
485
+ const context = agentContext(input);
486
+ const result = await this.dependencies.domain.createArtifact({
487
+ scope: context.scope,
488
+ actor: context.actor,
489
+ request: {
490
+ idempotencyKey: editableArtifactClientTransactionId(input.idempotencyKey),
491
+ modality: input.modality,
492
+ title: input.title
493
+ },
494
+ ...input.signal ? { signal: input.signal } : {}
495
+ });
496
+ await this.touch(context, result.artifact.id);
497
+ return projectArtifact(result.artifact);
498
+ }
499
+ async import(input) {
500
+ const context = agentContext(input);
501
+ const prepared = await this.dependencies.officeImports.prepare({
502
+ scope: context.scope,
503
+ actor: context.actor,
504
+ fileId: input.fileId,
505
+ modality: input.modality,
506
+ ...input.signal ? { signal: input.signal } : {}
507
+ });
508
+ const result = await this.dependencies.domain.importArtifact({
509
+ scope: context.scope,
510
+ actor: context.actor,
511
+ request: {
512
+ idempotencyKey: editableArtifactClientTransactionId(input.idempotencyKey),
513
+ modality: input.modality,
514
+ title: input.title,
515
+ originalImport: prepared.originalImport,
516
+ snapshot: prepared.snapshot
517
+ },
518
+ ...input.signal ? { signal: input.signal } : {}
519
+ });
520
+ await this.touch(context, result.artifact.id);
521
+ return projectArtifact(result.artifact);
522
+ }
523
+ async get(input) {
524
+ const context = agentContext(input);
525
+ const artifact = await this.dependencies.domain.getArtifact({
526
+ scope: context.scope,
527
+ actor: context.actor,
528
+ artifactId: editableArtifactId(input.artifactId)
529
+ });
530
+ await this.touch(context, artifact.id);
531
+ return projectArtifact(artifact);
532
+ }
533
+ async inspect(input) {
534
+ const context = agentContext(input);
535
+ const artifactId = editableArtifactId(input.artifactId);
536
+ const state = await this.dependencies.domain.readCurrentKernelState({
537
+ scope: context.scope,
538
+ actor: context.actor,
539
+ artifactId
540
+ });
541
+ if (state.modality !== input.request.modality)
542
+ throw new TypeError("Artifact modality mismatch");
543
+ const queryBytes = encodeQuery(input.request);
544
+ const responseBytes = await this.dependencies.inspector.query({ state, queryBytes });
545
+ const projection = decodeQueryResponse(input.request.modality, responseBytes);
546
+ await this.touch(context, artifactId);
547
+ return Object.freeze({ artifact: projectArtifact(state.artifact), projection });
548
+ }
549
+ async apply(input) {
550
+ const context = agentContext(input);
551
+ const artifactId = editableArtifactId(input.artifactId);
552
+ const commandBytes = encodeCommands(input.batch);
553
+ const clientTransactionId = editableArtifactClientTransactionId(input.clientTransactionId);
554
+ const expectedHeadSequence = boundedHeadSequence(input.expectedHeadSequence);
555
+ const expectedStateHash = editableArtifactStateHash(input.expectedStateHash);
556
+ const artifact = await this.dependencies.domain.getArtifact({
557
+ scope: context.scope,
558
+ actor: context.actor,
559
+ artifactId
560
+ });
561
+ if (artifact.modality !== input.batch.modality)
562
+ throw new TypeError("Artifact modality mismatch");
563
+ if (artifact.headSequence !== expectedHeadSequence || artifact.stateHash !== expectedStateHash) {
564
+ const existing = await this.dependencies.domain.findTransactionReceipt({
565
+ scope: context.scope,
566
+ actor: context.actor,
567
+ artifactId,
568
+ clientTransactionId
569
+ });
570
+ if (existing) {
571
+ if (!receiptMatchesAgentMutation(
572
+ existing,
573
+ expectedHeadSequence,
574
+ expectedStateHash,
575
+ commandBytes
576
+ )) {
577
+ throw new EditableArtifactIdempotencyConflictError();
578
+ }
579
+ await this.touch(context, artifactId);
580
+ return Object.freeze({
581
+ artifact: projectArtifact(artifact),
582
+ transaction: projectReceipt(existing, true)
583
+ });
584
+ }
585
+ throw new EditableArtifactStaleBaseError();
586
+ }
587
+ const authored = hashEditableArtifactMutationIntent({
588
+ envelopeVersion: EDITABLE_ARTIFACT_INTENT_VERSION,
589
+ protocolVersion: COMMITTED_TRANSACTION_PROTOCOL_VERSION,
590
+ modelSchemaVersion: EDITABLE_ARTIFACT_MODEL_SCHEMA_VERSION,
591
+ commandProtocolVersion: commandProtocolVersion(input.batch.modality),
592
+ artifactId,
593
+ clientTransactionId,
594
+ replicaId: context.actor.replicaId,
595
+ replicaCounter: 1,
596
+ previousLocalTransactionId: null,
597
+ observedHeadSequence: expectedHeadSequence,
598
+ causalBase: artifact.modality === "spreadsheet" ? artifact.causalFrontier : [],
599
+ selectiveUndoOperationIds: [],
600
+ commandBytes
601
+ });
602
+ let applied;
603
+ try {
604
+ applied = await this.dependencies.domain.applyTransaction({
605
+ scope: context.scope,
606
+ actor: context.actor,
607
+ artifactId,
608
+ request: {
609
+ intentBytes: authored.bytes,
610
+ requestHash: editableArtifactRequestHash(authored.requestHash),
611
+ expectedHead: Object.freeze({
612
+ sequence: expectedHeadSequence,
613
+ stateHash: expectedStateHash
614
+ })
615
+ }
616
+ });
617
+ } catch (error) {
618
+ if (!(error instanceof EditableArtifactIdempotencyConflictError)) throw error;
619
+ const receipt = await this.dependencies.domain.findTransactionReceipt({
620
+ scope: context.scope,
621
+ actor: context.actor,
622
+ artifactId,
623
+ clientTransactionId
624
+ });
625
+ if (!receipt || !receiptMatchesAgentMutation(receipt, expectedHeadSequence, expectedStateHash, commandBytes)) {
626
+ throw error;
627
+ }
628
+ applied = Object.freeze({ receipt, replayed: true });
629
+ }
630
+ const current = await this.dependencies.domain.getArtifact({
631
+ scope: context.scope,
632
+ actor: context.actor,
633
+ artifactId
634
+ });
635
+ await this.touch(context, artifactId);
636
+ return Object.freeze({
637
+ artifact: projectArtifact(current),
638
+ transaction: projectReceipt(applied.receipt, applied.replayed)
639
+ });
640
+ }
641
+ async startExport(input) {
642
+ const context = agentContext(input);
643
+ const artifactId = editableArtifactId(input.artifactId);
644
+ const artifact = await this.dependencies.domain.getArtifact({
645
+ scope: context.scope,
646
+ actor: context.actor,
647
+ artifactId
648
+ });
649
+ const version = await this.dependencies.exports.pinVersion({
650
+ scope: context.scope,
651
+ actor: context.actor,
652
+ artifactId,
653
+ idempotencyKey: exportChildIdempotencyKey(input.idempotencyKey, "version"),
654
+ name: `Export ${artifact.title}`,
655
+ ...input.signal ? { signal: input.signal } : {}
656
+ });
657
+ const materialization = await this.dependencies.exports.enqueueMaterialization({
658
+ scope: context.scope,
659
+ actor: context.actor,
660
+ artifactId,
661
+ idempotencyKey: exportChildIdempotencyKey(input.idempotencyKey, "materialization"),
662
+ versionId: version.version.id,
663
+ format: input.format,
664
+ ...input.options ? { options: input.options } : {}
665
+ });
666
+ const current = await this.dependencies.domain.getArtifact({
667
+ scope: context.scope,
668
+ actor: context.actor,
669
+ artifactId
670
+ });
671
+ await this.touch(context, artifactId);
672
+ return Object.freeze({
673
+ artifact: projectArtifact(current),
674
+ versionId: version.version.id,
675
+ jobId: materialization.job.id,
676
+ sourceHeadSequence: materialization.job.targetHeadSequence,
677
+ sourceStateHash: materialization.job.stateHash,
678
+ state: materialization.job.state
679
+ });
680
+ }
681
+ async exportStatus(input) {
682
+ const context = agentContext(input);
683
+ const artifactId = editableArtifactId(input.artifactId);
684
+ const artifact = await this.dependencies.domain.getArtifact({
685
+ scope: context.scope,
686
+ actor: context.actor,
687
+ artifactId
688
+ });
689
+ const job = await this.dependencies.exports.getMaterialization({
690
+ scope: context.scope,
691
+ actor: context.actor,
692
+ artifactId,
693
+ jobId: input.jobId
694
+ });
695
+ if (job.versionId !== input.versionId) throw new TypeError("Export version mismatch");
696
+ const file = job.state === "succeeded" && job.result ? await this.dependencies.workspaceFiles.ensureMaterializationFile({
697
+ scope: context.scope,
698
+ actor: context.actor,
699
+ artifact,
700
+ versionId: job.versionId,
701
+ jobId: job.id,
702
+ filename: defaultExportFilename(artifact.title, job.format),
703
+ sourceHeadSequence: job.targetHeadSequence,
704
+ sourceStateHash: job.stateHash,
705
+ ...input.signal ? { signal: input.signal } : {}
706
+ }) : null;
707
+ await this.touch(context, artifactId);
708
+ return Object.freeze({
709
+ artifact: projectArtifact(artifact),
710
+ versionId: job.versionId,
711
+ jobId: job.id,
712
+ sourceHeadSequence: job.targetHeadSequence,
713
+ sourceStateHash: job.stateHash,
714
+ state: job.state,
715
+ errorCode: job.errorCode,
716
+ file
717
+ });
718
+ }
719
+ async touch(context, artifactId) {
720
+ await this.dependencies.associations.touch({
721
+ scope: context.scope,
722
+ sessionId: context.sessionId,
723
+ artifactId
724
+ });
725
+ }
726
+ };
727
+ function agentContext(input) {
728
+ const scope = editableArtifactScope(input.scope);
729
+ validateEditableArtifactActor(input.actor);
730
+ if (input.actor.kind !== "agent" || input.actor.sessionId !== input.sessionId) {
731
+ throw new TypeError("Artifact agent context is not bound to its attempt session");
732
+ }
733
+ return Object.freeze({
734
+ scope,
735
+ actor: Object.freeze({ ...input.actor }),
736
+ sessionId: boundedSessionId(input.sessionId)
737
+ });
738
+ }
739
+ function encodeCommands(batch) {
740
+ if (batch.modality === "spreadsheet") {
741
+ return encodeSpreadsheetArtifactCommandBatch({ version: 1, commands: batch.commands });
742
+ }
743
+ if (batch.modality === "document") {
744
+ return encodeDocumentArtifactCommandBatch({ version: 1, commands: batch.commands });
745
+ }
746
+ return encodePresentationArtifactCommandBatch({ version: 1, commands: batch.commands });
747
+ }
748
+ function encodeQuery(request) {
749
+ if (request.modality === "spreadsheet") {
750
+ return encodeSpreadsheetArtifactKernelQuery(request.query);
751
+ }
752
+ if (request.modality === "document") return encodeDocumentArtifactQuery(request.query);
753
+ return encodePresentationArtifactQuery(request.query);
754
+ }
755
+ function decodeQueryResponse(modality, bytes) {
756
+ if (modality === "spreadsheet") return decodeSpreadsheetArtifactKernelProjection(bytes);
757
+ if (modality === "document") return decodeDocumentArtifactQueryResponse(bytes);
758
+ return decodePresentationArtifactQueryResponse(bytes);
759
+ }
760
+ function commandProtocolVersion(modality) {
761
+ if (modality === "spreadsheet") return SPREADSHEET_ARTIFACT_COMMAND_VERSION;
762
+ if (modality === "document") return DOCUMENT_ARTIFACT_COMMAND_VERSION;
763
+ return PRESENTATION_ARTIFACT_COMMAND_VERSION;
764
+ }
765
+ function projectArtifact(artifact) {
766
+ return Object.freeze({
767
+ id: artifact.id,
768
+ modality: artifact.modality,
769
+ title: artifact.title,
770
+ lifecycle: artifact.lifecycle,
771
+ headSequence: artifact.headSequence,
772
+ stateHash: artifact.stateHash,
773
+ createdAt: artifact.createdAt,
774
+ updatedAt: artifact.updatedAt
775
+ });
776
+ }
777
+ function projectReceipt(receipt, replayed) {
778
+ return Object.freeze({
779
+ id: receipt.serverTransactionId,
780
+ clientTransactionId: receipt.clientTransactionId,
781
+ sequenceStart: receipt.sequenceStart,
782
+ sequenceEnd: receipt.sequenceEnd,
783
+ stateHash: receipt.stateHash,
784
+ committedAt: receipt.committedAt,
785
+ replayed
786
+ });
787
+ }
788
+ function receiptMatchesAgentMutation(receipt, expectedHeadSequence, expectedStateHash, commandBytes) {
789
+ const intent = decodeEditableArtifactMutationIntent(receipt.intentBytes);
790
+ return intent.observedHeadSequence === expectedHeadSequence && receipt.priorStateHash === expectedStateHash && sameBytes(commandBytes, intent.commandBytes);
791
+ }
792
+ function sameBytes(left, right) {
793
+ if (left.byteLength !== right.byteLength) return false;
794
+ for (let index = 0; index < left.byteLength; index += 1) {
795
+ if (left[index] !== right[index]) return false;
796
+ }
797
+ return true;
798
+ }
799
+ function boundedSessionId(value) {
800
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(value)) {
801
+ throw new TypeError("Artifact session id is invalid");
802
+ }
803
+ return value;
804
+ }
805
+ function boundedLimit(value) {
806
+ if (!Number.isSafeInteger(value) || value < 1 || value > 64) {
807
+ throw new TypeError("Artifact list limit must be between 1 and 64");
808
+ }
809
+ return value;
810
+ }
811
+ function boundedHeadSequence(value) {
812
+ if (!Number.isSafeInteger(value) || value < 0) {
813
+ throw new TypeError("Artifact expected head sequence must be a nonnegative safe integer");
814
+ }
815
+ return value;
816
+ }
817
+ function defaultExportFilename(title, format) {
818
+ const stem = title.normalize("NFKC").replace(/[\\/:*?"<>|\u0000-\u001f\u007f]+/gu, "-").replace(/\s+/gu, " ").trim().slice(0, 180);
819
+ return `${stem || "artifact"}.${format}`;
820
+ }
821
+ function exportChildIdempotencyKey(value, operation) {
822
+ const digest = createHash2("sha256").update("opengeni:editable-artifact-export:v1\0", "utf8").update(operation, "utf8").update("\0", "utf8").update(value, "utf8").digest("hex");
823
+ return `artifact-export:${operation}:${digest}`;
824
+ }
825
+
826
+ // src/domain/editable-artifacts/durable-export-postgres.ts
827
+ import {
828
+ EditableArtifactDurableExportPersistenceError
829
+ } from "@opengeni/db/editable-artifact-durable-export";
830
+ function editableArtifactDurableExportStorePortFromPostgres(store) {
831
+ return Object.freeze({
832
+ async pinVersion(input) {
833
+ try {
834
+ const result = await store.pinVersion(persistedPinRequest(input));
835
+ if (result.kind === "authorization_stale") return result;
836
+ return Object.freeze({
837
+ kind: "result",
838
+ version: versionFromPersisted(result.value.version),
839
+ replayed: result.value.replayed
840
+ });
841
+ } catch (error) {
842
+ throw mapPersistenceError(error);
843
+ }
844
+ },
845
+ async enqueueMaterialization(input) {
846
+ try {
847
+ const result = await store.enqueueMaterialization(persistedEnqueueRequest(input));
848
+ if (result.kind === "authorization_stale") return result;
849
+ return Object.freeze({
850
+ kind: "result",
851
+ job: jobFromPersisted(result.value.job),
852
+ replayed: result.value.replayed
853
+ });
854
+ } catch (error) {
855
+ throw mapPersistenceError(error);
856
+ }
857
+ },
858
+ async readVersion(input) {
859
+ try {
860
+ const result = await store.readVersion(input);
861
+ if (result.kind === "authorization_stale") return result;
862
+ return Object.freeze({
863
+ kind: "result",
864
+ version: result.value ? versionFromPersisted(result.value) : null
865
+ });
866
+ } catch (error) {
867
+ throw mapPersistenceError(error);
868
+ }
869
+ },
870
+ async readMaterialization(input) {
871
+ try {
872
+ const result = await store.readMaterialization(input);
873
+ if (result.kind === "authorization_stale") return result;
874
+ return Object.freeze({
875
+ kind: "result",
876
+ job: result.value ? jobFromPersisted(result.value) : null
877
+ });
878
+ } catch (error) {
879
+ throw mapPersistenceError(error);
880
+ }
881
+ },
882
+ async readMaterializationDownload(input) {
883
+ try {
884
+ const result = await store.readMaterializationDownload(input);
885
+ if (result.kind === "authorization_stale") return result;
886
+ return Object.freeze({
887
+ kind: "result",
888
+ job: result.value.job ? jobFromPersisted(result.value.job) : null,
889
+ objectReference: result.value.objectReference
890
+ });
891
+ } catch (error) {
892
+ throw mapPersistenceError(error);
893
+ }
894
+ }
895
+ });
896
+ }
897
+ function persistedPinRequest(input) {
898
+ const snapshot = input.snapshot;
899
+ return {
900
+ ...input,
901
+ snapshot: {
902
+ modality: snapshot.modality,
903
+ snapshotId: snapshot.snapshotId,
904
+ coveredHeadSequence: snapshot.coveredHeadSequence,
905
+ stateHash: snapshot.stateHash,
906
+ coveredCausalFrontier: snapshot.modality === "spreadsheet" ? snapshot.coveredCausalFrontier : null,
907
+ nativeRevision: snapshot.modality === "spreadsheet" ? null : snapshot.nativeRevision
908
+ }
909
+ };
910
+ }
911
+ function persistedEnqueueRequest(input) {
912
+ return { ...input };
913
+ }
914
+ function versionFromPersisted(value) {
915
+ return validateEditableArtifactPinnedVersion(value);
916
+ }
917
+ function jobFromPersisted(value) {
918
+ return validateEditableArtifactMaterializationJob(value);
919
+ }
920
+ function mapPersistenceError(error) {
921
+ if (!(error instanceof EditableArtifactDurableExportPersistenceError)) return error;
922
+ switch (error.code) {
923
+ case "not_found":
924
+ return new EditableArtifactDurableExportError("not_found");
925
+ case "idempotency_conflict":
926
+ case "snapshot_conflict":
927
+ return new EditableArtifactDurableExportError("conflict");
928
+ case "unsupported_format":
929
+ return new EditableArtifactDurableExportError("unsupported_format");
930
+ case "database_contract_violation":
931
+ return new EditableArtifactDurableExportError("unavailable");
932
+ }
933
+ }
934
+
935
+ // src/domain/editable-artifacts/in-memory.ts
936
+ import { decodeCommittedTransactionSummary } from "@opengeni/contracts/editable-artifact-committed-transaction";
937
+ import { decodeEditableArtifactSerializedCommit } from "@opengeni/contracts/editable-artifact-serialized-commit";
938
+ var InMemoryEditableArtifactStore = class {
939
+ constructor(now = () => /* @__PURE__ */ new Date()) {
940
+ this.now = now;
941
+ }
942
+ aggregates = /* @__PURE__ */ new Map();
943
+ creationReceipts = /* @__PURE__ */ new Map();
944
+ scopeCreateAuthorizationRevisions = /* @__PURE__ */ new Map();
945
+ exclusiveTail = Promise.resolve();
946
+ async findArtifactCreation(scopeInput, operationKind, authorityKey, idempotencyKeyInput) {
947
+ const scope = editableArtifactScope(scopeInput);
948
+ const idempotencyKey = editableArtifactClientTransactionId(idempotencyKeyInput);
949
+ const key = creationReceiptKey(scope, operationKind, authorityKey, idempotencyKey);
950
+ return this.exclusive(async () => {
951
+ const receipt = this.creationReceipts.get(key);
952
+ if (!receipt) return null;
953
+ const aggregate = this.aggregates.get(aggregateKey(scope, receipt.artifactId));
954
+ const snapshot = aggregate?.snapshots.get(receipt.genesisSnapshotId);
955
+ if (!aggregate || !snapshot) {
956
+ throw new Error("Artifact creation receipt is corrupt");
957
+ }
958
+ return Object.freeze({
959
+ artifact: cloneArtifact(aggregate.artifact),
960
+ genesisSnapshot: cloneSnapshot(snapshot),
961
+ creationReceipt: cloneCreationReceipt(receipt),
962
+ replayed: true
963
+ });
964
+ });
965
+ }
966
+ async createArtifact(input) {
967
+ const scope = editableArtifactScope(input.scope);
968
+ const artifactId = editableArtifactId(input.artifactId);
969
+ const receiptId = editableArtifactReceiptId(input.receiptId);
970
+ const idempotencyKey = editableArtifactClientTransactionId(input.idempotencyKey);
971
+ const requestHash = editableArtifactRequestHash(input.requestHash);
972
+ if (input.operationKind !== "create" && input.operationKind !== "import") {
973
+ throw new TypeError("Unknown editable artifact origin operation");
974
+ }
975
+ if (input.operationKind === "import" !== Boolean(input.originalImport)) {
976
+ throw new TypeError("Editable artifact import source does not match its origin operation");
977
+ }
978
+ assertBoundedArtifactTitle(input.title);
979
+ assertPositiveSafeInteger(
980
+ input.expectedScopeAuthorizationRevision,
981
+ "expected scope create authorization revision"
982
+ );
983
+ assertPositiveSafeInteger(
984
+ input.initialArtifactAuthorizationRevision,
985
+ "initial artifact authorization revision"
986
+ );
987
+ const genesisSnapshot = cloneSnapshot(input.genesisSnapshot);
988
+ const outbox = cloneOutbox(input.outbox);
989
+ assertGenesisCreateRequest(scope, artifactId, input.operationKind, genesisSnapshot, outbox);
990
+ if (!["spreadsheet", "presentation", "document"].includes(input.modality)) {
991
+ throw new TypeError("Unknown editable artifact modality");
992
+ }
993
+ if (genesisSnapshot.modality !== input.modality) {
994
+ throw new TypeError("Genesis snapshot modality does not match artifact modality");
995
+ }
996
+ const creationKey = creationReceiptKey(
997
+ scope,
998
+ input.operationKind,
999
+ input.authorityKey,
1000
+ idempotencyKey
1001
+ );
1002
+ return this.exclusive(async () => {
1003
+ const prior = this.creationReceipts.get(creationKey);
1004
+ if (prior) {
1005
+ if (prior.requestHash !== requestHash) {
1006
+ throw new EditableArtifactIdempotencyConflictError();
1007
+ }
1008
+ const replay = this.aggregates.get(aggregateKey(scope, prior.artifactId));
1009
+ if (!replay) throw new Error("Artifact creation receipt is corrupt");
1010
+ const replaySnapshot = replay.snapshots.get(prior.genesisSnapshotId);
1011
+ if (!replaySnapshot) {
1012
+ throw new Error("Artifact creation receipt has no genesis snapshot");
1013
+ }
1014
+ return Object.freeze({
1015
+ kind: "result",
1016
+ value: Object.freeze({
1017
+ artifact: cloneArtifact(replay.artifact),
1018
+ genesisSnapshot: cloneSnapshot(replaySnapshot),
1019
+ creationReceipt: cloneCreationReceipt(prior),
1020
+ replayed: true
1021
+ })
1022
+ });
1023
+ }
1024
+ const scopeKey = authorizationScopeKey(scope);
1025
+ const currentScopeRevision = this.scopeCreateAuthorizationRevisions.get(scopeKey) ?? 1;
1026
+ if (currentScopeRevision !== input.expectedScopeAuthorizationRevision) {
1027
+ return Object.freeze({ kind: "authorization_stale" });
1028
+ }
1029
+ const key = aggregateKey(scope, artifactId);
1030
+ if (this.aggregates.has(key)) {
1031
+ throw new Error("Editable artifact identity already exists");
1032
+ }
1033
+ const commonArtifact = {
1034
+ scope,
1035
+ id: artifactId,
1036
+ title: input.title,
1037
+ lifecycle: "active",
1038
+ authorizationRevision: input.initialArtifactAuthorizationRevision,
1039
+ headSequence: 0,
1040
+ stateHash: genesisSnapshot.stateHash,
1041
+ currentSnapshotId: genesisSnapshot.snapshotId,
1042
+ createdAt: genesisSnapshot.publishedAt,
1043
+ updatedAt: genesisSnapshot.publishedAt
1044
+ };
1045
+ const artifact = input.modality === "spreadsheet" ? {
1046
+ ...commonArtifact,
1047
+ modality: "spreadsheet",
1048
+ causalFrontier: editableArtifactCausalFrontier(
1049
+ genesisSnapshot.modality === "spreadsheet" ? genesisSnapshot.coveredCausalFrontier : []
1050
+ )
1051
+ } : { ...commonArtifact, modality: input.modality };
1052
+ const creationReceipt = Object.freeze({
1053
+ receiptId,
1054
+ scope,
1055
+ artifactId,
1056
+ operationKind: input.operationKind,
1057
+ authorityKey: input.authorityKey,
1058
+ idempotencyKey,
1059
+ requestHash,
1060
+ genesisSnapshotId: genesisSnapshot.snapshotId,
1061
+ createdAt: genesisSnapshot.publishedAt
1062
+ });
1063
+ this.aggregates.set(key, emptyAggregate(artifact, genesisSnapshot, outbox));
1064
+ this.creationReceipts.set(creationKey, creationReceipt);
1065
+ return Object.freeze({
1066
+ kind: "result",
1067
+ value: Object.freeze({
1068
+ artifact: cloneArtifact(artifact),
1069
+ genesisSnapshot: cloneSnapshot(genesisSnapshot),
1070
+ creationReceipt: cloneCreationReceipt(creationReceipt),
1071
+ replayed: false
1072
+ })
1073
+ });
1074
+ });
1075
+ }
1076
+ async readScopeCreateAuthorizationRevision(scope) {
1077
+ const key = authorizationScopeKey(editableArtifactScope(scope));
1078
+ return this.exclusive(async () => {
1079
+ const revision = this.scopeCreateAuthorizationRevisions.get(key) ?? 1;
1080
+ this.scopeCreateAuthorizationRevisions.set(key, revision);
1081
+ return revision;
1082
+ });
1083
+ }
1084
+ async advanceScopeCreateAuthorizationRevision(scope, expectedRevision, nextRevision) {
1085
+ assertPositiveSafeInteger(expectedRevision, "expected scope create authorization revision");
1086
+ assertPositiveSafeInteger(nextRevision, "next scope create authorization revision");
1087
+ if (nextRevision <= expectedRevision) {
1088
+ throw new TypeError(
1089
+ "Next scope create authorization revision must exceed the expected revision"
1090
+ );
1091
+ }
1092
+ const key = authorizationScopeKey(editableArtifactScope(scope));
1093
+ return this.exclusive(async () => {
1094
+ const current = this.scopeCreateAuthorizationRevisions.get(key) ?? 1;
1095
+ if (current !== expectedRevision) {
1096
+ return Object.freeze({
1097
+ applied: false,
1098
+ authorizationRevision: current
1099
+ });
1100
+ }
1101
+ this.scopeCreateAuthorizationRevisions.set(key, nextRevision);
1102
+ return Object.freeze({
1103
+ applied: true,
1104
+ authorizationRevision: nextRevision
1105
+ });
1106
+ });
1107
+ }
1108
+ async seedArtifact(input) {
1109
+ const scope = editableArtifactScope(input.scope);
1110
+ const artifactId = editableArtifactId(input.artifactId);
1111
+ assertBoundedArtifactTitle(input.title);
1112
+ const stateHash = editableArtifactStateHash(input.stateHash);
1113
+ const createdAt = input.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString();
1114
+ assertIsoTimestamp(createdAt, "artifact creation timestamp");
1115
+ if (!["spreadsheet", "presentation", "document"].includes(input.modality)) {
1116
+ throw new TypeError("Unknown editable artifact modality");
1117
+ }
1118
+ const lifecycle = input.lifecycle ?? "active";
1119
+ if (lifecycle !== "active" && lifecycle !== "archived") {
1120
+ throw new TypeError("Unknown editable artifact lifecycle state");
1121
+ }
1122
+ const authorizationRevision = input.authorizationRevision ?? 1;
1123
+ assertPositiveSafeInteger(authorizationRevision, "artifact authorization revision");
1124
+ const title = input.title;
1125
+ const modality = input.modality;
1126
+ const nativeRevision = input.nativeRevision ?? 0;
1127
+ assertNonnegativeSafeInteger(nativeRevision, "artifact native revision");
1128
+ return this.exclusive(async () => {
1129
+ const key = aggregateKey(scope, artifactId);
1130
+ if (this.aggregates.has(key)) throw new Error("Editable artifact is already seeded");
1131
+ const commonArtifact = {
1132
+ scope,
1133
+ id: artifactId,
1134
+ title,
1135
+ lifecycle,
1136
+ authorizationRevision,
1137
+ headSequence: 0,
1138
+ stateHash,
1139
+ currentSnapshotId: null,
1140
+ createdAt,
1141
+ updatedAt: createdAt
1142
+ };
1143
+ const artifact = modality === "spreadsheet" ? {
1144
+ ...commonArtifact,
1145
+ modality: "spreadsheet",
1146
+ causalFrontier: editableArtifactCausalFrontier([])
1147
+ } : { ...commonArtifact, modality };
1148
+ this.aggregates.set(key, {
1149
+ artifact,
1150
+ receipts: /* @__PURE__ */ new Map(),
1151
+ transactions: /* @__PURE__ */ new Map(),
1152
+ committedTransactions: /* @__PURE__ */ new Map(),
1153
+ operations: /* @__PURE__ */ new Map(),
1154
+ undoClaims: /* @__PURE__ */ new Map(),
1155
+ snapshots: /* @__PURE__ */ new Map(),
1156
+ checkpoints: /* @__PURE__ */ new Map([[0, checkpointAtGenesis(artifact, nativeRevision)]]),
1157
+ outbox: /* @__PURE__ */ new Map()
1158
+ });
1159
+ return cloneArtifact(artifact);
1160
+ });
1161
+ }
1162
+ async getArtifact(scope, artifactId) {
1163
+ const key = aggregateKey(editableArtifactScope(scope), editableArtifactId(artifactId));
1164
+ return this.exclusive(async () => {
1165
+ const aggregate = this.aggregates.get(key);
1166
+ return aggregate ? cloneArtifact(aggregate.artifact) : null;
1167
+ });
1168
+ }
1169
+ async readArtifactAtAuthorizationRevision(scope, artifactId, expectedAuthorizationRevision) {
1170
+ assertPositiveSafeInteger(
1171
+ expectedAuthorizationRevision,
1172
+ "expected artifact authorization revision"
1173
+ );
1174
+ const key = aggregateKey(editableArtifactScope(scope), editableArtifactId(artifactId));
1175
+ return this.exclusive(async () => {
1176
+ const aggregate = this.aggregates.get(key);
1177
+ if (!aggregate) {
1178
+ return Object.freeze({ kind: "result", artifact: null });
1179
+ }
1180
+ if (aggregate.artifact.authorizationRevision !== expectedAuthorizationRevision) {
1181
+ return Object.freeze({ kind: "authorization_stale" });
1182
+ }
1183
+ return Object.freeze({
1184
+ kind: "result",
1185
+ artifact: cloneArtifact(aggregate.artifact)
1186
+ });
1187
+ });
1188
+ }
1189
+ /** Test/admin seam modeling the local policy invalidation transaction. */
1190
+ async advanceAuthorizationRevision(scope, artifactId, expectedRevision, nextRevision) {
1191
+ assertPositiveSafeInteger(expectedRevision, "expected artifact authorization revision");
1192
+ assertPositiveSafeInteger(nextRevision, "next artifact authorization revision");
1193
+ if (nextRevision <= expectedRevision) {
1194
+ throw new TypeError("Next artifact authorization revision must exceed the expected revision");
1195
+ }
1196
+ const key = aggregateKey(editableArtifactScope(scope), editableArtifactId(artifactId));
1197
+ return this.exclusive(async () => {
1198
+ const aggregate = this.aggregates.get(key);
1199
+ if (!aggregate) throw new EditableArtifactNotFoundError();
1200
+ if (aggregate.artifact.authorizationRevision !== expectedRevision) {
1201
+ return Object.freeze({
1202
+ applied: false,
1203
+ authorizationRevision: aggregate.artifact.authorizationRevision
1204
+ });
1205
+ }
1206
+ const updatedAt = authoritativeNow(this.now).toISOString();
1207
+ aggregate.artifact = {
1208
+ ...aggregate.artifact,
1209
+ authorizationRevision: nextRevision,
1210
+ updatedAt: laterIsoTimestamp(aggregate.artifact.updatedAt, updatedAt)
1211
+ };
1212
+ return Object.freeze({
1213
+ applied: true,
1214
+ authorizationRevision: nextRevision
1215
+ });
1216
+ });
1217
+ }
1218
+ async readTransactionBasis(scope, artifactId, request) {
1219
+ const normalizedScope = editableArtifactScope(scope);
1220
+ const normalizedArtifactId = editableArtifactId(artifactId);
1221
+ const key = aggregateKey(normalizedScope, normalizedArtifactId);
1222
+ return this.exclusive(async () => {
1223
+ const aggregate = this.aggregates.get(key);
1224
+ if (!aggregate) throw new EditableArtifactNotFoundError();
1225
+ const priorReceipt = aggregate.receipts.get(
1226
+ receiptKey(request.actorKey, request.clientTransactionId)
1227
+ );
1228
+ if (priorReceipt) {
1229
+ return Object.freeze({
1230
+ kind: "existing",
1231
+ receipt: cloneReceipt(priorReceipt)
1232
+ });
1233
+ }
1234
+ const predecessor = request.previousLocalTransactionId ? aggregate.receipts.get(receiptKey(request.actorKey, request.previousLocalTransactionId)) : void 0;
1235
+ const undoTargets = Object.freeze(
1236
+ request.selectiveUndoOperationIds.map(
1237
+ (operationId) => Object.freeze({
1238
+ operationId,
1239
+ operation: aggregate.operations.has(operationId) ? cloneOperation(aggregate.operations.get(operationId)) : null,
1240
+ claimedBy: aggregate.undoClaims.get(operationId) ?? null
1241
+ })
1242
+ )
1243
+ );
1244
+ const kernelState = kernelStateFromAggregate(aggregate);
1245
+ return Object.freeze({
1246
+ kind: "basis",
1247
+ artifact: kernelState.artifact,
1248
+ predecessor: predecessor ? cloneReceipt(predecessor) : null,
1249
+ undoTargets,
1250
+ kernelState
1251
+ });
1252
+ });
1253
+ }
1254
+ async readCurrentKernelState(scope, artifactId, expectedAuthorizationRevision) {
1255
+ const normalizedScope = editableArtifactScope(scope);
1256
+ const normalizedArtifactId = editableArtifactId(artifactId);
1257
+ const key = aggregateKey(normalizedScope, normalizedArtifactId);
1258
+ return this.exclusive(async () => {
1259
+ const aggregate = this.aggregates.get(key);
1260
+ if (!aggregate) throw new EditableArtifactNotFoundError();
1261
+ if (aggregate.artifact.authorizationRevision !== expectedAuthorizationRevision) {
1262
+ return Object.freeze({ kind: "authorization_stale" });
1263
+ }
1264
+ return Object.freeze({ kind: "basis", state: kernelStateFromAggregate(aggregate) });
1265
+ });
1266
+ }
1267
+ async tryCommitAppliedTransaction(request) {
1268
+ const scope = editableArtifactScope(request.scope);
1269
+ const artifactId = editableArtifactId(request.artifactId);
1270
+ const key = aggregateKey(scope, artifactId);
1271
+ return this.exclusive(async () => {
1272
+ const aggregate = this.aggregates.get(key);
1273
+ if (!aggregate) throw new EditableArtifactNotFoundError();
1274
+ const prior = aggregate.receipts.get(
1275
+ receiptKey(request.actorKey, request.clientTransactionId)
1276
+ );
1277
+ if (prior) {
1278
+ if (prior.requestHash !== request.requestHash) {
1279
+ throw new EditableArtifactIdempotencyConflictError();
1280
+ }
1281
+ return Object.freeze({
1282
+ kind: "replayed",
1283
+ receipt: cloneReceipt(prior)
1284
+ });
1285
+ }
1286
+ const artifact = aggregate.artifact;
1287
+ if (artifact.lifecycle !== request.expectedLifecycle || artifact.authorizationRevision !== request.expectedAuthorizationRevision || artifact.headSequence !== request.expectedHeadSequence) {
1288
+ return Object.freeze({ kind: "stale" });
1289
+ }
1290
+ if (!sameExpectedPredecessor(aggregate, request.expectedPredecessor)) {
1291
+ return Object.freeze({ kind: "stale" });
1292
+ }
1293
+ if (request.expectedUnclaimedUndoTargets.some(
1294
+ (operationId) => aggregate.undoClaims.has(operationId)
1295
+ )) {
1296
+ return Object.freeze({ kind: "stale" });
1297
+ }
1298
+ const working = cloneAggregate(aggregate);
1299
+ commitAppliedTransaction(working, request);
1300
+ this.aggregates.set(key, working);
1301
+ return Object.freeze({
1302
+ kind: "committed",
1303
+ receipt: cloneReceipt(request.receipt)
1304
+ });
1305
+ });
1306
+ }
1307
+ async withSnapshotPublicationLock(scope, artifactId, callback) {
1308
+ const key = aggregateKey(editableArtifactScope(scope), editableArtifactId(artifactId));
1309
+ return this.exclusive(async () => {
1310
+ const aggregate = this.aggregates.get(key);
1311
+ if (!aggregate) throw new EditableArtifactNotFoundError();
1312
+ const working = cloneAggregate(aggregate);
1313
+ const unitOfWork = new InMemoryEditableArtifactSnapshotUnitOfWork(working);
1314
+ try {
1315
+ const result = await callback(unitOfWork);
1316
+ this.aggregates.set(key, cloneAggregate(working));
1317
+ return result;
1318
+ } finally {
1319
+ unitOfWork.close();
1320
+ }
1321
+ });
1322
+ }
1323
+ async claimLiveOutbox(request) {
1324
+ assertLeaseRequest(request);
1325
+ const owner = request.owner;
1326
+ const leaseDurationMs = request.leaseDurationMs;
1327
+ const limit = request.limit;
1328
+ return this.exclusive(async () => {
1329
+ const nowMs = authoritativeNow(this.now).getTime();
1330
+ const eligible = [...this.aggregates.values()].flatMap(
1331
+ (aggregate) => [...aggregate.outbox.values()].map((record) => ({
1332
+ aggregate,
1333
+ record
1334
+ }))
1335
+ ).filter(({ record }) => {
1336
+ if (record.state === "pending") {
1337
+ return new Date(record.nextAttemptAt).getTime() <= nowMs;
1338
+ }
1339
+ if (record.state !== "publishing" || !record.leaseExpiresAt) return false;
1340
+ return new Date(record.leaseExpiresAt).getTime() <= nowMs;
1341
+ }).sort(
1342
+ (left, right) => compareText(left.record.createdAt, right.record.createdAt) || compareText(left.record.outboxId, right.record.outboxId)
1343
+ ).slice(0, limit);
1344
+ const leaseExpiresAt = new Date(nowMs + leaseDurationMs).toISOString();
1345
+ return Object.freeze(
1346
+ eligible.map(({ aggregate, record }) => {
1347
+ if (record.attemptCount >= Number.MAX_SAFE_INTEGER) {
1348
+ throw new Error("Editable artifact outbox attempt counter exhausted");
1349
+ }
1350
+ const claimed = {
1351
+ ...record,
1352
+ state: "publishing",
1353
+ attemptCount: record.attemptCount + 1,
1354
+ leaseOwner: owner,
1355
+ leaseExpiresAt
1356
+ };
1357
+ aggregate.outbox.set(record.outboxId, claimed);
1358
+ return cloneOutbox(claimed);
1359
+ })
1360
+ );
1361
+ });
1362
+ }
1363
+ async markLiveOutboxPublished(input) {
1364
+ const outboxId = editableArtifactOutboxId(input.outboxId);
1365
+ const owner = assertLeaseOwner(input.owner);
1366
+ assertPositiveSafeInteger(input.attemptCount, "outbox attempt count");
1367
+ await this.exclusive(async () => {
1368
+ const publishedAt = authoritativeNow(this.now);
1369
+ const publishedAtMs = publishedAt.getTime();
1370
+ const publishedAtIso = publishedAt.toISOString();
1371
+ const located = this.findOutbox(outboxId);
1372
+ if (!located) throw new EditableArtifactOutboxLeaseConflictError();
1373
+ const record = located.record;
1374
+ if (record.state === "published") {
1375
+ if (record.attemptCount === input.attemptCount) return;
1376
+ throw new EditableArtifactOutboxLeaseConflictError();
1377
+ }
1378
+ if (record.state !== "publishing" || record.leaseOwner !== owner || record.attemptCount !== input.attemptCount || !record.leaseExpiresAt || publishedAtMs >= new Date(record.leaseExpiresAt).getTime()) {
1379
+ throw new EditableArtifactOutboxLeaseConflictError();
1380
+ }
1381
+ located.aggregate.outbox.set(outboxId, {
1382
+ ...record,
1383
+ state: "published",
1384
+ leaseOwner: null,
1385
+ leaseExpiresAt: null,
1386
+ publishedAt: publishedAtIso
1387
+ });
1388
+ });
1389
+ }
1390
+ async releaseLiveOutbox(input) {
1391
+ const outboxId = editableArtifactOutboxId(input.outboxId);
1392
+ const owner = assertLeaseOwner(input.owner);
1393
+ assertPositiveSafeInteger(input.attemptCount, "outbox attempt count");
1394
+ await this.exclusive(async () => {
1395
+ const releasedAt = authoritativeNow(this.now).toISOString();
1396
+ const located = this.findOutbox(outboxId);
1397
+ if (!located) throw new EditableArtifactOutboxLeaseConflictError();
1398
+ if ((located.record.state === "published" || located.record.state === "pending" && located.record.leaseOwner === null && located.record.leaseExpiresAt === null) && located.record.attemptCount === input.attemptCount) {
1399
+ return;
1400
+ }
1401
+ if (located.record.state !== "publishing" || located.record.leaseOwner !== owner || located.record.attemptCount !== input.attemptCount) {
1402
+ throw new EditableArtifactOutboxLeaseConflictError();
1403
+ }
1404
+ located.aggregate.outbox.set(outboxId, {
1405
+ ...located.record,
1406
+ state: "pending",
1407
+ leaseOwner: null,
1408
+ leaseExpiresAt: null,
1409
+ nextAttemptAt: releasedAt
1410
+ });
1411
+ });
1412
+ }
1413
+ async renewLiveOutbox(input) {
1414
+ const outboxId = editableArtifactOutboxId(input.outboxId);
1415
+ const owner = assertLeaseOwner(input.owner);
1416
+ assertPositiveSafeInteger(input.attemptCount, "outbox attempt count");
1417
+ assertLeaseDuration(input.leaseDurationMs);
1418
+ await this.exclusive(async () => {
1419
+ const nowMs = authoritativeNow(this.now).getTime();
1420
+ const located = this.findOutbox(outboxId);
1421
+ if (!located) throw new EditableArtifactOutboxLeaseConflictError();
1422
+ assertActiveOutboxLease(located.record, owner, input.attemptCount, nowMs);
1423
+ located.aggregate.outbox.set(outboxId, {
1424
+ ...located.record,
1425
+ leaseExpiresAt: new Date(nowMs + input.leaseDurationMs).toISOString()
1426
+ });
1427
+ });
1428
+ }
1429
+ async retryLiveOutbox(input) {
1430
+ const outboxId = editableArtifactOutboxId(input.outboxId);
1431
+ const owner = assertLeaseOwner(input.owner);
1432
+ assertPositiveSafeInteger(input.attemptCount, "outbox attempt count");
1433
+ assertRetryDelay(input.retryDelayMs);
1434
+ assertRetryErrorCode(input.errorCode);
1435
+ await this.exclusive(async () => {
1436
+ const nowMs = authoritativeNow(this.now).getTime();
1437
+ const located = this.findOutbox(outboxId);
1438
+ if (!located) throw new EditableArtifactOutboxLeaseConflictError();
1439
+ const record = located.record;
1440
+ if (record.state === "pending" && record.attemptCount === input.attemptCount && record.leaseOwner === null && record.leaseExpiresAt === null && record.lastErrorCode === input.errorCode) {
1441
+ return;
1442
+ }
1443
+ assertActiveOutboxLease(record, owner, input.attemptCount, nowMs);
1444
+ located.aggregate.outbox.set(outboxId, {
1445
+ ...record,
1446
+ state: "pending",
1447
+ leaseOwner: null,
1448
+ leaseExpiresAt: null,
1449
+ nextAttemptAt: new Date(nowMs + input.retryDelayMs).toISOString(),
1450
+ lastErrorCode: input.errorCode
1451
+ });
1452
+ });
1453
+ }
1454
+ async deadLetterLiveOutbox(input) {
1455
+ const outboxId = editableArtifactOutboxId(input.outboxId);
1456
+ const owner = assertLeaseOwner(input.owner);
1457
+ assertPositiveSafeInteger(input.attemptCount, "outbox attempt count");
1458
+ assertDeadLetterErrorCode(input.errorCode);
1459
+ await this.exclusive(async () => {
1460
+ const now = authoritativeNow(this.now);
1461
+ const nowMs = now.getTime();
1462
+ const located = this.findOutbox(outboxId);
1463
+ if (!located) throw new EditableArtifactOutboxLeaseConflictError();
1464
+ const record = located.record;
1465
+ if (record.state === "dead_lettered" && record.attemptCount === input.attemptCount && record.leaseOwner === null && record.leaseExpiresAt === null && record.lastErrorCode === input.errorCode) {
1466
+ return;
1467
+ }
1468
+ assertActiveOutboxLease(record, owner, input.attemptCount, nowMs);
1469
+ located.aggregate.outbox.set(outboxId, {
1470
+ ...record,
1471
+ state: "dead_lettered",
1472
+ leaseOwner: null,
1473
+ leaseExpiresAt: null,
1474
+ lastErrorCode: input.errorCode,
1475
+ deadLetteredAt: now.toISOString()
1476
+ });
1477
+ });
1478
+ }
1479
+ async listReceipts(scope, artifactId) {
1480
+ return this.inspectAggregate(
1481
+ scope,
1482
+ artifactId,
1483
+ (aggregate) => Object.freeze(
1484
+ [...aggregate.transactions.values()].sort((left, right) => left.sequenceStart - right.sequenceStart).map(cloneReceipt)
1485
+ )
1486
+ );
1487
+ }
1488
+ async listOperations(scope, artifactId) {
1489
+ return this.inspectAggregate(
1490
+ scope,
1491
+ artifactId,
1492
+ (aggregate) => Object.freeze(
1493
+ [...aggregate.operations.values()].sort((left, right) => left.sequence - right.sequence).map(cloneOperation)
1494
+ )
1495
+ );
1496
+ }
1497
+ async listCommittedTransactions(scope, artifactId) {
1498
+ return this.inspectAggregate(
1499
+ scope,
1500
+ artifactId,
1501
+ (aggregate) => Object.freeze(
1502
+ [...aggregate.committedTransactions.values()].sort((left, right) => left.sequenceStart - right.sequenceStart).map(cloneCommittedTransaction)
1503
+ )
1504
+ );
1505
+ }
1506
+ async listSnapshots(scope, artifactId) {
1507
+ return this.inspectAggregate(
1508
+ scope,
1509
+ artifactId,
1510
+ (aggregate) => Object.freeze(
1511
+ [...aggregate.snapshots.values()].sort((left, right) => left.coveredHeadSequence - right.coveredHeadSequence).map(cloneSnapshot)
1512
+ )
1513
+ );
1514
+ }
1515
+ async listOutbox() {
1516
+ return this.exclusive(
1517
+ async () => Object.freeze(
1518
+ [...this.aggregates.values()].flatMap((aggregate) => [...aggregate.outbox.values()]).sort(
1519
+ (left, right) => compareText(left.createdAt, right.createdAt) || compareText(left.outboxId, right.outboxId)
1520
+ ).map(cloneOutbox)
1521
+ )
1522
+ );
1523
+ }
1524
+ async inspectAggregate(scope, artifactId, inspect) {
1525
+ const key = aggregateKey(editableArtifactScope(scope), editableArtifactId(artifactId));
1526
+ return this.exclusive(async () => {
1527
+ const aggregate = this.aggregates.get(key);
1528
+ if (!aggregate) throw new EditableArtifactNotFoundError();
1529
+ return inspect(aggregate);
1530
+ });
1531
+ }
1532
+ findOutbox(outboxId) {
1533
+ for (const aggregate of this.aggregates.values()) {
1534
+ const record = aggregate.outbox.get(outboxId);
1535
+ if (record) return { aggregate, record };
1536
+ }
1537
+ return void 0;
1538
+ }
1539
+ async exclusive(operation) {
1540
+ const prior = this.exclusiveTail;
1541
+ let release;
1542
+ this.exclusiveTail = new Promise((resolve) => {
1543
+ release = resolve;
1544
+ });
1545
+ await prior;
1546
+ try {
1547
+ return await operation();
1548
+ } finally {
1549
+ release();
1550
+ }
1551
+ }
1552
+ };
1553
+ function commitAppliedTransaction(aggregate, input) {
1554
+ const artifact = aggregate.artifact;
1555
+ if (input.expectedHeadSequence !== artifact.headSequence) {
1556
+ throw new Error("In-memory artifact head changed before its CAS commit");
1557
+ }
1558
+ if (input.receipt.modality !== artifact.modality || input.committedTransaction.modality !== artifact.modality || input.receipt.sequenceStart !== artifact.headSequence + 1) {
1559
+ throw new Error("Committed transaction modality or interval is invalid");
1560
+ }
1561
+ if (input.receipt.serverTransactionId !== input.serverTransactionId || input.operations.some(
1562
+ (operation, index) => operation.serverTransactionId !== input.serverTransactionId || operation.sequence !== input.receipt.sequenceStart + index
1563
+ )) {
1564
+ throw new Error("Committed operations are not bound to the transaction interval");
1565
+ }
1566
+ const committed = input.committedTransaction;
1567
+ if (committed.serverTransactionId !== input.serverTransactionId || committed.scope.accountId !== artifact.scope.accountId || committed.scope.workspaceId !== artifact.scope.workspaceId || committed.artifactId !== artifact.id || committed.requestHash !== input.receipt.requestHash || committed.sequenceStart !== input.receipt.sequenceStart || committed.sequenceEnd !== input.receipt.sequenceEnd || committed.priorStateHash !== artifact.stateHash || committed.stateHash !== input.receipt.stateHash || !(committed.committedTransactionBytes instanceof Uint8Array) || committed.committedTransactionBytes.byteLength < 1) {
1568
+ throw new Error("Canonical committed transaction disagrees with its receipt");
1569
+ }
1570
+ if (input.outbox.event.kind !== "transaction_committed" || input.outbox.event.modality !== artifact.modality || input.outbox.event.serverTransactionId !== input.serverTransactionId || input.outbox.event.sequenceStart !== input.receipt.sequenceStart || input.outbox.event.sequenceEnd !== input.receipt.sequenceEnd || input.outbox.event.stateHash !== input.receipt.stateHash) {
1571
+ throw new Error("Transaction outbox projection is inconsistent");
1572
+ }
1573
+ if (artifact.modality === "spreadsheet") {
1574
+ if (input.receipt.modality !== "spreadsheet" || committed.modality !== "spreadsheet" || input.outbox.event.modality !== "spreadsheet" || input.operations.length !== input.receipt.operationCount || input.receipt.sequenceEnd !== artifact.headSequence + input.operations.length || committed.operationIds.length !== input.operations.length || committed.operationIds.some(
1575
+ (operationId, index) => operationId !== input.operations[index]?.operationId
1576
+ ) || !causalFrontiersEqual(
1577
+ committed.resultingCausalFrontier,
1578
+ input.receipt.resultingCausalFrontier
1579
+ ) || input.outbox.event.operationProtocolVersion !== input.receipt.operationProtocolVersion) {
1580
+ throw new Error("Spreadsheet commit disagrees with its CRDT receipt");
1581
+ }
1582
+ const summary = decodeCommittedTransactionSummary(committed.committedTransactionBytes);
1583
+ if (summary.transactionId !== input.serverTransactionId || summary.priorStateHash !== committed.priorStateHash || summary.stateHash !== committed.stateHash || summary.operationIds.length !== committed.operationIds.length) {
1584
+ throw new Error("Spreadsheet OGACO metadata disagrees with its record");
1585
+ }
1586
+ } else {
1587
+ if (input.receipt.modality !== artifact.modality || committed.modality !== artifact.modality || input.outbox.event.modality !== artifact.modality || input.operations.length !== 0 || input.receipt.sequenceEnd !== input.receipt.sequenceStart || committed.sequenceEnd !== committed.sequenceStart || input.receipt.commitProtocolVersion !== committed.commitProtocolVersion || input.receipt.priorNativeRevision !== committed.priorNativeRevision || input.receipt.nativeRevision !== committed.nativeRevision || input.receipt.commandCount !== committed.commandCount || input.outbox.event.commitProtocolVersion !== input.receipt.commitProtocolVersion) {
1588
+ throw new Error("Serialized commit disagrees with its authoritative receipt");
1589
+ }
1590
+ const summary = decodeEditableArtifactSerializedCommit(
1591
+ committed.committedTransactionBytes,
1592
+ artifact.modality
1593
+ );
1594
+ if (summary.transactionId !== input.serverTransactionId || summary.parentHeadSequence !== artifact.headSequence || summary.resultHeadSequence !== input.receipt.sequenceEnd || summary.priorNativeRevision !== committed.priorNativeRevision || summary.nativeReceipt.revision !== committed.nativeRevision || summary.nativeReceipt.commandCount !== committed.commandCount || summary.priorStateHash !== artifact.stateHash || summary.stateHash !== input.receipt.stateHash || summary.requestHash !== input.receipt.requestHash || !sameBytes2(summary.intentBytes, input.receipt.intentBytes) || !sameBytes2(summary.nativeReceiptBytes, committed.nativeReceiptBytes)) {
1595
+ throw new Error("Serialized OGAST metadata disagrees with its record");
1596
+ }
1597
+ }
1598
+ const idempotencyKey = receiptKey(input.receipt.actorKey, input.receipt.clientTransactionId);
1599
+ if (aggregate.receipts.has(idempotencyKey) || aggregate.transactions.has(input.serverTransactionId) || aggregate.committedTransactions.has(input.serverTransactionId) || aggregate.outbox.has(input.outbox.outboxId)) {
1600
+ throw new Error("Duplicate transaction, receipt, or outbox identity");
1601
+ }
1602
+ for (const operation of input.operations) {
1603
+ if (aggregate.operations.has(operation.operationId)) {
1604
+ throw new Error(`Duplicate operation identity: ${operation.operationId}`);
1605
+ }
1606
+ }
1607
+ if (input.receipt.modality === "spreadsheet") {
1608
+ for (const target of input.receipt.selectiveUndoOperationIds) {
1609
+ if (aggregate.undoClaims.has(target)) {
1610
+ throw new Error(`Duplicate selective undo claim: ${target}`);
1611
+ }
1612
+ aggregate.undoClaims.set(target, input.serverTransactionId);
1613
+ }
1614
+ }
1615
+ aggregate.receipts.set(idempotencyKey, cloneReceipt(input.receipt));
1616
+ aggregate.transactions.set(input.serverTransactionId, cloneReceipt(input.receipt));
1617
+ aggregate.committedTransactions.set(
1618
+ input.serverTransactionId,
1619
+ cloneCommittedTransaction(input.committedTransaction)
1620
+ );
1621
+ for (const operation of input.operations) {
1622
+ aggregate.operations.set(operation.operationId, cloneOperation(operation));
1623
+ }
1624
+ aggregate.outbox.set(input.outbox.outboxId, cloneOutbox(input.outbox));
1625
+ if (artifact.modality === "spreadsheet") {
1626
+ if (input.receipt.modality !== "spreadsheet") {
1627
+ throw new Error("Spreadsheet artifact received a serialized receipt");
1628
+ }
1629
+ aggregate.artifact = {
1630
+ ...artifact,
1631
+ headSequence: input.receipt.sequenceEnd,
1632
+ causalFrontier: cloneFrontier(input.receipt.resultingCausalFrontier),
1633
+ stateHash: input.receipt.stateHash,
1634
+ updatedAt: laterIsoTimestamp(artifact.updatedAt, input.receipt.committedAt)
1635
+ };
1636
+ aggregate.checkpoints.set(input.receipt.sequenceEnd, {
1637
+ modality: "spreadsheet",
1638
+ headSequence: input.receipt.sequenceEnd,
1639
+ causalFrontier: cloneFrontier(input.receipt.resultingCausalFrontier),
1640
+ stateHash: input.receipt.stateHash
1641
+ });
1642
+ } else {
1643
+ if (input.receipt.modality === "spreadsheet") {
1644
+ throw new Error("Serialized artifact received a spreadsheet receipt");
1645
+ }
1646
+ aggregate.artifact = {
1647
+ ...artifact,
1648
+ headSequence: input.receipt.sequenceEnd,
1649
+ stateHash: input.receipt.stateHash,
1650
+ updatedAt: laterIsoTimestamp(artifact.updatedAt, input.receipt.committedAt)
1651
+ };
1652
+ aggregate.checkpoints.set(input.receipt.sequenceEnd, {
1653
+ modality: artifact.modality,
1654
+ headSequence: input.receipt.sequenceEnd,
1655
+ nativeRevision: input.receipt.nativeRevision,
1656
+ stateHash: input.receipt.stateHash
1657
+ });
1658
+ }
1659
+ }
1660
+ var InMemoryEditableArtifactSnapshotUnitOfWork = class {
1661
+ constructor(aggregate) {
1662
+ this.aggregate = aggregate;
1663
+ }
1664
+ committed = false;
1665
+ closed = false;
1666
+ artifact() {
1667
+ this.assertOpen();
1668
+ return cloneArtifact(this.aggregate.artifact);
1669
+ }
1670
+ async checkpoint(headSequence) {
1671
+ this.assertOpen();
1672
+ const checkpoint = this.aggregate.checkpoints.get(headSequence);
1673
+ return checkpoint ? cloneCheckpoint(checkpoint) : null;
1674
+ }
1675
+ async findSnapshot(snapshotId) {
1676
+ this.assertOpen();
1677
+ const snapshot = this.aggregate.snapshots.get(snapshotId);
1678
+ return snapshot ? cloneSnapshot(snapshot) : null;
1679
+ }
1680
+ async commitSnapshot(input) {
1681
+ this.assertUncommitted();
1682
+ if (input.authorizationPermission !== void 0 && input.authorizationPermission !== "manage" && input.authorizationPermission !== "read" && input.authorizationPermission !== "edit") {
1683
+ throw new TypeError("Snapshot authorization permission is invalid");
1684
+ }
1685
+ const artifact = this.aggregate.artifact;
1686
+ if (input.expectedCurrentSnapshotId !== artifact.currentSnapshotId) {
1687
+ throw new Error("In-memory current snapshot changed inside its transaction lock");
1688
+ }
1689
+ if (input.expectedAuthorizationRevision !== artifact.authorizationRevision) {
1690
+ throw new Error("In-memory artifact authorization changed before snapshot commit");
1691
+ }
1692
+ if (this.aggregate.snapshots.has(input.snapshot.snapshotId) || this.aggregate.outbox.has(input.outbox.outboxId)) {
1693
+ throw new Error("Duplicate snapshot or outbox identity");
1694
+ }
1695
+ const checkpoint = this.aggregate.checkpoints.get(input.snapshot.coveredHeadSequence);
1696
+ if (!checkpoint || checkpoint.modality !== artifact.modality || input.snapshot.modality !== artifact.modality || checkpoint.stateHash !== input.snapshot.stateHash || input.snapshot.modality === "spreadsheet" && (checkpoint.modality !== "spreadsheet" || !causalFrontiersEqual(
1697
+ checkpoint.causalFrontier,
1698
+ input.snapshot.coveredCausalFrontier
1699
+ )) || input.snapshot.modality !== "spreadsheet" && (checkpoint.modality === "spreadsheet" || checkpoint.nativeRevision !== input.snapshot.nativeRevision)) {
1700
+ throw new Error("Snapshot does not match an authoritative checkpoint");
1701
+ }
1702
+ this.aggregate.snapshots.set(input.snapshot.snapshotId, cloneSnapshot(input.snapshot));
1703
+ this.aggregate.outbox.set(input.outbox.outboxId, cloneOutbox(input.outbox));
1704
+ this.aggregate.artifact = {
1705
+ ...artifact,
1706
+ currentSnapshotId: input.snapshot.snapshotId,
1707
+ updatedAt: laterIsoTimestamp(artifact.updatedAt, input.snapshot.publishedAt)
1708
+ };
1709
+ this.committed = true;
1710
+ return Object.freeze({ kind: "committed" });
1711
+ }
1712
+ assertUncommitted() {
1713
+ this.assertOpen();
1714
+ if (this.committed) throw new Error("Artifact unit of work may commit exactly once");
1715
+ }
1716
+ close() {
1717
+ this.closed = true;
1718
+ }
1719
+ assertOpen() {
1720
+ if (this.closed) {
1721
+ throw new Error("Artifact unit of work is no longer inside its lock");
1722
+ }
1723
+ }
1724
+ };
1725
+ var InMemoryEditableArtifactStableIdFactory = class {
1726
+ nextCounter;
1727
+ namespace;
1728
+ constructor(namespace, initialCounter = 1n) {
1729
+ this.namespace = typeof namespace === "bigint" ? namespace : BigInt(`0x${namespace.replace(/^0x/, "")}`);
1730
+ if (this.namespace < 1n || this.namespace > 0xffffffffffffffffn) {
1731
+ throw new TypeError("Stable id namespace must be a nonzero unsigned 64-bit integer");
1732
+ }
1733
+ if (initialCounter < 1n || initialCounter > 0xffffffffffffffffn) {
1734
+ throw new TypeError("Stable id counter must be a nonzero unsigned 64-bit integer");
1735
+ }
1736
+ this.nextCounter = initialCounter;
1737
+ }
1738
+ next(_kind) {
1739
+ if (this.nextCounter > 0xffffffffffffffffn) {
1740
+ throw new Error("Stable id namespace exhausted");
1741
+ }
1742
+ const value = `${this.namespace.toString(16).padStart(16, "0")}${this.nextCounter.toString(16).padStart(16, "0")}`;
1743
+ this.nextCounter += 1n;
1744
+ return editableArtifactOperationId(value);
1745
+ }
1746
+ };
1747
+ var SystemEditableArtifactClock = class {
1748
+ now() {
1749
+ return /* @__PURE__ */ new Date();
1750
+ }
1751
+ };
1752
+ function aggregateKey(scope, artifactId) {
1753
+ return JSON.stringify([scope.accountId, scope.workspaceId, artifactId]);
1754
+ }
1755
+ function authorizationScopeKey(scope) {
1756
+ return JSON.stringify([scope.accountId, scope.workspaceId]);
1757
+ }
1758
+ function creationReceiptKey(scope, operationKind, authorityKey, idempotencyKey) {
1759
+ return JSON.stringify([
1760
+ scope.accountId,
1761
+ scope.workspaceId,
1762
+ operationKind,
1763
+ authorityKey,
1764
+ idempotencyKey
1765
+ ]);
1766
+ }
1767
+ function emptyAggregate(artifact, genesisSnapshot, outbox) {
1768
+ return {
1769
+ artifact,
1770
+ receipts: /* @__PURE__ */ new Map(),
1771
+ transactions: /* @__PURE__ */ new Map(),
1772
+ committedTransactions: /* @__PURE__ */ new Map(),
1773
+ operations: /* @__PURE__ */ new Map(),
1774
+ undoClaims: /* @__PURE__ */ new Map(),
1775
+ snapshots: /* @__PURE__ */ new Map([[genesisSnapshot.snapshotId, cloneSnapshot(genesisSnapshot)]]),
1776
+ checkpoints: /* @__PURE__ */ new Map([
1777
+ [
1778
+ 0,
1779
+ checkpointAtGenesis(
1780
+ artifact,
1781
+ genesisSnapshot.modality === "spreadsheet" ? 0 : genesisSnapshot.nativeRevision
1782
+ )
1783
+ ]
1784
+ ]),
1785
+ outbox: /* @__PURE__ */ new Map([[outbox.outboxId, cloneOutbox(outbox)]])
1786
+ };
1787
+ }
1788
+ function assertGenesisCreateRequest(scope, artifactId, operationKind, snapshot, outbox) {
1789
+ assertIsoTimestamp(snapshot.verifiedAt, "genesis snapshot verification time");
1790
+ assertIsoTimestamp(snapshot.publishedAt, "genesis snapshot publication time");
1791
+ if (snapshot.scope.accountId !== scope.accountId || snapshot.scope.workspaceId !== scope.workspaceId || snapshot.artifactId !== artifactId || snapshot.coveredHeadSequence !== 0 || operationKind === "create" && snapshot.modality === "spreadsheet" && snapshot.coveredCausalFrontier.length !== 0 || Date.parse(snapshot.verifiedAt) > Date.parse(snapshot.publishedAt)) {
1792
+ throw new TypeError(
1793
+ "Genesis snapshot is not the verified sequence-zero state for this artifact"
1794
+ );
1795
+ }
1796
+ if (outbox.state !== "pending" || outbox.attemptCount !== 0 || outbox.leaseOwner !== null || outbox.leaseExpiresAt !== null || outbox.nextAttemptAt !== snapshot.publishedAt || outbox.lastErrorCode !== null || outbox.publishedAt !== null || outbox.deadLetteredAt !== null || outbox.createdAt !== snapshot.publishedAt || outbox.event.kind !== "snapshot_published" || outbox.event.scope.accountId !== scope.accountId || outbox.event.scope.workspaceId !== scope.workspaceId || outbox.event.artifactId !== artifactId || outbox.event.modality !== snapshot.modality || outbox.event.snapshotId !== snapshot.snapshotId || outbox.event.coveredHeadSequence !== 0 || outbox.event.stateHash !== snapshot.stateHash || snapshot.modality === "spreadsheet" && (outbox.event.modality !== "spreadsheet" || outbox.event.operationProtocolVersion !== snapshot.operationProtocolVersion) || outbox.event.publishedAt !== snapshot.publishedAt) {
1797
+ throw new TypeError("Genesis snapshot outbox projection is inconsistent");
1798
+ }
1799
+ }
1800
+ function receiptKey(actorKey, clientTransactionId) {
1801
+ return JSON.stringify([actorKey, clientTransactionId]);
1802
+ }
1803
+ function sameExpectedPredecessor(aggregate, expected) {
1804
+ if (expected === null) return true;
1805
+ const actual = aggregate.receipts.get(
1806
+ receiptKey(expected.actorKey, expected.clientTransactionId)
1807
+ );
1808
+ return actual !== void 0 && actual.receiptId === expected.receiptId && actual.serverTransactionId === expected.serverTransactionId && actual.replicaId === expected.replicaId && actual.replicaCounter === expected.replicaCounter;
1809
+ }
1810
+ function assertLeaseRequest(request) {
1811
+ assertLeaseOwner(request.owner);
1812
+ assertLeaseDuration(request.leaseDurationMs);
1813
+ assertPositiveSafeInteger(request.limit, "outbox claim limit");
1814
+ if (request.limit > 1e3) throw new TypeError("Outbox claim limit must not exceed 1000");
1815
+ }
1816
+ function assertLeaseDuration(value) {
1817
+ assertPositiveSafeInteger(value, "outbox lease duration");
1818
+ if (value > 24 * 60 * 60 * 1e3) {
1819
+ throw new TypeError("Outbox lease duration must not exceed 24 hours");
1820
+ }
1821
+ }
1822
+ function assertRetryDelay(value) {
1823
+ assertPositiveSafeInteger(value, "outbox retry delay");
1824
+ if (value > 24 * 60 * 60 * 1e3) {
1825
+ throw new TypeError("Outbox retry delay must not exceed 24 hours");
1826
+ }
1827
+ }
1828
+ function assertActiveOutboxLease(record, owner, attemptCount, nowMs) {
1829
+ if (record.state !== "publishing" || record.leaseOwner !== owner || record.attemptCount !== attemptCount || !record.leaseExpiresAt || nowMs >= Date.parse(record.leaseExpiresAt)) {
1830
+ throw new EditableArtifactOutboxLeaseConflictError();
1831
+ }
1832
+ }
1833
+ function assertRetryErrorCode(value) {
1834
+ if (value !== "broker_unavailable" && value !== "broker_backpressure" && value !== "publish_timeout") {
1835
+ throw new TypeError("Outbox retry error code is invalid");
1836
+ }
1837
+ }
1838
+ function assertDeadLetterErrorCode(value) {
1839
+ if (value !== "invalid_hint" && value !== "oversized_hint") {
1840
+ throw new TypeError("Outbox dead-letter error code is invalid");
1841
+ }
1842
+ }
1843
+ function assertLeaseOwner(owner) {
1844
+ if (owner.length < 1 || owner.length > 256) {
1845
+ throw new TypeError("Outbox lease owner must contain 1-256 characters");
1846
+ }
1847
+ return owner;
1848
+ }
1849
+ function authoritativeNow(now) {
1850
+ const value = now();
1851
+ if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
1852
+ throw new TypeError("Editable artifact store clock returned an invalid date");
1853
+ }
1854
+ return new Date(value);
1855
+ }
1856
+ function laterIsoTimestamp(left, right) {
1857
+ return Date.parse(left) >= Date.parse(right) ? left : right;
1858
+ }
1859
+ function cloneAggregate(aggregate) {
1860
+ return {
1861
+ artifact: cloneArtifact(aggregate.artifact),
1862
+ receipts: new Map([...aggregate.receipts].map(([key, value]) => [key, cloneReceipt(value)])),
1863
+ transactions: new Map(
1864
+ [...aggregate.transactions].map(([key, value]) => [key, cloneReceipt(value)])
1865
+ ),
1866
+ committedTransactions: new Map(
1867
+ [...aggregate.committedTransactions].map(([key, value]) => [
1868
+ key,
1869
+ cloneCommittedTransaction(value)
1870
+ ])
1871
+ ),
1872
+ operations: new Map(
1873
+ [...aggregate.operations].map(([key, value]) => [key, cloneOperation(value)])
1874
+ ),
1875
+ undoClaims: new Map(aggregate.undoClaims),
1876
+ snapshots: new Map([...aggregate.snapshots].map(([key, value]) => [key, cloneSnapshot(value)])),
1877
+ checkpoints: new Map(
1878
+ [...aggregate.checkpoints].map(([key, value]) => [key, cloneCheckpoint(value)])
1879
+ ),
1880
+ outbox: new Map([...aggregate.outbox].map(([key, value]) => [key, cloneOutbox(value)]))
1881
+ };
1882
+ }
1883
+ function kernelStateFromAggregate(aggregate) {
1884
+ const snapshot = aggregate.artifact.currentSnapshotId ? aggregate.snapshots.get(aggregate.artifact.currentSnapshotId) ?? null : null;
1885
+ const artifact = cloneArtifact(aggregate.artifact);
1886
+ const covered = snapshot?.coveredHeadSequence ?? 0;
1887
+ const coveredCheckpoint = aggregate.checkpoints.get(covered);
1888
+ if (!coveredCheckpoint || coveredCheckpoint.modality !== artifact.modality) {
1889
+ throw new Error("Artifact replay base has no matching checkpoint");
1890
+ }
1891
+ const tail = [...aggregate.committedTransactions.values()].filter((transaction) => transaction.sequenceEnd > covered).sort((left, right) => left.sequenceStart - right.sequenceStart).map(cloneCommittedTransaction);
1892
+ const tailByteSize = tail.reduce(
1893
+ (total, transaction) => total + transaction.committedTransactionBytes.byteLength,
1894
+ 0
1895
+ );
1896
+ const common = {
1897
+ tailTransactionCount: tail.length,
1898
+ tailByteSize
1899
+ };
1900
+ if (artifact.modality === "spreadsheet") {
1901
+ return Object.freeze({
1902
+ ...common,
1903
+ modality: artifact.modality,
1904
+ artifact,
1905
+ snapshot: snapshot?.modality === "spreadsheet" ? cloneSnapshot(snapshot) : null,
1906
+ committedTransactionTail: Object.freeze(
1907
+ tail.map((transaction) => {
1908
+ if (transaction.modality !== "spreadsheet") {
1909
+ throw new Error("Spreadsheet artifact contains a cross-modality transaction");
1910
+ }
1911
+ return transaction;
1912
+ })
1913
+ )
1914
+ });
1915
+ }
1916
+ return Object.freeze({
1917
+ ...common,
1918
+ modality: artifact.modality,
1919
+ artifact,
1920
+ snapshot: snapshot && snapshot.modality !== "spreadsheet" ? cloneSnapshot(snapshot) : null,
1921
+ baseNativeRevision: coveredCheckpoint.modality === "spreadsheet" ? (() => {
1922
+ throw new Error("Serialized artifact has a spreadsheet replay checkpoint");
1923
+ })() : coveredCheckpoint.nativeRevision,
1924
+ committedTransactionTail: Object.freeze(
1925
+ tail.map((transaction) => {
1926
+ if (transaction.modality !== artifact.modality) {
1927
+ throw new Error("Serialized artifact contains a cross-modality transaction");
1928
+ }
1929
+ return transaction;
1930
+ })
1931
+ )
1932
+ });
1933
+ }
1934
+ function cloneArtifact(artifact) {
1935
+ if (artifact.modality !== "spreadsheet") {
1936
+ return Object.freeze({
1937
+ ...artifact,
1938
+ scope: Object.freeze({ ...artifact.scope })
1939
+ });
1940
+ }
1941
+ return Object.freeze({
1942
+ ...artifact,
1943
+ scope: Object.freeze({ ...artifact.scope }),
1944
+ causalFrontier: cloneFrontier(artifact.causalFrontier)
1945
+ });
1946
+ }
1947
+ function cloneCreationReceipt(receipt) {
1948
+ return Object.freeze({
1949
+ ...receipt,
1950
+ scope: Object.freeze({ ...receipt.scope })
1951
+ });
1952
+ }
1953
+ function cloneReceipt(receipt) {
1954
+ if (receipt.modality !== "spreadsheet") {
1955
+ return Object.freeze({
1956
+ ...receipt,
1957
+ scope: Object.freeze({ ...receipt.scope }),
1958
+ intentBytes: receipt.intentBytes.slice()
1959
+ });
1960
+ }
1961
+ return Object.freeze({
1962
+ ...receipt,
1963
+ scope: Object.freeze({ ...receipt.scope }),
1964
+ intentBytes: receipt.intentBytes.slice(),
1965
+ causalBase: cloneFrontier(receipt.causalBase),
1966
+ resolvedCausalBase: cloneFrontier(receipt.resolvedCausalBase),
1967
+ resultingCausalFrontier: cloneFrontier(receipt.resultingCausalFrontier),
1968
+ selectiveUndoOperationIds: Object.freeze([...receipt.selectiveUndoOperationIds])
1969
+ });
1970
+ }
1971
+ function cloneOperation(operation) {
1972
+ return Object.freeze({
1973
+ ...operation,
1974
+ scope: Object.freeze({ ...operation.scope }),
1975
+ dot: Object.freeze({ ...operation.dot })
1976
+ });
1977
+ }
1978
+ function cloneCommittedTransaction(transaction) {
1979
+ if (transaction.modality !== "spreadsheet") {
1980
+ return Object.freeze({
1981
+ ...transaction,
1982
+ scope: Object.freeze({ ...transaction.scope }),
1983
+ nativeReceiptBytes: transaction.nativeReceiptBytes.slice(),
1984
+ committedTransactionBytes: transaction.committedTransactionBytes.slice()
1985
+ });
1986
+ }
1987
+ return Object.freeze({
1988
+ ...transaction,
1989
+ scope: Object.freeze({ ...transaction.scope }),
1990
+ dot: Object.freeze({ ...transaction.dot }),
1991
+ resolvedCausalBase: cloneFrontier(transaction.resolvedCausalBase),
1992
+ resultingCausalFrontier: cloneFrontier(transaction.resultingCausalFrontier),
1993
+ operationIds: Object.freeze([...transaction.operationIds]),
1994
+ committedTransactionBytes: transaction.committedTransactionBytes.slice()
1995
+ });
1996
+ }
1997
+ function cloneSnapshot(snapshot) {
1998
+ if (snapshot.modality !== "spreadsheet") {
1999
+ return Object.freeze({
2000
+ ...snapshot,
2001
+ scope: Object.freeze({ ...snapshot.scope })
2002
+ });
2003
+ }
2004
+ return Object.freeze({
2005
+ ...snapshot,
2006
+ scope: Object.freeze({ ...snapshot.scope }),
2007
+ coveredCausalFrontier: cloneFrontier(snapshot.coveredCausalFrontier)
2008
+ });
2009
+ }
2010
+ function cloneCheckpoint(checkpoint) {
2011
+ if (checkpoint.modality !== "spreadsheet") {
2012
+ return Object.freeze({ ...checkpoint });
2013
+ }
2014
+ return Object.freeze({
2015
+ ...checkpoint,
2016
+ causalFrontier: cloneFrontier(checkpoint.causalFrontier)
2017
+ });
2018
+ }
2019
+ function checkpointAtGenesis(artifact, nativeRevision = 0) {
2020
+ return artifact.modality === "spreadsheet" ? Object.freeze({
2021
+ modality: "spreadsheet",
2022
+ headSequence: 0,
2023
+ causalFrontier: editableArtifactCausalFrontier([]),
2024
+ stateHash: artifact.stateHash
2025
+ }) : Object.freeze({
2026
+ modality: artifact.modality,
2027
+ headSequence: 0,
2028
+ nativeRevision,
2029
+ stateHash: artifact.stateHash
2030
+ });
2031
+ }
2032
+ function sameBytes2(left, right) {
2033
+ if (left.byteLength !== right.byteLength) return false;
2034
+ let difference = 0;
2035
+ for (let index = 0; index < left.byteLength; index += 1) {
2036
+ difference |= left[index] ^ right[index];
2037
+ }
2038
+ return difference === 0;
2039
+ }
2040
+ function cloneOutbox(record) {
2041
+ return Object.freeze({
2042
+ ...record,
2043
+ event: Object.freeze({
2044
+ ...record.event,
2045
+ scope: Object.freeze({ ...record.event.scope })
2046
+ })
2047
+ });
2048
+ }
2049
+ function cloneFrontier(frontier) {
2050
+ return Object.freeze(frontier.map((entry) => Object.freeze({ ...entry })));
2051
+ }
2052
+ function compareText(left, right) {
2053
+ return left < right ? -1 : left > right ? 1 : 0;
2054
+ }
2055
+
2056
+ // src/domain/editable-artifacts/postgres-adapters.ts
2057
+ function editableArtifactStorePortFromPostgres(store) {
2058
+ return store;
2059
+ }
2060
+ function editableArtifactAuthorizationRevisionPortFromPostgres(store) {
2061
+ return store;
2062
+ }
2063
+ function editableArtifactScopeAuthorizationRevisionPortFromPostgres(store) {
2064
+ return store;
2065
+ }
2066
+ function editableArtifactLiveReadPortFromPostgres(store) {
2067
+ return store;
2068
+ }
2069
+ function editableArtifactLiveTicketStorePortFromPostgres(store) {
2070
+ return store;
2071
+ }
2072
+
2073
+ // src/domain/editable-artifacts/snapshot-compaction.ts
2074
+ import { BoundedObjectWriteError } from "@opengeni/storage";
2075
+ var SNAPSHOT_MIME_TYPE = "application/vnd.opengeni.editable-artifact-snapshot";
2076
+ var EditableArtifactCompactionPipeline = class {
2077
+ #dependencies;
2078
+ constructor(dependencies) {
2079
+ const maxSnapshotBytes = dependencies.maxSnapshotBytes ?? MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES;
2080
+ if (!Number.isSafeInteger(maxSnapshotBytes) || maxSnapshotBytes <= 0 || maxSnapshotBytes > MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES) {
2081
+ throw new TypeError("Compaction snapshot limit is invalid");
2082
+ }
2083
+ this.#dependencies = Object.freeze({ ...dependencies, maxSnapshotBytes });
2084
+ }
2085
+ async prepare(input) {
2086
+ const scope = editableArtifactScope(input.scope);
2087
+ const artifactId = editableArtifactId(input.artifactId);
2088
+ const snapshotId = editableArtifactSnapshotId(input.snapshotId);
2089
+ validateBasis(input.state, scope, artifactId);
2090
+ throwIfCancelled(input.signal);
2091
+ try {
2092
+ const generated = await this.#dependencies.kernel.createCanonicalSnapshot({
2093
+ state: input.state,
2094
+ ...input.signal ? { signal: input.signal } : {}
2095
+ });
2096
+ validateGenerated(generated, input.state, scope, artifactId);
2097
+ const stored = await this.#dependencies.objects.write({
2098
+ chunks: generated.canonicalChunks,
2099
+ contentType: SNAPSHOT_MIME_TYPE,
2100
+ maxBytes: this.#dependencies.maxSnapshotBytes,
2101
+ expectedByteSize: generated.canonicalByteSize,
2102
+ expectedContentHash: generated.canonicalContentHash,
2103
+ ...input.signal ? { signal: input.signal } : {}
2104
+ });
2105
+ const common = {
2106
+ snapshotId,
2107
+ blobReference: stored.opaqueReference,
2108
+ byteSize: stored.byteSize,
2109
+ contentHash: editableArtifactContentHash(stored.contentHash),
2110
+ mimeType: SNAPSHOT_MIME_TYPE,
2111
+ modality: generated.modality,
2112
+ coveredHeadSequence: generated.coveredHeadSequence,
2113
+ stateHash: generated.stateHash,
2114
+ modelSchemaVersion: generated.modelSchemaVersion,
2115
+ kernelVersion: generated.kernelVersion,
2116
+ verifiedAt: canonicalTimestamp(this.#dependencies.now())
2117
+ };
2118
+ return generated.modality === "spreadsheet" ? Object.freeze({
2119
+ ...common,
2120
+ modality: generated.modality,
2121
+ coveredCausalFrontier: generated.coveredCausalFrontier,
2122
+ operationProtocolVersion: generated.operationProtocolVersion,
2123
+ crdtStateVersion: generated.crdtStateVersion
2124
+ }) : Object.freeze({
2125
+ ...common,
2126
+ modality: generated.modality,
2127
+ nativeRevision: generated.nativeRevision
2128
+ });
2129
+ } catch (error) {
2130
+ if (error instanceof EditableArtifactSnapshotVerificationError || error instanceof BoundedObjectWriteError) {
2131
+ throw error;
2132
+ }
2133
+ if (input.signal?.aborted) {
2134
+ throw new EditableArtifactSnapshotVerificationError("cancelled");
2135
+ }
2136
+ throw new EditableArtifactSnapshotVerificationError("kernel_rejected");
2137
+ }
2138
+ }
2139
+ };
2140
+ function validateBasis(state, scope, artifactId) {
2141
+ if (state.artifact.scope.accountId !== scope.accountId || state.artifact.scope.workspaceId !== scope.workspaceId || state.artifact.id !== artifactId || state.artifact.modality !== state.modality) {
2142
+ throw new EditableArtifactSnapshotVerificationError("identity_mismatch");
2143
+ }
2144
+ for (const value of [state.tailTransactionCount, state.tailByteSize]) {
2145
+ if (!Number.isSafeInteger(value) || value < 0) {
2146
+ throw new EditableArtifactSnapshotVerificationError("coverage_mismatch");
2147
+ }
2148
+ }
2149
+ }
2150
+ function validateGenerated(value, state, scope, artifactId) {
2151
+ if (value.scope.accountId !== scope.accountId || value.scope.workspaceId !== scope.workspaceId || value.artifactId !== artifactId || value.modality !== state.modality) {
2152
+ throw new EditableArtifactSnapshotVerificationError("identity_mismatch");
2153
+ }
2154
+ if (value.coveredHeadSequence !== state.artifact.headSequence || editableArtifactStateHash(value.stateHash) !== state.artifact.stateHash || value.modality === "spreadsheet" && (state.modality !== "spreadsheet" || !causalFrontiersEqual(
2155
+ editableArtifactCausalFrontier(value.coveredCausalFrontier),
2156
+ state.artifact.causalFrontier
2157
+ )) || value.modality !== "spreadsheet" && (state.modality === "spreadsheet" || value.nativeRevision !== expectedNativeRevision(state))) {
2158
+ throw new EditableArtifactSnapshotVerificationError("coverage_mismatch");
2159
+ }
2160
+ if (!Number.isSafeInteger(value.canonicalByteSize) || value.canonicalByteSize <= 0 || value.canonicalByteSize > MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES) {
2161
+ throw new EditableArtifactSnapshotVerificationError("limit_exceeded");
2162
+ }
2163
+ editableArtifactContentHash(value.canonicalContentHash);
2164
+ const versions = value.modality === "spreadsheet" ? [value.modelSchemaVersion, value.operationProtocolVersion, value.crdtStateVersion] : [value.modelSchemaVersion];
2165
+ if (versions.some((version) => !Number.isSafeInteger(version) || version <= 0)) {
2166
+ throw new EditableArtifactSnapshotVerificationError("version_mismatch");
2167
+ }
2168
+ try {
2169
+ assertBoundedKernelVersion(value.kernelVersion);
2170
+ } catch {
2171
+ throw new EditableArtifactSnapshotVerificationError("version_mismatch");
2172
+ }
2173
+ if (!value.canonicalChunks || typeof value.canonicalChunks[Symbol.asyncIterator] !== "function") {
2174
+ throw new EditableArtifactSnapshotVerificationError("kernel_rejected");
2175
+ }
2176
+ }
2177
+ function expectedNativeRevision(state) {
2178
+ return state.committedTransactionTail.at(-1)?.nativeRevision ?? state.snapshot?.nativeRevision ?? state.baseNativeRevision;
2179
+ }
2180
+ function canonicalTimestamp(value) {
2181
+ if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
2182
+ throw new TypeError("Compaction verification clock returned an invalid date");
2183
+ }
2184
+ return value.toISOString();
2185
+ }
2186
+ function throwIfCancelled(signal) {
2187
+ if (signal?.aborted) throw new EditableArtifactSnapshotVerificationError("cancelled");
2188
+ }
2189
+
2190
+ // src/domain/editable-artifacts/snapshot-verifier-genesis.ts
2191
+ import { BoundedObjectWriteError as BoundedObjectWriteError2 } from "@opengeni/storage";
2192
+ var SNAPSHOT_MIME_TYPE2 = "application/vnd.opengeni.editable-artifact-snapshot";
2193
+ var EditableArtifactGenesisPipeline = class {
2194
+ #dependencies;
2195
+ constructor(dependencies) {
2196
+ const maxSnapshotBytes = dependencies.maxSnapshotBytes ?? MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES;
2197
+ if (!Number.isSafeInteger(maxSnapshotBytes) || maxSnapshotBytes <= 0 || maxSnapshotBytes > MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES) {
2198
+ throw new TypeError("Genesis snapshot limit is invalid");
2199
+ }
2200
+ this.#dependencies = Object.freeze({
2201
+ kernel: dependencies.kernel,
2202
+ objects: dependencies.objects,
2203
+ now: dependencies.now,
2204
+ maxSnapshotBytes
2205
+ });
2206
+ }
2207
+ async prepare(input) {
2208
+ const scope = editableArtifactScope(input.scope);
2209
+ const artifactId = editableArtifactId(input.artifactId);
2210
+ const snapshotId = editableArtifactSnapshotId(input.snapshotId);
2211
+ if (!isModality(input.modality)) {
2212
+ throw new TypeError("Genesis modality is invalid");
2213
+ }
2214
+ throwIfGenesisCancelled(input.signal);
2215
+ try {
2216
+ const generated = await this.#dependencies.kernel.createCanonicalEmptySnapshot({
2217
+ scope,
2218
+ artifactId,
2219
+ modality: input.modality,
2220
+ ...input.signal ? { signal: input.signal } : {}
2221
+ });
2222
+ validateGeneratedGenesis(generated, scope, artifactId, input.modality);
2223
+ const stored = await this.#dependencies.objects.write({
2224
+ chunks: generated.canonicalChunks,
2225
+ contentType: SNAPSHOT_MIME_TYPE2,
2226
+ maxBytes: this.#dependencies.maxSnapshotBytes,
2227
+ expectedByteSize: generated.canonicalByteSize,
2228
+ expectedContentHash: generated.canonicalContentHash,
2229
+ ...input.signal ? { signal: input.signal } : {}
2230
+ });
2231
+ const verifiedAt = canonicalTimestamp2(this.#dependencies.now());
2232
+ const common = {
2233
+ snapshotId,
2234
+ blobReference: stored.opaqueReference,
2235
+ byteSize: stored.byteSize,
2236
+ contentHash: editableArtifactContentHash(stored.contentHash),
2237
+ mimeType: SNAPSHOT_MIME_TYPE2,
2238
+ modality: generated.modality,
2239
+ coveredHeadSequence: 0,
2240
+ stateHash: generated.stateHash,
2241
+ modelSchemaVersion: generated.modelSchemaVersion,
2242
+ kernelVersion: generated.kernelVersion,
2243
+ verifiedAt
2244
+ };
2245
+ return generated.modality === "spreadsheet" ? Object.freeze({
2246
+ ...common,
2247
+ modality: "spreadsheet",
2248
+ coveredCausalFrontier: editableArtifactCausalFrontier([]),
2249
+ operationProtocolVersion: generated.operationProtocolVersion,
2250
+ crdtStateVersion: generated.crdtStateVersion
2251
+ }) : Object.freeze({
2252
+ ...common,
2253
+ modality: generated.modality,
2254
+ nativeRevision: generated.nativeRevision
2255
+ });
2256
+ } catch (error) {
2257
+ if (error instanceof EditableArtifactSnapshotVerificationError || error instanceof BoundedObjectWriteError2) {
2258
+ throw error;
2259
+ }
2260
+ if (input.signal?.aborted) {
2261
+ throw new EditableArtifactSnapshotVerificationError("cancelled");
2262
+ }
2263
+ throw new EditableArtifactSnapshotVerificationError("kernel_rejected");
2264
+ }
2265
+ }
2266
+ };
2267
+ function validateGeneratedGenesis(value, scope, artifactId, modality) {
2268
+ if (value.scope.accountId !== scope.accountId || value.scope.workspaceId !== scope.workspaceId || value.artifactId !== artifactId || value.modality !== modality) {
2269
+ throw new EditableArtifactSnapshotVerificationError("identity_mismatch");
2270
+ }
2271
+ if (value.coveredHeadSequence !== 0 || (value.modality === "spreadsheet" ? editableArtifactCausalFrontier(value.coveredCausalFrontier).length !== 0 : value.nativeRevision !== 0)) {
2272
+ throw new EditableArtifactSnapshotVerificationError("coverage_mismatch");
2273
+ }
2274
+ if (!Number.isSafeInteger(value.canonicalByteSize) || value.canonicalByteSize <= 0 || value.canonicalByteSize > MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES) {
2275
+ throw new EditableArtifactSnapshotVerificationError("limit_exceeded");
2276
+ }
2277
+ editableArtifactContentHash(value.canonicalContentHash);
2278
+ editableArtifactStateHash(value.stateHash);
2279
+ const versions = value.modality === "spreadsheet" ? [value.modelSchemaVersion, value.operationProtocolVersion, value.crdtStateVersion] : [value.modelSchemaVersion];
2280
+ for (const version of versions) {
2281
+ if (!Number.isSafeInteger(version) || version <= 0) {
2282
+ throw new EditableArtifactSnapshotVerificationError("version_mismatch");
2283
+ }
2284
+ }
2285
+ try {
2286
+ assertBoundedKernelVersion(value.kernelVersion);
2287
+ } catch {
2288
+ throw new EditableArtifactSnapshotVerificationError("version_mismatch");
2289
+ }
2290
+ if (!value.canonicalChunks || typeof value.canonicalChunks[Symbol.asyncIterator] !== "function") {
2291
+ throw new EditableArtifactSnapshotVerificationError("kernel_rejected");
2292
+ }
2293
+ }
2294
+ function canonicalTimestamp2(value) {
2295
+ if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
2296
+ throw new TypeError("Genesis verification clock returned an invalid date");
2297
+ }
2298
+ return value.toISOString();
2299
+ }
2300
+ function isModality(value) {
2301
+ return value === "spreadsheet" || value === "presentation" || value === "document";
2302
+ }
2303
+ function throwIfGenesisCancelled(signal) {
2304
+ if (signal?.aborted) {
2305
+ throw new EditableArtifactSnapshotVerificationError("cancelled");
2306
+ }
2307
+ }
2308
+
2309
+ // src/domain/editable-artifacts/snapshot-verifier-materialization.ts
2310
+ import { createHash as createHash3 } from "crypto";
2311
+ import { EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES } from "@opengeni/contracts/editable-artifacts";
2312
+ var SHA256_PATTERN = /^sha256:[0-9a-f]{64}$/;
2313
+ var FORMAT_PATTERN = /^[a-z0-9][a-z0-9.+_-]{0,63}$/;
2314
+ var VERSION_PATTERN = /^[\x21-\x7e]+$/;
2315
+ function editableArtifactMaterializationKey(input) {
2316
+ for (const [label, value] of [
2317
+ ["state hash", input.stateHash],
2318
+ ["options hash", input.optionsHash],
2319
+ ["font registry hash", input.fontRegistryHash],
2320
+ ["policy hash", input.policyHash]
2321
+ ]) {
2322
+ if (!SHA256_PATTERN.test(value)) {
2323
+ throw new TypeError(`${label} must be a canonical SHA-256 digest`);
2324
+ }
2325
+ }
2326
+ if (!FORMAT_PATTERN.test(input.format)) {
2327
+ throw new TypeError("materialization format is invalid");
2328
+ }
2329
+ if (!VERSION_PATTERN.test(input.codecVersion) || input.codecVersion.length > 128) {
2330
+ throw new TypeError("codec version is invalid");
2331
+ }
2332
+ if (!VERSION_PATTERN.test(input.kernelVersion) || input.kernelVersion.length > EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES) {
2333
+ throw new TypeError("kernel version is invalid");
2334
+ }
2335
+ const fields = [
2336
+ input.stateHash,
2337
+ input.format,
2338
+ input.optionsHash,
2339
+ input.codecVersion,
2340
+ input.kernelVersion,
2341
+ input.fontRegistryHash,
2342
+ input.policyHash
2343
+ ];
2344
+ const digest = createHash3("sha256");
2345
+ digest.update("OpenGeni editable artifact materialization\0v1\0", "utf8");
2346
+ for (const field of fields) {
2347
+ const bytes = Buffer.from(field, "utf8");
2348
+ const length = Buffer.allocUnsafe(4);
2349
+ length.writeUInt32BE(bytes.byteLength);
2350
+ digest.update(length);
2351
+ digest.update(bytes);
2352
+ }
2353
+ return `materialization:v1:sha256:${digest.digest("hex")}`;
2354
+ }
2355
+
2356
+ export {
2357
+ EDITABLE_ARTIFACT_EXPORT_MAX_DOWNLOAD_BYTES,
2358
+ EDITABLE_ARTIFACT_EXPORT_MAX_OPTIONS_BYTES,
2359
+ EditableArtifactDurableExportError,
2360
+ EditableArtifactDurableExportService,
2361
+ editableArtifactMaterializationMimeType,
2362
+ editableArtifactFormatMatchesModality,
2363
+ validateEditableArtifactPinnedVersion,
2364
+ validateEditableArtifactMaterializationJob,
2365
+ EditableArtifactOfficeImportError,
2366
+ EditableArtifactAgentApplication,
2367
+ editableArtifactDurableExportStorePortFromPostgres,
2368
+ InMemoryEditableArtifactStore,
2369
+ InMemoryEditableArtifactStableIdFactory,
2370
+ SystemEditableArtifactClock,
2371
+ editableArtifactStorePortFromPostgres,
2372
+ editableArtifactAuthorizationRevisionPortFromPostgres,
2373
+ editableArtifactScopeAuthorizationRevisionPortFromPostgres,
2374
+ editableArtifactLiveReadPortFromPostgres,
2375
+ editableArtifactLiveTicketStorePortFromPostgres,
2376
+ EditableArtifactCompactionPipeline,
2377
+ EditableArtifactGenesisPipeline,
2378
+ editableArtifactMaterializationKey
2379
+ };
2380
+ //# sourceMappingURL=chunk-6WKPWE5S.js.map