@fuzdev/fuz_app 0.59.0 → 0.60.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 (95) hide show
  1. package/dist/actions/CLAUDE.md +5 -5
  2. package/dist/actions/action_codegen.d.ts +1 -1
  3. package/dist/actions/action_codegen.js +2 -2
  4. package/dist/actions/action_event_helpers.d.ts +3 -3
  5. package/dist/actions/action_event_helpers.js +8 -8
  6. package/dist/actions/action_event_types.d.ts +3 -3
  7. package/dist/actions/action_event_types.js +3 -3
  8. package/dist/actions/transports_ws_auth_guard.d.ts +2 -2
  9. package/dist/actions/transports_ws_auth_guard.js +3 -3
  10. package/dist/auth/CLAUDE.md +157 -15
  11. package/dist/auth/actor_lookup_action_specs.d.ts +127 -0
  12. package/dist/auth/actor_lookup_action_specs.d.ts.map +1 -0
  13. package/dist/auth/actor_lookup_action_specs.js +93 -0
  14. package/dist/auth/actor_lookup_actions.d.ts +19 -0
  15. package/dist/auth/actor_lookup_actions.d.ts.map +1 -0
  16. package/dist/auth/actor_lookup_actions.js +32 -0
  17. package/dist/auth/actor_lookup_queries.d.ts +44 -0
  18. package/dist/auth/actor_lookup_queries.d.ts.map +1 -0
  19. package/dist/auth/actor_lookup_queries.js +42 -0
  20. package/dist/auth/actor_search_action_specs.d.ts +166 -0
  21. package/dist/auth/actor_search_action_specs.d.ts.map +1 -0
  22. package/dist/auth/actor_search_action_specs.js +139 -0
  23. package/dist/auth/actor_search_actions.d.ts +31 -0
  24. package/dist/auth/actor_search_actions.d.ts.map +1 -0
  25. package/dist/auth/actor_search_actions.js +61 -0
  26. package/dist/auth/actor_search_queries.d.ts +75 -0
  27. package/dist/auth/actor_search_queries.d.ts.map +1 -0
  28. package/dist/auth/actor_search_queries.js +91 -0
  29. package/dist/auth/admin_actions.js +2 -2
  30. package/dist/auth/all_action_spec_registries.d.ts +55 -0
  31. package/dist/auth/all_action_spec_registries.d.ts.map +1 -0
  32. package/dist/auth/all_action_spec_registries.js +59 -0
  33. package/dist/auth/audit_emitter.d.ts +1 -1
  34. package/dist/auth/audit_emitter.js +2 -2
  35. package/dist/auth/audit_log_queries.d.ts +1 -1
  36. package/dist/auth/audit_log_queries.js +3 -3
  37. package/dist/auth/audit_log_routes.d.ts +1 -1
  38. package/dist/auth/audit_log_routes.js +1 -1
  39. package/dist/auth/audit_log_schema.d.ts +5 -5
  40. package/dist/auth/audit_log_schema.js +7 -7
  41. package/dist/auth/auth_ddl.d.ts +7 -0
  42. package/dist/auth/auth_ddl.d.ts.map +1 -1
  43. package/dist/auth/auth_ddl.js +8 -0
  44. package/dist/auth/credential_type_schema.d.ts +1 -1
  45. package/dist/auth/credential_type_schema.js +3 -3
  46. package/dist/auth/grant_path_schema.d.ts +1 -1
  47. package/dist/auth/grant_path_schema.js +3 -3
  48. package/dist/auth/migrations.d.ts +4 -4
  49. package/dist/auth/migrations.d.ts.map +1 -1
  50. package/dist/auth/migrations.js +7 -6
  51. package/dist/auth/role_grant_offer_actions.js +2 -2
  52. package/dist/auth/role_grant_offer_notifications.d.ts +2 -2
  53. package/dist/auth/role_grant_offer_notifications.js +2 -2
  54. package/dist/auth/role_grant_queries.d.ts +21 -0
  55. package/dist/auth/role_grant_queries.d.ts.map +1 -1
  56. package/dist/auth/role_grant_queries.js +31 -0
  57. package/dist/auth/role_schema.d.ts +2 -2
  58. package/dist/auth/role_schema.js +3 -3
  59. package/dist/auth/self_service_role_actions.d.ts +1 -1
  60. package/dist/auth/self_service_role_actions.js +2 -2
  61. package/dist/auth/session_cookie.d.ts +1 -1
  62. package/dist/auth/session_cookie.js +1 -1
  63. package/dist/auth/session_middleware.d.ts +1 -1
  64. package/dist/auth/session_middleware.js +5 -5
  65. package/dist/rate_limiter.d.ts +5 -5
  66. package/dist/rate_limiter.js +6 -6
  67. package/dist/realtime/sse_auth_guard.d.ts +3 -3
  68. package/dist/realtime/sse_auth_guard.js +4 -4
  69. package/dist/server/app_backend.d.ts +3 -3
  70. package/dist/server/app_backend.js +4 -4
  71. package/dist/server/app_server.d.ts +1 -1
  72. package/dist/server/app_server.js +10 -10
  73. package/dist/testing/CLAUDE.md +22 -12
  74. package/dist/testing/admin_integration.js +4 -4
  75. package/dist/testing/app_server.d.ts +1 -1
  76. package/dist/testing/app_server.js +2 -2
  77. package/dist/testing/attack_surface.d.ts +4 -4
  78. package/dist/testing/attack_surface.js +6 -6
  79. package/dist/testing/audit_completeness.js +4 -4
  80. package/dist/testing/data_exposure.d.ts +2 -2
  81. package/dist/testing/data_exposure.js +7 -7
  82. package/dist/testing/db.d.ts +8 -8
  83. package/dist/testing/db.js +11 -11
  84. package/dist/testing/integration.js +4 -4
  85. package/dist/testing/integration_helpers.d.ts +6 -6
  86. package/dist/testing/integration_helpers.js +7 -7
  87. package/dist/testing/rate_limiting.js +4 -4
  88. package/dist/testing/round_trip.js +2 -2
  89. package/dist/testing/rpc_round_trip.js +2 -2
  90. package/dist/testing/schema_generators.d.ts.map +1 -1
  91. package/dist/testing/schema_generators.js +23 -2
  92. package/dist/testing/sse_round_trip.js +2 -2
  93. package/dist/testing/surface_invariants.d.ts +4 -4
  94. package/dist/testing/surface_invariants.js +5 -5
  95. package/package.json +1 -1
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Prefix-based actor search.
3
+ *
4
+ * Sibling to `actor_lookup_queries.ts` — that resolves a batch of ids to
5
+ * labels; this resolves a partial name to candidate actors. Same row
6
+ * shape (`ActorLookupRow`) so the labels arc on the consumer side stays
7
+ * uniform.
8
+ *
9
+ * Case-insensitive LIKE-prefix on `actor.name` backed by the
10
+ * `idx_actor_name_lower` functional index. LIKE wildcards (`%`, `_`,
11
+ * `\`) in the query string are escaped at the JS layer so the
12
+ * prefix-only contract is enforceable — an unescaped `%xyz` would
13
+ * widen the surface to full-LIKE and defeat the per-call cap as a
14
+ * binding bound.
15
+ *
16
+ * ## Auth filtering — `scope_ids`
17
+ *
18
+ * When `scope_ids` is non-empty, the result is filtered to actors
19
+ * holding an **active** role_grant on one of the supplied scopes. Active
20
+ * means `revoked_at IS NULL AND (expires_at IS NULL OR expires_at > NOW())`.
21
+ * Stale (revoked / expired) role_grants do **not** confer membership for
22
+ * search-visibility purposes — otherwise a removed student would
23
+ * remain visible to teachers indefinitely.
24
+ *
25
+ * The `DISTINCT` on `actor.id` collapses the case where an actor holds
26
+ * multiple matching role_grants in the supplied scope set into one row.
27
+ *
28
+ * When `scope_ids` is omitted (admin-only global path; the handler
29
+ * gates), no role_grant join — every actor with a matching prefix is
30
+ * returned.
31
+ *
32
+ * ## Info-leak posture (see `actor_search_action_specs.ts` § audit)
33
+ *
34
+ * - Row shape **omits** `account_id` — the join is control-plane, not
35
+ * wire-visible. Identical to `actor_lookup_queries.ts`.
36
+ * - Hard-deleted actors (cascade-orphaned via `actor.account_id` FK)
37
+ * drop out silently.
38
+ * - No `created_at` / `updated_at` projected (timing-oracle avoidance).
39
+ * - Scope-membership uses ANY on the supplied `scope_ids` array but
40
+ * never surfaces "which scope matched" — the result row carries only
41
+ * the actor's wire shape. An attacker passing a random scope_id
42
+ * learns at most "this scope has at least one member matching X"
43
+ * if a match exists, indistinguishable from a no-match search; the
44
+ * caller-passes-scope_ids design (handler trusts the array as a
45
+ * filter, not as authority) means the attacker had to obtain the
46
+ * scope_id from somewhere else first.
47
+ *
48
+ * Caller bounds `limit` (the action-spec layer enforces
49
+ * `ACTOR_SEARCH_LIMIT_MAX`); SQL clamps to that cap on the call site
50
+ * before reaching this query.
51
+ *
52
+ * @module
53
+ */
54
+ import type { Uuid } from '@fuzdev/fuz_util/id.js';
55
+ import type { QueryDeps } from '../db/query_deps.js';
56
+ import type { ActorLookupRow } from './actor_lookup_queries.js';
57
+ /** Inputs for `query_actor_search`. */
58
+ export interface ActorSearchQueryInput {
59
+ /** Case-insensitive prefix string. Must be non-empty (action layer enforces `min(1)`). */
60
+ query: string;
61
+ /**
62
+ * When non-empty, restrict to actors holding an active role_grant on one
63
+ * of these scope ids. When empty / omitted, no scope filter is applied —
64
+ * the handler is responsible for the admin gate.
65
+ */
66
+ scope_ids?: ReadonlyArray<Uuid>;
67
+ /** Maximum rows to return. The handler clamps to `ACTOR_SEARCH_LIMIT_MAX`. */
68
+ limit: number;
69
+ }
70
+ /**
71
+ * Search actors by case-insensitive prefix on `actor.name`, optionally
72
+ * filtered to those holding an active role_grant on one of `scope_ids`.
73
+ */
74
+ export declare const query_actor_search: (deps: QueryDeps, input: ActorSearchQueryInput) => Promise<Array<ActorLookupRow>>;
75
+ //# sourceMappingURL=actor_search_queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor_search_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/actor_search_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAEjD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,uCAAuC;AACvC,MAAM,WAAW,qBAAqB;IACrC,0FAA0F;IAC1F,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;CACd;AASD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC9B,MAAM,SAAS,EACf,OAAO,qBAAqB,KAC1B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAmC/B,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Prefix-based actor search.
3
+ *
4
+ * Sibling to `actor_lookup_queries.ts` — that resolves a batch of ids to
5
+ * labels; this resolves a partial name to candidate actors. Same row
6
+ * shape (`ActorLookupRow`) so the labels arc on the consumer side stays
7
+ * uniform.
8
+ *
9
+ * Case-insensitive LIKE-prefix on `actor.name` backed by the
10
+ * `idx_actor_name_lower` functional index. LIKE wildcards (`%`, `_`,
11
+ * `\`) in the query string are escaped at the JS layer so the
12
+ * prefix-only contract is enforceable — an unescaped `%xyz` would
13
+ * widen the surface to full-LIKE and defeat the per-call cap as a
14
+ * binding bound.
15
+ *
16
+ * ## Auth filtering — `scope_ids`
17
+ *
18
+ * When `scope_ids` is non-empty, the result is filtered to actors
19
+ * holding an **active** role_grant on one of the supplied scopes. Active
20
+ * means `revoked_at IS NULL AND (expires_at IS NULL OR expires_at > NOW())`.
21
+ * Stale (revoked / expired) role_grants do **not** confer membership for
22
+ * search-visibility purposes — otherwise a removed student would
23
+ * remain visible to teachers indefinitely.
24
+ *
25
+ * The `DISTINCT` on `actor.id` collapses the case where an actor holds
26
+ * multiple matching role_grants in the supplied scope set into one row.
27
+ *
28
+ * When `scope_ids` is omitted (admin-only global path; the handler
29
+ * gates), no role_grant join — every actor with a matching prefix is
30
+ * returned.
31
+ *
32
+ * ## Info-leak posture (see `actor_search_action_specs.ts` § audit)
33
+ *
34
+ * - Row shape **omits** `account_id` — the join is control-plane, not
35
+ * wire-visible. Identical to `actor_lookup_queries.ts`.
36
+ * - Hard-deleted actors (cascade-orphaned via `actor.account_id` FK)
37
+ * drop out silently.
38
+ * - No `created_at` / `updated_at` projected (timing-oracle avoidance).
39
+ * - Scope-membership uses ANY on the supplied `scope_ids` array but
40
+ * never surfaces "which scope matched" — the result row carries only
41
+ * the actor's wire shape. An attacker passing a random scope_id
42
+ * learns at most "this scope has at least one member matching X"
43
+ * if a match exists, indistinguishable from a no-match search; the
44
+ * caller-passes-scope_ids design (handler trusts the array as a
45
+ * filter, not as authority) means the attacker had to obtain the
46
+ * scope_id from somewhere else first.
47
+ *
48
+ * Caller bounds `limit` (the action-spec layer enforces
49
+ * `ACTOR_SEARCH_LIMIT_MAX`); SQL clamps to that cap on the call site
50
+ * before reaching this query.
51
+ *
52
+ * @module
53
+ */
54
+ /**
55
+ * Escape LIKE wildcards in a user-supplied query string so the SQL
56
+ * prefix-match cannot be widened by user input. The `\` escape char is
57
+ * declared on the LIKE expression via `ESCAPE '\'`.
58
+ */
59
+ const escape_like_pattern = (s) => s.replace(/[\\%_]/g, '\\$&');
60
+ /**
61
+ * Search actors by case-insensitive prefix on `actor.name`, optionally
62
+ * filtered to those holding an active role_grant on one of `scope_ids`.
63
+ */
64
+ export const query_actor_search = async (deps, input) => {
65
+ const escaped_prefix = escape_like_pattern(input.query.toLowerCase());
66
+ const scope_ids = input.scope_ids ?? [];
67
+ if (scope_ids.length === 0) {
68
+ // Admin-global path — no role_grant join. Handler enforces admin.
69
+ return deps.db.query(`SELECT act.id, a.username, act.name AS display_name
70
+ FROM actor act
71
+ JOIN account a ON a.id = act.account_id
72
+ WHERE LOWER(act.name) LIKE $1 || '%' ESCAPE '\\'
73
+ ORDER BY display_name, id
74
+ LIMIT $2`, [escaped_prefix, input.limit]);
75
+ }
76
+ // Scoped path — filter to actors with an active role_grant on any of
77
+ // `scope_ids`. DISTINCT collapses actors holding multiple matching
78
+ // role_grants in the supplied scope set into one row. ORDER BY must
79
+ // reference SELECT-listed columns under DISTINCT, so we sort by the
80
+ // `display_name` alias rather than `LOWER(act.name)`.
81
+ return deps.db.query(`SELECT DISTINCT act.id, a.username, act.name AS display_name
82
+ FROM actor act
83
+ JOIN account a ON a.id = act.account_id
84
+ JOIN role_grant rg ON rg.actor_id = act.id
85
+ AND rg.scope_id = ANY($2)
86
+ AND rg.revoked_at IS NULL
87
+ AND (rg.expires_at IS NULL OR rg.expires_at > NOW())
88
+ WHERE LOWER(act.name) LIKE $1 || '%' ESCAPE '\\'
89
+ ORDER BY display_name, id
90
+ LIMIT $3`, [escaped_prefix, scope_ids, input.limit]);
91
+ };
@@ -29,7 +29,7 @@
29
29
  */
30
30
  import { rpc_action } from '../actions/action_rpc.js';
31
31
  import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
32
- import { BUILTIN_ROLE_SPECS_BY_NAME, list_roles_with_grant_path, } from './role_schema.js';
32
+ import { builtin_role_specs_by_name, list_roles_with_grant_path, } from './role_schema.js';
33
33
  import { GRANT_PATH_ADMIN } from './grant_path_schema.js';
34
34
  import { query_account_by_email, query_account_by_id, query_account_by_username, query_admin_account_list, } from './account_queries.js';
35
35
  import { query_session_list_all_active, query_session_revoke_all_for_account, } from './session_queries.js';
@@ -54,7 +54,7 @@ import { admin_account_list_action_spec, admin_session_list_action_spec, admin_s
54
54
  * @mutates `options.app_settings` ref - `app_settings_update` writes `open_signup`, `updated_at`, and `updated_by` so signup middleware reads without a DB round trip
55
55
  */
56
56
  export const create_admin_actions = (deps, options = {}) => {
57
- const role_specs = options.roles?.role_specs ?? BUILTIN_ROLE_SPECS_BY_NAME;
57
+ const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
58
58
  const grantable_roles = list_roles_with_grant_path(role_specs, GRANT_PATH_ADMIN);
59
59
  const account_list_handler = async (input, ctx) => {
60
60
  const accounts = await query_admin_account_list(ctx, {
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Canonical list of every fuz_auth action-spec registry — **for cross-cutting
3
+ * walkers and codegen only**. Not a mounting surface; consumers continue to
4
+ * import individual `all_*_action_specs` bundles (and `create_*_actions`
5
+ * factories) per registration site.
6
+ *
7
+ * The "one main bundle" alternative is an antipattern for mounting:
8
+ * `create_standard_rpc_actions` (admin + role_grant_offer + account) is the
9
+ * canonical surface, and opt-in registries (`self_service_role`,
10
+ * `actor_lookup`) are deliberately opt-in because their eligibility
11
+ * (`eligible_roles`) or coverage (byline labels) is app-specific. Spreading
12
+ * everything into a single mount would silently widen the dispatch surface
13
+ * the moment a new opt-in landed — the exact failure mode this module is
14
+ * built to detect, not propagate. See `./CLAUDE.md` §RPC actions
15
+ * (`standard_rpc_actions.ts`).
16
+ *
17
+ * Use cases for this registry:
18
+ *
19
+ * - Cross-registry walker tests (input-invariants, auth-shape
20
+ * biconditional) — iterate the spec arrays once, fail when a new
21
+ * registry slips by without an entry here.
22
+ * - Codegen that needs to see every fuz_auth surface at once
23
+ * (typed-client filters, attack-surface reports). For typed-client
24
+ * wiring of the standard surface, prefer `all_standard_action_specs`
25
+ * in `./standard_action_specs.ts` — it mirrors the
26
+ * `create_standard_rpc_actions` mount and stays narrower than this
27
+ * registry-of-registries (no opt-in bundles).
28
+ *
29
+ * `protocol_action_specs` (heartbeat / cancel) is **not** included —
30
+ * those are transport-level wire-protocol concerns shipped by fuz_app
31
+ * and spread by every consumer at registration via `protocol_actions`
32
+ * from `../actions/protocol.ts`. Walker tests that need protocol
33
+ * coverage spread `protocol_action_specs` separately.
34
+ *
35
+ * @module
36
+ */
37
+ import type { RequestResponseActionSpec } from '../actions/action_spec.js';
38
+ /** One named entry in the registry-of-registries. */
39
+ export interface FuzAuthActionSpecRegistry {
40
+ /** Stable identifier matching the source bundle name (`'admin'`, `'role_grant_offer'`, etc.). */
41
+ name: string;
42
+ /** The bundle's spec array — kept readonly here even when the source declares it mutable. */
43
+ specs: ReadonlyArray<RequestResponseActionSpec>;
44
+ }
45
+ /**
46
+ * Every fuz_auth action-spec registry, in dependency-stable order.
47
+ *
48
+ * Update this list when a new fuz_auth registry lands. The walker tests
49
+ * (`action_spec_input_invariants.test.ts`,
50
+ * `all_action_spec_registries.acting_biconditional.test.ts`) iterate
51
+ * over it — a missing entry silently skips coverage, which is the
52
+ * failure mode the registry-of-registries shape exists to prevent.
53
+ */
54
+ export declare const all_fuz_auth_action_spec_registries: ReadonlyArray<FuzAuthActionSpecRegistry>;
55
+ //# sourceMappingURL=all_action_spec_registries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"all_action_spec_registries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/all_action_spec_registries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAQzE,qDAAqD;AACrD,MAAM,WAAW,yBAAyB;IACzC,iGAAiG;IACjG,IAAI,EAAE,MAAM,CAAC;IACb,6FAA6F;IAC7F,KAAK,EAAE,aAAa,CAAC,yBAAyB,CAAC,CAAC;CAChD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mCAAmC,EAAE,aAAa,CAAC,yBAAyB,CAOxF,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Canonical list of every fuz_auth action-spec registry — **for cross-cutting
3
+ * walkers and codegen only**. Not a mounting surface; consumers continue to
4
+ * import individual `all_*_action_specs` bundles (and `create_*_actions`
5
+ * factories) per registration site.
6
+ *
7
+ * The "one main bundle" alternative is an antipattern for mounting:
8
+ * `create_standard_rpc_actions` (admin + role_grant_offer + account) is the
9
+ * canonical surface, and opt-in registries (`self_service_role`,
10
+ * `actor_lookup`) are deliberately opt-in because their eligibility
11
+ * (`eligible_roles`) or coverage (byline labels) is app-specific. Spreading
12
+ * everything into a single mount would silently widen the dispatch surface
13
+ * the moment a new opt-in landed — the exact failure mode this module is
14
+ * built to detect, not propagate. See `./CLAUDE.md` §RPC actions
15
+ * (`standard_rpc_actions.ts`).
16
+ *
17
+ * Use cases for this registry:
18
+ *
19
+ * - Cross-registry walker tests (input-invariants, auth-shape
20
+ * biconditional) — iterate the spec arrays once, fail when a new
21
+ * registry slips by without an entry here.
22
+ * - Codegen that needs to see every fuz_auth surface at once
23
+ * (typed-client filters, attack-surface reports). For typed-client
24
+ * wiring of the standard surface, prefer `all_standard_action_specs`
25
+ * in `./standard_action_specs.ts` — it mirrors the
26
+ * `create_standard_rpc_actions` mount and stays narrower than this
27
+ * registry-of-registries (no opt-in bundles).
28
+ *
29
+ * `protocol_action_specs` (heartbeat / cancel) is **not** included —
30
+ * those are transport-level wire-protocol concerns shipped by fuz_app
31
+ * and spread by every consumer at registration via `protocol_actions`
32
+ * from `../actions/protocol.ts`. Walker tests that need protocol
33
+ * coverage spread `protocol_action_specs` separately.
34
+ *
35
+ * @module
36
+ */
37
+ import { all_admin_action_specs } from './admin_action_specs.js';
38
+ import { all_role_grant_offer_action_specs } from './role_grant_offer_action_specs.js';
39
+ import { all_account_action_specs } from './account_action_specs.js';
40
+ import { all_self_service_role_action_specs } from './self_service_role_action_specs.js';
41
+ import { all_actor_lookup_action_specs } from './actor_lookup_action_specs.js';
42
+ import { all_actor_search_action_specs } from './actor_search_action_specs.js';
43
+ /**
44
+ * Every fuz_auth action-spec registry, in dependency-stable order.
45
+ *
46
+ * Update this list when a new fuz_auth registry lands. The walker tests
47
+ * (`action_spec_input_invariants.test.ts`,
48
+ * `all_action_spec_registries.acting_biconditional.test.ts`) iterate
49
+ * over it — a missing entry silently skips coverage, which is the
50
+ * failure mode the registry-of-registries shape exists to prevent.
51
+ */
52
+ export const all_fuz_auth_action_spec_registries = [
53
+ { name: 'admin', specs: all_admin_action_specs },
54
+ { name: 'role_grant_offer', specs: all_role_grant_offer_action_specs },
55
+ { name: 'account', specs: all_account_action_specs },
56
+ { name: 'self_service_role', specs: all_self_service_role_action_specs },
57
+ { name: 'actor_lookup', specs: all_actor_lookup_action_specs },
58
+ { name: 'actor_search', specs: all_actor_search_action_specs },
59
+ ];
@@ -144,7 +144,7 @@ export interface CreateAuditEmitterOptions {
144
144
  */
145
145
  on_audit_event?: ((event: AuditLogEvent) => void) | null;
146
146
  /**
147
- * Audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`. Consumer-
147
+ * Audit-log config. Defaults to `builtin_audit_log_config`. Consumer-
148
148
  * extended configs from `create_audit_log_config({extra_events})` get
149
149
  * registered here once at backend assembly.
150
150
  */
@@ -33,7 +33,7 @@
33
33
  * @module
34
34
  */
35
35
  import { query_audit_log } from './audit_log_queries.js';
36
- import { BUILTIN_AUDIT_LOG_CONFIG, } from './audit_log_schema.js';
36
+ import { builtin_audit_log_config, } from './audit_log_schema.js';
37
37
  /**
38
38
  * Build a bound `AuditEmitter`. Called once at `create_app_backend` time.
39
39
  *
@@ -41,7 +41,7 @@ import { BUILTIN_AUDIT_LOG_CONFIG, } from './audit_log_schema.js';
41
41
  * @returns the bound emitter; closes over the pool + config + listener chain
42
42
  */
43
43
  export const create_audit_emitter = (options) => {
44
- const { db, log, audit_log_config = BUILTIN_AUDIT_LOG_CONFIG } = options;
44
+ const { db, log, audit_log_config = builtin_audit_log_config } = options;
45
45
  const on_event_chain = [];
46
46
  if (options.on_audit_event)
47
47
  on_event_chain.push(options.on_audit_event);
@@ -38,7 +38,7 @@ export declare const reset_audit_unknown_event_type_failures: () => void;
38
38
  *
39
39
  * @param deps - query dependencies
40
40
  * @param input - the audit event to record
41
- * @param config - audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`.
41
+ * @param config - audit-log config. Defaults to `builtin_audit_log_config`.
42
42
  * @returns the inserted audit log row
43
43
  * @mutates `audit_log` table - inserts the new row
44
44
  * @mutates drift counters - bumps `audit_unknown_event_type_failures` and/or `audit_metadata_validation_failures` on mismatch
@@ -12,7 +12,7 @@
12
12
  * @module
13
13
  */
14
14
  import { assert_row } from '../db/assert_row.js';
15
- import { AUDIT_LOG_DEFAULT_LIMIT, BUILTIN_AUDIT_LOG_CONFIG, } from './audit_log_schema.js';
15
+ import { AUDIT_LOG_DEFAULT_LIMIT, builtin_audit_log_config, } from './audit_log_schema.js';
16
16
  /**
17
17
  * Process-wide counter for audit metadata validation failures. `query_audit_log`
18
18
  * increments on `safeParse` mismatch and writes the row anyway (fail-open —
@@ -61,12 +61,12 @@ export const reset_audit_unknown_event_type_failures = () => {
61
61
  *
62
62
  * @param deps - query dependencies
63
63
  * @param input - the audit event to record
64
- * @param config - audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`.
64
+ * @param config - audit-log config. Defaults to `builtin_audit_log_config`.
65
65
  * @returns the inserted audit log row
66
66
  * @mutates `audit_log` table - inserts the new row
67
67
  * @mutates drift counters - bumps `audit_unknown_event_type_failures` and/or `audit_metadata_validation_failures` on mismatch
68
68
  */
69
- export const query_audit_log = async (deps, input, config = BUILTIN_AUDIT_LOG_CONFIG) => {
69
+ export const query_audit_log = async (deps, input, config = builtin_audit_log_config) => {
70
70
  if (!config.event_types.includes(input.event_type)) {
71
71
  audit_unknown_event_type_failures++;
72
72
  console.error(`[audit_log] unknown event_type '${input.event_type}' — register via create_audit_log_config({extra_events})`);
@@ -6,7 +6,7 @@
6
6
  * `admin_session_list` on the same file. What remains here is the optional
7
7
  * `GET /audit/stream` SSE route — streams aren't an action-kind, so they
8
8
  * stay on REST. The event payload broadcast on the stream surfaces via
9
- * `AUDIT_LOG_EVENT_SPECS` (one `EventSpec` per audit event type) declared
9
+ * `audit_log_event_specs` (one `EventSpec` per audit event type) declared
10
10
  * alongside the broadcaster in `../realtime/sse_auth_guard.ts`.
11
11
  *
12
12
  * @module
@@ -6,7 +6,7 @@
6
6
  * `admin_session_list` on the same file. What remains here is the optional
7
7
  * `GET /audit/stream` SSE route — streams aren't an action-kind, so they
8
8
  * stay on REST. The event payload broadcast on the stream surfaces via
9
- * `AUDIT_LOG_EVENT_SPECS` (one `EventSpec` per audit event type) declared
9
+ * `audit_log_event_specs` (one `EventSpec` per audit event type) declared
10
10
  * alongside the broadcaster in `../realtime/sse_auth_guard.ts`.
11
11
  *
12
12
  * @module
@@ -64,7 +64,7 @@ export type AuditOutcome = z.infer<typeof AuditOutcome>;
64
64
  * stub schema); the Zod schemas themselves are reachable and mutable —
65
65
  * freeze isn't a security boundary.
66
66
  */
67
- export declare const AUDIT_METADATA_SCHEMAS: Readonly<{
67
+ export declare const audit_metadata_schemas: Readonly<{
68
68
  login: z.ZodNullable<z.ZodObject<{
69
69
  username: z.ZodString;
70
70
  }, z.core.$loose>>;
@@ -175,7 +175,7 @@ export declare const AUDIT_METADATA_SCHEMAS: Readonly<{
175
175
  }>;
176
176
  /** Mapped type of metadata shapes per event type, derived from Zod schemas. */
177
177
  export type AuditMetadataMap = {
178
- [K in AuditEventType]: z.infer<(typeof AUDIT_METADATA_SCHEMAS)[K]>;
178
+ [K in AuditEventType]: z.infer<(typeof audit_metadata_schemas)[K]>;
179
179
  };
180
180
  /** Audit log row from the database. See `AuditLogEventJson` for `event_type` widening rationale. */
181
181
  export interface AuditLogEvent {
@@ -270,7 +270,7 @@ export interface AuditLogInput<T extends string = AuditEventType> {
270
270
  * Lets consumers extend the closed `AUDIT_EVENT_TYPES` enum with their own
271
271
  * event strings (and metadata Zod schemas) without forking. Pass to
272
272
  * `create_audit_emitter` (or `query_audit_log` for in-tx call sites) as the
273
- * optional `config` argument; both default to `BUILTIN_AUDIT_LOG_CONFIG`.
273
+ * optional `config` argument; both default to `builtin_audit_log_config`.
274
274
  *
275
275
  * The DB column is `TEXT NOT NULL` and never enforced an enum, so consumer
276
276
  * event types round-trip through `query_audit_log_list` and SSE identically
@@ -291,7 +291,7 @@ export interface AuditLogConfig {
291
291
  readonly metadata_schemas: Readonly<Record<string, z.ZodType>>;
292
292
  }
293
293
  /** Builtin fuz_app audit-log config — every existing event type and its metadata schema. */
294
- export declare const BUILTIN_AUDIT_LOG_CONFIG: AuditLogConfig;
294
+ export declare const builtin_audit_log_config: AuditLogConfig;
295
295
  /** Options for `create_audit_log_config`. */
296
296
  export interface CreateAuditLogConfigOptions {
297
297
  /**
@@ -313,7 +313,7 @@ export interface CreateAuditLogConfigOptions {
313
313
  *
314
314
  * Call once at startup; pass the result to `create_app_backend` (which
315
315
  * threads it into `AppDeps.audit`). Builtin handlers omit the
316
- * `audit_log_config` slot and pick up `BUILTIN_AUDIT_LOG_CONFIG`.
316
+ * `audit_log_config` slot and pick up `builtin_audit_log_config`.
317
317
  *
318
318
  * @throws Error when an `extra_events` key collides with a builtin event type or fails `AuditEventTypeName` format validation
319
319
  */
@@ -64,7 +64,7 @@ export const AuditOutcome = z.enum(['success', 'failure']);
64
64
  * stub schema); the Zod schemas themselves are reachable and mutable —
65
65
  * freeze isn't a security boundary.
66
66
  */
67
- export const AUDIT_METADATA_SCHEMAS = Object.freeze({
67
+ export const audit_metadata_schemas = Object.freeze({
68
68
  login: z
69
69
  .looseObject({
70
70
  username: z.string().meta({ description: 'Username submitted with the login attempt.' }),
@@ -265,9 +265,9 @@ export const get_audit_metadata = (event) => {
265
265
  return event.metadata;
266
266
  };
267
267
  /** Builtin fuz_app audit-log config — every existing event type and its metadata schema. */
268
- export const BUILTIN_AUDIT_LOG_CONFIG = Object.freeze({
268
+ export const builtin_audit_log_config = Object.freeze({
269
269
  event_types: AUDIT_EVENT_TYPES,
270
- metadata_schemas: AUDIT_METADATA_SCHEMAS,
270
+ metadata_schemas: audit_metadata_schemas,
271
271
  });
272
272
  /**
273
273
  * Build an `AuditLogConfig` by merging fuz_app builtins with consumer extras.
@@ -277,20 +277,20 @@ export const BUILTIN_AUDIT_LOG_CONFIG = Object.freeze({
277
277
  *
278
278
  * Call once at startup; pass the result to `create_app_backend` (which
279
279
  * threads it into `AppDeps.audit`). Builtin handlers omit the
280
- * `audit_log_config` slot and pick up `BUILTIN_AUDIT_LOG_CONFIG`.
280
+ * `audit_log_config` slot and pick up `builtin_audit_log_config`.
281
281
  *
282
282
  * @throws Error when an `extra_events` key collides with a builtin event type or fails `AuditEventTypeName` format validation
283
283
  */
284
284
  export const create_audit_log_config = (options) => {
285
285
  const extras = options?.extra_events;
286
286
  if (!extras)
287
- return BUILTIN_AUDIT_LOG_CONFIG;
287
+ return builtin_audit_log_config;
288
288
  const extra_entries = Object.entries(extras);
289
289
  if (extra_entries.length === 0)
290
- return BUILTIN_AUDIT_LOG_CONFIG;
290
+ return builtin_audit_log_config;
291
291
  const builtin_set = new Set(AUDIT_EVENT_TYPES);
292
292
  const extra_keys = [];
293
- const metadata_schemas = { ...AUDIT_METADATA_SCHEMAS };
293
+ const metadata_schemas = { ...audit_metadata_schemas };
294
294
  for (const [t, schema] of extra_entries) {
295
295
  if (builtin_set.has(t)) {
296
296
  throw new Error(`extra_events key "${t}" collides with a builtin event type — pick a distinct string (e.g. "app_${t}")`);
@@ -12,6 +12,13 @@
12
12
  export declare const ACCOUNT_SCHEMA = "\nCREATE TABLE IF NOT EXISTS account (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n username TEXT UNIQUE NOT NULL,\n email TEXT,\n email_verified BOOLEAN NOT NULL DEFAULT false,\n password_hash TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n created_by UUID,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_by UUID\n)";
13
13
  export declare const ACTOR_SCHEMA = "\nCREATE TABLE IF NOT EXISTS actor (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n account_id UUID NOT NULL REFERENCES account(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ,\n updated_by UUID REFERENCES actor(id) ON DELETE SET NULL\n)";
14
14
  export declare const ACTOR_INDEX = "\nCREATE INDEX IF NOT EXISTS idx_actor_account ON actor(account_id)";
15
+ /**
16
+ * Functional index on `LOWER(actor.name)` supporting case-insensitive
17
+ * prefix search by `actor_search` (`LOWER(name) LIKE LOWER(query) || '%'`).
18
+ * `text_pattern_ops` keeps the LIKE-prefix pattern index-eligible — without
19
+ * it the planner falls back to a sequential scan once the table grows.
20
+ */
21
+ export declare const ACTOR_NAME_LOWER_INDEX = "\nCREATE INDEX IF NOT EXISTS idx_actor_name_lower ON actor (LOWER(name) text_pattern_ops)";
15
22
  export declare const ROLE_GRANT_SCHEMA = "\nCREATE TABLE IF NOT EXISTS role_grant (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n actor_id UUID NOT NULL REFERENCES actor(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMPTZ,\n revoked_at TIMESTAMPTZ,\n revoked_by UUID REFERENCES actor(id) ON DELETE SET NULL,\n granted_by UUID REFERENCES actor(id) ON DELETE SET NULL\n)";
16
23
  export declare const ROLE_GRANT_INDEXES: string[];
17
24
  export declare const AUTH_SESSION_SCHEMA = "\nCREATE TABLE IF NOT EXISTS auth_session (\n id TEXT PRIMARY KEY,\n account_id UUID NOT NULL REFERENCES account(id) ON DELETE CASCADE,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMPTZ NOT NULL,\n last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n)";
@@ -1 +1 @@
1
- {"version":3,"file":"auth_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/auth_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,cAAc,8WAWzB,CAAC;AAEH,eAAO,MAAM,YAAY,mUAQvB,CAAC;AAEH,eAAO,MAAM,WAAW,wEAC0C,CAAC;AAEnE,eAAO,MAAM,iBAAiB,2ZAU5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,UAI9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,0RAO9B,CAAC;AAEH,eAAO,MAAM,oBAAoB,UAGhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,iUAU3B,CAAC;AAEH,eAAO,MAAM,mBAAmB,4GACsE,CAAC;AAEvG,eAAO,MAAM,yBAAyB,6FACiD,CAAC;AAExF,eAAO,MAAM,eAAe,gFAC8C,CAAC;AAE3E,eAAO,MAAM,qBAAqB,wJAIhC,CAAC;AAEH,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,yHAGP,CAAC;AAE1B,eAAO,MAAM,aAAa,6ZAUxB,CAAC;AAEH,eAAO,MAAM,cAAc,UAI1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,oMAM9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,sEACkC,CAAC"}
1
+ {"version":3,"file":"auth_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/auth_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,cAAc,8WAWzB,CAAC;AAEH,eAAO,MAAM,YAAY,mUAQvB,CAAC;AAEH,eAAO,MAAM,WAAW,wEAC0C,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,8FACqD,CAAC;AAEzF,eAAO,MAAM,iBAAiB,2ZAU5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,UAI9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,0RAO9B,CAAC;AAEH,eAAO,MAAM,oBAAoB,UAGhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,iUAU3B,CAAC;AAEH,eAAO,MAAM,mBAAmB,4GACsE,CAAC;AAEvG,eAAO,MAAM,yBAAyB,6FACiD,CAAC;AAExF,eAAO,MAAM,eAAe,gFAC8C,CAAC;AAE3E,eAAO,MAAM,qBAAqB,wJAIhC,CAAC;AAEH,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,yHAGP,CAAC;AAE1B,eAAO,MAAM,aAAa,6ZAUxB,CAAC;AAEH,eAAO,MAAM,cAAc,UAI1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,oMAM9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,sEACkC,CAAC"}
@@ -32,6 +32,14 @@ CREATE TABLE IF NOT EXISTS actor (
32
32
  )`;
33
33
  export const ACTOR_INDEX = `
34
34
  CREATE INDEX IF NOT EXISTS idx_actor_account ON actor(account_id)`;
35
+ /**
36
+ * Functional index on `LOWER(actor.name)` supporting case-insensitive
37
+ * prefix search by `actor_search` (`LOWER(name) LIKE LOWER(query) || '%'`).
38
+ * `text_pattern_ops` keeps the LIKE-prefix pattern index-eligible — without
39
+ * it the planner falls back to a sequential scan once the table grows.
40
+ */
41
+ export const ACTOR_NAME_LOWER_INDEX = `
42
+ CREATE INDEX IF NOT EXISTS idx_actor_name_lower ON actor (LOWER(name) text_pattern_ops)`;
35
43
  export const ROLE_GRANT_SCHEMA = `
36
44
  CREATE TABLE IF NOT EXISTS role_grant (
37
45
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -67,7 +67,7 @@ export interface CredentialTypeMeta {
67
67
  * here. Read once at startup by `create_credential_type_schema`;
68
68
  * runtime mutation has no effect on already-built schemas.
69
69
  */
70
- export declare const BUILTIN_CREDENTIAL_TYPE_META: ReadonlyMap<string, CredentialTypeMeta>;
70
+ export declare const builtin_credential_type_meta: ReadonlyMap<string, CredentialTypeMeta>;
71
71
  /** The result of `create_credential_type_schema` — a Zod schema and metadata map. */
72
72
  export interface CredentialTypeSchemaResult {
73
73
  /**
@@ -60,7 +60,7 @@ export const BuiltinCredentialType = z.enum(BUILTIN_CREDENTIAL_TYPES);
60
60
  * here. Read once at startup by `create_credential_type_schema`;
61
61
  * runtime mutation has no effect on already-built schemas.
62
62
  */
63
- export const BUILTIN_CREDENTIAL_TYPE_META = new Map([
63
+ export const builtin_credential_type_meta = new Map([
64
64
  [
65
65
  CREDENTIAL_TYPE_SESSION,
66
66
  { description: 'Cookie-based session credential, signed and validated server-side.' },
@@ -109,7 +109,7 @@ export const create_credential_type_schema = (consumer_types = {}) => {
109
109
  if (!parsed.success) {
110
110
  throw new Error(`Invalid credential-type name "${name}": ${parsed.error.issues[0].message}`);
111
111
  }
112
- if (BUILTIN_CREDENTIAL_TYPE_META.has(name)) {
112
+ if (builtin_credential_type_meta.has(name)) {
113
113
  throw new Error(`Consumer credential-type "${name}" collides with builtin credential-type`);
114
114
  }
115
115
  if (seen.has(name)) {
@@ -119,7 +119,7 @@ export const create_credential_type_schema = (consumer_types = {}) => {
119
119
  }
120
120
  const all_names = [...BUILTIN_CREDENTIAL_TYPES, ...consumer_names];
121
121
  const CredentialType = z.enum(all_names);
122
- const credential_types = new Map(BUILTIN_CREDENTIAL_TYPE_META);
122
+ const credential_types = new Map(builtin_credential_type_meta);
123
123
  for (const name of consumer_names) {
124
124
  credential_types.set(name, consumer_types[name]);
125
125
  }
@@ -70,7 +70,7 @@ export interface GrantPathMeta {
70
70
  * here. Read once at startup by `create_grant_path_schema`; runtime
71
71
  * mutation has no effect on already-built schemas.
72
72
  */
73
- export declare const BUILTIN_GRANT_PATH_META: ReadonlyMap<string, GrantPathMeta>;
73
+ export declare const builtin_grant_path_meta: ReadonlyMap<string, GrantPathMeta>;
74
74
  /** The result of `create_grant_path_schema` — a Zod schema and metadata map. */
75
75
  export interface GrantPathSchemaResult {
76
76
  /**
@@ -63,7 +63,7 @@ export const BuiltinGrantPath = z.enum(BUILTIN_GRANT_PATHS);
63
63
  * here. Read once at startup by `create_grant_path_schema`; runtime
64
64
  * mutation has no effect on already-built schemas.
65
65
  */
66
- export const BUILTIN_GRANT_PATH_META = new Map([
66
+ export const builtin_grant_path_meta = new Map([
67
67
  [
68
68
  GRANT_PATH_ADMIN,
69
69
  {
@@ -119,7 +119,7 @@ export const create_grant_path_schema = (consumer_paths = {}) => {
119
119
  if (!parsed.success) {
120
120
  throw new Error(`Invalid grant-path name "${name}": ${parsed.error.issues[0].message}`);
121
121
  }
122
- if (BUILTIN_GRANT_PATH_META.has(name)) {
122
+ if (builtin_grant_path_meta.has(name)) {
123
123
  throw new Error(`Consumer grant-path "${name}" collides with builtin grant-path`);
124
124
  }
125
125
  if (seen.has(name)) {
@@ -129,7 +129,7 @@ export const create_grant_path_schema = (consumer_paths = {}) => {
129
129
  }
130
130
  const all_names = [...BUILTIN_GRANT_PATHS, ...consumer_names];
131
131
  const GrantPath = z.enum(all_names);
132
- const grant_paths = new Map(BUILTIN_GRANT_PATH_META);
132
+ const grant_paths = new Map(builtin_grant_path_meta);
133
133
  for (const name of consumer_names) {
134
134
  grant_paths.set(name, consumer_paths[name]);
135
135
  }
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * To add a migration in the pre-stable phase, prefer extending an existing
19
19
  * entry's body (consumers will re-bootstrap on upgrade). If you do append
20
- * a new entry to `AUTH_MIGRATIONS`, the runner will apply it on existing
20
+ * a new entry to `auth_migrations`, the runner will apply it on existing
21
21
  * tracker rows — the same shape that will become mandatory once the
22
22
  * schema stabilizes:
23
23
  *
@@ -46,7 +46,7 @@ export declare const AUTH_MIGRATION_NAMESPACE = "fuz_auth";
46
46
  * as `ReadonlyArray<string>` (not a literal tuple) so `.includes()` accepts
47
47
  * any consumer-supplied namespace string without a cast.
48
48
  */
49
- export declare const RESERVED_MIGRATION_NAMESPACES: ReadonlyArray<string>;
49
+ export declare const reserved_migration_namespaces: ReadonlyArray<string>;
50
50
  /**
51
51
  * Auth schema migrations in order.
52
52
  *
@@ -67,7 +67,7 @@ export declare const RESERVED_MIGRATION_NAMESPACES: ReadonlyArray<string>;
67
67
  * (registry-membership validation against `create_scope_kind_schema`);
68
68
  * v2 may add INSERT-time `(role, scope_kind)` enforcement.
69
69
  */
70
- export declare const AUTH_MIGRATIONS: Array<Migration>;
70
+ export declare const auth_migrations: Array<Migration>;
71
71
  /** Pre-composed migration namespace for auth tables. */
72
- export declare const AUTH_MIGRATION_NS: MigrationNamespace;
72
+ export declare const auth_migration_ns: MigrationNamespace;
73
73
  //# sourceMappingURL=migrations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AA8BH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AAEpE,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,EAAE,aAAa,CAAC,MAAM,CAA8B,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAqF5C,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AA+BH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AAEpE,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,EAAE,aAAa,CAAC,MAAM,CAA8B,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAsF5C,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}