@fuzdev/fuz_app 0.58.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 (107) hide show
  1. package/dist/actions/CLAUDE.md +13 -8
  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 +215 -45
  11. package/dist/auth/account_action_specs.d.ts +9 -0
  12. package/dist/auth/account_action_specs.d.ts.map +1 -1
  13. package/dist/auth/account_action_specs.js +9 -0
  14. package/dist/auth/actor_lookup_action_specs.d.ts +127 -0
  15. package/dist/auth/actor_lookup_action_specs.d.ts.map +1 -0
  16. package/dist/auth/actor_lookup_action_specs.js +93 -0
  17. package/dist/auth/actor_lookup_actions.d.ts +19 -0
  18. package/dist/auth/actor_lookup_actions.d.ts.map +1 -0
  19. package/dist/auth/actor_lookup_actions.js +32 -0
  20. package/dist/auth/actor_lookup_queries.d.ts +44 -0
  21. package/dist/auth/actor_lookup_queries.d.ts.map +1 -0
  22. package/dist/auth/actor_lookup_queries.js +42 -0
  23. package/dist/auth/actor_search_action_specs.d.ts +166 -0
  24. package/dist/auth/actor_search_action_specs.d.ts.map +1 -0
  25. package/dist/auth/actor_search_action_specs.js +139 -0
  26. package/dist/auth/actor_search_actions.d.ts +31 -0
  27. package/dist/auth/actor_search_actions.d.ts.map +1 -0
  28. package/dist/auth/actor_search_actions.js +61 -0
  29. package/dist/auth/actor_search_queries.d.ts +75 -0
  30. package/dist/auth/actor_search_queries.d.ts.map +1 -0
  31. package/dist/auth/actor_search_queries.js +91 -0
  32. package/dist/auth/admin_action_specs.d.ts +35 -0
  33. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  34. package/dist/auth/admin_action_specs.js +35 -0
  35. package/dist/auth/admin_actions.js +2 -2
  36. package/dist/auth/all_action_spec_registries.d.ts +55 -0
  37. package/dist/auth/all_action_spec_registries.d.ts.map +1 -0
  38. package/dist/auth/all_action_spec_registries.js +59 -0
  39. package/dist/auth/audit_emitter.d.ts +1 -1
  40. package/dist/auth/audit_emitter.js +2 -2
  41. package/dist/auth/audit_log_queries.d.ts +1 -1
  42. package/dist/auth/audit_log_queries.js +3 -3
  43. package/dist/auth/audit_log_routes.d.ts +1 -1
  44. package/dist/auth/audit_log_routes.js +1 -1
  45. package/dist/auth/audit_log_schema.d.ts +5 -5
  46. package/dist/auth/audit_log_schema.js +7 -7
  47. package/dist/auth/auth_ddl.d.ts +7 -0
  48. package/dist/auth/auth_ddl.d.ts.map +1 -1
  49. package/dist/auth/auth_ddl.js +8 -0
  50. package/dist/auth/credential_type_schema.d.ts +1 -1
  51. package/dist/auth/credential_type_schema.js +3 -3
  52. package/dist/auth/grant_path_schema.d.ts +1 -1
  53. package/dist/auth/grant_path_schema.js +3 -3
  54. package/dist/auth/migrations.d.ts +4 -4
  55. package/dist/auth/migrations.d.ts.map +1 -1
  56. package/dist/auth/migrations.js +7 -6
  57. package/dist/auth/role_grant_offer_action_specs.d.ts +17 -0
  58. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
  59. package/dist/auth/role_grant_offer_action_specs.js +17 -0
  60. package/dist/auth/role_grant_offer_actions.js +2 -2
  61. package/dist/auth/role_grant_offer_notifications.d.ts +2 -2
  62. package/dist/auth/role_grant_offer_notifications.js +2 -2
  63. package/dist/auth/role_grant_queries.d.ts +21 -0
  64. package/dist/auth/role_grant_queries.d.ts.map +1 -1
  65. package/dist/auth/role_grant_queries.js +31 -0
  66. package/dist/auth/role_schema.d.ts +2 -2
  67. package/dist/auth/role_schema.js +3 -3
  68. package/dist/auth/self_service_role_action_specs.d.ts +8 -0
  69. package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
  70. package/dist/auth/self_service_role_action_specs.js +8 -0
  71. package/dist/auth/self_service_role_actions.d.ts +1 -1
  72. package/dist/auth/self_service_role_actions.js +2 -2
  73. package/dist/auth/session_cookie.d.ts +1 -1
  74. package/dist/auth/session_cookie.js +1 -1
  75. package/dist/auth/session_middleware.d.ts +1 -1
  76. package/dist/auth/session_middleware.js +5 -5
  77. package/dist/rate_limiter.d.ts +5 -5
  78. package/dist/rate_limiter.js +6 -6
  79. package/dist/realtime/sse_auth_guard.d.ts +3 -3
  80. package/dist/realtime/sse_auth_guard.js +4 -4
  81. package/dist/server/app_backend.d.ts +3 -3
  82. package/dist/server/app_backend.js +4 -4
  83. package/dist/server/app_server.d.ts +1 -1
  84. package/dist/server/app_server.js +10 -10
  85. package/dist/testing/CLAUDE.md +22 -12
  86. package/dist/testing/admin_integration.js +4 -4
  87. package/dist/testing/app_server.d.ts +1 -1
  88. package/dist/testing/app_server.js +2 -2
  89. package/dist/testing/attack_surface.d.ts +4 -4
  90. package/dist/testing/attack_surface.js +6 -6
  91. package/dist/testing/audit_completeness.js +4 -4
  92. package/dist/testing/data_exposure.d.ts +2 -2
  93. package/dist/testing/data_exposure.js +7 -7
  94. package/dist/testing/db.d.ts +8 -8
  95. package/dist/testing/db.js +11 -11
  96. package/dist/testing/integration.js +4 -4
  97. package/dist/testing/integration_helpers.d.ts +6 -6
  98. package/dist/testing/integration_helpers.js +7 -7
  99. package/dist/testing/rate_limiting.js +4 -4
  100. package/dist/testing/round_trip.js +2 -2
  101. package/dist/testing/rpc_round_trip.js +2 -2
  102. package/dist/testing/schema_generators.d.ts.map +1 -1
  103. package/dist/testing/schema_generators.js +23 -2
  104. package/dist/testing/sse_round_trip.js +2 -2
  105. package/dist/testing/surface_invariants.d.ts +4 -4
  106. package/dist/testing/surface_invariants.js +5 -5
  107. 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
