@verdant-web/common 2.3.4 → 2.4.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/esm/authz.d.ts +25 -0
  2. package/dist/esm/authz.js +61 -0
  3. package/dist/esm/authz.js.map +1 -0
  4. package/dist/esm/baseline.d.ts +1 -0
  5. package/dist/esm/baseline.js +3 -0
  6. package/dist/esm/baseline.js.map +1 -1
  7. package/dist/esm/files.d.ts +4 -0
  8. package/dist/esm/files.js +18 -0
  9. package/dist/esm/files.js.map +1 -1
  10. package/dist/esm/index.d.ts +2 -0
  11. package/dist/esm/index.js +2 -0
  12. package/dist/esm/index.js.map +1 -1
  13. package/dist/esm/indexes.js +1 -1
  14. package/dist/esm/indexes.js.map +1 -1
  15. package/dist/esm/indexes.test.js +1 -1
  16. package/dist/esm/indexes.test.js.map +1 -1
  17. package/dist/esm/migration.d.ts +4 -2
  18. package/dist/esm/migration.js.map +1 -1
  19. package/dist/esm/oids.d.ts +6 -24
  20. package/dist/esm/oids.js +18 -107
  21. package/dist/esm/oids.js.map +1 -1
  22. package/dist/esm/oids.test.js +1 -188
  23. package/dist/esm/oids.test.js.map +1 -1
  24. package/dist/esm/oidsLegacy.d.ts +18 -0
  25. package/dist/esm/oidsLegacy.js +72 -0
  26. package/dist/esm/oidsLegacy.js.map +1 -0
  27. package/dist/esm/oidsLegacy.test.d.ts +1 -0
  28. package/dist/esm/oidsLegacy.test.js +115 -0
  29. package/dist/esm/oidsLegacy.test.js.map +1 -0
  30. package/dist/esm/operation.d.ts +28 -4
  31. package/dist/esm/operation.js +70 -35
  32. package/dist/esm/operation.js.map +1 -1
  33. package/dist/esm/operation.test.js.map +1 -1
  34. package/dist/esm/presence.d.ts +0 -2
  35. package/dist/esm/schema/fields.js +1 -1
  36. package/dist/esm/schema/fields.js.map +1 -1
  37. package/dist/esm/schema/validation.js +14 -7
  38. package/dist/esm/schema/validation.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/authz.ts +74 -0
  41. package/src/baseline.ts +5 -4
  42. package/src/files.ts +25 -0
  43. package/src/index.ts +2 -0
  44. package/src/indexes.test.ts +1 -1
  45. package/src/indexes.ts +1 -1
  46. package/src/migration.ts +5 -1
  47. package/src/oids.test.ts +0 -241
  48. package/src/oids.ts +24 -122
  49. package/src/oidsLegacy.test.ts +147 -0
  50. package/src/oidsLegacy.ts +87 -0
  51. package/src/operation.test.ts +0 -1
  52. package/src/operation.ts +202 -103
  53. package/src/presence.ts +0 -2
  54. package/src/schema/fields.ts +1 -1
  55. package/src/schema/validation.ts +23 -14
