@haverstack/core 0.28.0 → 0.30.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.
Files changed (94) hide show
  1. package/README.md +9 -2
  2. package/dist/access.d.ts +20 -0
  3. package/dist/access.d.ts.map +1 -1
  4. package/dist/access.js +26 -0
  5. package/dist/access.js.map +1 -1
  6. package/dist/adapter-entry.d.ts +1 -1
  7. package/dist/adapter-entry.d.ts.map +1 -1
  8. package/dist/adapter-entry.js +1 -1
  9. package/dist/adapter-entry.js.map +1 -1
  10. package/dist/changes.d.ts +15 -2
  11. package/dist/changes.d.ts.map +1 -1
  12. package/dist/changes.js +62 -6
  13. package/dist/changes.js.map +1 -1
  14. package/dist/combine.d.ts.map +1 -1
  15. package/dist/combine.js +1 -4
  16. package/dist/combine.js.map +1 -1
  17. package/dist/errors.d.ts +173 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +208 -0
  20. package/dist/errors.js.map +1 -0
  21. package/dist/grants.d.ts +84 -0
  22. package/dist/grants.d.ts.map +1 -0
  23. package/dist/grants.js +157 -0
  24. package/dist/grants.js.map +1 -0
  25. package/dist/id.d.ts +7 -5
  26. package/dist/id.d.ts.map +1 -1
  27. package/dist/id.js +17 -15
  28. package/dist/id.js.map +1 -1
  29. package/dist/identity-bindings.d.ts +13 -0
  30. package/dist/identity-bindings.d.ts.map +1 -0
  31. package/dist/identity-bindings.js +42 -0
  32. package/dist/identity-bindings.js.map +1 -0
  33. package/dist/index.d.ts +7 -4
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +5 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/limits.d.ts +23 -0
  38. package/dist/limits.d.ts.map +1 -0
  39. package/dist/limits.js +35 -0
  40. package/dist/limits.js.map +1 -0
  41. package/dist/merge.d.ts +1 -1
  42. package/dist/merge.js +2 -2
  43. package/dist/merge.js.map +1 -1
  44. package/dist/query-validation.d.ts +80 -0
  45. package/dist/query-validation.d.ts.map +1 -0
  46. package/dist/query-validation.js +223 -0
  47. package/dist/query-validation.js.map +1 -0
  48. package/dist/record-changes.d.ts +89 -0
  49. package/dist/record-changes.d.ts.map +1 -0
  50. package/dist/record-changes.js +201 -0
  51. package/dist/record-changes.js.map +1 -0
  52. package/dist/record-id.d.ts +70 -0
  53. package/dist/record-id.d.ts.map +1 -0
  54. package/dist/record-id.js +127 -0
  55. package/dist/record-id.js.map +1 -0
  56. package/dist/schema.d.ts.map +1 -1
  57. package/dist/schema.js +56 -5
  58. package/dist/schema.js.map +1 -1
  59. package/dist/scoped-stack.d.ts +460 -0
  60. package/dist/scoped-stack.d.ts.map +1 -0
  61. package/dist/scoped-stack.js +1163 -0
  62. package/dist/scoped-stack.js.map +1 -0
  63. package/dist/stack-reads.d.ts +38 -0
  64. package/dist/stack-reads.d.ts.map +1 -0
  65. package/dist/stack-reads.js +79 -0
  66. package/dist/stack-reads.js.map +1 -0
  67. package/dist/stack.d.ts +108 -700
  68. package/dist/stack.d.ts.map +1 -1
  69. package/dist/stack.js +235 -2286
  70. package/dist/stack.js.map +1 -1
  71. package/dist/testing.d.ts +3 -14
  72. package/dist/testing.d.ts.map +1 -1
  73. package/dist/testing.js +30 -42
  74. package/dist/testing.js.map +1 -1
  75. package/dist/types.d.ts +107 -30
  76. package/dist/types.d.ts.map +1 -1
  77. package/dist/types.js +16 -0
  78. package/dist/types.js.map +1 -1
  79. package/dist/validate.d.ts +31 -0
  80. package/dist/validate.d.ts.map +1 -1
  81. package/dist/validate.js +150 -3
  82. package/dist/validate.js.map +1 -1
  83. package/dist/wire-entry.d.ts +3 -3
  84. package/dist/wire-entry.d.ts.map +1 -1
  85. package/dist/wire-entry.js +3 -3
  86. package/dist/wire-entry.js.map +1 -1
  87. package/dist/wire-record.d.ts +16 -1
  88. package/dist/wire-record.d.ts.map +1 -1
  89. package/dist/wire-record.js +57 -1
  90. package/dist/wire-record.js.map +1 -1
  91. package/dist/wire-request.d.ts.map +1 -1
  92. package/dist/wire-request.js +3 -2
  93. package/dist/wire-request.js.map +1 -1
  94. package/package.json +1 -1
