@fuzdev/fuz_app 0.105.0 → 0.106.1

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 (72) hide show
  1. package/dist/actions/action_rpc.d.ts.map +1 -1
  2. package/dist/actions/action_rpc.js +2 -1
  3. package/dist/actions/perform_action.d.ts +8 -0
  4. package/dist/actions/perform_action.d.ts.map +1 -1
  5. package/dist/actions/perform_action.js +30 -12
  6. package/dist/actions/register_action_ws.d.ts.map +1 -1
  7. package/dist/actions/register_action_ws.js +27 -3
  8. package/dist/auth/account_action_specs.d.ts +28 -5
  9. package/dist/auth/account_action_specs.d.ts.map +1 -1
  10. package/dist/auth/account_action_specs.js +19 -6
  11. package/dist/auth/account_actions.d.ts.map +1 -1
  12. package/dist/auth/account_actions.js +15 -2
  13. package/dist/auth/account_schema.d.ts +13 -0
  14. package/dist/auth/account_schema.d.ts.map +1 -1
  15. package/dist/auth/account_schema.js +8 -1
  16. package/dist/auth/api_token_queries.d.ts +2 -1
  17. package/dist/auth/api_token_queries.d.ts.map +1 -1
  18. package/dist/auth/api_token_queries.js +21 -5
  19. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  20. package/dist/auth/audit_log_routes.js +9 -1
  21. package/dist/auth/bearer_auth.d.ts.map +1 -1
  22. package/dist/auth/bearer_auth.js +6 -1
  23. package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
  24. package/dist/auth/daemon_token_middleware.js +5 -1
  25. package/dist/auth/migrations.d.ts.map +1 -1
  26. package/dist/auth/migrations.js +33 -0
  27. package/dist/auth/request_context.d.ts +18 -0
  28. package/dist/auth/request_context.d.ts.map +1 -1
  29. package/dist/auth/request_context.js +27 -1
  30. package/dist/auth/role_grant_offer_action_specs.d.ts +12 -0
  31. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
  32. package/dist/auth/role_grant_offer_action_specs.js +12 -1
  33. package/dist/auth/self_service_role_action_specs.d.ts +7 -0
  34. package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
  35. package/dist/auth/self_service_role_action_specs.js +7 -1
  36. package/dist/auth/token_scope.d.ts +155 -0
  37. package/dist/auth/token_scope.d.ts.map +1 -0
  38. package/dist/auth/token_scope.js +190 -0
  39. package/dist/db/CLAUDE.md +1 -1
  40. package/dist/hono_context.d.ts +23 -0
  41. package/dist/hono_context.d.ts.map +1 -1
  42. package/dist/hono_context.js +14 -0
  43. package/dist/http/error_schemas.d.ts +12 -0
  44. package/dist/http/error_schemas.d.ts.map +1 -1
  45. package/dist/http/error_schemas.js +12 -0
  46. package/dist/server/serve_fact_route.d.ts.map +1 -1
  47. package/dist/server/serve_fact_route.js +9 -1
  48. package/dist/server/x_accel.d.ts +2 -4
  49. package/dist/server/x_accel.d.ts.map +1 -1
  50. package/dist/server/x_accel.js +2 -4
  51. package/dist/testing/admin_integration.js +2 -2
  52. package/dist/testing/app_server.d.ts.map +1 -1
  53. package/dist/testing/app_server.js +2 -1
  54. package/dist/testing/audit_completeness.js +1 -1
  55. package/dist/testing/cross_backend/conformance_case.d.ts +23 -0
  56. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  57. package/dist/testing/cross_backend/conformance_case.js +21 -0
  58. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  59. package/dist/testing/cross_backend/conformance_table.js +58 -5
  60. package/dist/testing/cross_backend/expected_schema.json +1 -0
  61. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  62. package/dist/testing/cross_backend/setup.js +5 -1
  63. package/dist/testing/integration.js +3 -3
  64. package/dist/ui/account_sessions_state.svelte.d.ts +3 -3
  65. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  66. package/package.json +2 -2
  67. package/dist/server/fact_write.d.ts +0 -32
  68. package/dist/server/fact_write.d.ts.map +0 -1
  69. package/dist/server/fact_write.js +0 -57
  70. package/dist/server/validate_nginx.d.ts +0 -34
  71. package/dist/server/validate_nginx.d.ts.map +0 -1
  72. package/dist/server/validate_nginx.js +0 -169
