@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
@@ -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"}
@@ -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
  *
@@ -36,7 +36,7 @@
36
36
  *
37
37
  * @module
38
38
  */
39
- import { ACCOUNT_SCHEMA, ACCOUNT_EMAIL_INDEX, ACCOUNT_USERNAME_CI_INDEX, ACTOR_SCHEMA, ACTOR_INDEX, ROLE_GRANT_SCHEMA, ROLE_GRANT_INDEXES, AUTH_SESSION_SCHEMA, AUTH_SESSION_INDEXES, API_TOKEN_SCHEMA, API_TOKEN_INDEX, BOOTSTRAP_LOCK_SCHEMA, BOOTSTRAP_LOCK_SEED, INVITE_SCHEMA, INVITE_INDEXES, APP_SETTINGS_SCHEMA, APP_SETTINGS_SEED, } from './auth_ddl.js';
39
+ import { ACCOUNT_SCHEMA, ACCOUNT_EMAIL_INDEX, ACCOUNT_USERNAME_CI_INDEX, ACTOR_SCHEMA, ACTOR_INDEX, ACTOR_NAME_LOWER_INDEX, ROLE_GRANT_SCHEMA, ROLE_GRANT_INDEXES, AUTH_SESSION_SCHEMA, AUTH_SESSION_INDEXES, API_TOKEN_SCHEMA, API_TOKEN_INDEX, BOOTSTRAP_LOCK_SCHEMA, BOOTSTRAP_LOCK_SEED, INVITE_SCHEMA, INVITE_INDEXES, APP_SETTINGS_SCHEMA, APP_SETTINGS_SEED, } from './auth_ddl.js';
40
40
  import { AUDIT_LOG_SCHEMA, AUDIT_LOG_INDEXES } from './audit_log_ddl.js';
41
41
  import { ROLE_GRANT_OFFER_SCHEMA, ROLE_GRANT_OFFER_PENDING_UNIQUE_INDEX, ROLE_GRANT_OFFER_INBOX_INDEX, ROLE_GRANT_OFFER_SCOPE_SENTINEL_UUID, ROLE_GRANT_OFFER_SCOPE_KIND_GLOBAL_TOKEN, } from './role_grant_offer_ddl.js';
42
42
  /** Namespace identifier for fuz_app auth migrations. */
@@ -48,7 +48,7 @@ export const AUTH_MIGRATION_NAMESPACE = 'fuz_auth';
48
48
  * as `ReadonlyArray<string>` (not a literal tuple) so `.includes()` accepts
49
49
  * any consumer-supplied namespace string without a cast.
50
50
  */
51
- export const RESERVED_MIGRATION_NAMESPACES = [AUTH_MIGRATION_NAMESPACE];
51
+ export const reserved_migration_namespaces = [AUTH_MIGRATION_NAMESPACE];
52
52
  /**
53
53
  * Auth schema migrations in order.
54
54
  *
@@ -69,7 +69,7 @@ export const RESERVED_MIGRATION_NAMESPACES = [AUTH_MIGRATION_NAMESPACE];
69
69
  * (registry-membership validation against `create_scope_kind_schema`);
70
70
  * v2 may add INSERT-time `(role, scope_kind)` enforcement.
71
71
  */
