@powerhousedao/shared 6.0.0-dev.105 → 6.0.0-dev.107

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 (131) hide show
  1. package/dist/analytics/index.d.ts +42 -4
  2. package/dist/analytics/index.d.ts.map +1 -1
  3. package/dist/analytics/index.js +307 -4
  4. package/dist/analytics/index.js.map +1 -1
  5. package/dist/clis/index.d.mts +1271 -0
  6. package/dist/clis/index.d.mts.map +1 -0
  7. package/dist/clis/index.mjs +6801 -0
  8. package/dist/clis/index.mjs.map +1 -0
  9. package/dist/connect/index.d.ts +866 -1
  10. package/dist/connect/index.d.ts.map +1 -1
  11. package/dist/connect/index.js +254 -1
  12. package/dist/connect/index.js.map +1 -1
  13. package/dist/constants.d.ts +8 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +41 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/document-drive/index.d.ts +546 -0
  18. package/dist/document-drive/index.d.ts.map +1 -0
  19. package/dist/document-drive/index.js +956 -0
  20. package/dist/document-drive/index.js.map +1 -0
  21. package/dist/document-model/index.d.ts +3 -5
  22. package/dist/document-model/index.js +3408 -2
  23. package/dist/document-model/index.js.map +1 -1
  24. package/dist/index-dg_xL7sp.d.ts +567 -0
  25. package/dist/index-dg_xL7sp.d.ts.map +1 -0
  26. package/dist/processors/index.d.ts +2 -5
  27. package/dist/processors/index.js +116 -3
  28. package/dist/processors/index.js.map +1 -1
  29. package/dist/registry/index.d.ts +46 -0
  30. package/dist/registry/index.d.ts.map +1 -0
  31. package/dist/registry/index.js +0 -0
  32. package/dist/types-DWXYsIF1.d.ts +158 -0
  33. package/dist/types-DWXYsIF1.d.ts.map +1 -0
  34. package/dist/types-faUXKACL.d.ts +2153 -0
  35. package/dist/types-faUXKACL.d.ts.map +1 -0
  36. package/package.json +44 -4
  37. package/dist/analytics/analytics-path.d.ts +0 -36
  38. package/dist/analytics/analytics-path.d.ts.map +0 -1
  39. package/dist/analytics/analytics-path.js +0 -170
  40. package/dist/analytics/analytics-path.js.map +0 -1
  41. package/dist/analytics/analytics-period.d.ts +0 -40
  42. package/dist/analytics/analytics-period.d.ts.map +0 -1
  43. package/dist/analytics/analytics-period.js +0 -204
  44. package/dist/analytics/analytics-period.js.map +0 -1
  45. package/dist/analytics/constants.d.ts +0 -35
  46. package/dist/analytics/constants.d.ts.map +0 -1
  47. package/dist/analytics/constants.js +0 -40
  48. package/dist/analytics/constants.js.map +0 -1
  49. package/dist/analytics/types.d.ts +0 -85
  50. package/dist/analytics/types.d.ts.map +0 -1
  51. package/dist/analytics/types.js +0 -2
  52. package/dist/analytics/types.js.map +0 -1
  53. package/dist/connect/env-config.d.ts +0 -862
  54. package/dist/connect/env-config.d.ts.map +0 -1
  55. package/dist/connect/env-config.js +0 -525
  56. package/dist/connect/env-config.js.map +0 -1
  57. package/dist/document-model/core/actions.d.ts +0 -62
  58. package/dist/document-model/core/actions.d.ts.map +0 -1
  59. package/dist/document-model/core/actions.js +0 -2
  60. package/dist/document-model/core/actions.js.map +0 -1
  61. package/dist/document-model/core/constants.d.ts +0 -6
  62. package/dist/document-model/core/constants.d.ts.map +0 -1
  63. package/dist/document-model/core/constants.js +0 -8
  64. package/dist/document-model/core/constants.js.map +0 -1
  65. package/dist/document-model/core/documents.d.ts +0 -102
  66. package/dist/document-model/core/documents.d.ts.map +0 -1
  67. package/dist/document-model/core/documents.js +0 -2
  68. package/dist/document-model/core/documents.js.map +0 -1
  69. package/dist/document-model/core/operations.d.ts +0 -74
  70. package/dist/document-model/core/operations.d.ts.map +0 -1
  71. package/dist/document-model/core/operations.js +0 -2
  72. package/dist/document-model/core/operations.js.map +0 -1
  73. package/dist/document-model/core/ph-types.d.ts +0 -7
  74. package/dist/document-model/core/ph-types.d.ts.map +0 -1
  75. package/dist/document-model/core/ph-types.js +0 -2
  76. package/dist/document-model/core/ph-types.js.map +0 -1
  77. package/dist/document-model/core/signatures.d.ts +0 -52
  78. package/dist/document-model/core/signatures.d.ts.map +0 -1
  79. package/dist/document-model/core/signatures.js +0 -2
  80. package/dist/document-model/core/signatures.js.map +0 -1
  81. package/dist/document-model/core/state.d.ts +0 -38
  82. package/dist/document-model/core/state.d.ts.map +0 -1
  83. package/dist/document-model/core/state.js +0 -2
  84. package/dist/document-model/core/state.js.map +0 -1
  85. package/dist/document-model/core/types.d.ts +0 -533
  86. package/dist/document-model/core/types.d.ts.map +0 -1
  87. package/dist/document-model/core/types.js +0 -2
  88. package/dist/document-model/core/types.js.map +0 -1
  89. package/dist/document-model/core/upgrades.d.ts +0 -24
  90. package/dist/document-model/core/upgrades.d.ts.map +0 -1
  91. package/dist/document-model/core/upgrades.js +0 -2
  92. package/dist/document-model/core/upgrades.js.map +0 -1
  93. package/dist/document-model/index.d.ts.map +0 -1
  94. package/dist/document-model/types.d.ts +0 -97
  95. package/dist/document-model/types.d.ts.map +0 -1
  96. package/dist/document-model/types.js +0 -2
  97. package/dist/document-model/types.js.map +0 -1
  98. package/dist/processors/constants.d.ts +0 -4
  99. package/dist/processors/constants.d.ts.map +0 -1
  100. package/dist/processors/constants.js +0 -4
  101. package/dist/processors/constants.js.map +0 -1
  102. package/dist/processors/drive-analytics/document-processor.d.ts +0 -10
  103. package/dist/processors/drive-analytics/document-processor.d.ts.map +0 -1
  104. package/dist/processors/drive-analytics/document-processor.js +0 -43
  105. package/dist/processors/drive-analytics/document-processor.js.map +0 -1
  106. package/dist/processors/drive-analytics/drive-processor.d.ts +0 -10
  107. package/dist/processors/drive-analytics/drive-processor.d.ts.map +0 -1
  108. package/dist/processors/drive-analytics/drive-processor.js +0 -85
  109. package/dist/processors/drive-analytics/drive-processor.js.map +0 -1
  110. package/dist/processors/drive-analytics/index.d.ts +0 -10
  111. package/dist/processors/drive-analytics/index.d.ts.map +0 -1
  112. package/dist/processors/drive-analytics/index.js +0 -28
  113. package/dist/processors/drive-analytics/index.js.map +0 -1
  114. package/dist/processors/drive-analytics/types.d.ts +0 -3
  115. package/dist/processors/drive-analytics/types.d.ts.map +0 -1
  116. package/dist/processors/drive-analytics/types.js +0 -2
  117. package/dist/processors/drive-analytics/types.js.map +0 -1
  118. package/dist/processors/index.d.ts.map +0 -1
  119. package/dist/processors/relational/types.d.ts +0 -72
  120. package/dist/processors/relational/types.d.ts.map +0 -1
  121. package/dist/processors/relational/types.js +0 -45
  122. package/dist/processors/relational/types.js.map +0 -1
  123. package/dist/processors/relational/utils.d.ts +0 -29
  124. package/dist/processors/relational/utils.d.ts.map +0 -1
  125. package/dist/processors/relational/utils.js +0 -67
  126. package/dist/processors/relational/utils.js.map +0 -1
  127. package/dist/processors/types.d.ts +0 -90
  128. package/dist/processors/types.d.ts.map +0 -1
  129. package/dist/processors/types.js +0 -2
  130. package/dist/processors/types.js.map +0 -1
  131. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,3 +1,3409 @@
