@astram/guard 0.5.0 → 0.6.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 (64) hide show
  1. package/dist/auth/account.controller.d.ts.map +1 -1
  2. package/dist/auth/account.controller.js +3 -0
  3. package/dist/auth/auth.controller.d.ts +90 -1
  4. package/dist/auth/auth.controller.d.ts.map +1 -1
  5. package/dist/auth/auth.controller.js +245 -7
  6. package/dist/auth/auth.module.d.ts +21 -0
  7. package/dist/auth/auth.module.d.ts.map +1 -1
  8. package/dist/auth/auth.module.js +28 -0
  9. package/dist/auth/dto.d.ts +32 -0
  10. package/dist/auth/dto.d.ts.map +1 -1
  11. package/dist/auth/ports/membership-checker.d.ts +41 -0
  12. package/dist/auth/ports/membership-checker.d.ts.map +1 -0
  13. package/dist/auth/ports/membership-checker.js +32 -0
  14. package/dist/auth/ports/scope-subtree-resolver.d.ts +48 -0
  15. package/dist/auth/ports/scope-subtree-resolver.d.ts.map +1 -0
  16. package/dist/auth/ports/scope-subtree-resolver.js +38 -0
  17. package/dist/auth/tokens.d.ts +25 -0
  18. package/dist/auth/tokens.d.ts.map +1 -1
  19. package/dist/auth/tokens.js +26 -1
  20. package/dist/authentication/mariadb-profile-writer.d.ts.map +1 -1
  21. package/dist/authentication/mariadb-profile-writer.js +10 -1
  22. package/dist/authz/list-scope-sql.d.ts +125 -0
  23. package/dist/authz/list-scope-sql.d.ts.map +1 -0
  24. package/dist/authz/list-scope-sql.js +477 -0
  25. package/dist/authz/mariadb-cross-tenant-grant-adapter.d.ts +28 -0
  26. package/dist/authz/mariadb-cross-tenant-grant-adapter.d.ts.map +1 -1
  27. package/dist/authz/mariadb-cross-tenant-grant-adapter.js +49 -0
  28. package/dist/authz/mariadb-list-scope-adapter.d.ts +61 -0
  29. package/dist/authz/mariadb-list-scope-adapter.d.ts.map +1 -0
  30. package/dist/authz/mariadb-list-scope-adapter.js +157 -0
  31. package/dist/authz/mariadb-policy-store.d.ts +118 -0
  32. package/dist/authz/mariadb-policy-store.d.ts.map +1 -0
  33. package/dist/authz/mariadb-policy-store.js +225 -0
  34. package/dist/authz/mariadb-record-rule-adapter.d.ts +7 -3
  35. package/dist/authz/mariadb-record-rule-adapter.d.ts.map +1 -1
  36. package/dist/authz/mariadb-record-rule-adapter.js +156 -13
  37. package/dist/authz/record-share-writer.d.ts +22 -0
  38. package/dist/authz/record-share-writer.d.ts.map +1 -1
  39. package/dist/authz/record-share-writer.js +41 -0
  40. package/dist/authz/wire-record-authorization.d.ts +35 -1
  41. package/dist/authz/wire-record-authorization.d.ts.map +1 -1
  42. package/dist/authz/wire-record-authorization.js +75 -0
  43. package/dist/identity/identity-actions.d.ts +7 -0
  44. package/dist/identity/identity-actions.d.ts.map +1 -1
  45. package/dist/identity/identity-actions.js +8 -1
  46. package/dist/index.d.ts +7 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +47 -3
  49. package/dist/module/shield.module.d.ts +33 -0
  50. package/dist/module/shield.module.d.ts.map +1 -1
  51. package/dist/module/shield.module.js +12 -0
  52. package/dist/request-auth/request-principal.d.ts.map +1 -1
  53. package/dist/request-auth/request-principal.js +12 -0
  54. package/dist/request-auth/session-token-binder.d.ts +35 -1
  55. package/dist/request-auth/session-token-binder.d.ts.map +1 -1
  56. package/dist/request-auth/session-token-binder.js +123 -8
  57. package/dist/scope/closure-builder.d.ts +75 -0
  58. package/dist/scope/closure-builder.d.ts.map +1 -0
  59. package/dist/scope/closure-builder.js +134 -0
  60. package/migrations/1710000000009-CreateRecordPermissionRule.cjs +56 -0
  61. package/migrations/1710000000014-CreateRecordShare.cjs +49 -0
  62. package/migrations/1710000000015-CreateScopeClosure.cjs +46 -0
  63. package/migrations/1710000000016-AlterCompanyParentFkRestrict.cjs +71 -0
  64. package/package.json +3 -3
@@ -35,9 +35,13 @@
35
35
  * ── SAFETY: every rule row is matched on `(tenant, type_key, action)` with all values
36
36
  * BOUND as `?` params (no interpolation). The action match is exact OR the rule's
37
37
  * wildcard `*`. Field conditions are evaluated in JS against the record attributes
38
- * core supplies (design §11.1 builder shape) — the operator set is a fixed
39
- * allow-list; an unknown operator makes the rule NOT match (fail-closed, never a
40
- * spurious allow).
38
+ * core supplies (design §11.1 builder shape) — the operator set is the FULL
39
+ * 14-operator {@link import('@astram/core').PolicyOperator} model (unified with
40
+ * the guided policy builder, Task 0.2): `eq/ne` (dual-accept legacy
41
+ * `equals`/`not_equals`), `in/not_in`, `gt/lt/gte/lte`, `contains/not_contains`,
42
+ * `is_null/is_not_null`, `is_owner/is_not_owner`. An unknown operator makes the
43
+ * rule NOT match (fail-closed, never a spurious allow) — see `conditionHolds`
44
+ * below for the exact per-operator semantics and the documented edge-case choices.
41
45
  */