72
- export const AUTH_MIGRATIONS = [
72
+ export const auth_migrations = [
73
73
  // v0: full auth schema — all IF NOT EXISTS, safe for existing databases
74
74
  {
75
75
  name: 'full_auth_schema',
@@ -79,6 +79,7 @@ export const AUTH_MIGRATIONS = [
79
79
  await db.query(ACCOUNT_USERNAME_CI_INDEX);
80
80
  await db.query(ACTOR_SCHEMA);
81
81
  await db.query(ACTOR_INDEX);
82
+ await db.query(ACTOR_NAME_LOWER_INDEX);
82
83
  await db.query(ROLE_GRANT_SCHEMA);
83
84
  for (const sql of ROLE_GRANT_INDEXES) {
84
85
  await db.query(sql);
@@ -150,7 +151,7 @@ export const AUTH_MIGRATIONS = [
150
151
  },
151
152
  ];
152
153
  /** Pre-composed migration namespace for auth tables. */
153
- export const AUTH_MIGRATION_NS = {
154
+ export const auth_migration_ns = {
154
155
  namespace: AUTH_MIGRATION_NAMESPACE,
155
- migrations: AUTH_MIGRATIONS,
156
+ migrations: auth_migrations,
156
157
  };
@@ -209,6 +209,16 @@ export declare const RoleGrantRevokeOutput: z.ZodObject<{
209
209
  revoked: z.ZodLiteral<true>;
210
210
  }, z.core.$strict>;
211
211
  export type RoleGrantRevokeOutput = z.infer<typeof RoleGrantRevokeOutput>;
212
+ /**
213
+ * `rate_limit: 'account'` throttles offer-spam at the authenticated
214
+ * grantor and bounds the account-existence oracle on `to_account_id` —
215
+ * the same shape as `invite_create_action_spec` upstream addresses, where
216
+ * a hostile authed caller iterates recipients to probe
217
+ * `ERROR_ACCOUNT_NOT_FOUND` (and the actor-binding via
218
+ * `ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`) as an enumeration
219
+ * vector. Failure-outcome audit rows preserve the forensic trail; the
220
+ * rate cap closes the budget.
221
+ */
212
222
  export declare const role_grant_offer_create_action_spec: {
213
223
  method: string;
214
224
  kind: "request_response";
@@ -250,6 +260,7 @@ export declare const role_grant_offer_create_action_spec: {
250
260
  async: true;
251
261
  description: string;
252
262
  error_reasons: ("role_grant_offer_self_target" | "role_grant_offer_role_not_grantable" | "role_grant_offer_not_authorized" | "role_grant_offer_actor_account_mismatch")[];
263
+ rate_limit: "account";
253
264
  };
254
265
  export declare const role_grant_offer_accept_action_spec: {
255
266
  method: string;
@@ -405,6 +416,12 @@ export declare const role_grant_offer_history_action_spec: {
405
416
  async: true;
406
417
  description: string;
407
418
  };
419
+ /**
420
+ * `rate_limit: 'account'` bounds admin-side burn of `role_grant_revoke` —
421
+ * the action is admin-gated and audit-trailed, but the per-account cap
422
+ * keeps a single admin script from churning role_grants in a loop and
423
+ * obscuring audit context for unrelated activity.
424
+ */
408
425
  export declare const role_grant_revoke_action_spec: {
409
426
  method: string;
410
427
  kind: "request_response";
@@ -1 +1 @@
1
- {"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"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"}
@@ -157,6 +157,16 @@ export const RoleGrantRevokeOutput = z.strictObject({
157
157
  revoked: z.literal(true),
158
158
  });
159
159
  // -- Action specs -----------------------------------------------------------
160
+ /**
161
+ * `rate_limit: 'account'` throttles offer-spam at the authenticated
162
+ * grantor and bounds the account-existence oracle on `to_account_id` —
163
+ * the same shape as `invite_create_action_spec` upstream addresses, where
164
+ * a hostile authed caller iterates recipients to probe
165
+ * `ERROR_ACCOUNT_NOT_FOUND` (and the actor-binding via
166
+ * `ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`) as an enumeration
167
+ * vector. Failure-outcome audit rows preserve the forensic trail; the
168
+ * rate cap closes the budget.
169
+ */
160
170
  export const role_grant_offer_create_action_spec = {
161
171
  method: 'role_grant_offer_create',
162
172
  kind: 'request_response',
@@ -173,6 +183,7 @@ export const role_grant_offer_create_action_spec = {
173
183
  ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED,
174
184
  ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH,
175
185
  ],
186
+ rate_limit: 'account',
176
187
  };
177
188
  export const role_grant_offer_accept_action_spec = {
178
189
  method: 'role_grant_offer_accept',
@@ -237,6 +248,12 @@ export const role_grant_offer_history_action_spec = {
237
248
  async: true,
238
249
  description: 'List every offer involving the caller (either direction), including terminal rows, newest first. Admins may pass `account_id` to inspect another account.',
239
250
  };
251
+ /**
252
+ * `rate_limit: 'account'` bounds admin-side burn of `role_grant_revoke` —
253
+ * the action is admin-gated and audit-trailed, but the per-account cap
254
+ * keeps a single admin script from churning role_grants in a loop and
255
+ * obscuring audit context for unrelated activity.
256
+ */
240
257
  export const role_grant_revoke_action_spec = {
241
258
  method: 'role_grant_revoke',
242
259
  kind: 'request_response',
@@ -40,7 +40,7 @@
40
40
  import { rpc_action, } from '../actions/action_rpc.js';
41
41
  import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
42
42
  import { emit_after_commit } from '../http/pending_effects.js';
43
- import { BUILTIN_ROLE_SPECS_BY_NAME, ROLE_ADMIN, role_has_grant_path, } from './role_schema.js';
43
+ import { builtin_role_specs_by_name, ROLE_ADMIN, role_has_grant_path, } from './role_schema.js';
44
44
  import { GRANT_PATH_ADMIN } from './grant_path_schema.js';
45
45
  import { ROLE_GRANT_OFFER_DEFAULT_TTL_MS, to_role_grant_offer_json, } from './role_grant_offer_schema.js';
46
46
  import { query_role_grant_offer_create, query_role_grant_offer_decline, query_role_grant_offer_retract, query_role_grant_offer_list, query_role_grant_offer_history_for_account, query_accept_offer, RoleGrantOfferActorAccountMismatchError, RoleGrantOfferActorMismatchError, RoleGrantOfferAlreadyTerminalError, RoleGrantOfferExpiredError, RoleGrantOfferNotFoundError, RoleGrantOfferSelfTargetError, } from './role_grant_offer_queries.js';
@@ -108,7 +108,7 @@ export const authorize_admin_or_holder = async (auth, input, _deps, _ctx) => {
108
108
  */
109
109
  export const create_role_grant_offer_actions = (deps, options = {}) => {
110
110
  const { log, audit, notification_sender = null } = deps;
111
- const role_specs = options.roles?.role_specs ?? BUILTIN_ROLE_SPECS_BY_NAME;
111
+ const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
112
112
  const default_ttl_ms = options.default_ttl_ms ?? ROLE_GRANT_OFFER_DEFAULT_TTL_MS;
113
113
  const authorize = options.authorize ?? default_authorize;
114
114
  // Four denial paths (admin-grant-path gate, authorize, self-target,
@@ -23,7 +23,7 @@
23
23
  * `NotificationSender.send_to_account` argument), not in the payload.
24
24
  *
25
25
  * The specs surface as `EventSpec`s via `create_action_event_spec` — callers
26
- * append `ROLE_GRANT_OFFER_NOTIFICATION_SPECS` to their `event_specs` on
26
+ * append `role_grant_offer_notification_specs` to their `event_specs` on
27
27
  * `create_app_server` so the surface reflects them and DEV-mode broadcast
28
28
  * validation catches payload drift.
29
29
  *
@@ -376,7 +376,7 @@ export declare const role_grant_revoke_notification_spec: {
376
376
  * Pass to `create_app_server`'s `event_specs` so the attack surface reflects
377
377
  * them and DEV-mode `create_validated_broadcaster` catches payload drift.
378
378
  */
379
- export declare const ROLE_GRANT_OFFER_NOTIFICATION_SPECS: Array<EventSpec>;
379
+ export declare const role_grant_offer_notification_specs: Array<EventSpec>;
380
380
  export declare const build_role_grant_offer_received_notification: (params: RoleGrantOfferReceivedParams) => JsonrpcNotification;
381
381
  export declare const build_role_grant_offer_retracted_notification: (params: RoleGrantOfferRetractedParams) => JsonrpcNotification;
382
382
  export declare const build_role_grant_offer_accepted_notification: (params: RoleGrantOfferAcceptedParams) => JsonrpcNotification;
@@ -23,7 +23,7 @@
23
23
  * `NotificationSender.send_to_account` argument), not in the payload.
24
24
  *
25
25
  * The specs surface as `EventSpec`s via `create_action_event_spec` — callers
26
- * append `ROLE_GRANT_OFFER_NOTIFICATION_SPECS` to their `event_specs` on
26
+ * append `role_grant_offer_notification_specs` to their `event_specs` on
27
27
  * `create_app_server` so the surface reflects them and DEV-mode broadcast
28
28
  * validation catches payload drift.
29
29
  *
@@ -165,7 +165,7 @@ export const role_grant_revoke_notification_spec = {
165
165
  * Pass to `create_app_server`'s `event_specs` so the attack surface reflects
166
166
  * them and DEV-mode `create_validated_broadcaster` catches payload drift.
167
167
  */
168
- export const ROLE_GRANT_OFFER_NOTIFICATION_SPECS = [
168
+ export const role_grant_offer_notification_specs = [
169
169
  create_action_event_spec(role_grant_offer_received_notification_spec),
170
170
  create_action_event_spec(role_grant_offer_retracted_notification_spec),
171
171
  create_action_event_spec(role_grant_offer_accepted_notification_spec),
@@ -113,6 +113,27 @@ export declare const query_role_grant_find_active_for_actor: (deps: QueryDeps, a
113
113
  * The `IS NOT DISTINCT FROM` comparison handles the NULL case uniformly.
114
114
  */
115
115
  export declare const query_role_grant_has_role: (deps: QueryDeps, actor_id: string, role: string, scope_id?: string | null) => Promise<boolean>;
116
+ /**
117
+ * Account-grain check: does any actor on `account_id` hold an active
118
+ * global role_grant for `role`?
119
+ *
120
+ * Symmetric with `query_role_grant_has_role` but keyed on the account
121
+ * instead of a single actor — for surfaces with `auth: actor: 'none'`
122
+ * that don't load `auth.role_grants` and can't use the in-memory
123
+ * `has_scoped_role` predicate. Joins `role_grant` → `actor`; matches
124
+ * only global role_grants (`scope_id IS NULL`) since the use case is
125
+ * "is the caller's account broadly admin", not scope-aware.
126
+ *
127
+ * Fast under the existing `idx_role_grant_actor` index — the inner
128
+ * `actor_id IN (...)` subquery is index-scan, and the outer EXISTS
129
+ * stops at the first match.
130
+ *
131
+ * @param deps - query dependencies
132
+ * @param account_id - the account to check
133
+ * @param role - the role to check for (e.g. `ROLE_ADMIN`)
134
+ * @returns `true` if any actor on the account has an active global role_grant for `role`
135
+ */
136
+ export declare const query_account_has_global_role: (deps: QueryDeps, account_id: string, role: string) => Promise<boolean>;
116
137
  /**
117
138
  * List all role_grants for an actor (including revoked/expired).
118
139
  */
@@ -1 +1 @@
1
- {"version":3,"file":"role_grant_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_queries.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"role_grant_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_queries.ts"],"names":[],"mappings":"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"}
@@ -180,6 +180,37 @@ export const query_role_grant_has_role = async (deps, actor_id, role, scope_id)
180
180
  ) AS exists`, [actor_id, role, scope_id ?? null]);
181
181
  return row?.exists ?? false;
182
182
  };
183
+ /**
184
+ * Account-grain check: does any actor on `account_id` hold an active
185
+ * global role_grant for `role`?
186
+ *
187
+ * Symmetric with `query_role_grant_has_role` but keyed on the account
188
+ * instead of a single actor — for surfaces with `auth: actor: 'none'`
189
+ * that don't load `auth.role_grants` and can't use the in-memory
190
+ * `has_scoped_role` predicate. Joins `role_grant` → `actor`; matches
191
+ * only global role_grants (`scope_id IS NULL`) since the use case is
192
+ * "is the caller's account broadly admin", not scope-aware.
193
+ *
194
+ * Fast under the existing `idx_role_grant_actor` index — the inner
195
+ * `actor_id IN (...)` subquery is index-scan, and the outer EXISTS
196
+ * stops at the first match.
197
+ *
198
+ * @param deps - query dependencies
199
+ * @param account_id - the account to check
200
+ * @param role - the role to check for (e.g. `ROLE_ADMIN`)
201
+ * @returns `true` if any actor on the account has an active global role_grant for `role`
202
+ */
203
+ export const query_account_has_global_role = async (deps, account_id, role) => {
204
+ const row = await deps.db.query_one(`SELECT EXISTS(
205
+ SELECT 1 FROM role_grant
206
+ WHERE actor_id IN (SELECT id FROM actor WHERE account_id = $1)
207
+ AND role = $2
208
+ AND scope_id IS NULL
209
+ AND revoked_at IS NULL
210
+ AND (expires_at IS NULL OR expires_at > NOW())
211
+ ) AS exists`, [account_id, role]);
212
+ return row?.exists ?? false;
213
+ };
183
214
  /**
184
215
  * List all role_grants for an actor (including revoked/expired).
185
216
  */
@@ -63,7 +63,7 @@ export type BuiltinRole = z.infer<typeof BuiltinRole>;
63
63
  * flows. Only useful for diagnostic snapshotting.
64
64
  *
65
65
  * Builtins (`keeper`, `admin`) ship preconfigured in
66
- * `BUILTIN_ROLE_SPECS_BY_NAME`.
66
+ * `builtin_role_specs_by_name`.
67
67
  */
68
68
  export interface RoleSpec {
69
69
  /** Unique role name. Must match `RoleName` regex; collisions with builtins throw. */
@@ -105,7 +105,7 @@ export interface RoleSpec {
105
105
  * no effect on already-built role schemas (the factory copies entries
106
106
  * into a fresh `Map`).
107
107
  */
108
- export declare const BUILTIN_ROLE_SPECS_BY_NAME: ReadonlyMap<string, RoleSpec>;
108
+ export declare const builtin_role_specs_by_name: ReadonlyMap<string, RoleSpec>;
109
109
  /** Optional registries to validate `RoleSpec` cross-axis fields against at construction time. */
110
110
  export interface CreateRoleSchemaOptions {
111
111
  /** Pass `create_credential_type_schema()` to validate `RoleSpec.required_credential_types` entries. */
@@ -44,7 +44,7 @@ export const BuiltinRole = z.enum(BUILTIN_ROLES);
44
44
  * no effect on already-built role schemas (the factory copies entries
45
45
  * into a fresh `Map`).
46
46
  */
47
- export const BUILTIN_ROLE_SPECS_BY_NAME = new Map([
47
+ export const builtin_role_specs_by_name = new Map([
48
48
  [
49
49
  ROLE_KEEPER,
50
50
  {
@@ -139,7 +139,7 @@ export const create_role_schema = (consumer_roles, options = {}) => {
139
139
  if (!parsed.success) {
140
140
  throw new Error(`Invalid role name "${spec.name}": ${parsed.error.issues[0].message}`);
141
141
  }
142
- if (BUILTIN_ROLE_SPECS_BY_NAME.has(spec.name)) {
142
+ if (builtin_role_specs_by_name.has(spec.name)) {
143
143
  throw new Error(`App role "${spec.name}" collides with builtin role`);
144
144
  }
145
145
  if (seen.has(spec.name)) {
@@ -150,7 +150,7 @@ export const create_role_schema = (consumer_roles, options = {}) => {
150
150
  validate_registry_membership(spec.name, 'applicable_scope_kinds', spec.applicable_scope_kinds, scope_kinds_registry);
151
151
  validate_registry_membership(spec.name, 'grant_paths', spec.grant_paths, grant_paths_registry);
152
152
  }
153
- const role_specs = new Map(BUILTIN_ROLE_SPECS_BY_NAME);
153
+ const role_specs = new Map(builtin_role_specs_by_name);
154
154
  for (const spec of consumer_roles) {
155
155
  role_specs.set(spec.name, spec);
156
156
  }
@@ -29,6 +29,13 @@ export declare const SelfServiceRoleSetOutput: z.ZodObject<{
29
29
  changed: z.ZodBoolean;
30
30
  }, z.core.$strict>;
31
31
  export type SelfServiceRoleSetOutput = z.infer<typeof SelfServiceRoleSetOutput>;
32
+ /**
33
+ * `rate_limit: 'account'` bounds audit-row churn. The toggle is idempotent
34
+ * (`changed: false` re-grants/re-revokes), but every call still writes a
35
+ * `role_grant_create` or `role_grant_revoke` audit row with
36
+ * `self_service: true`. Without the cap, a caller could flap the role in
37
+ * a loop to inflate the audit log and obscure other activity.
38
+ */
32
39
  export declare const self_service_role_set_action_spec: {
33
40
  method: string;
34
41
  kind: "request_response";
@@ -50,6 +57,7 @@ export declare const self_service_role_set_action_spec: {
50
57
  }, z.core.$strict>;
51
58
  async: true;
52
59
  description: string;
60
+ rate_limit: "account";
53
61
  };
54
62
  /**
55
63
  * All self-service role action specs — a codegen-ready registry. Single-element
@@ -1 +1 @@
1
- {"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAIzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;;kBAOlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;CAWT,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,aAAa,CAAC,yBAAyB,CAEvF,CAAC"}
1
+ {"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAIzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;;kBAOlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;;CAYT,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,aAAa,CAAC,yBAAyB,CAEvF,CAAC"}
@@ -30,6 +30,13 @@ export const SelfServiceRoleSetOutput = z.strictObject({
30
30
  enabled: z.boolean(),
31
31
  changed: z.boolean(),
32
32
  });
33
+ /**
34
+ * `rate_limit: 'account'` bounds audit-row churn. The toggle is idempotent
35
+ * (`changed: false` re-grants/re-revokes), but every call still writes a
36
+ * `role_grant_create` or `role_grant_revoke` audit row with
37
+ * `self_service: true`. Without the cap, a caller could flap the role in
38
+ * a loop to inflate the audit log and obscure other activity.
39
+ */
33
40
  export const self_service_role_set_action_spec = {
34
41
  method: 'self_service_role_set',
35
42
  kind: 'request_response',
@@ -40,6 +47,7 @@ export const self_service_role_set_action_spec = {
40
47
  output: SelfServiceRoleSetOutput,
41
48
  async: true,
42
49
  description: 'Toggle a self-service role. Idempotent in both directions — `changed: false` when post-call state already matched the request.',
50
+ rate_limit: 'account',
43
51
  };
44
52
  /**
45
53
  * All self-service role action specs — a codegen-ready registry. Single-element
@@ -44,7 +44,7 @@ export interface SelfServiceRoleActionsOptions {
44
44
  /**
45
45
  * Optional override allowlist of role strings eligible for
46
46
  * self-service. When omitted, eligibility is derived from
47
- * `roles.role_specs` (or `BUILTIN_ROLE_SPECS_BY_NAME` when `roles`
47
+ * `roles.role_specs` (or `builtin_role_specs_by_name` when `roles`
48
48
  * is also omitted) by selecting every role whose
49
49
  * `RoleSpec.grant_paths` includes `'self_service'`. Pass an empty
50
50
  * array to lock the surface down (every call comes back as
@@ -38,7 +38,7 @@
38
38
  */
39
39
  import { rpc_action } from '../actions/action_rpc.js';
40
40
  import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
41
- import { BUILTIN_ROLE_SPECS_BY_NAME, list_roles_with_grant_path, } from './role_schema.js';
41
+ import { builtin_role_specs_by_name, list_roles_with_grant_path, } from './role_schema.js';
42
42
  import { GRANT_PATH_SELF_SERVICE } from './grant_path_schema.js';
43
43
  import { query_create_role_grant, query_revoke_role_grant } from './role_grant_queries.js';
44
44
  import { is_role_grant_active } from './account_schema.js';
@@ -55,7 +55,7 @@ import { ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE, self_service_role_set_action_spec
55
55
  * @throws Error at factory time if any `eligible_roles` entry is missing from `options.roles.role_specs`
56
56
  */
57
57
  export const create_self_service_role_actions = (deps, options = {}) => {
58
- const role_specs = options.roles?.role_specs ?? BUILTIN_ROLE_SPECS_BY_NAME;
58
+ const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
59
59
  const eligible = options.eligible_roles
60
60
  ? new Set(options.eligible_roles)
61
61
  : new Set(list_roles_with_grant_path(role_specs, GRANT_PATH_SELF_SERVICE));
@@ -38,7 +38,7 @@ export interface SessionCookieOptions {
38
38
  * - `sameSite: 'strict'` - Prevents CSRF
39
39
  * - `httpOnly: true` - Prevents XSS access to cookie
40
40
  */
41
- export declare const SESSION_COOKIE_OPTIONS: SessionCookieOptions;
41
+ export declare const session_cookie_options: SessionCookieOptions;
42
42
  /**
43
43
  * Configuration for a session cookie format.
44
44
  *
@@ -31,7 +31,7 @@ const EXPIRES_AT_INTEGER_RE = /^\d+$/;
31
31
  * - `sameSite: 'strict'` - Prevents CSRF
32
32
  * - `httpOnly: true` - Prevents XSS access to cookie
33
33
  */
34
- export const SESSION_COOKIE_OPTIONS = {
34
+ export const session_cookie_options = {
35
35
  path: '/',
36
36
  httpOnly: true,
37
37
  secure: true,