1
- export * from "./core/constants.js";
2
- export * from "./core/ph-types.js";
1
+ import { ZodError, z } from "zod";
2
+ import stringifyJson, { stringify } from "safe-stable-stringify";
3
+ import { createHash } from "sha1-uint8array";
4
+ import JSZip from "jszip";
5
+ import { castDraft, create, unsafe } from "mutative";
6
+ import { pascalCase } from "change-case";
7
+ //#region document-model/crypto.ts
8
+ const hashBrowser = (data, algorithm = "sha1", encoding = "base64", _params) => {
9
+ if (!["sha1"].includes(algorithm)) throw new Error(`Hashing algorithm not supported: "${algorithm}". Available: sha1`);
10
+ if (!["base64", "hex"].includes(encoding)) throw new Error(`Hash encoding not supported: "${encoding}". Available: base64, hex`);
11
+ const hash = hashUIntArray(data, algorithm);
12
+ if (encoding === "hex") return uint8ArrayToHex(hash);
13
+ return uint8ArrayToBase64(hash);
14
+ };
15
+ function uint8ArrayToBase64(uint8Array) {
16
+ let binaryString = "";
17
+ for (let i = 0; i < uint8Array.length; i++) binaryString += String.fromCharCode(uint8Array[i]);
18
+ return btoa(binaryString);
19
+ }
20
+ function uint8ArrayToHex(uint8Array) {
21
+ return Array.from(uint8Array).map((byte) => byte.toString(16).padStart(2, "0")).join("");
22
+ }
23
+ function hashUIntArray(data, algorithm = "sha1") {
24
+ if (!["sha1"].includes(algorithm)) throw new Error("Hashing algorithm not supported: Available: sha1");
25
+ return createHash("sha1").update(data).digest();
26
+ }
27
+ function getUnixTimestamp(date) {
28
+ return (new Date(date).getTime() / 1e3).toFixed(0);
29
+ }
30
+ function buildOperationSignatureParams({ documentId, signer, action, previousStateHash }) {
31
+ const { scope, type } = action;
32
+ return [
33
+ getUnixTimestamp(/* @__PURE__ */ new Date()),
34
+ signer.app.key,
35
+ hashBrowser([
36
+ documentId,
37
+ scope,
38
+ type,
39
+ stringifyJson(action.input)
40
+ ].join("")),
41
+ previousStateHash
42
+ ];
43
+ }
44
+ const textEncode = new TextEncoder();
45
+ function buildOperationSignatureMessage(params) {
46
+ const message = params.join("");
47
+ const prefix = "Signed Operation:\n" + message.length.toString();
48
+ return textEncode.encode(prefix + message);
49
+ }
50
+ function ab2hex(ab) {
51
+ const view = ArrayBuffer.isView(ab) ? ab : new Uint8Array(ab);
52
+ return Array.prototype.map.call(view, (x) => ("00" + x.toString(16)).slice(-2)).join("");
53
+ }
54
+ function hex2ab(hex) {
55
+ return new Uint8Array(hex.match(/[\da-f]{2}/gi)?.map(function(h) {
56
+ return parseInt(h, 16);
57
+ }) ?? []);
58
+ }
59
+ //#endregion
60
+ //#region document-model/errors.ts
61
+ const FileSystemError = /* @__PURE__ */ new Error("File system not available.");
62
+ var InvalidActionInputError = class extends Error {
63
+ data;
64
+ constructor(data) {
65
+ super();
66
+ this.name = "InvalidActionInputError";
67
+ this.data = data;
68
+ this.message = this.message || `Invalid action input: ${JSON.stringify(data, null, 2)}`;
69
+ }
70
+ };
71
+ var InvalidActionInputZodError = class extends InvalidActionInputError {
72
+ issues;
73
+ constructor(issues) {
74
+ super(issues);
75
+ this.issues = issues;
76
+ this.name = "InvalidActionInputZodError";
77
+ }
78
+ };
79
+ var HashMismatchError = class extends Error {
80
+ _scope;
81
+ _document;
82
+ _operation;
83
+ constructor(scope, document, operation) {
84
+ super();
85
+ this.name = "HashMismatchError";
86
+ this._document = document;
87
+ this._scope = scope;
88
+ this._operation = operation;
89
+ this.message = JSON.stringify({
90
+ error: `Hash mismatch on document ${document.header.id}, scope ${scope}, index ${operation.index}`,
91
+ document,
92
+ operation
93
+ }, null, 1);
94
+ }
95
+ get document() {
96
+ return this._document;
97
+ }
98
+ get scope() {
99
+ return this._scope;
100
+ }
101
+ get operation() {
102
+ return this._operation;
103
+ }
104
+ };
105
+ //#endregion
106
+ //#region document-model/schemas.ts
107
+ const isDefinedNonNullAny = (v) => v !== void 0 && v !== null;
108
+ const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny(v));
109
+ const Load_StateSchema = z.enum(["LOAD_STATE"]);
110
+ const PruneSchema = z.enum(["PRUNE"]);
111
+ const RedoSchema = z.enum(["REDO"]);
112
+ const Set_NameSchema = z.enum(["SET_NAME"]);
113
+ const UndoSchema = z.enum(["UNDO"]);
114
+ function OperationScopeSchema() {
115
+ return z.string();
116
+ }
117
+ function DocumentActionSchema() {
118
+ return z.union([
119
+ LoadStateActionSchema(),
120
+ PruneActionSchema(),
121
+ RedoActionSchema(),
122
+ SetNameActionSchema(),
123
+ UndoActionSchema()
124
+ ]);
125
+ }
126
+ function DocumentFileSchema() {
127
+ return z.object({
128
+ __typename: z.literal("DocumentFile").optional(),
129
+ data: z.string(),
130
+ extension: z.string().nullable(),
131
+ fileName: z.string().nullable(),
132
+ mimeType: z.string()
133
+ });
134
+ }
135
+ function LoadStateActionSchema() {
136
+ return z.object({
137
+ id: z.string(),
138
+ timestampUtcMs: z.string(),
139
+ input: z.lazy(() => LoadStateActionInputSchema()),
140
+ type: Load_StateSchema,
141
+ scope: OperationScopeSchema()
142
+ });
143
+ }
144
+ function LoadStateActionInputSchema() {
145
+ return z.object({
146
+ operations: z.number(),
147
+ state: z.lazy(() => LoadStateActionStateInputSchema())
148
+ });
149
+ }
150
+ function LoadStateActionStateInputSchema() {
151
+ return z.object({
152
+ data: z.unknown().nullish(),
153
+ name: z.string()
154
+ });
155
+ }
156
+ function PruneActionSchema() {
157
+ return z.object({
158
+ id: z.string(),
159
+ timestampUtcMs: z.string(),
160
+ input: z.lazy(() => PruneActionInputSchema()),
161
+ type: PruneSchema,
162
+ scope: OperationScopeSchema()
163
+ });
164
+ }
165
+ function PruneActionInputSchema() {
166
+ return z.object({
167
+ end: z.number().nullish(),
168
+ start: z.number().nullish()
169
+ });
170
+ }
171
+ function RedoActionInputSchema() {
172
+ return z.object({ count: z.number() });
173
+ }
174
+ function RedoActionSchema() {
175
+ return z.object({
176
+ id: z.string(),
177
+ timestampUtcMs: z.string().datetime(),
178
+ input: RedoActionInputSchema(),
179
+ type: RedoSchema,
180
+ scope: OperationScopeSchema()
181
+ });
182
+ }
183
+ function SetNameActionInputSchema() {
184
+ return z.object({ name: z.string() });
185
+ }
186
+ function SetNameActionSchema() {
187
+ return z.object({
188
+ id: z.string(),
189
+ timestampUtcMs: z.string().datetime(),
190
+ input: SetNameActionInputSchema(),
191
+ type: Set_NameSchema,
192
+ scope: z.literal("global")
193
+ });
194
+ }
195
+ function UndoActionInputSchema() {
196
+ return z.object({ count: z.number() });
197
+ }
198
+ function UndoActionSchema() {
199
+ return z.object({
200
+ id: z.string(),
201
+ timestampUtcMs: z.string().datetime(),
202
+ input: UndoActionInputSchema(),
203
+ type: UndoSchema,
204
+ scope: OperationScopeSchema()
205
+ });
206
+ }
207
+ function AddChangeLogItemInputSchema() {
208
+ return z.object({
209
+ __typename: z.literal("AddChangeLogItemInput").optional(),
210
+ content: z.string(),
211
+ id: z.string(),
212
+ insertBefore: z.string().nullable()
213
+ });
214
+ }
215
+ function AddModuleInputSchema() {
216
+ return z.object({
217
+ description: z.string().nullish(),
218
+ id: z.string(),
219
+ name: z.string()
220
+ });
221
+ }
222
+ function AddOperationErrorInputSchema() {
223
+ return z.object({
224
+ errorCode: z.string().nullish(),
225
+ errorDescription: z.string().nullish(),
226
+ errorName: z.string().nullish(),
227
+ errorTemplate: z.string().nullish(),
228
+ id: z.string(),
229
+ operationId: z.string()
230
+ });
231
+ }
232
+ function AddOperationExampleInputSchema() {
233
+ return z.object({
234
+ example: z.string(),
235
+ id: z.string(),
236
+ operationId: z.string()
237
+ });
238
+ }
239
+ function AddOperationInputSchema() {
240
+ return z.object({
241
+ description: z.string().nullish(),
242
+ id: z.string(),
243
+ moduleId: z.string(),
244
+ name: z.string(),
245
+ reducer: z.string().nullish(),
246
+ schema: z.string().nullish(),
247
+ template: z.string().nullish(),
248
+ scope: OperationScopeSchema().nullish()
249
+ });
250
+ }
251
+ function AddStateExampleInputSchema() {
252
+ return z.object({
253
+ scope: z.string(),
254
+ example: z.string(),
255
+ id: z.string(),
256
+ insertBefore: z.string().nullish()
257
+ });
258
+ }
259
+ function AuthorSchema() {
260
+ return z.object({
261
+ __typename: z.literal("Author").optional(),
262
+ name: z.string(),
263
+ website: z.string().nullable()
264
+ });
265
+ }
266
+ function CodeExampleSchema() {
267
+ return z.object({
268
+ __typename: z.literal("CodeExample").optional(),
269
+ id: z.string(),
270
+ value: z.string()
271
+ });
272
+ }
273
+ function DeleteChangeLogItemInputSchema() {
274
+ return z.object({
275
+ __typename: z.literal("DeleteChangeLogItemInput").optional(),
276
+ id: z.string()
277
+ });
278
+ }
279
+ function DeleteModuleInputSchema() {
280
+ return z.object({ id: z.string() });
281
+ }
282
+ function DeleteOperationErrorInputSchema() {
283
+ return z.object({ id: z.string() });
284
+ }
285
+ function DeleteOperationExampleInputSchema() {
286
+ return z.object({ id: z.string() });
287
+ }
288
+ function DeleteOperationInputSchema() {
289
+ return z.object({ id: z.string() });
290
+ }
291
+ function DeleteStateExampleInputSchema() {
292
+ return z.object({
293
+ scope: z.string(),
294
+ id: z.string()
295
+ });
296
+ }
297
+ function DocumentModelInputSchema() {
298
+ return z.union([
299
+ AddChangeLogItemInputSchema(),
300
+ AddModuleInputSchema(),
301
+ AddOperationErrorInputSchema(),
302
+ AddOperationExampleInputSchema(),
303
+ AddOperationInputSchema(),
304
+ AddStateExampleInputSchema(),
305
+ DeleteChangeLogItemInputSchema(),
306
+ DeleteModuleInputSchema(),
307
+ DeleteOperationErrorInputSchema(),
308
+ DeleteOperationExampleInputSchema(),
309
+ DeleteOperationInputSchema(),
310
+ DeleteStateExampleInputSchema(),
311
+ MoveOperationInputSchema(),
312
+ ReorderChangeLogItemsInputSchema(),
313
+ ReorderModuleOperationsInputSchema(),
314
+ ReorderModulesInputSchema(),
315
+ ReorderOperationErrorsInputSchema(),
316
+ ReorderOperationExamplesInputSchema(),
317
+ ReorderStateExamplesInputSchema(),
318
+ SetAuthorNameInputSchema(),
319
+ SetAuthorWebsiteInputSchema(),
320
+ SetInitialStateInputSchema(),
321
+ SetModelDescriptionInputSchema(),
322
+ SetModelExtensionInputSchema(),
323
+ SetModelIdInputSchema(),
324
+ SetModelNameInputSchema(),
325
+ SetModuleDescriptionInputSchema(),
326
+ SetModuleNameInputSchema(),
327
+ SetOperationDescriptionInputSchema(),
328
+ SetOperationErrorCodeInputSchema(),
329
+ SetOperationErrorDescriptionInputSchema(),
330
+ SetOperationErrorNameInputSchema(),
331
+ SetOperationErrorTemplateInputSchema(),
332
+ SetOperationNameInputSchema(),
333
+ SetOperationReducerInputSchema(),
334
+ SetOperationSchemaInputSchema(),
335
+ SetOperationTemplateInputSchema(),
336
+ SetStateSchemaInputSchema(),
337
+ UpdateChangeLogItemInputSchema(),
338
+ UpdateOperationExampleInputSchema(),
339
+ UpdateStateExampleInputSchema()
340
+ ]);
341
+ }
342
+ function DocumentModelGlobalStateSchema() {
343
+ return z.object({
344
+ __typename: z.literal("DocumentModelGlobalState").optional(),
345
+ author: AuthorSchema(),
346
+ description: z.string(),
347
+ extension: z.string(),
348
+ id: z.string(),
349
+ name: z.string(),
350
+ specifications: z.array(DocumentSpecificationSchema())
351
+ });
352
+ }
353
+ function DocumentSpecificationSchema() {
354
+ return z.object({
355
+ __typename: z.literal("DocumentSpecification").optional(),
356
+ changeLog: z.array(z.string()),
357
+ modules: z.array(ModuleSchema()),
358
+ state: ScopeStateSchema(),
359
+ version: z.number().int()
360
+ });
361
+ }
362
+ function ModuleSchema() {
363
+ return z.object({
364
+ __typename: z.literal("ModuleSpecification").optional(),
365
+ description: z.string().nullable(),
366
+ id: z.string(),
367
+ name: z.string(),
368
+ operations: z.array(OperationSpecificationSchema())
369
+ });
370
+ }
371
+ function MoveOperationInputSchema() {
372
+ return z.object({
373
+ newModuleId: z.string(),
374
+ operationId: z.string()
375
+ });
376
+ }
377
+ function OperationSpecificationSchema() {
378
+ return z.object({
379
+ __typename: z.literal("OperationSpecification").optional(),
380
+ description: z.string().nullable(),
381
+ errors: z.array(OperationErrorSchema()),
382
+ examples: z.array(CodeExampleSchema()),
383
+ id: z.string(),
384
+ name: z.string().nullable(),
385
+ reducer: z.string().nullable(),
386
+ schema: z.string().nullable(),
387
+ template: z.string().nullable(),
388
+ scope: OperationScopeSchema()
389
+ });
390
+ }
391
+ function OperationErrorSchema() {
392
+ return z.object({
393
+ __typename: z.literal("OperationErrorSpecification").optional(),
394
+ code: z.string().nullable(),
395
+ description: z.string().nullable(),
396
+ id: z.string(),
397
+ name: z.string().nullable(),
398
+ template: z.string().nullable()
399
+ });
400
+ }
401
+ function ReorderChangeLogItemsInputSchema() {
402
+ return z.object({
403
+ __typename: z.literal("ReorderChangeLogItemsInput").optional(),
404
+ order: z.array(z.string())
405
+ });
406
+ }
407
+ function ReorderModuleOperationsInputSchema() {
408
+ return z.object({
409
+ moduleId: z.string(),
410
+ order: z.array(z.string())
411
+ });
412
+ }
413
+ function ReorderModulesInputSchema() {
414
+ return z.object({ order: z.array(z.string()) });
415
+ }
416
+ function ReorderOperationErrorsInputSchema() {
417
+ return z.object({
418
+ operationId: z.string(),
419
+ order: z.array(z.string())
420
+ });
421
+ }
422
+ function ReorderOperationExamplesInputSchema() {
423
+ return z.object({
424
+ operationId: z.string(),
425
+ order: z.array(z.string())
426
+ });
427
+ }
428
+ function ReorderStateExamplesInputSchema() {
429
+ return z.object({
430
+ scope: z.string(),
431
+ order: z.array(z.string())
432
+ });
433
+ }
434
+ function SetAuthorNameInputSchema() {
435
+ return z.object({ authorName: z.string() });
436
+ }
437
+ function SetAuthorWebsiteInputSchema() {
438
+ return z.object({ authorWebsite: z.string() });
439
+ }
440
+ function SetInitialStateInputSchema() {
441
+ return z.object({
442
+ scope: z.string(),
443
+ initialValue: z.string()
444
+ });
445
+ }
446
+ function SetModelDescriptionInputSchema() {
447
+ return z.object({ description: z.string() });
448
+ }
449
+ function SetModelExtensionInputSchema() {
450
+ return z.object({ extension: z.string() });
451
+ }
452
+ function SetModelIdInputSchema() {
453
+ return z.object({ id: z.string() });
454
+ }
455
+ function SetModelNameInputSchema() {
456
+ return z.object({ name: z.string() });
457
+ }
458
+ function SetModuleDescriptionInputSchema() {
459
+ return z.object({
460
+ description: z.string().nullish(),
461
+ id: z.string()
462
+ });
463
+ }
464
+ function SetModuleNameInputSchema() {
465
+ return z.object({
466
+ id: z.string(),
467
+ name: z.string().nullish()
468
+ });
469
+ }
470
+ function SetOperationDescriptionInputSchema() {
471
+ return z.object({
472
+ description: z.string().nullish(),
473
+ id: z.string()
474
+ });
475
+ }
476
+ function SetOperationErrorCodeInputSchema() {
477
+ return z.object({
478
+ errorCode: z.string().nullish(),
479
+ id: z.string()
480
+ });
481
+ }
482
+ function SetOperationErrorDescriptionInputSchema() {
483
+ return z.object({
484
+ errorDescription: z.string().nullish(),
485
+ id: z.string()
486
+ });
487
+ }
488
+ function SetOperationErrorNameInputSchema() {
489
+ return z.object({
490
+ errorName: z.string().nullish(),
491
+ id: z.string()
492
+ });
493
+ }
494
+ function SetOperationErrorTemplateInputSchema() {
495
+ return z.object({
496
+ errorTemplate: z.string().nullish(),
497
+ id: z.string()
498
+ });
499
+ }
500
+ function SetOperationNameInputSchema() {
501
+ return z.object({
502
+ id: z.string(),
503
+ name: z.string().nullish()
504
+ });
505
+ }
506
+ function SetOperationScopeInputSchema() {
507
+ return z.object({
508
+ id: z.string(),
509
+ scope: OperationScopeSchema()
510
+ });
511
+ }
512
+ function SetOperationReducerInputSchema() {
513
+ return z.object({
514
+ id: z.string(),
515
+ reducer: z.string().nullish()
516
+ });
517
+ }
518
+ function SetOperationSchemaInputSchema() {
519
+ return z.object({
520
+ id: z.string(),
521
+ schema: z.string().nullish()
522
+ });
523
+ }
524
+ function SetOperationTemplateInputSchema() {
525
+ return z.object({
526
+ id: z.string(),
527
+ template: z.string().nullish()
528
+ });
529
+ }
530
+ function SetStateSchemaInputSchema() {
531
+ return z.object({
532
+ scope: z.string(),
533
+ schema: z.string()
534
+ });
535
+ }
536
+ function StateSchema() {
537
+ return z.object({
538
+ __typename: z.literal("State").optional(),
539
+ examples: z.array(CodeExampleSchema()),
540
+ initialValue: z.string(),
541
+ schema: z.string()
542
+ });
543
+ }
544
+ function ScopeStateSchema() {
545
+ return z.object({
546
+ global: StateSchema(),
547
+ local: StateSchema()
548
+ });
549
+ }
550
+ function UpdateChangeLogItemInputSchema() {
551
+ return z.object({
552
+ __typename: z.literal("UpdateChangeLogItemInput").optional(),
553
+ id: z.string(),
554
+ newContent: z.string()
555
+ });
556
+ }
557
+ function UpdateOperationExampleInputSchema() {
558
+ return z.object({
559
+ example: z.string(),
560
+ id: z.string()
561
+ });
562
+ }
563
+ function UpdateStateExampleInputSchema() {
564
+ return z.object({
565
+ scope: z.string(),
566
+ id: z.string(),
567
+ newExample: z.string()
568
+ });
569
+ }
570
+ //#endregion
571
+ //#region document-model/utils.ts
572
+ function generateId(method) {
573
+ if (method && method.toString() !== "UUIDv4") throw new Error(`Id generation method not supported: "${method.toString()}"`);
574
+ return globalThis.crypto.randomUUID();
575
+ }
576
+ /**
577
+ * Derives a deterministic operation ID from stable properties.
578
+ */
579
+ function deriveOperationId(documentId, scope, branch, actionId) {
580
+ return hashBrowser(`${documentId}:${scope}:${branch}:${actionId}`, "sha1", "hex").slice(0, 32);
581
+ }
582
+ //#endregion
583
+ //#region document-model/actions.ts
584
+ /**
585
+ * Cancels the last `count` operations.
586
+ *
587
+ * @param count - Number of operations to cancel
588
+ * @category Actions
589
+ */
590
+ const undo = (count = 1, scope = "global") => createAction("UNDO", { count }, void 0, UndoActionInputSchema, scope);
591
+ /**
592
+ * Cancels the last `count` {@link undo | UNDO} operations.
593
+ *
594
+ * @param count - Number of UNDO operations to cancel
595
+ * @category Actions
596
+ */
597
+ const redo = (count = 1, scope = "global") => createAction("REDO", { count }, void 0, RedoActionInputSchema, scope);
598
+ /**
599
+ * Joins multiple operations into a single {@link loadState | LOAD_STATE} operation.
600
+ *
601
+ * @remarks
602
+ * Useful to keep operations history smaller. Operations to prune are selected by index,
603
+ * similar to the {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | slice} method in Arrays.
604
+ *
605
+ * @param start - Index of the first operation to prune
606
+ * @param end - Index of the last operation to prune
607
+ * @category Actions
608
+ */
609
+ const prune = (start, end, scope = "global") => createAction("PRUNE", {
610
+ start,
611
+ end
612
+ }, void 0, PruneActionInputSchema, scope);
613
+ /**
614
+ * Replaces the state of the document.
615
+ *
616
+ * @remarks
617
+ * This action shouldn't be used directly. It is dispatched by the {@link prune} action.
618
+ *
619
+ * @param state - State to be set in the document.
620
+ * @param operations - Number of operations that were removed from the previous state.
621
+ * @category Actions
622
+ */
623
+ const loadState = (state, operations) => createAction("LOAD_STATE", {
624
+ state,
625
+ operations
626
+ }, void 0, LoadStateActionInputSchema);
627
+ const noop = (scope = "global") => createAction("NOOP", {}, void 0, void 0, scope);
628
+ /**
629
+ * Helper function to be used by action creators.
630
+ *
631
+ * @remarks
632
+ * Creates an action with the given type and input properties. The input
633
+ * properties default to an empty object.
634
+ *
635
+ * @typeParam A - Type of the action to be returned.
636
+ *
637
+ * @param type - The type of the action.
638
+ * @param input - The input properties of the action.
639
+ * @param attachments - The attachments included in the action.
640
+ * @param validator - The validator to use for the input properties.
641
+ * @param scope - The scope of the action, can either be 'global' or 'local'.
642
+ * @param skip - The number of operations to skip before this new action is applied.
643
+ *
644
+ * @throws Error if the type is empty or not a string.
645
+ *
646
+ * @returns The new action.
647
+ */
648
+ function createAction(type, input, attachments, validator, scope = "global") {
649
+ if (!type) throw new Error("Empty action type");
650
+ if (typeof type !== "string") throw new Error(`Invalid action type: ${JSON.stringify(type)}`);
651
+ const action = {
652
+ id: generateId(),
653
+ timestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),
654
+ type,
655
+ input,
656
+ scope
657
+ };
658
+ if (attachments) action.attachments = attachments;
659
+ try {
660
+ validator?.().parse(action.input);
661
+ } catch (error) {
662
+ if (error instanceof ZodError) throw new InvalidActionInputZodError(error.issues);
663
+ throw new InvalidActionInputError(error);
664
+ }
665
+ return action;
666
+ }
667
+ /**
668
+ * This function should be used instead of { ...action } to ensure
669
+ * that extra properties are not included in the action.
670
+ */
671
+ const actionFromAction = (action) => {
672
+ return {
673
+ id: action.id,
674
+ timestampUtcMs: action.timestampUtcMs,
675
+ type: action.type,
676
+ input: action.input,
677
+ scope: action.scope,
678
+ context: action.context,
679
+ attachments: action.attachments
680
+ };
681
+ };
682
+ const operationFromAction = (action, index, skip, context) => {
683
+ return {
684
+ ...action,
685
+ action,
686
+ id: deriveOperationId(context.documentId, context.scope, context.branch, action.id),
687
+ timestampUtcMs: action.timestampUtcMs,
688
+ hash: "",
689
+ error: void 0,
690
+ index,
691
+ skip
692
+ };
693
+ };
694
+ const operationFromOperation = (operation, index, skip, context) => {
695
+ const id = deriveOperationId(context.documentId, context.scope, context.branch, operation.action.id);
696
+ return {
697
+ ...operation,
698
+ hash: "",
699
+ error: void 0,
700
+ index,
701
+ skip,
702
+ id
703
+ };
704
+ };
705
+ const operationWithContext = (operation, context) => {
706
+ if (!operation.action) throw new Error("Operation has no action");
707
+ return {
708
+ ...operation,
709
+ action: {
710
+ ...operation.action,
711
+ context
712
+ }
713
+ };
714
+ };
715
+ const actionContext = () => ({});
716
+ const actionSigner = (user, app, signatures = []) => ({
717
+ user,
718
+ app,
719
+ signatures
720
+ });
721
+ async function buildOperationSignature(context, signMethod) {
722
+ const params = buildOperationSignatureParams(context);
723
+ const signature = await signMethod(buildOperationSignatureMessage(params));
724
+ return [...params, `0x${ab2hex(signature)}`];
725
+ }
726
+ async function buildSignedAction(action, reducer, document, signer, signHandler) {
727
+ const scopeOperations = reducer(document, action, void 0, { reuseOperationResultingState: true }).operations[action.scope];
728
+ if (!scopeOperations) throw new Error(`No operations found for scope: ${action.scope}`);
729
+ const operation = scopeOperations.at(-1);
730
+ if (!operation) throw new Error("Action was not applied");
731
+ const previousStateHash = scopeOperations.at(-2)?.hash ?? "";
732
+ const signature = await buildOperationSignature({
733
+ documentId: document.header.id,
734
+ signer,
735
+ action,
736
+ previousStateHash
737
+ }, signHandler);
738
+ return operationWithContext(operation, { signer: actionSigner(signer.user, signer.app, [...signer.signatures, signature]) });
739
+ }
740
+ async function verifyOperationSignature(signature, signer, verifyHandler) {
741
+ const publicKey = signer.app.key;
742
+ const params = signature.slice(0, 4);
743
+ return verifyHandler(publicKey, hex2ab(signature[4]), buildOperationSignatureMessage(params));
744
+ }
745
+ /**
746
+ * Changes the name of the document.
747
+ *
748
+ * @param name - The name to be set in the document.
749
+ * @category Actions
750
+ */
751
+ const setName = (name) => createAction("SET_NAME", typeof name === "string" ? { name } : name, void 0, SetNameActionInputSchema, "global");
752
+ const setModelName = (input) => createAction("SET_MODEL_NAME", { ...input }, void 0, SetModelNameInputSchema, "global");
753
+ const setModelId = (input) => createAction("SET_MODEL_ID", { ...input }, void 0, SetModelIdInputSchema, "global");
754
+ const setModelExtension = (input) => createAction("SET_MODEL_EXTENSION", { ...input }, void 0, SetModelExtensionInputSchema, "global");
755
+ const setModelDescription = (input) => createAction("SET_MODEL_DESCRIPTION", { ...input }, void 0, SetModelDescriptionInputSchema, "global");
756
+ const setAuthorName = (input) => createAction("SET_AUTHOR_NAME", { ...input }, void 0, SetAuthorNameInputSchema, "global");
757
+ const setAuthorWebsite = (input) => createAction("SET_AUTHOR_WEBSITE", { ...input }, void 0, SetAuthorWebsiteInputSchema, "global");
758
+ const addModule = (input) => createAction("ADD_MODULE", { ...input }, void 0, AddModuleInputSchema, "global");
759
+ const setModuleName = (input) => createAction("SET_MODULE_NAME", { ...input }, void 0, SetModuleNameInputSchema, "global");
760
+ const setModuleDescription = (input) => createAction("SET_MODULE_DESCRIPTION", { ...input }, void 0, SetModuleDescriptionInputSchema, "global");
761
+ const deleteModule = (input) => createAction("DELETE_MODULE", { ...input }, void 0, DeleteModuleInputSchema, "global");
762
+ const reorderModules = (input) => createAction("REORDER_MODULES", { ...input }, void 0, ReorderModulesInputSchema, "global");
763
+ const addOperation = (input) => createAction("ADD_OPERATION", { ...input }, void 0, AddOperationInputSchema, "global");
764
+ const setOperationName = (input) => createAction("SET_OPERATION_NAME", { ...input }, void 0, SetOperationNameInputSchema, "global");
765
+ const setOperationScope = (input) => createAction("SET_OPERATION_SCOPE", { ...input }, void 0, SetOperationScopeInputSchema, "global");
766
+ const setOperationSchema = (input) => createAction("SET_OPERATION_SCHEMA", { ...input }, void 0, SetOperationSchemaInputSchema, "global");
767
+ const setOperationDescription = (input) => createAction("SET_OPERATION_DESCRIPTION", { ...input }, void 0, SetOperationDescriptionInputSchema, "global");
768
+ const setOperationTemplate = (input) => createAction("SET_OPERATION_TEMPLATE", { ...input }, void 0, SetOperationTemplateInputSchema, "global");
769
+ const setOperationReducer = (input) => createAction("SET_OPERATION_REDUCER", { ...input }, void 0, SetOperationReducerInputSchema, "global");
770
+ const moveOperation = (input) => createAction("MOVE_OPERATION", { ...input }, void 0, MoveOperationInputSchema, "global");
771
+ const deleteOperation = (input) => createAction("DELETE_OPERATION", { ...input }, void 0, DeleteOperationInputSchema, "global");
772
+ const reorderModuleOperations = (input) => createAction("REORDER_MODULE_OPERATIONS", { ...input }, void 0, ReorderModuleOperationsInputSchema, "global");
773
+ const addOperationError = (input) => createAction("ADD_OPERATION_ERROR", { ...input }, void 0, AddOperationErrorInputSchema, "global");
774
+ const setOperationErrorCode = (input) => createAction("SET_OPERATION_ERROR_CODE", { ...input }, void 0, SetOperationErrorCodeInputSchema, "global");
775
+ const setOperationErrorName = (input) => createAction("SET_OPERATION_ERROR_NAME", { ...input }, void 0, SetOperationErrorNameInputSchema, "global");
776
+ const setOperationErrorDescription = (input) => createAction("SET_OPERATION_ERROR_DESCRIPTION", { ...input }, void 0, SetOperationErrorDescriptionInputSchema, "global");
777
+ const setOperationErrorTemplate = (input) => createAction("SET_OPERATION_ERROR_TEMPLATE", { ...input }, void 0, SetOperationErrorTemplateInputSchema, "global");
778
+ const deleteOperationError = (input) => createAction("DELETE_OPERATION_ERROR", { ...input }, void 0, DeleteOperationErrorInputSchema, "global");
779
+ const reorderOperationErrors = (input) => createAction("REORDER_OPERATION_ERRORS", { ...input }, void 0, ReorderOperationErrorsInputSchema, "global");
780
+ const addOperationExample = (input) => createAction("ADD_OPERATION_EXAMPLE", { ...input }, void 0, AddOperationExampleInputSchema, "global");
781
+ const updateOperationExample = (input) => createAction("UPDATE_OPERATION_EXAMPLE", { ...input }, void 0, UpdateOperationExampleInputSchema, "global");
782
+ const deleteOperationExample = (input) => createAction("DELETE_OPERATION_EXAMPLE", { ...input }, void 0, DeleteOperationExampleInputSchema, "global");
783
+ const reorderOperationExamples = (input) => createAction("REORDER_OPERATION_EXAMPLES", { ...input }, void 0, ReorderOperationExamplesInputSchema, "global");
784
+ const operationExampleCreators = {
785
+ addOperationExample,
786
+ updateOperationExample,
787
+ deleteOperationExample,
788
+ reorderOperationExamples
789
+ };
790
+ const setStateSchema = (input) => createAction("SET_STATE_SCHEMA", { ...input }, void 0, SetStateSchemaInputSchema, "global");
791
+ const setInitialState = (input) => createAction("SET_INITIAL_STATE", { ...input }, void 0, SetInitialStateInputSchema, "global");
792
+ const addStateExample = (input) => createAction("ADD_STATE_EXAMPLE", { ...input }, void 0, AddStateExampleInputSchema, "global");
793
+ const updateStateExample = (input) => createAction("UPDATE_STATE_EXAMPLE", { ...input }, void 0, UpdateStateExampleInputSchema, "global");
794
+ const deleteStateExample = (input) => createAction("DELETE_STATE_EXAMPLE", { ...input }, void 0, DeleteStateExampleInputSchema, "global");
795
+ const reorderStateExamples = (input) => createAction("REORDER_STATE_EXAMPLES", { ...input }, void 0, ReorderStateExamplesInputSchema, "global");
796
+ const addChangeLogItem = (input) => createAction("ADD_CHANGE_LOG_ITEM", { ...input }, void 0, AddChangeLogItemInputSchema, "global");
797
+ const updateChangeLogItem = (input) => createAction("UPDATE_CHANGE_LOG_ITEM", { ...input }, void 0, UpdateChangeLogItemInputSchema, "global");
798
+ const deleteChangeLogItem = (input) => createAction("DELETE_CHANGE_LOG_ITEM", { ...input }, void 0, DeleteChangeLogItemInputSchema, "global");
799
+ const reorderChangeLogItems = (input) => createAction("REORDER_CHANGE_LOG_ITEMS", { ...input }, void 0, ReorderChangeLogItemsInputSchema, "global");
800
+ const releaseNewVersion = () => createAction("RELEASE_NEW_VERSION", {}, void 0, void 0, "global");
801
+ const baseActions = {
802
+ setName,
803
+ undo,
804
+ redo,
805
+ prune,
806
+ loadState,
807
+ noop
808
+ };
809
+ const documentModelActions = {
810
+ setModelName,
811
+ setModelId,
812
+ setModelExtension,
813
+ setModelDescription,
814
+ setAuthorName,
815
+ setAuthorWebsite,
816
+ addModule,
817
+ setModuleName,
818
+ setModuleDescription,
819
+ deleteModule,
820
+ reorderModules,
821
+ addOperation,
822
+ setOperationName,
823
+ setOperationScope,
824
+ setOperationSchema,
825
+ setOperationDescription,
826
+ setOperationTemplate,
827
+ setOperationReducer,
828
+ moveOperation,
829
+ deleteOperation,
830
+ reorderModuleOperations,
831
+ addOperationError,
832
+ setOperationErrorCode,
833
+ setOperationErrorName,
834
+ setOperationErrorDescription,
835
+ setOperationErrorTemplate,
836
+ deleteOperationError,
837
+ reorderOperationErrors,
838
+ setStateSchema,
839
+ setInitialState,
840
+ addStateExample,
841
+ updateStateExample,
842
+ deleteStateExample,
843
+ reorderStateExamples,
844
+ addChangeLogItem,
845
+ updateChangeLogItem,
846
+ deleteChangeLogItem,
847
+ reorderChangeLogItems,
848
+ releaseNewVersion
849
+ };
850
+ const actions = {
851
+ ...baseActions,
852
+ ...documentModelActions
853
+ };
854
+ //#endregion
855
+ //#region document-model/constants.ts
856
+ const documentModelFileExtension = "phdm";
857
+ const documentModelInitialLocalState = {};
858
+ const documentModelInitialGlobalState = {
859
+ id: "",
860
+ name: "",
861
+ extension: "",
862
+ description: "",
863
+ author: {
864
+ name: "",
865
+ website: ""
866
+ },
867
+ specifications: [{
868
+ version: 1,
869
+ changeLog: [],
870
+ state: {
871
+ global: {
872
+ schema: "",
873
+ initialValue: "",
874
+ examples: []
875
+ },
876
+ local: {
877
+ schema: "",
878
+ initialValue: "",
879
+ examples: []
880
+ }
881
+ },
882
+ modules: []
883
+ }]
884
+ };
885
+ const documentModelGlobalState = {
886
+ id: "powerhouse/document-model",
887
+ name: "DocumentModel",
888
+ extension: "phdm",
889
+ description: "The Powerhouse Document Model describes the state and operations of a document type.",
890
+ author: {
891
+ name: "Powerhouse",
892
+ website: "https://www.powerhouse.inc/"
893
+ },
894
+ specifications: [{
895
+ version: 1,
896
+ changeLog: [],
897
+ state: {
898
+ global: {
899
+ schema: "type CodeExample {\n id: ID!\n value: String!\n}\n\ntype OperationError {\n id: ID!\n code: String\n name: String\n description: String\n template: String\n}\n\ntype Operation {\n id: ID!\n name: String\n schema: String\n description: String\n template: String\n errors: [OperationError!]!\n examples: [CodeExample!]!\n reducer: String\n scope: String\n}\n\ntype Module {\n id: ID!\n name: String!\n description: String\n operations: [Operation!]!\n}\n\ntype State {\n schema: String!\n initialValue: String!\n examples: [CodeExample!]!\n}\n\ntype ScopeState {\n global: State!\n local: State!\n}\n\ntype Author {\n name: String!\n website: String\n}\n\ntype DocumentSpecification {\n version: Int!\n state: ScopeState!\n modules: [Module!]!\n changeLog: [String!]!\n}\n\ntype DocumentModelGlobalState {\n name: String!\n id: String!\n extension: String!\n description: String!\n author: Author!\n specifications: [DocumentSpecification!]!\n}",
900
+ initialValue: "{\n \"id\": \"\",\n \"name\": \"\",\n \"extension\": \"\",\n \"description\": \"\",\n \"author\": {\n \"name\": \"\",\n \"website\": \"\"\n },\n \"specifications\": [\n {\n \"version\": 1,\n \"changeLog\": [],\n \"state\": {\n \"global\": {\n \"schema\": \"\",\n \"initialValue\": \"\",\n \"examples\": []\n },\n \"local\": {\n \"schema\": \"\",\n \"initialValue\": \"\",\n \"examples\": []\n }\n },\n \"modules\": []\n }\n ]\n}",
901
+ examples: []
902
+ },
903
+ local: {
904
+ schema: "",
905
+ initialValue: "",
906
+ examples: []
907
+ }
908
+ },
909
+ modules: [
910
+ {
911
+ name: "header",
912
+ operations: [
913
+ {
914
+ name: "SET_MODEL_NAME",
915
+ id: "",
916
+ description: "Sets the name of the document model",
917
+ schema: "input SetModelNameInput {\n name: String!\n}",
918
+ template: "",
919
+ reducer: "",
920
+ examples: [],
921
+ errors: [],
922
+ scope: "global"
923
+ },
924
+ {
925
+ name: "SET_MODEL_ID",
926
+ id: "",
927
+ description: "Sets the unique identifier for the document model",
928
+ schema: "input SetModelIdInput {\n id: String!\n}",
929
+ template: "",
930
+ reducer: "",
931
+ examples: [],
932
+ errors: [],
933
+ scope: "global"
934
+ },
935
+ {
936
+ name: "SET_MODEL_EXTENSION",
937
+ id: "",
938
+ description: "Sets the file extension associated with this document model",
939
+ schema: "input SetModelExtensionInput {\n extension: String!\n}",
940
+ template: "",
941
+ reducer: "",
942
+ examples: [],
943
+ errors: [],
944
+ scope: "global"
945
+ },
946
+ {
947
+ name: "SET_MODEL_DESCRIPTION",
948
+ id: "",
949
+ description: "Sets the description text for the document model",
950
+ schema: "input SetModelDescriptionInput {\n description: String!\n}",
951
+ template: "",
952
+ reducer: "",
953
+ examples: [],
954
+ errors: [],
955
+ scope: "global"
956
+ },
957
+ {
958
+ name: "SET_AUTHOR_NAME",
959
+ id: "",
960
+ description: "Sets the name of the document model author",
961
+ schema: "input SetAuthorNameInput {\n authorName: String!\n}",
962
+ template: "",
963
+ reducer: "",
964
+ examples: [],
965
+ errors: [],
966
+ scope: "global"
967
+ },
968
+ {
969
+ name: "SET_AUTHOR_WEBSITE",
970
+ id: "",
971
+ description: "Sets the website URL of the document model author",
972
+ schema: "input SetAuthorWebsiteInput {\n authorWebsite: String!\n}",
973
+ template: "",
974
+ reducer: "",
975
+ examples: [],
976
+ errors: [],
977
+ scope: "global"
978
+ }
979
+ ],
980
+ id: "",
981
+ description: ""
982
+ },
983
+ {
984
+ name: "versioning",
985
+ operations: [
986
+ {
987
+ name: "ADD_CHANGE_LOG_ITEM",
988
+ id: "",
989
+ description: "Adds a new item to the document model changelog",
990
+ schema: "input AddChangeLogItemInput {\n id: ID!\n insertBefore: ID\n content: String!\n}",
991
+ template: "",
992
+ reducer: "",
993
+ examples: [],
994
+ errors: [],
995
+ scope: "global"
996
+ },
997
+ {
998
+ name: "UPDATE_CHANGE_LOG_ITEM",
999
+ id: "",
1000
+ description: "Updates an existing changelog item",
1001
+ schema: "input UpdateChangeLogItemInput {\n id: ID!\n newContent: String!\n}",
1002
+ template: "",
1003
+ reducer: "",
1004
+ examples: [],
1005
+ errors: [],
1006
+ scope: "global"
1007
+ },
1008
+ {
1009
+ name: "DELETE_CHANGE_LOG_ITEM",
1010
+ id: "",
1011
+ description: "Removes an item from the document model changelog",
1012
+ schema: "input DeleteChangeLogItemInput {\n id: ID!\n}",
1013
+ template: "",
1014
+ reducer: "",
1015
+ examples: [],
1016
+ errors: [],
1017
+ scope: "global"
1018
+ },
1019
+ {
1020
+ name: "REORDER_CHANGE_LOG_ITEMS",
1021
+ id: "",
1022
+ description: "Changes the order of changelog items",
1023
+ schema: "input ReorderChangeLogItemsInput {\n order: [ID!]!\n}",
1024
+ template: "",
1025
+ reducer: "",
1026
+ examples: [],
1027
+ errors: [],
1028
+ scope: "global"
1029
+ },
1030
+ {
1031
+ name: "RELEASE_NEW_VERSION",
1032
+ schema: null,
1033
+ id: "",
1034
+ description: "Creates a new version of the document model specification",
1035
+ template: "",
1036
+ reducer: "",
1037
+ examples: [],
1038
+ errors: [],
1039
+ scope: "global"
1040
+ }
1041
+ ],
1042
+ id: "",
1043
+ description: ""
1044
+ },
1045
+ {
1046
+ name: "module",
1047
+ operations: [
1048
+ {
1049
+ name: "ADD_MODULE",
1050
+ id: "",
1051
+ description: "Adds a new module to the document model specification",
1052
+ schema: "input AddModuleInput {\n id: ID!\n name: String!\n description: String\n}",
1053
+ template: "",
1054
+ reducer: "",
1055
+ examples: [],
1056
+ errors: [],
1057
+ scope: "global"
1058
+ },
1059
+ {
1060
+ name: "SET_MODULE_NAME",
1061
+ id: "",
1062
+ description: "Sets the name of an existing module",
1063
+ schema: "input SetModuleNameInput {\n id: ID!\n name: String\n}",
1064
+ template: "",
1065
+ reducer: "",
1066
+ examples: [],
1067
+ errors: [],
1068
+ scope: "global"
1069
+ },
1070
+ {
1071
+ name: "SET_MODULE_DESCRIPTION",
1072
+ id: "",
1073
+ description: "Sets the description of an existing module",
1074
+ schema: "input SetModuleDescriptionInput {\n id: ID!\n description: String\n}",
1075
+ template: "",
1076
+ reducer: "",
1077
+ examples: [],
1078
+ errors: [],
1079
+ scope: "global"
1080
+ },
1081
+ {
1082
+ name: "DELETE_MODULE",
1083
+ id: "",
1084
+ description: "Removes a module from the document model specification",
1085
+ schema: "input DeleteModuleInput {\n id: ID!\n}",
1086
+ template: "",
1087
+ reducer: "",
1088
+ examples: [],
1089
+ errors: [],
1090
+ scope: "global"
1091
+ },
1092
+ {
1093
+ name: "REORDER_MODULES",
1094
+ id: "",
1095
+ description: "Changes the order of modules in the document model specification",
1096
+ schema: "input ReorderModulesInput {\n order: [ID!]!\n}",
1097
+ template: "",
1098
+ reducer: "",
1099
+ examples: [],
1100
+ errors: [],
1101
+ scope: "global"
1102
+ }
1103
+ ],
1104
+ id: "",
1105
+ description: ""
1106
+ },
1107
+ {
1108
+ name: "operation-error",
1109
+ operations: [
1110
+ {
1111
+ name: "ADD_OPERATION_ERROR",
1112
+ id: "",
1113
+ description: "Adds a new error definition to an operation",
1114
+ schema: "input AddOperationErrorInput {\n operationId: ID!\n id: ID!\n errorCode: String\n errorName: String\n errorDescription: String\n errorTemplate: String\n}",
1115
+ template: "",
1116
+ reducer: "",
1117
+ examples: [],
1118
+ errors: [],
1119
+ scope: "global"
1120
+ },
1121
+ {
1122
+ name: "SET_OPERATION_ERROR_CODE",
1123
+ id: "",
1124
+ description: "Sets the error code for an operation error",
1125
+ schema: "input SetOperationErrorCodeInput {\n id: ID!\n errorCode: String\n}",
1126
+ template: "",
1127
+ reducer: "",
1128
+ examples: [],
1129
+ errors: [],
1130
+ scope: "global"
1131
+ },
1132
+ {
1133
+ name: "SET_OPERATION_ERROR_NAME",
1134
+ id: "",
1135
+ description: "Sets the name of an operation error",
1136
+ schema: "input SetOperationErrorNameInput {\n id: ID!\n errorName: String\n}",
1137
+ template: "",
1138
+ reducer: "",
1139
+ examples: [],
1140
+ errors: [],
1141
+ scope: "global"
1142
+ },
1143
+ {
1144
+ name: "SET_OPERATION_ERROR_DESCRIPTION",
1145
+ id: "",
1146
+ description: "Sets the description of an operation error",
1147
+ schema: "input SetOperationErrorDescriptionInput {\n id: ID!\n errorDescription: String\n}",
1148
+ template: "",
1149
+ reducer: "",
1150
+ examples: [],
1151
+ errors: [],
1152
+ scope: "global"
1153
+ },
1154
+ {
1155
+ name: "SET_OPERATION_ERROR_TEMPLATE",
1156
+ id: "",
1157
+ description: "Sets the template for an operation error",
1158
+ schema: "input SetOperationErrorTemplateInput {\n id: ID!\n errorTemplate: String\n}",
1159
+ template: "",
1160
+ reducer: "",
1161
+ examples: [],
1162
+ errors: [],
1163
+ scope: "global"
1164
+ },
1165
+ {
1166
+ name: "DELETE_OPERATION_ERROR",
1167
+ id: "",
1168
+ description: "Removes an error definition from an operation",
1169
+ schema: "input DeleteOperationErrorInput {\n id: ID!\n}",
1170
+ template: "",
1171
+ reducer: "",
1172
+ examples: [],
1173
+ errors: [],
1174
+ scope: "global"
1175
+ },
1176
+ {
1177
+ name: "REORDER_OPERATION_ERRORS",
1178
+ id: "",
1179
+ description: "Changes the order of error definitions for an operation",
1180
+ schema: "input ReorderOperationErrorsInput {\n operationId: ID!\n order: [ID!]!\n}",
1181
+ template: "",
1182
+ reducer: "",
1183
+ examples: [],
1184
+ errors: [],
1185
+ scope: "global"
1186
+ }
1187
+ ],
1188
+ id: "",
1189
+ description: ""
1190
+ },
1191
+ {
1192
+ name: "operation-example",
1193
+ operations: [
1194
+ {
1195
+ name: "ADD_OPERATION_EXAMPLE",
1196
+ id: "",
1197
+ description: "Adds a new code example to an operation",
1198
+ schema: "input AddOperationExampleInput {\n operationId: ID!\n id: ID!\n example: String!\n}",
1199
+ template: "",
1200
+ reducer: "",
1201
+ examples: [],
1202
+ errors: [],
1203
+ scope: "global"
1204
+ },
1205
+ {
1206
+ name: "UPDATE_OPERATION_EXAMPLE",
1207
+ id: "",
1208
+ description: "Updates an existing code example for an operation",
1209
+ schema: "input UpdateOperationExampleInput {\n id: ID!\n example: String!\n}",
1210
+ template: "",
1211
+ reducer: "",
1212
+ examples: [],
1213
+ errors: [],
1214
+ scope: "global"
1215
+ },
1216
+ {
1217
+ name: "DELETE_OPERATION_EXAMPLE",
1218
+ id: "",
1219
+ description: "Removes a code example from an operation",
1220
+ schema: "input DeleteOperationExampleInput {\n id: ID!\n}",
1221
+ template: "",
1222
+ reducer: "",
1223
+ examples: [],
1224
+ errors: [],
1225
+ scope: "global"
1226
+ },
1227
+ {
1228
+ name: "REORDER_OPERATION_EXAMPLES",
1229
+ id: "",
1230
+ description: "Changes the order of code examples for an operation",
1231
+ schema: "input ReorderOperationExamplesInput {\n operationId: ID!\n order: [ID!]!\n}",
1232
+ template: "",
1233
+ reducer: "",
1234
+ examples: [],
1235
+ errors: [],
1236
+ scope: "global"
1237
+ }
1238
+ ],
1239
+ id: "",
1240
+ description: ""
1241
+ },
1242
+ {
1243
+ name: "operation",
1244
+ operations: [
1245
+ {
1246
+ name: "ADD_OPERATION",
1247
+ id: "",
1248
+ description: "Adds a new operation to a module",
1249
+ schema: "input AddOperationInput {\n moduleId: ID!\n id: ID!\n name: String!\n schema: String\n description: String\n template: String\n reducer: String\n scope: String\n}",
1250
+ template: "",
1251
+ reducer: "",
1252
+ examples: [],
1253
+ errors: [],
1254
+ scope: "global"
1255
+ },
1256
+ {
1257
+ name: "SET_OPERATION_NAME",
1258
+ id: "",
1259
+ description: "Sets the name of an operation",
1260
+ schema: "input SetOperationNameInput {\n id: ID!\n name: String\n}",
1261
+ template: "",
1262
+ reducer: "",
1263
+ examples: [],
1264
+ errors: [],
1265
+ scope: "global"
1266
+ },
1267
+ {
1268
+ name: "SET_OPERATION_SCHEMA",
1269
+ id: "",
1270
+ description: "Sets the GraphQL schema definition for an operation's input",
1271
+ schema: "input SetOperationSchemaInput {\n id: ID!\n schema: String\n}",
1272
+ template: "",
1273
+ reducer: "",
1274
+ examples: [],
1275
+ errors: [],
1276
+ scope: "global"
1277
+ },
1278
+ {
1279
+ name: "SET_OPERATION_DESCRIPTION",
1280
+ id: "",
1281
+ description: "Sets the description of an operation",
1282
+ schema: "input SetOperationDescriptionInput {\n id: ID!\n description: String\n}",
1283
+ template: "",
1284
+ reducer: "",
1285
+ examples: [],
1286
+ errors: [],
1287
+ scope: "global"
1288
+ },
1289
+ {
1290
+ name: "SET_OPERATION_TEMPLATE",
1291
+ id: "",
1292
+ description: "Sets the template code for an operation",
1293
+ schema: "input SetOperationTemplateInput {\n id: ID!\n template: String\n}",
1294
+ template: "",
1295
+ reducer: "",
1296
+ examples: [],
1297
+ errors: [],
1298
+ scope: "global"
1299
+ },
1300
+ {
1301
+ name: "SET_OPERATION_REDUCER",
1302
+ id: "",
1303
+ description: "Sets the reducer function code for an operation",
1304
+ schema: "input SetOperationReducerInput {\n id: ID!\n reducer: String\n}",
1305
+ template: "",
1306
+ reducer: "",
1307
+ examples: [],
1308
+ errors: [],
1309
+ scope: "global"
1310
+ },
1311
+ {
1312
+ name: "SET_OPERATION_SCOPE",
1313
+ id: "",
1314
+ description: "Sets the scope of an operation (global or local)",
1315
+ schema: "input SetOperationScopeInput {\n id: ID!\n scope: String\n}",
1316
+ template: "",
1317
+ reducer: "",
1318
+ examples: [],
1319
+ errors: [],
1320
+ scope: "global"
1321
+ },
1322
+ {
1323
+ name: "MOVE_OPERATION",
1324
+ id: "",
1325
+ description: "Moves an operation from one module to another",
1326
+ schema: "input MoveOperationInput {\n operationId: ID!\n newModuleId: ID!\n}",
1327
+ template: "",
1328
+ reducer: "",
1329
+ examples: [],
1330
+ errors: [],
1331
+ scope: "global"
1332
+ },
1333
+ {
1334
+ name: "DELETE_OPERATION",
1335
+ id: "",
1336
+ description: "Removes an operation from a module",
1337
+ schema: "input DeleteOperationInput {\n id: ID!\n}",
1338
+ template: "",
1339
+ reducer: "",
1340
+ examples: [],
1341
+ errors: [],
1342
+ scope: "global"
1343
+ },
1344
+ {
1345
+ name: "REORDER_MODULE_OPERATIONS",
1346
+ id: "",
1347
+ description: "Changes the order of operations within a module",
1348
+ schema: "input ReorderModuleOperationsInput {\n moduleId: ID!\n order: [ID!]!\n}",
1349
+ template: "",
1350
+ reducer: "",
1351
+ examples: [],
1352
+ errors: [],
1353
+ scope: "global"
1354
+ }
1355
+ ],
1356
+ id: "",
1357
+ description: ""
1358
+ },
1359
+ {
1360
+ name: "state",
1361
+ operations: [
1362
+ {
1363
+ name: "SET_STATE_SCHEMA",
1364
+ id: "",
1365
+ description: "Sets the GraphQL schema definition for document state",
1366
+ schema: "input SetStateSchemaInput {\n scope: String!\n schema: String!\n}",
1367
+ template: "",
1368
+ reducer: "",
1369
+ examples: [],
1370
+ errors: [],
1371
+ scope: "global"
1372
+ },
1373
+ {
1374
+ name: "SET_INITIAL_STATE",
1375
+ id: "",
1376
+ description: "Sets the initial state value for a document scope",
1377
+ schema: "input SetInitialStateInput {\n scope: String!\n initialValue: String!\n}",
1378
+ template: "",
1379
+ reducer: "",
1380
+ examples: [],
1381
+ errors: [],
1382
+ scope: "global"
1383
+ },
1384
+ {
1385
+ name: "ADD_STATE_EXAMPLE",
1386
+ id: "",
1387
+ description: "Adds a new state example to a document scope",
1388
+ schema: "input AddStateExampleInput {\n scope: String!\n id: ID!\n insertBefore: ID\n example: String!\n}",
1389
+ template: "",
1390
+ reducer: "",
1391
+ examples: [],
1392
+ errors: [],
1393
+ scope: "global"
1394
+ },
1395
+ {
1396
+ name: "UPDATE_STATE_EXAMPLE",
1397
+ id: "",
1398
+ description: "Updates an existing state example for a document scope",
1399
+ schema: "input UpdateStateExampleInput {\n scope: String!\n id: ID!\n newExample: String!\n}",
1400
+ template: "",
1401
+ reducer: "",
1402
+ examples: [],
1403
+ errors: [],
1404
+ scope: "global"
1405
+ },
1406
+ {
1407
+ name: "DELETE_STATE_EXAMPLE",
1408
+ id: "",
1409
+ description: "Removes a state example from a document scope",
1410
+ schema: "input DeleteStateExampleInput {\n scope: String!\n id: ID!\n}",
1411
+ template: "",
1412
+ reducer: "",
1413
+ examples: [],
1414
+ errors: [],
1415
+ scope: "global"
1416
+ },
1417
+ {
1418
+ name: "REORDER_STATE_EXAMPLES",
1419
+ id: "",
1420
+ description: "Changes the order of state examples for a document scope",
1421
+ schema: "input ReorderStateExamplesInput {\n scope: String!\n order: [ID!]!\n}",
1422
+ template: "",
1423
+ reducer: "",
1424
+ examples: [],
1425
+ errors: [],
1426
+ scope: "global"
1427
+ }
1428
+ ],
1429
+ id: "",
1430
+ description: ""
1431
+ }
1432
+ ]
1433
+ }]
1434
+ };
1435
+ const HASH_ALGORITHM_SHA1 = "sha1";
1436
+ const HASH_ALGORITHM_SHA256 = "sha256";
1437
+ const HASH_ALGORITHM_SHA512 = "sha512";
1438
+ const HASH_ENCODING_BASE64 = "base64";
1439
+ const HASH_ENCODING_HEX = "hex";
1440
+ //#endregion
1441
+ //#region document-model/document-type.ts
1442
+ const documentModelDocumentType = "powerhouse/document-model";
1443
+ //#endregion
1444
+ //#region document-model/document-schema.ts
1445
+ const BaseDocumentHeaderSchema = z.object({
1446
+ id: z.string(),
1447
+ name: z.string(),
1448
+ createdAtUtcIso: z.string(),
1449
+ lastModifiedAtUtcIso: z.string(),
1450
+ documentType: z.string()
1451
+ });
1452
+ const BaseDocumentStateSchema = z.object({ global: z.unknown() });
1453
+ /** Schema for validating the header object of a DocumentModel document */
1454
+ const DocumentModelHeaderSchema = BaseDocumentHeaderSchema.extend({ documentType: z.literal(documentModelDocumentType) });
1455
+ /** Schema for validating the state object of a DocumentModel document */
1456
+ const DocumentModelPHStateSchema = BaseDocumentStateSchema.extend({ global: DocumentModelGlobalStateSchema() });
1457
+ const DocumentModelSchema = z.object({
1458
+ header: DocumentModelHeaderSchema,
1459
+ state: DocumentModelPHStateSchema,
1460
+ initialState: DocumentModelPHStateSchema
1461
+ });
1462
+ /** Simple helper function to check if a state object is a DocumentModel document state object */
1463
+ function isDocumentModelState(state) {
1464
+ return DocumentModelPHStateSchema.safeParse(state).success;
1465
+ }
1466
+ /** Simple helper function to assert that a document state object is a DocumentModel document state object */
1467
+ function assertIsDocumentModelState(state) {
1468
+ DocumentModelPHStateSchema.parse(state);
1469
+ }
1470
+ /** Simple helper function to check if a document is a DocumentModel document */
1471
+ function isDocumentModelDocument(document) {
1472
+ return DocumentModelSchema.safeParse(document).success;
1473
+ }
1474
+ /** Simple helper function to assert that a document is a DocumentModel document */
1475
+ function assertIsDocumentModelDocument(document) {
1476
+ DocumentModelSchema.parse(document);
1477
+ }
1478
+ //#endregion
1479
+ //#region document-model/header.ts
1480
+ /**
1481
+ * Generates a deterministic payload from signing parameters
1482
+ */
1483
+ const generateStablePayload = (parameters) => `${parameters.documentType}:${parameters.createdAtUtcIso}:${parameters.nonce}`;
1484
+ /**
1485
+ * Creates a verification-only signer from a public key.
1486
+ * This signer can only verify signatures, not sign data.
1487
+ *
1488
+ * @param pubKey - The public key to use for verification.
1489
+ * @returns An ISigner that can only verify signatures.
1490
+ */
1491
+ async function createVerificationSigner(pubKey) {
1492
+ const cryptoKey = await crypto.subtle.importKey("jwk", pubKey, {
1493
+ name: "ECDSA",
1494
+ namedCurve: "P-256"
1495
+ }, true, ["verify"]);
1496
+ return {
1497
+ publicKey: cryptoKey,
1498
+ async sign(_data) {
1499
+ throw new Error("verification-only signer cannot sign data");
1500
+ },
1501
+ async signAction(_action, _abortSignal) {
1502
+ throw new Error("verification-only signer cannot sign actions");
1503
+ },
1504
+ async verify(data, signature) {
1505
+ let isValid;
1506
+ try {
1507
+ isValid = await crypto.subtle.verify({
1508
+ name: "ECDSA",
1509
+ hash: "SHA-256"
1510
+ }, cryptoKey, new Uint8Array(signature), new Uint8Array(data));
1511
+ } catch {
1512
+ throw new Error("invalid signature");
1513
+ }
1514
+ if (!isValid) throw new Error("invalid signature");
1515
+ }
1516
+ };
1517
+ }
1518
+ /**
1519
+ * Creates a verification-only signer from a header.
1520
+ *
1521
+ * @param header - The header to create a signer from.
1522
+ * @returns A signer that can verify the header's signature.
1523
+ */
1524
+ const createSignerFromHeader = async (header) => {
1525
+ return createVerificationSigner(header.sig.publicKey);
1526
+ };
1527
+ /**
1528
+ * Signs a header. Generally, this is not called directly, but rather through
1529
+ * {@link createSignedHeader}.
1530
+ *
1531
+ * @param parameters - The parameters used to sign the header.
1532
+ * @param signer - The signer of the document.
1533
+ *
1534
+ * @returns The signature of the header.
1535
+ */
1536
+ const sign = async (parameters, signer) => {
1537
+ const payload = generateStablePayload(parameters);
1538
+ const data = new TextEncoder().encode(payload);
1539
+ const signature = await signer.sign(data);
1540
+ const signatureArray = new Uint8Array(signature);
1541
+ return btoa(String.fromCharCode(...signatureArray));
1542
+ };
1543
+ /**
1544
+ * Verifies a header signature. Generally, this is not called directly, but
1545
+ * rather through {@link validateHeader}.
1546
+ *
1547
+ * @param parameters - The parameters used to sign the header.
1548
+ * @param signature - The signature to verify.
1549
+ * @param signer - The signer of the document.
1550
+ */
1551
+ const verify = async (parameters, signature, signer) => {
1552
+ const payload = generateStablePayload(parameters);
1553
+ const data = new TextEncoder().encode(payload);
1554
+ const signatureBytes = Uint8Array.from(atob(signature), (c) => c.charCodeAt(0));
1555
+ await signer.verify(data, signatureBytes);
1556
+ };
1557
+ /**
1558
+ * Validates a header signature.
1559
+ */
1560
+ const validateHeader = async (header) => {
1561
+ const signer = await createSignerFromHeader(header);
1562
+ return verify({
1563
+ documentType: header.documentType,
1564
+ createdAtUtcIso: header.createdAtUtcIso,
1565
+ nonce: header.sig.nonce
1566
+ }, header.id, signer);
1567
+ };
1568
+ /**
1569
+ * Creates a header that has yet to be signed. This header is not valid, but
1570
+ * can be input into {@link createSignedHeader} to create a signed header.
1571
+ *
1572
+ * @returns An unsigned header for a document.
1573
+ */
1574
+ const createPresignedHeader = (id = generateId(), documentType = "") => {
1575
+ return {
1576
+ id,
1577
+ sig: {
1578
+ publicKey: {},
1579
+ nonce: ""
1580
+ },
1581
+ documentType,
1582
+ createdAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),
1583
+ slug: "",
1584
+ name: "",
1585
+ branch: "main",
1586
+ revision: { document: 0 },
1587
+ lastModifiedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),
1588
+ meta: {}
1589
+ };
1590
+ };
1591
+ /**
1592
+ * Creates a new, signed header for a document. This will replace the id of the
1593
+ * document.
1594
+ *
1595
+ * @param unsignedHeader - The unsigned header to created the signed header from.
1596
+ * @param signer - The signer of the document.
1597
+ *
1598
+ * @returns A new signed header for a document. Some fields are mutable and
1599
+ * some are not. See the PHDocumentHeader type for more information.
1600
+ */
1601
+ const createSignedHeader = async (unsignedHeader, documentType, signer) => {
1602
+ const parameters = {
1603
+ documentType,
1604
+ createdAtUtcIso: unsignedHeader.createdAtUtcIso,
1605
+ nonce: generateId()
1606
+ };
1607
+ return {
1608
+ id: await sign(parameters, signer),
1609
+ sig: {
1610
+ publicKey: await crypto.subtle.exportKey("jwk", signer.publicKey),
1611
+ nonce: parameters.nonce
1612
+ },
1613
+ documentType,
1614
+ createdAtUtcIso: unsignedHeader.createdAtUtcIso,
1615
+ slug: unsignedHeader.slug,
1616
+ name: unsignedHeader.name,
1617
+ branch: unsignedHeader.branch,
1618
+ revision: unsignedHeader.revision,
1619
+ lastModifiedAtUtcIso: unsignedHeader.lastModifiedAtUtcIso,
1620
+ meta: unsignedHeader.meta
1621
+ };
1622
+ };
1623
+ /**
1624
+ * Creates a signed header for a document. The document header requires a signer
1625
+ * as the document id is a cryptographic signature.
1626
+ *
1627
+ * @param documentType - The type of the document.
1628
+ * @param signer - The signer of the document.
1629
+ *
1630
+ * @returns The signed header for a document. Some fields are mutable and
1631
+ * some are not. See the PHDocumentHeader type for more information.
1632
+ */
1633
+ const createSignedHeaderForSigner = async (documentType, signer) => {
1634
+ return await createSignedHeader(createPresignedHeader(), documentType, signer);
1635
+ };
1636
+ //#endregion
1637
+ //#region document-model/documents.ts
1638
+ function isNoopOperation(op) {
1639
+ return op.type === "NOOP" && op.skip !== void 0 && op.skip > 0 && op.hash !== void 0;
1640
+ }
1641
+ function isUndoRedo(action) {
1642
+ return ["UNDO", "REDO"].includes(action.type);
1643
+ }
1644
+ function isUndo(action) {
1645
+ return action.type === "UNDO";
1646
+ }
1647
+ function isDocumentAction(action) {
1648
+ return [
1649
+ "SET_NAME",
1650
+ "UNDO",
1651
+ "REDO",
1652
+ "PRUNE",
1653
+ "LOAD_STATE"
1654
+ ].includes(action.type);
1655
+ }
1656
+ /**
1657
+ * Important note: it is the responsibility of the caller to set the document type
1658
+ * on the header.
1659
+ */
1660
+ function baseCreateDocument(createState, initialState) {
1661
+ const state = createState(initialState);
1662
+ return {
1663
+ header: createPresignedHeader(),
1664
+ state,
1665
+ initialState: state,
1666
+ operations: {
1667
+ global: [],
1668
+ local: []
1669
+ },
1670
+ clipboard: []
1671
+ };
1672
+ }
1673
+ function hashDocumentStateForScope(document, scope = "global") {
1674
+ return hashBrowser(stringifyJson(document.state[scope] || ""));
1675
+ }
1676
+ function readOnly(value) {
1677
+ return Object.freeze(value);
1678
+ }
1679
+ /**
1680
+ * Maps skipped operations in an array of operations.
1681
+ * Skipped operations are operations that are ignored during processing.
1682
+ * @param operations - The array of operations to map.
1683
+ * @param skippedHeadOperations - The number of operations to skip at the head of the array of operations.
1684
+ * @returns An array of mapped operations with ignore flag indicating if the operation is skipped.
1685
+ * @throws Error if the operation index is invalid and there are missing operations.
1686
+ */
1687
+ function mapSkippedOperations(operations, skippedHeadOperations) {
1688
+ const ops = [...operations];
1689
+ let skipped = skippedHeadOperations || 0;
1690
+ let latestOpIndex = ops.length > 0 ? ops[ops.length - 1].index : 0;
1691
+ const scopeOpsWithIgnore = [];
1692
+ for (const operation of ops.reverse()) {
1693
+ if (skipped > 0) {
1694
+ const operationsDiff = latestOpIndex - operation.index;
1695
+ skipped -= operationsDiff;
1696
+ }
1697
+ if (skipped < 0) throw new Error("Invalid operation index, missing operations");
1698
+ const mappedOp = {
1699
+ ignore: skipped > 0,
1700
+ operation
1701
+ };
1702
+ const operationSkip = operation.skip > 0 ? operation.skip + 1 : 0;
1703
+ if (operationSkip > 0 && operationSkip > skipped) {
1704
+ const skipDiff = operationSkip - skipped;
1705
+ skipped = skipped + skipDiff;
1706
+ }
1707
+ latestOpIndex = operation.index;
1708
+ scopeOpsWithIgnore.push(mappedOp);
1709
+ }
1710
+ return scopeOpsWithIgnore.reverse();
1711
+ }
1712
+ /**
1713
+ * V2 version of mapSkippedOperations for protocol version 2+.
1714
+ * In V2, all NOOPs have skip=1 and consecutive NOOPs form chains.
1715
+ * N consecutive NOOPs at any point skip N preceding content operations.
1716
+ *
1717
+ * Algorithm: Process from end to start
1718
+ * - When hitting a NOOP: increment chain length, mark as ignored
1719
+ * - When hitting a non-NOOP:
1720
+ * - If chain > 0: decrement chain, mark as ignored (this op was undone)
1721
+ * - If chain == 0: mark as not ignored (apply this op)
1722
+ */
1723
+ function mapSkippedOperationsV2(operations) {
1724
+ const ops = [...operations];
1725
+ const result = [];
1726
+ let noopChainLength = 0;
1727
+ for (let i = ops.length - 1; i >= 0; i--) {
1728
+ const operation = ops[i];
1729
+ if (operation.action.type === "NOOP") {
1730
+ noopChainLength++;
1731
+ result.unshift({
1732
+ ignore: true,
1733
+ operation
1734
+ });
1735
+ } else if (noopChainLength > 0) {
1736
+ noopChainLength--;
1737
+ result.unshift({
1738
+ ignore: true,
1739
+ operation
1740
+ });
1741
+ } else result.unshift({
1742
+ ignore: false,
1743
+ operation
1744
+ });
1745
+ }
1746
+ return result;
1747
+ }
1748
+ /**
1749
+ * V2 garbage collect that returns only operations that should be applied for state.
1750
+ * Uses the V2 model where consecutive NOOPs form chains.
1751
+ * Unlike V1 garbageCollect, this preserves ALL operations but marks which to apply.
1752
+ */
1753
+ function garbageCollectV2(sortedOperations) {
1754
+ const result = [];
1755
+ let noopChainLength = 0;
1756
+ for (let i = sortedOperations.length - 1; i >= 0; i--) {
1757
+ const op = sortedOperations[i];
1758
+ if ("action" in op && op.action.type === "NOOP" && op.skip > 0) {
1759
+ noopChainLength++;
1760
+ result.unshift(op);
1761
+ } else if (noopChainLength > 0) noopChainLength--;
1762
+ else result.unshift(op);
1763
+ }
1764
+ return result;
1765
+ }
1766
+ function sortMappedOperations(operations) {
1767
+ return Object.values(operations).flatMap((array) => array).sort((a, b) => new Date(a.operation.timestampUtcMs).getTime() - new Date(b.operation.timestampUtcMs).getTime());
1768
+ }
1769
+ const defaultCreateState = (state) => {
1770
+ return state;
1771
+ };
1772
+ function replayDocument(initialState, operations, reducer, header, dispatch, skipHeaderOperations = {}, options) {
1773
+ const { checkHashes = true, reuseOperationResultingState, operationResultingStateParser = parseResultingState, skipIndexValidation } = options || {};
1774
+ let documentState = initialState;
1775
+ const operationsToReplay = [];
1776
+ const allScopes = new Set([
1777
+ ...Object.keys(operations),
1778
+ "global",
1779
+ "local"
1780
+ ]);
1781
+ const initialOperations = {};
1782
+ for (const scope of allScopes) initialOperations[scope] = [];
1783
+ if (reuseOperationResultingState) for (const [scope, scopeOperations] of Object.entries(operations)) {
1784
+ if (!scopeOperations) continue;
1785
+ const index = scopeOperations.findLastIndex((s) => !!s.resultingState);
1786
+ if (index < 0) {
1787
+ operationsToReplay.push(...scopeOperations);
1788
+ continue;
1789
+ }
1790
+ const opWithState = scopeOperations[index];
1791
+ if (!opWithState || !opWithState.resultingState) continue;
1792
+ try {
1793
+ const scopeState = operationResultingStateParser(opWithState.resultingState);
1794
+ documentState = {
1795
+ ...documentState,
1796
+ [scope]: scopeState
1797
+ };
1798
+ const scopeInitialOps = initialOperations[scope];
1799
+ if (scopeInitialOps) scopeInitialOps.push(...scopeOperations.slice(0, index + 1));
1800
+ operationsToReplay.push(...scopeOperations.slice(index + 1));
1801
+ } catch {
1802
+ operationsToReplay.push(...scopeOperations);
1803
+ }
1804
+ }
1805
+ else operationsToReplay.push(...Object.values(operations).flatMap((ops) => ops || []));
1806
+ const document = {
1807
+ header,
1808
+ state: defaultCreateState(documentState),
1809
+ initialState,
1810
+ operations: initialOperations,
1811
+ clipboard: []
1812
+ };
1813
+ let result = document;
1814
+ if (operationsToReplay.length) result = operationsToReplay.reduce((document, operation) => {
1815
+ return reducer(document, operation.action, dispatch, {
1816
+ ignoreSkipOperations: true,
1817
+ checkHashes,
1818
+ skipIndexValidation,
1819
+ replayOptions: { operation }
1820
+ });
1821
+ }, document);
1822
+ else for (const scopeOperations of Object.values(initialOperations)) {
1823
+ if (!scopeOperations) continue;
1824
+ const lastOperation = scopeOperations.at(-1);
1825
+ if (lastOperation) result = updateHeaderRevision(result, lastOperation.action.scope, lastOperation.timestampUtcMs);
1826
+ }
1827
+ if (!checkHashes) for (const scope of Object.keys(result.state)) for (let i = operationsToReplay.length - 1; i >= 0; i--) {
1828
+ const operation = operationsToReplay[i];
1829
+ if (operation.action.scope !== scope) continue;
1830
+ if (operation.hash !== hashDocumentStateForScope(result, scope)) throw new HashMismatchError(scope, result, operation);
1831
+ else break;
1832
+ }
1833
+ const allResultScopes = new Set([
1834
+ ...Object.keys(result.operations),
1835
+ ...Object.keys(operations),
1836
+ "global",
1837
+ "local"
1838
+ ]);
1839
+ const initialResultOperations = {};
1840
+ for (const scope of allResultScopes) initialResultOperations[scope] = [];
1841
+ const resultOperations = Array.from(allResultScopes).reduce((acc, scope) => {
1842
+ const scopeOps = result.operations[scope] || [];
1843
+ return {
1844
+ ...acc,
1845
+ [scope]: [...scopeOps.map((operation, index) => {
1846
+ return {
1847
+ ...operation,
1848
+ timestamp: operations[scope]?.[index]?.timestampUtcMs ?? operation.timestampUtcMs
1849
+ };
1850
+ })]
1851
+ };
1852
+ }, initialResultOperations);
1853
+ const lastModified = header ? header.lastModifiedAtUtcIso : Object.values(resultOperations).reduce((acc, curr) => {
1854
+ if (!curr) return acc;
1855
+ const operation = curr.at(-1);
1856
+ if (operation) {
1857
+ if (operation.timestampUtcMs > acc) return operation.timestampUtcMs;
1858
+ }
1859
+ return acc;
1860
+ }, document.header.lastModifiedAtUtcIso);
1861
+ if (header) result.header = {
1862
+ ...header,
1863
+ revision: result.header.revision,
1864
+ lastModifiedAtUtcIso: lastModified
1865
+ };
1866
+ return {
1867
+ ...result,
1868
+ operations: resultOperations
1869
+ };
1870
+ }
1871
+ function parseResultingState(state) {
1872
+ const stateType = typeof state;
1873
+ if (stateType === "string") return JSON.parse(state);
1874
+ else if (stateType === "object") return state;
1875
+ else throw new Error(`Providing resulting state is of type: ${stateType}`);
1876
+ }
1877
+ let IntegrityIssueType = /* @__PURE__ */ function(IntegrityIssueType) {
1878
+ IntegrityIssueType["UNEXPECTED_INDEX"] = "UNEXPECTED_INDEX";
1879
+ return IntegrityIssueType;
1880
+ }({});
1881
+ let IntegrityIssueSubType = /* @__PURE__ */ function(IntegrityIssueSubType) {
1882
+ IntegrityIssueSubType["DUPLICATED_INDEX"] = "DUPLICATED_INDEX";
1883
+ IntegrityIssueSubType["MISSING_INDEX"] = "MISSING_INDEX";
1884
+ return IntegrityIssueSubType;
1885
+ }({});
1886
+ function checkCleanedOperationsIntegrity(sortedOperations) {
1887
+ const result = [];
1888
+ let currentIndex = -1;
1889
+ for (const nextOperation of sortedOperations) {
1890
+ const nextIndex = nextOperation.index - nextOperation.skip;
1891
+ if (nextIndex !== currentIndex + 1) result.push({
1892
+ operation: {
1893
+ index: nextOperation.index,
1894
+ skip: nextOperation.skip
1895
+ },
1896
+ issue: IntegrityIssueType.UNEXPECTED_INDEX,
1897
+ category: nextIndex > currentIndex + 1 ? IntegrityIssueSubType.MISSING_INDEX : IntegrityIssueSubType.DUPLICATED_INDEX,
1898
+ message: `Expected index ${currentIndex + 1} with skip 0 or equivalent, got index ${nextOperation.index} with skip ${nextOperation.skip}`
1899
+ });
1900
+ currentIndex = nextOperation.index;
1901
+ }
1902
+ return result;
1903
+ }
1904
+ function garbageCollect(sortedOperations) {
1905
+ const result = [];
1906
+ let i = sortedOperations.length - 1;
1907
+ while (i > -1) {
1908
+ result.unshift(sortedOperations[i]);
1909
+ const skipUntil = (sortedOperations[i]?.index || 0) - (sortedOperations[i]?.skip || 0) - 1;
1910
+ let j = i - 1;
1911
+ while (j > -1 && (sortedOperations[j]?.index || 0) > skipUntil) j--;
1912
+ i = j;
1913
+ }
1914
+ return result;
1915
+ }
1916
+ function addUndo(sortedOperations) {
1917
+ const operationsCopy = [...sortedOperations];
1918
+ const latestOperation = operationsCopy[operationsCopy.length - 1];
1919
+ if (!latestOperation) return operationsCopy;
1920
+ if (latestOperation.action.type === "NOOP") operationsCopy.push({
1921
+ ...latestOperation,
1922
+ index: latestOperation.index,
1923
+ skip: nextSkipNumber(sortedOperations),
1924
+ action: {
1925
+ ...latestOperation.action,
1926
+ id: generateId(),
1927
+ timestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),
1928
+ type: "NOOP"
1929
+ }
1930
+ });
1931
+ else operationsCopy.push({
1932
+ id: generateId(),
1933
+ timestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),
1934
+ index: latestOperation.index + 1,
1935
+ skip: 1,
1936
+ hash: latestOperation.hash,
1937
+ action: {
1938
+ id: generateId(),
1939
+ timestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),
1940
+ type: "NOOP",
1941
+ input: {},
1942
+ scope: latestOperation.action.scope
1943
+ }
1944
+ });
1945
+ return operationsCopy;
1946
+ }
1947
+ function sortOperations(operations) {
1948
+ return operations.slice().sort((a, b) => a.skip - b.skip).sort((a, b) => a.index - b.index);
1949
+ }
1950
+ function reshuffleByTimestamp(startIndex, opsA, opsB) {
1951
+ return [...opsA, ...opsB].sort((a, b) => {
1952
+ const timestampDiff = new Date(a.timestampUtcMs || "").getTime() - new Date(b.timestampUtcMs || "").getTime();
1953
+ if (timestampDiff !== 0) return timestampDiff;
1954
+ return (a.id || "").localeCompare(b.id || "");
1955
+ }).map((op, i) => ({
1956
+ ...op,
1957
+ index: startIndex.index + i,
1958
+ skip: i === 0 ? startIndex.skip : 0
1959
+ }));
1960
+ }
1961
+ function reshuffleByTimestampAndIndex(startIndex, opsA, opsB) {
1962
+ return [...opsA, ...opsB].sort((a, b) => {
1963
+ const indexDiff = a.index - b.index;
1964
+ if (indexDiff !== 0) return indexDiff;
1965
+ const timestampDiff = new Date(a.timestampUtcMs || "").getTime() - new Date(b.timestampUtcMs || "").getTime();
1966
+ if (timestampDiff !== 0) return timestampDiff;
1967
+ return (a.id || "").localeCompare(b.id || "");
1968
+ }).map((op, i) => ({
1969
+ ...op,
1970
+ index: startIndex.index + i,
1971
+ skip: i === 0 ? startIndex.skip : 0
1972
+ }));
1973
+ }
1974
+ function operationsAreEqual(op1, op2) {
1975
+ const a = op1;
1976
+ const b = op2;
1977
+ const aComparable = {
1978
+ index: a.index,
1979
+ skip: a.skip,
1980
+ type: a.type ?? null,
1981
+ scope: a.scope ?? null,
1982
+ input: a.input ?? null
1983
+ };
1984
+ const bComparable = {
1985
+ index: b.index,
1986
+ skip: b.skip,
1987
+ type: b.type ?? null,
1988
+ scope: b.scope ?? null,
1989
+ input: b.input ?? null
1990
+ };
1991
+ return stringify(aComparable) === stringify(bComparable);
1992
+ }
1993
+ function attachBranch(trunk, newBranch) {
1994
+ const trunkCopy = garbageCollect(sortOperations(trunk.slice()));
1995
+ const newOperations = garbageCollect(sortOperations(newBranch.slice()));
1996
+ if (trunkCopy.length < 1) return [newOperations, []];
1997
+ const result = [];
1998
+ let enteredBranch = false;
1999
+ while (newOperations.length > 0) {
2000
+ const newOperationCandidate = newOperations[0];
2001
+ let nextTrunkOperation = trunkCopy.shift();
2002
+ while (nextTrunkOperation && precedes(nextTrunkOperation, newOperationCandidate)) {
2003
+ result.push(nextTrunkOperation);
2004
+ nextTrunkOperation = trunkCopy.shift();
2005
+ }
2006
+ if (!nextTrunkOperation) enteredBranch = true;
2007
+ else if (!enteredBranch) if (operationsAreEqual(nextTrunkOperation, newOperationCandidate)) {
2008
+ newOperations.shift();
2009
+ result.push(nextTrunkOperation);
2010
+ } else {
2011
+ trunkCopy.unshift(nextTrunkOperation);
2012
+ enteredBranch = true;
2013
+ }
2014
+ if (enteredBranch) {
2015
+ let nextAppend = newOperations.shift();
2016
+ while (nextAppend) {
2017
+ result.push(nextAppend);
2018
+ nextAppend = newOperations.shift();
2019
+ }
2020
+ }
2021
+ }
2022
+ if (!enteredBranch) {
2023
+ let nextAppend = trunkCopy.shift();
2024
+ while (nextAppend) {
2025
+ result.push(nextAppend);
2026
+ nextAppend = trunkCopy.shift();
2027
+ }
2028
+ }
2029
+ return [garbageCollect(result), trunkCopy];
2030
+ }
2031
+ function precedes(op1, op2) {
2032
+ return op1.index < op2.index || op1.index === op2.index && op1.id === op2.id && op1.skip < op2.skip;
2033
+ }
2034
+ function split(sortedTargetOperations, sortedMergeOperations) {
2035
+ const commonOperations = [];
2036
+ const targetDiffOperations = [];
2037
+ const mergeDiffOperations = [];
2038
+ const maxLength = Math.max(sortedTargetOperations.length, sortedMergeOperations.length);
2039
+ let splitHappened = false;
2040
+ for (let i = 0; i < maxLength; i++) {
2041
+ const targetOperation = sortedTargetOperations[i];
2042
+ const mergeOperation = sortedMergeOperations[i];
2043
+ if (targetOperation && mergeOperation) if (!splitHappened && operationsAreEqual(targetOperation, mergeOperation)) commonOperations.push(targetOperation);
2044
+ else {
2045
+ splitHappened = true;
2046
+ targetDiffOperations.push(targetOperation);
2047
+ mergeDiffOperations.push(mergeOperation);
2048
+ }
2049
+ else if (targetOperation) targetDiffOperations.push(targetOperation);
2050
+ else if (mergeOperation) mergeDiffOperations.push(mergeOperation);
2051
+ }
2052
+ return [
2053
+ commonOperations,
2054
+ targetDiffOperations,
2055
+ mergeDiffOperations
2056
+ ];
2057
+ }
2058
+ function merge(sortedTargetOperations, sortedMergeOperations, reshuffle) {
2059
+ const [_commonOperations, _targetOperations, _mergeOperations] = split(garbageCollect(sortedTargetOperations), garbageCollect(sortedMergeOperations));
2060
+ const maxCommonIndex = getMaxIndex(_commonOperations);
2061
+ const nextIndex = 1 + Math.max(maxCommonIndex, getMaxIndex(_targetOperations), getMaxIndex(_mergeOperations));
2062
+ const filteredMergeOperations = filterDuplicatedOperations(_mergeOperations, _targetOperations);
2063
+ const newOperationHistory = reshuffle({
2064
+ index: nextIndex,
2065
+ skip: nextIndex - (maxCommonIndex + 1)
2066
+ }, _targetOperations, filteredMergeOperations);
2067
+ return _commonOperations.concat(newOperationHistory);
2068
+ }
2069
+ function getMaxIndex(sortedOperations) {
2070
+ const lastElement = sortedOperations[sortedOperations.length - 1];
2071
+ if (!lastElement) return -1;
2072
+ return lastElement.index;
2073
+ }
2074
+ function nextSkipNumber(sortedOperations) {
2075
+ if (sortedOperations.length < 1) return -1;
2076
+ const cleanedOperations = garbageCollect(sortedOperations);
2077
+ let nextSkip = (cleanedOperations[cleanedOperations.length - 1]?.skip || 0) + 1;
2078
+ if (cleanedOperations.length > 1) nextSkip += cleanedOperations[cleanedOperations.length - 2]?.skip || 0;
2079
+ return (cleanedOperations[cleanedOperations.length - 1]?.index || -1) < nextSkip ? -1 : nextSkip;
2080
+ }
2081
+ function checkOperationsIntegrity(operations) {
2082
+ return checkCleanedOperationsIntegrity(garbageCollect(sortOperations(operations)));
2083
+ }
2084
+ function groupOperationsByScope(operations) {
2085
+ return operations.reduce((acc, operation) => {
2086
+ if (!acc[operation.action.scope]) acc[operation.action.scope] = [];
2087
+ acc[operation.action.scope]?.push(operation);
2088
+ return acc;
2089
+ }, {});
2090
+ }
2091
+ function prepareOperations(operationsHistory, newOperations) {
2092
+ const result = {
2093
+ integrityIssues: [],
2094
+ validOperations: [],
2095
+ invalidOperations: [],
2096
+ duplicatedOperations: []
2097
+ };
2098
+ const sortedOperationsHistory = sortOperations(operationsHistory);
2099
+ const sortedOperations = sortOperations(newOperations);
2100
+ const integrityErrors = checkCleanedOperationsIntegrity([...sortedOperationsHistory, ...sortedOperations]);
2101
+ const firstMissingIndexOperation = [...integrityErrors.filter((integrityIssue) => integrityIssue.category === IntegrityIssueSubType.MISSING_INDEX)].sort((a, b) => b.operation.index - a.operation.index).pop()?.operation;
2102
+ for (const newOperation of sortedOperations) {
2103
+ if (firstMissingIndexOperation && newOperation.index >= firstMissingIndexOperation.index) {
2104
+ result.invalidOperations.push(newOperation);
2105
+ continue;
2106
+ }
2107
+ if (integrityErrors.some((integrityError) => {
2108
+ return integrityError.operation.index === newOperation.index && integrityError.operation.skip === newOperation.skip && integrityError.category === IntegrityIssueSubType.DUPLICATED_INDEX;
2109
+ })) {
2110
+ result.duplicatedOperations.push(newOperation);
2111
+ continue;
2112
+ }
2113
+ result.validOperations.push(newOperation);
2114
+ }
2115
+ result.integrityIssues.push(...integrityErrors);
2116
+ return result;
2117
+ }
2118
+ function removeExistingOperations(newOperations, operationsHistory) {
2119
+ return newOperations.filter((newOperation) => {
2120
+ return !operationsHistory.some((historyOperation) => {
2121
+ return newOperation.action.type === "NOOP" && newOperation.skip === 0 && newOperation.index === historyOperation.index || newOperation.index === historyOperation.index && newOperation.skip === historyOperation.skip && newOperation.action.scope === historyOperation.action.scope && newOperation.hash === historyOperation.hash && newOperation.action.type === historyOperation.action.type;
2122
+ });
2123
+ });
2124
+ }
2125
+ /**
2126
+ * Skips header operations and returns the remaining operations.
2127
+ *
2128
+ * @param operations - The array of operations.
2129
+ * @param skipHeaderOperation - The skip header operation index.
2130
+ * @returns The remaining operations after skipping header operations.
2131
+ */
2132
+ function skipHeaderOperations(operations, skipHeaderOperation) {
2133
+ const lastIndex = sortOperations(operations).at(-1)?.index ?? -1;
2134
+ const nextIndex = lastIndex + 1;
2135
+ const skipOperationIndex = {
2136
+ ...skipHeaderOperation,
2137
+ index: skipHeaderOperation.index ?? nextIndex
2138
+ };
2139
+ if (skipOperationIndex.index < lastIndex) throw new Error(`The skip header operation index must be greater than or equal to ${lastIndex}`);
2140
+ return garbageCollect(sortOperations([...operations, skipOperationIndex])).slice(0, -1);
2141
+ }
2142
+ function garbageCollectDocumentOperations(documentOperations) {
2143
+ return Object.entries(documentOperations).reduce((acc, entry) => {
2144
+ const [scope, ops] = entry;
2145
+ if (!ops) return acc;
2146
+ return {
2147
+ ...acc,
2148
+ [scope]: garbageCollect(sortOperations(ops))
2149
+ };
2150
+ }, {});
2151
+ }
2152
+ /**
2153
+ * Filters out duplicated operations from the target operations array based on their IDs.
2154
+ * If an operation has an ID, it is considered duplicated if there is another operation in the source operations array with the same ID.
2155
+ * If an operation does not have an ID, it is considered unique and will not be filtered out.
2156
+ * @param targetOperations - The array of target operations to filter.
2157
+ * @param sourceOperations - The array of source operations to compare against.
2158
+ * @returns An array of operations with duplicates filtered out.
2159
+ */
2160
+ function filterDuplicatedOperations(targetOperations, sourceOperations) {
2161
+ return targetOperations.filter((op) => {
2162
+ if (op.id) return !sourceOperations.some((targetOp) => targetOp.id === op.id);
2163
+ return true;
2164
+ });
2165
+ }
2166
+ function filterDocumentOperationsResultingState(documentOperations) {
2167
+ if (!documentOperations) return {};
2168
+ return Object.entries(documentOperations).reduce((acc, [scope, operations]) => {
2169
+ if (!operations) return acc;
2170
+ return {
2171
+ ...acc,
2172
+ [scope]: operations.map((op) => {
2173
+ const { resultingState, ...restProps } = op;
2174
+ return restProps;
2175
+ })
2176
+ };
2177
+ }, {});
2178
+ }
2179
+ /**
2180
+ * Calculates the difference between two arrays of operations.
2181
+ * Returns an array of operations that are present in `clearedOperationsA` but not in `clearedOperationsB`.
2182
+ *
2183
+ * @template TOp - The type of the operations.
2184
+ * @param {TOp[]} clearedOperationsA - The first array of operations.
2185
+ * @param {TOp[]} clearedOperationsB - The second array of operations.
2186
+ * @returns {TOp[]} - The difference between the two arrays of operations.
2187
+ */
2188
+ function diffOperations(clearedOperationsA, clearedOperationsB) {
2189
+ return clearedOperationsA.filter((operationA) => !clearedOperationsB.some((operationB) => operationA.index === operationB.index));
2190
+ }
2191
+ function getDocumentLastModified(document) {
2192
+ let latest;
2193
+ for (const ops of Object.values(document.operations)) {
2194
+ if (!ops) continue;
2195
+ for (const op of ops) if (!latest || op.index > latest.index || op.index === latest.index && op.skip > latest.skip) latest = op;
2196
+ }
2197
+ return latest?.timestampUtcMs || document.header.lastModifiedAtUtcIso;
2198
+ }
2199
+ /**
2200
+ * Gets the next revision number based on the provided scope.
2201
+ *
2202
+ * @param state The current state of the document.
2203
+ * @param scope The scope of the operation.
2204
+ * @returns The next revision number.
2205
+ */
2206
+ function getNextRevision(document, scope) {
2207
+ return (document.operations[scope]?.at(-1)?.index ?? -1) + 1;
2208
+ }
2209
+ /**
2210
+ * Updates the document header with the latest revision number and
2211
+ * date of last modification.
2212
+ *
2213
+ * @param document The current state of the document.
2214
+ * @param scope The scope of the operation.
2215
+ * @param lastModifiedTimestamp Optional timestamp to use directly, avoiding a scan of all operations.
2216
+ * @returns The updated document state.
2217
+ */
2218
+ function updateHeaderRevision(document, scope, lastModifiedTimestamp) {
2219
+ const newTimestamp = lastModifiedTimestamp ?? getDocumentLastModified(document);
2220
+ const currentTimestamp = document.header.lastModifiedAtUtcIso;
2221
+ const header = {
2222
+ ...document.header,
2223
+ revision: {
2224
+ ...document.header.revision,
2225
+ [scope]: getNextRevision(document, scope)
2226
+ },
2227
+ lastModifiedAtUtcIso: !currentTimestamp || newTimestamp > currentTimestamp ? newTimestamp : currentTimestamp
2228
+ };
2229
+ return {
2230
+ ...document,
2231
+ header
2232
+ };
2233
+ }
2234
+ //#endregion
2235
+ //#region document-model/operations.ts
2236
+ function setNameOperation(document, input) {
2237
+ return {
2238
+ ...document,
2239
+ header: {
2240
+ ...document.header,
2241
+ name: input.name
2242
+ }
2243
+ };
2244
+ }
2245
+ function undoOperation(document, action, skip) {
2246
+ const { scope } = action;
2247
+ return create({
2248
+ document,
2249
+ action,
2250
+ skip,
2251
+ reuseLastOperationIndex: false
2252
+ }, (draft) => {
2253
+ const sortedOperations = sortOperations([...document.operations[scope]]);
2254
+ draft.action = noop(scope);
2255
+ const lastOperation = sortedOperations.at(-1);
2256
+ let nextIndex = lastOperation?.index ?? -1;
2257
+ const isNewNoop = lastOperation?.action.type !== "NOOP";
2258
+ if (isNewNoop) nextIndex = nextIndex + 1;
2259
+ else draft.reuseLastOperationIndex = true;
2260
+ draft.skip = nextSkipNumber(isNewNoop ? [...sortedOperations, {
2261
+ index: nextIndex,
2262
+ skip: 0
2263
+ }] : sortedOperations);
2264
+ if (lastOperation && draft.skip > lastOperation.skip + 1) draft.skip = draft.skip + 1;
2265
+ if (draft.skip < 0) throw new Error(`Cannot undo: you can't undo more operations than the ones in the scope history`);
2266
+ });
2267
+ }
2268
+ /**
2269
+ * V2 of undoOperation for protocol version 2+.
2270
+ * Key differences from undoOperation:
2271
+ * - Never reuses operation index (always increments)
2272
+ * - Always sets skip=1 (consecutive NOOPs are handled during rebuild/GC)
2273
+ * - No complex skip calculation - simpler model where each UNDO is independent
2274
+ */
2275
+ function undoOperationV2(document, action, skip) {
2276
+ const { scope } = action;
2277
+ return create({
2278
+ document,
2279
+ action,
2280
+ skip,
2281
+ reuseLastOperationIndex: false
2282
+ }, (draft) => {
2283
+ const sortedOperations = sortOperations([...document.operations[scope] || []]);
2284
+ const nonNoopOps = sortedOperations.filter((op) => op.action.type !== "NOOP");
2285
+ let noopChainLength = 0;
2286
+ for (let i = sortedOperations.length - 1; i >= 0; i--) if (sortedOperations[i].action.type === "NOOP") noopChainLength++;
2287
+ else break;
2288
+ if (nonNoopOps.length <= noopChainLength) throw new Error(`Cannot undo: no more operations to undo in scope history`);
2289
+ draft.action = noop(scope);
2290
+ draft.skip = 1;
2291
+ });
2292
+ }
2293
+ function redoOperation(document, action, skip) {
2294
+ const { scope, input } = action;
2295
+ return create({
2296
+ document,
2297
+ action,
2298
+ skip,
2299
+ reuseLastOperationIndex: false
2300
+ }, (draft) => {
2301
+ if (draft.skip > 0) throw new Error(`Cannot redo: skip value from reducer cannot be used with REDO action`);
2302
+ const count = typeof input === "object" && input !== null && "count" in input ? input.count : input;
2303
+ if (typeof count !== "number" || count > 1) throw new Error(`Cannot redo: you can only redo one operation at a time`);
2304
+ if (typeof count !== "number" || count < 1) throw new Error(`Invalid REDO action: invalid redo input value`);
2305
+ if (draft.document.clipboard.length < 1) throw new Error(`Cannot redo: no operations in the clipboard`);
2306
+ const operationIndex = draft.document.clipboard.findLastIndex((op) => op.action.scope === scope);
2307
+ if (operationIndex < 0) throw new Error(`Cannot redo: no operations in clipboard for scope "${scope}"`);
2308
+ const operation = draft.document.clipboard.splice(operationIndex, 1)[0];
2309
+ draft.action = castDraft({
2310
+ type: operation.action.type,
2311
+ scope: operation.action.scope,
2312
+ input: operation.action.input
2313
+ });
2314
+ });
2315
+ }
2316
+ function loadStateOperation(document, action) {
2317
+ return {
2318
+ ...document,
2319
+ header: {
2320
+ ...document.header,
2321
+ name: action.state.name
2322
+ },
2323
+ state: action.state.data
2324
+ };
2325
+ }
2326
+ //#endregion
2327
+ //#region document-model/reducer.ts
2328
+ function replayOperations(initialState, clearedOperations, stateReducer, header, dispatch, documentReducer = baseReducer, skipHeaderOperations = {}, options) {
2329
+ return replayDocument(initialState, clearedOperations, createReducer(stateReducer, documentReducer), header, dispatch, skipHeaderOperations, options);
2330
+ }
2331
+ /**
2332
+ * Updates the operations history of the document based on the provided action.
2333
+ *
2334
+ * @param state The current state of the document.
2335
+ * @param action The action being applied to the document.
2336
+ * @param index The index of the operation to update.
2337
+ * @param skip The number of operations to skip before applying the action.
2338
+ * @param reuseLastOperationIndex Whether to reuse the last operation index (used when a an UNDO operation is performed after an existing one).
2339
+ * @param context The operation context for deterministic ID generation.
2340
+ * @returns The updated document state.
2341
+ */
2342
+ function updateOperationsForAction(document, action, reuseLastOperationIndex, skip, context) {
2343
+ if ([
2344
+ "UNDO",
2345
+ "REDO",
2346
+ "PRUNE"
2347
+ ].includes(action.type)) return document;
2348
+ const scope = action.scope;
2349
+ const existing = document.operations[scope];
2350
+ const lastOperationIndex = existing?.at(-1)?.index ?? -1;
2351
+ const newOperation = operationFromAction(action, reuseLastOperationIndex ? lastOperationIndex : lastOperationIndex + 1, skip, context);
2352
+ const operations = [...existing ?? [], newOperation];
2353
+ return {
2354
+ ...document,
2355
+ operations: {
2356
+ ...document.operations,
2357
+ [scope]: operations
2358
+ }
2359
+ };
2360
+ }
2361
+ function updateOperationsForOperation(document, operation, reuseLastOperationIndex, skip, context, skipIndexValidation) {
2362
+ const scope = operation.action.scope;
2363
+ const existing = document.operations[scope];
2364
+ const lastOperationIndex = existing?.at(-1)?.index ?? -1;
2365
+ const nextIndex = reuseLastOperationIndex ? lastOperationIndex : lastOperationIndex + 1;
2366
+ if (!skipIndexValidation && operation.index - skip > nextIndex) throw new Error(`Missing operations: expected ${nextIndex} with skip 0 or equivalent, got index ${operation.index} with skip ${skip}`);
2367
+ const newOperation = operationFromOperation(operation, operation.index, skip, context);
2368
+ const operations = [...existing ?? [], newOperation];
2369
+ return {
2370
+ ...document,
2371
+ operations: {
2372
+ ...document.operations,
2373
+ [scope]: operations
2374
+ }
2375
+ };
2376
+ }
2377
+ /**
2378
+ * Updates the document state based on the provided action.
2379
+ *
2380
+ * @param state The current state of the document.
2381
+ * @param action The action being applied to the document.
2382
+ * @param skip The number of operations to skip before applying the action.
2383
+ * @param reuseLastOperationIndex Whether to reuse the last operation index (used when a an UNDO operation is performed after an existing one).
2384
+ * @param context The operation context for deterministic ID generation.
2385
+ * @returns The updated document state.
2386
+ */
2387
+ function updateDocument(document, action, reuseLastOperationIndex, skip, context, operation, skipIndexValidation) {
2388
+ let newDocument;
2389
+ if (operation) newDocument = updateOperationsForOperation(document, operation, reuseLastOperationIndex, skip, context, skipIndexValidation);
2390
+ else newDocument = updateOperationsForAction(document, action, reuseLastOperationIndex, skip, context);
2391
+ newDocument = updateHeaderRevision(newDocument, action.scope, action.timestampUtcMs);
2392
+ return newDocument;
2393
+ }
2394
+ /**
2395
+ * The base document reducer function that wraps a custom reducer function.
2396
+ *
2397
+ * @param state The current state of the document.
2398
+ * @param action The action being applied to the document.
2399
+ * @param wrappedReducer The custom reducer function being wrapped by the base reducer.
2400
+ * @returns The updated document state.
2401
+ */
2402
+ function _baseReducer(document, action, wrappedReducer) {
2403
+ const parsedAction = DocumentActionSchema().parse(action);
2404
+ switch (parsedAction.type) {
2405
+ case "SET_NAME": return setNameOperation(document, parsedAction.input);
2406
+ case "PRUNE": return pruneOperation(document, parsedAction.input, wrappedReducer);
2407
+ case "LOAD_STATE": return loadStateOperation(document, parsedAction.input);
2408
+ default: return document;
2409
+ }
2410
+ }
2411
+ /**
2412
+ * Processes an UNDO or REDO action.
2413
+ *
2414
+ * @param document The current state of the document.
2415
+ * @param action The action being applied to the document.
2416
+ * @param skip The number of operations to skip before applying the action.
2417
+ * @returns The updated document, calculated skip value and transformed action (if applied).
2418
+ */
2419
+ function processUndoRedo(document, action, skip, protocolVersion = 1) {
2420
+ switch (action.type) {
2421
+ case "UNDO":
2422
+ if (protocolVersion >= 2) return undoOperationV2(document, action, skip);
2423
+ return undoOperation(document, action, skip);
2424
+ case "REDO": return redoOperation(document, action, skip);
2425
+ default: return {
2426
+ document,
2427
+ action,
2428
+ skip,
2429
+ reuseLastOperationIndex: false
2430
+ };
2431
+ }
2432
+ }
2433
+ function processSkipOperation(document, action, customReducer, skipValue, reuseOperationResultingState = false, resultingStateParser = parseResultingState) {
2434
+ const scope = action.scope;
2435
+ const scopeOperations = document.operations[scope];
2436
+ if (!scopeOperations) return document;
2437
+ const latestOperation = scopeOperations.at(-1);
2438
+ if (!latestOperation) return document;
2439
+ const documentOperations = garbageCollectDocumentOperations({
2440
+ ...document.operations,
2441
+ [scope]: skipHeaderOperations(scopeOperations, latestOperation)
2442
+ });
2443
+ let scopeState = void 0;
2444
+ const lastRemainingOperation = documentOperations[scope]?.at(-1);
2445
+ if (reuseOperationResultingState && lastRemainingOperation?.resultingState) scopeState = resultingStateParser(lastRemainingOperation.resultingState);
2446
+ else {
2447
+ const { state } = replayOperations(document.initialState, documentOperations, customReducer, document.header, void 0, void 0, void 0, {
2448
+ reuseOperationResultingState,
2449
+ operationResultingStateParser: resultingStateParser,
2450
+ skipIndexValidation: true
2451
+ });
2452
+ scopeState = state[scope];
2453
+ }
2454
+ return {
2455
+ ...document,
2456
+ state: {
2457
+ ...document.state,
2458
+ [scope]: scopeState
2459
+ },
2460
+ operations: garbageCollectDocumentOperations({ ...document.operations })
2461
+ };
2462
+ }
2463
+ function processUndoOperation(document, scope, customReducer, reuseOperationResultingState = false, resultingStateParser = parseResultingState) {
2464
+ const scopeOperations = document.operations[scope];
2465
+ if (!scopeOperations) return document;
2466
+ const sortedOperations = sortOperations([...scopeOperations]);
2467
+ sortedOperations.pop();
2468
+ const documentOperations = garbageCollectDocumentOperations({ ...document.operations });
2469
+ const documentScopeOps = documentOperations[scope];
2470
+ if (!documentScopeOps) return document;
2471
+ const clearedOperations = [...documentScopeOps];
2472
+ const diff = diffOperations(garbageCollect(sortedOperations), clearedOperations);
2473
+ const doc = replayOperations(document.initialState, documentOperations, customReducer, document.header, void 0, void 0, void 0, {
2474
+ reuseOperationResultingState,
2475
+ operationResultingStateParser: resultingStateParser
2476
+ });
2477
+ const clipboard = sortOperations([...document.clipboard, ...diff].filter((op) => op.action.type !== "NOOP")).reverse();
2478
+ return {
2479
+ ...doc,
2480
+ clipboard
2481
+ };
2482
+ }
2483
+ /**
2484
+ * Base document reducer that wraps a custom document reducer and handles
2485
+ * document-level actions such as undo, redo, prune, and set name.
2486
+ *
2487
+ * @template TGlobalState - The type of the state of the custom reducer.
2488
+ * @template TAction - The type of the actions of the custom reducer.
2489
+ * @param state - The current state of the document.
2490
+ * @param action - The action object to apply to the state.
2491
+ * @param customReducer - The custom reducer that implements the application logic
2492
+ * specific to the document's state.
2493
+ * @returns The new state of the document.
2494
+ */
2495
+ function baseReducer(document, action, customReducer, dispatch, options = {}) {
2496
+ const { skip, ignoreSkipOperations = false, reuseOperationResultingState = false, operationResultingStateParser, pruneOnSkip = true, branch = "main" } = options;
2497
+ let _action = actionFromAction(action);
2498
+ let skipValue = skip ?? options.replayOptions?.operation.skip ?? 0;
2499
+ let newDocument = { ...document };
2500
+ let reuseLastOperationIndex = false;
2501
+ const shouldProcessSkipOperation = !ignoreSkipOperations && skipValue > 0;
2502
+ if (isUndoRedo(_action)) {
2503
+ const { skip: calculatedSkip, action: transformedAction, document: processedDocument, reuseLastOperationIndex: reuseIndex } = processUndoRedo(document, _action, skipValue, options.protocolVersion ?? 1);
2504
+ _action = transformedAction;
2505
+ skipValue = calculatedSkip;
2506
+ newDocument = processedDocument;
2507
+ reuseLastOperationIndex = reuseIndex;
2508
+ } else newDocument = {
2509
+ ...newDocument,
2510
+ clipboard: []
2511
+ };
2512
+ if (isDocumentAction(_action)) newDocument = _baseReducer(newDocument, _action, customReducer);
2513
+ const operationContext = {
2514
+ documentId: document.header.id,
2515
+ scope: _action.scope,
2516
+ branch
2517
+ };
2518
+ newDocument = updateDocument(newDocument, _action, reuseLastOperationIndex, skipValue, operationContext, options.replayOptions?.operation, options.skipIndexValidation);
2519
+ const protocolVersion = options.protocolVersion ?? 1;
2520
+ if (isUndo(action) && protocolVersion < 2) return processUndoOperation(newDocument, action.scope, customReducer);
2521
+ const isNoopWithSkip = _action.type === "NOOP" && skipValue > 0;
2522
+ if ((isUndo(action) || isNoopWithSkip) && protocolVersion >= 2) {
2523
+ const scope = _action.scope;
2524
+ const opsToReplay = garbageCollectV2(sortOperations([...newDocument.operations[scope] || []])).filter((op) => op.action.type !== "NOOP");
2525
+ const replayOps = {
2526
+ ...newDocument.operations,
2527
+ [scope]: opsToReplay
2528
+ };
2529
+ return {
2530
+ ...replayOperations(newDocument.initialState, replayOps, customReducer, newDocument.header, dispatch, baseReducer, {}, { skipIndexValidation: true }),
2531
+ operations: newDocument.operations,
2532
+ clipboard: []
2533
+ };
2534
+ }
2535
+ if (shouldProcessSkipOperation) {
2536
+ const processed = processSkipOperation(newDocument, _action, customReducer, skipValue, reuseOperationResultingState, operationResultingStateParser);
2537
+ if (!pruneOnSkip) newDocument = {
2538
+ ...processed,
2539
+ operations: newDocument.operations
2540
+ };
2541
+ else newDocument = processed;
2542
+ }
2543
+ newDocument = create(newDocument, (draft) => {
2544
+ try {
2545
+ const newState = customReducer(draft.state, _action, dispatch);
2546
+ if (newState) unsafe(() => {
2547
+ draft.state = castDraft(newState);
2548
+ });
2549
+ } catch (error) {
2550
+ const actionScopeOps = newDocument.operations[_action.scope];
2551
+ if (!actionScopeOps) throw new Error(`No operations found for scope: ${_action.scope}`);
2552
+ const lastOperationIndex = actionScopeOps.length - 1;
2553
+ const draftScopeOps = draft.operations[_action.scope];
2554
+ if (!draftScopeOps) throw new Error(`No operations found in draft for scope: ${_action.scope}`);
2555
+ draftScopeOps[lastOperationIndex].error = error.message;
2556
+ draftScopeOps[lastOperationIndex].skip = 0;
2557
+ if (shouldProcessSkipOperation) {
2558
+ draft.state = castDraft({ ...document.state });
2559
+ const documentScopeOps = document.operations[_action.scope];
2560
+ if (!documentScopeOps) throw new Error(`No operations found for scope: ${_action.scope}`);
2561
+ draft.operations = castDraft({
2562
+ ...document.operations,
2563
+ [_action.scope]: [...documentScopeOps, { ...draftScopeOps[lastOperationIndex] }]
2564
+ });
2565
+ }
2566
+ }
2567
+ });
2568
+ if ([
2569
+ "UNDO",
2570
+ "REDO",
2571
+ "PRUNE"
2572
+ ].includes(_action.type)) return newDocument;
2573
+ const scope = _action.scope || "global";
2574
+ let hash = hashDocumentStateForScope(newDocument, scope);
2575
+ if (options.replayOptions?.operation.hash && options.replayOptions.operation.hash !== "") hash = options.replayOptions.operation.hash;
2576
+ const lastOperation = newDocument.operations[scope]?.at(-1);
2577
+ if (lastOperation) {
2578
+ lastOperation.hash = hash;
2579
+ if (reuseOperationResultingState) lastOperation.resultingState = JSON.stringify(newDocument.state[scope]);
2580
+ }
2581
+ return newDocument;
2582
+ }
2583
+ /**
2584
+ * Helper function to create a document model reducer.
2585
+ *
2586
+ * @remarks
2587
+ * This function creates a new reducer that wraps the provided `reducer` with
2588
+ * `documentReducer`, adding support for document actions:
2589
+ * - `SET_NAME`
2590
+ * - `UNDO`
2591
+ * - `REDO`
2592
+ * - `PRUNE`
2593
+ *
2594
+ * It also updates the document-related attributes on every operation.
2595
+ *
2596
+ * @param reducer - The custom reducer to wrap.
2597
+ * @param documentReducer - The document reducer to use.
2598
+ *
2599
+ * @returns The new reducer.
2600
+ */
2601
+ function createReducer(stateReducer, documentReducer = baseReducer) {
2602
+ const reducer = (document, action, dispatch, options) => {
2603
+ return documentReducer(document, action, stateReducer, dispatch, options);
2604
+ };
2605
+ return reducer;
2606
+ }
2607
+ function pruneOperation(document, input, wrappedReducer) {
2608
+ const operations = document.operations.global;
2609
+ if (!operations) throw new Error("No global operations found");
2610
+ let { start, end } = input;
2611
+ start = start || 0;
2612
+ end = end || operations.length;
2613
+ const actionsToPrune = operations.slice(start, end);
2614
+ const actionsToKeepStart = operations.slice(0, start);
2615
+ const actionsToKeepEnd = operations.slice(end);
2616
+ const newDocument = replayOperations(document.initialState, {
2617
+ ...document.operations,
2618
+ global: actionsToKeepStart.concat(actionsToPrune)
2619
+ }, wrappedReducer, document.header);
2620
+ const newState = newDocument.state;
2621
+ const name = newDocument.header.name;
2622
+ const loadStateIndex = actionsToKeepStart.length;
2623
+ const loadStateTimestamp = actionsToKeepStart.length ? actionsToKeepStart[actionsToKeepStart.length - 1].timestampUtcMs : actionsToKeepEnd.length ? actionsToKeepEnd[0].timestampUtcMs : (/* @__PURE__ */ new Date()).toISOString();
2624
+ const action = loadState({
2625
+ name,
2626
+ ...newState
2627
+ }, actionsToPrune.length);
2628
+ return replayOperations(document.initialState, {
2629
+ ...document.operations,
2630
+ global: [
2631
+ ...actionsToKeepStart,
2632
+ {
2633
+ skip: 0,
2634
+ ...action,
2635
+ action,
2636
+ timestampUtcMs: loadStateTimestamp,
2637
+ index: loadStateIndex,
2638
+ hash: hashDocumentStateForScope({ state: newState }, "global")
2639
+ },
2640
+ ...actionsToKeepEnd.map((action, index) => ({
2641
+ ...action,
2642
+ index: loadStateIndex + index + 1
2643
+ }))
2644
+ ]
2645
+ }, wrappedReducer, document.header);
2646
+ }
2647
+ //#endregion
2648
+ //#region document-model/validation.ts
2649
+ /**
2650
+ * Reserved operation names from base reducer (core/actions.ts).
2651
+ * These names cannot be used for custom operations.
2652
+ */
2653
+ const RESERVED_OPERATION_NAMES = [
2654
+ "UNDO",
2655
+ "REDO",
2656
+ "PRUNE",
2657
+ "LOAD_STATE",
2658
+ "SET_NAME",
2659
+ "NOOP"
2660
+ ];
2661
+ /**
2662
+ * Check if name conflicts with base reducer actions (case-insensitive).
2663
+ */
2664
+ function isReservedOperationName(name) {
2665
+ return RESERVED_OPERATION_NAMES.includes(name.toUpperCase());
2666
+ }
2667
+ /**
2668
+ * Get all operation names from all modules in the latest specification.
2669
+ * Returns names in uppercase for case-insensitive comparison.
2670
+ */
2671
+ function getAllOperationNames(state, excludeOperationId) {
2672
+ const latestSpec = state.specifications[state.specifications.length - 1];
2673
+ if (!latestSpec) return [];
2674
+ const names = [];
2675
+ for (const module of latestSpec.modules) for (const operation of module.operations) {
2676
+ if (excludeOperationId && operation.id === excludeOperationId) continue;
2677
+ if (operation.name) names.push(operation.name.toUpperCase());
2678
+ }
2679
+ return names;
2680
+ }
2681
+ /**
2682
+ * Validate operation name is not reserved or duplicate. Throws on failure.
2683
+ *
2684
+ * @param name - The operation name to validate
2685
+ * @param state - The document model global state
2686
+ * @param excludeOperationId - Optional operation ID to exclude (for rename validation)
2687
+ * @throws Error if the name is reserved or a duplicate
2688
+ */
2689
+ function validateOperationName(name, state, excludeOperationId) {
2690
+ if (!name) return;
2691
+ const upperName = name.toUpperCase();
2692
+ if (isReservedOperationName(name)) throw new Error(`Operation name "${name}" is reserved. Please use a different name.`);
2693
+ if (getAllOperationNames(state, excludeOperationId).includes(upperName)) throw new Error(`Operation name "${name}" is already used by another operation. Operation names must be unique across all modules.`);
2694
+ }
2695
+ function validateInitialState(initialState, allowEmptyState = false) {
2696
+ const errors = [];
2697
+ if (allowEmptyState && initialState === "") return errors;
2698
+ try {
2699
+ const state = JSON.parse(initialState);
2700
+ if (!allowEmptyState && !Object.keys(state).length) errors.push({
2701
+ message: "Initial state cannot be empty",
2702
+ details: { initialState }
2703
+ });
2704
+ } catch {
2705
+ errors.push({
2706
+ message: "Invalid initial state",
2707
+ details: { initialState }
2708
+ });
2709
+ }
2710
+ return errors;
2711
+ }
2712
+ function validateStateSchemaName(schema, documentName, scope = "", allowEmptySchema = true) {
2713
+ const errors = [];
2714
+ if (!allowEmptySchema && !schema) {
2715
+ errors.push({
2716
+ message: "State schema is required",
2717
+ details: { schema }
2718
+ });
2719
+ return errors;
2720
+ }
2721
+ if (allowEmptySchema && !schema) return errors;
2722
+ const expectedTypeName = `${pascalCase(documentName)}${pascalCase(scope)}State`;
2723
+ if (!new RegExp(`\\btype\\s+${expectedTypeName}(?:\\s|\\{|@|$)`).test(schema)) errors.push({
2724
+ message: `Invalid state schema name. Expected type ${expectedTypeName}`,
2725
+ details: { schema }
2726
+ });
2727
+ return errors;
2728
+ }
2729
+ function validateModules(modules) {
2730
+ const errors = [];
2731
+ if (!modules.length) errors.push({
2732
+ message: "Modules are required",
2733
+ details: { modules }
2734
+ });
2735
+ const modulesError = modules.reduce((acc, mod) => [...acc, ...validateModule(mod)], []);
2736
+ return [...errors, ...modulesError];
2737
+ }
2738
+ function validateModule(mod) {
2739
+ const errors = [];
2740
+ if (!mod.name) errors.push({
2741
+ message: "Module name is required",
2742
+ details: { module: mod }
2743
+ });
2744
+ if (!mod.operations.length) errors.push({
2745
+ message: "Module operations are required",
2746
+ details: { module: mod }
2747
+ });
2748
+ const operationErrors = mod.operations.reduce((acc, operation) => [...acc, ...validateModuleOperation(operation)], []);
2749
+ return [...errors, ...operationErrors];
2750
+ }
2751
+ function validateModuleOperation(operation) {
2752
+ const errors = [];
2753
+ if (!operation.name) errors.push({
2754
+ message: "Operation name is required",
2755
+ details: { operation }
2756
+ });
2757
+ if (!operation.schema) errors.push({
2758
+ message: "Operation schema is required",
2759
+ details: { operation }
2760
+ });
2761
+ return errors;
2762
+ }
2763
+ function validateOperations(operations) {
2764
+ const errors = [];
2765
+ const scopes = Object.keys(operations);
2766
+ for (const scope of scopes) {
2767
+ const scopeOperations = operations[scope];
2768
+ if (!scopeOperations) continue;
2769
+ const ops = scopeOperations.sort((a, b) => a.index - b.index);
2770
+ let opIndex = -1;
2771
+ for (let i = 0; i < ops.length; i++) {
2772
+ opIndex = opIndex + 1 + ops[i].skip;
2773
+ if (ops[i].index !== opIndex) errors.push({
2774
+ message: `Invalid operation index ${ops[i].index} at position ${i}`,
2775
+ details: {
2776
+ position: i,
2777
+ operation: ops[i],
2778
+ scope: ops[i].action.scope
2779
+ }
2780
+ });
2781
+ }
2782
+ }
2783
+ return errors;
2784
+ }
2785
+ //#endregion
2786
+ //#region document-model/reducers.ts
2787
+ function sorter(order) {
2788
+ const mapping = {};
2789
+ order.forEach((key, index) => mapping[key] = index);
2790
+ return (a, b) => (mapping[b.id] || 999999) - (mapping[a.id] || 999999);
2791
+ }
2792
+ const documentModelHeaderReducer = {
2793
+ setModelNameOperation(state, action) {
2794
+ state.name = action.input.name;
2795
+ },
2796
+ setModelIdOperation(state, action) {
2797
+ state.id = action.input.id;
2798
+ },
2799
+ setModelExtensionOperation(state, action) {
2800
+ state.extension = action.input.extension;
2801
+ },
2802
+ setModelDescriptionOperation(state, action) {
2803
+ state.description = action.input.description;
2804
+ },
2805
+ setAuthorNameOperation(state, action) {
2806
+ state.author = state.author || {
2807
+ name: "",
2808
+ website: null
2809
+ };
2810
+ state.author.name = action.input.authorName;
2811
+ },
2812
+ setAuthorWebsiteOperation(state, action) {
2813
+ state.author = state.author || {
2814
+ name: "",
2815
+ website: null
2816
+ };
2817
+ state.author.website = action.input.authorWebsite;
2818
+ }
2819
+ };
2820
+ const documentModelModuleReducer = {
2821
+ addModuleOperation(state, action) {
2822
+ state.specifications[state.specifications.length - 1].modules.push({
2823
+ id: action.input.id,
2824
+ name: action.input.name,
2825
+ description: action.input.description || "",
2826
+ operations: []
2827
+ });
2828
+ },
2829
+ setModuleNameOperation(state, action) {
2830
+ const latestSpec = state.specifications[state.specifications.length - 1];
2831
+ for (let i = 0; i < latestSpec.modules.length; i++) if (latestSpec.modules[i].id === action.input.id) latestSpec.modules[i].name = action.input.name || "";
2832
+ },
2833
+ setModuleDescriptionOperation(state, action) {
2834
+ const latestSpec = state.specifications[state.specifications.length - 1];
2835
+ for (let i = 0; i < latestSpec.modules.length; i++) if (latestSpec.modules[i].id === action.input.id) latestSpec.modules[i].description = action.input.description || "";
2836
+ },
2837
+ deleteModuleOperation(state, action) {
2838
+ const latestSpec = state.specifications[state.specifications.length - 1];
2839
+ latestSpec.modules = latestSpec.modules.filter((m) => m.id != action.input.id);
2840
+ },
2841
+ reorderModulesOperation(state, action) {
2842
+ state.specifications[state.specifications.length - 1].modules.sort(sorter(action.input.order));
2843
+ }
2844
+ };
2845
+ const documentModelOperationErrorReducer = {
2846
+ addOperationErrorOperation(state, action) {
2847
+ const latestSpec = state.specifications[state.specifications.length - 1];
2848
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.operationId) latestSpec.modules[i].operations[j].errors.push({
2849
+ id: action.input.id,
2850
+ name: action.input.errorName || "",
2851
+ code: action.input.errorCode || "",
2852
+ description: action.input.errorDescription || "",
2853
+ template: action.input.errorTemplate || ""
2854
+ });
2855
+ },
2856
+ setOperationErrorCodeOperation(state, action) {
2857
+ const latestSpec = state.specifications[state.specifications.length - 1];
2858
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) for (let k = 0; k < latestSpec.modules[i].operations[j].errors.length; k++) if (latestSpec.modules[i].operations[j].errors[k].id == action.input.id) latestSpec.modules[i].operations[j].errors[k].code = action.input.errorCode || "";
2859
+ },
2860
+ setOperationErrorNameOperation(state, action) {
2861
+ const latestSpec = state.specifications[state.specifications.length - 1];
2862
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) for (let k = 0; k < latestSpec.modules[i].operations[j].errors.length; k++) if (latestSpec.modules[i].operations[j].errors[k].id == action.input.id) latestSpec.modules[i].operations[j].errors[k].name = action.input.errorName || "";
2863
+ },
2864
+ setOperationErrorDescriptionOperation(state, action) {
2865
+ const latestSpec = state.specifications[state.specifications.length - 1];
2866
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) for (let k = 0; k < latestSpec.modules[i].operations[j].errors.length; k++) if (latestSpec.modules[i].operations[j].errors[k].id == action.input.id) latestSpec.modules[i].operations[j].errors[k].description = action.input.errorDescription || "";
2867
+ },
2868
+ setOperationErrorTemplateOperation(state, action) {
2869
+ const latestSpec = state.specifications[state.specifications.length - 1];
2870
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) for (let k = 0; k < latestSpec.modules[i].operations[j].errors.length; k++) if (latestSpec.modules[i].operations[j].errors[k].id == action.input.id) latestSpec.modules[i].operations[j].errors[k].template = action.input.errorTemplate || "";
2871
+ },
2872
+ deleteOperationErrorOperation(state, action) {
2873
+ const latestSpec = state.specifications[state.specifications.length - 1];
2874
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) latestSpec.modules[i].operations[j].errors = latestSpec.modules[i].operations[j].errors.filter((e) => e.id != action.input.id);
2875
+ },
2876
+ reorderOperationErrorsOperation(state, action) {
2877
+ const latestSpec = state.specifications[state.specifications.length - 1];
2878
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.operationId) latestSpec.modules[i].operations[j].errors.sort(sorter(action.input.order));
2879
+ }
2880
+ };
2881
+ const documentModelOperationExampleReducer = {
2882
+ addOperationExampleOperation(state, action) {
2883
+ const latestSpec = state.specifications[state.specifications.length - 1];
2884
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.operationId) latestSpec.modules[i].operations[j].examples.push({
2885
+ id: action.input.id,
2886
+ value: action.input.example
2887
+ });
2888
+ },
2889
+ updateOperationExampleOperation(state, action) {
2890
+ const latestSpec = state.specifications[state.specifications.length - 1];
2891
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) for (let k = 0; k < latestSpec.modules[i].operations[j].examples.length; k++) if (latestSpec.modules[i].operations[j].examples[k].id == action.input.id) latestSpec.modules[i].operations[j].examples[k].value = action.input.example;
2892
+ },
2893
+ deleteOperationExampleOperation(state, action) {
2894
+ const latestSpec = state.specifications[state.specifications.length - 1];
2895
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) latestSpec.modules[i].operations[j].examples = latestSpec.modules[i].operations[j].examples.filter((e) => e.id != action.input.id);
2896
+ },
2897
+ reorderOperationExamplesOperation(state, action) {
2898
+ const latestSpec = state.specifications[state.specifications.length - 1];
2899
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.operationId) latestSpec.modules[i].operations[j].examples.sort(sorter(action.input.order));
2900
+ }
2901
+ };
2902
+ const documentModelOperationReducer = {
2903
+ addOperationOperation(state, action) {
2904
+ validateOperationName(action.input.name, state);
2905
+ const latestSpec = state.specifications[state.specifications.length - 1];
2906
+ for (let i = 0; i < latestSpec.modules.length; i++) if (latestSpec.modules[i].id == action.input.moduleId) latestSpec.modules[i].operations.push({
2907
+ id: action.input.id,
2908
+ name: action.input.name,
2909
+ description: action.input.description || "",
2910
+ schema: action.input.schema || "",
2911
+ template: action.input.template || action.input.description || "",
2912
+ reducer: action.input.reducer || "",
2913
+ errors: [],
2914
+ examples: [],
2915
+ scope: action.input.scope || "global"
2916
+ });
2917
+ },
2918
+ setOperationNameOperation(state, action) {
2919
+ if (action.input.name) validateOperationName(action.input.name, state, action.input.id);
2920
+ const latestSpec = state.specifications[state.specifications.length - 1];
2921
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.id) latestSpec.modules[i].operations[j].name = action.input.name || "";
2922
+ },
2923
+ setOperationScopeOperation(state, action) {
2924
+ const latestSpec = state.specifications[state.specifications.length - 1];
2925
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.id) latestSpec.modules[i].operations[j].scope = action.input.scope || "global";
2926
+ },
2927
+ setOperationSchemaOperation(state, action) {
2928
+ const latestSpec = state.specifications[state.specifications.length - 1];
2929
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.id) latestSpec.modules[i].operations[j].schema = action.input.schema || "";
2930
+ },
2931
+ setOperationDescriptionOperation(state, action) {
2932
+ const latestSpec = state.specifications[state.specifications.length - 1];
2933
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.id) latestSpec.modules[i].operations[j].description = action.input.description || "";
2934
+ },
2935
+ setOperationTemplateOperation(state, action) {
2936
+ const latestSpec = state.specifications[state.specifications.length - 1];
2937
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.id) latestSpec.modules[i].operations[j].template = action.input.template || "";
2938
+ },
2939
+ setOperationReducerOperation(state, action) {
2940
+ const latestSpec = state.specifications[state.specifications.length - 1];
2941
+ for (let i = 0; i < latestSpec.modules.length; i++) for (let j = 0; j < latestSpec.modules[i].operations.length; j++) if (latestSpec.modules[i].operations[j].id == action.input.id) latestSpec.modules[i].operations[j].reducer = action.input.reducer || "";
2942
+ },
2943
+ moveOperationOperation(state, action) {
2944
+ const moveOperations = [];
2945
+ const latestSpec = state.specifications[state.specifications.length - 1];
2946
+ for (let i = 0; i < latestSpec.modules.length; i++) latestSpec.modules[i].operations = latestSpec.modules[i].operations.filter((operation) => {
2947
+ if (operation.id == action.input.operationId) {
2948
+ moveOperations.push(operation);
2949
+ return false;
2950
+ }
2951
+ return true;
2952
+ });
2953
+ for (let i = 0; i < latestSpec.modules.length; i++) if (latestSpec.modules[i].id == action.input.newModuleId) latestSpec.modules[i].operations.push(...moveOperations);
2954
+ },
2955
+ deleteOperationOperation(state, action) {
2956
+ const latestSpec = state.specifications[state.specifications.length - 1];
2957
+ for (let i = 0; i < latestSpec.modules.length; i++) latestSpec.modules[i].operations = latestSpec.modules[i].operations.filter((operation) => operation.id != action.input.id);
2958
+ },
2959
+ reorderModuleOperationsOperation(state, action) {
2960
+ const latestSpec = state.specifications[state.specifications.length - 1];
2961
+ for (let i = 0; i < latestSpec.modules.length; i++) if (latestSpec.modules[i].id == action.input.moduleId) latestSpec.modules[i].operations.sort(sorter(action.input.order));
2962
+ }
2963
+ };
2964
+ const documentModelStateSchemaReducer = {
2965
+ setStateSchemaOperation(state, action) {
2966
+ const latestSpec = state.specifications[state.specifications.length - 1];
2967
+ if (Object.keys(latestSpec.state).includes(action.input.scope)) latestSpec.state[action.input.scope].schema = action.input.schema;
2968
+ else throw new Error(`Invalid scope: ${action.input.scope}`);
2969
+ },
2970
+ setInitialStateOperation(state, action) {
2971
+ const latestSpec = state.specifications[state.specifications.length - 1];
2972
+ if (Object.keys(latestSpec.state).includes(action.input.scope)) latestSpec.state[action.input.scope].initialValue = action.input.initialValue;
2973
+ else throw new Error(`Invalid scope: ${action.input.scope}`);
2974
+ },
2975
+ addStateExampleOperation(state, action) {
2976
+ const latestSpec = state.specifications[state.specifications.length - 1];
2977
+ if (Object.keys(latestSpec.state).includes(action.input.scope)) latestSpec.state[action.input.scope].examples.push({
2978
+ id: action.input.id,
2979
+ value: action.input.example
2980
+ });
2981
+ else throw new Error(`Invalid scope: ${action.input.scope}`);
2982
+ },
2983
+ updateStateExampleOperation(state, action) {
2984
+ const latestSpec = state.specifications[state.specifications.length - 1];
2985
+ if (!Object.keys(latestSpec.state).includes(action.input.scope)) throw new Error(`Invalid scope: ${action.input.scope}`);
2986
+ const examples = latestSpec.state[action.input.scope].examples;
2987
+ for (let i = 0; i < examples.length; i++) if (examples[i].id == action.input.id) examples[i].value = action.input.newExample;
2988
+ },
2989
+ deleteStateExampleOperation(state, action) {
2990
+ const latestSpec = state.specifications[state.specifications.length - 1];
2991
+ if (Object.keys(latestSpec.state).includes(action.input.scope)) latestSpec.state[action.input.scope].examples = latestSpec.state[action.input.scope].examples.filter((e) => e.id != action.input.id);
2992
+ else throw new Error(`Invalid scope: ${action.input.scope}`);
2993
+ },
2994
+ reorderStateExamplesOperation(state, action) {
2995
+ const latestSpec = state.specifications[state.specifications.length - 1];
2996
+ if (Object.keys(latestSpec.state).includes(action.input.scope)) latestSpec.state[action.input.scope].examples.sort(sorter(action.input.order));
2997
+ else throw new Error(`Invalid scope: ${action.input.scope}`);
2998
+ }
2999
+ };
3000
+ const documentModelVersioningReducer = {
3001
+ addChangeLogItemOperation(state, action) {
3002
+ throw new Error("Reducer \"addChangeLogItemOperation\" not yet implemented");
3003
+ },
3004
+ updateChangeLogItemOperation(state, action) {
3005
+ throw new Error("Reducer \"updateChangeLogItemOperation\" not yet implemented");
3006
+ },
3007
+ deleteChangeLogItemOperation(state, action) {
3008
+ throw new Error("Reducer \"deleteChangeLogItemOperation\" not yet implemented");
3009
+ },
3010
+ reorderChangeLogItemsOperation(state, action) {
3011
+ throw new Error("Reducer \"reorderChangeLogItemsOperation\" not yet implemented");
3012
+ },
3013
+ releaseNewVersionOperation(state, action) {
3014
+ const latestSpec = state.specifications[state.specifications.length - 1];
3015
+ const copiedModules = latestSpec.modules.map((module) => ({
3016
+ ...module,
3017
+ operations: module.operations.map((op) => ({
3018
+ ...op,
3019
+ errors: op.errors.map((err) => ({ ...err })),
3020
+ examples: op.examples.map((ex) => ({ ...ex }))
3021
+ }))
3022
+ }));
3023
+ const copiedState = {
3024
+ global: {
3025
+ ...latestSpec.state.global,
3026
+ examples: latestSpec.state.global.examples.map((ex) => ({ ...ex }))
3027
+ },
3028
+ local: {
3029
+ ...latestSpec.state.local,
3030
+ examples: latestSpec.state.local.examples.map((ex) => ({ ...ex }))
3031
+ }
3032
+ };
3033
+ const newSpec = {
3034
+ version: latestSpec.version + 1,
3035
+ changeLog: [],
3036
+ state: copiedState,
3037
+ modules: copiedModules
3038
+ };
3039
+ state.specifications.push(newSpec);
3040
+ }
3041
+ };
3042
+ const documentModelStateReducer = (state, action) => {
3043
+ if (isDocumentAction(action)) return state;
3044
+ switch (action.type) {
3045
+ case "SET_MODEL_NAME":
3046
+ SetModelNameInputSchema().parse(action.input);
3047
+ documentModelHeaderReducer.setModelNameOperation(state.global, action);
3048
+ break;
3049
+ case "SET_MODEL_ID":
3050
+ SetModelIdInputSchema().parse(action.input);
3051
+ documentModelHeaderReducer.setModelIdOperation(state.global, action);
3052
+ break;
3053
+ case "SET_MODEL_EXTENSION":
3054
+ SetModelExtensionInputSchema().parse(action.input);
3055
+ documentModelHeaderReducer.setModelExtensionOperation(state.global, action);
3056
+ break;
3057
+ case "SET_MODEL_DESCRIPTION":
3058
+ SetModelDescriptionInputSchema().parse(action.input);
3059
+ documentModelHeaderReducer.setModelDescriptionOperation(state.global, action);
3060
+ break;
3061
+ case "SET_AUTHOR_NAME":
3062
+ SetAuthorNameInputSchema().parse(action.input);
3063
+ documentModelHeaderReducer.setAuthorNameOperation(state.global, action);
3064
+ break;
3065
+ case "SET_AUTHOR_WEBSITE":
3066
+ SetAuthorWebsiteInputSchema().parse(action.input);
3067
+ documentModelHeaderReducer.setAuthorWebsiteOperation(state.global, action);
3068
+ break;
3069
+ case "ADD_CHANGE_LOG_ITEM":
3070
+ AddChangeLogItemInputSchema().parse(action.input);
3071
+ documentModelVersioningReducer.addChangeLogItemOperation(state.global, action);
3072
+ break;
3073
+ case "UPDATE_CHANGE_LOG_ITEM":
3074
+ UpdateChangeLogItemInputSchema().parse(action.input);
3075
+ documentModelVersioningReducer.updateChangeLogItemOperation(state.global, action);
3076
+ break;
3077
+ case "DELETE_CHANGE_LOG_ITEM":
3078
+ DeleteChangeLogItemInputSchema().parse(action.input);
3079
+ documentModelVersioningReducer.deleteChangeLogItemOperation(state.global, action);
3080
+ break;
3081
+ case "REORDER_CHANGE_LOG_ITEMS":
3082
+ ReorderChangeLogItemsInputSchema().parse(action.input);
3083
+ documentModelVersioningReducer.reorderChangeLogItemsOperation(state.global, action);
3084
+ break;
3085
+ case "RELEASE_NEW_VERSION":
3086
+ if (Object.keys(action.input).length > 0) throw new Error("Expected empty input for action RELEASE_NEW_VERSION");
3087
+ documentModelVersioningReducer.releaseNewVersionOperation(state.global, action);
3088
+ break;
3089
+ case "ADD_MODULE":
3090
+ AddModuleInputSchema().parse(action.input);
3091
+ documentModelModuleReducer.addModuleOperation(state.global, action);
3092
+ break;
3093
+ case "SET_MODULE_NAME":
3094
+ SetModuleNameInputSchema().parse(action.input);
3095
+ documentModelModuleReducer.setModuleNameOperation(state.global, action);
3096
+ break;
3097
+ case "SET_MODULE_DESCRIPTION":
3098
+ SetModuleDescriptionInputSchema().parse(action.input);
3099
+ documentModelModuleReducer.setModuleDescriptionOperation(state.global, action);
3100
+ break;
3101
+ case "DELETE_MODULE":
3102
+ DeleteModuleInputSchema().parse(action.input);
3103
+ documentModelModuleReducer.deleteModuleOperation(state.global, action);
3104
+ break;
3105
+ case "REORDER_MODULES":
3106
+ ReorderModulesInputSchema().parse(action.input);
3107
+ documentModelModuleReducer.reorderModulesOperation(state.global, action);
3108
+ break;
3109
+ case "ADD_OPERATION_ERROR":
3110
+ AddOperationErrorInputSchema().parse(action.input);
3111
+ documentModelOperationErrorReducer.addOperationErrorOperation(state.global, action);
3112
+ break;
3113
+ case "SET_OPERATION_ERROR_CODE":
3114
+ SetOperationErrorCodeInputSchema().parse(action.input);
3115
+ documentModelOperationErrorReducer.setOperationErrorCodeOperation(state.global, action);
3116
+ break;
3117
+ case "SET_OPERATION_ERROR_NAME":
3118
+ SetOperationErrorNameInputSchema().parse(action.input);
3119
+ documentModelOperationErrorReducer.setOperationErrorNameOperation(state.global, action);
3120
+ break;
3121
+ case "SET_OPERATION_ERROR_DESCRIPTION":
3122
+ SetOperationErrorDescriptionInputSchema().parse(action.input);
3123
+ documentModelOperationErrorReducer.setOperationErrorDescriptionOperation(state.global, action);
3124
+ break;
3125
+ case "SET_OPERATION_ERROR_TEMPLATE":
3126
+ SetOperationErrorTemplateInputSchema().parse(action.input);
3127
+ documentModelOperationErrorReducer.setOperationErrorTemplateOperation(state.global, action);
3128
+ break;
3129
+ case "DELETE_OPERATION_ERROR":
3130
+ DeleteOperationErrorInputSchema().parse(action.input);
3131
+ documentModelOperationErrorReducer.deleteOperationErrorOperation(state.global, action);
3132
+ break;
3133
+ case "REORDER_OPERATION_ERRORS":
3134
+ ReorderOperationErrorsInputSchema().parse(action.input);
3135
+ documentModelOperationErrorReducer.reorderOperationErrorsOperation(state.global, action);
3136
+ break;
3137
+ case "ADD_OPERATION_EXAMPLE":
3138
+ AddOperationExampleInputSchema().parse(action.input);
3139
+ documentModelOperationExampleReducer.addOperationExampleOperation(state.global, action);
3140
+ break;
3141
+ case "UPDATE_OPERATION_EXAMPLE":
3142
+ UpdateOperationExampleInputSchema().parse(action.input);
3143
+ documentModelOperationExampleReducer.updateOperationExampleOperation(state.global, action);
3144
+ break;
3145
+ case "DELETE_OPERATION_EXAMPLE":
3146
+ DeleteOperationExampleInputSchema().parse(action.input);
3147
+ documentModelOperationExampleReducer.deleteOperationExampleOperation(state.global, action);
3148
+ break;
3149
+ case "REORDER_OPERATION_EXAMPLES":
3150
+ ReorderOperationExamplesInputSchema().parse(action.input);
3151
+ documentModelOperationExampleReducer.reorderOperationExamplesOperation(state.global, action);
3152
+ break;
3153
+ case "ADD_OPERATION":
3154
+ AddOperationInputSchema().parse(action.input);
3155
+ documentModelOperationReducer.addOperationOperation(state.global, action);
3156
+ break;
3157
+ case "SET_OPERATION_NAME":
3158
+ SetOperationNameInputSchema().parse(action.input);
3159
+ documentModelOperationReducer.setOperationNameOperation(state.global, action);
3160
+ break;
3161
+ case "SET_OPERATION_SCOPE":
3162
+ SetOperationScopeInputSchema().parse(action.input);
3163
+ documentModelOperationReducer.setOperationScopeOperation(state.global, action);
3164
+ break;
3165
+ case "SET_OPERATION_SCHEMA":
3166
+ SetOperationSchemaInputSchema().parse(action.input);
3167
+ documentModelOperationReducer.setOperationSchemaOperation(state.global, action);
3168
+ break;
3169
+ case "SET_OPERATION_DESCRIPTION":
3170
+ SetOperationDescriptionInputSchema().parse(action.input);
3171
+ documentModelOperationReducer.setOperationDescriptionOperation(state.global, action);
3172
+ break;
3173
+ case "SET_OPERATION_TEMPLATE":
3174
+ SetOperationTemplateInputSchema().parse(action.input);
3175
+ documentModelOperationReducer.setOperationTemplateOperation(state.global, action);
3176
+ break;
3177
+ case "SET_OPERATION_REDUCER":
3178
+ SetOperationReducerInputSchema().parse(action.input);
3179
+ documentModelOperationReducer.setOperationReducerOperation(state.global, action);
3180
+ break;
3181
+ case "MOVE_OPERATION":
3182
+ MoveOperationInputSchema().parse(action.input);
3183
+ documentModelOperationReducer.moveOperationOperation(state.global, action);
3184
+ break;
3185
+ case "DELETE_OPERATION":
3186
+ DeleteOperationInputSchema().parse(action.input);
3187
+ documentModelOperationReducer.deleteOperationOperation(state.global, action);
3188
+ break;
3189
+ case "REORDER_MODULE_OPERATIONS":
3190
+ ReorderModuleOperationsInputSchema().parse(action.input);
3191
+ documentModelOperationReducer.reorderModuleOperationsOperation(state.global, action);
3192
+ break;
3193
+ case "SET_STATE_SCHEMA":
3194
+ SetStateSchemaInputSchema().parse(action.input);
3195
+ documentModelStateSchemaReducer.setStateSchemaOperation(state.global, action);
3196
+ break;
3197
+ case "SET_INITIAL_STATE":
3198
+ SetInitialStateInputSchema().parse(action.input);
3199
+ documentModelStateSchemaReducer.setInitialStateOperation(state.global, action);
3200
+ break;
3201
+ case "ADD_STATE_EXAMPLE":
3202
+ AddStateExampleInputSchema().parse(action.input);
3203
+ documentModelStateSchemaReducer.addStateExampleOperation(state.global, action);
3204
+ break;
3205
+ case "UPDATE_STATE_EXAMPLE":
3206
+ UpdateStateExampleInputSchema().parse(action.input);
3207
+ documentModelStateSchemaReducer.updateStateExampleOperation(state.global, action);
3208
+ break;
3209
+ case "DELETE_STATE_EXAMPLE":
3210
+ DeleteStateExampleInputSchema().parse(action.input);
3211
+ documentModelStateSchemaReducer.deleteStateExampleOperation(state.global, action);
3212
+ break;
3213
+ case "REORDER_STATE_EXAMPLES":
3214
+ ReorderStateExamplesInputSchema().parse(action.input);
3215
+ documentModelStateSchemaReducer.reorderStateExamplesOperation(state.global, action);
3216
+ break;
3217
+ default: return state;
3218
+ }
3219
+ };
3220
+ const documentModelReducer = createReducer(documentModelStateReducer);
3221
+ //#endregion
3222
+ //#region document-model/files.ts
3223
+ function createZip(document) {
3224
+ const zip = new JSZip();
3225
+ const header = document.header;
3226
+ zip.file("header.json", JSON.stringify(header, null, 2));
3227
+ zip.file("state.json", JSON.stringify(document.initialState || {}, null, 2));
3228
+ zip.file("current-state.json", JSON.stringify(document.state || {}, null, 2));
3229
+ zip.file("operations.json", JSON.stringify(filterDocumentOperationsResultingState(document.operations), null, 2));
3230
+ return zip;
3231
+ }
3232
+ /**
3233
+ * Creates a minimal ZIP backup from strand data.
3234
+ * Used when the full document is not available (e.g., in onOperations handler).
3235
+ * Creates a ZIP with minimal header and empty operations.
3236
+ */
3237
+ function createMinimalZip(data) {
3238
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3239
+ const header = {
3240
+ id: data.documentId,
3241
+ sig: {
3242
+ publicKey: {},
3243
+ nonce: ""
3244
+ },
3245
+ documentType: data.documentType,
3246
+ createdAtUtcIso: now,
3247
+ slug: data.name,
3248
+ name: data.name,
3249
+ branch: data.branch,
3250
+ revision: {},
3251
+ lastModifiedAtUtcIso: now
3252
+ };
3253
+ const zip = new JSZip();
3254
+ zip.file("header.json", JSON.stringify(header, null, 2));
3255
+ zip.file("state.json", JSON.stringify(data.state, null, 2));
3256
+ zip.file("current-state.json", JSON.stringify(data.state, null, 2));
3257
+ zip.file("operations.json", JSON.stringify({}, null, 2));
3258
+ return zip;
3259
+ }
3260
+ async function baseSaveToFileHandle(document, input) {
3261
+ const blob = await createZip(document).generateAsync({ type: "blob" });
3262
+ const writable = await input.createWritable();
3263
+ await writable.write(blob);
3264
+ await writable.close();
3265
+ }
3266
+ async function loadFromZip(zip, reducer, options) {
3267
+ const initialStateZip = zip.file("state.json");
3268
+ if (!initialStateZip) throw new Error("Initial state not found");
3269
+ const initialStateStr = await initialStateZip.async("string");
3270
+ const initialState = JSON.parse(initialStateStr);
3271
+ const headerZip = zip.file("header.json");
3272
+ if (!headerZip) throw new Error("Document header not found - file format may be outdated");
3273
+ const header = JSON.parse(await headerZip.async("string"));
3274
+ const operationsZip = zip.file("operations.json");
3275
+ if (!operationsZip) throw new Error("Operations history not found");
3276
+ const clearedOperations = garbageCollectDocumentOperations(JSON.parse(await operationsZip.async("string")));
3277
+ const operationsError = validateOperations(clearedOperations);
3278
+ if (operationsError.length) {
3279
+ const errorMessages = operationsError.map((err) => err.message);
3280
+ throw new Error(errorMessages.join("\n"));
3281
+ }
3282
+ return replayDocument(initialState, clearedOperations, reducer, header, void 0, {}, options);
3283
+ }
3284
+ async function baseLoadFromInput(input, reducer, options) {
3285
+ const zip = new JSZip();
3286
+ await zip.loadAsync(input);
3287
+ return loadFromZip(zip, reducer, options);
3288
+ }
3289
+ const documentModelLoadFromInput = (input) => {
3290
+ return baseLoadFromInput(input, documentModelReducer);
3291
+ };
3292
+ const documentModelSaveToFileHandle = (document, input) => {
3293
+ return baseSaveToFileHandle(document, input);
3294
+ };
3295
+ function writeFileBrowser(path, name, stream) {
3296
+ throw FileSystemError;
3297
+ }
3298
+ function readFileBrowser(path) {
3299
+ throw FileSystemError;
3300
+ }
3301
+ function fetchFileBrowser(url) {
3302
+ throw FileSystemError;
3303
+ }
3304
+ const getFileBrowser = async (file) => {
3305
+ return readFileBrowser(file);
3306
+ };
3307
+ //#endregion
3308
+ //#region document-model/state.ts
3309
+ /**
3310
+ * Creates a default PHAuthState
3311
+ */
3312
+ function defaultAuthState() {
3313
+ return {};
3314
+ }
3315
+ /**
3316
+ * Creates a default PHDocumentState
3317
+ */
3318
+ function defaultDocumentState() {
3319
+ return {
3320
+ version: 0,
3321
+ hash: {
3322
+ algorithm: HASH_ALGORITHM_SHA1,
3323
+ encoding: HASH_ENCODING_BASE64
3324
+ }
3325
+ };
3326
+ }
3327
+ /**
3328
+ * Creates a default PHBaseState with auth and document properties
3329
+ */
3330
+ function defaultBaseState() {
3331
+ return {
3332
+ auth: defaultAuthState(),
3333
+ document: defaultDocumentState()
3334
+ };
3335
+ }
3336
+ /**
3337
+ * Creates a PHAuthState with the given properties
3338
+ */
3339
+ function createAuthState(auth) {
3340
+ return {
3341
+ ...defaultAuthState(),
3342
+ ...auth
3343
+ };
3344
+ }
3345
+ /**
3346
+ * Creates a PHDocumentState with the given properties
3347
+ */
3348
+ function createDocumentState(document) {
3349
+ return {
3350
+ ...defaultDocumentState(),
3351
+ ...document
3352
+ };
3353
+ }
3354
+ /**
3355
+ * Creates a PHBaseState with the given auth and document properties
3356
+ */
3357
+ function createBaseState(auth, document) {
3358
+ return {
3359
+ auth: createAuthState(auth),
3360
+ document: createDocumentState(document)
3361
+ };
3362
+ }
3363
+ function defaultGlobalState() {
3364
+ return {
3365
+ ...defaultBaseState(),
3366
+ author: {
3367
+ name: "",
3368
+ website: ""
3369
+ },
3370
+ description: "",
3371
+ extension: "",
3372
+ id: "",
3373
+ name: "",
3374
+ specifications: []
3375
+ };
3376
+ }
3377
+ function defaultLocalState() {
3378
+ return {};
3379
+ }
3380
+ function defaultPHState() {
3381
+ return {
3382
+ ...defaultBaseState(),
3383
+ global: defaultGlobalState(),
3384
+ local: defaultLocalState()
3385
+ };
3386
+ }
3387
+ function createGlobalState(state) {
3388
+ return {
3389
+ ...defaultGlobalState(),
3390
+ ...state || {}
3391
+ };
3392
+ }
3393
+ function createLocalState(state) {
3394
+ return {
3395
+ ...defaultLocalState(),
3396
+ ...state || {}
3397
+ };
3398
+ }
3399
+ function createState(baseState, globalState, localState) {
3400
+ return {
3401
+ ...createBaseState(baseState?.auth, baseState?.document),
3402
+ global: createGlobalState(globalState),
3403
+ local: createLocalState(localState)
3404
+ };
3405
+ }
3406
+ //#endregion
3407
+ export { AddChangeLogItemInputSchema, AddModuleInputSchema, AddOperationErrorInputSchema, AddOperationExampleInputSchema, AddOperationInputSchema, AddStateExampleInputSchema, AuthorSchema, BaseDocumentHeaderSchema, BaseDocumentStateSchema, CodeExampleSchema, DeleteChangeLogItemInputSchema, DeleteModuleInputSchema, DeleteOperationErrorInputSchema, DeleteOperationExampleInputSchema, DeleteOperationInputSchema, DeleteStateExampleInputSchema, DocumentActionSchema, DocumentFileSchema, DocumentModelGlobalStateSchema, DocumentModelHeaderSchema, DocumentModelInputSchema, DocumentModelPHStateSchema, DocumentModelSchema, DocumentSpecificationSchema, FileSystemError, HASH_ALGORITHM_SHA1, HASH_ALGORITHM_SHA256, HASH_ALGORITHM_SHA512, HASH_ENCODING_BASE64, HASH_ENCODING_HEX, HashMismatchError, IntegrityIssueSubType, IntegrityIssueType, InvalidActionInputError, InvalidActionInputZodError, LoadStateActionInputSchema, LoadStateActionSchema, LoadStateActionStateInputSchema, Load_StateSchema, ModuleSchema, MoveOperationInputSchema, OperationErrorSchema, OperationScopeSchema, OperationSpecificationSchema, PruneActionInputSchema, PruneActionSchema, PruneSchema, RESERVED_OPERATION_NAMES, RedoActionInputSchema, RedoActionSchema, RedoSchema, ReorderChangeLogItemsInputSchema, ReorderModuleOperationsInputSchema, ReorderModulesInputSchema, ReorderOperationErrorsInputSchema, ReorderOperationExamplesInputSchema, ReorderStateExamplesInputSchema, ScopeStateSchema, SetAuthorNameInputSchema, SetAuthorWebsiteInputSchema, SetInitialStateInputSchema, SetModelDescriptionInputSchema, SetModelExtensionInputSchema, SetModelIdInputSchema, SetModelNameInputSchema, SetModuleDescriptionInputSchema, SetModuleNameInputSchema, SetNameActionInputSchema, SetNameActionSchema, SetOperationDescriptionInputSchema, SetOperationErrorCodeInputSchema, SetOperationErrorDescriptionInputSchema, SetOperationErrorNameInputSchema, SetOperationErrorTemplateInputSchema, SetOperationNameInputSchema, SetOperationReducerInputSchema, SetOperationSchemaInputSchema, SetOperationScopeInputSchema, SetOperationTemplateInputSchema, SetStateSchemaInputSchema, Set_NameSchema, StateSchema, UndoActionInputSchema, UndoActionSchema, UndoSchema, UpdateChangeLogItemInputSchema, UpdateOperationExampleInputSchema, UpdateStateExampleInputSchema, ab2hex, actionContext, actionFromAction, actionSigner, actions, addChangeLogItem, addModule, addOperation, addOperationError, addOperationExample, addStateExample, addUndo, assertIsDocumentModelDocument, assertIsDocumentModelState, attachBranch, baseActions, baseCreateDocument, baseLoadFromInput, baseReducer, baseSaveToFileHandle, buildOperationSignature, buildOperationSignatureMessage, buildOperationSignatureParams, buildSignedAction, checkCleanedOperationsIntegrity, checkOperationsIntegrity, createAction, createAuthState, createBaseState, createDocumentState, createGlobalState, createLocalState, createMinimalZip, createPresignedHeader, createReducer, createSignedHeader, createSignedHeaderForSigner, createState, createVerificationSigner, createZip, defaultAuthState, defaultBaseState, defaultDocumentState, defaultGlobalState, defaultLocalState, defaultPHState, definedNonNullAnySchema, deleteChangeLogItem, deleteModule, deleteOperation, deleteOperationError, deleteOperationExample, deleteStateExample, deriveOperationId, diffOperations, documentModelActions, documentModelDocumentType, documentModelFileExtension, documentModelGlobalState, documentModelHeaderReducer, documentModelInitialGlobalState, documentModelInitialLocalState, documentModelLoadFromInput, documentModelModuleReducer, documentModelOperationErrorReducer, documentModelOperationExampleReducer, documentModelOperationReducer, documentModelReducer, documentModelSaveToFileHandle, documentModelStateReducer, documentModelStateSchemaReducer, documentModelVersioningReducer, fetchFileBrowser, filterDocumentOperationsResultingState, filterDuplicatedOperations, garbageCollect, garbageCollectDocumentOperations, garbageCollectV2, generateId, getAllOperationNames, getDocumentLastModified, getFileBrowser, getUnixTimestamp, groupOperationsByScope, hashBrowser, hashDocumentStateForScope, hex2ab, isDefinedNonNullAny, isDocumentAction, isDocumentModelDocument, isDocumentModelState, isNoopOperation, isReservedOperationName, isUndo, isUndoRedo, loadState, loadStateOperation, mapSkippedOperations, mapSkippedOperationsV2, merge, moveOperation, nextSkipNumber, noop, operationExampleCreators, operationFromAction, operationFromOperation, operationWithContext, operationsAreEqual, parseResultingState, precedes, prepareOperations, processUndoRedo, prune, pruneOperation, readFileBrowser, readOnly, redo, redoOperation, releaseNewVersion, removeExistingOperations, reorderChangeLogItems, reorderModuleOperations, reorderModules, reorderOperationErrors, reorderOperationExamples, reorderStateExamples, replayDocument, replayOperations, reshuffleByTimestamp, reshuffleByTimestampAndIndex, setAuthorName, setAuthorWebsite, setInitialState, setModelDescription, setModelExtension, setModelId, setModelName, setModuleDescription, setModuleName, setName, setNameOperation, setOperationDescription, setOperationErrorCode, setOperationErrorDescription, setOperationErrorName, setOperationErrorTemplate, setOperationName, setOperationReducer, setOperationSchema, setOperationScope, setOperationTemplate, setStateSchema, sign, skipHeaderOperations, sortMappedOperations, sortOperations, split, undo, undoOperation, undoOperationV2, updateChangeLogItem, updateDocument, updateHeaderRevision, updateOperationExample, updateStateExample, validateHeader, validateInitialState, validateModule, validateModuleOperation, validateModules, validateOperationName, validateOperations, validateStateSchemaName, verify, verifyOperationSignature, writeFileBrowser };
3408
+
3
3409
  //# sourceMappingURL=index.js.map