@opengeni/core 0.21.10 → 0.24.1

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 (116) 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/chunk-6WKPWE5S.js +2380 -0
  6. package/dist/chunk-6WKPWE5S.js.map +1 -0
  7. package/dist/chunk-JJU6I5XD.js +2713 -0
  8. package/dist/chunk-JJU6I5XD.js.map +1 -0
  9. package/dist/chunk-NYPMQ7NO.js +2270 -0
  10. package/dist/chunk-NYPMQ7NO.js.map +1 -0
  11. package/dist/dependencies.d.ts +26 -6
  12. package/dist/domain/capabilities.d.ts +28 -3
  13. package/dist/domain/company-profile-durable-learning-adapter.d.ts +39 -0
  14. package/dist/domain/durable-learning-slack-publication.d.ts +72 -0
  15. package/dist/domain/editable-artifacts/agent-application.d.ts +192 -0
  16. package/dist/domain/editable-artifacts/durable-export-postgres.d.ts +4 -0
  17. package/dist/domain/editable-artifacts/durable-export.d.ts +212 -0
  18. package/dist/domain/editable-artifacts/errors.d.ts +47 -0
  19. package/dist/domain/editable-artifacts/hash.d.ts +11 -0
  20. package/dist/domain/editable-artifacts/in-memory.d.ts +99 -0
  21. package/dist/domain/editable-artifacts/index.d.ts +14 -0
  22. package/dist/domain/editable-artifacts/ports.d.ts +341 -0
  23. package/dist/domain/editable-artifacts/postgres-adapters.d.ts +13 -0
  24. package/dist/domain/editable-artifacts/service.d.ts +105 -0
  25. package/dist/domain/editable-artifacts/snapshot-compaction.d.ts +44 -0
  26. package/dist/domain/editable-artifacts/snapshot-verifier-genesis.d.ts +50 -0
  27. package/dist/domain/editable-artifacts/snapshot-verifier-materialization.d.ts +21 -0
  28. package/dist/domain/editable-artifacts/snapshot-verifier.d.ts +118 -0
  29. package/dist/domain/editable-artifacts/types.d.ts +410 -0
  30. package/dist/domain/memory-slack-delivery.d.ts +19 -0
  31. package/dist/domain/packs.d.ts +29 -1
  32. package/dist/domain/personal-connection-delegations.d.ts +9 -1
  33. package/dist/domain/scheduled-tasks.d.ts +2 -2
  34. package/dist/domain/session-tool-policy.d.ts +2 -2
  35. package/dist/domain/sessions.d.ts +14 -6
  36. package/dist/domain/skill-imports.d.ts +32 -0
  37. package/dist/domain/slack-publication-secret-safety.d.ts +8 -0
  38. package/dist/domain/timeline-annotations.d.ts +5 -0
  39. package/dist/domain/video-generation-capabilities.d.ts +9 -0
  40. package/dist/domain/video-generation.d.ts +47 -0
  41. package/dist/editable-artifact-live/application.d.ts +69 -0
  42. package/dist/editable-artifact-live/errors.d.ts +1 -0
  43. package/dist/editable-artifact-live/index.d.ts +8 -0
  44. package/dist/editable-artifact-live/outbox-dispatcher.d.ts +162 -0
  45. package/dist/editable-artifact-live/ports.d.ts +100 -0
  46. package/dist/editable-artifact-live/server.d.ts +71 -0
  47. package/dist/editable-artifact-live/ticket.d.ts +40 -0
  48. package/dist/editable-artifact-live/types.d.ts +213 -0
  49. package/dist/editable-artifact-live/wire.d.ts +34 -0
  50. package/dist/editable-artifact-live.d.ts +2 -0
  51. package/dist/editable-artifact-live.js +58 -0
  52. package/dist/editable-artifact-live.js.map +1 -0
  53. package/dist/editable-artifacts.d.ts +2 -0
  54. package/dist/editable-artifacts.js +179 -0
  55. package/dist/editable-artifacts.js.map +1 -0
  56. package/dist/index.d.ts +35 -26
  57. package/dist/index.js +2792 -609
  58. package/dist/index.js.map +1 -1
  59. package/dist/managed-session.d.ts +1 -1
  60. package/dist/rigs/index.d.ts +1 -1
  61. package/dist/rigs/provider-images.d.ts +31 -0
  62. package/dist/sandbox/routing.d.ts +1 -0
  63. package/dist/session-authorization.d.ts +1 -1
  64. package/dist/workflow-wake-contract.d.ts +7 -0
  65. package/package.json +18 -10
  66. package/src/application/new-session-drafts.ts +2 -0
  67. package/src/application/session-commands.ts +188 -107
  68. package/src/dependencies.ts +30 -2
  69. package/src/domain/capabilities.ts +604 -220
  70. package/src/domain/company-profile-durable-learning-adapter.ts +221 -0
  71. package/src/domain/durable-learning-slack-publication.ts +202 -0
  72. package/src/domain/editable-artifacts/agent-application.ts +687 -0
  73. package/src/domain/editable-artifacts/durable-export-postgres.ts +139 -0
  74. package/src/domain/editable-artifacts/durable-export.ts +734 -0
  75. package/src/domain/editable-artifacts/errors.ts +115 -0
  76. package/src/domain/editable-artifacts/hash.ts +131 -0
  77. package/src/domain/editable-artifacts/in-memory.ts +1662 -0
  78. package/src/domain/editable-artifacts/index.ts +14 -0
  79. package/src/domain/editable-artifacts/ports.ts +462 -0
  80. package/src/domain/editable-artifacts/postgres-adapters.ts +49 -0
  81. package/src/domain/editable-artifacts/service.ts +2402 -0
  82. package/src/domain/editable-artifacts/snapshot-compaction.ts +246 -0
  83. package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +235 -0
  84. package/src/domain/editable-artifacts/snapshot-verifier-materialization.ts +74 -0
  85. package/src/domain/editable-artifacts/snapshot-verifier.ts +687 -0
  86. package/src/domain/editable-artifacts/types.ts +835 -0
  87. package/src/domain/insights.ts +136 -33
  88. package/src/domain/memory-slack-delivery.ts +204 -0
  89. package/src/domain/memory-slack-publication.ts +5 -2
  90. package/src/domain/packs.ts +266 -5
  91. package/src/domain/personal-connection-delegations.ts +97 -6
  92. package/src/domain/scheduled-tasks.ts +155 -29
  93. package/src/domain/session-tool-policy.ts +8 -2
  94. package/src/domain/sessions.ts +274 -131
  95. package/src/domain/skill-imports.ts +350 -0
  96. package/src/domain/slack-publication-secret-safety.ts +42 -0
  97. package/src/domain/timeline-annotations.ts +204 -0
  98. package/src/domain/video-generation-capabilities.ts +69 -0
  99. package/src/domain/video-generation.ts +249 -0
  100. package/src/editable-artifact-live/application.ts +182 -0
  101. package/src/editable-artifact-live/errors.ts +4 -0
  102. package/src/editable-artifact-live/index.ts +8 -0
  103. package/src/editable-artifact-live/outbox-dispatcher.ts +916 -0
  104. package/src/editable-artifact-live/ports.ts +139 -0
  105. package/src/editable-artifact-live/server.ts +1707 -0
  106. package/src/editable-artifact-live/ticket.ts +217 -0
  107. package/src/editable-artifact-live/types.ts +286 -0
  108. package/src/editable-artifact-live/wire.ts +95 -0
  109. package/src/editable-artifact-live.ts +2 -0
  110. package/src/editable-artifacts.ts +2 -0
  111. package/src/index.ts +13 -0
  112. package/src/rigs/index.ts +26 -19
  113. package/src/rigs/provider-images.ts +110 -0
  114. package/src/sandbox/routing.ts +6 -3
  115. package/src/session-authorization.ts +3 -0
  116. package/src/workflow-wake-contract.ts +8 -0