@@ -1 +1 @@
1
- {"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@ import { DEV } from 'esm-env';
16
16
  import {} from '../http/route_spec.js';
17
17
  import { get_client_ip } from '../http/client_ip.js';
18
18
  import { get_request_context } from '../auth/request_context.js';
19
- import { ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY, TEST_CONTEXT_PRESET_KEY } from '../hono_context.js';
19
+ import { ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY, TOKEN_SCOPE_KEY, TEST_CONTEXT_PRESET_KEY } from '../hono_context.js';
20
20
  import { compile_action_registry } from './compile_action_registry.js';
21
21
  import { JSONRPC_VERSION, JsonrpcRequest } from '../http/jsonrpc.js';
22
22
  import { jsonrpc_error_messages, jsonrpc_error_code_to_http_status, JSONRPC_ERROR_CODES, dev_only } from '../http/jsonrpc_errors.js';
@@ -163,6 +163,7 @@ export const create_rpc_endpoint = (options) => {
163
163
  request_id: id,
164
164
  account_id: c.get(ACCOUNT_ID_KEY) ?? null,
165
165
  credential_type: c.get(CREDENTIAL_TYPE_KEY) ?? null,
166
+ token_scope: c.get(TOKEN_SCOPE_KEY) ?? null,
166
167
  client_ip: get_client_ip(c),
167
168
  signal: c.req.raw.signal,
168
169
  notify,
@@ -46,6 +46,7 @@ import { type JsonrpcRequestId, type JsonrpcErrorObject } from '../http/jsonrpc.
46
46
  import type { RateLimiter } from '../rate_limiter.js';
47
47
  import type { RpcAction } from './action_rpc.js';
48
48
  import type { RequestClient } from './peer_request.js';
49
+ import { type TokenScope } from '../auth/token_scope.js';
49
50
  /**
50
51
  * Per-call inputs to `perform_action`. Each transport assembles this from
51
52
  * its wire envelope + connection identity.
@@ -61,6 +62,13 @@ export interface PerformActionInput {
61
62
  account_id: string | null;
62
63
  /** Credential type the request arrived on, or `null` for anonymous. */
63
64
  credential_type: CredentialType | null;
65
+ /**
66
+ * The credential's authority narrowing — `null` only for the anonymous
67
+ * caller, who holds no credential to narrow. Every resolved credential
68
+ * carries one, so this mirrors the `null` shape `credential_type` already
69
+ * has rather than introducing a permissive absent case.
70
+ */
71
+ token_scope: TokenScope | null;
64
72
  /** Resolved client IP (`'unknown'` if upstream couldn't resolve). */
65
73
  client_ip: string;
66
74
  /** Per-request abort signal. HTTP: `c.req.raw.signal`. WS: `AbortSignal.any([socket, request])`. */
@@ -1 +1 @@
1
- {"version":3,"file":"perform_action.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/perform_action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAGtC,OAAO,EAEN,KAAK,gBAAgB,EAErB,KAAK,kBAAkB,EACvB,MAAM,oBAAoB,CAAC;AAa5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAgC,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,MAAM,EAAE,SAAS,CAAC;IAClB,mGAAmG;IACnG,UAAU,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,yDAAyD;IACzD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uEAAuE;IACvE,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,MAAM,EAAE,WAAW,CAAC;IACpB,sFAAsF;IACtF,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,uDAAuD;IACvD,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,eAAe,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IACjC,gGAAgG;IAChG,EAAE,EAAE,EAAE,CAAC;IACP;;;OAGG;IACH,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;OAGG;IACH,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,uEAAuE;IACvE,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAC9B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhG;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAC1B,OAAO,kBAAkB,EACzB,MAAM,iBAAiB,KACrB,OAAO,CAAC,mBAAmB,CAsK7B,CAAC;AAoFF;;;GAGG;AACH,eAAO,MAAM,iCAAiC,GAC7C,IAAI,gBAAgB,EACpB,QAAQ,mBAAmB,KACzB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,gBAAgB,CAAA;CAAE,GAAG,CAC9C;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAMnD,CAAC"}
1
+ {"version":3,"file":"perform_action.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/perform_action.ts"],"names":[],"mappings":"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"}
@@ -44,8 +44,9 @@ import { is_void_schema } from '../http/schema_helpers.js';
44
44
  import { dispatch_with_post_commit_rollback } from '../http/pending_effects.js';
45
45
  import { JSONRPC_VERSION } from '../http/jsonrpc.js';
46
46
  import { jsonrpc_error_messages, jsonrpc_error_code_to_http_status, http_status_to_jsonrpc_error_code, JSONRPC_ERROR_CODES, dev_only } from '../http/jsonrpc_errors.js';
47
- import { ERROR_AUTHENTICATION_REQUIRED, ERROR_INSUFFICIENT_PERMISSIONS, ERROR_CREDENTIAL_TYPE_REQUIRED } from '../http/error_schemas.js';
47
+ import { ERROR_AUTHENTICATION_REQUIRED, ERROR_INSUFFICIENT_PERMISSIONS, ERROR_CREDENTIAL_TYPE_REQUIRED, ERROR_TOKEN_SCOPE_REQUIRED } from '../http/error_schemas.js';
48
48
  import { is_public_auth } from '../http/auth_shape.js';
49
+ import { token_scope_admits_method } from '../auth/token_scope.js';
49
50
  /**
50
51
  * The shared dispatch core. Pure data — no Hono context, no socket. Each
51
52
  * transport calls into this with pre-parsed inputs and binds the result
@@ -57,7 +58,7 @@ import { is_public_auth } from '../http/auth_shape.js';
57
58
  * still fires when the harness omits `account_id`.
58
59
  */
59
60
  export const perform_action = async (input, deps) => {
60
- const { action, raw_params, request_id: id, account_id, credential_type, client_ip, signal, notify, connection_id, request_client, preset } = input;
61
+ const { action, raw_params, request_id: id, account_id, credential_type, token_scope, client_ip, signal, notify, connection_id, request_client, preset } = input;
61
62
  const { db, pending_effects, post_commit_effects, log, action_ip_rate_limiter, action_account_rate_limiter } = deps;
62
63
  const { spec, handler } = action;
63
64
  const action_auth = spec.auth;
@@ -102,7 +103,7 @@ export const perform_action = async (input, deps) => {
102
103
  request_context = result.request_context;
103
104
  }
104
105
  // step 4: post-authorization auth — credential gate first, role gate second.
105
- const post = check_action_auth_post_authorization(action_auth, request_context, credential_type);
106
+ const post = check_action_auth_post_authorization(action_auth, request_context, credential_type, action.spec.method, token_scope);
106
107
  if (post)
107
108
  return error_result(post);
108
109
  // step 5: rate limit — throttle-requests semantics (record on every
@@ -230,17 +231,26 @@ const check_action_auth_pre_validation = (auth, account_id) => {
230
231
  * resolved the actor + role_grants. Enforces `auth.credential_types` and
231
232
  * `auth.roles`.
232
233
  *
233
- * Credential gate fires first: if the spec restricts credential types
234
- * and the request didn't arrive on one of them, emit
235
- * `ERROR_CREDENTIAL_TYPE_REQUIRED` 403 with `required_credential_types`
236
- * echoing the spec's allowlist (symmetric with the role gate's
237
- * `required_roles`).
234
+ * ## Gate order: credential → scope → role
238
235
  *
239
- * Role gate fires second: if the spec declares any roles and the actor
240
- * doesn't hold one globally, emit `ERROR_INSUFFICIENT_PERMISSIONS` 403
241
- * with `required_roles` (the multi-role disjunction).
236
+ * **Credential first** because it is the coarser fact ("this channel may never
237
+ * call me" outranks "this token may not"), because it preserves every existing
238
+ * wire assertion — a session-only spec called over bearer keeps returning
239
+ * `ERROR_CREDENTIAL_TYPE_REQUIRED` — and because it leaks less: telling a
240
+ * bearer caller "your token lacks `rpc:X`" on an endpoint no bearer may ever
241
+ * reach confirms the endpoint to a channel that should not learn it.
242
+ *
243
+ * **Scope second**, before the role gate, because scope is a fact about the
244
+ * credential decided without a DB read, while the role gate reads the resolved
245
+ * actor's grants. Coarse → fine, and an under-scoped token learns nothing about
246
+ * the deployment's role structure. `token_scope` is `null` only for the
247
+ * anonymous caller, who has no credential to narrow.
248
+ *
249
+ * **Role gate third**: if the spec declares any roles and the actor doesn't hold
250
+ * one globally, emit `ERROR_INSUFFICIENT_PERMISSIONS` 403 with `required_roles`
251
+ * (the multi-role disjunction).
242
252
  */
243
- const check_action_auth_post_authorization = (auth, request_context, credential_type) => {
253
+ const check_action_auth_post_authorization = (auth, request_context, credential_type, method, token_scope) => {
244
254
  if (auth.credential_types?.length) {
245
255
  if (!credential_type || !auth.credential_types.includes(credential_type)) {
246
256
  return jsonrpc_error_messages.forbidden('forbidden', {
@@ -249,6 +259,14 @@ const check_action_auth_post_authorization = (auth, request_context, credential_
249
259
  });
250
260
  }
251
261
  }
262
+ // Token-scope gate — second of three. See the doc comment for why the order
263
+ // is credential → scope → role.
264
+ if (token_scope && !token_scope_admits_method(token_scope, method)) {
265
+ return jsonrpc_error_messages.forbidden('forbidden', {
266
+ reason: ERROR_TOKEN_SCOPE_REQUIRED,
267
+ required_scope: `rpc:${method}`
268
+ });
269
+ }
252
270
  if (auth.roles?.length) {
253
271
  if (!has_any_scoped_role(request_context, auth.roles, null)) {
254
272
  return jsonrpc_error_messages.forbidden(`requires role: ${auth.roles.join(' or ')}`, {
@@ -1 +1 @@
1
- {"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAU,KAAK,MAAM,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAUnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAkBtD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,EAAE,yBAAyB,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAIhG,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IACjC,qFAAqF;IACrF,EAAE,EAAE,SAAS,CAAC;IACd,4EAA4E;IAC5E,aAAa,EAAE,IAAI,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,wFAAwF;IACxF,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,EAAE,EAAE,SAAS,CAAC;IACd,2CAA2C;IAC3C,aAAa,EAAE,IAAI,CAAC;IACpB,kGAAkG;IAClG,QAAQ,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wCAAwC;AACxC,MAAM,WAAW,uBAAuB;IACvC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,GAAG,EAAE,IAAI,CAAC;IACV,iEAAiE;IACjE,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;;;;;;OAOG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;;;;;;OASG;IACH,EAAE,EAAE,EAAE,CAAC;IACP;;;;OAIG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5C;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACjD;AAED,sCAAsC;AACtC,MAAM,WAAW,sBAAsB;IACtC,yEAAyE;IACzE,SAAS,EAAE,yBAAyB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,uBAAuB,KAAG,sBAgYrE,CAAC"}
1
+ {"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAU,KAAK,MAAM,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAWnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAmBtD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,EAAE,yBAAyB,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAIhG,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB,0EAA0E;AAC1E,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IACjC,qFAAqF;IACrF,EAAE,EAAE,SAAS,CAAC;IACd,4EAA4E;IAC5E,aAAa,EAAE,IAAI,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,wFAAwF;IACxF,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IAClC,+CAA+C;IAC/C,EAAE,EAAE,SAAS,CAAC;IACd,2CAA2C;IAC3C,aAAa,EAAE,IAAI,CAAC;IACpB,kGAAkG;IAClG,QAAQ,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wCAAwC;AACxC,MAAM,WAAW,uBAAuB;IACvC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,GAAG,EAAE,IAAI,CAAC;IACV,iEAAiE;IACjE,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;;;;;;OAOG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;;;;;;OASG;IACH,EAAE,EAAE,EAAE,CAAC;IACP;;;;OAIG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5C;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACjD;AAED,sCAAsC;AACtC,MAAM,WAAW,sBAAsB;IACtC,yEAAyE;IACzE,SAAS,EAAE,yBAAyB,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,uBAAuB,KAAG,sBAuZrE,CAAC"}
@@ -28,13 +28,13 @@
28
28
  */
29
29
  import { wait } from '@fuzdev/fuz_util/async.ts';
30
30
  import { Logger } from '@fuzdev/fuz_util/log.ts';
31
- import { get_request_context, require_request_context } from '../auth/request_context.js';
31
+ import { get_request_context, require_request_context, token_scope_surface_denial } from '../auth/request_context.js';
32
32
  import { hash_session_token } from '../auth/session_queries.js';
33
33
  import { get_client_ip } from '../http/client_ip.js';
34
34
  import { flush_pending_effects, flush_post_commit_effects } from '../http/pending_effects.js';
35
35
  import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
36
36
  import { create_jsonrpc_error_response, create_jsonrpc_notification, to_jsonrpc_message_id, to_jsonrpc_params, is_jsonrpc_request, is_jsonrpc_response, is_jsonrpc_error_response } from '../http/jsonrpc_helpers.js';
37
- import { CREDENTIAL_TYPE_KEY, AUTH_API_TOKEN_ID_KEY, TEST_CONTEXT_PRESET_KEY } from '../hono_context.js';
37
+ import { CREDENTIAL_TYPE_KEY, TOKEN_SCOPE_KEY, AUTH_API_TOKEN_ID_KEY, TEST_CONTEXT_PRESET_KEY } from '../hono_context.js';
38
38
  import {} from './action_types.js';
39
39
  import { compile_action_registry } from './compile_action_registry.js';
40
40
  import { cancel_action_spec, CancelNotificationParams } from './cancel.js';
@@ -84,7 +84,25 @@ export const register_action_ws = (options) => {
84
84
  // itself — a dead-because-blocked socket is close enough to
85
85
  // dead-because-unresponsive that closing is arguably correct.
86
86
  const heartbeat_tick_interval = Math.max(100, Math.floor(heartbeat_timeout / 2));
87
- app.get(path, upgradeWebSocket((c) => {
87
+ app.get(path,
88
+ // Token-scope surface gate — a narrowed token cannot hold a socket.
89
+ //
90
+ // Mounted as pre-upgrade middleware rather than inside the
91
+ // `upgradeWebSocket` callback, which must return `WSEvents` and so has no
92
+ // way to produce a denial response.
93
+ //
94
+ // Rule 3, doing real work rather than being conservative for its own
95
+ // sake: server-initiated pushes (broadcasts, role-grant-offer
96
+ // notifications, peer requests) reach whatever the account's connection
97
+ // reaches, and there is no per-recipient filter to narrow them by. So a
98
+ // scoped token that could upgrade would observe far more than it was
99
+ // granted.
100
+ async (c, next) => {
101
+ const denied = token_scope_surface_denial(c, 'ws_upgrade');
102
+ if (denied)
103
+ return denied;
104
+ return next();
105
+ }, upgradeWebSocket((c) => {
88
106
  // Upgrade-time identity capture. `require_auth` middleware has
89
107
  // already rejected unauthenticated upgrades, so request_context is
90
108
  // non-null here. Per-message dispatch reads `account_id` +
@@ -103,6 +121,11 @@ export const register_action_ws = (options) => {
103
121
  const account_id = upgrade_context.account.id;
104
122
  const client_ip = get_client_ip(c);
105
123
  const credential_type = c.get(CREDENTIAL_TYPE_KEY);
124
+ // Captured at upgrade and consulted per message. Rule 3 rejects a
125
+ // narrowed token at the boundary below, so in practice this is always
126
+ // `full` on a live socket — but the per-message gate runs regardless,
127
+ // so the invariant is enforced rather than assumed.
128
+ const token_scope = c.get(TOKEN_SCOPE_KEY) ?? null;
106
129
  // Session-based connections have a token hash for targeted revocation.
107
130
  // Bearer/daemon connections pass null — still reachable via
108
131
  // `close_sockets_for_account` / `close_sockets_for_token`.
@@ -326,6 +349,7 @@ export const register_action_ws = (options) => {
326
349
  request_id: id,
327
350
  account_id,
328
351
  credential_type,
352
+ token_scope,
329
353
  client_ip,
330
354
  signal,
331
355
  notify,
@@ -46,10 +46,25 @@ export declare const SessionRevokeAllOutput: z.ZodObject<{
46
46
  count: z.ZodNumber;
47
47
  }, z.core.$strict>;
48
48
  export type SessionRevokeAllOutput = z.infer<typeof SessionRevokeAllOutput>;
49
- /** Input for `account_token_create`. */
50
- export declare const TokenCreateInput: z.ZodPrefault<z.ZodObject<{
49
+ /**
50
+ * Input for `account_token_create`.
51
+ *
52
+ * `scope` is **required** — default-deny at mint. There is deliberately no
53
+ * permissive default: a caller who wants full authority spells
54
+ * `{kind: 'full'}`, and the stored document records that they did. That is the
55
+ * reversal of the 2026-02 design, where the field existed but nothing depended
56
+ * on it. Because `scope` has no default, the object as a whole no longer
57
+ * carries `.prefault({})`.
58
+ */
59
+ export declare const TokenCreateInput: z.ZodObject<{
51
60
  name: z.ZodDefault<z.ZodString>;
52
- }, z.core.$strict>>;
61
+ scope: z.ZodDiscriminatedUnion<[z.ZodObject<{
62
+ kind: z.ZodLiteral<"full">;
63
+ }, z.core.$strict>, z.ZodObject<{
64
+ kind: z.ZodLiteral<"methods">;
65
+ methods: z.ZodArray<z.ZodString>;
66
+ }, z.core.$strict>], "kind">;
67
+ }, z.core.$strict>;
53
68
  export type TokenCreateInput = z.infer<typeof TokenCreateInput>;
54
69
  /** Output for `account_token_create`. `token` is returned exactly once. */
55
70
  export declare const TokenCreateOutput: z.ZodObject<{
@@ -72,6 +87,7 @@ export declare const TokenListOutput: z.ZodObject<{
72
87
  last_used_at: z.ZodNullable<z.ZodString>;
73
88
  last_used_ip: z.ZodNullable<z.ZodString>;
74
89
  created_at: z.ZodString;
90
+ scope: z.ZodString;
75
91
  }, z.core.$strict>>;
76
92
  }, z.core.$strict>;
77
93
  export type TokenListOutput = z.infer<typeof TokenListOutput>;
@@ -186,9 +202,15 @@ export declare const account_token_create_action_spec: {
186
202
  credential_types: string[];
187
203
  };
188
204
  side_effects: true;
189
- input: z.ZodPrefault<z.ZodObject<{
205
+ input: z.ZodObject<{
190
206
  name: z.ZodDefault<z.ZodString>;
191
- }, z.core.$strict>>;
207
+ scope: z.ZodDiscriminatedUnion<[z.ZodObject<{
208
+ kind: z.ZodLiteral<"full">;
209
+ }, z.core.$strict>, z.ZodObject<{
210
+ kind: z.ZodLiteral<"methods">;
211
+ methods: z.ZodArray<z.ZodString>;
212
+ }, z.core.$strict>], "kind">;
213
+ }, z.core.$strict>;
192
214
  output: z.ZodObject<{
193
215
  ok: z.ZodLiteral<true>;
194
216
  token: z.ZodString;
@@ -218,6 +240,7 @@ export declare const account_token_list_action_spec: {
218
240
  last_used_at: z.ZodNullable<z.ZodString>;
219
241
  last_used_ip: z.ZodNullable<z.ZodString>;
220
242
  created_at: z.ZodString;
243
+ scope: z.ZodString;
221
244
  }, z.core.$strict>>;
222
245
  }, z.core.$strict>;
223
246
  async: true;
@@ -1 +1 @@
1
- {"version":3,"file":"account_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_action_specs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_action_specs.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@
8
8
  * @module
9
9
  */
10
10
  import { z } from 'zod';
11
+ import { TokenScopeInput } from './token_scope.js';
11
12
  import { AuthSessionJson, ClientApiTokenJson, SessionAccountJson, SessionId } from './account_schema.js';
12
13
  import { ApiTokenId } from './api_token.js';
13
14
  // -- Input/output schemas ---------------------------------------------------
@@ -35,15 +36,27 @@ export const SessionRevokeAllOutput = z.strictObject({
35
36
  ok: z.literal(true),
36
37
  count: z.number()
37
38
  });
38
- /** Input for `account_token_create`. */
39
- export const TokenCreateInput = z
40
- .strictObject({
39
+ /**
40
+ * Input for `account_token_create`.
41
+ *
42
+ * `scope` is **required** — default-deny at mint. There is deliberately no
43
+ * permissive default: a caller who wants full authority spells
44
+ * `{kind: 'full'}`, and the stored document records that they did. That is the
45
+ * reversal of the 2026-02 design, where the field existed but nothing depended
46
+ * on it. Because `scope` has no default, the object as a whole no longer
47
+ * carries `.prefault({})`.
48
+ */
49
+ export const TokenCreateInput = z.strictObject({
41
50
  name: z
42
51
  .string()
43
52
  .default('CLI token')
44
- .meta({ description: 'Human-friendly label; shown in the token list.' })
45
- })
46
- .prefault({});
53
+ .meta({ description: 'Human-friendly label; shown in the token list.' }),
54
+ scope: TokenScopeInput.meta({
55
+ description: "What the token may do. `{kind:'full'}` for full account authority, or " +
56
+ "`{kind:'methods',methods:[…]}` to narrow it to named RPC methods — a " +
57
+ 'narrowed token is RPC-only and reaches no non-RPC surface.'
58
+ })
59
+ });
47
60
  /** Output for `account_token_create`. `token` is returned exactly once. */
48
61
  export const TokenCreateOutput = z.strictObject({
49
62
  ok: z.literal(true),
@@ -1 +1 @@
1
- {"version":3,"file":"account_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAexE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAwBnD,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,iBAAiB,EACvB,UAAS,oBAAyB,KAChC,KAAK,CAAC,SAAS,CAyIjB,CAAC"}
1
+ {"version":3,"file":"account_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAoBxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAwBnD,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,iBAAiB,EACvB,UAAS,oBAAyB,KAChC,KAAK,CAAC,SAAS,CAqJjB,CAAC"}
@@ -26,6 +26,7 @@ import { rpc_action } from '../actions/action_rpc.js';
26
26
  import { to_session_account } from './account_schema.js';
27
27
  import { query_session_list_for_account, query_session_revoke_for_account, query_session_revoke_all_for_account } from './session_queries.js';
28
28
  import { query_api_token_enforce_limit, query_api_token_list_for_account, query_create_api_token, query_revoke_api_token_for_account } from './api_token_queries.js';
29
+ import { parse_stored_token_scope, token_scope_from_input, token_scope_label } from './token_scope.js';
29
30
  import { generate_api_token } from './api_token.js';
30
31
  import { DEFAULT_MAX_TOKENS } from './account_route_schema.js';
31
32
  import { account_verify_action_spec, account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec } from './account_action_specs.js';
@@ -97,7 +98,11 @@ export const create_account_actions = (deps, options = {}) => {
97
98
  };
98
99
  const token_create_handler = async (input, ctx) => {
99
100
  const { token, id, token_hash } = generate_api_token();
100
- await query_create_api_token(ctx, id, ctx.auth.account.id, input.name, token_hash);
101
+ // `input.scope` is required by `TokenCreateInput` — default-deny at mint.
102
+ // There is deliberately no permissive fallback here: an omitted scope is
103
+ // a validation error upstream, not a full-authority token.
104
+ const scope = token_scope_from_input(input.scope);
105
+ await query_create_api_token(ctx, id, ctx.auth.account.id, input.name, token_hash, scope);
101
106
  if (max_tokens != null) {
102
107
  await query_api_token_enforce_limit(ctx, ctx.auth.account.id, max_tokens);
103
108
  }
@@ -114,7 +119,15 @@ export const create_account_actions = (deps, options = {}) => {
114
119
  return { ok: true, token, id, name: input.name };
115
120
  };
116
121
  const token_list_handler = async (_input, ctx) => {
117
- const tokens = await query_api_token_list_for_account(ctx, ctx.auth.account.id);
122
+ const rows = await query_api_token_list_for_account(ctx, ctx.auth.account.id);
123
+ // Project the stored document down to its display label. Display-only, so
124
+ // an unreadable document degrades to a marker rather than failing the
125
+ // list — the opposite of the resolve path, and deliberately so: this is
126
+ // the surface an operator uses to *find* a bad token.
127
+ const tokens = rows.map(({ scope, ...rest }) => {
128
+ const parsed = parse_stored_token_scope(scope);
129
+ return { ...rest, scope: parsed ? token_scope_label(parsed) : 'unreadable' };
130
+ });
118
131
  return { tokens };
119
132
  };
120
133
  const token_revoke_handler = async (input, ctx) => {
@@ -130,6 +130,12 @@ export interface ApiToken {
130
130
  last_used_at: string | null;
131
131
  last_used_ip: string | null;
132
132
  created_at: string;
133
+ /**
134
+ * The token's authority narrowing (`api_token.scope`, `NOT NULL`). Stored as
135
+ * JSONB; read back through `parse_token_scope`, which is fail-closed — an
136
+ * unreadable document refuses the credential rather than widening it.
137
+ */
138
+ scope: unknown;
133
139
  }
134
140
  /** Zod schema for `SessionAccount` — account without sensitive fields. */
135
141
  export declare const SessionAccountJson: z.ZodObject<{
@@ -158,6 +164,13 @@ export declare const ClientApiTokenJson: z.ZodObject<{
158
164
  last_used_at: z.ZodNullable<z.ZodString>;
159
165
  last_used_ip: z.ZodNullable<z.ZodString>;
160
166
  created_at: z.ZodString;
167
+ /**
168
+ * Human-readable scope label (`full` / `full (grandfathered)` /
169
+ * `N methods`). A label rather than the document so the list stays a display
170
+ * surface — nothing authorizes off this, and a grandfathered token reads
171
+ * differently from a deliberately-full one.
172
+ */
173
+ scope: z.ZodString;
161
174
  }, z.core.$strict>;
162
175
  export type ClientApiTokenJson = z.infer<typeof ClientApiTokenJson>;
163
176
  /** Zod schema for the role_grant summary returned in admin account listings. */
@@ -1 +1 @@
1
- {"version":3,"file":"account_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAG9C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAI1D,mEAAmE;AACnE,MAAM,WAAW,OAAO;IACvB,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB;AAED,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,4FAA4F;AAC5F,MAAM,WAAW,KAAK;IACrB,EAAE,EAAE,IAAI,CAAC;IACT,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sEAAsE;IACtE,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,MAAM,CAAC;AAExD,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,IAAI,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,sHAAsH;IACtH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,mGAAmG;IACnG,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,oBAAoB,GAChC,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC5D,MAAK,IAAiB,KACpB,OAA2E,CAAC;AAE/E;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,qDAAgC,CAAC;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAElD,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,SAAS,CAAC;IACd,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,6CAA6C;AAC7C,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,EAAE,OAAO,CAAC;CACf;AAID,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB;;;;;;kBAM7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,6EAA6E;AAC7E,eAAO,MAAM,eAAe;;;;;;kBAM1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB;;;;;;;;IAQ9B;;;;;OAKG;;kBAEF,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,gFAAgF;AAChF,eAAO,MAAM,oBAAoB;;;;;;;;kBAQ/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB;;;kBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,iGAAiG;AACjG,eAAO,MAAM,gBAAgB;;;;;;;;;kBAU3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;kBASlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E,sGAAsG;AACtG,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAKhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI1E,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,IAAI,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,0GAA0G;IAC1G,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,cAMpD,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,KAAG,gBAKlD,CAAC"}
@@ -63,7 +63,14 @@ export const ClientApiTokenJson = z.strictObject({
63
63
  expires_at: z.string().nullable(),
64
64
  last_used_at: z.string().nullable(),
65
65
  last_used_ip: z.string().nullable(),
66
- created_at: z.string()
66
+ created_at: z.string(),
67
+ /**
68
+ * Human-readable scope label (`full` / `full (grandfathered)` /
69
+ * `N methods`). A label rather than the document so the list stays a display
70
+ * surface — nothing authorizes off this, and a grandfathered token reads
71
+ * differently from a deliberately-full one.
72
+ */
73
+ scope: z.string()
67
74
  });
68
75
  /** Zod schema for the role_grant summary returned in admin account listings. */
69
76
  export const RoleGrantSummaryJson = z.strictObject({
@@ -6,6 +6,7 @@
6
6
  import type { Logger } from '@fuzdev/fuz_util/log.ts';
7
7
  import type { QueryDeps } from '../db/query_deps.js';
8
8
  import type { ApiToken } from './account_schema.js';
9
+ import { type TokenScope } from './token_scope.js';
9
10
  /** Extended deps for `query_validate_api_token` which needs a logger. */
10
11
  export interface ApiTokenQueryDeps extends QueryDeps {
11
12
  log: Logger;
@@ -22,7 +23,7 @@ export interface ApiTokenQueryDeps extends QueryDeps {
22
23
  * @returns the stored token record
23
24
  * @mutates `api_token` table - inserts the new row keyed by `id`
24
25
  */
25
- export declare const query_create_api_token: (deps: QueryDeps, id: string, account_id: string, name: string, token_hash: string, expires_at?: Date | null) => Promise<ApiToken>;
26
+ export declare const query_create_api_token: (deps: QueryDeps, id: string, account_id: string, name: string, token_hash: string, scope: TokenScope, expires_at?: Date | null) => Promise<ApiToken>;
26
27
  /**
27
28
  * Validate a raw API token and return the token record.
28
29
  *
@@ -1 +1 @@
1
- {"version":3,"file":"api_token_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/api_token_queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,yEAAyE;AACzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,EAClB,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,aAAa,IAAI,GAAG,IAAI,KACtB,OAAO,CAAC,QAAQ,CAQlB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,iBAAiB,EACvB,WAAW,MAAM,EACjB,IAAI,MAAM,GAAG,SAAS,EACtB,iBAAiB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,KAC/C,OAAO,CAAC,QAAQ,GAAG,SAAS,CAuB9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAM7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAYhB,CAAC"}
1
+ {"version":3,"file":"api_token_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/api_token_queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,KAAK,UAAU,EAAmD,MAAM,kBAAkB,CAAC;AAEpG,yEAAyE;AACzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,EAClB,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAO,UAAU,EACjB,aAAa,IAAI,GAAG,IAAI,KACtB,OAAO,CAAC,QAAQ,CAelB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,iBAAiB,EACvB,WAAW,MAAM,EACjB,IAAI,MAAM,GAAG,SAAS,EACtB,iBAAiB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,KAC/C,OAAO,CAAC,QAAQ,GAAG,SAAS,CAgC9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAM7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAYhB,CAAC"}
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { assert_row } from '../db/assert_row.js';
7
7
  import { hash_api_token } from './api_token.js';
8
+ import { parse_stored_token_scope, serialize_token_scope } from './token_scope.js';
8
9
  /**
9
10
  * Store a new API token (the hash, not the raw token).
10
11
  *
@@ -17,10 +18,17 @@ import { hash_api_token } from './api_token.js';
17
18
  * @returns the stored token record
18
19
  * @mutates `api_token` table - inserts the new row keyed by `id`
19
20
  */
20
- export const query_create_api_token = async (deps, id, account_id, name, token_hash, expires_at) => {
21
- const row = await deps.db.query_one(`INSERT INTO api_token (id, account_id, name, token_hash, expires_at)
22
- VALUES ($1, $2, $3, $4, $5)
23
- RETURNING *`, [id, account_id, name, token_hash, expires_at?.toISOString() ?? null]);
21
+ export const query_create_api_token = async (deps, id, account_id, name, token_hash, scope, expires_at) => {
22
+ const row = await deps.db.query_one(`INSERT INTO api_token (id, account_id, name, token_hash, scope, expires_at)
23
+ VALUES ($1, $2, $3, $4, $5::jsonb, $6)
24
+ RETURNING *`, [
25
+ id,
26
+ account_id,
27
+ name,
28
+ token_hash,
29
+ serialize_token_scope(scope),
30
+ expires_at?.toISOString() ?? null
31
+ ]);
24
32
  return assert_row(row, 'INSERT INTO api_token');
25
33
  };
26
34
  /**
@@ -45,6 +53,14 @@ export const query_validate_api_token = async (deps, raw_token, ip, pending_effe
45
53
  AND (expires_at IS NULL OR expires_at > NOW())`, [token_hash]);
46
54
  if (!row)
47
55
  return undefined;
56
+ // **Fail-closed on an unreadable scope**: refuse the credential, the same
57
+ // outcome as an unknown token hash. The scope *is* the gate here, so a parse
58
+ // failure must not fall through to full authority — that would hand a
59
+ // narrowed token everything precisely when something is already wrong.
60
+ if (parse_stored_token_scope(row.scope) === null) {
61
+ deps.log.warn(`api_token.scope is unreadable for ${row.id}; refusing the credential`);
62
+ return undefined;
63
+ }
48
64
  // Fire-and-forget usage tracking
49
65
  const p = deps.db
50
66
  .query(`UPDATE api_token SET last_used_at = NOW(), last_used_ip = $1 WHERE id = $2`, [
@@ -92,7 +108,7 @@ export const query_revoke_api_token_for_account = async (deps, id, account_id) =
92
108
  * Must be updated if the `api_token` table gains new columns.
93
109
  */
94
110
  export const query_api_token_list_for_account = async (deps, account_id) => {
95
- return deps.db.query(`SELECT id, account_id, name, expires_at, last_used_at, last_used_ip, created_at
111
+ return deps.db.query(`SELECT id, account_id, name, expires_at, last_used_at, last_used_ip, created_at, scope
96
112
  FROM api_token WHERE account_id = $1 ORDER BY created_at DESC`, [account_id]);
97
113
  };
98
114
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"audit_log_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAuB,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAI3E,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACpC,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QACR,SAAS,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;QAC1F,GAAG,EAAE,MAAM,CAAC;KACZ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GAAI,UAAU,oBAAoB,KAAG,KAAK,CAAC,SAAS,CAyB5F,CAAC"}
1
+ {"version":3,"file":"audit_log_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAuB,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAQ3E,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACpC,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QACR,SAAS,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;QAC1F,GAAG,EAAE,MAAM,CAAC;KACZ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GAAI,UAAU,oBAAoB,KAAG,KAAK,CAAC,SAAS,CAiC5F,CAAC"}
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { create_audit_log_route_shape } from './audit_log_route_schema.js';
15
15
  import { create_sse_response } from '../realtime/sse.js';
16
- import { AUTH_SESSION_TOKEN_HASH_KEY, require_request_context } from './request_context.js';
16
+ import { AUTH_SESSION_TOKEN_HASH_KEY, require_request_context, token_scope_surface_denial } from './request_context.js';
17
17
  import { AUDIT_LOG_CHANNEL } from '../realtime/sse_auth_guard.js';
18
18
  /**
19
19
  * Create the optional audit-log SSE route spec.
@@ -32,6 +32,14 @@ export const create_audit_log_route_specs = (options) => {
32
32
  {
33
33
  ...create_audit_log_route_shape(options.required_role),
34
34
  handler: (c) => {
35
+ // Rule 3 — a narrowed token holds no audit feed. Same reasoning as
36
+ // the WS upgrade: this is a long-lived server→client stream whose
37
+ // contents are decided by the account's role, not by any
38
+ // per-message scope check, so there is no point after open at
39
+ // which a narrowing could apply.
40
+ const denied = token_scope_surface_denial(c, 'audit_stream');
41
+ if (denied)
42
+ return denied;
35
43
  const ctx = require_request_context(c);
36
44
  // scope = session hash (capped → tabs-per-session limit and
37
45
  // session-specific `session_revoke` close). groups = [account_id]
@@ -1 +1 @@
1
- {"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAItD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,iBAAiB,WAAW,GAAG,IAAI,EACnC,KAAK,MAAM,KACT,iBAgFF,CAAC"}
1
+ {"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAUtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,iBAAiB,WAAW,GAAG,IAAI,EACnC,KAAK,MAAM,KACT,iBAoFF,CAAC"}
@@ -15,7 +15,8 @@
15
15
  * @module
16
16
  */
17
17
  import { DEV } from 'esm-env';
18
- import { AUTH_API_TOKEN_ID_KEY, ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY } from '../hono_context.js';
18
+ import { AUTH_API_TOKEN_ID_KEY, ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY, TOKEN_SCOPE_KEY } from '../hono_context.js';
19
+ import { parse_stored_token_scope, token_scope_full } from './token_scope.js';
19
20
  import { query_validate_api_token } from './api_token_queries.js';
20
21
  import { get_client_ip } from '../http/client_ip.js';
21
22
  import { is_browser_context } from '../http/origin.js';
@@ -112,6 +113,10 @@ export const create_bearer_auth_middleware = (deps, ip_rate_limiter, log) => {
112
113
  c.set(ACCOUNT_ID_KEY, api_token.account_id);
113
114
  c.set(CREDENTIAL_TYPE_KEY, 'api_token');
114
115
  c.set(AUTH_API_TOKEN_ID_KEY, api_token.id);
116
+ // `query_validate_api_token` is fail-closed on an unreadable scope, so a
117
+ // token that got this far has a readable one. The `?? token_scope_full()`
118
+ // is unreachable defensive cover, not a fallback with meaning.
119
+ c.set(TOKEN_SCOPE_KEY, parse_stored_token_scope(api_token.scope) ?? token_scope_full());
115
120
  await next();
116
121
  };
117
122
  };
@@ -1 +1 @@
1
- {"version":3,"file":"daemon_token_middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/daemon_token_middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAMvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,mBAAmB,CAAC;AAE3B,8DAA8D;AAC9D,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,iDAAiD;AACjD,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAC1D,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,iBAAiB,GAAG,QAAQ,CAAC,GAAG;IAC3D,6FAA6F;IAC7F,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GACjC,SAAS,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EACjC,MAAM,MAAM,KACV,MAAM,GAAG,IAGX,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,GAC9B,SAAS,oBAAoB,EAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACX,OAAO,CAAC,IAAI,CAKd,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,GAAU,MAAM,SAAS,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAEtF,CAAC;AAEF,yCAAyC;AACzC,MAAM,WAAW,0BAA0B;IAC1C;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IACnC,2EAA2E;IAC3E,KAAK,EAAE,gBAAgB,CAAC;IACxB,kGAAkG;IAClG,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,GACvC,SAAS,oBAAoB,GAAG,YAAY,EAC5C,MAAM,SAAS,EACf,SAAS,0BAA0B,EACnC,KAAK,MAAM,KACT,OAAO,CAAC,mBAAmB,CAqD7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,8BAA8B,GAC1C,OAAO,gBAAgB,EACvB,MAAM,SAAS,EACf,KAAK,MAAM,KACT,iBAuEF,CAAC"}
1
+ {"version":3,"file":"daemon_token_middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/daemon_token_middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAYvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,mBAAmB,CAAC;AAE3B,8DAA8D;AAC9D,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,iDAAiD;AACjD,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAC1D,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,iBAAiB,GAAG,QAAQ,CAAC,GAAG;IAC3D,6FAA6F;IAC7F,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GACjC,SAAS,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EACjC,MAAM,MAAM,KACV,MAAM,GAAG,IAGX,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,GAC9B,SAAS,oBAAoB,EAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACX,OAAO,CAAC,IAAI,CAKd,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,GAAU,MAAM,SAAS,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAEtF,CAAC;AAEF,yCAAyC;AACzC,MAAM,WAAW,0BAA0B;IAC1C;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IACnC,2EAA2E;IAC3E,KAAK,EAAE,gBAAgB,CAAC;IACxB,kGAAkG;IAClG,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,GACvC,SAAS,oBAAoB,GAAG,YAAY,EAC5C,MAAM,SAAS,EACf,SAAS,0BAA0B,EACnC,KAAK,MAAM,KACT,OAAO,CAAC,mBAAmB,CAqD7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,8BAA8B,GAC1C,OAAO,gBAAgB,EACvB,MAAM,SAAS,EACf,KAAK,MAAM,KACT,iBA0EF,CAAC"}