@haverstack/core 0.29.0 → 0.31.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/dist/adapter-entry.d.ts +2 -2
- package/dist/adapter-entry.d.ts.map +1 -1
- package/dist/adapter-entry.js +1 -1
- package/dist/adapter-entry.js.map +1 -1
- package/dist/changes.d.ts +14 -0
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +35 -0
- package/dist/changes.js.map +1 -1
- package/dist/errors.d.ts +191 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +219 -0
- package/dist/errors.js.map +1 -0
- package/dist/grants.d.ts +84 -0
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +157 -0
- package/dist/grants.js.map +1 -0
- package/dist/id.d.ts +7 -5
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +17 -15
- package/dist/id.js.map +1 -1
- package/dist/identity-bindings.d.ts +13 -0
- package/dist/identity-bindings.d.ts.map +1 -0
- package/dist/identity-bindings.js +42 -0
- package/dist/identity-bindings.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +23 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +35 -0
- package/dist/limits.js.map +1 -0
- package/dist/query-validation.d.ts +83 -0
- package/dist/query-validation.d.ts.map +1 -0
- package/dist/query-validation.js +228 -0
- package/dist/query-validation.js.map +1 -0
- package/dist/record-changes.d.ts +89 -0
- package/dist/record-changes.d.ts.map +1 -0
- package/dist/record-changes.js +201 -0
- package/dist/record-changes.js.map +1 -0
- package/dist/record-id.d.ts +70 -0
- package/dist/record-id.d.ts.map +1 -0
- package/dist/record-id.js +127 -0
- package/dist/record-id.js.map +1 -0
- package/dist/scoped-stack.d.ts +468 -0
- package/dist/scoped-stack.d.ts.map +1 -0
- package/dist/scoped-stack.js +1173 -0
- package/dist/scoped-stack.js.map +1 -0
- package/dist/stack-reads.d.ts +38 -0
- package/dist/stack-reads.d.ts.map +1 -0
- package/dist/stack-reads.js +79 -0
- package/dist/stack-reads.js.map +1 -0
- package/dist/stack.d.ts +37 -643
- package/dist/stack.d.ts.map +1 -1
- package/dist/stack.js +102 -2254
- package/dist/stack.js.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +3 -1
- package/dist/testing.js.map +1 -1
- package/dist/types.d.ts +16 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/dist/wire-entry.d.ts +3 -2
- package/dist/wire-entry.d.ts.map +1 -1
- package/dist/wire-entry.js +6 -2
- package/dist/wire-entry.js.map +1 -1
- package/dist/wire-record.js +1 -1
- package/dist/wire-record.js.map +1 -1
- package/dist/wire-request.d.ts +14 -0
- package/dist/wire-request.d.ts.map +1 -1
- package/dist/wire-request.js +19 -2
- package/dist/wire-request.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EACV,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,EACZ,MAAM,YAAY,CAAC;AAGpB;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,WAAW,CAA0B,CAAC;AAEjF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,WAAW,EAAE,SAAS,WAAW,EAAE,CAK3E,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAIrF;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAAC;AAElE,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAYtF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAgB7D;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,CAAC,EAAE,YAAY,EACf,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE;IACJ,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC,CAAC;IAC1C,aAAa,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC9D,GACA,OAAO,CAAC,OAAO,CAAC,CAiBlB;AA+BD;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAIvD,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,WAAW,CAAC,GAC7C,OAAO,CAAC,WAAW,EAAE,CAAC,CAExB"}
|
package/dist/grants.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grant vocabulary and coverage
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* What a `_grant` Record says, and who it says it about. The coverage
|
|
5
|
+
* question — does this grant reach this grantee — is answered here rather
|
|
6
|
+
* than at each call site so that the access checks and listGrants() cannot
|
|
7
|
+
* drift apart about it.
|
|
8
|
+
*
|
|
9
|
+
* See docs/spec/access-control.md § Type-level grants.
|
|
10
|
+
*/
|
|
11
|
+
import { baseIdOf } from './schema.js';
|
|
12
|
+
import { StackQueryError } from './errors.js';
|
|
13
|
+
import { SYSTEM_TYPES, GRANT_ACTIONS } from './types.js';
|
|
14
|
+
import { groupRoleFromAssociations } from './access.js';
|
|
15
|
+
import { queryAllPages } from './stack-reads.js';
|
|
16
|
+
/**
|
|
17
|
+
* Valid GrantAction values, for runtime validation in Stack.grant().
|
|
18
|
+
* Built from GRANT_ACTIONS (types.ts), the source of truth GrantAction is
|
|
19
|
+
* itself derived from — so this can't drift from the type.
|
|
20
|
+
*/
|
|
21
|
+
export const GRANT_ACTION_SET = new Set(GRANT_ACTIONS);
|
|
22
|
+
/**
|
|
23
|
+
* The read actions that make a mutate action coherent, scope for scope: a
|
|
24
|
+
* `-any` verb needs read over the same reach it can mutate, a `-own` verb
|
|
25
|
+
* needs read over its author's own. A grant carrying neither conveys the
|
|
26
|
+
* verb to nobody. `create` has no companion — writing a Record you then
|
|
27
|
+
* cannot read is the drop-box, and it discloses nothing.
|
|
28
|
+
* See docs/spec/access-control.md § Write implies read.
|
|
29
|
+
*/
|
|
30
|
+
export const READ_COMPANIONS = new Map([
|
|
31
|
+
['update-own', ['read-own', 'read-any']],
|
|
32
|
+
['delete-own', ['read-own', 'read-any']],
|
|
33
|
+
['update-any', ['read-any']],
|
|
34
|
+
['delete-any', ['read-any']],
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Whether one grant's action list conveys `action`. The companion has to
|
|
38
|
+
* sit in the same `_grant` Record, not merely somewhere in the grantee's
|
|
39
|
+
* set: a grant is revoked whole, so a rule satisfied across two records
|
|
40
|
+
* would let revoking the read one leave a mutate-without-read grant
|
|
41
|
+
* standing — the configuration this rule exists to refuse, arrived at
|
|
42
|
+
* without anyone writing it.
|
|
43
|
+
*/
|
|
44
|
+
export function grantConveys(actions, action) {
|
|
45
|
+
if (!actions.includes(action))
|
|
46
|
+
return false;
|
|
47
|
+
const companions = READ_COMPANIONS.get(action);
|
|
48
|
+
return !companions || companions.some((c) => actions.includes(c));
|
|
49
|
+
}
|
|
50
|
+
/** Direct (non-roster) match between a stored _grant's content and a GrantTarget. */
|
|
51
|
+
export function matchesGrantTarget(content, target) {
|
|
52
|
+
if (target !== null && typeof target === 'object') {
|
|
53
|
+
// Guarded so an absent groupId can't match the absent granteeGroupId on
|
|
54
|
+
// every entity-targeted and default grant — `undefined === undefined`
|
|
55
|
+
// would otherwise sweep them all into a revoke aimed at one group.
|
|
56
|
+
if (!target.groupId)
|
|
57
|
+
return false;
|
|
58
|
+
return content.granteeGroupId === target.groupId;
|
|
59
|
+
}
|
|
60
|
+
if (target === null) {
|
|
61
|
+
return !content.granteeEntityId && !content.granteeGroupId;
|
|
62
|
+
}
|
|
63
|
+
return content.granteeEntityId === target;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Reject a grant target that names nobody. An empty groupId or entityId is
|
|
67
|
+
* falsy, so a stored record carrying one reads as a *default* grant — every
|
|
68
|
+
* authenticated entity — instead of the target the caller meant. `null` is
|
|
69
|
+
* the only way to say "default".
|
|
70
|
+
*/
|
|
71
|
+
export function validateGrantTarget(target) {
|
|
72
|
+
if (target === null)
|
|
73
|
+
return;
|
|
74
|
+
if (typeof target === 'string') {
|
|
75
|
+
if (target.length === 0) {
|
|
76
|
+
throw new StackQueryError('A grant target entityId cannot be empty. Pass null for a default grant.');
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (typeof target.groupId !== 'string' || target.groupId.length === 0) {
|
|
81
|
+
throw new StackQueryError('A group grant target requires a non-empty groupId.');
|
|
82
|
+
}
|
|
83
|
+
// Not a format check: granteeGroupId is a reference to an existing
|
|
84
|
+
// Record, like parentId or an association's recordId, and none of those
|
|
85
|
+
// are parsed either. One that resolves to nothing simply denies.
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether a stored _grant covers `grantee`: a direct DID match, roster
|
|
89
|
+
* membership when `allowGroup`, or a default when `allowDefault`. Presence
|
|
90
|
+
* decides the tier, never truthiness — an empty grantee field names nobody.
|
|
91
|
+
* Module-level so the access checks and listGrants() cannot drift apart.
|
|
92
|
+
* See docs/spec/access-control.md § Type-level grants.
|
|
93
|
+
*/
|
|
94
|
+
export async function grantCoversGrantee(c, grantee, opts) {
|
|
95
|
+
const namesEntity = c.granteeEntityId !== undefined;
|
|
96
|
+
const namesGroup = c.granteeGroupId !== undefined;
|
|
97
|
+
if (!namesEntity && !namesGroup)
|
|
98
|
+
return opts.allowDefault;
|
|
99
|
+
if (namesEntity && c.granteeEntityId !== grantee)
|
|
100
|
+
return false;
|
|
101
|
+
if (namesGroup) {
|
|
102
|
+
if (!opts.allowGroup)
|
|
103
|
+
return false;
|
|
104
|
+
if (!c.granteeGroupId)
|
|
105
|
+
return false;
|
|
106
|
+
const role = await resolveGroupRoleMemoized(c.granteeGroupId, grantee, opts.groupRoles, opts.resolveRecord);
|
|
107
|
+
if (role === null)
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* An entity's role on a `_group` roster, memoized in the caller's
|
|
114
|
+
* `groupRoles` map. That map is built per operation and threaded alongside
|
|
115
|
+
* `prefetchedGrants`, so no resolved role outlives the operation that
|
|
116
|
+
* resolved it — removal from a group must never go stale.
|
|
117
|
+
* See docs/spec/access-control.md § Type-level grants.
|
|
118
|
+
*/
|
|
119
|
+
async function resolveGroupRoleMemoized(groupId, entityId, groupRoles, resolveRecord) {
|
|
120
|
+
const key = `${groupId}:${entityId}`;
|
|
121
|
+
const cached = groupRoles.get(key);
|
|
122
|
+
if (cached !== undefined)
|
|
123
|
+
return cached;
|
|
124
|
+
const group = await resolveRecord(groupId);
|
|
125
|
+
// Only a real `_group` Record carries a roster. Without the family check
|
|
126
|
+
// any Record's relationship associations would serve as one, and a group
|
|
127
|
+
// migrated out of the family would keep resolving after it had stopped
|
|
128
|
+
// being a group.
|
|
129
|
+
const role = group && baseIdOf(group.typeId) === SYSTEM_TYPES.GROUP
|
|
130
|
+
? groupRoleFromAssociations(group.associations, entityId)
|
|
131
|
+
: null;
|
|
132
|
+
groupRoles.set(key, role);
|
|
133
|
+
return role;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* System type families grant() refuses to target: a grant on any of them
|
|
137
|
+
* would let the grantee mint their own grants, touch stack config, or
|
|
138
|
+
* register an app card claiming a DID that isn't theirs — the last of
|
|
139
|
+
* which is what verified app attribution rests on. See
|
|
140
|
+
* docs/spec/access-control.md § Type-level grants.
|
|
141
|
+
*/
|
|
142
|
+
export const UNGRANTABLE_SYSTEM_TYPES = new Set([
|
|
143
|
+
SYSTEM_TYPES.GRANT,
|
|
144
|
+
SYSTEM_TYPES.CONFIG,
|
|
145
|
+
SYSTEM_TYPES.APP,
|
|
146
|
+
]);
|
|
147
|
+
/**
|
|
148
|
+
* Every `_grant` Record, cursor-walked. Read through an unscoped query at
|
|
149
|
+
* every call site: a grant is what decides who may read, so it can never
|
|
150
|
+
* itself sit behind a read check. No content prefilter — a stored grant's
|
|
151
|
+
* typeId may be a bare baseId or versioned, so exact matching would wrongly
|
|
152
|
+
* exclude family versions.
|
|
153
|
+
*/
|
|
154
|
+
export function loadGrantRecords(query) {
|
|
155
|
+
return queryAllPages(query, { filter: { typeId: `${SYSTEM_TYPES.GRANT}@1` } });
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=grants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grants.js","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"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"}
|
package/dist/id.d.ts
CHANGED
|
@@ -15,9 +15,6 @@ export declare const RAND_SUFFIX_LENGTH = 3;
|
|
|
15
15
|
export declare class IdGenerationError extends Error {
|
|
16
16
|
constructor(message?: string);
|
|
17
17
|
}
|
|
18
|
-
export declare class IdGenerationOverflowError extends IdGenerationError {
|
|
19
|
-
constructor(message?: string);
|
|
20
|
-
}
|
|
21
18
|
export declare const crockford32Encode: (n: number) => string;
|
|
22
19
|
export declare const crockford32Decode: (s: string) => number;
|
|
23
20
|
export declare const _setLastNowId: (chars: string) => void;
|
|
@@ -39,8 +36,13 @@ export declare const MAX_ID_TIMESTAMP: number;
|
|
|
39
36
|
/**
|
|
40
37
|
* Generate a new Stack record ID. Time-sortable: lexicographic order
|
|
41
38
|
* matches creation order, with same-millisecond IDs monotonically
|
|
42
|
-
* incremented.
|
|
43
|
-
*
|
|
39
|
+
* incremented.
|
|
40
|
+
*
|
|
41
|
+
* A millisecond whose suffix space is spent carries into the next one
|
|
42
|
+
* rather than failing, so how many IDs a millisecond holds never depends
|
|
43
|
+
* on where its random suffix happened to start — which is what keeps the
|
|
44
|
+
* order total and the call free of a capacity a caller cannot see.
|
|
45
|
+
* See docs/spec/data-model.md § Record IDs.
|
|
44
46
|
*
|
|
45
47
|
* @param timestamp - Override the timestamp (ms since epoch). Defaults to Date.now().
|
|
46
48
|
*/
|
package/dist/id.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,eAAO,MAAM,IAAI,QAAoB,CAAC;AAGtC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAcpC,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,SAAK;CAIzB;
|
|
1
|
+
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,eAAO,MAAM,IAAI,QAAoB,CAAC;AAGtC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAcpC,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,SAAK;CAIzB;AAMD,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,KAAG,MAiB7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,KAAG,MAe7C,CAAC;AAkCF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,IAK7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,IAKjD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,KAAG,IAErD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,aAAa,QAAO,IAIhC,CAAC;AAMF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,QAA2C,CAAC;AAEzE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,GAAI,YAAW,MAAmB,KAAG,MAgB3D,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAAI,WAAW,MAAM,KAAG,MAS1D,CAAC;AASF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,KAAG,OAA6B,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,KAAG,MACa,CAAC"}
|
package/dist/id.js
CHANGED
|
@@ -30,12 +30,6 @@ export class IdGenerationError extends Error {
|
|
|
30
30
|
this.name = 'IdGenerationError';
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
export class IdGenerationOverflowError extends IdGenerationError {
|
|
34
|
-
constructor(message = '') {
|
|
35
|
-
super(message || 'Too many IDs have been generated in the same millisecond.');
|
|
36
|
-
this.name = 'IdGenerationOverflowError';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
33
|
// -------------------------------------------------------
|
|
40
34
|
// Encoding / decoding
|
|
41
35
|
// -------------------------------------------------------
|
|
@@ -88,12 +82,10 @@ const generateRandChars = () => {
|
|
|
88
82
|
} while (value > Math.floor(0xffffffff / modulus) * modulus);
|
|
89
83
|
return pad(crockford32Encode(value % modulus), RAND_SUFFIX_LENGTH);
|
|
90
84
|
};
|
|
85
|
+
/** The next suffix after `randChars`, or null once the space is spent. */
|
|
91
86
|
const incrementRandChars = (randChars) => {
|
|
92
87
|
const next = crockford32Encode(crockford32Decode(randChars) + 1);
|
|
93
|
-
|
|
94
|
-
throw new IdGenerationOverflowError();
|
|
95
|
-
}
|
|
96
|
-
return pad(next, RAND_SUFFIX_LENGTH);
|
|
88
|
+
return next.length > RAND_SUFFIX_LENGTH ? null : pad(next, RAND_SUFFIX_LENGTH);
|
|
97
89
|
};
|
|
98
90
|
// -------------------------------------------------------
|
|
99
91
|
// Test hooks (package-private)
|
|
@@ -136,15 +128,25 @@ export const MAX_ID_TIMESTAMP = Math.pow(BASE, MIN_TIMESTAMP_LENGTH) - 1;
|
|
|
136
128
|
/**
|
|
137
129
|
* Generate a new Stack record ID. Time-sortable: lexicographic order
|
|
138
130
|
* matches creation order, with same-millisecond IDs monotonically
|
|
139
|
-
* incremented.
|
|
140
|
-
*
|
|
131
|
+
* incremented.
|
|
132
|
+
*
|
|
133
|
+
* A millisecond whose suffix space is spent carries into the next one
|
|
134
|
+
* rather than failing, so how many IDs a millisecond holds never depends
|
|
135
|
+
* on where its random suffix happened to start — which is what keeps the
|
|
136
|
+
* order total and the call free of a capacity a caller cannot see.
|
|
137
|
+
* See docs/spec/data-model.md § Record IDs.
|
|
141
138
|
*
|
|
142
139
|
* @param timestamp - Override the timestamp (ms since epoch). Defaults to Date.now().
|
|
143
140
|
*/
|
|
144
141
|
export const generateId = (timestamp = Date.now()) => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
let effectiveTimestamp = Math.max(timestamp, lastTimestamp);
|
|
143
|
+
let nowId = pad(crockford32Encode(effectiveTimestamp), MIN_TIMESTAMP_LENGTH);
|
|
144
|
+
let randChars = nowId === lastNowId ? incrementRandChars(lastRandChars) : generateRandChars();
|
|
145
|
+
if (randChars === null) {
|
|
146
|
+
effectiveTimestamp += 1;
|
|
147
|
+
nowId = pad(crockford32Encode(effectiveTimestamp), MIN_TIMESTAMP_LENGTH);
|
|
148
|
+
randChars = generateRandChars();
|
|
149
|
+
}
|
|
148
150
|
lastTimestamp = effectiveTimestamp;
|
|
149
151
|
lastNowId = nowId;
|
|
150
152
|
lastRandChars = randChars;
|
package/dist/id.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,UAAU,GAAG,kCAAkC,CAAC;AAEtD,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC;AAEtC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,kEAAkE;AAClE,IAAI,SAAS,GAAG,EAAE,CAAC;AACnB,IAAI,aAAa,GAAG,EAAE,CAAC;AACvB,wEAAwE;AACxE,uEAAuE;AACvE,uDAAuD;AACvD,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB,0DAA0D;AAC1D,SAAS;AACT,0DAA0D;AAE1D,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAO,GAAG,EAAE;QACtB,KAAK,CAAC,OAAO,IAAI,+BAA+B,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DID bindings
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* Which content fields are lookup keys rather than display values, and
|
|
5
|
+
* which of those a stack resolves *by*. Every one is immutable once set;
|
|
6
|
+
* the unique subset is additionally one-per-stack, because a lookup with
|
|
7
|
+
* two answers is all an impersonating card needs.
|
|
8
|
+
*
|
|
9
|
+
* See docs/spec/identity.md § DID bindings.
|
|
10
|
+
*/
|
|
11
|
+
export declare const bindingFieldsOf: (family: string) => readonly ("did" | "appId")[];
|
|
12
|
+
export declare const uniqueBindingFieldsOf: (family: string) => readonly ("did" | "appId")[];
|
|
13
|
+
//# sourceMappingURL=identity-bindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-bindings.d.ts","sourceRoot":"","sources":["../src/identity-bindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkCH,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,KAAG,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,EACzC,CAAC;AAEnC,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,KAAG,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,EACxC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DID bindings
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* Which content fields are lookup keys rather than display values, and
|
|
5
|
+
* which of those a stack resolves *by*. Every one is immutable once set;
|
|
6
|
+
* the unique subset is additionally one-per-stack, because a lookup with
|
|
7
|
+
* two answers is all an impersonating card needs.
|
|
8
|
+
*
|
|
9
|
+
* See docs/spec/identity.md § DID bindings.
|
|
10
|
+
*/
|
|
11
|
+
import { SYSTEM_TYPES } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Content fields that are lookup keys rather than display values: a card
|
|
14
|
+
* claims one, and something later resolves through it. Every one of them is
|
|
15
|
+
* immutable once set. See docs/spec/identity.md § DID bindings.
|
|
16
|
+
*/
|
|
17
|
+
const BINDING_FIELDS = new Map([
|
|
18
|
+
[SYSTEM_TYPES.APP, ['did', 'appId']],
|
|
19
|
+
[SYSTEM_TYPES.ENTITY, ['did']],
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* The subset that is additionally unique per stack: the fields something
|
|
23
|
+
* resolves *by*. A Record's `principalId` finds its card by `_app.did` and
|
|
24
|
+
* its `entityId` by `_entity.did`, so a second card claiming either leaves
|
|
25
|
+
* that lookup without a single answer — and ambiguity is all an
|
|
26
|
+
* impersonating card needs.
|
|
27
|
+
*
|
|
28
|
+
* `_app.appId` is deliberately absent. Nothing resolves a card by it — the
|
|
29
|
+
* cross-check reaches the card by `did` and only compares `appId` — so
|
|
30
|
+
* uniqueness would buy no disambiguation, while forbidding the second card
|
|
31
|
+
* key rotation is supposed to produce: `appId` is required, so a
|
|
32
|
+
* replacement card for the same software necessarily repeats it. Moving one
|
|
33
|
+
* card onto another's `appId` is what immutability already refuses.
|
|
34
|
+
* See docs/spec/identity.md § DID bindings.
|
|
35
|
+
*/
|
|
36
|
+
const UNIQUE_BINDING_FIELDS = new Map([
|
|
37
|
+
[SYSTEM_TYPES.APP, ['did']],
|
|
38
|
+
[SYSTEM_TYPES.ENTITY, ['did']],
|
|
39
|
+
]);
|
|
40
|
+
export const bindingFieldsOf = (family) => BINDING_FIELDS.get(family) ?? [];
|
|
41
|
+
export const uniqueBindingFieldsOf = (family) => UNIQUE_BINDING_FIELDS.get(family) ?? [];
|
|
42
|
+
//# sourceMappingURL=identity-bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-bindings.js","sourceRoot":"","sources":["../src/identity-bindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;GAIG;AACH,MAAM,cAAc,GAAsD,IAAI,GAAG,CAAC;IAChF,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,CAAU,CAAC;IAC7C,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,KAAK,CAAU,CAAC;CACxC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,qBAAqB,GAAsD,IAAI,GAAG,CAAC;IACvF,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,KAAK,CAAU,CAAC;IACpC,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,KAAK,CAAU,CAAC;CACxC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAgC,EAAE,CAC9E,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;AAEnC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAc,EAAgC,EAAE,CACpF,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
* Storage adapters are published as separate packages:
|
|
15
15
|
* @haverstack/adapter-sqlite
|
|
16
16
|
*/
|
|
17
|
-
export { Stack
|
|
18
|
-
export
|
|
19
|
-
export type {
|
|
20
|
-
export {
|
|
17
|
+
export { Stack } from './stack.js';
|
|
18
|
+
export { ScopedStack } from './scoped-stack.js';
|
|
19
|
+
export type { StackClient, CreateRecordOptions, BackdatableCreateRecordOptions, StackOptions, GetRecordOptions, DeleteRecordOptions, IfVersionOptions, CollectAttachmentGarbageOptions, CollectAttachmentGarbageResult, } from './stack.js';
|
|
20
|
+
export { StackError, StackValidationError, StackMigrationError, StackPermissionError, StackNotFoundError, StackConflictError, StackVersionConflictError, StackQueryError, StackSchemaDriftError, StackPayloadTooLargeError, StackTimeoutError, StackClosedError, StackRelayScopeError, } from './errors.js';
|
|
21
|
+
export type { StackErrorCode } from './errors.js';
|
|
22
|
+
export type { RecordId, TypeId, FileId, EntityId, AttachmentContent, StackRecord, RecordChanges, RecordVersion, ActorOptions, ChangeKind, ChangeOp, ChangeActor, RecordChange, ChangeFilter, SubscribeOptions, Unsubscribe, ExpectedVersionOptions, SnapshotOptions, StackType, TypeSchema, FieldDef, ScalarFieldDef, ArrayFieldDef, ObjectFieldDef, ScalarFieldKind, Association, TagAssociation, AttachmentAssociation, RelationshipAssociation, RelationshipTarget, RecordTarget, EntityTarget, ExternalTarget, Permission, StackQuery, RecordFilter, RelatedToFilter, RelationshipTargetPattern, QuerySort, NativeSortField, ContentFilterReach, MissingCapability, QueryResult, DateRange, Migration, MigrationFn, StackAdapter, StackFeatures, TokenSession, EntityContent, AppContent, GroupContent, GrantAction, GrantContent, ConfigContent, } from './types.js';
|
|
23
|
+
export { SYSTEM_TYPES, NATIVE_SORT_FIELDS } from './types.js';
|
|
21
24
|
export { generateId } from './id.js';
|
|
22
25
|
export { hashSchema, isCompatible } from './schema.js';
|
|
23
26
|
export type { SchemaDriftViolation } from './schema.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,WAAW,EACX,mBAAmB,EACnB,8BAA8B,EAC9B,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,eAAe,EACf,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,YAAY,EACV,QAAQ,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,sBAAsB,EACtB,eAAe,EACf,SAAS,EACT,UAAU,EACV,QAAQ,EACR,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EACf,WAAW,EACX,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,UAAU,EACV,UAAU,EACV,YAAY,EACZ,eAAe,EACf,yBAAyB,EACzB,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,aAAa,EACb,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAM9D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,8 +15,11 @@
|
|
|
15
15
|
* @haverstack/adapter-sqlite
|
|
16
16
|
*/
|
|
17
17
|
// Core class and client interface
|
|
18
|
-
export { Stack
|
|
19
|
-
export {
|
|
18
|
+
export { Stack } from './stack.js';
|
|
19
|
+
export { ScopedStack } from './scoped-stack.js';
|
|
20
|
+
// The error taxonomy
|
|
21
|
+
export { StackError, StackValidationError, StackMigrationError, StackPermissionError, StackNotFoundError, StackConflictError, StackVersionConflictError, StackQueryError, StackSchemaDriftError, StackPayloadTooLargeError, StackTimeoutError, StackClosedError, StackRelayScopeError, } from './errors.js';
|
|
22
|
+
export { SYSTEM_TYPES, NATIVE_SORT_FIELDS } from './types.js';
|
|
20
23
|
// Utilities
|
|
21
24
|
// No in-repo caller: client-minted IDs are the default per spec, and an app
|
|
22
25
|
// needing the ID before the write round-trips has to mint one itself.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,kCAAkC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,kCAAkC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAahD,qBAAqB;AACrB,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,eAAe,EACf,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AA8DrB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE9D,YAAY;AAEZ,4EAA4E;AAC5E,sEAAsE;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/limits.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared-ceiling pre-checks
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* Client-side guards against an adapter's declared `limits`. Local
|
|
5
|
+
* adapters declare `null` and skip them entirely; only a server names a
|
|
6
|
+
* ceiling, and its own request-size limit stays authoritative — these just
|
|
7
|
+
* spare an app the round trip and give it a typed failure instead of a 413
|
|
8
|
+
* it has to interpret.
|
|
9
|
+
*
|
|
10
|
+
* See docs/spec/wire-format.md § Request size limits.
|
|
11
|
+
*/
|
|
12
|
+
/** Shared by Stack.putAttachment() and ScopedStack.putAttachment(). */
|
|
13
|
+
export declare function assertAttachmentSize(byteLength: number, attachmentBytes: number | null): void;
|
|
14
|
+
/**
|
|
15
|
+
* The content half of the same pre-check, on Stack.create() and
|
|
16
|
+
* Stack.mutate(). Local adapters declare `limits.contentBytes: null` and skip
|
|
17
|
+
* the serialization entirely; only a server declares a ceiling, and its
|
|
18
|
+
* own request-size limit stays authoritative — this just spares an app the
|
|
19
|
+
* round trip and gives it a typed failure instead of a 413 it has to
|
|
20
|
+
* interpret. See docs/spec/wire-format.md § Request size limits.
|
|
21
|
+
*/
|
|
22
|
+
export declare function assertContentSize(content: Record<string, unknown>, contentBytes: number | null, what: 'Content' | 'Patch'): void;
|
|
23
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAM7F;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,IAAI,EAAE,SAAS,GAAG,OAAO,GACxB,IAAI,CAQN"}
|
package/dist/limits.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared-ceiling pre-checks
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* Client-side guards against an adapter's declared `limits`. Local
|
|
5
|
+
* adapters declare `null` and skip them entirely; only a server names a
|
|
6
|
+
* ceiling, and its own request-size limit stays authoritative — these just
|
|
7
|
+
* spare an app the round trip and give it a typed failure instead of a 413
|
|
8
|
+
* it has to interpret.
|
|
9
|
+
*
|
|
10
|
+
* See docs/spec/wire-format.md § Request size limits.
|
|
11
|
+
*/
|
|
12
|
+
import { StackPayloadTooLargeError } from './errors.js';
|
|
13
|
+
/** Shared by Stack.putAttachment() and ScopedStack.putAttachment(). */
|
|
14
|
+
export function assertAttachmentSize(byteLength, attachmentBytes) {
|
|
15
|
+
if (attachmentBytes !== null && byteLength > attachmentBytes) {
|
|
16
|
+
throw new StackPayloadTooLargeError(`Attachment (${byteLength} bytes) exceeds the ${attachmentBytes}-byte limit.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The content half of the same pre-check, on Stack.create() and
|
|
21
|
+
* Stack.mutate(). Local adapters declare `limits.contentBytes: null` and skip
|
|
22
|
+
* the serialization entirely; only a server declares a ceiling, and its
|
|
23
|
+
* own request-size limit stays authoritative — this just spares an app the
|
|
24
|
+
* round trip and gives it a typed failure instead of a 413 it has to
|
|
25
|
+
* interpret. See docs/spec/wire-format.md § Request size limits.
|
|
26
|
+
*/
|
|
27
|
+
export function assertContentSize(content, contentBytes, what) {
|
|
28
|
+
if (contentBytes === null)
|
|
29
|
+
return;
|
|
30
|
+
const byteLength = new TextEncoder().encode(JSON.stringify(content)).length;
|
|
31
|
+
if (byteLength > contentBytes) {
|
|
32
|
+
throw new StackPayloadTooLargeError(`${what} (${byteLength} bytes) exceeds the ${contentBytes}-byte limit.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAExD,uEAAuE;AACvE,MAAM,UAAU,oBAAoB,CAAC,UAAkB,EAAE,eAA8B;IACrF,IAAI,eAAe,KAAK,IAAI,IAAI,UAAU,GAAG,eAAe,EAAE,CAAC;QAC7D,MAAM,IAAI,yBAAyB,CACjC,eAAe,UAAU,uBAAuB,eAAe,cAAc,CAC9E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAgC,EAChC,YAA2B,EAC3B,IAAyB;IAEzB,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO;IAClC,MAAM,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5E,IAAI,UAAU,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,IAAI,yBAAyB,CACjC,GAAG,IAAI,KAAK,UAAU,uBAAuB,YAAY,cAAc,CACxE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query and association validation
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* The sanitizers a query passes through before any adapter sees it, plus
|
|
5
|
+
* the relationship-target rules an association is held to. Both sides of
|
|
6
|
+
* the same job: a discriminated union and a `QuerySort` field are compile-
|
|
7
|
+
* time promises, and a server mapping a request body onto either supplies
|
|
8
|
+
* raw JSON that no compiler has seen.
|
|
9
|
+
*
|
|
10
|
+
* These live in the invariant layer for the reason validation and
|
|
11
|
+
* `_config` protection do — so no adapter can forget one. `assertQueryCapabilities`
|
|
12
|
+
* and its neighbours are shared verbatim with `adapter-api`, which asks the
|
|
13
|
+
* same questions of a request arriving over the wire. A refusal names the
|
|
14
|
+
* capability it was refused for on the error itself, so a client reporting
|
|
15
|
+
* it in its own vocabulary reads that name rather than re-deriving it from
|
|
16
|
+
* the query — one rule, one answer.
|
|
17
|
+
* See docs/spec/data-model.md § Capability-gated filters.
|
|
18
|
+
*/
|
|
19
|
+
import type { ValidationError } from './validate.js';
|
|
20
|
+
import type { Association, QuerySort, RecordFilter, StackFeatures } from './types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Fail loud rather than silently widen: a filter the adapter can't honor
|
|
23
|
+
* would otherwise be dropped, returning an unfiltered superset presented
|
|
24
|
+
* as the filtered result. Shared by Stack.query() and
|
|
25
|
+
* APIAdapter.queryRecords(). See docs/spec/data-model.md
|
|
26
|
+
* § Capability-gated filters.
|
|
27
|
+
*/
|
|
28
|
+
export declare function assertQueryCapabilities(filter: RecordFilter | undefined, capabilities: Pick<StackFeatures, 'filter'>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Whether a single-segment content filter can be pushed down to the
|
|
31
|
+
* adapter. Callers that read a content field pair this with an in-memory
|
|
32
|
+
* predicate over the wider result, so the query stays correct against an
|
|
33
|
+
* adapter that reaches no content at all — the rung comparison lives here
|
|
34
|
+
* rather than at each of them.
|
|
35
|
+
*/
|
|
36
|
+
export declare function filtersContent(features: Pick<StackFeatures, 'filter'>): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Split a content filter key into path segments. Write-time validation
|
|
39
|
+
* keeps stored field names free of the path metacharacters, but a filter
|
|
40
|
+
* arrives from a request body and has made no such promise, so the same
|
|
41
|
+
* rule is enforced here. See docs/spec/data-model.md § Content field names.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseContentFilterKey(key: string): string[];
|
|
44
|
+
/**
|
|
45
|
+
* Reject a sort whose field or direction is outside the closed set the
|
|
46
|
+
* types promise. `QuerySort` is typed `'asc' | 'desc'`, but a type is not a
|
|
47
|
+
* runtime guard: a server mapping `?direction=` onto a query, or a
|
|
48
|
+
* delegated app calling query(), supplies a raw string. A SQLite record
|
|
49
|
+
* adapter interpolates the direction straight into `ORDER BY`, so an
|
|
50
|
+
* unvalidated value there is a SQL-injection sink reachable from every
|
|
51
|
+
* untrusted caller. Validating in the invariant layer — the same reason
|
|
52
|
+
* emission and _config protection live here — means no adapter can forget
|
|
53
|
+
* it. See docs/spec/data-model.md § Sorting and pagination.
|
|
54
|
+
*/
|
|
55
|
+
export declare function assertValidSort(sort: QuerySort | undefined): void;
|
|
56
|
+
/**
|
|
57
|
+
* Fail loud rather than silently reorder: an adapter that can't honor the
|
|
58
|
+
* requested sort would otherwise answer in some other order, which a
|
|
59
|
+
* caller paging a bounded window has no way to notice. The companion to
|
|
60
|
+
* assertQueryCapabilities(), split from it because a sort is not a filter
|
|
61
|
+
* — see docs/spec/data-model.md § Capability-gated filters.
|
|
62
|
+
*/
|
|
63
|
+
export declare function assertSortCapability(sort: QuerySort | undefined, capabilities: Pick<StackFeatures, 'sort'>): void;
|
|
64
|
+
/**
|
|
65
|
+
* Reject a relationship target outside the closed set the types promise.
|
|
66
|
+
* A discriminated union is not a runtime guard — a server mapping a
|
|
67
|
+
* request body onto an association supplies raw JSON — and an
|
|
68
|
+
* unrecognized scope would otherwise be stored under the one arm that
|
|
69
|
+
* names a Record in this stack. See docs/spec/data-model.md
|
|
70
|
+
* § Relationship targets.
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateAssociation(association: Association, path?: string): ValidationError[];
|
|
73
|
+
/** validateAssociation() over a create's `associations` array. */
|
|
74
|
+
export declare function validateAssociations(associations: Association[] | undefined, path?: string): ValidationError[];
|
|
75
|
+
/**
|
|
76
|
+
* Reject a relationship filter that names neither a label nor a target,
|
|
77
|
+
* or whose target is malformed. `RelatedToFilter` promises one half is
|
|
78
|
+
* always present; without the runtime check a filter decoded from a
|
|
79
|
+
* request could arrive empty and match every record carrying any
|
|
80
|
+
* relationship. See docs/spec/data-model.md § Filter.
|
|
81
|
+
*/
|
|
82
|
+
export declare function assertValidRelatedTo(relatedTo: RecordFilter['relatedTo']): void;
|
|
83
|
+
//# sourceMappingURL=query-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-validation.d.ts","sourceRoot":"","sources":["../src/query-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,YAAY,EAGZ,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,GAAG,SAAS,EAChC,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,GAC1C,IAAI,CAmCN;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,GAAG,OAAO,CAE/E;AAKD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAwB3D;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CA2BjE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,GAAG,SAAS,EAC3B,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GACxC,IAAI,CAmBN;AA0CD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,EACxB,IAAI,SAAgB,GACnB,eAAe,EAAE,CAGnB;AAED,kEAAkE;AAClE,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,WAAW,EAAE,GAAG,SAAS,EACvC,IAAI,SAAiB,GACpB,eAAe,EAAE,CAEnB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAY/E"}
|