@@ -0,0 +1,201 @@
1
+ /**
2
+ * What a write moved, and how a Record is presented
3
+ * -------------------------------------------------------
4
+ * Two jobs that share one question — what does this Record actually say?
5
+ *
6
+ * The equality helpers answer it against a proposed write, so the no-op
7
+ * decision and a change event's `ops` are the same comparison and can never
8
+ * disagree. The projections answer it against a reader: a soft-deleted
9
+ * Record is its tombstone, and a snapshot's `permissions` are owner-only
10
+ * audit data.
11
+ *
12
+ * See docs/spec/events.md § The event shape and docs/spec/versioning.md
13
+ * § The tombstone is literal.
14
+ */
15
+ import { baseIdOf } from './schema.js';
16
+ import { StackQueryError } from './errors.js';
17
+ import { SYSTEM_TYPES, RECORD_CHANGE_KEYS } from './types.js';
18
+ /**
19
+ * Matches the SQLite adapter's association primary key (kind, label,
20
+ * file_id, related_scope, related_id, related_ns, related_stack).
21
+ */
22
+ export function associationEqual(a, b) {
23
+ if (a.kind !== b.kind || a.label !== b.label)
24
+ return false;
25
+ if (a.kind === 'attachment' && b.kind === 'attachment')
26
+ return a.fileId === b.fileId;
27
+ if (a.kind === 'relationship' && b.kind === 'relationship') {
28
+ return targetEqual(a.target, b.target);
29
+ }
30
+ return true;
31
+ }
32
+ /** Structural equality per target arm — what dissociate() matches on. */
33
+ export function targetEqual(a, b) {
34
+ if (a.scope !== b.scope)
35
+ return false;
36
+ if (a.scope === 'record' && b.scope === 'record') {
37
+ return a.recordId === b.recordId && (a.stackUrl ?? '') === (b.stackUrl ?? '');
38
+ }
39
+ if (a.scope === 'entity' && b.scope === 'entity')
40
+ return a.entityId === b.entityId;
41
+ if (a.scope === 'external' && b.scope === 'external')
42
+ return a.ns === b.ns && a.id === b.id;
43
+ return false;
44
+ }
45
+ export function permissionEqual(a, b) {
46
+ if (a.access !== b.access)
47
+ return false;
48
+ if (a.access === 'public')
49
+ return true;
50
+ if (a.access === 'entity' && b.access === 'entity') {
51
+ return a.entityId === b.entityId && a.read === b.read && a.write === b.write;
52
+ }
53
+ if (a.access === 'group' && b.access === 'group') {
54
+ return a.groupId === b.groupId && a.role === b.role && a.read === b.read && a.write === b.write;
55
+ }
56
+ return false;
57
+ }
58
+ /**
59
+ * A change set has to name at least one aspect. Refused rather than read
60
+ * as a no-op: it addresses nothing, so there is nothing it could have
61
+ * failed to satisfy, and every way of producing one is a caller bug —
62
+ * typically a conditional that built an empty object.
63
+ * See docs/spec/data-model.md § Mutations.
64
+ */
65
+ export function assertNonEmptyChangeSet(changes) {
66
+ // Presence, not truthiness: `unlisted: false` and `parentId: null` are
67
+ // aspects this call names, and reading them as absent would drop a
68
+ // change the caller asked for.
69
+ if (RECORD_CHANGE_KEYS.some((key) => changes[key] !== undefined))
70
+ return;
71
+ throw new StackQueryError('A change set names at least one of: ' + RECORD_CHANGE_KEYS.join(', ') + '.');
72
+ }
73
+ /**
74
+ * Which aspects a change set actually moves, against the record as it
75
+ * stands — the no-op decision and the change event's `ops` are the same
76
+ * comparison, so they can never disagree. A key naming the value a record
77
+ * already holds contributes nothing.
78
+ *
79
+ * `merged` is the content the patch produces, computed once by the
80
+ * caller that had to validate it anyway.
81
+ * See docs/spec/events.md § The event shape.
82
+ */
83
+ export function changeSetOps(existing, changes, merged) {
84
+ const ops = [];
85
+ if (merged !== undefined && !contentEqual(existing.content, merged))
86
+ ops.push('patch');
87
+ if (changes.parentId !== undefined && changes.parentId !== (existing.parentId ?? null)) {
88
+ ops.push('reparent');
89
+ }
90
+ if (changes.permissions && !permissionsEqual(existing.permissions ?? [], changes.permissions)) {
91
+ ops.push('permissions');
92
+ }
93
+ if (changes.associations) {
94
+ const before = existing.associations ?? [];
95
+ const after = changes.associations;
96
+ if (after.some((a) => !before.some((b) => associationEqual(a, b))))
97
+ ops.push('associate');
98
+ if (before.some((b) => !after.some((a) => associationEqual(a, b))))
99
+ ops.push('dissociate');
100
+ }
101
+ if (changes.unlisted !== undefined && Boolean(existing.unlistedAt) !== changes.unlisted) {
102
+ ops.push(changes.unlisted ? 'unlist' : 'list');
103
+ }
104
+ return ops;
105
+ }
106
+ /**
107
+ * The change set narrowed to the aspects that actually moved. An adapter
108
+ * is handed this rather than what the caller wrote, so restating an aspect
109
+ * cannot rewrite it: `unlisted: true` on an already-unlisted record would
110
+ * otherwise drag `unlistedAt` forward, moving the record's publish moment
111
+ * with no op reporting it. It also keeps the adapter contract honest —
112
+ * every key an adapter receives is one it must write.
113
+ */
114
+ export function effectiveChanges(changes, ops) {
115
+ const effective = {};
116
+ if (ops.includes('patch'))
117
+ effective.contentPatch = changes.contentPatch;
118
+ if (ops.includes('reparent'))
119
+ effective.parentId = changes.parentId;
120
+ if (ops.includes('permissions'))
121
+ effective.permissions = changes.permissions;
122
+ if (ops.includes('associate') || ops.includes('dissociate')) {
123
+ effective.associations = changes.associations;
124
+ }
125
+ if (ops.includes('unlist') || ops.includes('list'))
126
+ effective.unlisted = changes.unlisted;
127
+ return effective;
128
+ }
129
+ /**
130
+ * Whether a merge patch produced the content the record already held.
131
+ * Compared by serialization: content is JSON by construction — it round
132
+ * trips through storage that way — and a patch preserves key order for
133
+ * every field it does not name, so the encoding of an unchanged record is
134
+ * stable. A reordering patch that changes nothing else is the one case
135
+ * this reports as a change, which costs an empty version rather than a
136
+ * wrong answer.
137
+ */
138
+ export function contentEqual(a, b) {
139
+ return JSON.stringify(a) === JSON.stringify(b);
140
+ }
141
+ export function permissionsEqual(a, b) {
142
+ return a.length === b.length && a.every((p, i) => permissionEqual(p, b[i]));
143
+ }
144
+ /**
145
+ * Ensures `creator` carries an `admin` relationship association, adding one
146
+ * if it's not already present. Used to bootstrap a `_group` record's first
147
+ * admin at create time.
148
+ */
149
+ export function stampGroupAdmin(associations, creator) {
150
+ const list = associations ?? [];
151
+ const alreadyAdmin = list.some((a) => a.kind === 'relationship' &&
152
+ a.label === 'admin' &&
153
+ a.target.scope === 'entity' &&
154
+ a.target.entityId === creator);
155
+ if (alreadyAdmin)
156
+ return list;
157
+ return [
158
+ ...list,
159
+ { kind: 'relationship', label: 'admin', target: { scope: 'entity', entityId: creator } },
160
+ ];
161
+ }
162
+ /**
163
+ * Whether a Record is a `_group`, in any of its type versions — the family
164
+ * whose roster rules apply.
165
+ */
166
+ export function isGroupRecord(record) {
167
+ return baseIdOf(record.typeId) === SYSTEM_TYPES.GROUP;
168
+ }
169
+ /**
170
+ * Drops a snapshot's `permissions` — owner-only audit data, never served
171
+ * to a non-owner history reader. `entityId` (change attribution) stays.
172
+ * See docs/spec/versioning.md § History access.
173
+ */
174
+ export function stripVersionPermissions(version) {
175
+ if (version.permissions === undefined)
176
+ return version;
177
+ const { permissions: _permissions, ...rest } = version;
178
+ return rest;
179
+ }
180
+ /**
181
+ * The tombstone a soft-deleted Record is presented as. `permissions` is
182
+ * retained because it decides whether the caller may undelete; history is
183
+ * exempt, which is why getVersions() still serves the content this
184
+ * withholds. See docs/spec/versioning.md § The tombstone is literal.
185
+ */
186
+ export function tombstoneOf(record) {
187
+ return {
188
+ id: record.id,
189
+ typeId: record.typeId,
190
+ createdAt: record.createdAt,
191
+ updatedAt: record.updatedAt,
192
+ version: record.version,
193
+ content: {},
194
+ ...(record.deletedAt !== undefined && { deletedAt: record.deletedAt }),
195
+ ...(record.unlistedAt !== undefined && { unlistedAt: record.unlistedAt }),
196
+ ...(record.permissions !== undefined && { permissions: record.permissions }),
197
+ };
198
+ }
199
+ /** A soft-deleted Record presented as its tombstone; anything else untouched. */
200
+ export const presentDeleted = (record) => record.deletedAt ? tombstoneOf(record) : record;
201
+ //# sourceMappingURL=record-changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-changes.js","sourceRoot":"","sources":["../src/record-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAY9D;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAc,EAAE,CAAc;IAC7D,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAC3D,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC;IACrF,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QAC3D,OAAO,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,WAAW,CAAC,CAAqB,EAAE,CAAqB;IACtE,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACjD,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC;IACnF,IAAI,CAAC,CAAC,KAAK,KAAK,UAAU,IAAI,CAAC,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;IAC5F,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,CAAa,EAAE,CAAa;IAC1D,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QACjD,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC;IAClG,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAsB;IAC5D,uEAAuE;IACvE,mEAAmE;IACnE,+BAA+B;IAC/B,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;QAAE,OAAO;IACzE,MAAM,IAAI,eAAe,CACvB,sCAAsC,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAC7E,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAqB,EACrB,OAAsB,EACtB,MAA2C;IAE3C,MAAM,GAAG,GAAe,EAAE,CAAC;IAE3B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvF,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,CAAC,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC;QACvF,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1F,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;QACxF,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAsB,EAAE,GAAe;IACtE,MAAM,SAAS,GAAkB,EAAE,CAAC;IACpC,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,SAAS,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IACzE,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACpE,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAC7E,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC5D,SAAS,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC1F,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,CAA0B,EAAE,CAA0B;IACjF,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAe,EAAE,CAAe;IAC/D,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,YAAuC,EACvC,OAAiB;IAEjB,MAAM,IAAI,GAAG,YAAY,IAAI,EAAE,CAAC;IAChC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAC5B,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,cAAc;QACzB,CAAC,CAAC,KAAK,KAAK,OAAO;QACnB,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ;QAC3B,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,CAChC,CAAC;IACF,IAAI,YAAY;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO;QACL,GAAG,IAAI;QACP,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;KACzF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAmB;IAC/C,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAsB;IAC5D,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACtD,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAmB;IAC7C,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,EAAE;QACX,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;QACtE,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;QACzE,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAmB,EAAe,EAAE,CACjE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Record ID and clock-field validation
3
+ * -------------------------------------------------------
4
+ * The rules a caller-supplied `id`, `parentId`, `createdAt` or `updatedAt`
5
+ * is held to before any of them reaches storage. A client may mint its own
6
+ * id and backdate a record's clock, so both are untrusted input here even
7
+ * when the types say otherwise.
8
+ *
9
+ * See docs/spec/data-model.md § Record IDs.
10
+ */
11
+ import type { ValidationError } from './validate.js';
12
+ export declare const DEFAULT_ID_TIMESTAMP_SKEW_MS: number;
13
+ /**
14
+ * The same format rule applied to a `parentId` a caller names. Separate
15
+ * from validateRecordId() only for its message: the id under discussion is
16
+ * the destination, not the record being written, and a shared message would
17
+ * report the wrong one. See docs/spec/data-model.md § Reparenting.
18
+ */
19
+ export declare function validateParentId(parentId: string): void;
20
+ /**
21
+ * Format and reserved-prefix checks — full-trust context (Stack.create()).
22
+ * Checked before the format check: the Crockford charset already excludes
23
+ * "_", so a reserved-looking id (e.g. "_config") would otherwise just fail
24
+ * as a generic format error instead of a specific, actionable one.
25
+ *
26
+ * Throws StackQueryError, not StackValidationError: a malformed id is
27
+ * structurally bad input the request never gets past — it doesn't reach
28
+ * type-schema validation — the same reasoning that makes an undecodable
29
+ * pagination cursor a StackQueryError rather than a content-validation
30
+ * failure. See StackQueryError's doc comment.
31
+ */
32
+ export declare function validateRecordId(id: string): void;
33
+ /**
34
+ * Validity and range check for the backdating options on unscoped
35
+ * Stack.create(). A Date is only as good as what the caller parsed it
36
+ * from, and the two failure modes both need catching here rather than
37
+ * downstream:
38
+ *
39
+ * - **Invalid Date** (`new Date('13/45/2020')` off a malformed import row)
40
+ * has a NaN getTime(), and every comparison against NaN is false — so an
41
+ * unchecked Invalid Date passes the updatedAt/createdAt ordering check
42
+ * and the id/createdAt skew check by turning them off, mints the
43
+ * epoch-zero ID `000000000xxx`, and persists a record whose
44
+ * `createdAt.toISOString()` throws RangeError in serializeRecord() —
45
+ * making that record, and any wire response containing it,
46
+ * permanently unreadable.
47
+ * - **Out of encodable range** — before 1970 crockford32Encode() throws a
48
+ * bare RangeError from deep inside the ID encoder, and past
49
+ * MAX_ID_TIMESTAMP the derived ID silently grows to 13 characters and
50
+ * fails isValidIdFormat().
51
+ *
52
+ * Checked at the door for both, as a StackValidationError naming the
53
+ * field. Applies whether or not an `id` is supplied: a clock field outside
54
+ * this range is unrepresentable regardless of where the ID came from.
55
+ */
56
+ export declare function validateClockField(value: Date | undefined, path: string): ValidationError[];
57
+ /**
58
+ * Timestamp-prefix plausibility check, shared by callers that compare an
59
+ * ID's embedded millisecond against a different reference each:
60
+ * ScopedStack.create() against the current time for any non-backdated
61
+ * create (a grantee is untrusted and could otherwise mint an ID that
62
+ * forges its sort position, and this is the one check standing between a
63
+ * delegated or grantee caller and doing so), and Stack.create() — reached
64
+ * directly when unscoped, or via ScopedStack.create() when the requester
65
+ * is the owner acting alone with an explicit `createdAt` — against that
66
+ * `createdAt` instead (the two must agree, not silently diverge — see
67
+ * docs/spec/data-model.md § Record IDs). Pass null to disable.
68
+ */
69
+ export declare function validateIdTimestampSkew(id: string, toleranceMs: number | null, referenceMs: number, referenceLabel: string): void;
70
+ //# sourceMappingURL=record-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-id.d.ts","sourceRoot":"","sources":["../src/record-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOrD,eAAO,MAAM,4BAA4B,QAAsB,CAAC;AAEhE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAWvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CASjD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CA0B3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,GACrB,IAAI,CAWN"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Record ID and clock-field validation
3
+ * -------------------------------------------------------
4
+ * The rules a caller-supplied `id`, `parentId`, `createdAt` or `updatedAt`
5
+ * is held to before any of them reaches storage. A client may mint its own
6
+ * id and backdate a record's clock, so both are untrusted input here even
7
+ * when the types say otherwise.
8
+ *
9
+ * See docs/spec/data-model.md § Record IDs.
10
+ */
11
+ import { isValidIdFormat, idTimestamp, MAX_ID_TIMESTAMP } from './id.js';
12
+ import { StackQueryError, StackValidationError } from './errors.js';
13
+ // -------------------------------------------------------
14
+ // Record ID validation
15
+ // -------------------------------------------------------
16
+ const RESERVED_ID_PREFIX = '_';
17
+ export const DEFAULT_ID_TIMESTAMP_SKEW_MS = 24 * 60 * 60 * 1000;
18
+ /**
19
+ * The same format rule applied to a `parentId` a caller names. Separate
20
+ * from validateRecordId() only for its message: the id under discussion is
21
+ * the destination, not the record being written, and a shared message would
22
+ * report the wrong one. See docs/spec/data-model.md § Reparenting.
23
+ */
24
+ export function validateParentId(parentId) {
25
+ if (parentId.startsWith(RESERVED_ID_PREFIX)) {
26
+ throw new StackQueryError(`Invalid parentId "${parentId}": uses the reserved "${RESERVED_ID_PREFIX}" prefix.`);
27
+ }
28
+ if (!isValidIdFormat(parentId)) {
29
+ throw new StackQueryError(`Invalid parentId "${parentId}": expected 12 lowercase Crockford base-32 characters.`);
30
+ }
31
+ }
32
+ /**
33
+ * Format and reserved-prefix checks — full-trust context (Stack.create()).
34
+ * Checked before the format check: the Crockford charset already excludes
35
+ * "_", so a reserved-looking id (e.g. "_config") would otherwise just fail
36
+ * as a generic format error instead of a specific, actionable one.
37
+ *
38
+ * Throws StackQueryError, not StackValidationError: a malformed id is
39
+ * structurally bad input the request never gets past — it doesn't reach
40
+ * type-schema validation — the same reasoning that makes an undecodable
41
+ * pagination cursor a StackQueryError rather than a content-validation
42
+ * failure. See StackQueryError's doc comment.
43
+ */
44
+ export function validateRecordId(id) {
45
+ if (id.startsWith(RESERVED_ID_PREFIX)) {
46
+ throw new StackQueryError(`ID "${id}" uses the reserved "${RESERVED_ID_PREFIX}" prefix.`);
47
+ }
48
+ if (!isValidIdFormat(id)) {
49
+ throw new StackQueryError(`Invalid ID "${id}": expected 12 lowercase Crockford base-32 characters.`);
50
+ }
51
+ }
52
+ /**
53
+ * Validity and range check for the backdating options on unscoped
54
+ * Stack.create(). A Date is only as good as what the caller parsed it
55
+ * from, and the two failure modes both need catching here rather than
56
+ * downstream:
57
+ *
58
+ * - **Invalid Date** (`new Date('13/45/2020')` off a malformed import row)
59
+ * has a NaN getTime(), and every comparison against NaN is false — so an
60
+ * unchecked Invalid Date passes the updatedAt/createdAt ordering check
61
+ * and the id/createdAt skew check by turning them off, mints the
62
+ * epoch-zero ID `000000000xxx`, and persists a record whose
63
+ * `createdAt.toISOString()` throws RangeError in serializeRecord() —
64
+ * making that record, and any wire response containing it,
65
+ * permanently unreadable.
66
+ * - **Out of encodable range** — before 1970 crockford32Encode() throws a
67
+ * bare RangeError from deep inside the ID encoder, and past
68
+ * MAX_ID_TIMESTAMP the derived ID silently grows to 13 characters and
69
+ * fails isValidIdFormat().
70
+ *
71
+ * Checked at the door for both, as a StackValidationError naming the
72
+ * field. Applies whether or not an `id` is supplied: a clock field outside
73
+ * this range is unrepresentable regardless of where the ID came from.
74
+ */
75
+ export function validateClockField(value, path) {
76
+ if (value === undefined)
77
+ return [];
78
+ // Type-checked callers always pass a Date, but this option is now
79
+ // reachable from the wire: JSON has no Date, so a server that forwards a
80
+ // parsed `POST /records` body hands us the ISO *string* it deserialized.
81
+ // Without this the very next line is `"2020-…".getTime()` — an unhandled
82
+ // TypeError, a 500 where the caller should have got a 400 naming the
83
+ // field.
84
+ if (!(value instanceof Date)) {
85
+ return [{ path, message: `${path} must be a Date.` }];
86
+ }
87
+ const ms = value.getTime();
88
+ if (Number.isNaN(ms)) {
89
+ return [{ path, message: `${path} is not a valid Date.` }];
90
+ }
91
+ if (ms < 0 || ms > MAX_ID_TIMESTAMP) {
92
+ return [
93
+ {
94
+ path,
95
+ message: `${path} is outside the representable range ` +
96
+ `(1970-01-01T00:00:00.000Z…${new Date(MAX_ID_TIMESTAMP).toISOString()}).`,
97
+ },
98
+ ];
99
+ }
100
+ return [];
101
+ }
102
+ /**
103
+ * Timestamp-prefix plausibility check, shared by callers that compare an
104
+ * ID's embedded millisecond against a different reference each:
105
+ * ScopedStack.create() against the current time for any non-backdated
106
+ * create (a grantee is untrusted and could otherwise mint an ID that
107
+ * forges its sort position, and this is the one check standing between a
108
+ * delegated or grantee caller and doing so), and Stack.create() — reached
109
+ * directly when unscoped, or via ScopedStack.create() when the requester
110
+ * is the owner acting alone with an explicit `createdAt` — against that
111
+ * `createdAt` instead (the two must agree, not silently diverge — see
112
+ * docs/spec/data-model.md § Record IDs). Pass null to disable.
113
+ */
114
+ export function validateIdTimestampSkew(id, toleranceMs, referenceMs, referenceLabel) {
115
+ if (toleranceMs === null)
116
+ return;
117
+ const skew = Math.abs(referenceMs - idTimestamp(id));
118
+ if (skew > toleranceMs) {
119
+ throw new StackValidationError([
120
+ {
121
+ path: 'id',
122
+ message: `ID "${id}" timestamp disagrees with ${referenceLabel} by more than the allowed clock-skew tolerance (${toleranceMs}ms).`,
123
+ },
124
+ ]);
125
+ }
126
+ }
127
+ //# sourceMappingURL=record-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-id.js","sourceRoot":"","sources":["../src/record-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGpE,0DAA0D;AAC1D,uBAAuB;AACvB,0DAA0D;AAE1D,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,QAAQ,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,eAAe,CACvB,qBAAqB,QAAQ,yBAAyB,kBAAkB,WAAW,CACpF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,eAAe,CACvB,qBAAqB,QAAQ,wDAAwD,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,IAAI,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,eAAe,CAAC,OAAO,EAAE,wBAAwB,kBAAkB,WAAW,CAAC,CAAC;IAC5F,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,eAAe,CACvB,eAAe,EAAE,wDAAwD,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAuB,EAAE,IAAY;IACtE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACnC,kEAAkE;IAClE,yEAAyE;IACzE,yEAAyE;IACzE,yEAAyE;IACzE,qEAAqE;IACrE,SAAS;IACT,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,kBAAkB,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,uBAAuB,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAC;QACpC,OAAO;YACL;gBACE,IAAI;gBACJ,OAAO,EACL,GAAG,IAAI,sCAAsC;oBAC7C,6BAA6B,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,IAAI;aAC5E;SACF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CACrC,EAAU,EACV,WAA0B,EAC1B,WAAmB,EACnB,cAAsB;IAEtB,IAAI,WAAW,KAAK,IAAI;QAAE,OAAO;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,IAAI,IAAI,GAAG,WAAW,EAAE,CAAC;QACvB,MAAM,IAAI,oBAAoB,CAAC;YAC7B;gBACE,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,OAAO,EAAE,8BAA8B,cAAc,mDAAmD,WAAW,MAAM;aACnI;SACF,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,YAAY,CAAC;AA8CxE;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAU,QAAQ,UAAU,KAAG,OAAO,CAAC,MAAM,CAMnE,CAAC;AA8DF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,iBAAiB,UAAU,EAAE,gBAAgB,UAAU,KAAG,OAC9B,CAAC;AAU1D,MAAM,MAAM,oBAAoB,GAAG;IACjC,qHAAqH;IACrH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAyEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,UAAU,EAAE,WAAW,UAAU,KAAG,oBAAoB,EAI3F,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,KAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAIlF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAAgC,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,MAA+C,CAAC;AAE1F;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,OAGnD,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,YAAY,CAAC;AAmExE;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAU,QAAQ,UAAU,KAAG,OAAO,CAAC,MAAM,CAMnE,CAAC;AA2EF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,iBAAiB,UAAU,EAAE,gBAAgB,UAAU,KAAG,OAC9B,CAAC;AAU1D,MAAM,MAAM,oBAAoB,GAAG;IACjC,qHAAqH;IACrH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAwFF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,UAAU,EAAE,WAAW,UAAU,KAAG,oBAAoB,EAI3F,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,KAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAIlF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAAgC,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,MAA+C,CAAC;AAE1F;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,OAGnD,CAAC"}
package/dist/schema.js CHANGED
@@ -17,6 +17,18 @@
17
17
  */
