@fuzdev/fuz_app 0.113.0 → 0.115.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.
- package/dist/actions/CLAUDE.md +46 -20
- package/dist/actions/action_dispatcher.d.ts +1 -1
- package/dist/actions/action_dispatcher.d.ts.map +1 -1
- package/dist/actions/action_dispatcher.js +22 -16
- package/dist/actions/action_event.d.ts +18 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +63 -19
- package/dist/actions/action_event_types.d.ts +22 -0
- package/dist/actions/action_event_types.d.ts.map +1 -1
- package/dist/actions/action_event_types.js +19 -0
- package/dist/actions/compile_action_registry.d.ts +4 -2
- package/dist/actions/compile_action_registry.d.ts.map +1 -1
- package/dist/actions/compile_action_registry.js +8 -3
- package/dist/actions/frontend_rpc_client.d.ts +6 -0
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +2 -1
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +8 -4
- package/dist/actions/peer_ping.d.ts.map +1 -1
- package/dist/actions/peer_ping.js +3 -1
- package/dist/actions/perform_action.d.ts +1 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +6 -4
- package/dist/actions/register_action_ws.d.ts +13 -0
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +23 -2
- package/dist/actions/rpc_client.d.ts +1 -1
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +2 -1
- package/dist/actions/socket.svelte.d.ts +53 -10
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +84 -23
- package/dist/actions/transports.d.ts +24 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -0
- package/dist/actions/transports_http.d.ts +11 -4
- package/dist/actions/transports_http.d.ts.map +1 -1
- package/dist/actions/transports_http.js +63 -18
- package/dist/actions/transports_ws.d.ts +28 -3
- package/dist/actions/transports_ws.d.ts.map +1 -1
- package/dist/actions/transports_ws.js +33 -4
- package/dist/actions/ws_endpoint_spec.d.ts +7 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +52 -8
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +4 -3
- package/dist/auth/audit_log_schema.d.ts +3 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +13 -3
- package/dist/auth/cell_action_specs.js +1 -1
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +33 -4
- package/dist/auth/cell_authorize.d.ts +3 -0
- package/dist/auth/cell_authorize.d.ts.map +1 -1
- package/dist/auth/cell_authorize.js +7 -4
- package/dist/auth/request_context.d.ts +12 -3
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +12 -3
- package/dist/auth/role_grant_offer_action_specs.d.ts +30 -5
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +53 -17
- package/dist/auth/role_grant_offer_actions.d.ts +23 -12
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +132 -38
- package/dist/auth/role_grant_offer_queries.d.ts +36 -0
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +76 -0
- package/dist/auth/role_schema.d.ts +12 -0
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +12 -0
- package/dist/auth/self_service_role_actions.d.ts +14 -0
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +25 -1
- package/dist/http/CLAUDE.md +7 -3
- package/dist/http/jsonrpc_helpers.d.ts +0 -5
- package/dist/http/jsonrpc_helpers.d.ts.map +1 -1
- package/dist/http/jsonrpc_helpers.js +0 -13
- package/dist/http/schema_helpers.d.ts +56 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +91 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +1 -0
- package/dist/server/serve_fact_route.d.ts +3 -1
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +7 -4
- package/dist/testing/CLAUDE.md +29 -16
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +23 -1
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +18 -0
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +34 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +12 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +13 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +9 -7
- package/dist/testing/cross_backend/ws_round_trip.d.ts +11 -3
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +74 -12
- package/dist/testing/entities.d.ts +6 -3
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +4 -1
- package/dist/testing/transports/ws_client.d.ts +6 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +6 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +5 -0
- package/dist/ui/BootstrapForm.svelte +14 -10
- package/dist/ui/BootstrapForm.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +19 -7
- package/dist/ui/LoginForm.svelte +8 -4
- package/dist/ui/LoginForm.svelte.d.ts.map +1 -1
- package/dist/ui/RoleGrantOfferForm.svelte +29 -14
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts +2 -3
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -1
- package/dist/ui/SignupForm.svelte +14 -13
- package/dist/ui/form_state.svelte.d.ts +24 -11
- package/dist/ui/form_state.svelte.d.ts.map +1 -1
- package/dist/ui/form_state.svelte.js +38 -10
- package/dist/ui/role_grant_offers_state.svelte.d.ts +25 -15
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/role_grant_offers_state.svelte.js +7 -1
- package/package.json +2 -22
- package/dist/actions/request_tracker.svelte.d.ts +0 -77
- package/dist/actions/request_tracker.svelte.d.ts.map +0 -1
- package/dist/actions/request_tracker.svelte.js +0 -169
|
@@ -16,6 +16,7 @@ import { columns_sql, qualify_columns } from '../db/sql_columns.js';
|
|
|
16
16
|
import { ROLE_GRANT_OFFER_COLUMNS, role_grant_offer_expr, ROLE_GRANT_OFFER_SCOPE_KIND_GLOBAL_TOKEN, ROLE_GRANT_OFFER_SCOPE_SENTINEL_UUID, ROLE_GRANT_OFFER_WITH_GRANTOR_SELECT } from './role_grant_offer_ddl.js';
|
|
17
17
|
import { query_create_role_grant, query_role_grant_by_id } from './role_grant_queries.js';
|
|
18
18
|
import { query_audit_log } from './audit_log_queries.js';
|
|
19
|
+
import { is_builtin_role, ROLE_ADMIN, ROLE_KEEPER } from './role_schema.js';
|
|
19
20
|
/**
|
|
20
21
|
* Error thrown by offer-lifecycle queries when the offer is in a non-pending
|
|
21
22
|
* state (accepted / declined / retracted / superseded) and therefore not
|
|
@@ -81,6 +82,22 @@ export class RoleGrantOfferActorMismatchError extends Error {
|
|
|
81
82
|
this.name = 'RoleGrantOfferActorMismatchError';
|
|
82
83
|
}
|
|
83
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Error thrown by `query_accept_offer` when the offer confers a builtin role
|
|
87
|
+
* (`admin` / `keeper`) that this accept must not mint — `refusal` names the
|
|
88
|
+
* rule. Carries the locked (still pending, untouched) offer so the caller can
|
|
89
|
+
* audit the refusal with the offer's role and scope.
|
|
90
|
+
*/
|
|
91
|
+
export class RoleGrantOfferBuiltinRefusedError extends Error {
|
|
92
|
+
offer;
|
|
93
|
+
refusal;
|
|
94
|
+
constructor(offer, refusal) {
|
|
95
|
+
super(`Offer ${offer.id} is refused: ${refusal}`);
|
|
96
|
+
this.name = 'RoleGrantOfferBuiltinRefusedError';
|
|
97
|
+
this.offer = offer;
|
|
98
|
+
this.refusal = refusal;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
84
101
|
/**
|
|
85
102
|
* Error thrown when `query_role_grant_offer_create` is called with a
|
|
86
103
|
* `to_actor_id` that does not exist or does not belong to `to_account_id`.
|
|
@@ -307,6 +324,35 @@ export const query_role_grant_offer_sweep_expired = async (deps) => {
|
|
|
307
324
|
AND expires_at <= NOW()
|
|
308
325
|
ORDER BY role_grant_offer.expires_at ASC`);
|
|
309
326
|
};
|
|
327
|
+
/**
|
|
328
|
+
* Whether `grantor_actor_id` holds an active **global** `admin` on an active
|
|
329
|
+
* actor of an active account — the authority a builtin-role offer needs at the
|
|
330
|
+
* moment its grant is minted.
|
|
331
|
+
*
|
|
332
|
+
* A locking read: `FOR SHARE OF rg` takes a share lock on the grant row that
|
|
333
|
+
* admits, so a concurrent revoke (an `UPDATE` of that row) is strictly ordered
|
|
334
|
+
* against this accept — it either commits first, and the recheck of the locked
|
|
335
|
+
* row sees `revoked_at` set and excludes it, or it waits for this transaction
|
|
336
|
+
* to commit the grant it authorized. A plain `EXISTS` could read the grant as
|
|
337
|
+
* active while a revoke commits in between. The actor and account tombstones
|
|
338
|
+
* are read but not locked — ordering a delete racing an accept isn't worth
|
|
339
|
+
* locking two more tables. Twin of the Rust `grantor_holds_global_admin`.
|
|
340
|
+
*/
|
|
341
|
+
const query_grantor_holds_global_admin = async (deps, grantor_actor_id) => {
|
|
342
|
+
const row = await deps.db.query_one(`SELECT 1 AS held FROM role_grant rg
|
|
343
|
+
JOIN actor act ON act.id = rg.actor_id
|
|
344
|
+
JOIN account a ON a.id = act.account_id
|
|
345
|
+
WHERE rg.actor_id = $1
|
|
346
|
+
AND rg.role = $2
|
|
347
|
+
AND rg.scope_id IS NULL
|
|
348
|
+
AND rg.revoked_at IS NULL
|
|
349
|
+
AND (rg.expires_at IS NULL OR rg.expires_at > NOW())
|
|
350
|
+
AND act.deleted_at IS NULL
|
|
351
|
+
AND a.deleted_at IS NULL
|
|
352
|
+
LIMIT 1
|
|
353
|
+
FOR SHARE OF rg`, [grantor_actor_id, ROLE_ADMIN]);
|
|
354
|
+
return row != null;
|
|
355
|
+
};
|
|
310
356
|
/**
|
|
311
357
|
* Accept an offer atomically: mark accepted, insert the role_grant, stamp
|
|
312
358
|
* `resulting_role_grant_id`, supersede sibling pending offers for the same
|
|
@@ -325,6 +371,11 @@ export const query_role_grant_offer_sweep_expired = async (deps) => {
|
|
|
325
371
|
* - `RoleGrantOfferAlreadyTerminalError` — offer is declined, retracted, or
|
|
326
372
|
* superseded.
|
|
327
373
|
* - `RoleGrantOfferExpiredError` — offer is pending but past `expires_at`.
|
|
374
|
+
* - `RoleGrantOfferActorMismatchError` — actor-targeted offer, different actor.
|
|
375
|
+
* - `RoleGrantOfferBuiltinRefusedError` — a builtin-role offer that must not
|
|
376
|
+
* mint: `keeper` at all, a builtin bound to a scope, or one whose grantor no
|
|
377
|
+
* longer holds an active global `admin` (read under `FOR SHARE`). The offer
|
|
378
|
+
* stays pending.
|
|
328
379
|
*
|
|
329
380
|
* Sibling supersede is what closes the "accept a pre-revoke sibling offer
|
|
330
381
|
* to bypass a revoke" path: once A is accepted, B/C/... can no longer be
|
|
@@ -337,6 +388,8 @@ export const query_role_grant_offer_sweep_expired = async (deps) => {
|
|
|
337
388
|
* @throws RoleGrantOfferNotFoundError if the offer is missing or belongs to another recipient
|
|
338
389
|
* @throws RoleGrantOfferAlreadyTerminalError if the offer is declined, retracted, or superseded
|
|
339
390
|
* @throws RoleGrantOfferExpiredError if the offer is pending but past `expires_at`
|
|
391
|
+
* @throws RoleGrantOfferActorMismatchError if the offer is actor-targeted to a different actor
|
|
392
|
+
* @throws RoleGrantOfferBuiltinRefusedError if a builtin-role offer must not mint (see `BuiltinOfferRefusal`)
|
|
340
393
|
* @throws Error if the accepting `actor_id` does not belong to `to_account_id`, or invariant assertions fail
|
|
341
394
|
*/
|
|
342
395
|
export const query_accept_offer = async (deps, input) => {
|
|
@@ -413,6 +466,29 @@ export const query_accept_offer = async (deps, input) => {
|
|
|
413
466
|
if (locked.to_actor_id != null && locked.to_actor_id !== actor_id) {
|
|
414
467
|
throw new RoleGrantOfferActorMismatchError(offer_id);
|
|
415
468
|
}
|
|
469
|
+
// Builtin-role offers — checked here, the chokepoint where an offer turns
|
|
470
|
+
// into a `role_grant`, so a direct caller of this query can't skip them. No
|
|
471
|
+
// current grant path creates a refused shape, but a pending row can still
|
|
472
|
+
// carry one (a direct `query_role_grant_offer_create`, or an offer made under
|
|
473
|
+
// a since-closed path).
|
|
474
|
+
if (is_builtin_role(locked.role)) {
|
|
475
|
+
let refusal = null;
|
|
476
|
+
if (locked.role === ROLE_KEEPER) {
|
|
477
|
+
// `keeper` is bootstrap-only — never conferred through an offer, even
|
|
478
|
+
// from a global admin.
|
|
479
|
+
refusal = 'bootstrap_only';
|
|
480
|
+
}
|
|
481
|
+
else if (locked.scope_id !== null) {
|
|
482
|
+
// Builtin roles are global-only.
|
|
483
|
+
refusal = 'scoped';
|
|
484
|
+
}
|
|
485
|
+
else if (!(await query_grantor_holds_global_admin(deps, locked.from_actor_id))) {
|
|
486
|
+
refusal = 'grantor_not_authorized';
|
|
487
|
+
}
|
|
488
|
+
if (refusal !== null) {
|
|
489
|
+
throw new RoleGrantOfferBuiltinRefusedError(locked, refusal);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
416
492
|
// Verify the accepting actor belongs to the recipient account.
|
|
417
493
|
// Defense-in-depth: the action handler passes `auth.actor.id` which is
|
|
418
494
|
// already session-bound, but enforcing the invariant here protects
|
|
@@ -39,6 +39,18 @@ export declare const BuiltinRole: z.ZodEnum<{
|
|
|
39
39
|
keeper: "keeper";
|
|
40
40
|
}>;
|
|
41
41
|
export type BuiltinRole = z.infer<typeof BuiltinRole>;
|
|
42
|
+
/**
|
|
43
|
+
* Whether `name` is a builtin role (`keeper` / `admin`).
|
|
44
|
+
*
|
|
45
|
+
* Builtin roles are **global-only**: no grant path binds one to a scope
|
|
46
|
+
* (`role_grant_assign`, `role_grant_offer_create`, and
|
|
47
|
+
* `role_grant_offer_accept` refuse it), and every gate that reads one checks
|
|
48
|
+
* the global grant, so a scoped builtin row confers nothing.
|
|
49
|
+
*
|
|
50
|
+
* @param name - the role name to check
|
|
51
|
+
* @returns `true` for `keeper` or `admin`
|
|
52
|
+
*/
|
|
53
|
+
export declare const is_builtin_role: (name: string) => name is BuiltinRole;
|
|
42
54
|
/**
|
|
43
55
|
* Configuration for a role.
|
|
44
56
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEN,KAAK,0BAA0B,EAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAGN,KAAK,qBAAqB,EAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,0FAA0F;AAC1F,eAAO,MAAM,QAAQ,aAKnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIhD,sFAAsF;AACtF,eAAO,MAAM,WAAW,WAAW,CAAC;AAEpC,iEAAiE;AACjE,eAAO,MAAM,UAAU,UAAU,CAAC;AAElC,+CAA+C;AAC/C,eAAO,MAAM,aAAa,8BAAqC,CAAC;AAEhE,yCAAyC;AACzC,eAAO,MAAM,WAAW;;;EAAwB,CAAC;AACjD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,QAAQ;IACxB,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAClD;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/C;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAuBnE,CAAC;AAEH,iGAAiG;AACjG,MAAM,WAAW,uBAAuB;IACvC,uGAAuG;IACvG,gBAAgB,CAAC,EAAE,0BAA0B,CAAC;IAC9C,+FAA+F;IAC/F,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,oFAAoF;IACpF,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAChC,0GAA0G;IAC1G,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,yEAAyE;IACzE,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAC1C;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,kBAAkB,GAC9B,gBAAgB,aAAa,CAAC,QAAQ,CAAC,EACvC,UAAS,uBAA4B,KACnC,gBA2CF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC/B,YAAY,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,EACzC,MAAM,MAAM,EACZ,YAAY,MAAM,KAChB,OAGF,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,GACtC,YAAY,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,EACzC,YAAY,MAAM,KAChB,KAAK,CAAC,MAAM,CAMd,CAAC"}
|
|
1
|
+
{"version":3,"file":"role_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEN,KAAK,0BAA0B,EAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAGN,KAAK,qBAAqB,EAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,0FAA0F;AAC1F,eAAO,MAAM,QAAQ,aAKnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIhD,sFAAsF;AACtF,eAAO,MAAM,WAAW,WAAW,CAAC;AAEpC,iEAAiE;AACjE,eAAO,MAAM,UAAU,UAAU,CAAC;AAElC,+CAA+C;AAC/C,eAAO,MAAM,aAAa,8BAAqC,CAAC;AAEhE,yCAAyC;AACzC,eAAO,MAAM,WAAW;;;EAAwB,CAAC;AACjD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,IAAI,IAAI,WACX,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,QAAQ;IACxB,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAClD;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/C;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAuBnE,CAAC;AAEH,iGAAiG;AACjG,MAAM,WAAW,uBAAuB;IACvC,uGAAuG;IACvG,gBAAgB,CAAC,EAAE,0BAA0B,CAAC;IAC9C,+FAA+F;IAC/F,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,oFAAoF;IACpF,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAChC,0GAA0G;IAC1G,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,yEAAyE;IACzE,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAC1C;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,kBAAkB,GAC9B,gBAAgB,aAAa,CAAC,QAAQ,CAAC,EACvC,UAAS,uBAA4B,KACnC,gBA2CF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC/B,YAAY,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,EACzC,MAAM,MAAM,EACZ,YAAY,MAAM,KAChB,OAGF,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,GACtC,YAAY,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,EACzC,YAAY,MAAM,KAChB,KAAK,CAAC,MAAM,CAMd,CAAC"}
|
package/dist/auth/role_schema.js
CHANGED
|
@@ -36,6 +36,18 @@ export const ROLE_ADMIN = 'admin';
|
|
|
36
36
|
export const BUILTIN_ROLES = [ROLE_KEEPER, ROLE_ADMIN];
|
|
37
37
|
/** Zod schema for builtin roles only. */
|
|
38
38
|
export const BuiltinRole = z.enum(BUILTIN_ROLES);
|
|
39
|
+
/**
|
|
40
|
+
* Whether `name` is a builtin role (`keeper` / `admin`).
|
|
41
|
+
*
|
|
42
|
+
* Builtin roles are **global-only**: no grant path binds one to a scope
|
|
43
|
+
* (`role_grant_assign`, `role_grant_offer_create`, and
|
|
44
|
+
* `role_grant_offer_accept` refuse it), and every gate that reads one checks
|
|
45
|
+
* the global grant, so a scoped builtin row confers nothing.
|
|
46
|
+
*
|
|
47
|
+
* @param name - the role name to check
|
|
48
|
+
* @returns `true` for `keeper` or `admin`
|
|
49
|
+
*/
|
|
50
|
+
export const is_builtin_role = (name) => name === ROLE_KEEPER || name === ROLE_ADMIN;
|
|
39
51
|
/**
|
|
40
52
|
* Builtin role specs, keyed by role name. Not overridable by consumers
|
|
41
53
|
* — read once at startup by `create_role_schema` and the action
|
|
@@ -39,6 +39,19 @@
|
|
|
39
39
|
import { type RpcAction } from '../actions/action_rpc.js';
|
|
40
40
|
import { type RoleSchemaResult } from './role_schema.js';
|
|
41
41
|
import type { ActionFactoryDeps } from './deps.js';
|
|
42
|
+
/**
|
|
43
|
+
* Validate a deployment's self-service eligible-role set at construction.
|
|
44
|
+
*
|
|
45
|
+
* Refuses a builtin role (`admin` / `keeper`) — self-toggling one would hand
|
|
46
|
+
* any account instance-wide authority, so no eligible set may name it — and a
|
|
47
|
+
* name outside the `RoleName` grammar. The same fail-loud-at-boot shape as
|
|
48
|
+
* `create_role_schema`, which refuses a builtin name where only app roles
|
|
49
|
+
* belong. Twin of the Rust `validate_self_service_eligible_roles`.
|
|
50
|
+
*
|
|
51
|
+
* @param roles - the eligible role names
|
|
52
|
+
* @throws Error on a builtin role or a name outside the role grammar
|
|
53
|
+
*/
|
|
54
|
+
export declare const validate_self_service_eligible_roles: (roles: Iterable<string>) => void;
|
|
42
55
|
/** Options for `create_self_service_role_actions`. */
|
|
43
56
|
export interface SelfServiceRoleActionsOptions {
|
|
44
57
|
/**
|
|
@@ -70,6 +83,7 @@ export interface SelfServiceRoleActionsOptions {
|
|
|
70
83
|
* @param options - optional eligible-role override plus optional role schema for default-eligibility derivation
|
|
71
84
|
* @returns the `RpcAction` array to spread into a `create_rpc_endpoint` call
|
|
72
85
|
* @throws Error at factory time if any `eligible_roles` entry is missing from `options.roles.role_specs`
|
|
86
|
+
* @throws Error at factory time if the eligible set names a builtin role or an invalid role name
|
|
73
87
|
*/
|
|
74
88
|
export declare const create_self_service_role_actions: (deps: ActionFactoryDeps, options?: SelfServiceRoleActionsOptions) => Array<RpcAction>;
|
|
75
89
|
//# sourceMappingURL=self_service_role_actions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self_service_role_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE/F,OAAO,
|
|
1
|
+
{"version":3,"file":"self_service_role_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE/F,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAWnD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oCAAoC,GAAI,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAG,IAW9E,CAAC;AAEF,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC7C;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,iBAAiB,EACvB,UAAS,6BAAkC,KACzC,KAAK,CAAC,SAAS,CA6HjB,CAAC"}
|
|
@@ -38,12 +38,34 @@
|
|
|
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, is_builtin_role, list_roles_with_grant_path, RoleName } 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';
|
|
45
45
|
import { has_scoped_role } from './request_context.js';
|
|
46
46
|
import { ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE, self_service_role_set_action_spec } from './self_service_role_action_specs.js';
|
|
47
|
+
/**
|
|
48
|
+
* Validate a deployment's self-service eligible-role set at construction.
|
|
49
|
+
*
|
|
50
|
+
* Refuses a builtin role (`admin` / `keeper`) — self-toggling one would hand
|
|
51
|
+
* any account instance-wide authority, so no eligible set may name it — and a
|
|
52
|
+
* name outside the `RoleName` grammar. The same fail-loud-at-boot shape as
|
|
53
|
+
* `create_role_schema`, which refuses a builtin name where only app roles
|
|
54
|
+
* belong. Twin of the Rust `validate_self_service_eligible_roles`.
|
|
55
|
+
*
|
|
56
|
+
* @param roles - the eligible role names
|
|
57
|
+
* @throws Error on a builtin role or a name outside the role grammar
|
|
58
|
+
*/
|
|
59
|
+
export const validate_self_service_eligible_roles = (roles) => {
|
|
60
|
+
for (const role of roles) {
|
|
61
|
+
if (is_builtin_role(role)) {
|
|
62
|
+
throw new Error(`self-service eligible role "${role}" is a builtin role — builtin roles are never self-service`);
|
|
63
|
+
}
|
|
64
|
+
if (!RoleName.safeParse(role).success) {
|
|
65
|
+
throw new Error(`self-service eligible role "${role}" is not a valid role name`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
47
69
|
/**
|
|
48
70
|
* Build the unified self-service role toggle RPC action.
|
|
49
71
|
*
|
|
@@ -53,12 +75,14 @@ import { ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE, self_service_role_set_action_spec
|
|
|
53
75
|
* @param options - optional eligible-role override plus optional role schema for default-eligibility derivation
|
|
54
76
|
* @returns the `RpcAction` array to spread into a `create_rpc_endpoint` call
|
|
55
77
|
* @throws Error at factory time if any `eligible_roles` entry is missing from `options.roles.role_specs`
|
|
78
|
+
* @throws Error at factory time if the eligible set names a builtin role or an invalid role name
|
|
56
79
|
*/
|
|
57
80
|
export const create_self_service_role_actions = (deps, options = {}) => {
|
|
58
81
|
const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
|
|
59
82
|
const eligible = options.eligible_roles
|
|
60
83
|
? new Set(options.eligible_roles)
|
|
61
84
|
: new Set(list_roles_with_grant_path(role_specs, GRANT_PATH_SELF_SERVICE));
|
|
85
|
+
validate_self_service_eligible_roles(eligible);
|
|
62
86
|
if (options.eligible_roles && options.roles) {
|
|
63
87
|
for (const r of eligible) {
|
|
64
88
|
if (!role_specs.has(r)) {
|
package/dist/http/CLAUDE.md
CHANGED
|
@@ -17,7 +17,7 @@ effects, see ../../../docs/architecture.md.
|
|
|
17
17
|
- `http/route_spec.ts` — `RouteSpec` + `apply_route_specs`, validation pipeline, transactions.
|
|
18
18
|
- `http/auth_shape.ts` — canonical `RouteAuth` Zod schema + cross-axis invariants + predicates.
|
|
19
19
|
- `http/error_schemas.ts` — `ERROR_*` constants, standard error shapes, `derive_error_schemas`.
|
|
20
|
-
- `http/schema_helpers.ts` — shared Zod introspection (null/strict/surface/merge/middleware-applies)
|
|
20
|
+
- `http/schema_helpers.ts` — shared Zod introspection (null/void/strict/surface/merge/middleware-applies) + `to_void_params` / `to_input_params` / `safe_parse_dropping_unknown_keys`.
|
|
21
21
|
- `http/middleware_spec.ts` — `MiddlewareSpec` interface.
|
|
22
22
|
- `http/surface.ts` — `AppSurface`, `AppSurfaceSpec`, `generate_app_surface`, diagnostics.
|
|
23
23
|
- `http/surface_query.ts` — pure filters/groupings over `AppSurface`.
|
|
@@ -220,7 +220,7 @@ confirmation.
|
|
|
220
220
|
— extracted to break a circular dependency between `http/route_spec.ts`
|
|
221
221
|
(input validation) and `http/surface.ts` (surface generation).
|
|
222
222
|
|
|
223
|
-
**Import `is_null_schema`, `is_strict_object_schema`, `schema_to_surface`,
|
|
223
|
+
**Import `is_null_schema`, `is_void_schema`, `to_void_params`, `to_input_params`, `is_strict_object_schema`, `schema_to_surface`,
|
|
224
224
|
`middleware_applies`, and `merge_error_schemas` from `http/schema_helpers.ts`,
|
|
225
225
|
not from `http/surface.ts`.** The helpers were moved; `http/surface.ts`
|
|
226
226
|
only imports and re-uses them for generation logic.
|
|
@@ -228,6 +228,10 @@ only imports and re-uses them for generation logic.
|
|
|
228
228
|
Key helpers:
|
|
229
229
|
|
|
230
230
|
- `is_null_schema(schema)` — `instanceof z.ZodNull` (not parse-null, to avoid false positives from `z.nullable(z.string())`)
|
|
231
|
+
- `is_void_schema(schema)` — `instanceof z.ZodVoid`; a `z.void()` input declares a parameterless RPC method
|
|
232
|
+
- `to_void_params(raw_params)` — reads absent, `null`, and `{}` params of a `z.void()` input as the no-arg call (`undefined`), passing any other shape through for `z.void()` to refuse — the twin of the Rust spine's `require_void_params`
|
|
233
|
+
- `to_input_params(input, raw_params)` — the one params normalizer every receiving end runs before `input.safeParse`: `to_void_params` for a `z.void()` input, else absent/`null` → `{}`; used by both the server dispatch core (`perform_action`) and the peer receive path (`ActionDispatcher`)
|
|
234
|
+
- `safe_parse_dropping_unknown_keys(schema, value)` — the forward-compatible read of a remote-authored payload: when every issue is an unrecognized key, strips those keys from a copy and reparses; any other issue still fails. Used for response `result`s (`ActionEvent`) and peer replies (`peer/ping`); matches serde's ignore-unknown-fields default on the Rust spine
|
|
231
235
|
- `is_strict_object_schema(schema)` — detects `z.strictObject()` by checking `schema.def.catchall instanceof z.ZodNever`
|
|
232
236
|
- `schema_to_surface(schema)` — Zod → JSON Schema, with `$schema` and `default` keys stripped recursively (defaults may be non-deterministic; `$schema` is snapshot noise)
|
|
233
237
|
- `middleware_applies(mw_path, route_path)` — Hono pattern matching: `'*'`, exact, `'/api/*'` prefix (handles `prefix.slice(0, -1)` so `/api/*` also matches the bare `/api`)
|
|
@@ -401,7 +405,7 @@ to a JSON-RPC code.
|
|
|
401
405
|
- Envelope schemas in `http/jsonrpc.ts`: `JsonrpcRequest`, `JsonrpcNotification`, `JsonrpcResponse`, `JsonrpcErrorResponse`, `JsonrpcResponseOrError`, `JsonrpcMessage`, `JsonrpcMessageFromClientToServer`, `JsonrpcMessageFromServerToClient`. Also `JsonrpcRequestId`, `JsonrpcMethod`, `JsonrpcProgressToken`, `JsonrpcMcpMeta`, `JsonrpcRequestParamsMeta`
|
|
402
406
|
- Builders in `http/jsonrpc_helpers.ts`: `create_jsonrpc_request`, `create_jsonrpc_notification`, `create_jsonrpc_response`, `create_jsonrpc_error_response`, `create_jsonrpc_error_response_from_thrown` (preserves code/message/data on `ThrownJsonrpcError`; plain `Error` → `internal_error` with `{stack}` in DEV)
|
|
403
407
|
- Type guards: `is_jsonrpc_request_id` (rejects NaN/Infinity), `is_jsonrpc_object`, `is_jsonrpc_message`, `is_jsonrpc_request` / `_notification` / `_response` / `_error_response`
|
|
404
|
-
- Converters: `to_jsonrpc_message_id`, `to_jsonrpc_params` (normalizes primitives to `{value}`)
|
|
408
|
+
- Converters: `to_jsonrpc_message_id`, `to_jsonrpc_params` (normalizes primitives to `{value}`)
|
|
405
409
|
|
|
406
410
|
Handlers can `throw jsonrpc_errors.*` — `apply_route_specs`' error-catch
|
|
407
411
|
layer converts to `{error: JsonrpcErrorObject}` at the correct HTTP status.
|
|
@@ -61,9 +61,4 @@ export declare const to_jsonrpc_envelope_id: (frame: unknown) => JsonrpcRequestI
|
|
|
61
61
|
* Returns `undefined` for null/undefined, wraps primitives in `{value}`.
|
|
62
62
|
*/
|
|
63
63
|
export declare const to_jsonrpc_params: (input: unknown) => Record<string, any> | undefined;
|
|
64
|
-
/**
|
|
65
|
-
* Normalizes output to JSON-RPC result format.
|
|
66
|
-
* Returns empty object for null/undefined, wraps primitives in `{value}`.
|
|
67
|
-
*/
|
|
68
|
-
export declare const to_jsonrpc_result: (output: unknown) => Record<string, any>;
|
|
69
64
|
//# sourceMappingURL=jsonrpc_helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonrpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,eAAe,EACf,MAAM,cAAc,CAAC;AAKtB,0CAA0C;AAC1C,eAAO,MAAM,sBAAsB,GAClC,QAAQ,aAAa,EACrB,QAAQ,oBAAoB,GAAG,SAAS,EACxC,IAAI,gBAAgB,KAClB,cAUF,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,GACnC,IAAI,gBAAgB,EACpB,QAAQ,aAAa,KACnB,eAID,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,GACvC,QAAQ,aAAa,EACrB,QAAQ,yBAAyB,GAAG,SAAS,KAC3C,mBASF,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,6BAA6B,GACzC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAC9B,OAAO,oBAAoB,CAAC,OAAO,CAAC,KAClC,oBAID,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yCAAyC,GACrD,IAAI,gBAAgB,GAAG,IAAI,EAC3B,OAAO,OAAO,KACZ,oBAyBF,CAAC;AAIF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,GAAI,IAAI,OAAO,KAAG,EAAE,IAAI,gBAGzD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,GAC7B,SAAS,OAAO,KACd,OAAO,IAAI;IAAE,OAAO,EAAE,OAAO,eAAe,CAAA;CAIF,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,GAC9B,SAAS,OAAO,KACd,OAAO,IAAI,cAAc,GAAG,KAAK,CAAC,cAAc,CAGrB,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,cACI,CAAC;AAEtE,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,mBACE,CAAC;AAEzE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,eACG,CAAC;AAEtE,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,oBACJ,CAAC;AAIrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,gBAAgB,GAAG,IAOjF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,gBAAgB,GAAG,IACX,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAQxE,CAAC
|
|
1
|
+
{"version":3,"file":"jsonrpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,eAAe,EACf,MAAM,cAAc,CAAC;AAKtB,0CAA0C;AAC1C,eAAO,MAAM,sBAAsB,GAClC,QAAQ,aAAa,EACrB,QAAQ,oBAAoB,GAAG,SAAS,EACxC,IAAI,gBAAgB,KAClB,cAUF,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,GACnC,IAAI,gBAAgB,EACpB,QAAQ,aAAa,KACnB,eAID,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,GACvC,QAAQ,aAAa,EACrB,QAAQ,yBAAyB,GAAG,SAAS,KAC3C,mBASF,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,6BAA6B,GACzC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAC9B,OAAO,oBAAoB,CAAC,OAAO,CAAC,KAClC,oBAID,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yCAAyC,GACrD,IAAI,gBAAgB,GAAG,IAAI,EAC3B,OAAO,OAAO,KACZ,oBAyBF,CAAC;AAIF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,GAAI,IAAI,OAAO,KAAG,EAAE,IAAI,gBAGzD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,GAC7B,SAAS,OAAO,KACd,OAAO,IAAI;IAAE,OAAO,EAAE,OAAO,eAAe,CAAA;CAIF,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,GAC9B,SAAS,OAAO,KACd,OAAO,IAAI,cAAc,GAAG,KAAK,CAAC,cAAc,CAGrB,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,cACI,CAAC;AAEtE,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,mBACE,CAAC;AAEzE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,eACG,CAAC;AAEtE,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,oBACJ,CAAC;AAIrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,gBAAgB,GAAG,IAOjF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,gBAAgB,GAAG,IACX,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAQxE,CAAC"}
|
|
@@ -136,16 +136,3 @@ export const to_jsonrpc_params = (input) => {
|
|
|
136
136
|
}
|
|
137
137
|
return { value: input };
|
|
138
138
|
};
|
|
139
|
-
/**
|
|
140
|
-
* Normalizes output to JSON-RPC result format.
|
|
141
|
-
* Returns empty object for null/undefined, wraps primitives in `{value}`.
|
|
142
|
-
*/
|
|
143
|
-
export const to_jsonrpc_result = (output) => {
|
|
144
|
-
if (output === null || output === undefined) {
|
|
145
|
-
return {};
|
|
146
|
-
}
|
|
147
|
-
if (typeof output === 'object' && !Array.isArray(output)) {
|
|
148
|
-
return output;
|
|
149
|
-
}
|
|
150
|
-
return { value: output };
|
|
151
|
-
};
|
|
@@ -27,6 +27,62 @@ export declare const is_null_schema: (schema: z.ZodType) => boolean;
|
|
|
27
27
|
* and the dispatcher maps absent params to `undefined` for these specs.
|
|
28
28
|
*/
|
|
29
29
|
export declare const is_void_schema: (schema: z.ZodType) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Normalize the raw `params` of a `z.void()` input: an absent `params`, an
|
|
32
|
+
* empty object, and the `null` a GET `?params=null` parses to are all the
|
|
33
|
+
* no-arg call (`undefined`); anything else passes through for `z.void()` to
|
|
34
|
+
* refuse.
|
|
35
|
+
*
|
|
36
|
+
* JSON-RPC 2.0 lets a parameterless call omit `params`, and an empty by-name
|
|
37
|
+
* structure carries no parameters, so refusing `{}` would only break clients
|
|
38
|
+
* that send it for a parameterless call. Arrays — `[]` included — are not
|
|
39
|
+
* normalized: RPC params are by-name only. The Rust spine's
|
|
40
|
+
* `require_void_params` accepts the same shapes. Receiving ends reach it
|
|
41
|
+
* through `to_input_params`.
|
|
42
|
+
*
|
|
43
|
+
* @param raw_params - the request's `params` as parsed off the wire
|
|
44
|
+
* @returns `undefined` for an empty shape, else `raw_params` unchanged
|
|
45
|
+
*/
|
|
46
|
+
export declare const to_void_params: (raw_params: unknown) => unknown;
|
|
47
|
+
/**
|
|
48
|
+
* Normalize the raw `params` of an RPC call for `input` to validate: for a
|
|
49
|
+
* `z.void()` input, `to_void_params`; for any other input, an absent or
|
|
50
|
+
* `null` `params` reads as `{}`, so an all-optional object input accepts a
|
|
51
|
+
* call that omits them. Every receiving end — the server dispatch
|
|
52
|
+
* (`perform_action`) and a peer receiving a request or notification
|
|
53
|
+
* (`ActionDispatcher`) — reads params through this, so a peer is never
|
|
54
|
+
* stricter than the server.
|
|
55
|
+
*
|
|
56
|
+
* @param input - the action's input schema
|
|
57
|
+
* @param raw_params - the call's `params` as parsed off the wire
|
|
58
|
+
* @returns the value to run `input.safeParse` on
|
|
59
|
+
*/
|
|
60
|
+
export declare const to_input_params: (input: z.ZodType, raw_params: unknown) => unknown;
|
|
61
|
+
/**
|
|
62
|
+
* `schema.safeParse(value)`, except that keys the schema doesn't declare are
|
|
63
|
+
* dropped rather than refused — the forward-compatible read of a payload a
|
|
64
|
+
* remote authored.
|
|
65
|
+
*
|
|
66
|
+
* Output schemas are strict so the server's DEV output validation catches a
|
|
67
|
+
* handler leaking fields it shouldn't. The receiving side, though, is often
|
|
68
|
+
* older than the remote it talks to — a deploy lands before open tabs reload
|
|
69
|
+
* — and a remote that adds a field is making a compatible change. So when
|
|
70
|
+
* every issue is an unrecognized key, those keys are stripped from a copy of
|
|
71
|
+
* `value` and it's parsed again; any other issue (a wrong type, a missing
|
|
72
|
+
* field, `null` where a value is required) still fails. `value` itself is
|
|
73
|
+
* never mutated. This matches serde's default on the Rust spine, which
|
|
74
|
+
* ignores unknown fields. Keys nested in a `z.union` branch surface as a
|
|
75
|
+
* union issue and aren't stripped; a `z.discriminatedUnion` reports its
|
|
76
|
+
* matched branch's issues directly, so those are.
|
|
77
|
+
*
|
|
78
|
+
* Used for a response's `result` (`ActionEvent`) and for a peer's reply to a
|
|
79
|
+
* server-initiated request (`peer/ping`).
|
|
80
|
+
*
|
|
81
|
+
* @param schema - the declared shape
|
|
82
|
+
* @param value - the remote-authored payload
|
|
83
|
+
* @returns the parse result, with undeclared keys dropped on success
|
|
84
|
+
*/
|
|
85
|
+
export declare const safe_parse_dropping_unknown_keys: <T extends z.ZodType>(schema: T, value: unknown) => z.ZodSafeParseResult<z.output<T>>;
|
|
30
86
|
/**
|
|
31
87
|
* Check if a schema is a strict object (`z.strictObject()`).
|
|
32
88
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAUtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,OAAO,KAAG,OAUpD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,OAAO,KAAG,OACA,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gCAAgC,GAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EACnE,QAAQ,CAAC,EACT,OAAO,OAAO,KACZ,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAclC,CAAC;AAWF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAUtB,CAAC"}
|
|
@@ -26,6 +26,97 @@ export const is_null_schema = (schema) => schema instanceof z.ZodNull;
|
|
|
26
26
|
* and the dispatcher maps absent params to `undefined` for these specs.
|
|
27
27
|
*/
|
|
28
28
|
export const is_void_schema = (schema) => schema instanceof z.ZodVoid;
|
|
29
|
+
/**
|
|
30
|
+
* Normalize the raw `params` of a `z.void()` input: an absent `params`, an
|
|
31
|
+
* empty object, and the `null` a GET `?params=null` parses to are all the
|
|
32
|
+
* no-arg call (`undefined`); anything else passes through for `z.void()` to
|
|
33
|
+
* refuse.
|
|
34
|
+
*
|
|
35
|
+
* JSON-RPC 2.0 lets a parameterless call omit `params`, and an empty by-name
|
|
36
|
+
* structure carries no parameters, so refusing `{}` would only break clients
|
|
37
|
+
* that send it for a parameterless call. Arrays — `[]` included — are not
|
|
38
|
+
* normalized: RPC params are by-name only. The Rust spine's
|
|
39
|
+
* `require_void_params` accepts the same shapes. Receiving ends reach it
|
|
40
|
+
* through `to_input_params`.
|
|
41
|
+
*
|
|
42
|
+
* @param raw_params - the request's `params` as parsed off the wire
|
|
43
|
+
* @returns `undefined` for an empty shape, else `raw_params` unchanged
|
|
44
|
+
*/
|
|
45
|
+
export const to_void_params = (raw_params) => {
|
|
46
|
+
if (raw_params === undefined || raw_params === null)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (typeof raw_params === 'object' &&
|
|
49
|
+
!Array.isArray(raw_params) &&
|
|
50
|
+
Object.keys(raw_params).length === 0) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
return raw_params;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Normalize the raw `params` of an RPC call for `input` to validate: for a
|
|
57
|
+
* `z.void()` input, `to_void_params`; for any other input, an absent or
|
|
58
|
+
* `null` `params` reads as `{}`, so an all-optional object input accepts a
|
|
59
|
+
* call that omits them. Every receiving end — the server dispatch
|
|
60
|
+
* (`perform_action`) and a peer receiving a request or notification
|
|
61
|
+
* (`ActionDispatcher`) — reads params through this, so a peer is never
|
|
62
|
+
* stricter than the server.
|
|
63
|
+
*
|
|
64
|
+
* @param input - the action's input schema
|
|
65
|
+
* @param raw_params - the call's `params` as parsed off the wire
|
|
66
|
+
* @returns the value to run `input.safeParse` on
|
|
67
|
+
*/
|
|
68
|
+
export const to_input_params = (input, raw_params) => is_void_schema(input) ? to_void_params(raw_params) : (raw_params ?? {});
|
|
69
|
+
/**
|
|
70
|
+
* `schema.safeParse(value)`, except that keys the schema doesn't declare are
|
|
71
|
+
* dropped rather than refused — the forward-compatible read of a payload a
|
|
72
|
+
* remote authored.
|
|
73
|
+
*
|
|
74
|
+
* Output schemas are strict so the server's DEV output validation catches a
|
|
75
|
+
* handler leaking fields it shouldn't. The receiving side, though, is often
|
|
76
|
+
* older than the remote it talks to — a deploy lands before open tabs reload
|
|
77
|
+
* — and a remote that adds a field is making a compatible change. So when
|
|
78
|
+
* every issue is an unrecognized key, those keys are stripped from a copy of
|
|
79
|
+
* `value` and it's parsed again; any other issue (a wrong type, a missing
|
|
80
|
+
* field, `null` where a value is required) still fails. `value` itself is
|
|
81
|
+
* never mutated. This matches serde's default on the Rust spine, which
|
|
82
|
+
* ignores unknown fields. Keys nested in a `z.union` branch surface as a
|
|
83
|
+
* union issue and aren't stripped; a `z.discriminatedUnion` reports its
|
|
84
|
+
* matched branch's issues directly, so those are.
|
|
85
|
+
*
|
|
86
|
+
* Used for a response's `result` (`ActionEvent`) and for a peer's reply to a
|
|
87
|
+
* server-initiated request (`peer/ping`).
|
|
88
|
+
*
|
|
89
|
+
* @param schema - the declared shape
|
|
90
|
+
* @param value - the remote-authored payload
|
|
91
|
+
* @returns the parse result, with undeclared keys dropped on success
|
|
92
|
+
*/
|
|
93
|
+
export const safe_parse_dropping_unknown_keys = (schema, value) => {
|
|
94
|
+
const parsed = schema.safeParse(value);
|
|
95
|
+
if (parsed.success)
|
|
96
|
+
return parsed;
|
|
97
|
+
const { issues } = parsed.error;
|
|
98
|
+
if (!issues.every((issue) => issue.code === 'unrecognized_keys'))
|
|
99
|
+
return parsed;
|
|
100
|
+
const stripped = structuredClone(value);
|
|
101
|
+
for (const issue of issues) {
|
|
102
|
+
const target = get_at_path(stripped, issue.path);
|
|
103
|
+
if (typeof target !== 'object' || target === null)
|
|
104
|
+
return parsed;
|
|
105
|
+
for (const key of issue.keys) {
|
|
106
|
+
Reflect.deleteProperty(target, key);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return schema.safeParse(stripped);
|
|
110
|
+
};
|
|
111
|
+
const get_at_path = (value, path) => {
|
|
112
|
+
let current = value;
|
|
113
|
+
for (const segment of path) {
|
|
114
|
+
if (typeof current !== 'object' || current === null)
|
|
115
|
+
return undefined;
|
|
116
|
+
current = current[segment];
|
|
117
|
+
}
|
|
118
|
+
return current;
|
|
119
|
+
};
|
|
29
120
|
/**
|
|
30
121
|
* Check if a schema is a strict object (`z.strictObject()`).
|
|
31
122
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -375,6 +375,7 @@ export const create_app_server = async (options) => {
|
|
|
375
375
|
transport: endpoint_transport,
|
|
376
376
|
heartbeat: endpoint.heartbeat,
|
|
377
377
|
artificial_delay: endpoint.artificial_delay,
|
|
378
|
+
max_message_bytes: endpoint.max_message_bytes,
|
|
378
379
|
on_socket_open: endpoint.on_socket_open,
|
|
379
380
|
on_socket_close: endpoint.on_socket_close,
|
|
380
381
|
log,
|
|
@@ -138,7 +138,9 @@ export declare const create_serve_cell_fact_route_spec: (options: CreateServeFac
|
|
|
138
138
|
* Auth is `{account: 'required', actor: 'required', roles: ['admin']}` —
|
|
139
139
|
* the dispatcher's authorization phase resolves the acting actor and the
|
|
140
140
|
* post-authorization guard enforces the admin role before the handler runs.
|
|
141
|
-
* The handler re-checks
|
|
141
|
+
* The handler re-checks the **global** admin grant
|
|
142
|
+
* (`has_scoped_role(_, admin, null)`, the auth phase's own reading) as
|
|
143
|
+
* defense-in-depth so a future
|
|
142
144
|
* mounting/auth-shape regression fails closed rather than serving by bare
|
|
143
145
|
* hash to a non-admin.
|
|
144
146
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve_fact_route.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/serve_fact_route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAetD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkEjD,MAAM,WAAW,+BAA+B;IAC/C;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACZ;AAgHD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAC7C,SAAS,+BAA+B,KACtC,SAgDF,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"serve_fact_route.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/serve_fact_route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAetD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkEjD,MAAM,WAAW,+BAA+B;IAC/C;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACZ;AAgHD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAC7C,SAAS,+BAA+B,KACtC,SAgDF,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,4BAA4B,GACxC,SAAS,+BAA+B,KACtC,SA2CF,CAAC"}
|
|
@@ -93,7 +93,7 @@ import { join } from 'node:path';
|
|
|
93
93
|
import { FactHashSchema } from '@fuzdev/fuz_util/hash_schemas.ts';
|
|
94
94
|
import { Uuid } from '@fuzdev/fuz_util/id.ts';
|
|
95
95
|
import { z } from 'zod';
|
|
96
|
-
import { build_request_context, get_request_context,
|
|
96
|
+
import { build_request_context, get_request_context, has_scoped_role } from '../auth/request_context.js';
|
|
97
97
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
98
98
|
import { ActingActor } from '../http/auth_shape.js';
|
|
99
99
|
import { ACCOUNT_ID_KEY } from '../hono_context.js';
|
|
@@ -315,7 +315,9 @@ export const create_serve_cell_fact_route_spec = (options) => {
|
|
|
315
315
|
* Auth is `{account: 'required', actor: 'required', roles: ['admin']}` —
|
|
316
316
|
* the dispatcher's authorization phase resolves the acting actor and the
|
|
317
317
|
* post-authorization guard enforces the admin role before the handler runs.
|
|
318
|
-
* The handler re-checks
|
|
318
|
+
* The handler re-checks the **global** admin grant
|
|
319
|
+
* (`has_scoped_role(_, admin, null)`, the auth phase's own reading) as
|
|
320
|
+
* defense-in-depth so a future
|
|
319
321
|
* mounting/auth-shape regression fails closed rather than serving by bare
|
|
320
322
|
* hash to a non-admin.
|
|
321
323
|
*/
|
|
@@ -351,8 +353,9 @@ export const create_serve_fact_route_spec = (options) => {
|
|
|
351
353
|
const { hash } = get_route_params(c);
|
|
352
354
|
// Defense-in-depth: the auth phase already gated this on the admin
|
|
353
355
|
// role, but re-check the resolved context so a mounting/auth-shape
|
|
354
|
-
// regression fails closed instead of serving by bare hash.
|
|
355
|
-
|
|
356
|
+
// regression fails closed instead of serving by bare hash. Global
|
|
357
|
+
// grant only — a scoped `admin` row must not read every fact.
|
|
358
|
+
if (!has_scoped_role(get_request_context(c), ROLE_ADMIN, null)) {
|
|
356
359
|
return c.body(null, 404);
|
|
357
360
|
}
|
|
358
361
|
return serve_fact_bytes(c, route, hash, config);
|