@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
@@ -0,0 +1,147 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ getLegacyDotOidSubIdRange,
4
+ MATCH_LEGACY_OID_JSON_STRING,
5
+ replaceLegacyOidsInObject,
6
+ } from './oidsLegacy.js';
7
+ import {
8
+ areOidsRelated,
9
+ createSubOid,
10
+ getOidRoot,
11
+ ObjectIdentifier,
12
+ } from './oids.js';
13
+
14
+ describe('handling legacy OIDs', () => {
15
+ it('should get the root OID for a legacy OID', () => {
16
+ expect(getOidRoot('items/clabgyjfh00003968qycsq3ld.inputs.#')).toEqual(
17
+ 'items/clabgyjfh00003968qycsq3ld',
18
+ );
19
+ });
20
+ it('should create sub-ids for legacy OIDs in new format', () => {
21
+ expect(
22
+ createSubOid(
23
+ 'items/clabgyjfh00003968qycsq3ld.inputs.#',
24
+ () => 'pseudorandom',
25
+ ),
26
+ ).toEqual('items/clabgyjfh00003968qycsq3ld:pseudorandom');
27
+ });
28
+ it('should identify new sub-OIDs as related to the legacy root OID', () => {
29
+ expect(
30
+ areOidsRelated(
31
+ 'items/clabgyjfh00003968qycsq3ld.inputs.#',
32
+ 'items/clabgyjfh00003968qycsq3ld:pseudorandom',
33
+ ),
34
+ ).toBe(true);
35
+ });
36
+ it.each([
37
+ ['items/clabgyjfh00003968qycsq3ld.inputs.#:baz', true],
38
+ // include more unicode chars
39
+ ['items/clabgyjfh00003968qycsq3ld\ufea3.inputs\u39fc.#:baz!!!', true],
40
+ // not matching new oids
41
+ ['items/clabgyjfh00003968qycsq3ld', false],
42
+ ['items/clabgyjfh00003968qycsq3ld:baz', false],
43
+ ['items/clabgyjfh00003968qycsq3ld:baz1111', false],
44
+ // not matching anything else
45
+ [
46
+ '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.',
47
+ false,
48
+ ],
49
+ ])('matches legacy oids', (oid, match) => {
50
+ expect(MATCH_LEGACY_OID_JSON_STRING.test('"' + oid + '"'), oid).toBe(match);
51
+ // regex are stateful 🙄
52
+ MATCH_LEGACY_OID_JSON_STRING.lastIndex = 0;
53
+ });
54
+ it.each([
55
+ [
56
+ { op: 'delete', oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz' },
57
+ { op: 'delete', oid: 'items/clabgyjfh00003968qycsq3ld:baz' },
58
+ ],
59
+ [
60
+ {
61
+ op: 'list-push',
62
+ oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz',
63
+ value: {
64
+ '@@type': 'ref',
65
+ id: 'items/clabgyjfh00003968qycsq3ld.inputs.#:qux',
66
+ },
67
+ },
68
+ {
69
+ op: 'list-push',
70
+ oid: 'items/clabgyjfh00003968qycsq3ld:baz',
71
+ value: { '@@type': 'ref', id: 'items/clabgyjfh00003968qycsq3ld:qux' },
72
+ },
73
+ ],
74
+ [
75
+ {
76
+ op: 'list-remove',
77
+ oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz',
78
+ value: {
79
+ '@@type': 'ref',
80
+ id: 'items/clabgyjfh00003968qycsq3ld.inputs.#:qux',
81
+ },
82
+ },
83
+ {
84
+ op: 'list-remove',
85
+ oid: 'items/clabgyjfh00003968qycsq3ld:baz',
86
+ value: { '@@type': 'ref', id: 'items/clabgyjfh00003968qycsq3ld:qux' },
87
+ },
88
+ ],
89
+ [
90
+ {
91
+ oid: 'items/clabgyjfh00003968qycsq3ld.inputs.#:baz',
92
+ timestamp: '2021-03-04T21:00:00.000Z',
93
+ snapshot: {
94
+ foo: 1,
95
+ bar: {
96
+ '@@type': 'ref',
97
+ id: 'items/clabgyjfh00003968qycsq3ld.inputs.#:qux',
98
+ },
99
+ },
100
+ },
101
+ {
102
+ oid: 'items/clabgyjfh00003968qycsq3ld:baz',
103
+ timestamp: '2021-03-04T21:00:00.000Z',
104
+ snapshot: {
105
+ foo: 1,
106
+ bar: { '@@type': 'ref', id: 'items/clabgyjfh00003968qycsq3ld:qux' },
107
+ },
108
+ },
109
+ ],
110
+ [
111
+ { oid: 'test/what if.boo.blah so what:fajsdfj' },
112
+ { oid: 'test/what if:fajsdfj' },
113
+ ],
114
+ ])(
115
+ 'should replace legacy OIDs in a JSON string with new OIDs',
116
+ (from, to) => {
117
+ expect(replaceLegacyOidsInObject(from), JSON.stringify(from)).toEqual(to);
118
+ },
119
+ );
120
+
121
+ it('should accommodate legacy dot style oids when computing ranges', () => {
122
+ function isWithin(
123
+ oid: ObjectIdentifier,
124
+ start: ObjectIdentifier,
125
+ end: ObjectIdentifier,
126
+ ) {
127
+ return oid >= start && oid <= end;
128
+ }
129
+
130
+ const [start, end] = getLegacyDotOidSubIdRange('test/a.foo:barrrr');
131
+ expect(start).toEqual('test/a.');
132
+ expect(end).toEqual('test/a.\uffff');
133
+ expect(start < end).toBe(true);
134
+ expect(isWithin('test/a.foo:0', start, end)).toBe(true);
135
+ expect(isWithin('test/a.foo:1', start, end)).toBe(true);
136
+ expect(isWithin('test/a.bar:zzzzzzzzzzzzzzzzzzzzzzz', start, end)).toBe(
137
+ true,
138
+ );
139
+ expect(isWithin('test/a.aff:\uffff', start, end)).toBe(true);
140
+ expect(isWithin('test1/a', start, end)).toBe(false);
141
+ expect(isWithin('test/b', start, end)).toBe(false);
142
+ expect(isWithin('test/ ', start, end)).toBe(false);
143
+ expect(isWithin('test/a1', start, end)).toBe(false);
144
+ expect(isWithin('test/a1:3', start, end)).toBe(false);
145
+ expect(isWithin('test/a.foo:barrrr', start, end)).toBe(true);
146
+ });
147
+ });
@@ -0,0 +1,87 @@
1
+ import {
2
+ assignOid,
3
+ createOid,
4
+ decomposeOid,
5
+ getOidRoot,
6
+ ObjectIdentifier,
7
+ } from './oids.js';
8
+ import { isObject } from './utils.js';
9
+
10
+ export const LEGACY_OID_KEY = '__@@oid_do_not_use';
11
+ export const OID_KEY = '@@id';
12
+
13
+ export function maybeGetOidProperty(obj: any) {
14
+ if (!isObject(obj)) {
15
+ return undefined;
16
+ }
17
+ return obj[OID_KEY] || obj[LEGACY_OID_KEY];
18
+ }
19
+
20
+ function removeOidProperty(obj: any) {
21
+ if (!isObject(obj)) {
22
+ return obj;
23
+ }
24
+ delete obj[LEGACY_OID_KEY];
25
+ delete obj[OID_KEY];
26
+ return obj;
27
+ }
28
+
29
+ function copyOidFromPropertyToSystem(obj: any) {
30
+ const oid = maybeGetOidProperty(obj);
31
+ if (oid) {
32
+ assignOid(obj, oid);
33
+ }
34
+ }
35
+
36
+ /**
37
+ *
38
+ * Removes the special property from all objects in the given object
39
+ * which have an OID, transferring the OID from the property to the OID
40
+ * system in-memory.
41
+ */
42
+ export function removeOidPropertiesFromAllSubObjects(obj: any) {
43
+ copyOidFromPropertyToSystem(obj);
44
+ removeOidProperty(obj);
45
+
46
+ if (Array.isArray(obj)) {
47
+ for (let i = 0; i < obj.length; i++) {
48
+ removeOidPropertiesFromAllSubObjects(obj[i]);
49
+ }
50
+ } else if (isObject(obj)) {
51
+ for (const key of Object.keys(obj)) {
52
+ removeOidPropertiesFromAllSubObjects(obj[key]);
53
+ }
54
+ }
55
+ }
56
+
57
+ export function isLegacyDotOid(oid: ObjectIdentifier) {
58
+ const partBeforeRandomSep = oid.split(':')[0];
59
+ return partBeforeRandomSep.includes('.');
60
+ }
61
+
62
+ export function convertLegacyOid(oid: ObjectIdentifier) {
63
+ const { collection, id, subId } = decomposeOid(oid);
64
+ return createOid(collection, id, subId);
65
+ }
66
+
67
+ // NOTE: all legacy OIDs should now be gone.
68
+ export const MATCH_LEGACY_OID_JSON_STRING = /"\w+\/[^"]+?(\.[^"]+)+\:[\S]+?"/g;
69
+ export function replaceLegacyOidsInJsonString(string: string) {
70
+ // replace every match of a legacy OID, converting to a new OID
71
+ return string.replaceAll(MATCH_LEGACY_OID_JSON_STRING, (match) => {
72
+ const legacyOid = match.slice(1, match.length - 1);
73
+ return `"${convertLegacyOid(legacyOid)}"`;
74
+ });
75
+ }
76
+ export function replaceLegacyOidsInObject(obj: any) {
77
+ return JSON.parse(replaceLegacyOidsInJsonString(JSON.stringify(obj)));
78
+ }
79
+
80
+ export function getLegacyDotOidSubIdRange(oid: ObjectIdentifier) {
81
+ const root = getOidRoot(oid);
82
+ return [`${root}.`, `${root}.\uffff`];
83
+ }
84
+
85
+ export function isOidKey(key: string) {
86
+ return key === OID_KEY || key === LEGACY_OID_KEY;
87
+ }
@@ -5,7 +5,6 @@ import {
5
5
  assignOidsToAllSubObjects,
6
6
  createRef,
7
7
  getOid,
8
- OID_KEY,
9
8
  } from './oids.js';
10
9
  import {
11
10
  applyPatch,