@verdant-web/common 2.7.3 → 2.8.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/src/patch.ts CHANGED
@@ -3,10 +3,10 @@
3
3
  */
4
4
 
5
5
  import { AuthorizationKey } from './authz.js';
6
+ import { diffToPatches } from './diffing.js';
6
7
  import { FileRef } from './files.js';
7
8
  import { createRef, createSubOid, ObjectIdentifier } from './oids.js';
8
9
  import {
9
- diffToPatches,
10
10
  initialToPatches,
11
11
  ObjectRef,
12
12
  Operation,
@@ -17,8 +17,8 @@ import { isObject } from './utils.js';
17
17
 
18
18
  export class PatchCreator {
19
19
  constructor(
20
- private getNow: () => string,
21
- private createSubId?: () => string,
20
+ readonly getNow: () => string,
21
+ readonly createSubId?: () => string,
22
22
  ) {}
23
23
 
24
24
  isPrimitive = (value: any) => {
@@ -52,6 +52,7 @@ export class PatchCreator {
52
52
  oid: ObjectIdentifier,
53
53
  key: PropertyName,
54
54
  value: any,
55
+ authz?: string,
55
56
  ): Operation[] => {
56
57
  // incoming value must be normalized. if it's not a primitive, it and all sub-objects
57
58
  // must be created
@@ -65,6 +66,7 @@ export class PatchCreator {
65
66
  name: key,
66
67
  value,
67
68
  },
69
+ authz,
68
70
  },
69
71
  ];
70
72
  } else {
@@ -72,7 +74,16 @@ export class PatchCreator {
72
74
  return [
73
75
  // since we're setting a complex nested object, we can initialize it wholesale.
74
76
  // no diffing to do.
75
- ...initialToPatches(value, itemOid, this.getNow),
77
+ ...initialToPatches(
78
+ value,
79
+ itemOid,
80
+ this.getNow,
81
+ this.createSubId,
82
+ undefined,
83
+ {
84
+ authz,
85
+ },
86
+ ),
76
87
  // then set the reference to the object
77
88
  {
78
89
  oid,
@@ -82,12 +93,17 @@ export class PatchCreator {
82
93
  value: createRef(itemOid),
83
94
  name: key,
84
95
  },
96
+ authz,
85
97
  },
86
98
  ];
87
99
  }
88
100
  };
89
101
 
90
- createRemove = (oid: ObjectIdentifier, key: PropertyName): Operation[] => {
102
+ createRemove = (
103
+ oid: ObjectIdentifier,
104
+ key: PropertyName,
105
+ authz?: string,
106
+ ): Operation[] => {
91
107
  return [
92
108
  {
93
109
  oid,
@@ -96,6 +112,7 @@ export class PatchCreator {
96
112
  op: 'remove',
97
113
  name: key,
98
114
  },
115
+ authz,
99
116
  },
100
117
  ];
101
118
  };
@@ -104,6 +121,7 @@ export class PatchCreator {
104
121
  oid: ObjectIdentifier,
105
122
  index: number,
106
123
  value: any,
124
+ authz?: string,
107
125
  ): Operation[] => {
108
126
  if (this.isPrimitive(value)) {
109
127
  return [
@@ -115,12 +133,22 @@ export class PatchCreator {
115
133
  index,
116
134
  value,
117
135
  },
136
+ authz,
118
137
  },
119
138
  ];
120
139
  } else {
121
140
  const itemOid = createSubOid(oid, this.createSubId);
122
141
  return [
123
- ...initialToPatches(value, itemOid, this.getNow),
142
+ ...initialToPatches(
143
+ value,
144
+ itemOid,
145
+ this.getNow,
146
+ this.createSubId,
147
+ undefined,
148
+ {
149
+ authz,
150
+ },
151
+ ),
124
152
  {
125
153
  oid,
126
154
  timestamp: this.getNow(),
@@ -129,12 +157,17 @@ export class PatchCreator {
129
157
  index,
130
158
  value: createRef(itemOid),
131
159
  },
160
+ authz,
132
161
  },
133
162
  ];
134
163
  }
135
164
  };
136
165
 
137
- createListPush = (oid: ObjectIdentifier, value: any): Operation[] => {
166
+ createListPush = (
167
+ oid: ObjectIdentifier,
168
+ value: any,
169
+ authz?: string,
170
+ ): Operation[] => {
138
171
  if (this.isPrimitive(value)) {
139
172
  return [
140
173
  {
@@ -144,12 +177,15 @@ export class PatchCreator {
144
177
  op: 'list-push',
145
178
  value,
146
179
  },
180
+ authz,
147
181
  },
148
182
  ];
149
183
  } else {
150
184
  const itemOid = createSubOid(oid, this.createSubId);
151
185
  return [
152
- ...initialToPatches(value, itemOid, this.getNow),
186
+ ...initialToPatches(value, itemOid, this.getNow, undefined, undefined, {
187
+ authz,
188
+ }),
153
189
  {
154
190
  oid,
155
191
  timestamp: this.getNow(),
@@ -157,12 +193,17 @@ export class PatchCreator {
157
193
  op: 'list-push',
158
194
  value: createRef(itemOid),
159
195
  },
196
+ authz,
160
197
  },
161
198
  ];
162
199
  }
163
200
  };
164
201
 
165
- createListAdd = (oid: ObjectIdentifier, value: any): Operation[] => {
202
+ createListAdd = (
203
+ oid: ObjectIdentifier,
204
+ value: any,
205
+ authz?: string,
206
+ ): Operation[] => {
166
207
  if (!this.isPrimitive(value)) {
167
208
  return [
168
209
  {
@@ -172,6 +213,7 @@ export class PatchCreator {
172
213
  op: 'list-add',
173
214
  value: createRef(value),
174
215
  },
216
+ authz,
175
217
  },
176
218
  ];
177
219
  } else {
@@ -183,6 +225,7 @@ export class PatchCreator {
183
225
  op: 'list-add',
184
226
  value,
185
227
  },
228
+ authz,
186
229
  },
187
230
  ];
188
231
  }
@@ -192,6 +235,7 @@ export class PatchCreator {
192
235
  oid: ObjectIdentifier,
193
236
  index: number,
194
237
  value: any,
238
+ authz?: string,
195
239
  ): Operation[] => {
196
240
  if (this.isPrimitive(value)) {
197
241
  return [
@@ -203,12 +247,15 @@ export class PatchCreator {
203
247
  value,
204
248
  index,
205
249
  },
250
+ authz,
206
251
  },
207
252
  ];
208
253
  } else {
209
254
  const itemOid = createSubOid(oid, this.createSubId);
210
255
  return [
211
- ...initialToPatches(value, itemOid, this.getNow),
256
+ ...initialToPatches(value, itemOid, this.getNow, undefined, undefined, {
257
+ authz,
258
+ }),
212
259
  {
213
260
  oid,
214
261
  timestamp: this.getNow(),
@@ -217,6 +264,7 @@ export class PatchCreator {
217
264
  value: createRef(itemOid),
218
265
  index,
219
266
  },
267
+ authz,
220
268
  },
221
269
  ];
222
270
  }
@@ -226,6 +274,7 @@ export class PatchCreator {
226
274
  oid: ObjectIdentifier,
227
275
  value: any,
228
276
  only?: 'first' | 'last',
277
+ authz?: string,
229
278
  ): Operation[] => {
230
279
  return [
231
280
  {
@@ -236,6 +285,7 @@ export class PatchCreator {
236
285
  value,
237
286
  only,
238
287
  },
288
+ authz,
239
289
  },
240
290
  ];
241
291
  };
@@ -244,6 +294,7 @@ export class PatchCreator {
244
294
  oid: ObjectIdentifier,
245
295
  index: number,
246
296
  count: number = 1,
297
+ authz?: string,
247
298
  ): Operation[] => {
248
299
  return [
249
300
  {
@@ -254,6 +305,7 @@ export class PatchCreator {
254
305
  index,
255
306
  count,
256
307
  },
308
+ authz,
257
309
  },
258
310
  ];
259
311
  };
@@ -262,6 +314,7 @@ export class PatchCreator {
262
314
  oid: ObjectIdentifier,
263
315
  value: ObjectRef | FileRef,
264
316
  index: number,
317
+ authz?: string,
265
318
  ): Operation[] => {
266
319
  return [
267
320
  {
@@ -272,6 +325,7 @@ export class PatchCreator {
272
325
  value,
273
326
  index,
274
327
  },
328
+ authz,
275
329
  },
276
330
  ];
277
331
  };
@@ -280,6 +334,7 @@ export class PatchCreator {
280
334
  oid: ObjectIdentifier,
281
335
  fromIndex: number,
282
336
  toIndex: number,
337
+ authz?: string,
283
338
  ): Operation[] => {
284
339
  return [
285
340
  {
@@ -290,11 +345,12 @@ export class PatchCreator {
290
345
  from: fromIndex,
291
346
  to: toIndex,
292
347
  },
348
+ authz,
293
349
  },
294
350
  ];
295
351
  };
296
352
 
297
- createDelete = (oid: ObjectIdentifier): Operation[] => {
353
+ createDelete = (oid: ObjectIdentifier, authz?: string): Operation[] => {
298
354
  return [
299
355
  {
300
356
  oid,
@@ -302,6 +358,7 @@ export class PatchCreator {
302
358
  data: {
303
359
  op: 'delete',
304
360
  },
361
+ authz,
305
362
  },
306
363
  ];
307
364
  };
package/src/timestamp.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import cuid from 'cuid';
2
- import { v4 } from 'uuid';
3
2
 
4
3
  export interface TimestampProvider {
5
4
  now(version: number): string;
@@ -37,6 +36,10 @@ export class NaiveTimestampProvider implements TimestampProvider {
37
36
  getWallClockTime = (timestamp: string) => {
38
37
  return parseInt(timestamp.slice(VERSION_BLOCK_LENGTH).split('-')[0], 10);
39
38
  };
39
+
40
+ reset() {
41
+ this.counter = 0;
42
+ }
40
43
  }
41
44
 
42
45
  export class HybridLogicalClockTimestampProvider implements TimestampProvider {
@@ -0,0 +1,21 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createOid } from './oids.js';
3
+ import { PatchCreator } from './patch.js';
4
+ import { getUndoOperations } from './undo.js';
5
+
6
+ describe('undo', () => {
7
+ it('correctly removes added list items', () => {
8
+ let time = 0;
9
+ const clock = () => `time-${time++}`;
10
+ let subId = 0;
11
+ const patchCreator = new PatchCreator(clock, () => `${subId++}`);
12
+ const initial = [1, 2];
13
+ const oid = createOid('test', 'foo');
14
+ const operations = patchCreator.createListSet(oid, 2, 3);
15
+ time = 0;
16
+ const undos = getUndoOperations(oid, initial, operations, clock);
17
+
18
+ time = 0;
19
+ expect(undos).toEqual(patchCreator.createListDelete(oid, 2, 1));
20
+ });
21
+ });
package/src/undo.ts CHANGED
@@ -190,14 +190,27 @@ function getUndoOperation(
190
190
  },
191
191
  ];
192
192
  case 'list-set':
193
+ if (initial[data.index]) {
194
+ return [
195
+ {
196
+ oid,
197
+ timestamp: getNow(),
198
+ data: {
199
+ op: 'list-set',
200
+ index: data.index,
201
+ value: initial[data.index],
202
+ },
203
+ },
204
+ ];
205
+ }
193
206
  return [
194
207
  {
195
208
  oid,
196
209
  timestamp: getNow(),
197
210
  data: {
198
- op: 'list-set',
211
+ op: 'list-delete',
199
212
  index: data.index,
200
- value: initial[data.index],
213
+ count: 1,
201
214
  },
202
215
  },
203
216
  ];