@graffiti-garden/wrapper-synchronize 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graffiti-garden/wrapper-synchronize",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Internal synchronization for the Graffiti API",
5
5
  "types": "./dist/index.d.ts",
6
6
  "module": "./dist/esm/index.js",
@@ -53,8 +53,8 @@
53
53
  "vitest": "^3.0.5"
54
54
  },
55
55
  "dependencies": {
56
- "@graffiti-garden/api": "^0.5.0",
57
- "@graffiti-garden/implementation-local": "^0.5.0",
56
+ "@graffiti-garden/api": "^0.6.1",
57
+ "@graffiti-garden/implementation-local": "^0.6.1",
58
58
  "@repeaterjs/repeater": "^3.0.6",
59
59
  "ajv": "^8.17.1",
60
60
  "esbuild-plugin-polyfill-node": "^0.3.0",
package/src/index.spec.ts CHANGED
@@ -37,16 +37,17 @@ describe.concurrent("synchronizeDiscover", () => {
37
37
 
38
38
  const graffiti2 = useGraffiti();
39
39
  const next = graffiti2.synchronizeDiscover(channels, {}).next();
40
+ await new Promise((resolve) => setTimeout(resolve, 100));
40
41
  const gotten = await graffiti2.get(putted, {}, session);
41
42
 
42
- const result = (await next).value;
43
- if (!result || result.error) {
43
+ const result = await next;
44
+ if (result.done || result.value.error) {
44
45
  throw new Error("Error in synchronize");
45
46
  }
46
- expect(result.value.value).toEqual(object.value);
47
- expect(result.value.channels).toEqual(channels);
48
- expect(result.value.tombstone).toBe(false);
49
- expect(result.value.lastModified).toEqual(gotten.lastModified);
47
+ assert(!result.value.tombstone);
48
+ expect(result.value.object.value).toEqual(object.value);
49
+ expect(result.value.object.channels).toEqual(channels);
50
+ expect(result.value.object.lastModified).toEqual(gotten.lastModified);
50
51
  });
51
52
 
52
53
  it("put", async () => {
@@ -54,6 +55,11 @@ describe.concurrent("synchronizeDiscover", () => {
54
55
  const afterChannel = randomString();
55
56
  const sharedChannel = randomString();
56
57
 
58
+ // Start listening for changes...
59
+ const beforeIterator = graffiti.synchronizeDiscover([beforeChannel], {});
60
+ // Skip the first result
61
+ beforeIterator.next();
62
+
57
63
  const oldValue = { hello: "world" };
58
64
  const oldChannels = [beforeChannel, sharedChannel];
59
65
  const putted = await graffiti.put<{}>(
@@ -64,51 +70,59 @@ describe.concurrent("synchronizeDiscover", () => {
64
70
  session,
65
71
  );
66
72
 
67
- // Start listening for changes...
68
- const before = graffiti.synchronizeDiscover([beforeChannel], {}).next();
73
+ const beforeButAfter = graffiti
74
+ .synchronizeDiscover([beforeChannel], {})
75
+ .next();
76
+ const before = beforeIterator.next();
69
77
  const after = graffiti.synchronizeDiscover([afterChannel], {}).next();
70
78
  const shared = graffiti.synchronizeDiscover([sharedChannel], {}).next();
71
79
 
72
80
  // Replace the object
73
81
  const newValue = { goodbye: "world" };
74
82
  const newChannels = [afterChannel, sharedChannel];
75
- await graffiti.put<{}>(
83
+ const putted2 = await graffiti.put<{}>(
76
84
  {
77
- uri: putted.uri,
85
+ url: putted.url,
78
86
  value: newValue,
79
87
  channels: newChannels,
80
88
  },
81
89
  session,
82
90
  );
83
91
 
84
- const beforeResult = (await before).value;
85
- const afterResult = (await after).value;
86
- const sharedResult = (await shared).value;
87
- if (
88
- !beforeResult ||
89
- beforeResult.error ||
90
- !afterResult ||
91
- afterResult.error ||
92
- !sharedResult ||
93
- sharedResult.error
94
- ) {
95
- throw new Error("Error in synchronize");
96
- }
92
+ // If you just start synchronizing after the first put,
93
+ // it won't show the deletion because it never saw the object.
94
+ await expect(
95
+ // @ts-ignore
96
+ Promise.race([
97
+ beforeButAfter,
98
+ new Promise((resolve, reject) => setTimeout(reject, 100, "Timeout")),
99
+ ]),
100
+ ).rejects.toThrow("Timeout");
97
101
 
98
- expect(beforeResult.value.value).toEqual(oldValue);
99
- expect(beforeResult.value.channels).toEqual([beforeChannel]);
100
- expect(beforeResult.value.tombstone).toBe(true);
101
- expect(afterResult.value.value).toEqual(newValue);
102
- expect(afterResult.value.channels).toEqual([afterChannel]);
103
- expect(afterResult.value.tombstone).toBe(false);
104
- expect(sharedResult.value.value).toEqual(newValue);
105
- expect(sharedResult.value.channels).toEqual([sharedChannel]);
106
- expect(sharedResult.value.tombstone).toBe(false);
107
- expect(beforeResult.value.lastModified).toEqual(
108
- afterResult.value.lastModified,
102
+ const beforeResult = await before;
103
+ const afterResult = await after;
104
+ const sharedResult = await shared;
105
+ assert(!beforeResult.done && !beforeResult.value.error, "Error in before");
106
+ assert(!afterResult.done && !afterResult.value.error, "Error in after");
107
+ assert(!sharedResult.done && !sharedResult.value.error, "Error in shared");
108
+
109
+ assert(beforeResult.value.tombstone, "Before is not tombstone");
110
+ assert(!afterResult.value.tombstone, "After is tombstone");
111
+ assert(!sharedResult.value.tombstone, "Shared is tombstone");
112
+
113
+ expect(beforeResult.value.object.url).toEqual(putted.url);
114
+ expect(beforeResult.value.object.lastModified).toEqual(
115
+ putted2.lastModified,
116
+ );
117
+ expect(afterResult.value.object.value).toEqual(newValue);
118
+ expect(afterResult.value.object.channels).toEqual([afterChannel]);
119
+ expect(sharedResult.value.object.value).toEqual(newValue);
120
+ expect(sharedResult.value.object.channels).toEqual([sharedChannel]);
121
+ expect(beforeResult.value.object.lastModified).toEqual(
122
+ afterResult.value.object.lastModified,
109
123
  );
110
- expect(sharedResult.value.lastModified).toEqual(
111
- afterResult.value.lastModified,
124
+ expect(sharedResult.value.object.lastModified).toEqual(
125
+ afterResult.value.object.lastModified,
112
126
  );
113
127
  });
114
128
 
@@ -117,6 +131,11 @@ describe.concurrent("synchronizeDiscover", () => {
117
131
  const afterChannel = randomString();
118
132
  const sharedChannel = randomString();
119
133
 
134
+ // Start listening for changes...
135
+ const beforeIterator = graffiti.synchronizeDiscover([beforeChannel], {});
136
+ // Skip the first result
137
+ beforeIterator.next();
138
+
120
139
  const oldValue = { hello: "world" };
121
140
  const oldChannels = [beforeChannel, sharedChannel];
122
141
  const putted = await graffiti.put<{}>(
@@ -127,12 +146,14 @@ describe.concurrent("synchronizeDiscover", () => {
127
146
  session,
128
147
  );
129
148
 
130
- // Start listening for changes...
131
- const before = graffiti.synchronizeDiscover([beforeChannel], {}).next();
149
+ const beforeButAfter = graffiti
150
+ .synchronizeDiscover([beforeChannel], {})
151
+ .next();
152
+ const before = beforeIterator.next();
132
153
  const after = graffiti.synchronizeDiscover([afterChannel], {}).next();
133
154
  const shared = graffiti.synchronizeDiscover([sharedChannel], {}).next();
134
155
 
135
- await graffiti.patch(
156
+ const patched = await graffiti.patch(
136
157
  {
137
158
  value: [
138
159
  {
@@ -157,42 +178,52 @@ describe.concurrent("synchronizeDiscover", () => {
157
178
  session,
158
179
  );
159
180
 
160
- const beforeResult = (await before).value;
161
- const afterResult = (await after).value;
162
- const sharedResult = (await shared).value;
163
- if (
164
- !beforeResult ||
165
- beforeResult.error ||
166
- !afterResult ||
167
- afterResult.error ||
168
- !sharedResult ||
169
- sharedResult.error
170
- ) {
171
- throw new Error("Error in synchronize");
172
- }
181
+ // If you just start synchronizing after the first put,
182
+ // it won't show the deletion because it never saw the object.
183
+ await expect(
184
+ // @ts-ignore
185
+ Promise.race([
186
+ beforeButAfter,
187
+ new Promise((resolve, reject) => setTimeout(reject, 100, "Timeout")),
188
+ ]),
189
+ ).rejects.toThrow("Timeout");
190
+
191
+ const beforeResult = await before;
192
+ const afterResult = await after;
193
+ const sharedResult = await shared;
194
+ assert(!beforeResult.done && !beforeResult.value.error, "Error in before");
195
+ assert(!afterResult.done && !afterResult.value.error, "Error in after");
196
+ assert(!sharedResult.done && !sharedResult.value.error, "Error in shared");
197
+
198
+ assert(beforeResult.value.tombstone, "Before is not tombstone");
199
+ assert(!afterResult.value.tombstone, "After is tombstone");
200
+ assert(!sharedResult.value.tombstone, "Shared is tombstone");
173
201
 
174
202
  const newValue = { ...oldValue, something: "new value" };
175
- const newChannels = [sharedChannel, afterChannel];
176
- expect(beforeResult.value.value).toEqual(oldValue);
177
- expect(beforeResult.value.channels).toEqual([beforeChannel]);
178
- expect(beforeResult.value.tombstone).toBe(true);
179
- expect(afterResult.value.value).toEqual(newValue);
180
- expect(afterResult.value.channels).toEqual([afterChannel]);
181
- expect(afterResult.value.tombstone).toBe(false);
182
- expect(sharedResult.value.value).toEqual(newValue);
183
- expect(sharedResult.value.channels).toEqual([sharedChannel]);
184
- expect(sharedResult.value.tombstone).toBe(false);
185
- expect(beforeResult.value.lastModified).toEqual(
186
- afterResult.value.lastModified,
203
+ expect(beforeResult.value.object.url).toEqual(putted.url);
204
+ expect(beforeResult.value.object.lastModified).toEqual(
205
+ patched.lastModified,
206
+ );
207
+ expect(afterResult.value.object.value).toEqual(newValue);
208
+ expect(afterResult.value.object.channels).toEqual([afterChannel]);
209
+ expect(sharedResult.value.object.value).toEqual(newValue);
210
+ expect(sharedResult.value.object.channels).toEqual([sharedChannel]);
211
+ expect(beforeResult.value.object.lastModified).toEqual(
212
+ afterResult.value.object.lastModified,
187
213
  );
188
- expect(sharedResult.value.lastModified).toEqual(
189
- afterResult.value.lastModified,
214
+ expect(sharedResult.value.object.lastModified).toEqual(
215
+ afterResult.value.object.lastModified,
190
216
  );
191
217
  });
192
218
 
193
219
  it("delete", async () => {
194
220
  const channels = [randomString(), randomString(), randomString()];
195
221
 
222
+ // Start listening for changes...
223
+ const beforeIterator = graffiti.synchronizeDiscover(channels, {});
224
+ // Skip the first result
225
+ beforeIterator.next();
226
+
196
227
  const oldValue = { hello: "world" };
197
228
  const oldChannels = [randomString(), ...channels.slice(1)];
198
229
  const putted = await graffiti.put<{}>(
@@ -203,19 +234,26 @@ describe.concurrent("synchronizeDiscover", () => {
203
234
  session,
204
235
  );
205
236
 
206
- const next = graffiti.synchronizeDiscover(channels, {}).next();
237
+ const beforeButAfter = graffiti.synchronizeDiscover(channels, {}).next();
238
+ const next = beforeIterator.next();
207
239
 
208
- graffiti.delete(putted, session);
240
+ const deleted = await graffiti.delete(putted, session);
209
241
 
210
- const result = (await next).value;
211
- if (!result || result.error) {
212
- throw new Error("Error in synchronize");
213
- }
214
- expect(result.value.tombstone).toBe(true);
215
- expect(result.value.value).toEqual(oldValue);
216
- expect(result.value.channels).toEqual(
217
- channels.filter((c) => oldChannels.includes(c)),
218
- );
242
+ // If you just start synchronizing after the first put,
243
+ // it won't show the deletion because it never saw the object.
244
+ await expect(
245
+ // @ts-ignore
246
+ Promise.race([
247
+ beforeButAfter,
248
+ new Promise((resolve, reject) => setTimeout(reject, 100, "Timeout")),
249
+ ]),
250
+ ).rejects.toThrow("Timeout");
251
+
252
+ const result = await next;
253
+ assert(!result.done && !result.value.error, "Error in before");
254
+ assert(result.value.tombstone, "Before is not tombstone");
255
+ expect(result.value.object.url).toEqual(putted.url);
256
+ expect(result.value.object.lastModified).toEqual(deleted.lastModified);
219
257
  });
220
258
 
221
259
  it("synchronize happens before putters", async () => {
@@ -267,7 +305,10 @@ describe.concurrent("synchronizeDiscover", () => {
267
305
  }
268
306
 
269
307
  // Try returning...
270
- iterator.return();
308
+ iterator.return({
309
+ continue: () => iterator,
310
+ cursor: "",
311
+ });
271
312
  });
272
313
 
273
314
  it("not allowed", async () => {
@@ -299,24 +340,28 @@ describe.concurrent("synchronizeDiscover", () => {
299
340
  ]),
300
341
  ).rejects.toThrow("Timeout");
301
342
 
302
- const creatorResult = (await creatorNext).value;
303
- const allowedResult = (await allowedNext).value;
343
+ const creatorResult = await creatorNext;
344
+ const allowedResult = await allowedNext;
304
345
 
305
- if (
306
- !creatorResult ||
307
- creatorResult.error ||
308
- !allowedResult ||
309
- allowedResult.error
310
- ) {
311
- throw new Error("Error in synchronize");
312
- }
346
+ assert(
347
+ !creatorResult.done &&
348
+ !creatorResult.value.error &&
349
+ !creatorResult.value.tombstone,
350
+ "Error in creator",
351
+ );
352
+ assert(
353
+ !allowedResult.done &&
354
+ !allowedResult.value.error &&
355
+ !allowedResult.value.tombstone,
356
+ "Error in allowed",
357
+ );
313
358
 
314
- expect(creatorResult.value.value).toEqual(value);
315
- expect(creatorResult.value.allowed).toEqual(allowed);
316
- expect(creatorResult.value.channels).toEqual(allChannels);
317
- expect(allowedResult.value.value).toEqual(value);
318
- expect(allowedResult.value.allowed).toEqual([session2.actor]);
319
- expect(allowedResult.value.channels).toEqual(channels);
359
+ expect(creatorResult.value.object.value).toEqual(value);
360
+ expect(creatorResult.value.object.allowed).toEqual(allowed);
361
+ expect(creatorResult.value.object.channels).toEqual(allChannels);
362
+ expect(allowedResult.value.object.value).toEqual(value);
363
+ expect(allowedResult.value.object.allowed).toEqual([session2.actor]);
364
+ expect(allowedResult.value.object.channels).toEqual(channels);
320
365
  });
321
366
  });
322
367
 
@@ -343,29 +388,28 @@ describe.concurrent("synchronizeGet", () => {
343
388
  const newValue = { goodbye: "world" };
344
389
  const putted2 = await graffiti.put<{}>(
345
390
  {
346
- uri: putted.uri,
391
+ url: putted.url,
347
392
  channels: object.channels,
348
393
  value: newValue,
349
394
  },
350
395
  session,
351
396
  );
352
397
 
353
- const result = (await next).value;
354
- assert(result && !result.error);
398
+ const result = await next;
399
+ assert(!result.done && !result.value.error && !result.value.tombstone);
355
400
 
356
- expect(result.value.value).toEqual(newValue);
357
- expect(result.value.actor).toEqual(session.actor);
358
- expect(result.value.channels).toEqual([]);
359
- expect(result.value.tombstone).toBe(false);
360
- expect(result.value.lastModified).toEqual(putted2.lastModified);
361
- expect(result.value.allowed).toBeUndefined();
401
+ expect(result.value.object.value).toEqual(newValue);
402
+ expect(result.value.object.actor).toEqual(session.actor);
403
+ expect(result.value.object.channels).toEqual([]);
404
+ expect(result.value.object.lastModified).toEqual(putted2.lastModified);
405
+ expect(result.value.object.allowed).toBeUndefined();
362
406
 
363
407
  // Delete the object
364
408
  const deleted = await graffiti.delete(putted2, session);
365
- const result2 = (await iterator.next()).value;
366
- assert(result2 && !result2.error);
409
+ const result2 = await iterator.next();
410
+ assert(!result2.done && !result2.value.error);
367
411
  expect(result2.value.tombstone).toBe(true);
368
- expect(result2.value.lastModified).toEqual(deleted.lastModified);
412
+ expect(result2.value.object.lastModified).toEqual(deleted.lastModified);
369
413
 
370
414
  // Put something else
371
415
  await graffiti.put<{}>(randomPutObject(), session);
@@ -387,6 +431,11 @@ describe.concurrent("synchronizeGet", () => {
387
431
  const iterator1 = graffiti.synchronizeGet(putted, {}, session1);
388
432
  const iterator2 = graffiti.synchronizeGet(putted, {}, session2);
389
433
 
434
+ // Do a get to trigger the synchronize
435
+ graffiti.get<{}>(putted, {}, session1);
436
+ iterator1.next();
437
+ iterator2.next();
438
+
390
439
  const next1 = iterator1.next();
391
440
  const next2 = iterator2.next();
392
441
 
@@ -400,21 +449,20 @@ describe.concurrent("synchronizeGet", () => {
400
449
  },
401
450
  session1,
402
451
  );
403
- const result1 = (await next1).value;
404
- const result2 = (await next2).value;
405
- assert(result1 && !result1.error);
406
- assert(result2 && !result2.error);
407
-
408
- expect(result1.value.value).toEqual(newValue);
409
- expect(result2.value.value).toEqual(object.value);
410
- expect(result1.value.actor).toEqual(session1.actor);
411
- expect(result2.value.actor).toEqual(session1.actor);
412
- expect(result1.value.channels).toEqual(object.channels);
413
- expect(result2.value.channels).toEqual([]);
414
- expect(result1.value.tombstone).toBe(false);
415
- expect(result2.value.tombstone).toBe(true);
416
- expect(result1.value.lastModified).toEqual(putted2.lastModified);
417
- expect(result2.value.lastModified).toEqual(putted2.lastModified);
452
+
453
+ const result1 = await next1;
454
+ const result2 = await next2;
455
+ assert(!result1.done && !result1.value.error);
456
+ assert(!result2.done && !result2.value.error);
457
+ assert(!result1.value.tombstone);
458
+ assert(result2.value.tombstone);
459
+
460
+ expect(result1.value.object.value).toEqual(newValue);
461
+ expect(result1.value.object.actor).toEqual(session1.actor);
462
+ expect(result1.value.object.channels).toEqual(object.channels);
463
+ expect(result1.value.object.lastModified).toEqual(putted2.lastModified);
464
+ expect(result2.value.object.url).toEqual(putted.url);
465
+ expect(result2.value.object.lastModified).toEqual(putted2.lastModified);
418
466
  });
419
467
  });
420
468
 
@@ -435,7 +483,7 @@ describe("synchronizeAll", () => {
435
483
 
436
484
  expect(object1.channels).not.toEqual(object2.channels);
437
485
 
438
- const iterator = graffiti.synchronizeAll();
486
+ const iterator = graffiti.synchronizeAll({});
439
487
 
440
488
  const next1 = iterator.next();
441
489
  const next2 = iterator.next();
@@ -443,14 +491,14 @@ describe("synchronizeAll", () => {
443
491
  await graffiti.put<{}>(object1, session1);
444
492
  await graffiti.put<{}>(object2, session2);
445
493
 
446
- const result1 = (await next1).value;
447
- const result2 = (await next2).value;
448
- assert(result1 && !result1.error);
449
- assert(result2 && !result2.error);
494
+ const result1 = await next1;
495
+ const result2 = await next2;
496
+ assert(!result1.done && !result1.value.error && !result1.value.tombstone);
497
+ assert(!result2.done && !result2.value.error && !result2.value.tombstone);
450
498
 
451
- expect(result1.value.value).toEqual(object1.value);
452
- expect(result1.value.channels).toEqual([]);
453
- expect(result2.value.value).toEqual(object2.value);
499
+ expect(result1.value.object.value).toEqual(object1.value);
500
+ expect(result1.value.object.channels).toEqual([]);
501
+ expect(result2.value.object.value).toEqual(object2.value);
454
502
  });
455
503
 
456
504
  it("omniscient", async () => {
@@ -461,15 +509,15 @@ describe("synchronizeAll", () => {
461
509
  const object1 = randomPutObject();
462
510
  object1.allowed = [randomString()];
463
511
 
464
- const iterator = graffiti.synchronizeAll();
512
+ const iterator = graffiti.synchronizeAll({});
465
513
  const next = iterator.next();
466
514
 
467
515
  await graffiti.put<{}>(object1, session1);
468
516
 
469
- const result = (await next).value;
470
- assert(result && !result.error);
471
- expect(result.value.value).toEqual(object1.value);
472
- expect(result.value.channels).toEqual(object1.channels);
473
- expect(result.value.allowed).toEqual(object1.allowed);
517
+ const result = await next;
518
+ assert(!result.done && !result.value.error && !result.value.tombstone);
519
+ expect(result.value.object.value).toEqual(object1.value);
520
+ expect(result.value.object.channels).toEqual(object1.channels);
521
+ expect(result.value.object.allowed).toEqual(object1.allowed);
474
522
  });
475
523
  });