18
18
  const canonicalizeFieldDef = (def) => {
19
19
  if (def.kind === 'array') {
20
+ // `open` carries into the hash and `items` drops out of it, for the
21
+ // reason an object's `properties` does below: an open array accepts
22
+ // content a declared one refuses. A closed array omits the flag rather
23
+ // than storing `false`, so declaring it explicitly hashes the same as
24
+ // leaving it off.
25
+ if (def.open) {
26
+ return {
27
+ kind: def.kind,
28
+ open: true,
29
+ ...(def.required !== undefined && { required: def.required }),
30
+ };
31
+ }
20
32
  return {
21
33
  items: canonicalizeFieldDef(def.items),
22
34
  kind: def.kind,
@@ -24,6 +36,15 @@ const canonicalizeFieldDef = (def) => {
24
36
  };
25
37
  }
26
38
  if (def.kind === 'object') {
39
+ // An open object and one declaring no properties accept different
40
+ // content, so they must not share a hash.
41
+ if (def.open) {
42
+ return {
43
+ kind: def.kind,
44
+ open: true,
45
+ ...(def.required !== undefined && { required: def.required }),
46
+ };
47
+ }
27
48
  return {
28
49
  kind: def.kind,
29
50
  properties: canonicalizeSchema(def.properties),
@@ -78,6 +99,8 @@ const READ_COMPATIBLE = {
78
99
  // items / object properties is depth-bounded — matches MAX_VALIDATION_DEPTH
79
100
  // in validate.ts. Past the limit we can't verify compatibility, so we
80
101
  // fail closed (treat as incompatible) rather than risk a stack overflow.
102
+ /** Only a container can be open, so this is false for every scalar. */
103
+ const isOpen = (def) => (def.kind === 'array' || def.kind === 'object') && def.open === true;
81
104
  const MAX_COMPATIBILITY_DEPTH = 32;
82
105
  /**
83
106
  * Check whether a candidate field satisfies a required field, recursing
@@ -87,11 +110,24 @@ const isFieldCompatible = (candidate, required, depth) => {
87
110
  if (depth > MAX_COMPATIBILITY_DEPTH)
88
111
  return false;
89
112
  if (required.kind === 'array') {
90
- return (candidate.kind === 'array' && isFieldCompatible(candidate.items, required.items, depth + 1));
113
+ if (candidate.kind !== 'array')
114
+ return false;
115
+ // An open requirement asks nothing of the elements, so any array
116
+ // satisfies it; a declared one is unsatisfied by an open candidate,
117
+ // which promises nothing about what it holds.
118
+ if (required.open)
119
+ return true;
120
+ return !candidate.open && isFieldCompatible(candidate.items, required.items, depth + 1);
91
121
  }
92
122
  if (required.kind === 'object') {
93
- return (candidate.kind === 'object' &&
94
- isCompatibleAtDepth(candidate.properties, required.properties, depth + 1));
123
+ if (candidate.kind !== 'object')
124
+ return false;
125
+ // Same on both sides: an open candidate declares no fields, so it
126
+ // satisfies a required object only where that one asks for none — a bag
127
+ // promises a consumer nothing to read.
128
+ if (required.open)
129
+ return true;
130
+ return isCompatibleAtDepth(candidate.open ? {} : candidate.properties, required.properties, depth + 1);
95
131
  }
96
132
  if (candidate.kind === 'array' || candidate.kind === 'object')
97
133
  return false;
@@ -138,11 +174,26 @@ const diffField = (path, stored, candidate, depth, violations) => {
138
174
  message: `required changed from ${!!stored.required} to ${!!candidate.required}`,
139
175
  });
140
176
  }
177
+ // Opening a declared container, or closing an open one, changes which
178
+ // content it accepts in a way no field-by-field diff would show.
179
+ if (isOpen(stored) !== isOpen(candidate)) {
180
+ violations.push({
181
+ path,
182
+ message: isOpen(stored)
183
+ ? `${stored.kind} changed from open to declared`
184
+ : `${stored.kind} changed from declared to open`,
185
+ });
186
+ return;
187
+ }
141
188
  if (stored.kind === 'array' && candidate.kind === 'array') {
142
- diffField(`${path}[]`, stored.items, candidate.items, depth + 1, violations);
189
+ if (!stored.open && !candidate.open) {
190
+ diffField(`${path}[]`, stored.items, candidate.items, depth + 1, violations);
191
+ }
143
192
  }
144
193
  if (stored.kind === 'object' && candidate.kind === 'object') {
145
- diffFields(path, stored.properties, candidate.properties, depth + 1, violations);
194
+ if (!stored.open && !candidate.open) {
195
+ diffFields(path, stored.properties, candidate.properties, depth + 1, violations);
196
+ }
146
197
  }
147
198
  };
148
199
  const diffFields = (prefix, stored, candidate, depth, violations) => {
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}