package/src/authz.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { DocumentBaseline } from './baseline.js';
2
+ import { Operation } from './operation.js';
3
+
4
+ function encode(str: string): AuthorizationKey {
5
+ if (typeof Buffer !== 'undefined') {
6
+ const val = Buffer.from(str).toString('base64');
7
+ return val as AuthorizationKey;
8
+ }
9
+ const val = btoa(str);
10
+ return val as AuthorizationKey;
11
+ }
12
+
13
+ function decode(str: string): string {
14
+ if (typeof Buffer !== 'undefined') {
15
+ return Buffer.from(str, 'base64').toString();
16
+ }
17
+ return atob(str);
18
+ }
19
+
20
+ export type AuthorizationKey = string & {
21
+ '@@type': 'authz';
22
+ };
23
+
24
+ export const authz = {
25
+ onlyUser: (userId: string): AuthorizationKey => encode(`u:${userId}:*`),
26
+ onlyMe: (): AuthorizationKey => authz.onlyUser(ORIGINATOR_SUBJECT),
27
+ decode: (encoded: string) => {
28
+ const decoded = decode(encoded);
29
+ const parts = decoded.split(':');
30
+ if (parts.length !== 3) {
31
+ throw new Error('Invalid authz string');
32
+ }
33
+ return {
34
+ scope: parts[0],
35
+ subject: parts[1],
36
+ action: parts[2],
37
+ };
38
+ },
39
+ };
40
+
41
+ export const ORIGINATOR_SUBJECT = '$$_originator_$$';
42
+
43
+ /**
44
+ * Rewrites the special "originator" constant subject (used by
45
+ * local-only clients) to the given user ID.
46
+ *
47
+ * Used to initialize a library from a local-only replica
48
+ */
49
+ export function rewriteAuthzOriginator(
50
+ data: { operations?: Operation[]; baselines?: DocumentBaseline[] },
51
+ newSubject: string,
52
+ ) {
53
+ const { operations, baselines } = data;
54
+ if (operations) {
55
+ for (const op of operations) {
56
+ if (op.authz) {
57
+ const decoded = authz.decode(op.authz);
58
+ if (decoded.subject === ORIGINATOR_SUBJECT) {
59
+ op.authz = authz.onlyUser(newSubject);
60
+ }
61
+ }
62
+ }
63
+ }
64
+ if (baselines) {
65
+ for (const baseline of baselines) {
66
+ if (baseline.authz) {
67
+ const decoded = authz.decode(baseline.authz);
68
+ if (decoded.subject === ORIGINATOR_SUBJECT) {
69
+ baseline.authz = authz.onlyUser(newSubject);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
package/src/baseline.ts CHANGED
@@ -1,9 +1,10 @@
1
+ // A: Docs without a base state don't have a baseline, it's
2
+ // written upon rebasing. If you apply ops to an undefined
3
+ // snapshot without an initialize, it remains undefined.
4
+
1
5
  export type DocumentBaseline<T extends any = any> = {
2
6
  oid: string;
3
7
  snapshot: T;
4
8
  timestamp: string;
5
- // TODO: is a deleted flag required here? can we disambiguate
6
- // a document which was snapshotted in a deleted state, vs
7
- // one without a base state at all? what happens if you apply
8
- // ops onto an undefined snapshot (which aren't initialize)?
9
+ authz?: string;
9
10
  };
package/src/files.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { isObject } from './utils.js';
2
+
1
3
  export type FileRef = {
2
4
  '@@type': 'file';
3
5
  id: string;
@@ -22,7 +24,9 @@ export type FileData = {
22
24
  remote: boolean;
23
25
  name: string;
24
26
  type: string;
27
+ /** A local File instance, if available. */
25
28
  file?: Blob;
29
+ /** The server URL of this file. */
26
30
  url?: string;
27
31
  };
28
32
 
@@ -32,3 +36,24 @@ export function getAllFileFields(snapshot: any): [string, FileRef][] {
32
36
  FileRef,
33
37
  ][];
34
38
  }
39
+
40
+ export function isFile(value: any) {
41
+ if (typeof File !== 'undefined' && value instanceof File) {
42
+ return true;
43
+ }
44
+ if (typeof Blob !== 'undefined' && value instanceof Blob) {
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+
50
+ export function isFileData(value: any): value is FileData {
51
+ return (
52
+ value &&
53
+ isObject(value) &&
54
+ typeof value.id === 'string' &&
55
+ typeof value.remote === 'boolean' &&
56
+ typeof value.name === 'string' &&
57
+ typeof value.type === 'string'
58
+ );
59
+ }
package/src/index.ts CHANGED
@@ -20,6 +20,7 @@ export type {
20
20
  export type { UserInfo } from './presence.js';
21
21
  export * from './patch.js';
22
22
  export * from './oids.js';
23
+ export * from './oidsLegacy.js';
23
24
  export * from './EventSubscriber.js';
24
25
  export * from './undo.js';
25
26
  export * from './batching.js';
@@ -28,3 +29,4 @@ export type { Ref } from './refs.js';
28
29
  export { makeObjectRef, makeFileRef, isRef, compareRefs } from './refs.js';
29
30
  export * from './memo.js';
30
31
  export * from './error.js';
32
+ export * from './authz.js';
@@ -185,7 +185,7 @@ describe('all indexes', () => {
185
185
  ),
186
186
  ).toEqual({
187
187
  foobar: 'foo' + COMPOUND_INDEX_SEPARATOR + 'foobar',
188
- '@@@snapshot': { foo: 'foo' },
188
+ '@@@snapshot': JSON.stringify({ foo: 'foo' }),
189
189
  foo: 'foo',
190
190
  bar: 'foobar',
191
191
  });
package/src/indexes.ts CHANGED
@@ -161,7 +161,7 @@ export function getIndexValues(
161
161
  basicIndexes,
162
162
  computeCompoundIndices(schema, { ...doc, ...basicIndexes }),
163
163
  );
164
- basicIndexes['@@@snapshot'] = doc;
164
+ basicIndexes['@@@snapshot'] = JSON.stringify(doc);
165
165
  return basicIndexes;
166
166
  }
167
167
 
package/src/migration.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  getOid,
14
14
  hasDefault,
15
15
  validateEntity,
16
+ AuthorizationKey,
16
17
  } from './index.js';
17
18
 
18
19
  /**@deprecated */
@@ -473,7 +474,10 @@ type MigrationQueries<Old extends SchemaDocuments> = {
473
474
  };
474
475
  type MigrationMutations<New extends SchemaDocuments> = {
475
476
  [Key in keyof New]: {
476
- put(document: New[Key]['init']): Promise<New[Key]['snapshot']>;
477
+ put(
478
+ document: New[Key]['init'],
479
+ options?: { access?: AuthorizationKey },
480
+ ): Promise<New[Key]['snapshot']>;
477
481
  delete(primaryKey: string): Promise<void>;
478
482
  };
479
483
  };
package/src/oids.test.ts CHANGED
@@ -1,27 +1,15 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { createFileRef } from './files.js';
3
3
  import {
4
- areOidsRelated,
5
4
  assignOid,
6
- assignOidPropertiesToAllSubObjects,
7
- assignOidProperty,
8
5
  assignOidsToAllSubObjects,
9
6
  createOid,
10
- createSubOid,
11
7
  decomposeOid,
12
- getOid,
13
8
  getOidSubIdRange,
14
- getOidRoot,
15
9
  hasOid,
16
- maybeGetOidProperty,
17
10
  normalize,
18
11
  normalizeFirstLevel,
19
12
  ObjectIdentifier,
20
- removeOidPropertiesFromAllSubObjects,
21
- getLegacyDotOidSubIdRange,
22
- replaceLegacyOidsInJsonString,
23
- MATCH_LEGACY_OID_JSON_STRING,
24
- replaceLegacyOidsInObject,
25
13
  } from './oids.js';
26
14
 
27
15
  describe('normalizing an object', () => {
@@ -280,127 +268,6 @@ describe('computing a range of oids for a whole object set', () => {
280
268
  expect(isWithin('test/a1', start, end)).toBe(false);
281
269
  expect(isWithin('test/a1:3', start, end)).toBe(false);
282
270
  });
283
- it('should accommodate legacy dot style oids', () => {
284
- const [start, end] = getLegacyDotOidSubIdRange('test/a.foo:barrrr');
285
- expect(start).toEqual('test/a.');
286
- expect(end).toEqual('test/a.\uffff');
287
- expect(start < end).toBe(true);
288
- expect(isWithin('test/a.foo:0', start, end)).toBe(true);
289
- expect(isWithin('test/a.foo:1', start, end)).toBe(true);
290
- expect(isWithin('test/a.bar:zzzzzzzzzzzzzzzzzzzzzzz', start, end)).toBe(
291
- true,
292
- );
293
- expect(isWithin('test/a.aff:\uffff', start, end)).toBe(true);
294
- expect(isWithin('test1/a', start, end)).toBe(false);
295
- expect(isWithin('test/b', start, end)).toBe(false);
296
- expect(isWithin('test/ ', start, end)).toBe(false);
297
- expect(isWithin('test/a1', start, end)).toBe(false);
298
- expect(isWithin('test/a1:3', start, end)).toBe(false);
299
- expect(isWithin('test/a.foo:barrrr', start, end)).toBe(true);
300
- });
301
- });
302
-
303
- describe('assigning OIDs as properties', () => {
304
- it('should assign to all sub-objects', () => {
305
- let i = 0;
306
- function createSubId() {
307
- return (i++).toString();
308
- }
309
-
310
- const initial = {
311
- foo: {
312
- bar: 1,
313
- baz: [2, 3],
314
- },
315
- qux: [
316
- {
317
- corge: true,
318
- },
319
- {
320
- grault: {
321
- garply: 4,
322
- },
323
- },
324
- ],
325
- };
326
- assignOid(initial, 'test/a');
327
- assignOidsToAllSubObjects(initial, createSubId);
328
- assignOidPropertiesToAllSubObjects(initial);
329
-
330
- expect(initial).toMatchInlineSnapshot(`
331
- {
332
- "@@id": "test/a",
333
- "foo": {
334
- "@@id": "test/a:0",
335
- "bar": 1,
336
- "baz": [
337
- 2,
338
- 3,
339
- ],
340
- },
341
- "qux": [
342
- {
343
- "@@id": "test/a:3",
344
- "corge": true,
345
- },
346
- {
347
- "@@id": "test/a:4",
348
- "grault": {
349
- "@@id": "test/a:5",
350
- "garply": 4,
351
- },
352
- },
353
- ],
354
- }
355
- `);
356
- // extra check needed for array since it doesn't serialize in the snapshot
357
- expect(maybeGetOidProperty(initial.qux)).toBe('test/a:2');
358
- });
359
-
360
- it('should transfer assigned OID properties to the memory system', () => {
361
- const initial = assignOidProperty(
362
- {
363
- foo: assignOidProperty(
364
- {
365
- bar: 1,
366
- },
367
- 'test/a:1',
368
- ),
369
- qux: assignOidProperty(
370
- [
371
- assignOidProperty(
372
- {
373
- corge: true,
374
- },
375
- 'test/a:2',
376
- ),
377
- assignOidProperty(
378
- {
379
- grault: assignOidProperty(
380
- {
381
- garply: 4,
382
- },
383
- 'test/a:3',
384
- ),
385
- },
386
- 'test/a:4',
387
- ),
388
- ],
389
- 'test/a:2',
390
- ),
391
- },
392
- 'test/a',
393
- );
394
-
395
- removeOidPropertiesFromAllSubObjects(initial);
396
-
397
- expect(getOid(initial)).toEqual('test/a');
398
- expect(getOid(initial.foo)).toEqual('test/a:1');
399
- expect(getOid(initial.qux)).toEqual('test/a:2');
400
- expect(getOid(initial.qux[0])).toEqual('test/a:2');
401
- expect(getOid(initial.qux[1])).toEqual('test/a:4');
402
- expect(getOid(initial.qux[1].grault)).toEqual('test/a:3');
403
- });
404
271
  });
405
272
 
406
273
  it('should handle special characters in document id or collection', () => {
@@ -430,111 +297,3 @@ describe('assigning OIDs to sub-objects', () => {
430
297
  expect(hasOid(obj.bar[0])).toBe(false);
431
298
  });
432
299
  });
433
-
434
- describe('handling legacy OIDs', () => {
435
- it('should get the root OID for a legacy OID', () => {
436
- expect(getOidRoot('items/clabgyjfh00003968qycsq3ld.inputs.#')).toEqual(
437
- 'items/clabgyjfh00003968qycsq3ld',
438
- );
439
- });
440
- it('should create sub-ids for legacy OIDs in new format', () => {
441
- expect(
442
- createSubOid(
443
- 'items/clabgyjfh00003968qycsq3ld.inputs.#',
444
- () => 'pseudorandom',
445
- ),
446
- ).toEqual('items/clabgyjfh00003968qycsq3ld:pseudorandom');
447
- });
448
- it('should identify new sub-OIDs as related to the legacy root OID', () => {
449
- expect(
450
- areOidsRelated(
451
- 'items/clabgyjfh00003968qycsq3ld.inputs.#',
452
- 'items/clabgyjfh00003968qycsq3ld:pseudorandom',
453
- ),
454
- ).toBe(true);
455
- });
456
- it.each([
457
- ['items/clabgyjfh00003968qycsq3ld.inputs.#:baz', true],
458
- // include more unicode chars
459
- ['items/clabgyjfh00003968qycsq3ld\ufea3.inputs\u39fc.#:baz!!!', true],
460
- // not matching new oids
461
- ['items/clabgyjfh00003968qycsq3ld', false],
462
- ['items/clabgyjfh00003968qycsq3ld:baz', false],
463
- ['items/clabgyjfh00003968qycsq3ld:baz1111', false],
464
- // not matching anything else
465
- [
466
- 'PREPARE SOUS VIDE BATH: Fill container or pot with water. Set the temperature to 130F/54.4C – 132F/55.5C (for very moist and tender) and allow water to heat to that temperature.Tip: start with hot tap water instead of cold water to reduce heating time. Note 4 for other temperatures.',
467
- false,
468
- ],
469
- ])('matches legacy oids', (oid, match) => {
470
- expect(MATCH_LEGACY_OID_JSON_STRING.test('"' + oid + '"'), oid).toBe(match);
471
- // regex are stateful 🙄
472
- MATCH_LEGACY_OID_JSON_STRING.lastIndex = 0;
473
- });
474
- it.each([
475
- [
476
- { op: 'delete', oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz' },
477
- { op: 'delete', oid: 'items/clabgyjfh00003968qycsq3ld:baz' },
478
- ],
479
- [
480
- {
481
- op: 'list-push',
482
- oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz',
483
- value: {
484
- '@@type': 'ref',
485
- id: 'items/clabgyjfh00003968qycsq3ld.inputs.#:qux',
486
- },
487
- },
488
- {
489
- op: 'list-push',
490
- oid: 'items/clabgyjfh00003968qycsq3ld:baz',
491
- value: { '@@type': 'ref', id: 'items/clabgyjfh00003968qycsq3ld:qux' },
492
- },
493
- ],
494
- [
495
- {
496
- op: 'list-remove',
497
- oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz',
498
- value: {
499
- '@@type': 'ref',
500
- id: 'items/clabgyjfh00003968qycsq3ld.inputs.#:qux',
501
- },
502
- },
503
- {
504
- op: 'list-remove',
505
- oid: 'items/clabgyjfh00003968qycsq3ld:baz',
506
- value: { '@@type': 'ref', id: 'items/clabgyjfh00003968qycsq3ld:qux' },
507
- },
508
- ],
509
- [
510
- {
511
- oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz',
512
- timestamp: '2021-03-04T21:00:00.000Z',
513
- snapshot: {
514
- foo: 1,
515
- bar: {
516
- '@@type': 'ref',
517
- id: 'items/clabgyjfh00003968qycsq3ld.inputs.#:qux',
518
- },
519
- },
520
- },
521
- {
522
- oid: 'items/clabgyjfh00003968qycsq3ld:baz',
523
- timestamp: '2021-03-04T21:00:00.000Z',
524
- snapshot: {
525
- foo: 1,
526
- bar: { '@@type': 'ref', id: 'items/clabgyjfh00003968qycsq3ld:qux' },
527
- },
528
- },
529
- ],
530
- [
531
- { oid: 'test/what if.boo.blah so what:fajsdfj' },
532
- { oid: 'test/what if:fajsdfj' },
533
- ],
534
- ])(
535
- 'should replace legacy OIDs in a JSON string with new OIDs',
536
- (from, to) => {
537
- expect(replaceLegacyOidsInObject(from), JSON.stringify(from)).toEqual(to);
538
- },
539
- );
540
- });
package/src/oids.ts CHANGED
@@ -29,10 +29,7 @@ import { isObject, assert } from './utils.js';
29
29
 
30
30
  export type ObjectIdentifier = string;
31
31
 
32
- export const LEGACY_OID_KEY = '__@@oid_do_not_use';
33
- export const OID_KEY = '@@id';
34
-
35
- const COLLECTION_SEPARATOR = '/';
32
+ const SEGMENT_SEPARATOR = '/';
36
33
  const RANDOM_SEPARATOR = ':';
37
34
 
38
35
  /**
@@ -54,7 +51,7 @@ export function maybeGetOid(obj: any): ObjectIdentifier | undefined {
54
51
  if (!isObject(obj)) {
55
52
  return undefined;
56
53
  }
57
- return oidMap.get(obj) ?? obj[OID_KEY] ?? obj[LEGACY_OID_KEY];
54
+ return oidMap.get(obj);
58
55
  }
59
56
 
60
57
  export function assignOid(obj: any, oid: ObjectIdentifier) {
@@ -78,10 +75,6 @@ export function removeOid(obj: any) {
78
75
  return obj;
79
76
  }
80
77
 
81
- export function isOidKey(key: string) {
82
- return key === OID_KEY || key === LEGACY_OID_KEY;
83
- }
84
-
85
78
  /**
86
79
  * For sub-objects, assign a random sub-OID if no OID
87
80
  * is already assigned.
@@ -141,6 +134,11 @@ function unsanitizeFragment(id: string) {
141
134
  .replace(/&dot;/g, '.');
142
135
  }
143
136
 
137
+ /**
138
+ * Creates an OID for the document with a particular ID.
139
+ * To create a sub-object OID, use createSubOid and pass
140
+ * the root OID.
141
+ */
144
142
  export function createOid(
145
143
  collection: string,
146
144
  documentId: string,
@@ -148,7 +146,7 @@ export function createOid(
148
146
  ) {
149
147
  let oid =
150
148
  sanitizeFragment(collection) +
151
- COLLECTION_SEPARATOR +
149
+ SEGMENT_SEPARATOR +
152
150
  sanitizeFragment(documentId);
153
151
  if (subId) {
154
152
  oid += RANDOM_SEPARATOR + subId;
@@ -169,18 +167,26 @@ export function decomposeOid(oid: ObjectIdentifier): {
169
167
  id: string;
170
168
  subId?: string;
171
169
  } {
172
- const [core, random] = oid.split(RANDOM_SEPARATOR);
173
- let [collection, idOrLegacyPathId, ...others] = core.split('/');
174
- // if there's more than one slash... something went wrong, but we can just bolt the rest on.
170
+ let [collection, coreId, ...others] = oid.split('/');
171
+ // if 'others' exists, something's off, but maybe we can recover...
172
+ // by assuming the last segment is the authz and bolting the rest onto coreId
175
173
  if (others.length) {
176
- idOrLegacyPathId += '/' + others.join('/');
174
+ console.error(
175
+ `OID ${oid} has more than 3 segments. Attempting to parse it anyway.`,
176
+ );
177
+ coreId += '/' + others.join('/');
177
178
  }
179
+
180
+ const [idOrLegacyPathId, random] = coreId.split(RANDOM_SEPARATOR);
181
+
178
182
  let id;
183
+ // legacy path handling. shouldn't be necessary anymore.
179
184
  if (idOrLegacyPathId.includes('.')) {
180
185
  id = idOrLegacyPathId.slice(0, idOrLegacyPathId.indexOf('.'));
181
186
  } else {
182
187
  id = idOrLegacyPathId;
183
188
  }
189
+
184
190
  return {
185
191
  collection: unsanitizeFragment(collection),
186
192
  id: unsanitizeFragment(id),
@@ -230,84 +236,6 @@ export function assignOidsToAllSubObjects(
230
236
  }
231
237
  }
232
238
 
233
- export function assignOidProperty(obj: any, oid: ObjectIdentifier) {
234
- assert(
235
- isObject(obj),
236
- `Only objects can be assigned OIDs, received ${JSON.stringify(obj)}`,
237
- );
238
- obj[OID_KEY] = oid;
239
- return obj;
240
- }
241
-
242
- export function maybeGetOidProperty(obj: any) {
243
- if (!isObject(obj)) {
244
- return undefined;
245
- }
246
- return obj[OID_KEY] || obj[LEGACY_OID_KEY];
247
- }
248
-
249
- function removeOidProperty(obj: any) {
250
- if (!isObject(obj)) {
251
- return obj;
252
- }
253
- delete obj[LEGACY_OID_KEY];
254
- delete obj[OID_KEY];
255
- return obj;
256
- }
257
-
258
- function transferOidFromSystemToProperty(obj: any) {
259
- const oid = maybeGetOid(obj);
260
- if (oid) {
261
- assignOidProperty(obj, oid);
262
- }
263
- }
264
-
265
- /**
266
- * Assigns a special property to all objects in the given object
267
- * which have an OID
268
- */
269
- export function assignOidPropertiesToAllSubObjects(obj: any) {
270
- transferOidFromSystemToProperty(obj);
271
-
272
- if (Array.isArray(obj)) {
273
- for (let i = 0; i < obj.length; i++) {
274
- assignOidPropertiesToAllSubObjects(obj[i]);
275
- }
276
- } else if (isObject(obj)) {
277
- for (const key of Object.keys(obj)) {
278
- assignOidPropertiesToAllSubObjects(obj[key]);
279
- }
280
- }
281
- }
282
-
283
- function copyOidFromPropertyToSystem(obj: any) {
284
- const oid = maybeGetOidProperty(obj);
285
- if (oid) {
286
- assignOid(obj, oid);
287
- }
288
- }
289
-
290
- /**
291
- *
292
- * Removes the special property from all objects in the given object
293
- * which have an OID, transferring the OID from the property to the OID
294
- * system in-memory.
295
- */
296
- export function removeOidPropertiesFromAllSubObjects(obj: any) {
297
- copyOidFromPropertyToSystem(obj);
298
- removeOidProperty(obj);
299
-
300
- if (Array.isArray(obj)) {
301
- for (let i = 0; i < obj.length; i++) {
302
- removeOidPropertiesFromAllSubObjects(obj[i]);
303
- }
304
- } else if (isObject(obj)) {
305
- for (const key of Object.keys(obj)) {
306
- removeOidPropertiesFromAllSubObjects(obj[key]);
307
- }
308
- }
309
- }
310
-
311
239
  export function removeOidsFromAllSubObjects(obj: any) {
312
240
  removeOid(obj);
313
241
 
@@ -442,10 +370,6 @@ export function getOidSubIdRange(oid: ObjectIdentifier) {
442
370
  const lastSubId = createSubOid(root, () => '\uffff');
443
371
  return [`${root}${RANDOM_SEPARATOR}`, lastSubId];
444
372
  }
445
- export function getLegacyDotOidSubIdRange(oid: ObjectIdentifier) {
446
- const root = getOidRoot(oid);
447
- return [`${root}.`, `${root}.\uffff`];
448
- }
449
373
 
450
374
  export function getRoots(oids: ObjectIdentifier[]) {
451
375
  const set = new Set<ObjectIdentifier>();
@@ -459,6 +383,10 @@ export function areOidsRelated(oidA: ObjectIdentifier, oidB: ObjectIdentifier) {
459
383
  return getOidRoot(oidA) === getOidRoot(oidB);
460
384
  }
461
385
 
386
+ export function isRootOid(oid: ObjectIdentifier) {
387
+ return !oid.includes(RANDOM_SEPARATOR);
388
+ }
389
+
462
390
  /**
463
391
  * Recursively rewrites any OIDs in an object which are 'foreign' -
464
392
  * i.e. relate to some other object/entity - to be local to the
@@ -493,29 +421,3 @@ function migrateForeignOid(parentOid: ObjectIdentifier, child: any) {
493
421
  );
494
422
  }
495
423
  }
496
-
497
- export function isLegacyDotOid(oid: ObjectIdentifier) {
498
- const partBeforeRandomSep = oid.split(RANDOM_SEPARATOR)[0];
499
- return partBeforeRandomSep.includes('.');
500
- }
501
-
502
- export function convertLegacyOid(oid: ObjectIdentifier) {
503
- const { collection, id, subId } = decomposeOid(oid);
504
- return createOid(collection, id, subId);
505
- }
506
-
507
- export const MATCH_LEGACY_OID_JSON_STRING = /"\w+\/[^"]+?(\.[^"]+)+\:[\S]+?"/g;
508
- export function replaceLegacyOidsInJsonString(string: string) {
509
- // replace every match of a legacy OID, converting to a new OID
510
- return string.replaceAll(MATCH_LEGACY_OID_JSON_STRING, (match) => {
511
- const legacyOid = match.slice(1, match.length - 1);
512
- return `"${convertLegacyOid(legacyOid)}"`;
513
- });
514
- }
515
- export function replaceLegacyOidsInObject(obj: any) {
516
- return JSON.parse(replaceLegacyOidsInJsonString(JSON.stringify(obj)));
517
- }
518
-
519
- export function isRootOid(oid: ObjectIdentifier) {
520
- return !oid.includes(RANDOM_SEPARATOR);
521
- }