+ };
@@ -264,6 +264,12 @@ export declare const AppSettingsUpdateOutput: z.ZodObject<{
264
264
  }, z.core.$strict>;
265
265
  }, z.core.$strict>;
266
266
  export type AppSettingsUpdateOutput = z.infer<typeof AppSettingsUpdateOutput>;
267
+ /**
268
+ * `rate_limit: 'account'` bounds admin-side scraping of the account table
269
+ * via `(limit, offset)` walking — admin trust is not a substitute for a
270
+ * read-rate cap when the listing is paginated and cross-account (yields
271
+ * every account + actor + active role_grant in the system).
272
+ */
267
273
  export declare const admin_account_list_action_spec: {
268
274
  method: string;
269
275
  kind: "request_response";
@@ -318,7 +324,13 @@ export declare const admin_account_list_action_spec: {
318
324
  }, z.core.$strict>;
319
325
  async: true;
320
326
  description: string;
327
+ rate_limit: "account";
321
328
  };
329
+ /**
330
+ * `rate_limit: 'account'` bounds cross-account scraping of every active
331
+ * `auth_session` row — no pagination, but the read is unbounded across
332
+ * accounts and reveals one row per live cookie globally.
333
+ */
322
334
  export declare const admin_session_list_action_spec: {
323
335
  method: string;
324
336
  kind: "request_response";
@@ -344,6 +356,7 @@ export declare const admin_session_list_action_spec: {
344
356
  }, z.core.$strict>;
345
357
  async: true;
346
358
  description: string;
359
+ rate_limit: "account";
347
360
  };
