@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.
- package/dist/esm/authz.d.ts +25 -0
- package/dist/esm/authz.js +61 -0
- package/dist/esm/authz.js.map +1 -0
- package/dist/esm/baseline.d.ts +1 -0
- package/dist/esm/baseline.js +3 -0
- package/dist/esm/baseline.js.map +1 -1
- package/dist/esm/files.d.ts +4 -0
- package/dist/esm/files.js +18 -0
- package/dist/esm/files.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indexes.js +1 -1
- package/dist/esm/indexes.js.map +1 -1
- package/dist/esm/indexes.test.js +1 -1
- package/dist/esm/indexes.test.js.map +1 -1
- package/dist/esm/migration.d.ts +4 -2
- package/dist/esm/migration.js.map +1 -1
- package/dist/esm/oids.d.ts +6 -24
- package/dist/esm/oids.js +18 -107
- package/dist/esm/oids.js.map +1 -1
- package/dist/esm/oids.test.js +1 -188
- package/dist/esm/oids.test.js.map +1 -1
- package/dist/esm/oidsLegacy.d.ts +18 -0
- package/dist/esm/oidsLegacy.js +72 -0
- package/dist/esm/oidsLegacy.js.map +1 -0
- package/dist/esm/oidsLegacy.test.d.ts +1 -0
- package/dist/esm/oidsLegacy.test.js +115 -0
- package/dist/esm/oidsLegacy.test.js.map +1 -0
- package/dist/esm/operation.d.ts +28 -4
- package/dist/esm/operation.js +70 -35
- package/dist/esm/operation.js.map +1 -1
- package/dist/esm/operation.test.js.map +1 -1
- package/dist/esm/presence.d.ts +0 -2
- package/dist/esm/schema/fields.js +1 -1
- package/dist/esm/schema/fields.js.map +1 -1
- package/dist/esm/schema/validation.js +14 -7
- package/dist/esm/schema/validation.js.map +1 -1
- package/package.json +1 -1
- package/src/authz.ts +74 -0
- package/src/baseline.ts +5 -4
- package/src/files.ts +25 -0
- package/src/index.ts +2 -0
- package/src/indexes.test.ts +1 -1
- package/src/indexes.ts +1 -1
- package/src/migration.ts +5 -1
- package/src/oids.test.ts +0 -241
- package/src/oids.ts +24 -122
- package/src/oidsLegacy.test.ts +147 -0
- package/src/oidsLegacy.ts +87 -0
- package/src/operation.test.ts +0 -1
- package/src/operation.ts +202 -103
- package/src/presence.ts +0 -2
- package/src/schema/fields.ts +1 -1
- 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
|
+
}
|