42
46
  Object.defineProperty(exports, "__esModule", { value: true });
43
47
  exports.MariaDbRecordPermissionRuleAdapter = exports.SHIELD_RECORD_RULE_PORT = void 0;
@@ -69,10 +73,76 @@ function resolveValue(raw, input) {
69
73
  function fieldValue(field, input) {
70
74
  return input.attributes?.[field];
71
75
  }
76
+ /** Whether a record attribute value counts as "present" — not absent, not null. */
77
+ function isPresent(value) {
78
+ return value !== undefined && value !== null;
79
+ }
80
+ /**
81
+ * Ordered compare of the record attribute vs. the resolved rule value (for
82
+ * `gt`/`lt`/`gte`/`lte`). RULE (documented, design §Task-0.2): if BOTH sides
83
+ * parse as finite numbers → NUMERIC compare; otherwise → LEXICAL (string)
84
+ * compare. Returns `null` when the attribute is absent/null — the condition
85
+ * does NOT hold for any ordered operator in that case (fail-closed; no
86
+ * comparison against a missing value).
87
+ */
88
+ function orderedCompare(actual, expected) {
89
+ if (!isPresent(actual))
90
+ return null;
91
+ const actualNum = Number(actual);
92
+ const expectedNum = Number(expected);
93
+ const bothNumeric = actual !== '' &&
94
+ expected !== '' &&
95
+ Number.isFinite(actualNum) &&
96
+ Number.isFinite(expectedNum);
97
+ if (bothNumeric) {
98
+ return actualNum < expectedNum ? -1 : actualNum > expectedNum ? 1 : 0;
99
+ }
100
+ const actualStr = String(actual);
101
+ const expectedStr = String(expected);
102
+ return actualStr < expectedStr ? -1 : actualStr > expectedStr ? 1 : 0;
103
+ }
72
104
  /**
73
105
  * Evaluate a rule's field condition. A rule with NO field (`rpr_field` null) is
74
106
  * UNCONDITIONAL (applies whenever subject+action match). The operator set is a fixed
75
- * allow-list; an unknown operator → the condition does NOT hold (fail-closed).
107
+ * allow-list covering the full 14-operator {@link import('@astram/core').PolicyOperator}
108
+ * model — unifying this enforcement path with the guided policy builder. An unknown
109
+ * operator → the condition does NOT hold (fail-closed).
110
+ *
111
+ * ── DUAL-ACCEPT (back-compat): this table may hold either the core canonical
112
+ * operator names (`eq`/`ne`, as the Task-0.3 policy store persists) or the
113
+ * legacy astram3 names (`equals`/`not_equals`) from any pre-existing row —
114
+ * both are accepted and behave identically. `in`/`not_in` are shared by both
115
+ * naming schemes already.
116
+ * ── `in`/`not_in`: comma-separated token-set membership. `in` on an
117
+ * absent/null attribute already does NOT hold (its stringified form is
118
+ * never in a real authored set). `not_in` is the MIRROR of `ne` — an
119
+ * absent/null attribute must NOT be treated as "not in the set" (that
120
+ * would trivially hold via `!set.includes('undefined')` and WIDEN the
121
+ * policy for every record missing the attribute); guarded the same way:
122
+ * does NOT hold unless the attribute is present.
123
+ * ── `eq`/`equals`: absent/null attribute never equals a resolved value (an
124
+ * absent attribute simply is not `===` to anything) — already fail-closed.
125
+ * ── `ne`/`not_equals`: the MIRROR of `eq` — an absent/null attribute must
126
+ * NOT be treated as "not equal" (that would trivially hold via
127
+ * `undefined !== expected` and WIDEN the policy for every record missing
128
+ * the attribute). Guarded symmetrically with every other operator: does
129
+ * NOT hold unless the attribute is present.
130
+ * ── `gt`/`lt`/`gte`/`lte`: numeric compare when both sides parse as finite
131
+ * numbers, else lexical (string) compare. An absent/null attribute never
132
+ * holds for any ordered operator (fail-closed — no comparison against
133
+ * nothing).
134
+ * ── `contains`/`not_contains`: substring match on the string form. An
135
+ * absent/null attribute means the record has no such value to test — the
136
+ * SAFER choice is taken: the condition does NOT hold for EITHER `contains`
137
+ * OR `not_contains` when the attribute is absent (no accidental widen via
138
+ * "it doesn't contain what's missing").
139
+ * ── `is_null`/`is_not_null`: take no operand (the rule's value is ignored);
140
+ * test only whether the attribute is absent/null vs. present-and-non-null.
141
+ * ── `is_owner`/`is_not_owner`: the OWNERSHIP predicate — the field's value
142
+ * (a reference/owner-id attribute) compared to `input.principal.id`; the
143
+ * rule's value operand is ignored. An absent/null OR EMPTY-STRING attribute
144
+ * → does NOT hold for either (fail-closed — no owner to compare, and an
145
+ * empty attribute must never "match" an empty `principal.id`).
76
146
  */
77
147
  function conditionHolds(row, input) {
78
148
  if (row.rpr_field === null)
@@ -81,10 +151,15 @@ function conditionHolds(row, input) {
81
151
  const expectedRaw = row.rpr_value ?? '';
82
152
  const expected = resolveValue(expectedRaw, input);
83
153
  switch (row.rpr_operator) {
154
+ case 'eq':
84
155
  case 'equals':
85
156
  return actual === expected;
157
+ case 'ne':
86
158
  case 'not_equals':
87
- return actual !== expected;
159
+ // absent attribute → does NOT hold (fail-closed; consistent with every
160
+ // other operator — `undefined !== expected` would otherwise be trivially
161
+ // true and WIDEN the policy for every record missing this attribute).
162
+ return isPresent(actual) && actual !== expected;
88
163
  case 'in': {
89
164
  // comma-separated token list; membership by string comparison.
90
165
  const set = String(expectedRaw)
@@ -93,11 +168,50 @@ function conditionHolds(row, input) {
93
168
  return set.includes(String(actual));
94
169
  }
95
170
  case 'not_in': {
171
+ // absent attribute → does NOT hold (fail-closed; consistent with `ne`/
172
+ // `not_contains`/`is_not_owner` — otherwise `!set.includes('undefined')`
173
+ // would trivially hold and WIDEN the policy for every record missing the field).
174
+ if (!isPresent(actual))
175
+ return false;
96
176
  const set = String(expectedRaw)
97
177
  .split(',')
98
178
  .map((s) => s.trim());
99
179
  return !set.includes(String(actual));
100
180
  }
181
+ case 'gt': {
182
+ const cmp = orderedCompare(actual, expected);
183
+ return cmp !== null && cmp > 0;
184
+ }
185
+ case 'gte': {
186
+ const cmp = orderedCompare(actual, expected);
187
+ return cmp !== null && cmp >= 0;
188
+ }
189
+ case 'lt': {
190
+ const cmp = orderedCompare(actual, expected);
191
+ return cmp !== null && cmp < 0;
192
+ }
193
+ case 'lte': {
194
+ const cmp = orderedCompare(actual, expected);
195
+ return cmp !== null && cmp <= 0;
196
+ }
197
+ case 'contains':
198
+ // absent attribute → does NOT hold (no accidental widen).
199
+ return isPresent(actual) && String(actual).includes(String(expected));
200
+ case 'not_contains':
201
+ // absent attribute → does NOT hold either (the safer, non-widening choice).
202
+ return isPresent(actual) && !String(actual).includes(String(expected));
203
+ case 'is_null':
204
+ return !isPresent(actual);
205
+ case 'is_not_null':
206
+ return isPresent(actual);
207
+ case 'is_owner':
208
+ // absent OR empty-string → does NOT hold (fail-closed; an empty attribute
209
+ // must never "match" an empty principal.id).
210
+ return isPresent(actual) && actual !== '' && actual === input.principal.id;
211
+ case 'is_not_owner':
212
+ // absent OR empty-string → does NOT hold (fail-closed; same hardening,
213
+ // mirrored for the negative ownership operator).
214
+ return isPresent(actual) && actual !== '' && actual !== input.principal.id;
101
215
  default:
102
216
  return false; // unknown operator → fail-closed (rule does not apply)
103
217
  }
@@ -119,7 +233,7 @@ class MariaDbRecordPermissionRuleAdapter {
119
233
  const tenantId = input.resource.tenantId ?? input.principal.tenantId;
120
234
  let rows;
121
235
  try {
122
- rows = (await this.db.query(`SELECT rpr_effect, rpr_subject_kind, rpr_subject_value, rpr_field, rpr_operator, rpr_value
236
+ rows = (await this.db.query(`SELECT rpr_policy_uuid, rpr_effect, rpr_subject_kind, rpr_subject_value, rpr_field, rpr_operator, rpr_value
123
237
  FROM \`${this.schema}\`.\`record_permission_rule\`
124
238
  WHERE rpr_type_key = ?
125
239
  AND (rpr_tenant_uuid = ? OR rpr_tenant_uuid IS NULL)
@@ -130,18 +244,47 @@ class MariaDbRecordPermissionRuleAdapter {
130
244
  throw new core_1.AuthorizationUnavailableError(`record_permission_rule store unavailable for ` +
131
245
  `${input.resource.typeKey}:${input.action.key}: ${err.message}`);
132
246
  }
247
+ // ── AND-GROUPING BY rpr_policy_uuid (author-what-enforces, Task 0.3) ──────────
248
+ // A guided policy has N AND-composed conditions persisted as N rows sharing one
249
+ // `rpr_policy_uuid`. A group (policy) APPLIES iff EVERY row in it subject-matches
250
+ // AND its condition holds — the AND. A legacy single-row rule (`rpr_policy_uuid`
251
+ // NULL) keeps the historical INDEPENDENT-row behavior: each such row is its OWN
252
+ // singleton group. This prevents the over-widening a naive per-row OR fold would
253
+ // cause on a multi-condition policy (allow when EITHER holds).
254
+ //
255
+ // Grouping: rows sharing a non-null policy uuid form ONE group; every NULL-policy
256
+ // row is a distinct singleton group (keyed by a unique sentinel per row).
257
+ const groups = new Map();
258
+ let nullGroupSeq = 0;
259
+ for (const row of rows) {
260
+ const key = row.rpr_policy_uuid != null // null OR undefined ⇒ legacy single-row rule
261
+ ? `p:${row.rpr_policy_uuid}`
262
+ : `n:${nullGroupSeq++}`; // each legacy row → its own singleton group
263
+ const bucket = groups.get(key);
264
+ if (bucket)
265
+ bucket.push(row);
266
+ else
267
+ groups.set(key, [row]);
268
+ }
133
269
  let allow = false;
134
270
  let explicitDeny = false;
135
- for (const row of rows) {
136
- if (!subjectMatches(row, input))
137
- continue;
138
- if (!conditionHolds(row, input))
271
+ for (const groupRows of groups.values()) {
272
+ const head = groupRows[0];
273
+ if (head === undefined)
274
+ continue; // a group always has ≥1 row; guard for the type
275
+ // The group (policy) applies IFF every row subject-matches AND its condition holds.
276
+ // Its effect is consistent across rows (the store writes one effect per policy);
277
+ // we take the group's effect from its first row and ignore any anomalous mix
278
+ // fail-closed (a non-'allow'/'deny' effect contributes nothing).
279
+ const applies = groupRows.every((row) => subjectMatches(row, input) && conditionHolds(row, input));
280
+ if (!applies)
139
281
  continue;
140
- if (row.rpr_effect === 'deny') {
141
- // Deny-wins — one matching deny is final for this tier.
282
+ const effect = head.rpr_effect;
283
+ if (effect === 'deny') {
284
+ // Deny-wins — one applying deny group is final for this tier.
142
285
  explicitDeny = true;
143
286
  }
144
- else if (row.rpr_effect === 'allow') {
287
+ else if (effect === 'allow') {
145
288
  allow = true;
146
289
  }
147
290
  // any other effect string is ignored (fail-closed — no permit inferred).
@@ -156,6 +156,28 @@ export declare class RecordShareWriter {
156
156
  * row(s); a no-match delete is a benign no-op. Emits `share.removed` on success.
157
157
  */
158
158
  unshare(input: ShareInput): Promise<void>;
159
+ /**
160
+ * List the shares CURRENTLY on a record — the owner-facing "who can see this" view. The SAME
161
+ * §6.2 owner bound applies: only the record's owner (in the sharer's tenant) may list its
162
+ * shares (a grantee cannot enumerate a record they don't own). Returns the raw share rows
163
+ * (grantee kind + uuid + action + sharer); the CALLER resolves grantee uuids → names before
164
+ * they reach the UI (no raw uuid rule — the identity module wires the DirectoryLabelResolver).
165
+ *
166
+ * @throws {@link ShareNotPermittedError} if the caller is not the record's owner (or the type
167
+ * is not owned / the record is not in their tenant) — same fail-closed bound as share().
168
+ * @throws {@link ShareStoreUnavailableError} on a transient store failure.
169
+ */
170
+ listSharesForRecord(input: {
171
+ tenantId: string;
172
+ typeKey: string;
173
+ recordId: string;
174
+ sharerId: string;
175
+ }): Promise<ReadonlyArray<{
176
+ granteeKind: ShareGranteeKind;
177
+ granteeUuid: string;
178
+ action: string;
179
+ grantedBy: string;
180
+ }>>;
159
181
  /**
160
182
  * Enforce the §6.2 who-may-share bound (steps 1–3) and return the resolved type info.
161
183
  * Fetches the record owner tenant-scoped and proves `sharerId` owns it. Throws
@@ -1 +1 @@
1
- {"version":3,"file":"record-share-writer.d.ts","sourceRoot":"","sources":["../../src/authz/record-share-writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"record-share-writer.d.ts","sourceRoot":"","sources":["../../src/authz/record-share-writer.ts"],"names":[],"mappings":"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"}
@@ -137,6 +137,47 @@ class RecordShareWriter {
137
137
  }
138
138
  await this.emit('share.removed', input);
139
139
  }
140
+ /**
141
+ * List the shares CURRENTLY on a record — the owner-facing "who can see this" view. The SAME
142
+ * §6.2 owner bound applies: only the record's owner (in the sharer's tenant) may list its
143
+ * shares (a grantee cannot enumerate a record they don't own). Returns the raw share rows
144
+ * (grantee kind + uuid + action + sharer); the CALLER resolves grantee uuids → names before
145
+ * they reach the UI (no raw uuid rule — the identity module wires the DirectoryLabelResolver).
146
+ *
147
+ * @throws {@link ShareNotPermittedError} if the caller is not the record's owner (or the type
148
+ * is not owned / the record is not in their tenant) — same fail-closed bound as share().
149
+ * @throws {@link ShareStoreUnavailableError} on a transient store failure.
150
+ */
151
+ async listSharesForRecord(input) {
152
+ // Reuse the owner bound (steps 1–3) — a non-owner NEVER sees a record's share list.
153
+ await this.assertMayShare({
154
+ tenantId: input.tenantId,
155
+ typeKey: input.typeKey,
156
+ recordId: input.recordId,
157
+ sharerId: input.sharerId,
158
+ // grantee/action are irrelevant to the owner check; supply inert placeholders that the
159
+ // bound ignores (it reads only type/record/tenant/sharer).
160
+ granteeKind: 'user',
161
+ granteeUuid: '',
162
+ action: '',
163
+ });
164
+ let rows;
165
+ try {
166
+ rows = (await this.db.query(`SELECT rs_grantee_kind, rs_grantee_uuid, rs_action, rs_granted_by` +
167
+ ` FROM \`${this.schema}\`.\`record_share\`` +
168
+ ` WHERE rs_tenant_uuid = ? AND rs_type_key = ? AND rs_record_uuid = ?` +
169
+ ` ORDER BY rs_created_at`, [input.tenantId, input.typeKey, input.recordId]));
170
+ }
171
+ catch (err) {
172
+ throw new ShareStoreUnavailableError(`record_share list failed for ${input.typeKey}: ${err.message}`);
173
+ }
174
+ return rows.map((r) => ({
175
+ granteeKind: r.rs_grantee_kind === 'role' ? 'role' : 'user',
176
+ granteeUuid: r.rs_grantee_uuid,
177
+ action: r.rs_action,
178
+ grantedBy: r.rs_granted_by,
179
+ }));
180
+ }
140
181
  // --- the bound -------------------------------------------------------------
141
182
  /**
142
183
  * Enforce the §6.2 who-may-share bound (steps 1–3) and return the resolved type info.
@@ -23,7 +23,8 @@
23
23
  * import inside the `SHIELD_DECISION_AUTHORITY` async factory — which runs ONLY when a
24
24
  * consumer opts into `recordAuthorization`. This file (and thus core) loads only then.
25
25
  */
26
- import type { DecisionAuthority, ModuleRegistry, PermissionFactsPort, SessionFactsReader } from '@astram/core';
26
+ import type { DecisionAuthority, ModuleRegistry, PermissionFactsPort, Principal, SessionFactsReader } from '@astram/core';
27
+ import type { ObjectType } from '@astram/engine';
27
28
  import { type RuleQueryable } from './mariadb-record-rule-adapter.js';
28
29
  import { type OperationManifestEntry } from './manifest-operation-authority-adapter.js';
29
30
  /**
@@ -63,4 +64,37 @@ export interface RecordAuthorizationInputs {
63
64
  * pool, same registry, same ports) — this is a wiring MOVE, not a logic change.
64
65
  */
65
66
  export declare function buildRecordAuthorization(inputs: RecordAuthorizationInputs): DecisionAuthority;
67
+ /**
68
+ * The engine-facing list-scope fn (Task 2.2). Given the engine's registered
69
+ * {@link ObjectType}, the requesting {@link Principal}, and the list action key, it returns
70
+ * the SAFE, parameterized WHERE fragment describing the visible set. The engine's `list()`
71
+ * (Task 3.1) ANDs `sql` into its WHERE and appends `params`.
72
+ *
73
+ * A transient store outage (an `AuthorizationUnavailableError` from the list-scope port)
74
+ * PROPAGATES through the returned promise — the engine's `list()` fails rather than falling
75
+ * open to an unbounded set (Invariant #8 / ADR-0016).
76
+ */
77
+ export type ListScopeFn = (reg: ObjectType, actor: Principal, action: string) => Promise<{
78
+ sql: string;
79
+ params: unknown[];
80
+ }>;
81
+ /**
82
+ * Construct the engine-facing {@link ListScopeFn} — the LIST-form sibling to
83
+ * `buildRecordAuthorization`'s per-record authority. It is a SEPARATE exported factory
84
+ * (Option A in the task report) that the module wiring calls ALONGSIDE
85
+ * `buildRecordAuthorization`: both take {@link RecordAuthorizationInputs} and both construct
86
+ * their adapters over the SAME un-overridable `inputs.pool`. This keeps
87
+ * `buildRecordAuthorization`'s `DecisionAuthority` return type unchanged (least blast radius).
88
+ *
89
+ * ── THE UN-OVERRIDABLE SEAM (the SECURITY POINT). The {@link MariaDbListScopeAdapter} is
90
+ * constructed HERE, over `inputs.pool` — the SAME pool the four record-tier read adapters
91
+ * use — and is DELIBERATELY NOT a field of {@link RecordAuthorizationInputs}. A consumer
92
+ * supplies ONLY the pool; it can NOT inject a fail-OPEN scope port (the exact hole this
93
+ * closes, mirroring the four record-tier adapters).
94
+ *
95
+ * ── FAIL-CLOSED. Nothing in the returned fn catches or swallows: a transient throw at ANY
96
+ * step (the port's store outage → `AuthorizationUnavailableError`, or the translator's
97
+ * unknown-field rejection) PROPAGATES so the read fails, NEVER falls open to unbounded.
98
+ */
99
+ export declare function buildListScopeFn(inputs: RecordAuthorizationInputs): ListScopeFn;
66
100
  //# sourceMappingURL=wire-record-authorization.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wire-record-authorization.d.ts","sourceRoot":"","sources":["../../src/authz/wire-record-authorization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,2CAA2C,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAC9C,6FAA6F;IAC7F,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,6GAA6G;IAC7G,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,GAAG,iBAAiB,CAmB7F"}
1
+ {"version":3,"file":"wire-record-authorization.d.ts","sourceRoot":"","sources":["../../src/authz/wire-record-authorization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EAEd,mBAAmB,EACnB,SAAS,EAET,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;AAK1C,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,2CAA2C,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAC9C,6FAA6F;IAC7F,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,6GAA6G;IAC7G,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,GAAG,iBAAiB,CAmB7F;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,yBAAyB,GAAG,WAAW,CAkE/E"}
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildRecordAuthorization = buildRecordAuthorization;
4
+ exports.buildListScopeFn = buildListScopeFn;
4
5
  const core_1 = require("@astram/core");
5
6
  const mariadb_record_rule_adapter_js_1 = require("./mariadb-record-rule-adapter.js");
6
7
  const mariadb_record_share_adapter_js_1 = require("./mariadb-record-share-adapter.js");
7
8
  const mariadb_cross_tenant_grant_adapter_js_1 = require("./mariadb-cross-tenant-grant-adapter.js");
9
+ const mariadb_list_scope_adapter_js_1 = require("./mariadb-list-scope-adapter.js");
10
+ const list_scope_sql_js_1 = require("./list-scope-sql.js");
8
11
  const manifest_operation_authority_adapter_js_1 = require("./manifest-operation-authority-adapter.js");
9
12
  /**
10
13
  * Construct the four framework-owned record-tier adapters over the supplied pool +
@@ -32,3 +35,75 @@ function buildRecordAuthorization(inputs) {
32
35
  operationAuthority: new manifest_operation_authority_adapter_js_1.ManifestOperationAuthorityAdapter(inputs.operationManifest ?? []),
33
36
  });
34
37
  }
38
+ /**
39
+ * Construct the engine-facing {@link ListScopeFn} — the LIST-form sibling to
40
+ * `buildRecordAuthorization`'s per-record authority. It is a SEPARATE exported factory
41
+ * (Option A in the task report) that the module wiring calls ALONGSIDE
42
+ * `buildRecordAuthorization`: both take {@link RecordAuthorizationInputs} and both construct
43
+ * their adapters over the SAME un-overridable `inputs.pool`. This keeps
44
+ * `buildRecordAuthorization`'s `DecisionAuthority` return type unchanged (least blast radius).
45
+ *
46
+ * ── THE UN-OVERRIDABLE SEAM (the SECURITY POINT). The {@link MariaDbListScopeAdapter} is
47
+ * constructed HERE, over `inputs.pool` — the SAME pool the four record-tier read adapters
48
+ * use — and is DELIBERATELY NOT a field of {@link RecordAuthorizationInputs}. A consumer
49
+ * supplies ONLY the pool; it can NOT inject a fail-OPEN scope port (the exact hole this
50
+ * closes, mirroring the four record-tier adapters).
51
+ *
52
+ * ── FAIL-CLOSED. Nothing in the returned fn catches or swallows: a transient throw at ANY
53
+ * step (the port's store outage → `AuthorizationUnavailableError`, or the translator's
54
+ * unknown-field rejection) PROPAGATES so the read fails, NEVER falls open to unbounded.
55
+ */
56
+ function buildListScopeFn(inputs) {
57
+ // Framework-constructed over `inputs.pool` — UN-overridable (not a field of the inputs).
58
+ const listScopePort = new mariadb_list_scope_adapter_js_1.MariaDbListScopeAdapter(inputs.pool);
59
+ // The cross-tenant grant adapter — reused HERE to resolve the OWNING tenants a grantee
60
+ // reaches, so the list can apply the OWNING tenant's deny rules to the cross-tenant branch
61
+ // (deny-wins per the resource's tenant — the fail-open leak the Phase-4 review found). Same
62
+ // un-overridable `inputs.pool`.
63
+ const crossTenantAdapter = new mariadb_cross_tenant_grant_adapter_js_1.MariaDbCrossTenantGrantAdapter(inputs.pool);
64
+ return async (reg, actor, action) => {
65
+ // Bridge the engine `ObjectType` → the core `ComputeListScopeDeps.registry` shape.
66
+ // `computeListScope` reads ONLY `descriptor.access` for the owner-baseline posture
67
+ // (see list-scope.ts `ownerBaselineFor`), so `label`/`fields` are inert — the engine's
68
+ // `reg.access` (`AccessDeclaration`) is structurally core's `RecordAccessPosture`.
69
+ const registry = {
70
+ resolveObjectType(typeKey) {
71
+ return typeKey === reg.typeKey
72
+ ? { typeKey: reg.typeKey, label: reg.typeKey, fields: [], access: reg.access }
73
+ : undefined;
74
+ },
75
+ };
76
+ // A transient throw here PROPAGATES (fail-closed — NOT caught).
77
+ const spec = await (0, core_1.computeListScope)({ registry, listScope: listScopePort }, { principal: actor, action, typeKey: reg.typeKey, tenantId: actor.tenantId });
78
+ // ── OWNING-TENANT DENY (Task 4.2 — the fail-open leak fix) ────────────────────────────
79
+ // A cross-tenant grant reaches the OWNING tenant's records; `decide()` evaluates those at
80
+ // the RESOURCE's (owning) tenant, so the owning tenant's DENY rules apply (deny-wins,
81
+ // ADR-0005). The same-tenant deny (in `spec.policyDeny`) does NOT cover them — it is scoped
82
+ // to the actor's own subtree. So resolve the active grants' owning tenants and fetch THEIR
83
+ // deny groups, to be applied ONLY to the cross-tenant branch (per-branch deny scoping — a
84
+ // global deny would over-restrict the same-tenant set). Fires ONLY for a NON-ROOT grantee
85
+ // with `crossTenant.kind === 'granted'`; root has no cross-tenant branch. A transient throw
86
+ // PROPAGATES (fail-closed — never drop the owning-tenant deny). Global (NULL-tenant) deny
87
+ // rules come back in BOTH fetches, so they apply to both branches (as `decide()` does).
88
+ let owningTenantDeny = [];
89
+ if (spec.crossTenant.kind === 'granted') {
90
+ const owningTenants = await crossTenantAdapter.listActiveOwningTenants({
91
+ grantee: actor.id,
92
+ roleIds: actor.roleIds,
93
+ typeKey: reg.typeKey,
94
+ action,
95
+ });
96
+ if (owningTenants.length > 0) {
97
+ const owningPolicy = await listScopePort.listPolicyConditions(reg.typeKey, owningTenants, action, {
98
+ principalId: actor.id,
99
+ roleIds: actor.roleIds,
100
+ });
101
+ owningTenantDeny = owningPolicy.deny; // ONLY the deny — the GRANT is the permit source
102
+ }
103
+ }
104
+ // Translate the abstract spec → SAFE parameterized WHERE fragment. An unknown-field
105
+ // rejection here also PROPAGATES (fail-closed).
106
+ const translated = (0, list_scope_sql_js_1.translateListScope)(spec, reg, { principalId: actor.id, principalTenantId: actor.tenantId }, { owningTenantDeny });
107
+ return { sql: translated.sql, params: translated.params };
108
+ };
109
+ }
@@ -17,6 +17,13 @@ export type IdentityAction = (typeof IDENTITY_ACTIONS)[number];
17
17
  */
18
18
  export declare const CROSS_TENANT_GRANT_ACTIONS: readonly ["share", "accept", "revoke"];
19
19
  export type CrossTenantGrantAction = (typeof CROSS_TENANT_GRANT_ACTIONS)[number];
20
+ /**
21
+ * `record_share`'s action vocabulary (list-scoping engine Phase 6, §9.2) — NOT the CRUD verbs.
22
+ * `share` gates the create/revoke routes (a per-record owner action; the writer's owner-bound is
23
+ * the real wall), `read` gates the list-a-record's-shares route.
24
+ */
25
+ export declare const RECORD_SHARE_ACTIONS: readonly ["share", "read"];
26
+ export type RecordShareAction = (typeof RECORD_SHARE_ACTIONS)[number];
20
27
  /** The action vocabulary for `typeKey` — the per-type override if one exists, else the default. */
21
28
  export declare function actionsFor(typeKey: string): readonly string[];
22
29
  //# sourceMappingURL=identity-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../src/identity/identity-actions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,aAAa,CAAC;AACrC,eAAO,MAAM,gBAAgB,iDAAkD,CAAC;AAChF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,wCAAyC,CAAC;AACjF,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAUjF,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE7D"}
1
+ {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../src/identity/identity-actions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,aAAa,CAAC;AACrC,eAAO,MAAM,gBAAgB,iDAAkD,CAAC;AAChF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,wCAAyC,CAAC;AACjF,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,4BAA6B,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAWtE,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE7D"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CROSS_TENANT_GRANT_ACTIONS = exports.IDENTITY_ACTIONS = exports.MODULE_KEY = void 0;
3
+ exports.RECORD_SHARE_ACTIONS = exports.CROSS_TENANT_GRANT_ACTIONS = exports.IDENTITY_ACTIONS = exports.MODULE_KEY = void 0;
4
4
  exports.actionsFor = actionsFor;
5
5
  /**
6
6
  * The fixed action vocabulary + module key for the framework's @astram/identity objects.
@@ -19,12 +19,19 @@ exports.IDENTITY_ACTIONS = ['read', 'create', 'update', 'delete'];
19
19
  * revoke -> 'revoke'). Mirrors astram3's `authz/actions.ts`'s `CROSS_TENANT_GRANT_ACTIONS`.
20
20
  */
21
21
  exports.CROSS_TENANT_GRANT_ACTIONS = ['share', 'accept', 'revoke'];
22
+ /**
23
+ * `record_share`'s action vocabulary (list-scoping engine Phase 6, §9.2) — NOT the CRUD verbs.
24
+ * `share` gates the create/revoke routes (a per-record owner action; the writer's owner-bound is
25
+ * the real wall), `read` gates the list-a-record's-shares route.
26
+ */
27
+ exports.RECORD_SHARE_ACTIONS = ['share', 'read'];
22
28
  /**
23
29
  * Per-type action-vocabulary override. Every type not listed here defaults to
24
30
  * {@link IDENTITY_ACTIONS} (the CRUD verbs).
25
31
  */
26
32
  const ACTIONS_BY_TYPE = {
27
33
  cross_tenant_grant: exports.CROSS_TENANT_GRANT_ACTIONS,
34
+ record_share: exports.RECORD_SHARE_ACTIONS,
28
35
  };
29
36
  /** The action vocabulary for `typeKey` — the per-type override if one exists, else the default. */
30
37
  function actionsFor(typeKey) {
package/dist/index.d.ts CHANGED
@@ -33,6 +33,9 @@ export { stubDecisionAuthority, type Effect, type CoreDecisionAuthority, type Co
33
33
  export { Argon2idPasswordHasher, argon2idHasherProvider, SHIELD_PASSWORD_HASHER, type Argon2idParams, } from './authentication/argon2id-password-hasher.js';
34
34
  export { MariaDbSessionRecordStore, SHIELD_SESSION_RECORD_STORE, RedisHotSessionStore, SHIELD_HOT_SESSION_STORE, CryptoTokenGenerator, Sha256RefreshTokenHasher, SystemClock, cryptoTokenGeneratorProvider, refreshHasherProvider, systemClockProvider, SHIELD_TOKEN_GENERATOR, SHIELD_REFRESH_HASHER, SHIELD_CLOCK, } from './session/index.js';
35
35
  export { MariaDbRecordPermissionRuleAdapter, SHIELD_RECORD_RULE_PORT, type RuleQueryable, } from './authz/mariadb-record-rule-adapter.js';
36
+ export { MariaDbPolicyStore, SHIELD_POLICY_STORE, type RuleQueryable as PolicyStoreQueryable, } from './authz/mariadb-policy-store.js';
37
+ export { MariaDbListScopeAdapter, SHIELD_LIST_SCOPE_PORT, type ListScopeQueryable, } from './authz/mariadb-list-scope-adapter.js';
38
+ export { translateListScope, UnknownScopeFieldError, type TranslatedListScope, type ListScopePrincipal, } from './authz/list-scope-sql.js';
36
39
  export { MariaDbRecordShareAdapter, SHIELD_RECORD_SHARE_PORT, type ShareQueryable, } from './authz/mariadb-record-share-adapter.js';
37
40
  export { RecordShareWriter, SHIELD_RECORD_SHARE_WRITER, ShareNotPermittedError, ShareStoreUnavailableError, type ShareInput, type ShareGranteeKind, type ShareTypeInfo, type ShareTypeResolver, type ShareAuditEvent, type ShareAuditSink, } from './authz/record-share-writer.js';
38
41
  export { makeShareDeleteCascade, type RecordDeletedHook, type ShareQueryFn, } from './authz/record-share-cascade.js';
@@ -40,6 +43,7 @@ export { MariaDbCrossTenantGrantAdapter, SHIELD_CROSS_TENANT_GRANT_PORT, type Gr
40
43
  export { CrossTenantGrantWriter, SHIELD_CROSS_TENANT_GRANT_WRITER, GrantNotPermittedError, InvalidGrantError, GrantStoreUnavailableError, type GrantAuthorizeFn, type GrantAuditEvent, type GrantAuditSink, type GrantGranteeKind, type GrantScope, type OfferGrantInput, type AcceptGrantInput, type RevokeGrantInput, } from './authz/cross-tenant-grant-writer.js';
41
44
  export { ManifestOperationAuthorityAdapter, SHIELD_OPERATION_AUTHORITY_PORT, type OperationManifestEntry, } from './authz/manifest-operation-authority-adapter.js';
42
45
  export { buildRecordAuthorization } from './authz/wire-record-authorization.js';
46
+ export { buildListScopeFn, type ListScopeFn } from './authz/wire-record-authorization.js';
43
47
  export { BootSequence, assertPoolBudget } from './boot/boot-sequence.js';
44
48
  export { APP_CONFIG } from './config/config.module.js';
45
49
  export { loadAppConfig, loadPoolBudget, evaluatePoolBudget, DEFAULT_POOL_BUDGET, SCHEMA_SVC_POOL_HARD_CAP, type AppConfig, type PoolBudgetConfig, type PoolBudgetEvaluation, type RuntimeAccountPools, loadDbConfig, loadRedisConfig, loadSessionLifetimes, loadRefreshHmacKey, assertRefreshHmacKey, DEFAULT_DB_CONFIG, DEFAULT_REDIS_URL, type DbConfig, type RedisConfig, type SessionLifetimeOverrides, } from './config/app-config.js';
@@ -62,8 +66,11 @@ export type { MfaDeviceStore, MfaDevice } from './auth/ports/mfa-device-store.js
62
66
  export type { AuditSink, AuthAuditEvent } from './auth/ports/audit-sink.js';
63
67
  export type { SessionFactsProjector } from './auth/ports/session-facts-projector.js';
64
68
  export { SHIELD_SESSION_FACTS_PROJECTOR } from './auth/tokens.js';
69
+ export type { ScopeSubtreeResolver } from './auth/ports/scope-subtree-resolver.js';
70
+ export { SHIELD_SCOPE_SUBTREE_RESOLVER } from './auth/tokens.js';
65
71
  export { AuthController } from './auth/auth.controller.js';
66
72
  export { PendingMfaStore } from './auth/pending-mfa-store.js';
67
73
  export { generateTotpSecret, buildOtpauthUri, generateRecoveryCodes, } from './auth/totp-enrollment.js';
68
74
  export { AccountController } from './auth/account.controller.js';
75
+ export { buildClosureRows, ScopeCycleError, ScopeDepthError, ScopeUnknownParentError, type ScopeEdge, type ClosureRow, } from './scope/closure-builder.js';
69
76
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AASzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAG1F,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAI7B,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACL,MAAM,EACN,UAAU,EACV,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,2CAA2C,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAKhF,OAAO,EAAE,yBAAyB,EAAE,MAAM,+CAA+C,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACjG,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,eAAe,GAChB,MAAM,uCAAuC,CAAC;AAM/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,YAAY,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAS7C,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,iBAAiB,GACvB,MAAM,qCAAqC,CAAC;AAU7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAKnF,OAAO,EACL,qBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,cAAc,GACpB,MAAM,8CAA8C,CAAC;AAOtD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,4BAA4B,EAC5B,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EACL,kCAAkC,EAClC,uBAAuB,EACvB,KAAK,aAAa,GACnB,MAAM,wCAAwC,CAAC;AAMhD,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,KAAK,cAAc,GACpB,MAAM,yCAAyC,CAAC;AASjD,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,EAC1B,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,gCAAgC,CAAC;AAMxC,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AAOzC,OAAO,EACL,8BAA8B,EAC9B,8BAA8B,EAC9B,KAAK,cAAc,GACpB,MAAM,+CAA+C,CAAC;AAWvD,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAChC,sBAAsB,EACtB,iBAAiB,EACjB,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,sCAAsC,CAAC;AAQ9C,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,iDAAiD,CAAC;AAYzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAIhF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAOzE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EACL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAGxB,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAC9B,MAAM,wBAAwB,CAAC;AAchC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,EAIxB,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,EAEtB,iBAAiB,EAEjB,uBAAuB,EAEvB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAI5F,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,UAAU,EACV,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,SAAS,GACV,MAAM,eAAe,CAAC;AAKvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAQ3E,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAS/F,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACf,MAAM,cAAc,CAAC;AAQtB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM9E,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,aAAa,GACd,MAAM,4BAA4B,CAAC;AAMpC,YAAY,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC9E,YAAY,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAK5E,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAOlE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAK9D,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AASzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAG1F,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAI7B,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACL,MAAM,EACN,UAAU,EACV,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,2CAA2C,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAKhF,OAAO,EAAE,yBAAyB,EAAE,MAAM,+CAA+C,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACjG,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,eAAe,GAChB,MAAM,uCAAuC,CAAC;AAM/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,YAAY,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAS7C,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,iBAAiB,GACvB,MAAM,qCAAqC,CAAC;AAU7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAKnF,OAAO,EACL,qBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,cAAc,GACpB,MAAM,8CAA8C,CAAC;AAOtD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,4BAA4B,EAC5B,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EACL,kCAAkC,EAClC,uBAAuB,EACvB,KAAK,aAAa,GACnB,MAAM,wCAAwC,CAAC;AAShD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,aAAa,IAAI,oBAAoB,GAC3C,MAAM,iCAAiC,CAAC;AAUzC,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,KAAK,cAAc,GACpB,MAAM,yCAAyC,CAAC;AASjD,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,EAC1B,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,gCAAgC,CAAC;AAMxC,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AAOzC,OAAO,EACL,8BAA8B,EAC9B,8BAA8B,EAC9B,KAAK,cAAc,GACpB,MAAM,+CAA+C,CAAC;AAWvD,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAChC,sBAAsB,EACtB,iBAAiB,EACjB,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,sCAAsC,CAAC;AAQ9C,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,iDAAiD,CAAC;AAYzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAOhF,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAI1F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAOzE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EACL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EAGxB,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAC9B,MAAM,wBAAwB,CAAC;AAchC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,EAIxB,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,EAEtB,iBAAiB,EAEjB,uBAAuB,EAEvB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAI5F,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,UAAU,EACV,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,SAAS,GACV,MAAM,eAAe,CAAC;AAKvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAQ3E,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAS/F,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACf,MAAM,cAAc,CAAC;AAQtB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM9E,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,aAAa,GACd,MAAM,4BAA4B,CAAC;AAMpC,YAAY,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC9E,YAAY,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,YAAY,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAK5E,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAMlE,YAAY,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAK9D,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAQjE,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,uBAAuB,EACvB,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,4BAA4B,CAAC"}