348
361
  export declare const admin_session_revoke_all_action_spec: {
349
362
  method: string;
@@ -389,6 +402,14 @@ export declare const admin_token_revoke_all_action_spec: {
389
402
  description: string;
390
403
  rate_limit: "account";
391
404
  };
405
+ /**
406
+ * `rate_limit: 'account'` bounds admin-side enumeration of the entire
407
+ * audit log via `(limit, offset)` walking — same shape as
408
+ * `admin_account_list_action_spec`. The listing carries cross-account
409
+ * forensic detail (target ids, IPs, metadata), so the read-rate cap is
410
+ * the only check that distinguishes a human reviewer from a scraping
411
+ * script.
412
+ */
392
413
  export declare const audit_log_list_action_spec: {
393
414
  method: string;
394
415
  kind: "request_response";
@@ -433,7 +454,13 @@ export declare const audit_log_list_action_spec: {
433
454
  }, z.core.$strict>;
434
455
  async: true;
435
456
  description: string;
457
+ rate_limit: "account";
436
458
  };
459
+ /**
460
+ * `rate_limit: 'account'` bounds admin-side enumeration of the role_grant
461
+ * history via `(limit, offset)` walking — same shape as `audit_log_list`,
462
+ * narrower projection but identical scraping vector.
463
+ */
437
464
  export declare const audit_log_role_grant_history_action_spec: {
438
465
  method: string;
439
466
  kind: "request_response";
@@ -471,6 +498,7 @@ export declare const audit_log_role_grant_history_action_spec: {
471
498
  }, z.core.$strict>;
472
499
  async: true;
473
500
  description: string;
501
+ rate_limit: "account";
474
502
  };
475
503
  export declare const invite_create_action_spec: {
476
504
  method: string;
@@ -503,6 +531,12 @@ export declare const invite_create_action_spec: {
503
531
  description: string;
504
532
  rate_limit: "account";
505
533
  };
534
+ /**
535
+ * `rate_limit: 'account'` bounds admin-side scraping of the invite table —
536
+ * bounded by table size, but every row carries email + username +
537
+ * creator/claimer identifiers worth defense-in-depth against an admin
538
+ * mutation oracle running scripted reads alongside `invite_create`.
539
+ */
506
540
  export declare const invite_list_action_spec: {
507
541
  method: string;
508
542
  kind: "request_response";
@@ -531,6 +565,7 @@ export declare const invite_list_action_spec: {
531
565
  }, z.core.$strict>;
532
566
  async: true;
533
567
  description: string;
568
+ rate_limit: "account";
534
569
  };
535
570
  export declare const invite_delete_action_spec: {
536
571
  method: string;
@@ -1 +1 @@
1
- {"version":3,"file":"admin_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_action_specs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"admin_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_action_specs.ts"],"names":[],"mappings":"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"}
@@ -193,6 +193,12 @@ export const AppSettingsUpdateOutput = z.strictObject({
193
193
  settings: AppSettingsWithUsernameJson,
194
194
  });
195
195
  // -- Action specs -----------------------------------------------------------
196
+ /**
197
+ * `rate_limit: 'account'` bounds admin-side scraping of the account table
198
+ * via `(limit, offset)` walking — admin trust is not a substitute for a
199
+ * read-rate cap when the listing is paginated and cross-account (yields
200
+ * every account + actor + active role_grant in the system).
201
+ */
196
202
  export const admin_account_list_action_spec = {
197
203
  method: 'admin_account_list',
198
204
  kind: 'request_response',
@@ -203,7 +209,13 @@ export const admin_account_list_action_spec = {
203
209
  output: AdminAccountListOutput,
204
210
  async: true,
205
211
  description: 'List all accounts with their actors, role_grants, and pending offers. Admin-only.',
212
+ rate_limit: 'account',
206
213
  };
214
+ /**
215
+ * `rate_limit: 'account'` bounds cross-account scraping of every active
216
+ * `auth_session` row — no pagination, but the read is unbounded across
217
+ * accounts and reveals one row per live cookie globally.
218
+ */
207
219
  export const admin_session_list_action_spec = {
208
220
  method: 'admin_session_list',
209
221
  kind: 'request_response',
@@ -214,6 +226,7 @@ export const admin_session_list_action_spec = {
214
226
  output: AdminSessionListOutput,
215
227
  async: true,
216
228
  description: 'List every active auth session across all accounts. Admin-only.',
229
+ rate_limit: 'account',
217
230
  };
218
231
  export const admin_session_revoke_all_action_spec = {
219
232
  method: 'admin_session_revoke_all',
@@ -239,6 +252,14 @@ export const admin_token_revoke_all_action_spec = {
239
252
  description: 'Revoke all API tokens for an account. Admin-only.',
240
253
  rate_limit: 'account',
241
254
  };
255
+ /**
256
+ * `rate_limit: 'account'` bounds admin-side enumeration of the entire
257
+ * audit log via `(limit, offset)` walking — same shape as
258
+ * `admin_account_list_action_spec`. The listing carries cross-account
259
+ * forensic detail (target ids, IPs, metadata), so the read-rate cap is
260
+ * the only check that distinguishes a human reviewer from a scraping
261
+ * script.
262
+ */
242
263
  export const audit_log_list_action_spec = {
243
264
  method: 'audit_log_list',
244
265
  kind: 'request_response',
@@ -249,7 +270,13 @@ export const audit_log_list_action_spec = {
249
270
  output: AuditLogListOutput,
250
271
  async: true,
251
272
  description: 'List audit log events with optional filters. Admin-only.',
273
+ rate_limit: 'account',
252
274
  };
275
+ /**
276
+ * `rate_limit: 'account'` bounds admin-side enumeration of the role_grant
277
+ * history via `(limit, offset)` walking — same shape as `audit_log_list`,
278
+ * narrower projection but identical scraping vector.
279
+ */
253
280
  export const audit_log_role_grant_history_action_spec = {
254
281
  method: 'audit_log_role_grant_history',
255
282
  kind: 'request_response',
@@ -260,6 +287,7 @@ export const audit_log_role_grant_history_action_spec = {
260
287
  output: AuditLogRoleGrantHistoryOutput,
261
288
  async: true,
262
289
  description: 'List role_grant grant and revoke events with usernames. Admin-only.',
290
+ rate_limit: 'account',
263
291
  };
264
292
  export const invite_create_action_spec = {
265
293
  method: 'invite_create',
@@ -273,6 +301,12 @@ export const invite_create_action_spec = {
273
301
  description: 'Create an invite addressed to an email, username, or both. Admin-only.',
274
302
  rate_limit: 'account',
275
303
  };
304
+ /**
305
+ * `rate_limit: 'account'` bounds admin-side scraping of the invite table —
306
+ * bounded by table size, but every row carries email + username +
307
+ * creator/claimer identifiers worth defense-in-depth against an admin
308
+ * mutation oracle running scripted reads alongside `invite_create`.
309
+ */
276
310
  export const invite_list_action_spec = {
277
311
  method: 'invite_list',
278
312
  kind: 'request_response',
@@ -283,6 +317,7 @@ export const invite_list_action_spec = {
283
317
  output: InviteListOutput,
284
318
  async: true,
285
319
  description: 'List all invites with creator and claimer usernames. Admin-only.',
320
+ rate_limit: 'account',
286
321
  };
287
322
  export const invite_delete_action_spec = {
288
323
  method: 'invite_delete',
@@ -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
  */