@pstdio/sdk 0.44.0 → 0.45.0-nightly.20261020145025

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.
@@ -1,4 +1,36 @@
1
+ var __create = Object.create;
2
+ var __getProtoOf = Object.getPrototypeOf;
1
3
  var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ function __accessProp(key) {
7
+ return this[key];
8
+ }
9
+ var __toESMCache_node;
10
+ var __toESMCache_esm;
11
+ var __toESM = (mod, isNodeMode, target) => {
12
+ var canCache = mod != null && typeof mod === "object";
13
+ if (canCache) {
14
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
15
+ var cached = cache.get(mod);
16
+ if (cached)
17
+ return cached;
18
+ }
19
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
20
+ const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
21
+ if (mod && typeof mod === "object" || typeof mod === "function") {
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ }
29
+ if (canCache)
30
+ cache.set(mod, to);
31
+ return to;
32
+ };
33
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
2
34
  var __returnValue = (v) => v;
3
35
  function __exportSetter(name, newValue) {
4
36
  this[name] = __returnValue.bind(null, newValue);
@@ -13,6 +45,730 @@ var __export = (target, all) => {
13
45
  });
14
46
  };
15
47
 
48
+ // ../../node_modules/.bun/fast-diff@1.3.0/node_modules/fast-diff/diff.js
49
+ var require_diff = __commonJS(function(exports, module) {
50
+ var DIFF_DELETE = -1;
51
+ var DIFF_INSERT = 1;
52
+ var DIFF_EQUAL = 0;
53
+ function diff_main(text1, text2, cursor_pos, cleanup, _fix_unicode) {
54
+ if (text1 === text2) {
55
+ if (text1) {
56
+ return [[DIFF_EQUAL, text1]];
57
+ }
58
+ return [];
59
+ }
60
+ if (cursor_pos != null) {
61
+ var editdiff = find_cursor_edit_diff(text1, text2, cursor_pos);
62
+ if (editdiff) {
63
+ return editdiff;
64
+ }
65
+ }
66
+ var commonlength = diff_commonPrefix(text1, text2);
67
+ var commonprefix = text1.substring(0, commonlength);
68
+ text1 = text1.substring(commonlength);
69
+ text2 = text2.substring(commonlength);
70
+ commonlength = diff_commonSuffix(text1, text2);
71
+ var commonsuffix = text1.substring(text1.length - commonlength);
72
+ text1 = text1.substring(0, text1.length - commonlength);
73
+ text2 = text2.substring(0, text2.length - commonlength);
74
+ var diffs = diff_compute_(text1, text2);
75
+ if (commonprefix) {
76
+ diffs.unshift([DIFF_EQUAL, commonprefix]);
77
+ }
78
+ if (commonsuffix) {
79
+ diffs.push([DIFF_EQUAL, commonsuffix]);
80
+ }
81
+ diff_cleanupMerge(diffs, _fix_unicode);
82
+ if (cleanup) {
83
+ diff_cleanupSemantic(diffs);
84
+ }
85
+ return diffs;
86
+ }
87
+ function diff_compute_(text1, text2) {
88
+ var diffs;
89
+ if (!text1) {
90
+ return [[DIFF_INSERT, text2]];
91
+ }
92
+ if (!text2) {
93
+ return [[DIFF_DELETE, text1]];
94
+ }
95
+ var longtext = text1.length > text2.length ? text1 : text2;
96
+ var shorttext = text1.length > text2.length ? text2 : text1;
97
+ var i = longtext.indexOf(shorttext);
98
+ if (i !== -1) {
99
+ diffs = [
100
+ [DIFF_INSERT, longtext.substring(0, i)],
101
+ [DIFF_EQUAL, shorttext],
102
+ [DIFF_INSERT, longtext.substring(i + shorttext.length)]
103
+ ];
104
+ if (text1.length > text2.length) {
105
+ diffs[0][0] = diffs[2][0] = DIFF_DELETE;
106
+ }
107
+ return diffs;
108
+ }
109
+ if (shorttext.length === 1) {
110
+ return [
111
+ [DIFF_DELETE, text1],
112
+ [DIFF_INSERT, text2]
113
+ ];
114
+ }
115
+ var hm = diff_halfMatch_(text1, text2);
116
+ if (hm) {
117
+ var text1_a = hm[0];
118
+ var text1_b = hm[1];
119
+ var text2_a = hm[2];
120
+ var text2_b = hm[3];
121
+ var mid_common = hm[4];
122
+ var diffs_a = diff_main(text1_a, text2_a);
123
+ var diffs_b = diff_main(text1_b, text2_b);
124
+ return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b);
125
+ }
126
+ return diff_bisect_(text1, text2);
127
+ }
128
+ function diff_bisect_(text1, text2) {
129
+ var text1_length = text1.length;
130
+ var text2_length = text2.length;
131
+ var max_d = Math.ceil((text1_length + text2_length) / 2);
132
+ var v_offset = max_d;
133
+ var v_length = 2 * max_d;
134
+ var v1 = new Array(v_length);
135
+ var v2 = new Array(v_length);
136
+ for (var x = 0;x < v_length; x++) {
137
+ v1[x] = -1;
138
+ v2[x] = -1;
139
+ }
140
+ v1[v_offset + 1] = 0;
141
+ v2[v_offset + 1] = 0;
142
+ var delta = text1_length - text2_length;
143
+ var front = delta % 2 !== 0;
144
+ var k1start = 0;
145
+ var k1end = 0;
146
+ var k2start = 0;
147
+ var k2end = 0;
148
+ for (var d = 0;d < max_d; d++) {
149
+ for (var k1 = -d + k1start;k1 <= d - k1end; k1 += 2) {
150
+ var k1_offset = v_offset + k1;
151
+ var x1;
152
+ if (k1 === -d || k1 !== d && v1[k1_offset - 1] < v1[k1_offset + 1]) {
153
+ x1 = v1[k1_offset + 1];
154
+ } else {
155
+ x1 = v1[k1_offset - 1] + 1;
156
+ }
157
+ var y1 = x1 - k1;
158
+ while (x1 < text1_length && y1 < text2_length && text1.charAt(x1) === text2.charAt(y1)) {
159
+ x1++;
160
+ y1++;
161
+ }
162
+ v1[k1_offset] = x1;
163
+ if (x1 > text1_length) {
164
+ k1end += 2;
165
+ } else if (y1 > text2_length) {
166
+ k1start += 2;
167
+ } else if (front) {
168
+ var k2_offset = v_offset + delta - k1;
169
+ if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] !== -1) {
170
+ var x2 = text1_length - v2[k2_offset];
171
+ if (x1 >= x2) {
172
+ return diff_bisectSplit_(text1, text2, x1, y1);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ for (var k2 = -d + k2start;k2 <= d - k2end; k2 += 2) {
178
+ var k2_offset = v_offset + k2;
179
+ var x2;
180
+ if (k2 === -d || k2 !== d && v2[k2_offset - 1] < v2[k2_offset + 1]) {
181
+ x2 = v2[k2_offset + 1];
182
+ } else {
183
+ x2 = v2[k2_offset - 1] + 1;
184
+ }
185
+ var y2 = x2 - k2;
186
+ while (x2 < text1_length && y2 < text2_length && text1.charAt(text1_length - x2 - 1) === text2.charAt(text2_length - y2 - 1)) {
187
+ x2++;
188
+ y2++;
189
+ }
190
+ v2[k2_offset] = x2;
191
+ if (x2 > text1_length) {
192
+ k2end += 2;
193
+ } else if (y2 > text2_length) {
194
+ k2start += 2;
195
+ } else if (!front) {
196
+ var k1_offset = v_offset + delta - k2;
197
+ if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] !== -1) {
198
+ var x1 = v1[k1_offset];
199
+ var y1 = v_offset + x1 - k1_offset;
200
+ x2 = text1_length - x2;
201
+ if (x1 >= x2) {
202
+ return diff_bisectSplit_(text1, text2, x1, y1);
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+ return [
209
+ [DIFF_DELETE, text1],
210
+ [DIFF_INSERT, text2]
211
+ ];
212
+ }
213
+ function diff_bisectSplit_(text1, text2, x, y) {
214
+ var text1a = text1.substring(0, x);
215
+ var text2a = text2.substring(0, y);
216
+ var text1b = text1.substring(x);
217
+ var text2b = text2.substring(y);
218
+ var diffs = diff_main(text1a, text2a);
219
+ var diffsb = diff_main(text1b, text2b);
220
+ return diffs.concat(diffsb);
221
+ }
222
+ function diff_commonPrefix(text1, text2) {
223
+ if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) {
224
+ return 0;
225
+ }
226
+ var pointermin = 0;
227
+ var pointermax = Math.min(text1.length, text2.length);
228
+ var pointermid = pointermax;
229
+ var pointerstart = 0;
230
+ while (pointermin < pointermid) {
231
+ if (text1.substring(pointerstart, pointermid) == text2.substring(pointerstart, pointermid)) {
232
+ pointermin = pointermid;
233
+ pointerstart = pointermin;
234
+ } else {
235
+ pointermax = pointermid;
236
+ }
237
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
238
+ }
239
+ if (is_surrogate_pair_start(text1.charCodeAt(pointermid - 1))) {
240
+ pointermid--;
241
+ }
242
+ return pointermid;
243
+ }
244
+ function diff_commonOverlap_(text1, text2) {
245
+ var text1_length = text1.length;
246
+ var text2_length = text2.length;
247
+ if (text1_length == 0 || text2_length == 0) {
248
+ return 0;
249
+ }
250
+ if (text1_length > text2_length) {
251
+ text1 = text1.substring(text1_length - text2_length);
252
+ } else if (text1_length < text2_length) {
253
+ text2 = text2.substring(0, text1_length);
254
+ }
255
+ var text_length = Math.min(text1_length, text2_length);
256
+ if (text1 == text2) {
257
+ return text_length;
258
+ }
259
+ var best = 0;
260
+ var length = 1;
261
+ while (true) {
262
+ var pattern = text1.substring(text_length - length);
263
+ var found = text2.indexOf(pattern);
264
+ if (found == -1) {
265
+ return best;
266
+ }
267
+ length += found;
268
+ if (found == 0 || text1.substring(text_length - length) == text2.substring(0, length)) {
269
+ best = length;
270
+ length++;
271
+ }
272
+ }
273
+ }
274
+ function diff_commonSuffix(text1, text2) {
275
+ if (!text1 || !text2 || text1.slice(-1) !== text2.slice(-1)) {
276
+ return 0;
277
+ }
278
+ var pointermin = 0;
279
+ var pointermax = Math.min(text1.length, text2.length);
280
+ var pointermid = pointermax;
281
+ var pointerend = 0;
282
+ while (pointermin < pointermid) {
283
+ if (text1.substring(text1.length - pointermid, text1.length - pointerend) == text2.substring(text2.length - pointermid, text2.length - pointerend)) {
284
+ pointermin = pointermid;
285
+ pointerend = pointermin;
286
+ } else {
287
+ pointermax = pointermid;
288
+ }
289
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
290
+ }
291
+ if (is_surrogate_pair_end(text1.charCodeAt(text1.length - pointermid))) {
292
+ pointermid--;
293
+ }
294
+ return pointermid;
295
+ }
296
+ function diff_halfMatch_(text1, text2) {
297
+ var longtext = text1.length > text2.length ? text1 : text2;
298
+ var shorttext = text1.length > text2.length ? text2 : text1;
299
+ if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
300
+ return null;
301
+ }
302
+ function diff_halfMatchI_(longtext, shorttext, i) {
303
+ var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
304
+ var j = -1;
305
+ var best_common = "";
306
+ var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
307
+ while ((j = shorttext.indexOf(seed, j + 1)) !== -1) {
308
+ var prefixLength = diff_commonPrefix(longtext.substring(i), shorttext.substring(j));
309
+ var suffixLength = diff_commonSuffix(longtext.substring(0, i), shorttext.substring(0, j));
310
+ if (best_common.length < suffixLength + prefixLength) {
311
+ best_common = shorttext.substring(j - suffixLength, j) + shorttext.substring(j, j + prefixLength);
312
+ best_longtext_a = longtext.substring(0, i - suffixLength);
313
+ best_longtext_b = longtext.substring(i + prefixLength);
314
+ best_shorttext_a = shorttext.substring(0, j - suffixLength);
315
+ best_shorttext_b = shorttext.substring(j + prefixLength);
316
+ }
317
+ }
318
+ if (best_common.length * 2 >= longtext.length) {
319
+ return [
320
+ best_longtext_a,
321
+ best_longtext_b,
322
+ best_shorttext_a,
323
+ best_shorttext_b,
324
+ best_common
325
+ ];
326
+ } else {
327
+ return null;
328
+ }
329
+ }
330
+ var hm1 = diff_halfMatchI_(longtext, shorttext, Math.ceil(longtext.length / 4));
331
+ var hm2 = diff_halfMatchI_(longtext, shorttext, Math.ceil(longtext.length / 2));
332
+ var hm;
333
+ if (!hm1 && !hm2) {
334
+ return null;
335
+ } else if (!hm2) {
336
+ hm = hm1;
337
+ } else if (!hm1) {
338
+ hm = hm2;
339
+ } else {
340
+ hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
341
+ }
342
+ var text1_a, text1_b, text2_a, text2_b;
343
+ if (text1.length > text2.length) {
344
+ text1_a = hm[0];
345
+ text1_b = hm[1];
346
+ text2_a = hm[2];
347
+ text2_b = hm[3];
348
+ } else {
349
+ text2_a = hm[0];
350
+ text2_b = hm[1];
351
+ text1_a = hm[2];
352
+ text1_b = hm[3];
353
+ }
354
+ var mid_common = hm[4];
355
+ return [text1_a, text1_b, text2_a, text2_b, mid_common];
356
+ }
357
+ function diff_cleanupSemantic(diffs) {
358
+ var changes = false;
359
+ var equalities = [];
360
+ var equalitiesLength = 0;
361
+ var lastequality = null;
362
+ var pointer = 0;
363
+ var length_insertions1 = 0;
364
+ var length_deletions1 = 0;
365
+ var length_insertions2 = 0;
366
+ var length_deletions2 = 0;
367
+ while (pointer < diffs.length) {
368
+ if (diffs[pointer][0] == DIFF_EQUAL) {
369
+ equalities[equalitiesLength++] = pointer;
370
+ length_insertions1 = length_insertions2;
371
+ length_deletions1 = length_deletions2;
372
+ length_insertions2 = 0;
373
+ length_deletions2 = 0;
374
+ lastequality = diffs[pointer][1];
375
+ } else {
376
+ if (diffs[pointer][0] == DIFF_INSERT) {
377
+ length_insertions2 += diffs[pointer][1].length;
378
+ } else {
379
+ length_deletions2 += diffs[pointer][1].length;
380
+ }
381
+ if (lastequality && lastequality.length <= Math.max(length_insertions1, length_deletions1) && lastequality.length <= Math.max(length_insertions2, length_deletions2)) {
382
+ diffs.splice(equalities[equalitiesLength - 1], 0, [
383
+ DIFF_DELETE,
384
+ lastequality
385
+ ]);
386
+ diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
387
+ equalitiesLength--;
388
+ equalitiesLength--;
389
+ pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
390
+ length_insertions1 = 0;
391
+ length_deletions1 = 0;
392
+ length_insertions2 = 0;
393
+ length_deletions2 = 0;
394
+ lastequality = null;
395
+ changes = true;
396
+ }
397
+ }
398
+ pointer++;
399
+ }
400
+ if (changes) {
401
+ diff_cleanupMerge(diffs);
402
+ }
403
+ diff_cleanupSemanticLossless(diffs);
404
+ pointer = 1;
405
+ while (pointer < diffs.length) {
406
+ if (diffs[pointer - 1][0] == DIFF_DELETE && diffs[pointer][0] == DIFF_INSERT) {
407
+ var deletion = diffs[pointer - 1][1];
408
+ var insertion = diffs[pointer][1];
409
+ var overlap_length1 = diff_commonOverlap_(deletion, insertion);
410
+ var overlap_length2 = diff_commonOverlap_(insertion, deletion);
411
+ if (overlap_length1 >= overlap_length2) {
412
+ if (overlap_length1 >= deletion.length / 2 || overlap_length1 >= insertion.length / 2) {
413
+ diffs.splice(pointer, 0, [
414
+ DIFF_EQUAL,
415
+ insertion.substring(0, overlap_length1)
416
+ ]);
417
+ diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlap_length1);
418
+ diffs[pointer + 1][1] = insertion.substring(overlap_length1);
419
+ pointer++;
420
+ }
421
+ } else {
422
+ if (overlap_length2 >= deletion.length / 2 || overlap_length2 >= insertion.length / 2) {
423
+ diffs.splice(pointer, 0, [
424
+ DIFF_EQUAL,
425
+ deletion.substring(0, overlap_length2)
426
+ ]);
427
+ diffs[pointer - 1][0] = DIFF_INSERT;
428
+ diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlap_length2);
429
+ diffs[pointer + 1][0] = DIFF_DELETE;
430
+ diffs[pointer + 1][1] = deletion.substring(overlap_length2);
431
+ pointer++;
432
+ }
433
+ }
434
+ pointer++;
435
+ }
436
+ pointer++;
437
+ }
438
+ }
439
+ var nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/;
440
+ var whitespaceRegex_ = /\s/;
441
+ var linebreakRegex_ = /[\r\n]/;
442
+ var blanklineEndRegex_ = /\n\r?\n$/;
443
+ var blanklineStartRegex_ = /^\r?\n\r?\n/;
444
+ function diff_cleanupSemanticLossless(diffs) {
445
+ function diff_cleanupSemanticScore_(one, two) {
446
+ if (!one || !two) {
447
+ return 6;
448
+ }
449
+ var char1 = one.charAt(one.length - 1);
450
+ var char2 = two.charAt(0);
451
+ var nonAlphaNumeric1 = char1.match(nonAlphaNumericRegex_);
452
+ var nonAlphaNumeric2 = char2.match(nonAlphaNumericRegex_);
453
+ var whitespace1 = nonAlphaNumeric1 && char1.match(whitespaceRegex_);
454
+ var whitespace2 = nonAlphaNumeric2 && char2.match(whitespaceRegex_);
455
+ var lineBreak1 = whitespace1 && char1.match(linebreakRegex_);
456
+ var lineBreak2 = whitespace2 && char2.match(linebreakRegex_);
457
+ var blankLine1 = lineBreak1 && one.match(blanklineEndRegex_);
458
+ var blankLine2 = lineBreak2 && two.match(blanklineStartRegex_);
459
+ if (blankLine1 || blankLine2) {
460
+ return 5;
461
+ } else if (lineBreak1 || lineBreak2) {
462
+ return 4;
463
+ } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) {
464
+ return 3;
465
+ } else if (whitespace1 || whitespace2) {
466
+ return 2;
467
+ } else if (nonAlphaNumeric1 || nonAlphaNumeric2) {
468
+ return 1;
469
+ }
470
+ return 0;
471
+ }
472
+ var pointer = 1;
473
+ while (pointer < diffs.length - 1) {
474
+ if (diffs[pointer - 1][0] == DIFF_EQUAL && diffs[pointer + 1][0] == DIFF_EQUAL) {
475
+ var equality1 = diffs[pointer - 1][1];
476
+ var edit = diffs[pointer][1];
477
+ var equality2 = diffs[pointer + 1][1];
478
+ var commonOffset = diff_commonSuffix(equality1, edit);
479
+ if (commonOffset) {
480
+ var commonString = edit.substring(edit.length - commonOffset);
481
+ equality1 = equality1.substring(0, equality1.length - commonOffset);
482
+ edit = commonString + edit.substring(0, edit.length - commonOffset);
483
+ equality2 = commonString + equality2;
484
+ }
485
+ var bestEquality1 = equality1;
486
+ var bestEdit = edit;
487
+ var bestEquality2 = equality2;
488
+ var bestScore = diff_cleanupSemanticScore_(equality1, edit) + diff_cleanupSemanticScore_(edit, equality2);
489
+ while (edit.charAt(0) === equality2.charAt(0)) {
490
+ equality1 += edit.charAt(0);
491
+ edit = edit.substring(1) + equality2.charAt(0);
492
+ equality2 = equality2.substring(1);
493
+ var score = diff_cleanupSemanticScore_(equality1, edit) + diff_cleanupSemanticScore_(edit, equality2);
494
+ if (score >= bestScore) {
495
+ bestScore = score;
496
+ bestEquality1 = equality1;
497
+ bestEdit = edit;
498
+ bestEquality2 = equality2;
499
+ }
500
+ }
501
+ if (diffs[pointer - 1][1] != bestEquality1) {
502
+ if (bestEquality1) {
503
+ diffs[pointer - 1][1] = bestEquality1;
504
+ } else {
505
+ diffs.splice(pointer - 1, 1);
506
+ pointer--;
507
+ }
508
+ diffs[pointer][1] = bestEdit;
509
+ if (bestEquality2) {
510
+ diffs[pointer + 1][1] = bestEquality2;
511
+ } else {
512
+ diffs.splice(pointer + 1, 1);
513
+ pointer--;
514
+ }
515
+ }
516
+ }
517
+ pointer++;
518
+ }
519
+ }
520
+ function diff_cleanupMerge(diffs, fix_unicode) {
521
+ diffs.push([DIFF_EQUAL, ""]);
522
+ var pointer = 0;
523
+ var count_delete = 0;
524
+ var count_insert = 0;
525
+ var text_delete = "";
526
+ var text_insert = "";
527
+ var commonlength;
528
+ while (pointer < diffs.length) {
529
+ if (pointer < diffs.length - 1 && !diffs[pointer][1]) {
530
+ diffs.splice(pointer, 1);
531
+ continue;
532
+ }
533
+ switch (diffs[pointer][0]) {
534
+ case DIFF_INSERT:
535
+ count_insert++;
536
+ text_insert += diffs[pointer][1];
537
+ pointer++;
538
+ break;
539
+ case DIFF_DELETE:
540
+ count_delete++;
541
+ text_delete += diffs[pointer][1];
542
+ pointer++;
543
+ break;
544
+ case DIFF_EQUAL:
545
+ var previous_equality = pointer - count_insert - count_delete - 1;
546
+ if (fix_unicode) {
547
+ if (previous_equality >= 0 && ends_with_pair_start(diffs[previous_equality][1])) {
548
+ var stray = diffs[previous_equality][1].slice(-1);
549
+ diffs[previous_equality][1] = diffs[previous_equality][1].slice(0, -1);
550
+ text_delete = stray + text_delete;
551
+ text_insert = stray + text_insert;
552
+ if (!diffs[previous_equality][1]) {
553
+ diffs.splice(previous_equality, 1);
554
+ pointer--;
555
+ var k = previous_equality - 1;
556
+ if (diffs[k] && diffs[k][0] === DIFF_INSERT) {
557
+ count_insert++;
558
+ text_insert = diffs[k][1] + text_insert;
559
+ k--;
560
+ }
561
+ if (diffs[k] && diffs[k][0] === DIFF_DELETE) {
562
+ count_delete++;
563
+ text_delete = diffs[k][1] + text_delete;
564
+ k--;
565
+ }
566
+ previous_equality = k;
567
+ }
568
+ }
569
+ if (starts_with_pair_end(diffs[pointer][1])) {
570
+ var stray = diffs[pointer][1].charAt(0);
571
+ diffs[pointer][1] = diffs[pointer][1].slice(1);
572
+ text_delete += stray;
573
+ text_insert += stray;
574
+ }
575
+ }
576
+ if (pointer < diffs.length - 1 && !diffs[pointer][1]) {
577
+ diffs.splice(pointer, 1);
578
+ break;
579
+ }
580
+ if (text_delete.length > 0 || text_insert.length > 0) {
581
+ if (text_delete.length > 0 && text_insert.length > 0) {
582
+ commonlength = diff_commonPrefix(text_insert, text_delete);
583
+ if (commonlength !== 0) {
584
+ if (previous_equality >= 0) {
585
+ diffs[previous_equality][1] += text_insert.substring(0, commonlength);
586
+ } else {
587
+ diffs.splice(0, 0, [
588
+ DIFF_EQUAL,
589
+ text_insert.substring(0, commonlength)
590
+ ]);
591
+ pointer++;
592
+ }
593
+ text_insert = text_insert.substring(commonlength);
594
+ text_delete = text_delete.substring(commonlength);
595
+ }
596
+ commonlength = diff_commonSuffix(text_insert, text_delete);
597
+ if (commonlength !== 0) {
598
+ diffs[pointer][1] = text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1];
599
+ text_insert = text_insert.substring(0, text_insert.length - commonlength);
600
+ text_delete = text_delete.substring(0, text_delete.length - commonlength);
601
+ }
602
+ }
603
+ var n = count_insert + count_delete;
604
+ if (text_delete.length === 0 && text_insert.length === 0) {
605
+ diffs.splice(pointer - n, n);
606
+ pointer = pointer - n;
607
+ } else if (text_delete.length === 0) {
608
+ diffs.splice(pointer - n, n, [DIFF_INSERT, text_insert]);
609
+ pointer = pointer - n + 1;
610
+ } else if (text_insert.length === 0) {
611
+ diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete]);
612
+ pointer = pointer - n + 1;
613
+ } else {
614
+ diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete], [DIFF_INSERT, text_insert]);
615
+ pointer = pointer - n + 2;
616
+ }
617
+ }
618
+ if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
619
+ diffs[pointer - 1][1] += diffs[pointer][1];
620
+ diffs.splice(pointer, 1);
621
+ } else {
622
+ pointer++;
623
+ }
624
+ count_insert = 0;
625
+ count_delete = 0;
626
+ text_delete = "";
627
+ text_insert = "";
628
+ break;
629
+ }
630
+ }
631
+ if (diffs[diffs.length - 1][1] === "") {
632
+ diffs.pop();
633
+ }
634
+ var changes = false;
635
+ pointer = 1;
636
+ while (pointer < diffs.length - 1) {
637
+ if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
638
+ if (diffs[pointer][1].substring(diffs[pointer][1].length - diffs[pointer - 1][1].length) === diffs[pointer - 1][1]) {
639
+ diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length);
640
+ diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
641
+ diffs.splice(pointer - 1, 1);
642
+ changes = true;
643
+ } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == diffs[pointer + 1][1]) {
644
+ diffs[pointer - 1][1] += diffs[pointer + 1][1];
645
+ diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1];
646
+ diffs.splice(pointer + 1, 1);
647
+ changes = true;
648
+ }
649
+ }
650
+ pointer++;
651
+ }
652
+ if (changes) {
653
+ diff_cleanupMerge(diffs, fix_unicode);
654
+ }
655
+ }
656
+ function is_surrogate_pair_start(charCode) {
657
+ return charCode >= 55296 && charCode <= 56319;
658
+ }
659
+ function is_surrogate_pair_end(charCode) {
660
+ return charCode >= 56320 && charCode <= 57343;
661
+ }
662
+ function starts_with_pair_end(str) {
663
+ return is_surrogate_pair_end(str.charCodeAt(0));
664
+ }
665
+ function ends_with_pair_start(str) {
666
+ return is_surrogate_pair_start(str.charCodeAt(str.length - 1));
667
+ }
668
+ function remove_empty_tuples(tuples) {
669
+ var ret = [];
670
+ for (var i = 0;i < tuples.length; i++) {
671
+ if (tuples[i][1].length > 0) {
672
+ ret.push(tuples[i]);
673
+ }
674
+ }
675
+ return ret;
676
+ }
677
+ function make_edit_splice(before, oldMiddle, newMiddle, after) {
678
+ if (ends_with_pair_start(before) || starts_with_pair_end(after)) {
679
+ return null;
680
+ }
681
+ return remove_empty_tuples([
682
+ [DIFF_EQUAL, before],
683
+ [DIFF_DELETE, oldMiddle],
684
+ [DIFF_INSERT, newMiddle],
685
+ [DIFF_EQUAL, after]
686
+ ]);
687
+ }
688
+ function find_cursor_edit_diff(oldText, newText, cursor_pos) {
689
+ var oldRange = typeof cursor_pos === "number" ? { index: cursor_pos, length: 0 } : cursor_pos.oldRange;
690
+ var newRange = typeof cursor_pos === "number" ? null : cursor_pos.newRange;
691
+ var oldLength = oldText.length;
692
+ var newLength = newText.length;
693
+ if (oldRange.length === 0 && (newRange === null || newRange.length === 0)) {
694
+ var oldCursor = oldRange.index;
695
+ var oldBefore = oldText.slice(0, oldCursor);
696
+ var oldAfter = oldText.slice(oldCursor);
697
+ var maybeNewCursor = newRange ? newRange.index : null;
698
+ editBefore: {
699
+ var newCursor = oldCursor + newLength - oldLength;
700
+ if (maybeNewCursor !== null && maybeNewCursor !== newCursor) {
701
+ break editBefore;
702
+ }
703
+ if (newCursor < 0 || newCursor > newLength) {
704
+ break editBefore;
705
+ }
706
+ var newBefore = newText.slice(0, newCursor);
707
+ var newAfter = newText.slice(newCursor);
708
+ if (newAfter !== oldAfter) {
709
+ break editBefore;
710
+ }
711
+ var prefixLength = Math.min(oldCursor, newCursor);
712
+ var oldPrefix = oldBefore.slice(0, prefixLength);
713
+ var newPrefix = newBefore.slice(0, prefixLength);
714
+ if (oldPrefix !== newPrefix) {
715
+ break editBefore;
716
+ }
717
+ var oldMiddle = oldBefore.slice(prefixLength);
718
+ var newMiddle = newBefore.slice(prefixLength);
719
+ return make_edit_splice(oldPrefix, oldMiddle, newMiddle, oldAfter);
720
+ }
721
+ editAfter: {
722
+ if (maybeNewCursor !== null && maybeNewCursor !== oldCursor) {
723
+ break editAfter;
724
+ }
725
+ var cursor = oldCursor;
726
+ var newBefore = newText.slice(0, cursor);
727
+ var newAfter = newText.slice(cursor);
728
+ if (newBefore !== oldBefore) {
729
+ break editAfter;
730
+ }
731
+ var suffixLength = Math.min(oldLength - cursor, newLength - cursor);
732
+ var oldSuffix = oldAfter.slice(oldAfter.length - suffixLength);
733
+ var newSuffix = newAfter.slice(newAfter.length - suffixLength);
734
+ if (oldSuffix !== newSuffix) {
735
+ break editAfter;
736
+ }
737
+ var oldMiddle = oldAfter.slice(0, oldAfter.length - suffixLength);
738
+ var newMiddle = newAfter.slice(0, newAfter.length - suffixLength);
739
+ return make_edit_splice(oldBefore, oldMiddle, newMiddle, oldSuffix);
740
+ }
741
+ }
742
+ if (oldRange.length > 0 && newRange && newRange.length === 0) {
743
+ replaceRange: {
744
+ var oldPrefix = oldText.slice(0, oldRange.index);
745
+ var oldSuffix = oldText.slice(oldRange.index + oldRange.length);
746
+ var prefixLength = oldPrefix.length;
747
+ var suffixLength = oldSuffix.length;
748
+ if (newLength < prefixLength + suffixLength) {
749
+ break replaceRange;
750
+ }
751
+ var newPrefix = newText.slice(0, prefixLength);
752
+ var newSuffix = newText.slice(newLength - suffixLength);
753
+ if (oldPrefix !== newPrefix || oldSuffix !== newSuffix) {
754
+ break replaceRange;
755
+ }
756
+ var oldMiddle = oldText.slice(prefixLength, oldLength - suffixLength);
757
+ var newMiddle = newText.slice(prefixLength, newLength - suffixLength);
758
+ return make_edit_splice(oldPrefix, oldMiddle, newMiddle, oldSuffix);
759
+ }
760
+ }
761
+ return null;
762
+ }
763
+ function diff(text1, text2, cursor_pos, cleanup) {
764
+ return diff_main(text1, text2, cursor_pos, cleanup, true);
765
+ }
766
+ diff.INSERT = DIFF_INSERT;
767
+ diff.DELETE = DIFF_DELETE;
768
+ diff.EQUAL = DIFF_EQUAL;
769
+ module.exports = diff;
770
+ });
771
+
16
772
  // src/testing/memory-repo-files.ts