@@ -0,0 +1,835 @@
1
+ import type {
2
+ EditableArtifactMutationIntent as ContractEditableArtifactMutationIntent,
3
+ EDITABLE_ARTIFACT_INTENT_VERSION,
4
+ } from "@opengeni/contracts/editable-artifacts";
5
+ import { EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES } from "@opengeni/contracts/editable-artifacts";
6
+
7
+ /**
8
+ * Domain vocabulary for collaborative, editable Office-like artifacts.
9
+ *
10
+ * This is intentionally unrelated to OpenGeni's published HTML artifacts and
11
+ * document-ingestion records. An editable artifact is mutable canonical model
12
+ * state plus a causally ordered operation history.
13
+ */
14
+
15
+ declare const editableArtifactIdBrand: unique symbol;
16
+ declare const editableArtifactTransactionIdBrand: unique symbol;
17
+ declare const editableArtifactReceiptIdBrand: unique symbol;
18
+ declare const editableArtifactSnapshotIdBrand: unique symbol;
19
+ declare const editableArtifactOutboxIdBrand: unique symbol;
20
+ declare const editableArtifactOperationIdBrand: unique symbol;
21
+ declare const editableArtifactReplicaIdBrand: unique symbol;
22
+ declare const editableArtifactClientTransactionIdBrand: unique symbol;
23
+ declare const editableArtifactRequestHashBrand: unique symbol;
24
+ declare const editableArtifactStateHashBrand: unique symbol;
25
+ declare const editableArtifactContentHashBrand: unique symbol;
26
+
27
+ export type EditableArtifactId = string & {
28
+ readonly [editableArtifactIdBrand]: true;
29
+ };
30
+ export type EditableArtifactTransactionId = string & {
31
+ readonly [editableArtifactTransactionIdBrand]: true;
32
+ };
33
+ export type EditableArtifactReceiptId = string & {
34
+ readonly [editableArtifactReceiptIdBrand]: true;
35
+ };
36
+ export type EditableArtifactSnapshotId = string & {
37
+ readonly [editableArtifactSnapshotIdBrand]: true;
38
+ };
39
+ export type EditableArtifactOutboxId = string & {
40
+ readonly [editableArtifactOutboxIdBrand]: true;
41
+ };
42
+ export type EditableArtifactOperationId = string & {
43
+ readonly [editableArtifactOperationIdBrand]: true;
44
+ };
45
+ export type EditableArtifactReplicaId = string & {
46
+ readonly [editableArtifactReplicaIdBrand]: true;
47
+ };
48
+ export type EditableArtifactClientTransactionId = string & {
49
+ readonly [editableArtifactClientTransactionIdBrand]: true;
50
+ };
51
+ export type EditableArtifactRequestHash = string & {
52
+ readonly [editableArtifactRequestHashBrand]: true;
53
+ };
54
+ export type EditableArtifactStateHash = string & {
55
+ readonly [editableArtifactStateHashBrand]: true;
56
+ };
57
+ export type EditableArtifactContentHash = string & {
58
+ readonly [editableArtifactContentHashBrand]: true;
59
+ };
60
+
61
+ export type EditableArtifactStableId =
62
+ | EditableArtifactId
63
+ | EditableArtifactTransactionId
64
+ | EditableArtifactReceiptId
65
+ | EditableArtifactSnapshotId
66
+ | EditableArtifactOutboxId
67
+ | EditableArtifactOperationId;
68
+
69
+ const STABLE_ID_PATTERN = /^[0-9a-f]{32}$/;
70
+ const REPLICA_ID_PATTERN = /^[0-9a-f]{16}$/;
71
+ const SHA256_PATTERN = /^sha256:[0-9a-f]{64}$/;
72
+
73
+ function assertNonzeroHex(value: string, pattern: RegExp, label: string): void {
74
+ if (!pattern.test(value) || /^0+$/.test(value)) {
75
+ throw new TypeError(`${label} must be fixed-width lowercase nonzero hexadecimal text`);
76
+ }
77
+ }
78
+
79
+ export function editableArtifactId(value: string): EditableArtifactId {
80
+ assertNonzeroHex(value, STABLE_ID_PATTERN, "artifact id");
81
+ return value as EditableArtifactId;
82
+ }
83
+
84
+ export function editableArtifactTransactionId(value: string): EditableArtifactTransactionId {
85
+ assertNonzeroHex(value, STABLE_ID_PATTERN, "server transaction id");
86
+ return value as EditableArtifactTransactionId;
87
+ }
88
+
89
+ export function editableArtifactReceiptId(value: string): EditableArtifactReceiptId {
90
+ assertNonzeroHex(value, STABLE_ID_PATTERN, "receipt id");
91
+ return value as EditableArtifactReceiptId;
92
+ }
93
+
94
+ export function editableArtifactSnapshotId(value: string): EditableArtifactSnapshotId {
95
+ assertNonzeroHex(value, STABLE_ID_PATTERN, "snapshot id");
96
+ return value as EditableArtifactSnapshotId;
97
+ }
98
+
99
+ export function editableArtifactOutboxId(value: string): EditableArtifactOutboxId {
100
+ assertNonzeroHex(value, STABLE_ID_PATTERN, "outbox id");
101
+ return value as EditableArtifactOutboxId;
102
+ }
103
+
104
+ export function editableArtifactOperationId(value: string): EditableArtifactOperationId {
105
+ assertNonzeroHex(value, STABLE_ID_PATTERN, "operation id");
106
+ return value as EditableArtifactOperationId;
107
+ }
108
+
109
+ export function editableArtifactReplicaId(value: string): EditableArtifactReplicaId {
110
+ assertNonzeroHex(value, REPLICA_ID_PATTERN, "replica id");
111
+ return value as EditableArtifactReplicaId;
112
+ }
113
+
114
+ export function editableArtifactClientTransactionId(
115
+ value: string,
116
+ ): EditableArtifactClientTransactionId {
117
+ if (value.length < 1 || value.length > 200 || !/^[A-Za-z0-9._:-]+$/.test(value)) {
118
+ throw new TypeError("client transaction id must contain 1-200 portable identifier characters");
119
+ }
120
+ return value as EditableArtifactClientTransactionId;
121
+ }
122
+
123
+ export function editableArtifactRequestHash(value: string): EditableArtifactRequestHash {
124
+ if (!SHA256_PATTERN.test(value)) {
125
+ throw new TypeError("request hash must be sha256 followed by 64 lowercase hexadecimal digits");
126
+ }
127
+ return value as EditableArtifactRequestHash;
128
+ }
129
+
130
+ export function editableArtifactStateHash(value: string): EditableArtifactStateHash {
131
+ if (!SHA256_PATTERN.test(value)) {
132
+ throw new TypeError("state hash must be sha256 followed by 64 lowercase hexadecimal digits");
133
+ }
134
+ return value as EditableArtifactStateHash;
135
+ }
136
+
137
+ export function editableArtifactContentHash(value: string): EditableArtifactContentHash {
138
+ if (!SHA256_PATTERN.test(value)) {
139
+ throw new TypeError("content hash must be sha256 followed by 64 lowercase hexadecimal digits");
140
+ }
141
+ return value as EditableArtifactContentHash;
142
+ }
143
+
144
+ export type EditableArtifactScope = Readonly<{
145
+ accountId: string;
146
+ workspaceId: string;
147
+ }>;
148
+
149
+ export function editableArtifactScope(input: EditableArtifactScope): EditableArtifactScope {
150
+ return Object.freeze({
151
+ accountId: boundedIdentity(input.accountId, "account id"),
152
+ workspaceId: boundedIdentity(input.workspaceId, "workspace id"),
153
+ });
154
+ }
155
+
156
+ function boundedIdentity(value: string, label: string): string {
157
+ if (
158
+ value.length < 1 ||
159
+ value.length > 256 ||
160
+ value.trim() !== value ||
161
+ !isWellFormedPersistedText(value)
162
+ ) {
163
+ throw new TypeError(`${label} must contain 1-256 non-padding characters`);
164
+ }
165
+ return value;
166
+ }
167
+
168
+ function boundedActorIdentity(value: string, label: string): string {
169
+ const byteLength = new TextEncoder().encode(value).byteLength;
170
+ if (
171
+ value.length < 1 ||
172
+ value.length > 256 ||
173
+ byteLength > 1_024 ||
174
+ value.trim() !== value ||
175
+ !isWellFormedPersistedText(value)
176
+ ) {
177
+ throw new TypeError(
178
+ `${label} must contain 1-256 well-formed non-padding characters and at most 1024 UTF-8 bytes`,
179
+ );
180
+ }
181
+ return value;
182
+ }
183
+
184
+ function isWellFormedPersistedText(value: string): boolean {
185
+ if (value.includes("\0")) return false;
186
+ for (let index = 0; index < value.length; index += 1) {
187
+ const codeUnit = value.charCodeAt(index);
188
+ if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {
189
+ const next = value.charCodeAt(index + 1);
190
+ if (!Number.isFinite(next) || next < 0xdc00 || next > 0xdfff) return false;
191
+ index += 1;
192
+ } else if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) {
193
+ return false;
194
+ }
195
+ }
196
+ return true;
197
+ }
198
+
199
+ export type EditableArtifactModality = "spreadsheet" | "presentation" | "document";
200
+ export type EditableArtifactLifecycleState = "active" | "archived";
201
+ export type EditableArtifactPermission =
202
+ | "create"
203
+ | "read"
204
+ | "edit"
205
+ | "import"
206
+ | "export"
207
+ | "manage";
208
+
209
+ export type EditableArtifactHumanActor = Readonly<{
210
+ kind: "human";
211
+ subjectId: string;
212
+ replicaId: EditableArtifactReplicaId;
213
+ }>;
214
+
215
+ export type EditableArtifactAgentActor = Readonly<{
216
+ kind: "agent";
217
+ subjectId: string;
218
+ replicaId: EditableArtifactReplicaId;
219
+ sessionId: string;
220
+ turnId: string;
221
+ attemptId: string;
222
+ generation: number;
223
+ }>;
224
+
225
+ export type EditableArtifactServiceActor = Readonly<{
226
+ kind: "service";
227
+ subjectId: string;
228
+ replicaId: EditableArtifactReplicaId;
229
+ service: string;
230
+ }>;
231
+
232
+ export type EditableArtifactActor =
233
+ | EditableArtifactHumanActor
234
+ | EditableArtifactAgentActor
235
+ | EditableArtifactServiceActor;
236
+
237
+ export function validateEditableArtifactActor(actor: EditableArtifactActor): void {
238
+ const record = exactPlainDataRecord(actor, "editable artifact actor");
239
+ const kind = ownDataValue(record, "kind", "editable artifact actor");
240
+ const allowed =
241
+ kind === "human"
242
+ ? ["kind", "subjectId", "replicaId"]
243
+ : kind === "agent"
244
+ ? ["kind", "subjectId", "replicaId", "sessionId", "turnId", "attemptId", "generation"]
245
+ : kind === "service"
246
+ ? ["kind", "subjectId", "replicaId", "service"]
247
+ : null;
248
+ if (!allowed) throw new TypeError("editable artifact actor kind is invalid");
249
+ const names = Object.getOwnPropertyNames(record);
250
+ if (names.length !== allowed.length || names.some((name) => !allowed.includes(name))) {
251
+ throw new TypeError("editable artifact actor contains missing or unknown properties");
252
+ }
253
+ const subjectId = ownDataValue(record, "subjectId", "editable artifact actor");
254
+ const replicaId = ownDataValue(record, "replicaId", "editable artifact actor");
255
+ if (typeof subjectId !== "string" || typeof replicaId !== "string") {
256
+ throw new TypeError("editable artifact actor identity is malformed");
257
+ }
258
+ boundedActorIdentity(subjectId, "actor subject id");
259
+ editableArtifactReplicaId(replicaId);
260
+ if (kind === "agent") {
261
+ const sessionId = ownDataValue(record, "sessionId", "agent actor");
262
+ const turnId = ownDataValue(record, "turnId", "agent actor");
263
+ const attemptId = ownDataValue(record, "attemptId", "agent actor");
264
+ const generation = ownDataValue(record, "generation", "agent actor");
265
+ if (
266
+ typeof sessionId !== "string" ||
267
+ typeof turnId !== "string" ||
268
+ typeof attemptId !== "string" ||
269
+ typeof generation !== "number"
270
+ ) {
271
+ throw new TypeError("editable artifact agent actor is malformed");
272
+ }
273
+ boundedActorIdentity(sessionId, "agent session id");
274
+ boundedActorIdentity(turnId, "agent turn id");
275
+ boundedActorIdentity(attemptId, "agent attempt id");
276
+ assertNonnegativeSafeInteger(generation, "agent generation");
277
+ } else if (kind === "service") {
278
+ const service = ownDataValue(record, "service", "service actor");
279
+ if (typeof service !== "string") {
280
+ throw new TypeError("editable artifact service actor is malformed");
281
+ }
282
+ boundedActorIdentity(service, "service name");
283
+ }
284
+ }
285
+
286
+ function exactPlainDataRecord(value: unknown, label: string): Record<string, unknown> {
287
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
288
+ throw new TypeError(`${label} must be a plain data object`);
289
+ }
290
+ const prototype = Object.getPrototypeOf(value);
291
+ if (prototype !== Object.prototype && prototype !== null) {
292
+ throw new TypeError(`${label} must be a plain data object`);
293
+ }
294
+ if (Object.getOwnPropertySymbols(value).length > 0) {
295
+ throw new TypeError(`${label} must not contain symbol properties`);
296
+ }
297
+ return value as Record<string, unknown>;
298
+ }
299
+
300
+ function ownDataValue(record: Record<string, unknown>, key: string, label: string): unknown {
301
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
302
+ if (
303
+ !descriptor ||
304
+ !("value" in descriptor) ||
305
+ descriptor.enumerable !== true ||
306
+ descriptor.value === undefined
307
+ ) {
308
+ throw new TypeError(`${label} property ${key} must be own data`);
309
+ }
310
+ return descriptor.value;
311
+ }
312
+
313
+ /** Exact authority identity used by idempotency and operation authorship. */
314
+ export function editableArtifactActorKey(actor: EditableArtifactActor): string {
315
+ validateEditableArtifactActor(actor);
316
+ let actorKey: string;
317
+ switch (actor.kind) {
318
+ case "human":
319
+ actorKey = JSON.stringify([actor.kind, actor.subjectId]);
320
+ break;
321
+ case "agent":
322
+ actorKey = JSON.stringify([
323
+ actor.kind,
324
+ actor.subjectId,
325
+ actor.sessionId,
326
+ actor.turnId,
327
+ actor.attemptId,
328
+ actor.generation,
329
+ ]);
330
+ break;
331
+ case "service":
332
+ actorKey = JSON.stringify([actor.kind, actor.subjectId, actor.service]);
333
+ break;
334
+ default:
335
+ throw new TypeError("editable artifact actor kind is invalid");
336
+ }
337
+ if (new TextEncoder().encode(actorKey).byteLength > 8_192) {
338
+ throw new TypeError("editable artifact actor key exceeds 8192 UTF-8 bytes");
339
+ }
340
+ return actorKey;
341
+ }
342
+
343
+ export type EditableArtifactCausalEntry = Readonly<{
344
+ replicaId: EditableArtifactReplicaId;
345
+ counter: number;
346
+ }>;
347
+
348
+ /** Sorted, duplicate-free semantic causality. Never substitute headSequence. */
349
+ export type EditableArtifactCausalFrontier = readonly EditableArtifactCausalEntry[];
350
+
351
+ export function editableArtifactCausalFrontier(
352
+ entries: Iterable<EditableArtifactCausalEntry>,
353
+ ): EditableArtifactCausalFrontier {
354
+ const seen = new Set<string>();
355
+ const normalized = [...entries].map((entry) => {
356
+ const replicaId = editableArtifactReplicaId(entry.replicaId);
357
+ assertPositiveSafeInteger(entry.counter, `causal counter for ${replicaId}`);
358
+ if (seen.has(replicaId)) throw new TypeError(`duplicate causal replica: ${replicaId}`);
359
+ seen.add(replicaId);
360
+ return Object.freeze({ replicaId, counter: entry.counter });
361
+ });
362
+ normalized.sort((left, right) => compareCodeUnits(left.replicaId, right.replicaId));
363
+ return Object.freeze(normalized);
364
+ }
365
+
366
+ export function causalCounter(
367
+ frontier: EditableArtifactCausalFrontier,
368
+ replicaId: EditableArtifactReplicaId,
369
+ ): number {
370
+ return frontier.find((entry) => entry.replicaId === replicaId)?.counter ?? 0;
371
+ }
372
+
373
+ export function causalFrontierDominates(
374
+ candidate: EditableArtifactCausalFrontier,
375
+ required: EditableArtifactCausalFrontier,
376
+ ): boolean {
377
+ return required.every((entry) => causalCounter(candidate, entry.replicaId) >= entry.counter);
378
+ }
379
+
380
+ export function causalFrontiersEqual(
381
+ left: EditableArtifactCausalFrontier,
382
+ right: EditableArtifactCausalFrontier,
383
+ ): boolean {
384
+ return (
385
+ left.length === right.length &&
386
+ left.every(
387
+ (entry, index) =>
388
+ entry.replicaId === right[index]?.replicaId && entry.counter === right[index]?.counter,
389
+ )
390
+ );
391
+ }
392
+
393
+ export function mergeCausalFrontiers(
394
+ ...frontiers: readonly EditableArtifactCausalFrontier[]
395
+ ): EditableArtifactCausalFrontier {
396
+ const counters = new Map<EditableArtifactReplicaId, number>();
397
+ for (const frontier of frontiers) {
398
+ for (const entry of frontier) {
399
+ counters.set(entry.replicaId, Math.max(counters.get(entry.replicaId) ?? 0, entry.counter));
400
+ }
401
+ }
402
+ return editableArtifactCausalFrontier(
403
+ [...counters].map(([replicaId, counter]) => ({ replicaId, counter })),
404
+ );
405
+ }
406
+
407
+ export type EditableArtifactCausalDot = EditableArtifactCausalEntry;
408
+
409
+ type EditableArtifactCommon = Readonly<{
410
+ scope: EditableArtifactScope;
411
+ id: EditableArtifactId;
412
+ title: string;
413
+ lifecycle: EditableArtifactLifecycleState;
414
+ /** Local policy revision atomically fenced with every durable write. */
415
+ authorizationRevision: number;
416
+ headSequence: number;
417
+ stateHash: EditableArtifactStateHash;
418
+ currentSnapshotId: EditableArtifactSnapshotId | null;
419
+ createdAt: string;
420
+ updatedAt: string;
421
+ }>;
422
+
423
+ export type EditableArtifactSpreadsheet = EditableArtifactCommon &
424
+ Readonly<{
425
+ modality: "spreadsheet";
426
+ causalFrontier: EditableArtifactCausalFrontier;
427
+ }>;
428
+
429
+ export type EditableArtifactSerialized = EditableArtifactCommon &
430
+ Readonly<{ modality: "document" | "presentation" }>;
431
+
432
+ export type EditableArtifact = EditableArtifactSpreadsheet | EditableArtifactSerialized;
433
+
434
+ export type CreateEditableArtifactRequest = Readonly<{
435
+ idempotencyKey: EditableArtifactClientTransactionId;
436
+ modality: EditableArtifactModality;
437
+ title: string;
438
+ }>;
439
+
440
+ export type EditableArtifactOriginOperation = "create" | "import";
441
+ export const EDITABLE_ARTIFACT_ORIGINAL_IMPORT_MAX_BYTES = 64 * 1024 * 1024;
442
+
443
+ /**
444
+ * Immutable, already-retained Office source for one imported artifact. The
445
+ * object reference is infrastructure-owned; the remaining facts are bound into
446
+ * the import idempotency hash and independently checked by the snapshot
447
+ * verifier before publication.
448
+ */
449
+ export type EditableArtifactOriginalImport = Readonly<{
450
+ fileId: string;
451
+ blobReference: string;
452
+ byteSize: number;
453
+ contentHash: EditableArtifactContentHash;
454
+ mimeType:
455
+ | "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
456
+ | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
457
+ | "application/vnd.openxmlformats-officedocument.presentationml.presentation";
458
+ }>;
459
+
460
+ type ImportedEditableArtifactSnapshotRequest =
461
+ PublishEditableArtifactSnapshotRequest extends infer Snapshot
462
+ ? Snapshot extends PublishEditableArtifactSnapshotRequest
463
+ ? Omit<Snapshot, "snapshotId" | "verifiedAt">
464
+ : never
465
+ : never;
466
+
467
+ export type ImportEditableArtifactRequest = Readonly<{
468
+ idempotencyKey: EditableArtifactClientTransactionId;
469
+ modality: EditableArtifactModality;
470
+ title: string;
471
+ originalImport: EditableArtifactOriginalImport;
472
+ /** Snapshot identity and verification/publication timestamps remain server-owned. */
473
+ snapshot: ImportedEditableArtifactSnapshotRequest;
474
+ }>;
475
+
476
+ export type EditableArtifactCreationReceipt = Readonly<{
477
+ receiptId: EditableArtifactReceiptId;
478
+ scope: EditableArtifactScope;
479
+ artifactId: EditableArtifactId;
480
+ operationKind: EditableArtifactOriginOperation;
481
+ authorityKey: string;
482
+ idempotencyKey: EditableArtifactClientTransactionId;
483
+ /** Canonical hash of client semantics only; generated genesis facts are result data. */
484
+ requestHash: EditableArtifactRequestHash;
485
+ genesisSnapshotId: EditableArtifactSnapshotId;
486
+ createdAt: string;
487
+ }>;
488
+
489
+ export type CreateEditableArtifactResult = Readonly<{
490
+ artifact: EditableArtifact;
491
+ genesisSnapshot: EditableArtifactSnapshotMetadata;
492
+ creationReceipt: EditableArtifactCreationReceipt;
493
+ replayed: boolean;
494
+ }>;
495
+
496
+ /** Exact decoded shared OGATX001 contract; never independently recanonicalized. */
497
+ export type EditableArtifactMutationIntent = ContractEditableArtifactMutationIntent;
498
+
499
+ /** Server-validated/branded projection of the exact decoded shared contract. */
500
+ export type ValidatedEditableArtifactMutationIntent = Readonly<{
501
+ envelopeVersion: typeof EDITABLE_ARTIFACT_INTENT_VERSION;
502
+ protocolVersion: number;
503
+ modelSchemaVersion: number;
504
+ commandProtocolVersion: number;
505
+ artifactId: EditableArtifactId;
506
+ clientTransactionId: EditableArtifactClientTransactionId;
507
+ replicaId: EditableArtifactReplicaId;
508
+ /** One persisted counter is reserved per atomic local transaction. */
509
+ replicaCounter: number;
510
+ /** Null only for the first transaction authored by this replica. */
511
+ previousLocalTransactionId: EditableArtifactClientTransactionId | null;
512
+ observedHeadSequence: number;
513
+ causalBase: EditableArtifactCausalFrontier;
514
+ selectiveUndoOperationIds: readonly EditableArtifactOperationId[];
515
+ /** Canonical client commands; only the authoritative kernel may decode them. */
516
+ commandBytes: Uint8Array;
517
+ }>;
518
+
519
+ export type ApplyEditableArtifactTransactionRequest = Readonly<{
520
+ /** Exact owned canonical OGATX001 bytes. */
521
+ intentBytes: Uint8Array;
522
+ requestHash: EditableArtifactRequestHash;
523
+ /**
524
+ * Optional exact-head fence for clients that author from a bounded read.
525
+ * Browser replicas deliberately omit it so spreadsheet CRDT operations can
526
+ * merge. Agent edits always provide it and must re-inspect after a conflict.
527
+ */
528
+ expectedHead?: Readonly<{
529
+ sequence: number;
530
+ stateHash: EditableArtifactStateHash;
531
+ }>;
532
+ }>;
533
+
534
+ /** Metadata indexed for authorship/selective undo; command data stays in OGACO. */
535
+ export type EditableArtifactKernelOperation = Readonly<{
536
+ operationId: EditableArtifactOperationId;
537
+ dot: EditableArtifactCausalDot;
538
+ }>;
539
+
540
+ export type EditableArtifactOperationRecord = EditableArtifactKernelOperation &
541
+ Readonly<{
542
+ scope: EditableArtifactScope;
543
+ artifactId: EditableArtifactId;
544
+ serverTransactionId: EditableArtifactTransactionId;
545
+ sequence: number;
546
+ actorKey: string;
547
+ createdAt: string;
548
+ }>;
549
+
550
+ /**
551
+ * One exact canonical OGACO transaction. The opaque bytes are the sole
552
+ * authoritative operation payload and are replayed atomically by the native
553
+ * or WASM kernel. Core never decodes modality commands from this envelope.
554
+ */
555
+ type EditableArtifactCommittedTransactionCommon = Readonly<{
556
+ scope: EditableArtifactScope;
557
+ artifactId: EditableArtifactId;
558
+ modality: EditableArtifactModality;
559
+ serverTransactionId: EditableArtifactTransactionId;
560
+ requestHash: EditableArtifactRequestHash;
561
+ sequenceStart: number;
562
+ sequenceEnd: number;
563
+ priorStateHash: EditableArtifactStateHash;
564
+ stateHash: EditableArtifactStateHash;
565
+ modelSchemaVersion: number;
566
+ kernelVersion: string;
567
+ committedTransactionBytes: Uint8Array;
568
+ committedAt: string;
569
+ }>;
570
+
571
+ export type EditableArtifactSpreadsheetCommittedTransactionRecord =
572
+ EditableArtifactCommittedTransactionCommon &
573
+ Readonly<{
574
+ modality: "spreadsheet";
575
+ dot: EditableArtifactCausalDot;
576
+ resolvedCausalBase: EditableArtifactCausalFrontier;
577
+ resultingCausalFrontier: EditableArtifactCausalFrontier;
578
+ operationIds: readonly EditableArtifactOperationId[];
579
+ operationProtocolVersion: number;
580
+ }>;
581
+
582
+ export type EditableArtifactSerializedCommittedTransactionRecord =
583
+ EditableArtifactCommittedTransactionCommon &
584
+ Readonly<{
585
+ modality: "document" | "presentation";
586
+ commitProtocolVersion: number;
587
+ priorNativeRevision: number;
588
+ nativeRevision: number;
589
+ commandCount: number;
590
+ nativeReceiptBytes: Uint8Array;
591
+ }>;
592
+
593
+ export type EditableArtifactCommittedTransactionRecord =
594
+ | EditableArtifactSpreadsheetCommittedTransactionRecord
595
+ | EditableArtifactSerializedCommittedTransactionRecord;
596
+
597
+ type EditableArtifactReceiptCommon = Readonly<{
598
+ receiptId: EditableArtifactReceiptId;
599
+ scope: EditableArtifactScope;
600
+ artifactId: EditableArtifactId;
601
+ modality: EditableArtifactModality;
602
+ serverTransactionId: EditableArtifactTransactionId;
603
+ clientTransactionId: EditableArtifactClientTransactionId;
604
+ replicaId: EditableArtifactReplicaId;
605
+ replicaCounter: number;
606
+ previousLocalTransactionId: EditableArtifactClientTransactionId | null;
607
+ requestHash: EditableArtifactRequestHash;
608
+ /** Exact canonical bytes whose SHA-256 is requestHash. */
609
+ intentBytes: Uint8Array;
610
+ actorKey: string;
611
+ sequenceStart: number;
612
+ sequenceEnd: number;
613
+ priorStateHash: EditableArtifactStateHash;
614
+ stateHash: EditableArtifactStateHash;
615
+ intentEnvelopeVersion: number;
616
+ intentProtocolVersion: number;
617
+ commandProtocolVersion: number;
618
+ kernelVersion: string;
619
+ modelSchemaVersion: number;
620
+ committedAt: string;
621
+ }>;
622
+
623
+ export type EditableArtifactSpreadsheetReceipt = EditableArtifactReceiptCommon &
624
+ Readonly<{
625
+ modality: "spreadsheet";
626
+ causalBase: EditableArtifactCausalFrontier;
627
+ resolvedCausalBase: EditableArtifactCausalFrontier;
628
+ resultingCausalFrontier: EditableArtifactCausalFrontier;
629
+ stateHash: EditableArtifactStateHash;
630
+ operationCount: number;
631
+ selectiveUndoOperationIds: readonly EditableArtifactOperationId[];
632
+ operationProtocolVersion: number;
633
+ }>;
634
+
635
+ export type EditableArtifactSerializedReceipt = EditableArtifactReceiptCommon &
636
+ Readonly<{
637
+ modality: "document" | "presentation";
638
+ commitProtocolVersion: number;
639
+ priorNativeRevision: number;
640
+ nativeRevision: number;
641
+ commandCount: number;
642
+ }>;
643
+
644
+ export type EditableArtifactReceipt =
645
+ | EditableArtifactSpreadsheetReceipt
646
+ | EditableArtifactSerializedReceipt;
647
+
648
+ export type ApplyEditableArtifactTransactionResult = Readonly<{
649
+ receipt: EditableArtifactReceipt;
650
+ replayed: boolean;
651
+ }>;
652
+
653
+ type EditableArtifactSnapshotMetadataCommon = Readonly<{
654
+ scope: EditableArtifactScope;
655
+ artifactId: EditableArtifactId;
656
+ modality: EditableArtifactModality;
657
+ snapshotId: EditableArtifactSnapshotId;
658
+ blobReference: string;
659
+ byteSize: number;
660
+ contentHash: EditableArtifactContentHash;
661
+ mimeType: "application/vnd.opengeni.editable-artifact-snapshot";
662
+ coveredHeadSequence: number;
663
+ stateHash: EditableArtifactStateHash;
664
+ modelSchemaVersion: number;
665
+ kernelVersion: string;
666
+ verifiedAt: string;
667
+ publishedAt: string;
668
+ }>;
669
+
670
+ export type EditableArtifactSpreadsheetSnapshotMetadata = EditableArtifactSnapshotMetadataCommon &
671
+ Readonly<{
672
+ modality: "spreadsheet";
673
+ coveredCausalFrontier: EditableArtifactCausalFrontier;
674
+ operationProtocolVersion: number;
675
+ crdtStateVersion: number;
676
+ }>;
677
+
678
+ export type EditableArtifactSerializedSnapshotMetadata = EditableArtifactSnapshotMetadataCommon &
679
+ Readonly<{
680
+ modality: "document" | "presentation";
681
+ nativeRevision: number;
682
+ }>;
683
+
684
+ export type EditableArtifactSnapshotMetadata =
685
+ | EditableArtifactSpreadsheetSnapshotMetadata
686
+ | EditableArtifactSerializedSnapshotMetadata;
687
+
688
+ export type PublishEditableArtifactSnapshotRequest =
689
+ EditableArtifactSnapshotMetadata extends infer Snapshot
690
+ ? Snapshot extends EditableArtifactSnapshotMetadata
691
+ ? Omit<Snapshot, "scope" | "artifactId" | "publishedAt">
692
+ : never
693
+ : never;
694
+
695
+ type EditableArtifactTransactionCommittedEventCommon = Readonly<{
696
+ kind: "transaction_committed";
697
+ schemaVersion: 1;
698
+ scope: EditableArtifactScope;
699
+ artifactId: EditableArtifactId;
700
+ modality: EditableArtifactModality;
701
+ serverTransactionId: EditableArtifactTransactionId;
702
+ sequenceStart: number;
703
+ sequenceEnd: number;
704
+ stateHash: EditableArtifactStateHash;
705
+ committedAt: string;
706
+ }>;
707
+
708
+ export type EditableArtifactTransactionCommittedEvent =
709
+ | (EditableArtifactTransactionCommittedEventCommon &
710
+ Readonly<{ modality: "spreadsheet"; operationProtocolVersion: number }>)
711
+ | (EditableArtifactTransactionCommittedEventCommon &
712
+ Readonly<{
713
+ modality: "document" | "presentation";
714
+ commitProtocolVersion: number;
715
+ }>);
716
+
717
+ type EditableArtifactSnapshotPublishedEventCommon = Readonly<{
718
+ kind: "snapshot_published";
719
+ schemaVersion: 1;
720
+ scope: EditableArtifactScope;
721
+ artifactId: EditableArtifactId;
722
+ modality: EditableArtifactModality;
723
+ snapshotId: EditableArtifactSnapshotId;
724
+ coveredHeadSequence: number;
725
+ stateHash: EditableArtifactStateHash;
726
+ publishedAt: string;
727
+ }>;
728
+
729
+ export type EditableArtifactSnapshotPublishedEvent =
730
+ | (EditableArtifactSnapshotPublishedEventCommon &
731
+ Readonly<{ modality: "spreadsheet"; operationProtocolVersion: number }>)
732
+ | (EditableArtifactSnapshotPublishedEventCommon &
733
+ Readonly<{ modality: "document" | "presentation" }>);
734
+
735
+ /** Durable live fanout hint. Consumers gap-fill canonical transactions. */
736
+ export type EditableArtifactLiveEvent =
737
+ | EditableArtifactTransactionCommittedEvent
738
+ | EditableArtifactSnapshotPublishedEvent;
739
+
740
+ export type EditableArtifactOutboxRetryFailureCode =
741
+ | "broker_unavailable"
742
+ | "broker_backpressure"
743
+ | "publish_timeout";
744
+
745
+ export type EditableArtifactOutboxDeadLetterFailureCode = "invalid_hint" | "oversized_hint";
746
+
747
+ export type EditableArtifactOutboxErrorCode =
748
+ | EditableArtifactOutboxRetryFailureCode
749
+ | EditableArtifactOutboxDeadLetterFailureCode;
750
+
751
+ export type EditableArtifactLiveOutboxRecord = Readonly<{
752
+ outboxId: EditableArtifactOutboxId;
753
+ event: EditableArtifactLiveEvent;
754
+ state: "pending" | "publishing" | "published" | "dead_lettered";
755
+ attemptCount: number;
756
+ leaseOwner: string | null;
757
+ leaseExpiresAt: string | null;
758
+ nextAttemptAt: string;
759
+ lastErrorCode: EditableArtifactOutboxErrorCode | null;
760
+ publishedAt: string | null;
761
+ deadLetteredAt: string | null;
762
+ createdAt: string;
763
+ }>;
764
+
765
+ export type EditableArtifactSequenceCheckpoint =
766
+ | Readonly<{
767
+ modality: "spreadsheet";
768
+ headSequence: number;
769
+ causalFrontier: EditableArtifactCausalFrontier;
770
+ stateHash: EditableArtifactStateHash;
771
+ }>
772
+ | Readonly<{
773
+ modality: "document" | "presentation";
774
+ headSequence: number;
775
+ nativeRevision: number;
776
+ stateHash: EditableArtifactStateHash;
777
+ }>;
778
+
779
+ export function assertNonnegativeSafeInteger(value: number, label: string): void {
780
+ if (!Number.isSafeInteger(value) || value < 0) {
781
+ throw new TypeError(`${label} must be a nonnegative safe integer`);
782
+ }
783
+ }
784
+
785
+ export function assertPositiveSafeInteger(value: number, label: string): void {
786
+ if (!Number.isSafeInteger(value) || value < 1) {
787
+ throw new TypeError(`${label} must be a positive safe integer`);
788
+ }
789
+ }
790
+
791
+ export function assertIsoTimestamp(value: string, label: string): void {
792
+ if (
793
+ !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value) ||
794
+ !Number.isFinite(Date.parse(value)) ||
795
+ new Date(value).toISOString() !== value
796
+ ) {
797
+ throw new TypeError(`${label} must be a canonical UTC ISO timestamp`);
798
+ }
799
+ }
800
+
801
+ export function assertBoundedArtifactTitle(value: string): void {
802
+ const bytes = new TextEncoder().encode(value).byteLength;
803
+ if (bytes < 1 || bytes > 512 || value.trim() !== value || !isWellFormedPersistedText(value)) {
804
+ throw new TypeError("artifact title must contain 1-512 UTF-8 bytes without padding");
805
+ }
806
+ }
807
+
808
+ export function assertBoundedOpaqueReference(value: string, label: string): void {
809
+ const bytes = new TextEncoder().encode(value).byteLength;
810
+ if (bytes < 1 || bytes > 1024 || value.trim() !== value || !isWellFormedPersistedText(value)) {
811
+ throw new TypeError(`${label} must contain 1-1024 UTF-8 bytes without padding`);
812
+ }
813
+ }
814
+
815
+ export function assertBoundedKernelVersion(value: unknown): asserts value is string {
816
+ if (typeof value !== "string") {
817
+ throw new TypeError("kernel version must be a string");
818
+ }
819
+ const bytes = new TextEncoder().encode(value).byteLength;
820
+ if (
821
+ bytes < 1 ||
822
+ bytes > EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES ||
823
+ value.trim() !== value ||
824
+ !isWellFormedPersistedText(value)
825
+ ) {
826
+ throw new TypeError(
827
+ `kernel version must contain 1-${EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES} well-formed UTF-8 bytes without padding`,
828
+ );
829
+ }
830
+ }
831
+
832
+ /** Locale-independent ordering used by every canonical wire/hash projection. */
833
+ export function compareCodeUnits(left: string, right: string): number {
834
+ return left < right ? -1 : left > right ? 1 : 0;
835
+ }