17
773
  var globMatcher = (pattern) => new RegExp(`^${pattern.replace(/\*\*\/|\*\*|\*|[.+^${}()|[\]\\]/g, (token) => {
18
774
  if (token === "**/")
@@ -5885,10 +6641,16 @@ var ZodBase64 = /* @__PURE__ */ $constructor("ZodBase64", (inst, def) => {
5885
6641
  $ZodBase64.init(inst, def);
5886
6642
  ZodStringFormat.init(inst, def);
5887
6643
  });
6644
+ function base642(params) {
6645
+ return _base64(ZodBase64, params);
6646
+ }
5888
6647
  var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => {
5889
6648
  $ZodBase64URL.init(inst, def);
5890
6649
  ZodStringFormat.init(inst, def);
5891
6650
  });
6651
+ function base64url2(params) {
6652
+ return _base64url(ZodBase64URL, params);
6653
+ }
5892
6654
  var ZodE164 = /* @__PURE__ */ $constructor("ZodE164", (inst, def) => {
5893
6655
  $ZodE164.init(inst, def);
5894
6656
  ZodStringFormat.init(inst, def);
@@ -6536,12 +7298,36 @@ function preprocess(fn, schema) {
6536
7298
  out: schema
6537
7299
  });
6538
7300
  }
7301
+ // ../../node_modules/.bun/zod@4.5.4/node_modules/zod/v4/classic/iso.js
7302
+ var exports_iso = {};
7303
+ __export(exports_iso, {
7304
+ ZodISODate: () => ZodISODate,
7305
+ ZodISODateTime: () => ZodISODateTime,
7306
+ ZodISODuration: () => ZodISODuration,
7307
+ ZodISOTime: () => ZodISOTime,
7308
+ date: () => date2,
7309
+ datetime: () => datetime2,
7310
+ duration: () => duration2,
7311
+ time: () => time2
7312
+ });
7313
+ function datetime2(params) {
7314
+ return _isoDateTime(ZodISODateTime, params);
7315
+ }
7316
+ function date2(params) {
7317
+ return _isoDate(ZodISODate, params);
7318
+ }
7319
+ function time2(params) {
7320
+ return _isoTime(ZodISOTime, params);
7321
+ }
7322
+ function duration2(params) {
7323
+ return _isoDuration(ZodISODuration, params);
7324
+ }
6539
7325
  // ../../node_modules/.bun/zod@4.5.4/node_modules/zod/v4/classic/coerce.js
6540
7326
  var exports_coerce = {};
6541
7327
  __export(exports_coerce, {
6542
7328
  bigint: () => bigint2,
6543
7329
  boolean: () => boolean3,
6544
- date: () => date2,
7330
+ date: () => date3,
6545
7331
  number: () => number3,
6546
7332
  string: () => string3
6547
7333
  });
@@ -6557,7 +7343,7 @@ function boolean3(params) {
6557
7343
  function bigint2(params) {
6558
7344
  return _coercedBigint(ZodBigInt, params);
6559
7345
  }
6560
- function date2(params) {
7346
+ function date3(params) {
6561
7347
  return _coercedDate(ZodDate, params);
6562
7348
  }
6563
7349
  // ../pstdio-api-contracts/src/activity.ts
@@ -6666,30 +7452,6 @@ var harnessLocalId = (id) => id.slice(id.lastIndexOf(".") + 1);
6666
7452
  var agentDetailsSchema = agentInfoSchema.extend({
6667
7453
  skills: agentSkillsLayoutSchema.extend({ globalDir: string2() }).optional()
6668
7454
  });
6669
- // ../pstdio-sync-contracts/src/compatibility.ts
6670
- var peerSchema = strictObject({
6671
- release: string2().min(1),
6672
- protocolVersions: array(number2().int().positive()).min(1),
6673
- supportedFeatures: array(string2().min(1)),
6674
- requiredFeatures: array(string2().min(1))
6675
- });
6676
- var protocolPeer = {
6677
- release: "contracts-v1",
6678
- protocolVersions: [1],
6679
- supportedFeatures: ["atomic-groups", "retained-recovery", "revisioned-resolution"],
6680
- requiredFeatures: ["atomic-groups", "retained-recovery", "revisioned-resolution"]
6681
- };
6682
- function negotiate(client, relay) {
6683
- const common = client.protocolVersions.includes(1) && relay.protocolVersions.includes(1);
6684
- const features = client.requiredFeatures.every((feature) => relay.supportedFeatures.includes(feature)) && relay.requiredFeatures.every((feature) => client.supportedFeatures.includes(feature));
6685
- if (common && features)
6686
- return { status: "compatible", protocolVersion: 1 };
6687
- return {
6688
- status: "unsupported-protocol",
6689
- recoverable: true,
6690
- action: "Update the local runtime or relay to a common protocol and required feature set. Local work remains saved; retry after updating."
6691
- };
6692
- }
6693
7455
  // ../pstdio-sync-contracts/src/json.ts
6694
7456
  function isJson(value) {
6695
7457
  try {
@@ -6825,24 +7587,258 @@ async function fingerprint(value) {
6825
7587
  const digest = await crypto.subtle.digest("SHA-256", bytes);
6826
7588
  return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
6827
7589
  }
6828
- async function sealMutation(body) {
6829
- const parsed = mutationSchema.parse({ ...body, fingerprint: "0".repeat(64) });
6830
- const { fingerprint: _ignored, ...normalized } = parsed;
6831
- return { ...normalized, fingerprint: await fingerprint(normalized) };
6832
- }
6833
- async function validateMutation(input) {
6834
- const mutation = mutationSchema.parse(input);
6835
- const { fingerprint: supplied, ...body } = mutation;
6836
- if (await fingerprint(body) !== supplied)
6837
- throw new Error("Payload fingerprint does not match");
6838
- return mutation;
6839
- }
7590
+
7591
+ // ../pstdio-sync-contracts/src/checkpoint.ts
7592
+ var writerPositionSchema = strictObject({
7593
+ environmentId: identitySchema,
7594
+ sequence: number2().int().positive()
7595
+ });
7596
+ var checkpointBodySchema = strictObject({
7597
+ protocolVersion: literal(2),
7598
+ scope: scopeSchema,
7599
+ epoch: identitySchema,
7600
+ generation: revisionSchema,
7601
+ environmentId: identitySchema,
7602
+ sequence: number2().int().positive(),
7603
+ parents: array(identitySchema),
7604
+ document: strictObject({ recordId: identitySchema, generation: revisionSchema, recoveryRevision: revisionSchema }),
7605
+ changes: array(changeSchema).min(1),
7606
+ resolution: resolutionSchema.optional(),
7607
+ rebase: strictObject({
7608
+ expectedSnapshotHash: fingerprintSchema,
7609
+ sources: array(strictObject({ operationId: identitySchema, fingerprint: fingerprintSchema })).min(1)
7610
+ }).optional()
7611
+ });
7612
+ var checkpointGroupSchema = checkpointBodySchema.extend({ fingerprint: fingerprintSchema }).superRefine((group, ctx) => {
7613
+ checkGroup({ ...group, operationId: `${group.environmentId}:${group.sequence}` }, ctx);
7614
+ const sources = group.rebase?.sources.map((source) => source.operationId) ?? [];
7615
+ if (new Set(sources).size !== sources.length || sources.some((id) => !group.parents.includes(id)))
7616
+ ctx.addIssue({ code: "custom", message: "Rebased sources must be unique captured parents" });
7617
+ if (new Set(group.parents).size !== group.parents.length || group.parents.includes(`${group.environmentId}:${group.sequence}`))
7618
+ ctx.addIssue({ code: "custom", message: "Checkpoint parents must be unique and cannot include itself" });
7619
+ if (new Set(group.changes.map((change) => change.recordId)).size !== group.changes.length || !group.changes.some((change) => change.recordId === group.document.recordId && change.shared?.kind === "text"))
7620
+ ctx.addIssue({ code: "custom", message: "Checkpoint needs a document delta and unique projection records" });
7621
+ });
7622
+ var coverageAckSchema = strictObject({
7623
+ protocolVersion: literal(2),
7624
+ scope: scopeSchema,
7625
+ epoch: identitySchema,
7626
+ generation: revisionSchema,
7627
+ environmentId: identitySchema,
7628
+ cut: revisionSchema,
7629
+ snapshotHash: fingerprintSchema,
7630
+ branches: array(identitySchema),
7631
+ recovery: array(strictObject({
7632
+ recordId: identitySchema,
7633
+ generation: revisionSchema,
7634
+ revision: revisionSchema,
7635
+ checkpointRevision: revisionSchema,
7636
+ baseCut: revisionSchema,
7637
+ branches: array(identitySchema)
7638
+ }).refine((recovery) => recovery.checkpointRevision <= recovery.revision, "Recovery checkpoint is in the future"))
7639
+ });
7640
+ var writerFrontierSchema = strictObject({ floor: revisionSchema });
7641
+ var recoveryFileSchema = strictObject({
7642
+ protocolVersion: literal(2),
7643
+ scope: scopeSchema,
7644
+ recordId: identitySchema,
7645
+ epoch: identitySchema,
7646
+ generation: revisionSchema,
7647
+ revision: revisionSchema,
7648
+ checkpointRevision: revisionSchema,
7649
+ state: string2(),
7650
+ checkpointVector: string2(),
7651
+ projectionBaseline: string2(),
7652
+ frozen: strictObject({
7653
+ identity: identitySchema,
7654
+ revision: revisionSchema,
7655
+ update: string2(),
7656
+ vector: string2(),
7657
+ group: checkpointGroupSchema.nullable(),
7658
+ projectionBaseline: string2()
7659
+ }).nullable()
7660
+ });
7661
+ var liveFrameSchema = strictObject({
7662
+ protocolVersion: literal(2),
7663
+ scope: scopeSchema,
7664
+ epoch: identitySchema,
7665
+ documentId: identitySchema,
7666
+ generation: revisionSchema,
7667
+ kind: _enum(["update", "state-vector", "barrier"]),
7668
+ payload: string2()
7669
+ });
7670
+ var backupCoverageSchema = strictObject({
7671
+ scope: scopeSchema,
7672
+ epoch: identitySchema,
7673
+ generation: revisionSchema,
7674
+ cut: revisionSchema,
7675
+ snapshotHash: fingerprintSchema,
7676
+ manifestHash: fingerprintSchema
7677
+ });
7678
+ var documentRotationSchema = strictObject({
7679
+ scope: scopeSchema,
7680
+ epoch: identitySchema,
7681
+ documentId: identitySchema,
7682
+ previousGeneration: revisionSchema,
7683
+ generation: revisionSchema,
7684
+ seed: string2()
7685
+ }).refine((rotation) => rotation.generation === rotation.previousGeneration + 1, "Document generation must advance once");
7686
+ var documentPositionSchema = strictObject({
7687
+ scope: scopeSchema,
7688
+ epoch: identitySchema,
7689
+ documentId: identitySchema,
7690
+ generation: revisionSchema,
7691
+ position: string2()
7692
+ });
7693
+ // ../pstdio-sync-contracts/src/compatibility.ts
7694
+ var peerSchema = strictObject({
7695
+ release: string2().min(1),
7696
+ protocolVersions: array(number2().int().positive()).min(1),
7697
+ supportedFeatures: array(string2().min(1)),
7698
+ requiredFeatures: array(string2().min(1))
7699
+ });
6840
7700
  // ../pstdio-sync-contracts/src/identity.ts
6841
7701
  var environmentIdentitySchema = strictObject({ environmentId: identitySchema });
6842
7702
  var environmentTargetSchema = environmentIdentitySchema.extend({
6843
7703
  workbenchId: identitySchema,
6844
7704
  workspaceId: identitySchema
6845
7705
  });
7706
+ // ../pstdio-sync-contracts/src/protocol/envelopes.ts
7707
+ var syncIdSchema = string2().regex(/^[A-Za-z0-9_-]{16,128}$/);
7708
+ var sequenceSchema = number2().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
7709
+ var byteLengthSchema = sequenceSchema;
7710
+ var payloadSchema = base642();
7711
+ var blobIdsSchema = array(syncIdSchema).max(1e5).refine((ids) => new Set(ids).size === ids.length, "Blob IDs must be unique");
7712
+ var spaceOwnerSchema = identitySchema.nullable();
7713
+ var updateEnvelopeSchema = strictObject({
7714
+ updateId: syncIdSchema,
7715
+ payload: payloadSchema,
7716
+ blobIds: blobIdsSchema
7717
+ });
7718
+ var updateResultSchema = strictObject({ sequence: sequenceSchema.min(1), duplicate: boolean2() });
7719
+ var stateEnvelopeSchema = strictObject({
7720
+ stateId: syncIdSchema,
7721
+ baseStateId: syncIdSchema.nullable(),
7722
+ through: sequenceSchema,
7723
+ payload: payloadSchema,
7724
+ summary: payloadSchema,
7725
+ blobIds: blobIdsSchema
7726
+ });
7727
+ var stateInfoSchema = strictObject({
7728
+ stateId: syncIdSchema,
7729
+ baseStateId: syncIdSchema.nullable(),
7730
+ through: sequenceSchema,
7731
+ byteLength: byteLengthSchema,
7732
+ summary: payloadSchema,
7733
+ deviceId: identitySchema,
7734
+ createdAt: exports_iso.datetime()
7735
+ });
7736
+ var stateResultSchema = strictObject({ state: stateInfoSchema });
7737
+ var storedUpdateSchema = strictObject({
7738
+ sequence: sequenceSchema.min(1),
7739
+ updateId: syncIdSchema,
7740
+ deviceId: identitySchema,
7741
+ payload: payloadSchema,
7742
+ createdAt: exports_iso.datetime()
7743
+ });
7744
+ var readRequestSchema = strictObject({ after: sequenceSchema });
7745
+ var readResultSchema = discriminatedUnion("status", [
7746
+ strictObject({
7747
+ status: literal("updates"),
7748
+ state: stateInfoSchema.nullable(),
7749
+ lastSequence: sequenceSchema,
7750
+ updates: array(storedUpdateSchema),
7751
+ more: boolean2()
7752
+ }),
7753
+ strictObject({
7754
+ status: literal("state-required"),
7755
+ state: stateInfoSchema.nullable(),
7756
+ lastSequence: sequenceSchema
7757
+ })
7758
+ ]);
7759
+ var blobBeginSchema = strictObject({ sha256: fingerprintSchema, byteLength: byteLengthSchema });
7760
+ var blobStatusSchema = strictObject({
7761
+ partSize: number2().int().positive(),
7762
+ completed: boolean2(),
7763
+ parts: array(strictObject({ number: number2().int().positive(), sha256: fingerprintSchema, byteLength: byteLengthSchema }))
7764
+ });
7765
+ var blobReadSchema = strictObject({ offset: byteLengthSchema });
7766
+ var liveClientMessageSchema = strictObject({
7767
+ type: literal("live"),
7768
+ spaceOwner: spaceOwnerSchema,
7769
+ payload: payloadSchema
7770
+ });
7771
+ var liveServerMessageSchema = discriminatedUnion("type", [
7772
+ strictObject({ type: literal("ready"), protocolVersion: number2().int().positive() }),
7773
+ strictObject({
7774
+ type: literal("live"),
7775
+ spaceOwner: spaceOwnerSchema,
7776
+ deviceId: identitySchema,
7777
+ payload: payloadSchema
7778
+ }),
7779
+ strictObject({
7780
+ type: literal("changed"),
7781
+ spaceOwner: spaceOwnerSchema,
7782
+ documentId: syncIdSchema,
7783
+ lastSequence: sequenceSchema,
7784
+ stateId: syncIdSchema.nullable()
7785
+ })
7786
+ ]);
7787
+ var syncErrorSchema = discriminatedUnion("error", [
7788
+ strictObject({
7789
+ error: literal("protocol-unsupported"),
7790
+ supported: array(number2().int()),
7791
+ message: string2()
7792
+ }),
7793
+ strictObject({ error: literal("stale-state"), state: stateInfoSchema.nullable() }),
7794
+ strictObject({ error: literal("missing-blobs"), blobIds: array(syncIdSchema) }),
7795
+ strictObject({
7796
+ error: _enum([
7797
+ "invalid-request",
7798
+ "unauthorized",
7799
+ "forbidden",
7800
+ "not-found",
7801
+ "method-not-allowed",
7802
+ "too-large",
7803
+ "quota-exceeded",
7804
+ "rate-limited",
7805
+ "unavailable"
7806
+ ])
7807
+ })
7808
+ ]);
7809
+ // ../pstdio-sync-contracts/src/protocol/keys.ts
7810
+ var spaceKeySchema = strictObject({
7811
+ generation: number2().int().positive(),
7812
+ secret: base64url2().length(43)
7813
+ });
7814
+ var spaceKeysSchema = strictObject({
7815
+ project: array(spaceKeySchema).min(1),
7816
+ personal: array(spaceKeySchema).min(1)
7817
+ });
7818
+ // ../pstdio-sync-contracts/src/protocol/routes.ts
7819
+ var space = { projectId: identitySchema, spaceOwner: identitySchema.nullable() };
7820
+ var routeSchema = discriminatedUnion("kind", [
7821
+ strictObject({
7822
+ kind: literal("document"),
7823
+ ...space,
7824
+ documentId: syncIdSchema,
7825
+ operation: _enum(["updates", "read", "state"])
7826
+ }),
7827
+ strictObject({ kind: literal("state"), ...space, documentId: syncIdSchema, stateId: syncIdSchema }),
7828
+ strictObject({
7829
+ kind: literal("blob"),
7830
+ ...space,
7831
+ blobId: syncIdSchema,
7832
+ operation: _enum(["begin", "finish", "read"])
7833
+ }),
7834
+ strictObject({
7835
+ kind: literal("part"),
7836
+ ...space,
7837
+ blobId: syncIdSchema,
7838
+ number: number2().int().min(1).max(1e4)
7839
+ }),
7840
+ strictObject({ kind: literal("live"), projectId: identitySchema })
7841
+ ]);
6846
7842
  // ../pstdio-sync-contracts/src/state.ts
6847
7843
  var checkpointSchema = strictObject({ epoch: identitySchema, sequence: revisionSchema });
6848
7844
  var recordSchema = strictObject({
@@ -6919,6 +7915,44 @@ var replaySchema = strictObject({
6919
7915
  message: "Replay must contain contiguous complete accepted groups in one scope and epoch"
6920
7916
  });
6921
7917
  });
7918
+ // ../pstdio-sync-contracts/src/retention.ts
7919
+ var coveredReceiptSchema = strictObject({
7920
+ group: checkpointGroupSchema,
7921
+ status: _enum(["accepted", "pending", "conflict"]),
7922
+ cut: revisionSchema.nullable()
7923
+ }).refine((receipt) => receipt.status === "accepted" === (receipt.cut !== null), "Only accepted receipts have a cut");
7924
+ var coveredSnapshotSchema = strictObject({
7925
+ protocolVersion: literal(2),
7926
+ scope: scopeSchema,
7927
+ epoch: identitySchema,
7928
+ generation: revisionSchema,
7929
+ cut: revisionSchema,
7930
+ covered: revisionSchema,
7931
+ records: dictionarySchema(recordSchema),
7932
+ conflicts: dictionarySchema(conflictSchema),
7933
+ publishedRevision: identitySchema,
7934
+ documents: dictionarySchema(revisionSchema),
7935
+ receipts: dictionarySchema(coveredReceiptSchema),
7936
+ writers: dictionarySchema(writerFrontierSchema),
7937
+ retainedBranches: array(identitySchema)
7938
+ });
7939
+ var recoveryCoverageSchema = strictObject({
7940
+ recordId: identitySchema,
7941
+ generation: revisionSchema,
7942
+ revision: revisionSchema,
7943
+ checkpointRevision: revisionSchema,
7944
+ baseCut: revisionSchema,
7945
+ branches: array(identitySchema)
7946
+ }).refine((recovery) => recovery.checkpointRevision <= recovery.revision, "Checkpoint cannot cover future recovery edits");
7947
+ var backupManifestSchema = strictObject({
7948
+ protocolVersion: literal(2),
7949
+ snapshot: coveredSnapshotSchema,
7950
+ assets: array(assetSchema),
7951
+ packages: array(assetSchema),
7952
+ copiesScope: scopeSchema,
7953
+ snapshotHash: fingerprintSchema,
7954
+ coverage: array(coverageAckSchema)
7955
+ });
6922
7956
  // ../pstdio-sync-contracts/src/transport.ts
6923
7957
  var relayOperationSchema = _enum([
6924
7958
  "initialize",
@@ -6939,21 +7973,21 @@ var relayReplayResultSchema = discriminatedUnion("status", [
6939
7973
  strictObject({ status: literal("replay"), batch: replaySchema }),
6940
7974
  strictObject({ status: literal("snapshot-required"), checkpoint: checkpointSchema })
6941
7975
  ]);
6942
- var byteLengthSchema = number2().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
7976
+ var byteLengthSchema2 = number2().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
6943
7977
  var relayAssetBeginSchema = strictObject({ uploadId: identitySchema, asset: assetSchema });
6944
7978
  var relayAssetUploadSchema = strictObject({ uploadId: identitySchema });
6945
7979
  var relayAssetPartSchema = strictObject({
6946
7980
  uploadId: identitySchema,
6947
7981
  number: number2().int().min(1).max(1e4),
6948
7982
  sha256: fingerprintSchema,
6949
- byteLength: byteLengthSchema
7983
+ byteLength: byteLengthSchema2
6950
7984
  });
6951
- var relayAssetReadSchema = strictObject({ asset: assetSchema, offset: byteLengthSchema }).refine(({ asset, offset }) => offset <= asset.byteLength, "Offset exceeds the asset");
7985
+ var relayAssetReadSchema = strictObject({ asset: assetSchema, offset: byteLengthSchema2 }).refine(({ asset, offset }) => offset <= asset.byteLength, "Offset exceeds the asset");
6952
7986
  var relayAssetStatusSchema = strictObject({
6953
7987
  asset: assetSchema,
6954
7988
  partSize: number2().int().positive(),
6955
7989
  completed: boolean2(),
6956
- parts: array(strictObject({ number: number2().int().positive(), sha256: fingerprintSchema, byteLength: byteLengthSchema }))
7990
+ parts: array(strictObject({ number: number2().int().positive(), sha256: fingerprintSchema, byteLength: byteLengthSchema2 }))
6957
7991
  });
6958
7992
  var relayEventSchema = strictObject({ protocolVersion: literal(1), type: _enum(["ready", "changed"]) });
6959
7993
  var relayInitializeSchema = strictObject({ publishedRevision: identitySchema });
@@ -7791,6 +8825,14 @@ var extensionRendererRecordBaseSchema = object({
7791
8825
  emptyDescription: localizableStringSchema.optional()
7792
8826
  });
7793
8827
  var extensionTreeRendererRecordSchema = extensionRendererRecordBaseSchema.extend({
8828
+ structure: array(object({
8829
+ id: string2(),
8830
+ label: localizableStringSchema.optional(),
8831
+ collapsible: boolean2().optional(),
8832
+ hiddenByDefault: boolean2().optional(),
8833
+ canHide: boolean2().optional(),
8834
+ resourceNode: object({ id: string2(), icon: string2().optional() }).optional()
8835
+ })).optional(),
7794
8836
  searchable: boolean2().optional(),
7795
8837
  searchPlaceholder: localizableStringSchema.optional(),
7796
8838
  headerHandlerId: string2().optional(),
@@ -8148,6 +9190,11 @@ var regionSizeSchema = object({
8148
9190
  });
8149
9191
  var regionSettingsSchema = object({
8150
9192
  showHeader: boolean2().optional(),
9193
+ canOpen: boolean2().optional(),
9194
+ canClose: boolean2().optional(),
9195
+ acceptsTabs: boolean2().optional(),
9196
+ resizable: boolean2().optional(),
9197
+ floatable: boolean2().optional(),
8151
9198
  size: regionSizeSchema.optional(),
8152
9199
  collapsible: boolean2().optional(),
8153
9200
  alwaysShowTabs: boolean2().optional()
@@ -9569,13 +10616,15 @@ var serializeCommandError = (error) => {
9569
10616
  return result;
9570
10617
  };
9571
10618
  // ../pstdio-api-contracts/src/extension-kernel/types/extension.ts
9572
- var EXTENSION_API_VERSION = "0.2.0";
10619
+ var EXTENSION_API_VERSION = "0.2.1";
9573
10620
  // ../pstdio-api-contracts/src/extension-kernel/types/webview-capabilities.ts
9574
10621
  var WEBVIEW_HOST_CAPABILITY_VERSION = 1;
9575
10622
  var WEBVIEW_DECLARABLE_CAPABILITIES = [
9576
10623
  "clipboard.write",
9577
10624
  "commands.execute",
9578
10625
  "commands.stream",
10626
+ "harnesses.read",
10627
+ "resources.actions",
9579
10628
  "navigation.open",
9580
10629
  "page.params.update",
9581
10630
  "placement.close",
@@ -9898,6 +10947,10 @@ var reconcileMessageHistory = (input, projection = {}) => {
9898
10947
  throw error;
9899
10948
  }
9900
10949
  };
10950
+ // ../pstdio-api-contracts/src/link-icons.ts
10951
+ var linkIconSchema = object({
10952
+ data_url: string2()
10953
+ });
9901
10954
  // ../pstdio-api-contracts/src/pagination.ts
9902
10955
  var pageQuerySchema = object({ cursor: string2().optional(), limit: exports_coerce.number().optional() });
9903
10956
  // ../pstdio-api-contracts/src/session-request-values.ts
@@ -10876,131 +11929,6 @@ var createMemoryAssets = () => {
10876
11929
  return api;
10877
11930
  };
10878
11931
 
10879
- // ../pstdio-sync/src/encoding.ts
10880
- var encodeBytes = (bytes) => btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join(""));
10881
- var decodeBytes = (encoded) => Uint8Array.from(atob(encoded), (character) => character.charCodeAt(0));
10882
- var encodeText = (text) => encodeBytes(new TextEncoder().encode(text));
10883
- var decodeText = (encoded) => new TextDecoder().decode(decodeBytes(encoded));
10884
-
10885
- // ../pstdio-sync/src/namespaces.ts
10886
- var storageRecordId = (namespace, recordId) => JSON.stringify([...namespace, recordId]);
10887
- var scopeRecordStorage = (records, namespace) => {
10888
- return { id: (key) => storageRecordId(namespace, key), ...records };
10889
- };
10890
- var legacyNamespaceStorage = (records, namespace) => {
10891
- const prefix = `${JSON.stringify(namespace).slice(0, -1)},`;
10892
- const storedId = (id) => storageRecordId(namespace, id);
10893
- return {
10894
- read: (id) => records.read(storedId(id)),
10895
- list: async () => (await records.list()).filter((record) => record.recordId.startsWith(prefix)).map((record) => ({ ...record, recordId: JSON.parse(record.recordId).at(-1) })),
10896
- commit: (group) => records.commit({
10897
- ...group,
10898
- edits: group.edits.map((edit) => ({ ...edit, recordId: storedId(edit.recordId) }))
10899
- })
10900
- };
10901
- };
10902
-
10903
- // ../pstdio-sync/src/graph.ts
10904
- var orderOperations = (available, ids) => {
10905
- const remaining = new Set(ids);
10906
- const ordered = [];
10907
- while (remaining.size) {
10908
- const ready = [...remaining].filter((id) => available.get(id).parents.every((parent) => !remaining.has(parent)));
10909
- if (!ready.length)
10910
- throw new Error("Cyclic operation dependency");
10911
- for (const id of ready) {
10912
- ordered.push(available.get(id));
10913
- remaining.delete(id);
10914
- }
10915
- }
10916
- return ordered;
10917
- };
10918
-
10919
- // ../pstdio-sync/src/journal.ts
10920
- var completedOperations = (snapshot) => {
10921
- const completed = new Set;
10922
- for (const receipt of Object.values(snapshot?.receipts ?? {})) {
10923
- if (receipt.status !== "accepted")
10924
- continue;
10925
- completed.add(receipt.operationId);
10926
- for (const captured of receipt.mutation.resolution?.capturedOperationIds ?? [])
10927
- completed.add(captured);
10928
- }
10929
- return completed;
10930
- };
10931
- var retainAcceptance = (entry, receipt) => {
10932
- if (receipt.recoveryProof)
10933
- entry.recoveryProof = receipt.recoveryProof;
10934
- if (receipt.status !== "accepted" || !receipt.checkpoint)
10935
- return;
10936
- const next = { fingerprint: receipt.fingerprint, order: receipt.order, checkpoint: receipt.checkpoint };
10937
- const previous = entry.acceptance;
10938
- if (previous?.fingerprint === next.fingerprint && previous.order === next.order && previous.checkpoint.epoch === next.checkpoint.epoch && previous.checkpoint.sequence === next.checkpoint.sequence)
10939
- return;
10940
- entry.acceptance = next;
10941
- };
10942
- var checkScope = (state, scope) => {
10943
- if (scope.workbenchId !== state.owner.workbenchId || scope.extensionId !== state.owner.extensionId)
10944
- throw new Error("Relay scope belongs to another storage owner");
10945
- if (state.accepted && canonicalJson(state.accepted.scope) !== canonicalJson(scope))
10946
- throw new Error("Storage is already bound to another account");
10947
- };
10948
- var sealOperation = async (state, operation) => {
10949
- if (!state.accepted)
10950
- throw new Error("Storage has not received a relay snapshot");
10951
- return sealMutation({ ...operation, protocolVersion: 1, scope: state.accepted.scope });
10952
- };
10953
- var snapshotVersion = (snapshot) => snapshot && canonicalJson(snapshot);
10954
- var receiveSnapshot = async (state, snapshot, observed) => {
10955
- checkScope(state, snapshot.scope);
10956
- if (snapshotVersion(state.accepted) !== snapshotVersion(observed))
10957
- return;
10958
- if (state.accepted?.checkpoint.epoch === snapshot.checkpoint.epoch && (snapshot.journalSequence < state.accepted.journalSequence || snapshot.checkpoint.sequence < state.accepted.checkpoint.sequence))
10959
- return;
10960
- for (const receipt of Object.values(snapshot.receipts)) {
10961
- let entry = state.journal.find((entry) => entry.mutation.operationId === receipt.operationId);
10962
- if (entry) {
10963
- const sealed = await sealMutation({ ...entry.mutation, protocolVersion: 1, scope: snapshot.scope });
10964
- if (sealed.fingerprint !== receipt.fingerprint)
10965
- throw new Error("Received operation identity has changed content");
10966
- } else {
10967
- const { operationId, environmentId, parents, changes, resolution } = receipt.mutation;
10968
- entry = {
10969
- inputFingerprint: receipt.fingerprint,
10970
- mutation: { operationId, environmentId, parents, changes, resolution }
10971
- };
10972
- state.journal.push(entry);
10973
- }
10974
- retainAcceptance(entry, receipt);
10975
- }
10976
- state.accepted = snapshot;
10977
- };
10978
- var pendingOperations = (state, environmentId) => {
10979
- const completed = completedOperations(state.accepted);
10980
- const entries = new Map(state.journal.map((entry) => [entry.mutation.operationId, entry]));
10981
- const recovery = new Set;
10982
- const visit = (id) => {
10983
- if (completed.has(id) || recovery.has(id))
10984
- return;
10985
- const entry = entries.get(id);
10986
- if (!entry)
10987
- throw new Error("Journal dependency is unavailable");
10988
- recovery.add(id);
10989
- for (const parent of entry.mutation.parents)
10990
- visit(parent);
10991
- };
10992
- for (const entry of state.journal)
10993
- if (entry.acceptance && !completed.has(entry.mutation.operationId))
10994
- visit(entry.mutation.operationId);
10995
- const ordered = orderOperations(new Map([...entries].map(([id, entry]) => [id, entry.mutation])), recovery);
10996
- for (const entry of state.journal) {
10997
- const mutation = entry.mutation;
10998
- if (mutation.environmentId === environmentId && !completed.has(mutation.operationId) && !recovery.has(mutation.operationId))
10999
- ordered.push(mutation);
11000
- }
11001
- return ordered;
11002
- };
11003
-
11004
11932
  // ../../node_modules/.bun/lib0@0.2.117/node_modules/lib0/map.js
11005
11933
  var create = () => new Map;
11006
11934
  var copy = (m) => {
@@ -11719,13 +12647,13 @@ var equals = (a, b) => a === b || !!a?.[EqualityTraitSymbol]?.(b) || false;
11719
12647
  // ../../node_modules/.bun/lib0@0.2.117/node_modules/lib0/object.js
11720
12648
  var isObject2 = (o) => typeof o === "object";
11721
12649
  var assign = Object.assign;
11722
- var keys = Object.keys;
12650
+ var keys2 = Object.keys;
11723
12651
  var forEach = (obj, f) => {
11724
12652
  for (const key in obj) {
11725
12653
  f(obj[key], key);
11726
12654
  }
11727
12655
  };
11728
- var size = (obj) => keys(obj).length;
12656
+ var size = (obj) => keys2(obj).length;
11729
12657
  var isEmpty = (obj) => {
11730
12658
  for (const _k in obj) {
11731
12659
  return false;
@@ -13374,6 +14302,25 @@ var readStateVector = (decoder) => {
13374
14302
  return ss;
13375
14303
  };
13376
14304
  var decodeStateVector = (decodedState) => readStateVector(new DSDecoderV1(createDecoder(decodedState)));
14305
+ var writeStateVector = (encoder, sv) => {
14306
+ writeVarUint(encoder.restEncoder, sv.size);
14307
+ from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
14308
+ writeVarUint(encoder.restEncoder, client);
14309
+ writeVarUint(encoder.restEncoder, clock);
14310
+ });
14311
+ return encoder;
14312
+ };
14313
+ var writeDocumentStateVector = (encoder, doc) => writeStateVector(encoder, getStateVector(doc.store));
14314
+ var encodeStateVectorV2 = (doc, encoder = new DSEncoderV2) => {
14315
+ if (doc instanceof Map) {
14316
+ writeStateVector(encoder, doc);
14317
+ } else {
14318
+ writeDocumentStateVector(encoder, doc);
14319
+ }
14320
+ return encoder.toUint8Array();
14321
+ };
14322
+ var encodeStateVector = (doc) => encodeStateVectorV2(doc, new DSEncoderV1);
14323
+
13377
14324
  class EventHandler {
13378
14325
  constructor() {
13379
14326
  this.l = [];
@@ -13795,6 +14742,20 @@ class LazyStructReader {
13795
14742
  return this.curr;
13796
14743
  }
13797
14744
  }
14745
+ var decodeUpdate = (update) => decodeUpdateV2(update, UpdateDecoderV1);
14746
+ var decodeUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
14747
+ const structs = [];
14748
+ const updateDecoder = new YDecoder(createDecoder(update));
14749
+ const lazyDecoder = new LazyStructReader(updateDecoder, false);
14750
+ for (let curr = lazyDecoder.curr;curr !== null; curr = lazyDecoder.next()) {
14751
+ structs.push(curr);
14752
+ }
14753
+ return {
14754
+ structs,
14755
+ ds: readDeleteSet(updateDecoder)
14756
+ };
14757
+ };
14758
+
13798
14759
  class LazyStructWriter {
13799
14760
  constructor(encoder) {
13800
14761
  this.currClient = 0;
@@ -14232,6 +15193,16 @@ var updateMarkerChanges = (searchMarker, index, len) => {
14232
15193
  }
14233
15194
  }
14234
15195
  };
15196
+ var getTypeChildren = (t) => {
15197
+ t.doc ?? warnPrematureAccess();
15198
+ let s = t._start;
15199
+ const arr = [];
15200
+ while (s) {
15201
+ arr.push(s);
15202
+ s = s.right;
15203
+ }
15204
+ return arr;
15205
+ };
14235
15206
  var callTypeObservers = (type, transaction, event) => {
14236
15207
  const changedType = type;
14237
15208
  const changedParentTypes = transaction.changedParentTypes;
@@ -16823,813 +17794,507 @@ if (glo[importIdentifier] === true) {
16823
17794
  }
16824
17795
  glo[importIdentifier] = true;
16825
17796
 
16826
- // ../pstdio-sync/src/records.ts
16827
- var put = (target, key, value) => Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
16828
- var blankRecord = (recordId) => {
16829
- const record = {
16830
- recordId,
16831
- revision: 0,
16832
- deleted: false,
16833
- primitive: null,
16834
- map: {},
16835
- value: null,
16836
- asset: null
17797
+ // ../pstdio-sync/src/document-types.ts
17798
+ var memoryDocumentState = (document2) => {
17799
+ const operations = new Map;
17800
+ return {
17801
+ document: document2,
17802
+ operation: async (id) => operations.get(id),
17803
+ remember: (id, fingerprint) => {
17804
+ operations.set(id, fingerprint);
17805
+ }
16837
17806
  };
16838
- return record;
16839
17807
  };
16840
- var openDocument = (record) => {
16841
- const document2 = new Doc2;
16842
- if (record.shared)
16843
- applyUpdate(document2, decodeBytes(record.shared.update));
16844
- return document2;
16845
- };
16846
- var sharedValue = (record) => {
16847
- if (record.primitive === "map")
16848
- return { kind: "map", value: structuredClone(record.map) };
16849
- if (!record.primitive)
16850
- return null;
16851
- const document2 = openDocument(record);
16852
- try {
16853
- if (record.primitive === "text")
16854
- return { kind: "text", value: document2.getText("body").toString() };
16855
- return { kind: "list", value: document2.getArray("items").toArray() };
16856
- } finally {
16857
- document2.destroy();
16858
- }
16859
- };
16860
- var publicRecord = (record) => ({
16861
- recordId: record.recordId,
16862
- exists: record.revision > 0,
16863
- value: structuredClone(record.value),
16864
- asset: structuredClone(record.asset),
16865
- deleted: record.deleted,
16866
- shared: sharedValue(record)
16867
- });
16868
- var cellFingerprint = (map, key) => fingerprint({ exists: Object.hasOwn(map, key), value: Object.hasOwn(map, key) ? map[key] : null });
16869
- var recordConflict = async (record, change) => {
16870
- if (record.deleted !== change.baseDeleted)
16871
- return "delete versus edit";
16872
- if (change.deleted !== undefined && record.revision !== change.expectedRevision)
16873
- return "delete versus edit";
16874
- if (change.expectedRevision > record.revision)
16875
- return "unknown base revision";
16876
- if (change.asset && canonicalJson(record.asset) !== canonicalJson(change.asset.base) && canonicalJson(record.asset) !== canonicalJson(change.asset.next))
16877
- return "competing asset replacements";
16878
- if (change.value && await fingerprint(record.value) !== change.value.expected)
16879
- return "competing JSON replacements";
16880
- if (change.shared && record.primitive && change.shared.kind !== record.primitive)
16881
- return "incompatible shared primitive";
16882
- if (change.shared?.kind === "map") {
16883
- for (const entry of change.shared.entries)
16884
- if (await cellFingerprint(record.map, entry.key) !== entry.expected)
16885
- return "competing map key edits";
16886
- }
16887
- };
16888
- var applySequenceEdit = (document2, edit) => {
16889
- if (edit.kind === "text.insert")
16890
- document2.getText("body").insert(edit.index, edit.text);
16891
- if (edit.kind === "text.delete")
16892
- document2.getText("body").delete(edit.index, edit.count);
16893
- if (edit.kind === "list.insert")
16894
- document2.getArray("items").insert(edit.index, edit.values);
16895
- if (edit.kind === "list.delete")
16896
- document2.getArray("items").delete(edit.index, edit.count);
16897
- };
16898
- var sharedChange = async (record, edits) => {
16899
- const document2 = openDocument(record);
16900
- const entries = new Map;
16901
- let kind;
16902
- try {
16903
- for (const edit of edits) {
16904
- const nextKind = edit.kind.split(".")[0];
16905
- if (kind && kind !== nextKind)
16906
- throw new Error("One shared primitive per record");
16907
- kind = nextKind;
16908
- applySequenceEdit(document2, edit);
16909
- if (edit.kind === "map.set" || edit.kind === "map.delete") {
16910
- entries.set(edit.key, {
16911
- key: edit.key,
16912
- expected: await cellFingerprint(record.map, edit.key),
16913
- next: edit.kind === "map.set" ? { kind: "set", value: edit.value } : { kind: "delete" }
16914
- });
16915
- }
17808
+
17809
+ // ../pstdio-sync/src/checkpoint-capture.ts
17810
+ async function captureCheckpoint(document2, owner, action, observer) {
17811
+ const fork = new Doc2;
17812
+ const baseline = encodeStateVector(document2);
17813
+ applyUpdate(fork, encodeStateAsUpdate(document2));
17814
+ const state = memoryDocumentState(fork);
17815
+ const store = {
17816
+ observer,
17817
+ transaction: async (target, run) => {
17818
+ if (target.workbenchId !== owner.workbenchId || target.extensionId !== owner.extensionId)
17819
+ throw new Error("A checkpoint cannot cross its storage owner");
17820
+ return run(state);
16916
17821
  }
16917
- if (!kind)
16918
- throw new Error("Empty shared edit");
16919
- if (kind === "map")
16920
- return { kind, entries: [...entries.values()] };
16921
- return { kind, update: encodeBytes(encodeStateAsUpdate(document2)) };
17822
+ };
17823
+ try {
17824
+ const value = await action(store);
17825
+ return { value, update: encodeStateAsUpdate(fork, baseline) };
16922
17826
  } finally {
16923
- document2.destroy();
17827
+ fork.destroy();
16924
17828
  }
17829
+ }
17830
+ // ../pstdio-sync/src/document-history.ts
17831
+ var ranges = (items) => {
17832
+ const merged = [];
17833
+ for (const item of items.sort(([a, b], [c, d]) => a - c || b - d)) {
17834
+ const previous = merged.at(-1);
17835
+ if (previous && previous[0] === item[0] && previous[1] + previous[2] === item[1] && previous[3] === item[3])
17836
+ previous[2] += item[2];
17837
+ else
17838
+ merged.push([...item]);
17839
+ }
17840
+ return JSON.stringify(merged);
16925
17841
  };
16926
- var applyRecordChange = (record, change) => {
16927
- const next = structuredClone(record);
16928
- if (change.shared)
16929
- next.primitive = change.shared.kind;
16930
- if (change.shared?.kind === "map") {
16931
- for (const entry of change.shared.entries) {
16932
- if (entry.next.kind === "delete")
16933
- delete next.map[entry.key];
17842
+ var documentHistory = (document2) => {
17843
+ const decoded = decodeUpdate(encodeStateAsUpdate(document2));
17844
+ const clients = new Map;
17845
+ for (const struct of decoded.structs) {
17846
+ const items = clients.get(struct.id.client) ?? [];
17847
+ items.push(struct);
17848
+ clients.set(struct.id.client, items);
17849
+ }
17850
+ const itemAt = (id) => {
17851
+ const items = clients.get(id.client) ?? [];
17852
+ let low = 0;
17853
+ let high = items.length;
17854
+ while (low < high) {
17855
+ const middle = low + high >>> 1;
17856
+ if (items[middle].id.clock + items[middle].length <= id.clock)
17857
+ low = middle + 1;
16934
17858
  else
16935
- put(next.map, entry.key, entry.next.value);
17859
+ high = middle;
16936
17860
  }
16937
- } else if (change.shared) {
16938
- const document2 = openDocument(record);
17861
+ return items[low];
17862
+ };
17863
+ const addresses = new Map;
17864
+ const address = (item) => {
17865
+ const chain = [];
17866
+ let current = item;
17867
+ let result;
17868
+ while (current) {
17869
+ if (addresses.has(current)) {
17870
+ result = addresses.get(current);
17871
+ break;
17872
+ }
17873
+ chain.push(current);
17874
+ if (typeof current.parent === "string") {
17875
+ result = { parent: current.parent, key: current.parentSub };
17876
+ break;
17877
+ }
17878
+ const origin = current.origin ?? current.rightOrigin;
17879
+ const previous = origin && itemAt(origin);
17880
+ current = previous instanceof Item ? previous : undefined;
17881
+ }
17882
+ for (const entry of chain)
17883
+ addresses.set(entry, result);
17884
+ return result;
17885
+ };
17886
+ const fieldRanges = new Map;
17887
+ for (const item of decoded.structs) {
17888
+ if (!(item instanceof Item))
17889
+ continue;
17890
+ const field = address(item);
17891
+ if (!field || field.key === null)
17892
+ continue;
17893
+ const key = JSON.stringify([field.parent, field.key]);
17894
+ const entries = fieldRanges.get(key) ?? [];
17895
+ entries.push([item.id.client, item.id.clock, item.length, isDeleted(decoded.ds, item.id)]);
17896
+ fieldRanges.set(key, entries);
17897
+ }
17898
+ const fields = new Map([...fieldRanges].map(([key, entries]) => [key, ranges(entries)]));
17899
+ const sequences = new Map([...document2.share].map(([name, type]) => [
17900
+ name,
17901
+ ranges(getTypeChildren(type).map((item) => [item.id.client, item.id.clock, item.length, item.deleted]))
17902
+ ]));
17903
+ return { fields, sequences };
17904
+ };
17905
+ // ../pstdio-sync/src/document-author.ts
17906
+ var documentAuthorId = (key) => {
17907
+ let first = 2166136261;
17908
+ let second = 3339675911;
17909
+ for (let index = 0;index < key.length; index++) {
17910
+ first = Math.imul(first ^ key.charCodeAt(index), 16777619) >>> 0;
17911
+ second = Math.imul(second ^ key.charCodeAt(index), 2246822519) >>> 0;
17912
+ }
17913
+ return 2 ** 48 + first * 65536 + (second >>> 16);
17914
+ };
17915
+ var migrationAuthor = (document2, seed, history) => {
17916
+ if (!seed)
17917
+ return;
17918
+ const author = (parent, key, value, action) => {
17919
+ const current = document2.getMap(parent).get(key);
17920
+ let sequence = null;
17921
+ if (current?.kind === "text")
17922
+ sequence = history?.sequences.get(current.name) ?? null;
17923
+ if (current?.kind === "list")
17924
+ sequence = history?.sequences.get(`${current.name}:order`) ?? null;
17925
+ const previous = document2.clientID;
17926
+ document2.clientID = documentAuthorId(canonicalJson([seed, parent, key, history?.fields.get(JSON.stringify([parent, key])) ?? null, sequence, value]));
16939
17927
  try {
16940
- applyUpdate(document2, decodeBytes(change.shared.update));
16941
- next.shared = { kind: change.shared.kind, update: encodeBytes(encodeStateAsUpdate(document2)) };
17928
+ return action();
16942
17929
  } finally {
16943
- document2.destroy();
17930
+ document2.clientID = previous;
16944
17931
  }
16945
- }
16946
- if (change.value)
16947
- next.value = change.value.next;
16948
- if (change.asset)
16949
- next.asset = change.asset.next;
16950
- next.deleted = change.deleted ?? change.baseDeleted;
16951
- next.revision++;
16952
- return next;
16953
- };
16954
-
16955
- // ../pstdio-sync/src/resolution-validation.ts
16956
- var parentProblem = (state, operation, captured, visited) => {
16957
- for (const parent of operation.parents) {
16958
- if (captured.has(parent)) {
16959
- if (!visited.has(parent))
16960
- return "captured branch is not in ancestry order";
16961
- } else if (!state.availableParentIds.has(parent))
16962
- return "uncaptured unaccepted prerequisite";
16963
- }
16964
- };
16965
- var connectedSize = (operations, rootId) => {
16966
- const captured = new Set(operations.map((operation) => operation.operationId));
16967
- const edges = new Map;
16968
- for (const operation of operations) {
16969
- for (const parent of operation.parents.filter((id) => captured.has(id))) {
16970
- edges.set(operation.operationId, new Set([...edges.get(operation.operationId) ?? [], parent]));
16971
- edges.set(parent, new Set([...edges.get(parent) ?? [], operation.operationId]));
16972
- }
16973
- }
16974
- const connected = new Set([rootId]);
16975
- for (const id of connected)
16976
- for (const next of edges.get(id) ?? [])
16977
- connected.add(next);
16978
- return connected.size;
16979
- };
16980
- var captureProblem = (state, mutation) => {
16981
- const proposal = mutation.resolution;
16982
- const captured = new Set(proposal.capturedOperationIds);
16983
- if (!captured.has(proposal.conflictId))
16984
- return "resolution must capture its root conflict";
16985
- const visited = new Set;
16986
- const recordIds = new Set;
16987
- const operations = [];
16988
- for (const id of proposal.capturedOperationIds) {
16989
- const operation = state.operations.get(id);
16990
- if (!operation || state.acceptedOperationIds.has(id))
16991
- return "captured branch is unavailable";
16992
- const problem = parentProblem(state, operation, captured, visited);
16993
- if (problem)
16994
- return problem;
16995
- operations.push(operation);
16996
- visited.add(id);
16997
- for (const change of operation.changes)
16998
- recordIds.add(change.recordId);
16999
- }
17000
- if (connectedSize(operations, proposal.conflictId) !== captured.size)
17001
- return "unrelated captured operation";
17002
- if (recordIds.size !== mutation.changes.length || mutation.changes.some((change) => !recordIds.has(change.recordId)))
17003
- return "resolution omits captured records";
17004
- };
17005
- var validateResolution = (state, mutation) => {
17006
- const proposal = mutation.resolution;
17007
- if (!proposal)
17008
- return;
17009
- const root = state.conflicts.get(proposal.conflictId);
17010
- if (!root || root.resolvedBy)
17011
- return "stale conflict revision";
17012
- for (const expected of proposal.expectedConflicts) {
17013
- const conflict = state.conflicts.get(expected.conflictId);
17014
- if (!conflict || conflict.revision !== expected.revision)
17015
- return "stale conflict revision";
17016
- }
17017
- const captured = new Set(proposal.capturedOperationIds);
17018
- const affected = [...state.conflicts.values()].filter((conflict) => conflict.alternativeOperationIds.some((id) => captured.has(id)));
17019
- if (affected.length !== proposal.expectedConflicts.length || affected.some((conflict) => !proposal.expectedConflicts.some((entry) => entry.conflictId === conflict.conflictId)))
17020
- return "missing captured conflict revision";
17021
- if (proposal.handler && proposal.handler.publishedRevision !== state.publishedRevision)
17022
- return "stale published handler revision";
17023
- for (const expected of proposal.expectedInputs)
17024
- if (expected.revision !== (state.records.get(expected.recordId)?.revision ?? 0))
17025
- return "stale input revision";
17026
- for (const change of mutation.changes) {
17027
- const record = state.records.get(change.recordId) ?? blankRecord(change.recordId);
17028
- if (change.shared && record.primitive && change.shared.kind !== record.primitive)
17029
- return "incompatible shared primitive";
17030
- }
17031
- return captureProblem(state, mutation);
17932
+ };
17933
+ return author;
17032
17934
  };
17033
17935
 
17034
- // ../pstdio-sync/src/resolution-preflight.ts
17035
- var resolutionGuards = (state, current) => {
17036
- const conflicts = new Map(Object.values(state.accepted?.conflicts ?? {}).map((conflict) => [conflict.conflictId, conflict]));
17037
- for (const conflict of current)
17038
- conflicts.set(conflict.conflictId, conflict);
17039
- return conflicts;
17040
- };
17041
- var resolutionProblem = (view, state, mutation) => {
17042
- if (mutation.resolution && !view.conflicts.has(mutation.resolution.conflictId))
17043
- return "stale conflict revision";
17044
- return validateResolution({
17045
- records: view.records,
17046
- conflicts: resolutionGuards(state, view.conflicts.values()),
17047
- operations: new Map(state.journal.map((entry) => [entry.mutation.operationId, entry.mutation])),
17048
- acceptedOperationIds: new Set(Object.values(state.accepted?.receipts ?? {}).filter((receipt) => receipt.status === "accepted").map((receipt) => receipt.operationId)),
17049
- availableParentIds: new Set([...view.outcomes].filter(([, outcome]) => outcome.status !== "conflict").map(([id]) => id)),
17050
- publishedRevision: state.accepted?.publishedRevision
17051
- }, mutation);
17052
- };
17053
- var retainAfterResolution = (view, mutation) => {
17054
- const proposal = mutation.resolution;
17055
- const captured = new Set(proposal.capturedOperationIds);
17056
- for (const id of captured)
17057
- view.completed.add(id);
17058
- for (const expected of proposal.expectedConflicts) {
17059
- const conflict = view.conflicts.get(expected.conflictId);
17060
- if (!conflict)
17061
- continue;
17062
- view.conflicts.delete(expected.conflictId);
17063
- for (const alternative of conflict.alternatives) {
17064
- if (captured.has(alternative.operationId))
17065
- continue;
17066
- view.conflicts.set(alternative.operationId, {
17067
- conflictId: alternative.operationId,
17068
- revision: 1,
17069
- recordIds: alternative.records.map((record) => record.recordId),
17070
- alternativeOperationIds: [alternative.operationId],
17071
- reason: conflict.reason,
17072
- alternatives: [alternative]
17073
- });
17936
+ // ../pstdio-sync/src/document-values.ts
17937
+ var import_fast_diff = __toESM(require_diff(), 1);
17938
+ var readValue = (value, document2) => {
17939
+ if (value === null || typeof value !== "object")
17940
+ return value ?? null;
17941
+ const reference = value;
17942
+ if (reference.kind === "text")
17943
+ return document2.getText(reference.name).toString();
17944
+ if (reference.kind === "list") {
17945
+ const items = document2.getMap(`${reference.name}:items`);
17946
+ const order = document2.getArray(`${reference.name}:order`).toArray();
17947
+ return order.filter((key, index) => items.has(key) && order.lastIndexOf(key) === index).map((key) => readValue(items.get(key), document2));
17948
+ }
17949
+ return Object.fromEntries([...document2.getMap(reference.name)].map(([key, entry]) => [key, readValue(entry, document2)]));
17950
+ };
17951
+ var writeText = (text, next) => {
17952
+ let index = 0;
17953
+ for (const [operation, value] of import_fast_diff.default(text.toString(), next)) {
17954
+ if (operation === -1)
17955
+ text.delete(index, value.length);
17956
+ else {
17957
+ if (operation === 1)
17958
+ text.insert(index, value);
17959
+ index += value.length;
17074
17960
  }
17075
17961
  }
17076
17962
  };
17077
-
17078
- // ../pstdio-sync/src/projection.ts
17079
- var receiptOutcome = (state, receipt) => {
17080
- if (receipt.status === "accepted")
17081
- return { status: "synchronized", operationId: receipt.operationId, checkpoint: receipt.checkpoint };
17082
- if (receipt.status === "conflict")
17083
- return {
17084
- status: "conflict",
17085
- operationId: receipt.operationId,
17086
- conflictId: receipt.conflictId,
17087
- conflictRevision: state.accepted.conflicts[receipt.conflictId].revision
17088
- };
17089
- return {
17090
- status: "pending",
17091
- operationId: receipt.operationId,
17092
- reason: receipt.reason ?? "awaiting dependency"
17093
- };
17094
- };
17095
- var acceptedProjection = (state) => {
17096
- const records = new Map(Object.entries(structuredClone(state.accepted?.records ?? {})));
17097
- const operations = new Map;
17098
- const outcomes = new Map;
17099
- const receipts = Object.values(state.accepted?.receipts ?? {}).sort((left, right) => (left.checkpoint?.sequence ?? 0) - (right.checkpoint?.sequence ?? 0));
17100
- for (const receipt of receipts) {
17101
- outcomes.set(receipt.operationId, receiptOutcome(state, receipt));
17102
- if (receipt.status === "accepted")
17103
- for (const change of receipt.mutation.changes)
17104
- operations.set(change.recordId, [...operations.get(change.recordId) ?? [], receipt.operationId]);
17105
- }
17106
- return {
17107
- records,
17108
- operations,
17109
- outcomes,
17110
- applied: new Set(receipts.filter((receipt) => receipt.status === "accepted").map((receipt) => receipt.operationId)),
17111
- completed: completedOperations(state.accepted),
17112
- conflicts: new Map(Object.values(state.accepted?.conflicts ?? {}).filter((conflict) => !conflict.resolvedBy).map((conflict) => [
17113
- conflict.conflictId,
17114
- {
17115
- ...structuredClone(conflict),
17116
- reason: "Retained alternative",
17117
- alternatives: []
17118
- }
17119
- ]))
17120
- };
17121
- };
17122
- var addConflict = (view, mutation, conflictId, reason) => {
17123
- const conflict = view.conflicts.get(conflictId) ?? {
17124
- conflictId,
17125
- reason,
17126
- revision: 1,
17127
- recordIds: mutation.changes.map((change) => change.recordId),
17128
- alternativeOperationIds: [],
17129
- alternatives: []
17130
- };
17131
- if (!conflict.alternativeOperationIds.includes(mutation.operationId))
17132
- conflict.alternativeOperationIds.push(mutation.operationId);
17133
- conflict.alternatives.push({
17134
- operationId: mutation.operationId,
17135
- records: mutation.changes.map((change) => applyRecordChange(view.records.get(change.recordId) ?? blankRecord(change.recordId), change))
17136
- });
17137
- view.conflicts.set(conflictId, conflict);
17138
- view.outcomes.set(mutation.operationId, {
17139
- status: "conflict",
17140
- operationId: mutation.operationId,
17141
- conflictId,
17142
- conflictRevision: conflict.revision
17963
+ var listKeys = (values) => {
17964
+ const seen = new Map;
17965
+ return values.map((value) => {
17966
+ const identity = value && typeof value === "object" && !Array.isArray(value) && "id" in value ? canonicalJson(["id", value.id]) : canonicalJson(["value", value]);
17967
+ const occurrence = seen.get(identity) ?? 0;
17968
+ seen.set(identity, occurrence + 1);
17969
+ return canonicalJson([identity, occurrence]);
17143
17970
  });
17144
17971
  };
17145
- var localOutcome = (state, entry) => {
17146
- const operationId = entry.mutation.operationId;
17147
- if (!state.accepted)
17148
- return { status: "saved-locally", operationId };
17149
- if (entry.acceptance?.checkpoint.epoch === state.accepted.checkpoint.epoch)
17150
- return { status: "synchronized", operationId, checkpoint: entry.acceptance.checkpoint };
17151
- return { status: "pending", operationId, reason: "awaiting relay acceptance" };
17152
- };
17153
- var operationProblem = async (view, state, mutation) => {
17154
- if (mutation.resolution)
17155
- return resolutionProblem(view, state, mutation);
17156
- const blocked = mutation.parents.map((id) => view.outcomes.get(id)).find((outcome) => outcome?.status === "conflict");
17157
- if (blocked)
17158
- return "Unaccepted dependency";
17159
- const problems = await Promise.all(mutation.changes.map((change) => recordConflict(view.records.get(change.recordId) ?? blankRecord(change.recordId), change)));
17160
- return problems.find((problem) => problem !== undefined);
17161
- };
17162
- var advanceConflicts = (view, mutation) => {
17163
- for (const conflict of view.conflicts.values())
17164
- if (mutation.changes.some((change) => conflict.recordIds.includes(change.recordId)))
17165
- conflict.revision++;
17166
- };
17167
- var waitingForParent = (view, mutation) => {
17168
- const captured = new Set(mutation.resolution?.capturedOperationIds ?? []);
17169
- return mutation.parents.some((id) => !captured.has(id) && !view.applied.has(id) && view.outcomes.get(id)?.status !== "conflict");
17170
- };
17171
- var applyOperation = (view, mutation) => {
17172
- if (mutation.resolution)
17173
- retainAfterResolution(view, mutation);
17174
- for (const change of mutation.changes) {
17175
- view.records.set(change.recordId, applyRecordChange(view.records.get(change.recordId) ?? blankRecord(change.recordId), change));
17176
- view.operations.set(change.recordId, [...view.operations.get(change.recordId) ?? [], mutation.operationId]);
17177
- }
17178
- view.applied.add(mutation.operationId);
17179
- };
17180
- var projectOperation = async (view, state, entry, environmentId) => {
17181
- const mutation = entry.mutation;
17182
- if (view.completed.has(mutation.operationId))
17183
- return;
17184
- const known = state.accepted?.receipts[mutation.operationId];
17185
- const retained = known?.status === "conflict" ? Object.values(state.accepted.conflicts).find((conflict) => !conflict.resolvedBy && conflict.alternativeOperationIds.includes(mutation.operationId)) : undefined;
17186
- if (mutation.environmentId !== environmentId && !entry.acceptance && known?.status !== "conflict")
17187
- return;
17188
- if (known?.status !== "conflict" && waitingForParent(view, mutation)) {
17189
- view.outcomes.set(mutation.operationId, {
17190
- status: "pending",
17191
- operationId: mutation.operationId,
17192
- reason: "awaiting dependency"
17193
- });
17194
- return;
17195
- }
17196
- const blocked = mutation.parents.map((id) => view.outcomes.get(id)).find((outcome) => outcome?.status === "conflict");
17197
- const problem = await operationProblem(view, state, mutation);
17198
- if (!known && !blocked)
17199
- advanceConflicts(view, mutation);
17200
- if (known?.status === "conflict" || problem) {
17201
- addConflict(view, mutation, retained?.conflictId ?? (mutation.resolution && view.conflicts.has(mutation.resolution.conflictId) ? mutation.resolution.conflictId : undefined) ?? blocked?.conflictId ?? mutation.operationId, problem ?? "Unaccepted dependency");
17202
- return;
17203
- }
17204
- applyOperation(view, mutation);
17205
- view.outcomes.set(mutation.operationId, localOutcome(state, entry));
17206
- };
17207
- var projectGroups = async (state, environmentId) => {
17208
- const view = acceptedProjection(state);
17209
- for (const entry of state.journal)
17210
- await projectOperation(view, state, entry, environmentId);
17211
- const read = (recordId) => ({
17212
- ...publicRecord(view.records.get(recordId) ?? blankRecord(recordId)),
17213
- revision: encodeText(JSON.stringify({ owner: state.owner, recordId, operations: view.operations.get(recordId) ?? [] }))
17214
- });
17215
- return {
17216
- read,
17217
- records: view.records,
17218
- operations: view.operations,
17219
- outcomes: view.outcomes,
17220
- conflicts: [...view.conflicts.values()],
17221
- completed: view.completed
17222
- };
17223
- };
17224
-
17225
- // ../pstdio-sync/src/authoring.ts
17226
- var recordVersion = (state, recordId, captured) => {
17227
- const token = JSON.parse(decodeText(captured));
17228
- if (token.owner.workbenchId !== state.owner.workbenchId || token.owner.extensionId !== state.owner.extensionId)
17229
- throw new Error("Revision belongs to another storage owner");
17230
- if (token.recordId !== recordId)
17231
- throw new Error("Revision belongs to another record");
17232
- let record = blankRecord(recordId);
17233
- for (const operationId of token.operations) {
17234
- const entry = state.journal.find((entry) => entry.mutation.operationId === operationId);
17235
- if (!entry)
17236
- throw new Error("Unknown record revision");
17237
- const change = entry.mutation.changes.find((change) => change.recordId === recordId);
17238
- if (change)
17239
- record = applyRecordChange(record, change);
17240
- }
17241
- return { record, operations: token.operations };
17242
- };
17243
- var authorGroup = async (state, input, environmentId) => {
17244
- const parents = new Set;
17245
- const { completed } = await projectGroups(state, environmentId);
17246
- const changes = await Promise.all(input.edits.map(async (edit) => {
17247
- const base = recordVersion(state, edit.recordId, edit.expectedRevision);
17248
- for (const id of base.operations)
17249
- if (!completed.has(id))
17250
- parents.add(id);
17251
- return {
17252
- recordId: edit.recordId,
17253
- expectedRevision: base.record.revision,
17254
- baseDeleted: base.record.deleted,
17255
- ...Object.hasOwn(edit, "replace") && {
17256
- value: { expected: await fingerprint(base.record.value), next: edit.replace }
17257
- },
17258
- ...edit.shared && { shared: await sharedChange(base.record, edit.shared) },
17259
- ...edit.asset !== undefined && { asset: { base: base.record.asset, next: edit.asset } },
17260
- ...edit.deleted !== undefined && { deleted: edit.deleted }
17261
- };
17262
- }));
17263
- return { operationId: input.operationId, environmentId, parents: [...parents], changes };
17264
- };
17265
- var inputFingerprint = (input) => fingerprint(input);
17266
- var entryFor = async (state, input, environmentId) => ({
17267
- inputFingerprint: await inputFingerprint(input),
17268
- mutation: await authorGroup(state, input, environmentId)
17269
- });
17270
-
17271
- // ../pstdio-sync/src/branches.ts
17272
- var workingRecords = (state, environmentId) => {
17273
- const pending = pendingOperations(state, environmentId);
17274
- const replaced = new Set(pending.flatMap((operation) => operation.resolution?.capturedOperationIds ?? []));
17275
- const records = new Map(Object.entries(structuredClone(state.accepted?.records ?? {})));
17276
- for (const mutation of pending) {
17277
- if (replaced.has(mutation.operationId))
17972
+ var valueReference = (parent, key, kind, path) => {
17973
+ const current = parent.get(key);
17974
+ if (current?.kind === kind)
17975
+ return current;
17976
+ const reference = { kind, name: `${path.length}:${path}${key.length}:${key}:${kind}` };
17977
+ parent.set(key, reference);
17978
+ return reference;
17979
+ };
17980
+ var writeList = (document2, name, values, author) => {
17981
+ const items = document2.getMap(`${name}:items`);
17982
+ const order = document2.getArray(`${name}:order`);
17983
+ const keys = listKeys(values);
17984
+ const wanted = new Set(keys);
17985
+ for (const key of items.keys())
17986
+ if (!wanted.has(key))
17987
+ items.delete(key);
17988
+ for (let index = 0;index < keys.length; index++)
17989
+ writeValue(items, keys[index], values[index], `${name}:items`, author);
17990
+ const current = order.toArray();
17991
+ for (let index = current.length - 1;index >= 0; index--) {
17992
+ if (!wanted.has(current[index]) || current.lastIndexOf(current[index]) !== index)
17993
+ order.delete(index, 1);
17994
+ }
17995
+ for (let index = 0;index < keys.length; index++) {
17996
+ if (order.get(index) === keys[index])
17278
17997
  continue;
17279
- for (const change of mutation.changes)
17280
- records.set(change.recordId, applyRecordChange(records.get(change.recordId) ?? blankRecord(change.recordId), change));
17281
- }
17282
- return Object.fromEntries(records);
17283
- };
17284
- var ancestors = (state, operationId) => {
17285
- const available = new Map(state.journal.map((entry) => [entry.mutation.operationId, entry.mutation]));
17286
- const required = new Set([operationId]);
17287
- for (const id of required) {
17288
- const operation = available.get(id);
17289
- if (!operation)
17290
- throw new Error("Branch operation is unavailable");
17291
- for (const parent of operation.parents)
17292
- if (state.accepted?.receipts[parent]?.status !== "accepted")
17293
- required.add(parent);
17294
- }
17295
- return orderOperations(available, required);
17296
- };
17297
- var readBranch = async (state, environmentId, recordId, operationId) => {
17298
- const view = await projectGroups(state, environmentId);
17299
- const applied = new Set([...view.operations.values()].flat());
17300
- const branch = ancestors(state, operationId);
17301
- const replaced = new Set(branch.flatMap((mutation) => mutation.resolution?.capturedOperationIds ?? []));
17302
- for (const mutation of branch) {
17303
- if (replaced.has(mutation.operationId))
17304
- continue;
17305
- if (applied.has(mutation.operationId))
17306
- continue;
17307
- for (const change of mutation.changes) {
17308
- view.records.set(change.recordId, applyRecordChange(view.records.get(change.recordId) ?? blankRecord(change.recordId), change));
17309
- view.operations.set(change.recordId, [...view.operations.get(change.recordId) ?? [], mutation.operationId]);
17310
- }
17311
- applied.add(mutation.operationId);
17998
+ const previous = order.toArray().indexOf(keys[index], index);
17999
+ if (previous >= 0)
18000
+ order.delete(previous, 1);
18001
+ order.insert(index, [keys[index]]);
17312
18002
  }
17313
- return {
17314
- ...publicRecord(view.records.get(recordId) ?? blankRecord(recordId)),
17315
- revision: encodeText(JSON.stringify({ owner: state.owner, recordId, operations: view.operations.get(recordId) ?? [] }))
17316
- };
17317
- };
17318
-
17319
- // ../pstdio-sync/src/capture.ts
17320
- var captureBranch = (state, environmentId, rootId, published = new Set) => {
17321
- const available = new Map(state.journal.map((entry) => [entry.mutation.operationId, entry.mutation]));
17322
- const captured = new Set([rootId]);
17323
- const pending = pendingOperations(state, environmentId);
17324
- let changed = true;
17325
- while (changed) {
17326
- const before = captured.size;
17327
- for (const mutation of pending.filter((operation) => !published.has(operation.operationId)))
17328
- if (mutation.parents.some((parent) => captured.has(parent)))
17329
- captured.add(mutation.operationId);
17330
- for (const id of captured) {
17331
- const mutation = available.get(id);
17332
- if (!mutation)
17333
- throw new Error("Captured branch is unavailable");
17334
- for (const parent of mutation.parents)
17335
- if (state.accepted?.receipts[parent]?.status !== "accepted" && !published.has(parent))
17336
- captured.add(parent);
17337
- }
17338
- changed = captured.size !== before;
17339
- }
17340
- return orderOperations(available, captured);
17341
18003
  };
17342
-
17343
- // ../pstdio-sync/src/resolution.ts
17344
- var inspectConflict = async (state, environmentId, conflictId) => {
17345
- const known = state.accepted?.conflicts[conflictId];
17346
- const view = await projectGroups(state, environmentId);
17347
- const conflict = view.conflicts.find((entry) => entry.conflictId === conflictId);
17348
- if (!conflict || "resolvedBy" in conflict && conflict.resolvedBy)
17349
- throw new Error("No unresolved conflict");
17350
- const published = new Set([...view.outcomes].filter(([, outcome]) => outcome.status !== "conflict").map(([id]) => id));
17351
- const branch = captureBranch(state, environmentId, conflictId, known ? undefined : published);
17352
- const captured = new Set(branch.map((mutation) => mutation.operationId));
17353
- const ids = [...new Set(branch.flatMap((mutation) => mutation.changes.map((change) => change.recordId)))];
17354
- const accepted = ids.map(view.read);
17355
- return {
17356
- conflictId,
17357
- revision: conflict.revision,
17358
- expectedConflicts: [...resolutionGuards(state, view.conflicts).values()].filter((entry) => entry.alternativeOperationIds.some((id) => captured.has(id))).map((entry) => ({ conflictId: entry.conflictId, revision: entry.revision })),
17359
- capturedOperationIds: [...captured],
17360
- expectedInputs: accepted.map(({ recordId, revision }) => ({ recordId, revision })),
17361
- accepted,
17362
- alternatives: await Promise.all(branch.map(async (mutation) => ({
17363
- operationId: mutation.operationId,
17364
- parents: mutation.parents,
17365
- records: await Promise.all(mutation.changes.map((change) => readBranch(state, environmentId, change.recordId, mutation.operationId)))
17366
- })))
17367
- };
17368
- };
17369
- var resolutionShared = async (current, draft, choose) => {
17370
- const selected = choose === "local" ? draft : current;
17371
- const source = choose === "remote" && current.primitive !== draft.primitive ? current : draft;
17372
- if (source.primitive !== "map")
17373
- return source.shared;
17374
- const keys = [...new Set([...Object.keys(source.map), ...Object.keys(current.map)])];
17375
- if (!keys.length)
18004
+ var writeValue = (parent, key, next, path, author) => {
18005
+ const write = () => writeValueContent(parent, key, next, path, author);
18006
+ if (author)
18007
+ author(path, key, next, write);
18008
+ else
18009
+ write();
18010
+ };
18011
+ var writeValueContent = (parent, key, next, path, author) => {
18012
+ const current = parent.get(key);
18013
+ const document2 = parent.doc;
18014
+ if (Array.isArray(next)) {
18015
+ const reference = valueReference(parent, key, "list", path);
18016
+ writeList(document2, reference.name, next, author);
18017
+ } else if (next !== null && typeof next === "object") {
18018
+ const reference = valueReference(parent, key, "object", path);
18019
+ const map = document2.getMap(reference.name);
18020
+ for (const field of map.keys())
18021
+ if (!Object.hasOwn(next, field))
18022
+ map.delete(field);
18023
+ for (const [field, value] of Object.entries(next).sort(([a], [b]) => a.localeCompare(b)))
18024
+ writeValue(map, field, value, reference.name, author);
18025
+ } else if (typeof next === "string" && (next.includes(`
18026
+ `) || current && typeof current === "object" && ("kind" in current) && current.kind === "text")) {
18027
+ const reference = valueReference(parent, key, "text", path);
18028
+ if (typeof current === "string")
18029
+ seedText(document2, reference.name, current);
18030
+ writeText(document2.getText(reference.name), next);
18031
+ } else if (current !== next)
18032
+ parent.set(key, next);
18033
+ };
18034
+ var seedText = (document2, name, value) => {
18035
+ const client = documentAuthorId(canonicalJson(["text-promotion", name, value]));
18036
+ if (decodeStateVector(encodeStateVector(document2)).has(client))
17376
18037
  return;
17377
- const entries = await Promise.all(keys.map(async (key) => ({
17378
- key,
17379
- expected: await fingerprint(null),
17380
- next: Object.hasOwn(selected.map, key) ? { kind: "set", value: selected.map[key] } : { kind: "delete" }
17381
- })));
17382
- return { kind: "map", entries };
17383
- };
17384
- var resolutionEntry = async (state, input, environmentId) => {
17385
- const available = new Map(state.journal.map((entry) => [entry.mutation.operationId, entry.mutation]));
17386
- const branch = input.capturedOperationIds.map((id) => {
17387
- const operation = available.get(id);
17388
- if (!operation)
17389
- throw new Error("Captured branch is unavailable");
17390
- return operation;
17391
- });
17392
- const ids = [...new Set(branch.flatMap((mutation) => mutation.changes.map((change) => change.recordId)))];
17393
- if (input.expectedInputs.length !== ids.length)
17394
- throw new Error("Resolution inputs must cover every captured record");
17395
- const replaced = new Set(branch.flatMap((mutation) => mutation.resolution?.capturedOperationIds ?? []));
17396
- const current = new Map(ids.map((id) => {
17397
- const expected = input.expectedInputs.find((entry) => entry.recordId === id);
17398
- if (!expected)
17399
- throw new Error("Resolution input is unavailable");
17400
- return [id, recordVersion(state, id, expected.revision).record];
17401
- }));
17402
- const draft = new Map([...current].map(([id, record]) => [id, structuredClone(record)]));
17403
- for (const mutation of branch) {
17404
- if (replaced.has(mutation.operationId))
17405
- continue;
17406
- for (const change of mutation.changes)
17407
- draft.set(change.recordId, applyRecordChange(draft.get(change.recordId), change));
18038
+ const author = document2.clientID;
18039
+ document2.clientID = client;
18040
+ try {
18041
+ document2.getText(name).insert(0, value);
18042
+ } finally {
18043
+ document2.clientID = author;
17408
18044
  }
17409
- const changes = await Promise.all(ids.map(async (recordId) => {
17410
- const base = current.get(recordId);
17411
- const alternative = draft.get(recordId);
17412
- const selected = input.choose === "local" ? alternative : base;
17413
- return {
17414
- recordId,
17415
- expectedRevision: base.revision,
17416
- baseDeleted: base.deleted,
17417
- shared: await resolutionShared(base, alternative, input.choose),
17418
- value: { expected: await fingerprint(base.value), next: selected.value },
17419
- asset: { base: base.asset, next: selected.asset },
17420
- deleted: selected.deleted
17421
- };
17422
- }));
17423
- const mutation = {
17424
- operationId: input.operationId,
17425
- environmentId,
17426
- parents: input.capturedOperationIds,
17427
- changes,
17428
- resolution: {
17429
- conflictId: input.conflictId,
17430
- expectedConflicts: input.expectedConflicts,
17431
- capturedOperationIds: input.capturedOperationIds,
17432
- expectedInputs: ids.map((recordId) => ({ recordId, revision: current.get(recordId).revision })),
17433
- ...input.handler && { handler: input.handler }
17434
- }
17435
- };
17436
- return { inputFingerprint: await inputFingerprint(input), mutation };
17437
18045
  };
17438
18046
 
17439
- // ../pstdio-sync/src/asset-transfer.ts
17440
- class MissingRemoteAsset extends Error {
17441
- }
17442
- var uploadMutationAssets = async (local, adapter, mutation) => {
17443
- for (const change of mutation.changes) {
17444
- const asset = change.asset?.next;
17445
- if (!asset)
17446
- continue;
17447
- if (!local || !adapter.assets)
17448
- throw new Error("Asset transport is unavailable");
17449
- await adapter.assets.put(asset, () => local.read(asset));
18047
+ // ../pstdio-sync/src/document-edits.ts
18048
+ var applyShared = (document2, record, name, shared, author) => {
18049
+ const kind = shared.kind.split(".")[0];
18050
+ if (record.get("sharedKind") !== kind)
18051
+ record.set("sharedKind", kind);
18052
+ switch (shared.kind) {
18053
+ case "map.set":
18054
+ case "map.delete": {
18055
+ const reference = valueReference(record, "shared", "object", name);
18056
+ const map = document2.getMap(reference.name);
18057
+ if (shared.kind === "map.set")
18058
+ writeValue(map, shared.key, shared.value, reference.name, author);
18059
+ else
18060
+ map.delete(shared.key);
18061
+ break;
18062
+ }
18063
+ case "text.insert":
18064
+ case "text.delete": {
18065
+ const reference = valueReference(record, "shared", "text", name);
18066
+ const text = document2.getText(reference.name);
18067
+ if (shared.kind === "text.insert")
18068
+ text.insert(shared.index, shared.text);
18069
+ else
18070
+ text.delete(shared.index, shared.count);
18071
+ break;
18072
+ }
18073
+ case "list.insert":
18074
+ case "list.delete": {
18075
+ const values = record.has("shared") ? readValue(record.get("shared"), document2) : [];
18076
+ if (shared.kind === "list.insert")
18077
+ values.splice(shared.index, 0, ...shared.values);
18078
+ else
18079
+ values.splice(shared.index, shared.count);
18080
+ writeValue(record, "shared", values, name, author);
18081
+ break;
18082
+ }
17450
18083
  }
17451
18084
  };
17452
- var downloadAsset = async (local, adapter, asset, required) => {
17453
- if (!local) {
17454
- if (required)
17455
- throw new Error("Asset storage is unavailable");
17456
- return;
17457
- }
17458
- try {
17459
- await local.verifyComplete([asset]);
17460
- return;
17461
- } catch {}
17462
- if (!adapter.assets) {
17463
- if (required)
17464
- throw new Error("Asset transport is unavailable");
18085
+ var applyDocumentEdit = (document2, edit, author) => {
18086
+ const records = document2.getMap("records");
18087
+ if (edit.deleted) {
18088
+ records.delete(edit.recordId);
18089
+ document2.getMap("deleted").set(edit.recordId, true);
17465
18090
  return;
17466
18091
  }
17467
- try {
17468
- await local.receive(asset, async (offset, signal) => {
17469
- const source = await adapter.assets.get(asset, offset, signal);
17470
- if (!source)
17471
- throw new MissingRemoteAsset(`Required asset is incomplete: ${asset.sha256}`);
17472
- return source;
17473
- });
17474
- } catch (error) {
17475
- if (!required && error instanceof MissingRemoteAsset)
18092
+ let name = records.get(edit.recordId);
18093
+ if (!name) {
18094
+ if (document2.getMap("deleted").has(edit.recordId) && edit.deleted !== false)
17476
18095
  return;
17477
- throw error;
18096
+ name = JSON.stringify(["record", edit.recordId]);
18097
+ records.set(edit.recordId, name);
18098
+ document2.getMap("deleted").delete(edit.recordId);
18099
+ }
18100
+ const record = document2.getMap(name);
18101
+ if (Object.hasOwn(edit, "replace"))
18102
+ writeValue(record, "value", edit.replace, name, author);
18103
+ if (edit.asset !== undefined && canonicalJson(record.get("asset") ?? null) !== canonicalJson(edit.asset))
18104
+ record.set("asset", structuredClone(edit.asset));
18105
+ for (const shared of edit.shared ?? []) {
18106
+ const apply = () => applyShared(document2, record, name, shared, author);
18107
+ if (author)
18108
+ author(name, "shared", shared, apply);
18109
+ else
18110
+ apply();
17478
18111
  }
17479
18112
  };
17480
- var downloadSnapshotAssets = async (local, adapter, snapshot) => {
17481
- const references = new Map;
17482
- for (const receipt of Object.values(snapshot.receipts)) {
17483
- for (const change of receipt.mutation.changes) {
17484
- const asset = change.asset?.next;
17485
- if (!asset)
17486
- continue;
17487
- const key = canonicalJson(asset);
17488
- references.set(key, { asset, required: receipt.status !== "pending" || references.get(key)?.required === true });
18113
+
18114
+ // ../pstdio-sync/src/document-validation.ts
18115
+ var sequenceRange = (index, count, length) => {
18116
+ if (!Number.isSafeInteger(index) || index < 0 || index > length || !Number.isSafeInteger(count) || count < 0 || index + count > length)
18117
+ throw new Error("Shared edit is outside the current sequence");
18118
+ };
18119
+ var validateSequence = (value, shared) => {
18120
+ switch (shared.kind) {
18121
+ case "text.insert":
18122
+ case "text.delete": {
18123
+ const text = typeof value === "string" ? value : "";
18124
+ const count = shared.kind === "text.delete" ? shared.count : 0;
18125
+ sequenceRange(shared.index, count, text.length);
18126
+ return text.slice(0, shared.index) + (shared.kind === "text.insert" ? shared.text : "") + text.slice(shared.index + count);
18127
+ }
18128
+ case "list.insert":
18129
+ case "list.delete": {
18130
+ const list = Array.isArray(value) ? value : [];
18131
+ const count = shared.kind === "list.delete" ? shared.count : 0;
18132
+ sequenceRange(shared.index, count, list.length);
18133
+ list.splice(shared.index, count, ...shared.kind === "list.insert" ? shared.values : []);
18134
+ return list;
17489
18135
  }
18136
+ default:
18137
+ return value;
18138
+ }
18139
+ };
18140
+ var validateEdit = (document2, edit) => {
18141
+ if (!Object.hasOwn(edit, "replace") && edit.asset === undefined && edit.deleted === undefined && !edit.shared?.length)
18142
+ throw new Error("Empty record edit");
18143
+ if (Object.hasOwn(edit, "replace"))
18144
+ canonicalJson(edit.replace);
18145
+ const name = document2.getMap("records").get(edit.recordId);
18146
+ const record = name ? document2.getMap(name) : undefined;
18147
+ let kind = record?.get("sharedKind");
18148
+ let value = record ? readValue(record.get("shared"), document2) : null;
18149
+ for (const shared of edit.shared ?? []) {
18150
+ const nextKind = shared.kind.split(".")[0];
18151
+ if (kind && kind !== nextKind)
18152
+ throw new Error("One shared primitive per record");
18153
+ kind = nextKind;
18154
+ value = validateSequence(value, shared);
18155
+ }
18156
+ };
18157
+ var validateDocumentGroup = (document2, group) => {
18158
+ if (!group.operationId || !group.edits.length)
18159
+ throw new Error("Empty storage commit");
18160
+ const seen = new Set;
18161
+ for (const edit of group.edits) {
18162
+ if (!edit.recordId || seen.has(edit.recordId))
18163
+ throw new Error("A commit must name each record once");
18164
+ seen.add(edit.recordId);
18165
+ validateEdit(document2, edit);
17490
18166
  }
17491
- for (const record of Object.values(snapshot.records))
17492
- if (record.asset)
17493
- references.set(canonicalJson(record.asset), { asset: record.asset, required: true });
17494
- for (const { asset, required } of references.values())
17495
- await downloadAsset(local, adapter, asset, required);
17496
18167
  };
17497
18168
 
17498
- // ../pstdio-sync/src/synchronize.ts
17499
- var synchronize = async (input, adapter) => {
17500
- const compatibility = negotiate(protocolPeer, adapter.peer ?? protocolPeer);
17501
- if (compatibility.status !== "compatible")
17502
- return { ...compatibility, outcomes: [] };
17503
- await input.store.transaction(input.owner, async (state) => checkScope(state, adapter.scope));
17504
- const receive = async () => {
17505
- const observed = await input.store.transaction(input.owner, async (state) => state.accepted);
17506
- const snapshot = snapshotSchema.parse(await adapter.snapshot());
17507
- if (canonicalJson(snapshot.scope) !== canonicalJson(adapter.scope))
17508
- throw new Error("Relay snapshot scope differs from its adapter");
17509
- for (const receipt of Object.values(snapshot.receipts))
17510
- await validateMutation(receipt.mutation);
17511
- await downloadSnapshotAssets(input.assets, adapter, snapshot);
17512
- await input.store.transaction(input.owner, (state) => receiveSnapshot(state, snapshot, observed));
18169
+ // ../pstdio-sync/src/document-storage.ts
18170
+ var outcome = (operationId) => ({
18171
+ operationId,
18172
+ state: "saved-locally",
18173
+ status: "saved-locally"
18174
+ });
18175
+ var readRecord = async (document2, recordId) => {
18176
+ const name = document2.getMap("records").get(recordId);
18177
+ const record = name ? document2.getMap(name) : undefined;
18178
+ const deleted = !record && document2.getMap("deleted").has(recordId);
18179
+ const shared = record?.get("sharedKind");
18180
+ const value = record ? readValue(record.get("value"), document2) : null;
18181
+ const asset = structuredClone(record?.get("asset") ?? null);
18182
+ const sharedValue = shared ? { kind: shared, value: readValue(record?.get("shared"), document2) } : null;
18183
+ return {
18184
+ recordId,
18185
+ exists: !!record || deleted,
18186
+ deleted,
18187
+ value,
18188
+ asset,
18189
+ shared: sharedValue,
18190
+ revision: await fingerprint({ value, asset, shared: sharedValue, deleted })
17513
18191
  };
17514
- await receive();
17515
- const pending = await input.store.transaction(input.owner, async (state) => Promise.all(pendingOperations(state, input.environmentId).map(async (operation) => ({
17516
- mutation: await sealOperation(state, operation),
17517
- proof: state.journal.find((entry) => entry.mutation.operationId === operation.operationId)?.recoveryProof
17518
- }))));
17519
- const outcomes = [];
17520
- for (const { mutation, proof } of pending) {
17521
- await uploadMutationAssets(input.assets, adapter, mutation);
17522
- const foreignRecovery = mutation.environmentId !== input.environmentId && adapter.recover;
17523
- if (foreignRecovery && !proof)
17524
- throw new Error("Relay recovery proof is unavailable for a retained operation");
17525
- const receipt = receiptSchema.parse(foreignRecovery ? await foreignRecovery(mutation, proof) : await adapter.submit(mutation));
17526
- await validateMutation(receipt.mutation);
17527
- if (receipt.operationId !== mutation.operationId || receipt.fingerprint !== mutation.fingerprint)
17528
- throw new Error("Relay receipt differs from the submitted operation");
17529
- await input.store.transaction(input.owner, async (state) => {
17530
- const entry = state.journal.find((entry) => entry.mutation.operationId === mutation.operationId);
17531
- retainAcceptance(entry, receipt);
17532
- });
17533
- outcomes.push(receipt);
17534
- }
17535
- await receive();
17536
- return input.store.transaction(input.owner, async (state) => {
17537
- const conflicts = Object.values(state.accepted?.conflicts ?? {}).some((conflict) => !conflict.resolvedBy);
17538
- if (conflicts)
17539
- return { status: "conflict", outcomes };
17540
- if (pendingOperations(state, input.environmentId).length)
17541
- return { status: "pending", outcomes };
17542
- return { status: "synchronized", outcomes };
17543
- });
17544
18192
  };
17545
-
17546
- // ../pstdio-sync/src/storage.ts
17547
- var createRecordStorage = (input) => {
17548
- const readRecord = (record) => {
17549
- input.store.observer?.read(input.owner, record);
18193
+ var createDocumentStorage = (input) => {
18194
+ const { owner, store } = input;
18195
+ const observed = async (document2, id) => {
18196
+ const record = await readRecord(document2, id);
18197
+ store.observer?.read(owner, record);
17550
18198
  return record;
17551
18199
  };
17552
18200
  return {
17553
- synchronize: (adapter) => synchronize(input, adapter),
17554
- readState: () => input.store.transaction(input.owner, async (state) => {
17555
- const snapshot = structuredClone(state);
17556
- return {
17557
- ...snapshot,
17558
- pending: pendingOperations(snapshot, input.environmentId),
17559
- working: workingRecords(snapshot, input.environmentId)
17560
- };
18201
+ dataVersion: (scope) => store.transaction(owner, async ({ document: document2 }) => {
18202
+ const prefix = `${JSON.stringify([scope]).slice(0, -1)},`;
18203
+ const versions = [...document2.getMap("data-migrations").keys()].filter((key) => key.startsWith(prefix));
18204
+ return Math.max(0, ...versions.map((key) => JSON.parse(key)[1]));
17561
18205
  }),
17562
- mutation: (operationId) => input.store.transaction(input.owner, async (state) => {
17563
- const entry = state.journal.find((entry) => entry.mutation.operationId === operationId);
17564
- if (!entry)
17565
- throw new Error("Operation not found");
17566
- return sealOperation(state, entry.mutation);
18206
+ setDataVersion: (scope, version) => store.transaction(owner, async ({ document: document2 }) => {
18207
+ document2.getMap("data-migrations").set(JSON.stringify([scope, version]), true);
17567
18208
  }),
18209
+ exportUpdate: () => store.transaction(owner, async ({ document: document2 }) => encodeStateAsUpdate(document2)),
18210
+ applyUpdate: (update) => store.transaction(owner, async ({ document: document2 }) => {
18211
+ applyUpdate(document2, update);
18212
+ }),
18213
+ capture: async (action) => {
18214
+ const update = await store.transaction(owner, async ({ document: document2 }) => encodeStateAsUpdate(document2));
18215
+ const snapshot = new Doc2;
18216
+ applyUpdate(snapshot, update);
18217
+ try {
18218
+ return await captureCheckpoint(snapshot, owner, action, store.observer);
18219
+ } finally {
18220
+ snapshot.destroy();
18221
+ }
18222
+ },
17568
18223
  records: {
17569
- list: () => input.store.transaction(input.owner, async (state) => {
17570
- const view = await projectGroups(state, input.environmentId);
17571
- return [...view.records.keys()].filter((id) => !view.records.get(id).deleted).sort().map((id) => readRecord(view.read(id)));
17572
- }),
17573
- outcome: (operationId) => input.store.transaction(input.owner, async (state) => (await projectGroups(state, input.environmentId)).outcomes.get(operationId)),
17574
- inspect: (conflictId) => input.store.transaction(input.owner, (state) => inspectConflict(state, input.environmentId, conflictId)),
17575
- resolve: (proposal) => input.store.transaction(input.owner, async (state) => {
17576
- const previous = state.journal.find((entry) => entry.mutation.operationId === proposal.operationId);
17577
- if (previous && previous.inputFingerprint !== await inputFingerprint(proposal))
17578
- throw new Error("Operation identity reused with changed payload");
17579
- if (!previous) {
17580
- const entry = await resolutionEntry(state, proposal, input.environmentId);
17581
- localOperationSchema.parse(entry.mutation);
17582
- state.journal.push(entry);
17583
- }
17584
- return (await projectGroups(state, input.environmentId)).outcomes.get(proposal.operationId);
17585
- }),
17586
- read: (recordId, options) => input.store.transaction(input.owner, async (state) => {
17587
- if (!options)
17588
- return readRecord((await projectGroups(state, input.environmentId)).read(recordId));
17589
- return readBranch(state, input.environmentId, recordId, options.operationId);
17590
- }),
17591
- conflicts: () => input.store.transaction(input.owner, async (state) => (await projectGroups(state, input.environmentId)).conflicts.map(({ conflictId, revision, reason, recordIds, alternativeOperationIds }) => ({
17592
- conflictId,
17593
- revision,
17594
- reason,
17595
- recordIds,
17596
- alternativeOperationIds
17597
- }))),
17598
- commit: async (proposal) => {
17599
- const group = input.store.observer?.group(input.owner, proposal) ?? proposal;
18224
+ read: (id, _branch) => store.transaction(owner, async ({ document: document2 }) => observed(document2, id)),
18225
+ list: (prefix = "") => store.transaction(owner, async ({ document: document2 }) => Promise.all([...document2.getMap("records").keys()].filter((id) => id.startsWith(prefix)).sort().map((id) => observed(document2, id)))),
18226
+ outcome: (id) => store.transaction(owner, async (state) => await state.operation(id) ? outcome(id) : undefined),
18227
+ conflicts: async () => [],
18228
+ inspect: (_id) => Promise.reject(new Error("Records merge automatically; there are no conflicts to inspect")),
18229
+ resolve: (_proposal) => Promise.reject(new Error("Records merge automatically; there are no conflicts to resolve")),
18230
+ commit: async (group) => {
18231
+ if (!group.edits.length)
18232
+ throw new Error("Empty storage commit");
17600
18233
  const assets = group.edits.flatMap((edit) => edit.asset ? [edit.asset] : []);
17601
18234
  if (assets.length) {
17602
18235
  if (!input.assets)
17603
18236
  throw new Error("Asset verification is unavailable");
17604
18237
  await input.assets.verifyComplete(assets);
17605
18238
  }
17606
- return input.store.transaction(input.owner, async (state) => {
17607
- const previous = state.journal.find((entry) => entry.mutation.operationId === group.operationId);
17608
- if (previous && previous.inputFingerprint !== await inputFingerprint(group))
18239
+ const identity = await fingerprint(group.edits.map(({ expectedRevision: _revision, ...edit }) => edit));
18240
+ const saved = await store.transaction(owner, async (state) => {
18241
+ const doc = state.document;
18242
+ const previous = await state.operation(group.operationId);
18243
+ if (previous !== undefined && previous !== identity)
17609
18244
  throw new Error("Operation identity reused with changed payload");
17610
- if (!previous) {
17611
- const entry = await entryFor(state, group, input.environmentId);
17612
- localOperationSchema.parse(entry.mutation);
17613
- state.journal.push(entry);
18245
+ if (previous === undefined) {
18246
+ validateDocumentGroup(doc, group);
18247
+ const author = migrationAuthor(doc, state.migrationSeed, state.migrationHistory);
18248
+ doc.transact(() => {
18249
+ for (const edit of group.edits)
18250
+ applyDocumentEdit(doc, edit, author);
18251
+ });
17614
18252
  }
17615
- const view = await projectGroups(state, input.environmentId);
17616
- const outcome = view.outcomes.get(group.operationId);
17617
- input.store.observer?.committed(input.owner, group.edits.map((edit) => view.read(edit.recordId)), outcome);
17618
- return outcome;
18253
+ state.remember(group.operationId, identity);
18254
+ return Promise.all(group.edits.map((edit) => readRecord(doc, edit.recordId)));
17619
18255
  });
18256
+ const result = outcome(group.operationId);
18257
+ store.observer?.committed(owner, saved, result);
18258
+ return result;
17620
18259
  }
17621
18260
  }
17622
18261
  };
17623
18262
  };
18263
+ // ../pstdio-sync/src/encryption/sealing.ts
18264
+ var headerLength = 1 + 4 + 12;
18265
+
18266
+ // ../pstdio-sync/src/encryption/space.ts
18267
+ var encoder = new TextEncoder;
18268
+ // ../pstdio-sync/src/namespaces.ts
18269
+ var storageRecordId = (namespace, recordId) => JSON.stringify([...namespace, recordId]);
18270
+ var scopeRecordStorage = (records, namespace) => {
18271
+ return { id: (key) => storageRecordId(namespace, key), ...records };
18272
+ };
18273
+ var legacyNamespaceStorage = (records, namespace) => {
18274
+ const prefix = `${JSON.stringify(namespace).slice(0, -1)},`;
18275
+ const storedId = (id) => storageRecordId(namespace, id);
18276
+ return {
18277
+ read: (id) => records.read(storedId(id)),
18278
+ list: async () => (await records.list(prefix)).map((record) => ({
18279
+ ...record,
18280
+ recordId: JSON.parse(record.recordId).at(-1)
18281
+ })),
18282
+ commit: (group) => records.commit({
18283
+ ...group,
18284
+ edits: group.edits.map((edit) => ({ ...edit, recordId: storedId(edit.recordId) }))
18285
+ })
18286
+ };
18287
+ };
17624
18288
 
17625
18289
  // ../pstdio-sync/src/legacy.ts
17626
18290
  var legacyJson = (value) => JSON.parse(JSON.stringify(value));
17627
18291
  var createLegacyRecordStorage = (input) => {
17628
- const within = (namespace, action) => input.store.transaction(input.owner, (state) => action(legacyNamespaceStorage(createRecordStorage({
18292
+ const within = (namespace, action) => input.store.transaction(input.owner, (state) => action(legacyNamespaceStorage(createDocumentStorage({
17629
18293
  ...input,
17630
18294
  store: { transaction: async (_owner, run) => run(state), observer: input.store.observer }
17631
18295
  }).records, namespace)));
17632
18296
  const namespaceApi = (namespace) => {
18297
+ const current = legacyNamespaceStorage(createDocumentStorage(input).records, namespace);
17633
18298
  const read = (records, id) => records.read(id);
17634
18299
  const replace = async (records, id, value, deleted = false) => {
17635
18300
  const current = await read(records, id);
@@ -17646,11 +18311,10 @@ var createLegacyRecordStorage = (input) => {
17646
18311
  });
17647
18312
  };
17648
18313
  return {
17649
- get: (id) => within(namespace, async (records) => {
17650
- const record = await read(records, id);
18314
+ get: (id) => current.read(id).then((record) => {
17651
18315
  return record.exists && !record.deleted ? record.value : undefined;
17652
18316
  }),
17653
- list: () => within(namespace, (records) => records.list()),
18317
+ list: () => current.list(),
17654
18318
  set: (id, value) => within(namespace, (records) => replace(records, id, value)),
17655
18319
  createIfAbsent: (id, value) => within(namespace, async (records) => {
17656
18320
  const current = await read(records, id);
@@ -17736,31 +18400,49 @@ var createLegacyRecordStorage = (input) => {
17736
18400
  }
17737
18401
  };
17738
18402
  };
17739
- // src/testing/memory-record-owner.ts
17740
- var createMemoryRecordOwner = (assets, seed = {}) => {
17741
- const owner = { workbenchId: crypto.randomUUID(), extensionId: "test-extension" };
17742
- const environmentId = crypto.randomUUID();
17743
- let state = { owner, accepted: null, journal: [] };
18403
+ // ../pstdio-sync/src/memory-document-store.ts
18404
+ var createMemoryDocumentStore = () => {
18405
+ const document2 = new Doc2;
18406
+ const state = memoryDocumentState(document2);
17744
18407
  let previous = Promise.resolve();
17745
- const baseStore = {
17746
- transaction: async (_owner, action) => {
17747
- const pending = previous;
17748
- let release = () => {};
17749
- previous = new Promise((resolve) => {
17750
- release = resolve;
17751
- });
18408
+ let previousMigration = Promise.resolve();
18409
+ const transaction = async (_owner, action) => {
18410
+ const pending = previous;
18411
+ const { promise, resolve } = Promise.withResolvers();
18412
+ previous = promise;
18413
+ await pending;
18414
+ try {
18415
+ return await action(state);
18416
+ } finally {
18417
+ resolve();
18418
+ }
18419
+ };
18420
+ return {
18421
+ transaction,
18422
+ async duringMigration(key, run) {
18423
+ const pending = previousMigration;
18424
+ const { promise, resolve } = Promise.withResolvers();
18425
+ previousMigration = promise;
17752
18426
  await pending;
18427
+ const previousSeed = state.migrationSeed;
18428
+ const previousHistory = state.migrationHistory;
18429
+ state.migrationSeed = key;
18430
+ state.migrationHistory = documentHistory(document2);
17753
18431
  try {
17754
- const draft = structuredClone(state);
17755
- const result = await action(draft);
17756
- state = draft;
17757
- return result;
18432
+ return await run();
17758
18433
  } finally {
17759
- release();
18434
+ state.migrationSeed = previousSeed;
18435
+ state.migrationHistory = previousHistory;
18436
+ resolve();
17760
18437
  }
17761
18438
  }
17762
18439
  };
17763
- const seedStorage = createLegacyRecordStorage({ store: baseStore, owner, environmentId }).scope("project", owner.workbenchId);
18440
+ };
18441
+ // src/testing/memory-record-owner.ts
18442
+ var createMemoryRecordOwner = (assets, seed = {}) => {
18443
+ const owner = { workbenchId: crypto.randomUUID(), extensionId: "test-extension" };
18444
+ const baseStore = createMemoryDocumentStore();
18445
+ const seedStorage = createLegacyRecordStorage({ store: baseStore, owner }).scope("project", owner.workbenchId);
17764
18446
  const initialized = Promise.all([
17765
18447
  ...Object.entries(seed.kv ?? {}).map(([key, value]) => seedStorage.kv.set(key, value)),
17766
18448
  ...Object.entries(seed.collections ?? {}).flatMap(([name, items]) => Object.entries(items).map(([id, value]) => seedStorage.collection(name).set(id, value)))
@@ -17771,10 +18453,9 @@ var createMemoryRecordOwner = (assets, seed = {}) => {
17771
18453
  return baseStore.transaction(target, action);
17772
18454
  }
17773
18455
  };
17774
- const storage = createRecordStorage({
18456
+ const storage = createDocumentStorage({
17775
18457
  store,
17776
18458
  owner,
17777
- environmentId,
17778
18459
  assets: {
17779
18460
  verifyComplete: assets.verifyComplete,
17780
18461
  read: assets.read,
@@ -17783,9 +18464,15 @@ var createMemoryRecordOwner = (assets, seed = {}) => {
17783
18464
  }
17784
18465
  }
17785
18466
  });
17786
- const legacy = createLegacyRecordStorage({ store, owner, environmentId });
18467
+ const legacy = createLegacyRecordStorage({ store, owner });
17787
18468
  return {
17788
18469
  workbenchId: owner.workbenchId,
18470
+ dataVersion: storage.dataVersion,
18471
+ setDataVersion: storage.setDataVersion,
18472
+ duringMigration: async (key, run) => {
18473
+ await initialized;
18474
+ return baseStore.duringMigration(key, run);
18475
+ },
17789
18476
  scope: (type, id) => ({
17790
18477
  records: scopeRecordStorage(storage.records, [type, id, "kv"]),
17791
18478
  legacy: legacy.scope(type, id)
@@ -17803,12 +18490,9 @@ var createMemoryStorage = (options = {}) => {
17803
18490
  const existing = migrations.get(scope);
17804
18491
  if (existing)
17805
18492
  return existing;
17806
- let version = 0;
17807
18493
  const migrate = createDataMigrationRunner({
17808
- readVersion: async () => version,
17809
- writeVersion: async (next) => {
17810
- version = next;
17811
- }
18494
+ readVersion: () => owner.dataVersion(scope),
18495
+ writeVersion: (next) => owner.setDataVersion(scope, next)
17812
18496
  });
17813
18497
  migrations.set(scope, migrate);
17814
18498
  return migrate;
@@ -17868,7 +18552,7 @@ var createMemoryStorage = (options = {}) => {
17868
18552
  const { records, legacy } = owner.scope(scopeType, scopeId);
17869
18553
  const blobKey = JSON.stringify([scopeType, scopeId]);
17870
18554
  const api = {
17871
- migrate: migrateFor(blobKey),
18555
+ migrate: (version, run) => migrateFor(blobKey)(version, (previous) => owner.duringMigration(JSON.stringify(["test-extension", scopeType, scopeId, version]), () => run(previous))),
17872
18556
  readLegacy: async (source) => structuredClone(options.legacyData?.[source]),
17873
18557
  records,
17874
18558
  assets,