@fuzdev/fuz_app 0.148.0 → 0.150.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 +11 -9
- package/dist/actions/action_bridge.d.ts +7 -0
- package/dist/actions/action_bridge.d.ts.map +1 -1
- package/dist/actions/action_bridge.js +10 -0
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +14 -1
- package/dist/actions/action_event_types.d.ts +1 -1
- package/dist/actions/action_event_types.d.ts.map +1 -1
- package/dist/actions/perform_action.d.ts +17 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +30 -7
- package/dist/actions/register_action_ws.d.ts +8 -2
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +24 -4
- package/dist/actions/transports_ws_auth_guard.d.ts +6 -4
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +9 -6
- package/dist/actions/ws_endpoint_spec.d.ts +1 -1
- package/dist/auth/CLAUDE.md +72 -33
- package/dist/auth/account_action_specs.d.ts +12 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +16 -2
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +7 -4
- package/dist/auth/actor_lookup_queries.d.ts +3 -2
- package/dist/auth/actor_lookup_queries.d.ts.map +1 -1
- package/dist/auth/actor_lookup_queries.js +6 -3
- package/dist/auth/actor_search_queries.d.ts +5 -2
- package/dist/auth/actor_search_queries.d.ts.map +1 -1
- package/dist/auth/actor_search_queries.js +11 -4
- package/dist/auth/admin_action_specs.d.ts +4 -4
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +33 -12
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +35 -6
- package/dist/auth/all_cell_actions.d.ts +11 -2
- package/dist/auth/all_cell_actions.d.ts.map +1 -1
- package/dist/auth/all_cell_actions.js +2 -1
- package/dist/auth/audit_emitter.d.ts +23 -3
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +14 -4
- package/dist/auth/audit_log_schema.d.ts +1 -0
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +9 -5
- package/dist/auth/bootstrap_account.d.ts +25 -1
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +37 -4
- package/dist/auth/bootstrap_routes.d.ts +3 -2
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +5 -4
- package/dist/auth/cell_action_specs.d.ts +215 -15
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +103 -16
- package/dist/auth/cell_actions.d.ts +40 -18
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +126 -19
- package/dist/auth/cell_audit_events.d.ts +1 -1
- package/dist/auth/cell_audit_events.d.ts.map +1 -1
- package/dist/auth/cell_audit_events.js +3 -2
- package/dist/auth/cell_audit_metadata.d.ts +11 -0
- package/dist/auth/cell_audit_metadata.d.ts.map +1 -1
- package/dist/auth/cell_audit_metadata.js +10 -0
- package/dist/auth/cell_grant_action_specs.d.ts +7 -0
- package/dist/auth/cell_grant_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_grant_action_specs.js +7 -0
- package/dist/auth/cell_grant_actions.d.ts +36 -4
- package/dist/auth/cell_grant_actions.d.ts.map +1 -1
- package/dist/auth/cell_grant_actions.js +20 -3
- package/dist/auth/credential_type_schema.d.ts +3 -2
- package/dist/auth/credential_type_schema.d.ts.map +1 -1
- package/dist/auth/credential_type_schema.js +3 -2
- package/dist/auth/role_grant_offer_action_specs.d.ts +18 -2
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +30 -6
- package/dist/auth/role_grant_offer_actions.d.ts +9 -4
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +58 -7
- package/dist/auth/role_grant_offer_notifications.d.ts +3 -2
- package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_notifications.js +3 -2
- package/dist/auth/role_grant_offer_queries.d.ts +20 -0
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +35 -0
- package/dist/auth/role_grant_queries.d.ts +27 -9
- package/dist/auth/role_grant_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_queries.js +40 -13
- package/dist/auth/role_schema.d.ts +14 -8
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +6 -3
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +20 -0
- package/dist/db/CLAUDE.md +9 -2
- package/dist/db/cell_ddl.d.ts +9 -1
- package/dist/db/cell_ddl.d.ts.map +1 -1
- package/dist/db/cell_ddl.js +11 -1
- package/dist/db/cell_queries.d.ts +53 -7
- package/dist/db/cell_queries.d.ts.map +1 -1
- package/dist/db/cell_queries.js +61 -7
- package/dist/http/CLAUDE.md +14 -2
- package/dist/http/body_limit.d.ts +3 -1
- package/dist/http/body_limit.d.ts.map +1 -1
- package/dist/http/body_limit.js +6 -1
- package/dist/http/error_schemas.d.ts +8 -0
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +12 -0
- package/dist/http/jsonrpc.d.ts +9 -0
- package/dist/http/jsonrpc.d.ts.map +1 -1
- package/dist/http/jsonrpc.js +17 -0
- package/dist/http/jsonrpc_errors.d.ts +40 -15
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +99 -35
- package/dist/http/proxy.d.ts +4 -2
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +7 -2
- package/dist/http/surface.d.ts +3 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +7 -4
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +3 -2
- package/dist/schema_meta.d.ts +92 -1
- package/dist/schema_meta.d.ts.map +1 -1
- package/dist/schema_meta.js +117 -0
- package/dist/server/app_server.d.ts +13 -5
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +32 -8
- package/dist/testing/CLAUDE.md +196 -82
- package/dist/testing/adversarial_input_cases.d.ts +67 -7
- package/dist/testing/adversarial_input_cases.d.ts.map +1 -1
- package/dist/testing/adversarial_input_cases.js +210 -165
- package/dist/testing/app_server.d.ts +3 -1
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.d.ts +3 -2
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +5 -3
- package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
- package/dist/testing/cross_backend/actor_lookup.js +27 -0
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts +6 -0
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -1
- package/dist/testing/cross_backend/audit_cross_helpers.js +11 -0
- package/dist/testing/cross_backend/capabilities.d.ts +29 -5
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +10 -6
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +117 -2
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +109 -13
- package/dist/testing/cross_backend/cell_moderate.d.ts +7 -1
- package/dist/testing/cross_backend/cell_moderate.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_moderate.js +68 -4
- package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_ref_admission.js +18 -9
- package/dist/testing/cross_backend/conformance_table.d.ts +5 -0
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_table.js +12 -10
- package/dist/testing/cross_backend/cross_rpc.d.ts +3 -1
- package/dist/testing/cross_backend/cross_rpc.d.ts.map +1 -1
- package/dist/testing/cross_backend/cross_rpc.js +2 -2
- package/dist/testing/cross_backend/default_backend_configs.d.ts +9 -7
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +3 -3
- package/dist/testing/cross_backend/differential.d.ts +7 -0
- package/dist/testing/cross_backend/differential.d.ts.map +1 -1
- package/dist/testing/cross_backend/differential.js +17 -0
- package/dist/testing/cross_backend/expected_schema.json +1 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +5 -4
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.js +74 -2
- package/dist/testing/cross_backend/rpc_adversarial.d.ts +9 -0
- package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -1
- package/dist/testing/cross_backend/rpc_adversarial.js +16 -6
- package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts +1 -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 +6 -3
- package/dist/testing/cross_backend/setup.d.ts +2 -2
- package/dist/testing/cross_backend/spine_suites.d.ts +85 -5
- package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_suites.js +291 -20
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +15 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +24 -0
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts +18 -19
- 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 +66 -42
- package/dist/testing/cross_backend/testing_backdoor.d.ts +27 -4
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +136 -41
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +30 -15
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +52 -35
- package/dist/testing/cross_backend/transport_composition.js +3 -3
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +6 -3
- package/dist/testing/rpc_attack_surface.d.ts +10 -0
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +15 -3
- package/dist/testing/rpc_envelope_cases.d.ts +5 -2
- package/dist/testing/rpc_envelope_cases.d.ts.map +1 -1
- package/dist/testing/rpc_envelope_cases.js +4 -1
- package/dist/testing/rpc_round_trip.js +3 -3
- package/dist/testing/schema_generators.d.ts +99 -2
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +244 -76
- package/dist/testing/stubs.d.ts +4 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +6 -4
- package/dist/zod.d.ts +9 -0
- package/dist/zod.d.ts.map +1 -1
- package/dist/zod.js +20 -0
- package/package.json +1 -1
package/dist/auth/CLAUDE.md
CHANGED
|
@@ -37,7 +37,7 @@ over the pool so rows persist when request transactions roll back. See root
|
|
|
37
37
|
- `auth/password_argon2.ts` — `hash_password`, `verify_password`, `verify_dummy`, `argon2_password_deps`.
|
|
38
38
|
- `auth/api_token.ts` — `API_TOKEN_PREFIX` (`secret_fuz_token_`), `hash_api_token`, `generate_api_token`, and the shape precheck `is_api_token_shaped` (`API_TOKEN_REGEX`: the prefix plus exactly `API_TOKEN_BODY_LENGTH` = 43 base64url chars).
|
|
39
39
|
- `auth/daemon_token.ts` — `DaemonToken`, `DAEMON_TOKEN_HEADER` (`X-Daemon-Token`), `generate_daemon_token`, `validate_daemon_token`, `DaemonTokenState`.
|
|
40
|
-
- `auth/bootstrap_account.ts` — `bootstrap_account` (one-shot, `bootstrap_lock`-protected).
|
|
40
|
+
- `auth/bootstrap_account.ts` — `bootstrap_account` (one-shot, `bootstrap_lock`-protected) + `read_bootstrap_token`, the read both it and `check_bootstrap_status` use: the secure read less one trailing LF, a token under `BOOTSTRAP_TOKEN_MIN_BYTES` (32) refused as unreadable with an error log.
|
|
41
41
|
|
|
42
42
|
Cross-cutting notes that don't live on any single symbol:
|
|
43
43
|
|
|
@@ -77,8 +77,8 @@ Convention — `*_schema.ts` is Zod-only; `*_ddl.ts` holds DDL strings.
|
|
|
77
77
|
All take `deps: QueryDeps = {db}` first; `query_validate_api_token` adds `log` and returns a `ValidatedApiToken` — the row with `scope` parsed, refusing (returning `undefined` for) a row whose stored scope is unreadable.
|
|
78
78
|
|
|
79
79
|
- `auth/account_queries.ts` — account CRUD, actor resolution, password update with verify-write race guard, paged `query_admin_account_list`.
|
|
80
|
-
- `auth/actor_lookup_queries.ts` — batched `actor` ⨝ `account` for the labels arc.
|
|
81
|
-
- `auth/actor_search_queries.ts` — case-insensitive prefix search on `actor.name`, scope-filtered when not admin.
|
|
80
|
+
- `auth/actor_lookup_queries.ts` — batched `actor` ⨝ `account` for the labels arc; active actors of active accounts only.
|
|
81
|
+
- `auth/actor_search_queries.ts` — case-insensitive prefix search on `actor.name`, scope-filtered when not admin; active actors of active accounts only.
|
|
82
82
|
- `auth/role_grant_queries.ts` — idempotent create, IDOR-guarded revoke (with in-tx supersede), scope-aware lookup, role/account predicates, `query_role_grant_revoke_for_scope` parent-scope cascade.
|
|
83
83
|
- `auth/role_grant_offer_queries.ts` — offer create/decline/retract/list/history/sweep, atomic `query_accept_offer` with sibling supersede; error classes `RoleGrantOfferSelfTargetError` / `_AlreadyTerminalError` / `_ExpiredError` / `_NotFoundError` / `_ActorAccountMismatchError` / `_ActorMismatchError`.
|
|
84
84
|
- `auth/session_queries.ts` — server-side sessions (blake3-hashed), `query_session_revoke_by_hash_unscoped` (logout only), `query_session_enforce_limit` (transaction-required; returns the evicted sessions' ids — their token hashes — so the caller closes their connections after the commit), `query_session_cleanup_expired` (returns the swept sessions' ids for the same close — `cleanup_expired_sessions` is its caller). No touch/renewal query — `expires_at` is an absolute cap set at mint (`AUTH_SESSION_LIFETIME_MS`).
|
|
@@ -130,6 +130,7 @@ its registered listeners + optional `AuditLogConfig`. Its methods:
|
|
|
130
130
|
- `add_listener(listener)` — listener registration, returning a remover for that registration (idempotent; the same function registered twice is two registrations, each with its own remover). Twin of Rust `fuz_auth` `AuditEmitter::add_listener` in firing order and snapshot-at-notify
|
|
131
131
|
- `listener_count()` — registered-listener count, for tests / diagnostics
|
|
132
132
|
- `drain_inflight()` — test-binary barrier: waits until no `emit` write is in flight, writes started while waiting included. Only an emitter built with `track_inflight: true` tracks; otherwise it resolves at once (production never tracks). Backs `_testing_drain_effects` (twin of Rust `AuditEmitter::drain_inflight` / `new_with_inflight_tracking`)
|
|
133
|
+
- `is_tracking_inflight()` — whether the emitter was built with `track_inflight: true`, i.e. whether `drain_inflight` can wait on anything. `_testing_drain_effects` reports it as `tracked`, and `cross_drain_effects` (every `list_audit_events` read) refuses `false` (twin of Rust `AuditEmitter::is_tracking_inflight`)
|
|
133
134
|
|
|
134
135
|
Listeners are closure-private; they change only through `add_listener` and
|
|
135
136
|
its removers. `create_app_server` registers the audit-log SSE listener,
|
|
@@ -146,12 +147,16 @@ the next event, and one removed mid-fan-out still hears the in-flight event
|
|
|
146
147
|
**failure** row is announced as soon as it is written — the attempt happened
|
|
147
148
|
whatever the transaction does; a **success** row is announced only after the
|
|
148
149
|
request's transaction commits (a thunk on `ctx.post_commit_effects` that awaits
|
|
149
|
-
the write
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
the write; after the handler returns, on a route without one) and never when
|
|
151
|
+
the handler throws. The listeners act on a success row — the revocation guards
|
|
152
|
+
close connections, the audit stream broadcasts it — so announcing one before
|
|
153
|
+
its commit would close while the revoked credential still reads as valid, and
|
|
154
|
+
a rolled-back revocation would close anyway. A route that runs without a
|
|
155
|
+
request transaction and opens its own around just its writes (`/login`,
|
|
156
|
+
`/password`) emits its success row after that transaction commits. The Rust
|
|
157
|
+
spine follows the same order: a success row emitted inside a request
|
|
158
|
+
transaction is written in it with its fan-out queued behind the commit, and
|
|
159
|
+
`/login` and `/password` emit after their own commit. `AuditEmitterContext` is therefore
|
|
155
160
|
`{pending_effects, post_commit_effects}` — `RouteContext` and `ActionContext`
|
|
156
161
|
both satisfy it.
|
|
157
162
|
|
|
@@ -246,8 +251,9 @@ consumer's `validate_data` pass-through callback on `CellActionDeps`.
|
|
|
246
251
|
- `auth/cell_action_specs.ts` — `CellVisibility` enum, `CellPath` brand,
|
|
247
252
|
`CELL_KIND_LENGTH_MAX` (64 — the wire `kind` on `cell_create` and the
|
|
248
253
|
`cell_list` filter; the tag is copied into the cell's audit rows),
|
|
249
|
-
`CellJson`,
|
|
250
|
-
|
|
254
|
+
`CellJson`, `CellPolicy` (a root's contribution policy, `z.looseObject`), the
|
|
255
|
+
generic verb specs (`cell_create / get / update / delete / list / clone /
|
|
256
|
+
moderate / policy_set`), error reasons, and `all_cell_action_specs`
|
|
251
257
|
(spreads in the grant / field / item / audit registries so codegen + UI
|
|
252
258
|
see one cell namespace). `CellJson` has no hub axis; `path` is global. The
|
|
253
259
|
directory-tree columns `parent_id` / `root_id` (containment, immutable in v1)
|
|
@@ -310,24 +316,39 @@ auth, ids)`: two queries for the whole id-set, the cells read through the
|
|
|
310
316
|
the mounted `authorize_create` for **every** cell it writes as a parentless
|
|
311
317
|
create — a denial is the same 403 `cell_create_forbidden`, so clone is no
|
|
312
318
|
side door past the creation policy. The optional
|
|
313
|
-
parent-aware `authorize_create` dep (`CellCreateAuthorize` —
|
|
314
|
-
`{kind, data, parent_id, root_id,
|
|
315
|
-
|
|
319
|
+
parent-aware `authorize_create` dep (`CellCreateAuthorize` — an object whose
|
|
320
|
+
`authorize` takes a wider input `{kind, data, parent_id, root_id, root_policy,
|
|
321
|
+
scope_id}` than `validate_data` and returns a `CellCreateVerdict`
|
|
322
|
+
`{allow:false} | {allow:true, moderation_required}`, and whose optional
|
|
323
|
+
`validate_policy` accepts or refuses a root policy write)
|
|
316
324
|
gates create by capability; it runs after the validator + the parent-resolve
|
|
317
325
|
(which **404**s `cell_not_found` on a missing or soft-deleted root as on a
|
|
318
326
|
missing parent, authorizer or not).
|
|
319
327
|
A **viewable**-parent / root-creation deny is **403** `cell_create_forbidden`
|
|
320
328
|
(the create-path **404** mask is reserved for a hidden parent); `Allow` folds
|
|
321
329
|
the moderation outcome (born `pending`+private vs `approved`+author-visibility).
|
|
322
|
-
The authorizer is **pure** — the handler reads the governing root
|
|
323
|
-
|
|
324
|
-
`
|
|
325
|
-
single-connection deadlock of the in-memory drivers). `None`/omitted = open
|
|
326
|
-
mirrors `validate_data`)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
The authorizer is **pure** — the handler reads the governing root in-tx and
|
|
331
|
+
hands its `policy` column over as `root_policy`, so a directory policy
|
|
332
|
+
resolves `root_policy[kind]` without its own DB read (which also dodges the
|
|
333
|
+
single-connection deadlock of the in-memory drivers). `None`/omitted = open
|
|
334
|
+
create (the default; mirrors `validate_data`), and every non-null policy write
|
|
335
|
+
refused `cell_policy_unsupported`. A root's `policy` (a JSON object, roots only
|
|
336
|
+
by table CHECK, opaque to the spine, readable on `CellJson`) is set at a
|
|
337
|
+
root's `cell_create` and changed only by `cell_policy_set` — the 404 mask, then
|
|
338
|
+
manage-tier (403 `cell_policy_manage_only`, an editor grant included), then
|
|
339
|
+
root-only (400 `cell_policy_root_only`), then the authorizer's
|
|
340
|
+
`validate_policy`; audited with the new and the previous policy. `cell_update`
|
|
341
|
+
never writes it (an editor can rewrite `data`, so a policy read from `data`
|
|
342
|
+
would be the editor's to loosen), and a clone is born without one.
|
|
343
|
+
`cell_moderate` is the `pending → approved | rejected` transition (plus
|
|
344
|
+
`approved → rejected`, the takedown), gated on
|
|
345
|
+
`can_manage_cell` of the **governing root** (admin / root owner — the author
|
|
346
|
+
lands a 403, the anti-self-approval guard; a root owner reaches the check
|
|
347
|
+
through the steward arm); approve flips
|
|
348
|
+
`moderation → approved` + `visibility → public`, reject sets `rejected`
|
|
349
|
+
(visibility untouched). The write carries the from-state: approve moves only
|
|
350
|
+
a pending contribution, reject a pending or approved one (the takedown); any
|
|
351
|
+
other transition answers 400 `cell_not_pending`.
|
|
331
352
|
- `auth/cell_ref_admission.ts` — `require_new_refs_held`, the
|
|
332
353
|
possession gate `cell_create` / `cell_update` / `cell_clone` run last before
|
|
333
354
|
their write: a non-admin write introducing a fact ref (beyond the cell's
|
|
@@ -339,7 +360,10 @@ auth, ids)`: two queries for the whole id-set, the cells read through the
|
|
|
339
360
|
- `auth/cell_grant_actions.ts` / `cell_field_actions.ts` /
|
|
340
361
|
`cell_item_actions.ts` / `cell_audit_actions.ts` — the relation + ACL +
|
|
341
362
|
audit handlers, exporting `to_grant_json` / `to_field_json` /
|
|
342
|
-
`to_item_json` reused by the `cell_get` bundle.
|
|
363
|
+
`to_item_json` reused by the `cell_get` bundle. `cell_grant_create` takes an
|
|
364
|
+
optional `authorize_grant_create` (`CellGrantCreateAuthorize`), asked of a
|
|
365
|
+
manager after the spine's gates and before the write (a level change too);
|
|
366
|
+
`false` is 403 `cell_grant_not_authorized`, nothing written.
|
|
343
367
|
- `auth/all_cell_actions.ts` — `create_all_cell_actions(deps, {roles})`, the
|
|
344
368
|
handler-side twin of `all_cell_action_specs` and sibling of
|
|
345
369
|
`create_standard_rpc_actions`: bundles all five cell factories (CRUD + grant
|
|
@@ -356,8 +380,8 @@ auth, ids)`: two queries for the whole id-set, the cells read through the
|
|
|
356
380
|
Consumers spread it into `extra_events` to register the whole layer in
|
|
357
381
|
one call (aggregator by design, not a compat shim).
|
|
358
382
|
|
|
359
|
-
The cell event types (`cell_create` / `_update` / `_delete` / `_clone
|
|
360
|
-
`cell_grant_create` / `_revoke`, `cell_field_set` / `_delete`,
|
|
383
|
+
The cell event types (`cell_create` / `_update` / `_delete` / `_clone` /
|
|
384
|
+
`_moderate`, `cell_policy_set`, `cell_grant_create` / `_revoke`, `cell_field_set` / `_delete`,
|
|
361
385
|
`cell_item_insert` / `_move` / `_delete`) are consumer-registered extras,
|
|
362
386
|
not built-ins — see §Audit event extensibility.
|
|
363
387
|
|
|
@@ -615,7 +639,7 @@ fine — same as `role_grant_revoke`). `account_undelete` is admin-only —
|
|
|
615
639
|
reactivation has no self path because a soft-deleted account can't
|
|
616
640
|
authenticate.
|
|
617
641
|
|
|
618
|
-
- `admin_account_list_action_spec` — read; input `{limit?, offset?, include_deleted?}`; output `{accounts, grantable_roles}`. `include_deleted` (default false) surfaces soft-deleted rows (with `account.deleted_at` set) for the admin UI's reactivation view.
|
|
642
|
+
- `admin_account_list_action_spec` — read; input `{limit?, offset?, include_deleted?}`; output `{accounts, grantable_roles}`. On it and the other paged reads (`audit_log_list`, `audit_log_role_grant_history`, `role_grant_offer_history`) `limit` / `offset` declare `invalid_reason` `ERROR_LIMIT_INVALID` / `ERROR_OFFSET_INVALID` (`http/error_schemas.ts`), and `audit_log_list`'s `since_seq` / `outcome` `ERROR_SINCE_SEQ_INVALID` / `ERROR_OUTCOME_INVALID`: every refusal of the field carries it. `include_deleted` (default false) surfaces soft-deleted rows (with `account.deleted_at` set) for the admin UI's reactivation view.
|
|
619
643
|
- `account_delete_action_spec` — mutation (soft delete); self-or-admin (`{account, actor}`, handler elevates to admin when `account_id` ≠ self); the self path is session-only, handler-enforced ahead of the target guards (an API or daemon token gets the dispatcher's `ERROR_CREDENTIAL_TYPE_REQUIRED` 403 via `credential_type_required_error`), while an admin deleting another account keeps any credential; input `{account_id?}`; output `{ok, deleted}`. Tombstones account + actor(s), revokes sessions/tokens, emits `account_delete` + per-actor `actor_delete`. Refuses a keeper-role target (`ERROR_CANNOT_DELETE_KEEPER`) or the sole active admin (`ERROR_CANNOT_DELETE_LAST_ADMIN`) — both fail-loud with a failure-audit row.
|
|
620
644
|
- `account_purge_action_spec` — mutation (hard purge); keeper-only (`credential_types: ['daemon_token']` + `roles: ['keeper']`) + `confirm: true` + WARN; input `{account_id, confirm?}`; output `{ok, purged}`. Cascading delete; emits `account_purge` + per-actor `actor_purge` (identity snapshot survives in metadata since `audit_log` ids carry no FK). Refuses a keeper-role target (`ERROR_CANNOT_DELETE_KEEPER`) or the sole active admin (`ERROR_CANNOT_DELETE_LAST_ADMIN`).
|
|
621
645
|
- `account_undelete_action_spec` — mutation (reactivation, inverse of soft delete); admin-only (`roles: ['admin']` — no self path, a tombstoned account can't authenticate); input `{account_id}`; output `{ok, undeleted}`. Clears the `deleted_at` tombstone on the account + its actor(s), emits `account_undelete` + per-actor `actor_undelete`. Does not restore revoked sessions/tokens.
|
|
@@ -641,8 +665,8 @@ omits `confirm: true`, `ERROR_CANNOT_DELETE_KEEPER` (403) when `account_delete`
|
|
|
641
665
|
`account_purge` targets a keeper-role account (the keeper account is never
|
|
642
666
|
API-removable — auth + daemon-token both pivot on it),
|
|
643
667
|
`ERROR_CANNOT_DELETE_LAST_ADMIN` (403) when `account_delete` / `account_purge`
|
|
644
|
-
targets the sole remaining active admin (
|
|
645
|
-
|
|
668
|
+
targets the sole remaining active admin (soft-deleted admins don't count; the
|
|
669
|
+
count locks its rows, so concurrent removals can't both pass), `ERROR_INVITE_ACCOUNT_EXISTS_USERNAME` /
|
|
646
670
|
`_EMAIL` / `ERROR_INVITE_DUPLICATE` on invite create, `ERROR_INVITE_NOT_FOUND`
|
|
647
671
|
on invite delete. `invite_create` empty input is rejected at the schema via
|
|
648
672
|
`.refine()` and surfaces as `invalid_params` with `error.data.issues`.
|
|
@@ -693,6 +717,15 @@ event additionally records `credential_type` in metadata (defense in depth).
|
|
|
693
717
|
- `role_grant_offer_list_action_spec` — input `{account_id?}`; output `{offers}`.
|
|
694
718
|
- `role_grant_offer_history_action_spec` — input `{account_id?, limit?, offset?}`; output `{offers}`.
|
|
695
719
|
- `role_grant_revoke_action_spec` — input `{actor_id, role_grant_id, reason?}`; output `{ok, revoked}`.
|
|
720
|
+
A global `admin` grant is guarded: the keeper account's is refused
|
|
721
|
+
(`ERROR_CANNOT_REVOKE_KEEPER_ADMIN`, 403) and so is one whose revoke would
|
|
722
|
+
leave no active admin account (`ERROR_CANNOT_REVOKE_LAST_ADMIN`, 403, under
|
|
723
|
+
the locked count `query_count_active_accounts_with_global_role_for_update`,
|
|
724
|
+
which leaves the revoked grant out). Besides the
|
|
725
|
+
revokee's incoming sibling offers, the revoke supersedes every pending offer
|
|
726
|
+
the revokee's actor made (`query_role_grant_offer_supersede_outgoing`) —
|
|
727
|
+
`account_delete` / `account_purge` do the same for every actor of the account
|
|
728
|
+
(`reason: 'account_deleted'`, audited, no notification).
|
|
696
729
|
- `role_grant_assign_action_spec` — global-admin-only immediate conferral (no
|
|
697
730
|
consent step); input `{to_account_id, to_actor_id?, role, scope_kind?, scope_id?}`
|
|
698
731
|
(the pair as on offer-create); output `{ok, role_grant_id}`. The handler:
|
|
@@ -701,6 +734,9 @@ event additionally records `credential_type` in metadata (defense in depth).
|
|
|
701
734
|
`admin` (`invalid_params` + `ERROR_ROLE_GRANT_BUILTIN_SCOPED`; a scoped
|
|
702
735
|
`keeper` stays 403 `ERROR_ROLE_NOT_WEB_GRANTABLE`, since `keeper` is never
|
|
703
736
|
web-grantable);
|
|
737
|
+
- runs the consumer's `RoleGrantOfferCreateAuthorize` callback (the offer
|
|
738
|
+
policy binds the consent-free path too — a refusal is 403
|
|
739
|
+
`ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`, failure-audited);
|
|
704
740
|
- resolves the target actor (named `to_actor_id` ∈ the account's active
|
|
705
741
|
actors, else its sole active actor — multi-actor → `invalid_params`,
|
|
706
742
|
actorless → 404);
|
|
@@ -710,6 +746,7 @@ event additionally records `credential_type` in metadata (defense in depth).
|
|
|
710
746
|
|
|
711
747
|
No WS notification in v1. Reasons: `ERROR_INSUFFICIENT_PERMISSIONS`,
|
|
712
748
|
`ERROR_ROLE_NOT_WEB_GRANTABLE`, `ERROR_ROLE_GRANT_BUILTIN_SCOPED`,
|
|
749
|
+
`ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`,
|
|
713
750
|
`ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`.
|
|
714
751
|
|
|
715
752
|
Every input carries `acting?: ActingActor` (registry-time invariant 2).
|
|
@@ -725,7 +762,9 @@ holder-propagation (holding the offered role confers no power to offer it). The
|
|
|
725
762
|
global check (`has_scoped_role(_, ROLE_ADMIN, null)`) stops a scoped `admin`
|
|
726
763
|
escalating into global authority over the offer surface. A consumer needing
|
|
727
764
|
scope-aware delegation (e.g. a classroom teacher offering within their own
|
|
728
|
-
scope) supplies a custom `authorize` callback.
|
|
765
|
+
scope) supplies a custom `authorize` callback. The callback receives
|
|
766
|
+
`{to_account_id, role, scope_kind, scope_id}` and also gates
|
|
767
|
+
`role_grant_assign`.
|
|
729
768
|
|
|
730
769
|
**Builtin roles (`admin` / `keeper`) are global-only**, decided by the spine
|
|
731
770
|
ahead of any callback. Offer-create refuses a scoped `admin`
|
|
@@ -777,7 +816,7 @@ Post-commit via `emit_after_commit` (see `http/CLAUDE.md` §Pending Effects):
|
|
|
777
816
|
- Retract — `role_grant_offer_retracted` → recipient.
|
|
778
817
|
- Accept — `role_grant_offer_accepted` → grantor + `_supersede` per sibling.
|
|
779
818
|
- Decline — `role_grant_offer_declined` → grantor.
|
|
780
|
-
- Revoke — `role_grant_revoke` → revokee + `_supersede` per superseded
|
|
819
|
+
- Revoke — `role_grant_revoke` → revokee + `_supersede` per superseded offer (the revokee's incoming siblings and its own outgoing offers, each to its grantor).
|
|
781
820
|
|
|
782
821
|
Spec module is `auth/role_grant_offer_notifications.ts` — six
|
|
783
822
|
`RemoteNotificationActionSpec`s with Zod params schemas and notification
|
|
@@ -805,7 +844,7 @@ Options: `roles?: RoleSchemaResult` (drives admin-grant-path lookup),
|
|
|
805
844
|
- `account_session_list_action_spec` — read; input `z.void()`; output `{sessions}`.
|
|
806
845
|
- `account_session_revoke_action_spec` — mutation; input `{session_id}`; output `{ok, revoked}`.
|
|
807
846
|
- `account_session_revoke_all_action_spec` — mutation; input `z.void()`; output `{ok, count}`.
|
|
808
|
-
- `account_token_create_action_spec` — mutation; input `{name?, scope, lifetime}` (both `scope` and `lifetime` required — default-deny at mint on both axes; `name` at most `API_TOKEN_NAME_LENGTH_MAX` = 255 characters, since it is copied into the audit row); output `{ok, token, id, name, expires_at}`.
|
|
847
|
+
- `account_token_create_action_spec` — mutation; input `{name?, scope, lifetime}` (both `scope` and `lifetime` required — default-deny at mint on both axes; `name` at most `API_TOKEN_NAME_LENGTH_MAX` = 255 characters, since it is copied into the audit row); output `{ok, token, id, name, expires_at}`. `scope` / `lifetime` declare `invalid_reason` `ERROR_TOKEN_SCOPE_INVALID` / `ERROR_TOKEN_LIFETIME_INVALID`, so every refusal of either carries it — the handler's over-cap scope refusal included.
|
|
809
848
|
- `account_token_list_action_spec` — read; input `z.void()`; output `{tokens}`.
|
|
810
849
|
- `account_token_revoke_action_spec` — mutation; input `{token_id}`; output `{ok, revoked}`.
|
|
811
850
|
|
|
@@ -831,7 +870,7 @@ required `connection_closer`. Each revoking handler queues its close
|
|
|
831
870
|
after the handler's transaction commits and is dropped if it throws;
|
|
832
871
|
`account_token_create` queues a token close for each token its cap evicts.
|
|
833
872
|
Failure outcomes (`revoked: false`) queue no close — mirrors the listeners'
|
|
834
|
-
`outcome === '
|
|
873
|
+
`outcome === 'success'` guard so attacker-guessable ids can't target
|
|
835
874
|
arbitrary connections.
|
|
836
875
|
|
|
837
876
|
### Standard RPC bundle
|
|
@@ -52,6 +52,18 @@ export type SessionRevokeAllOutput = z.infer<typeof SessionRevokeAllOutput>;
|
|
|
52
52
|
* the Rust spine's `API_TOKEN_NAME_LENGTH_MAX`.
|
|
53
53
|
*/
|
|
54
54
|
export declare const API_TOKEN_NAME_LENGTH_MAX = 255;
|
|
55
|
+
/**
|
|
56
|
+
* `error.data.reason` on any refusal of `account_token_create`'s `scope` —
|
|
57
|
+
* missing, `null`, an unknown `kind` or key, a malformed `methods`, an
|
|
58
|
+
* over-cap document. The field's declared `invalid_reason`.
|
|
59
|
+
*/
|
|
60
|
+
export declare const ERROR_TOKEN_SCOPE_INVALID: "token_scope_invalid";
|
|
61
|
+
/**
|
|
62
|
+
* `error.data.reason` on any refusal of `account_token_create`'s `lifetime` —
|
|
63
|
+
* missing, `null`, an unknown `kind` or key, a `days` out of range. The
|
|
64
|
+
* field's declared `invalid_reason`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const ERROR_TOKEN_LIFETIME_INVALID: "token_lifetime_invalid";
|
|
55
67
|
/**
|
|
56
68
|
* Input for `account_token_create`.
|
|
57
69
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAW3E,6EAA6E;AAC7E,eAAO,MAAM,WAAW,WAAW,CAAC;AACpC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,yCAAyC;AACzC,eAAO,MAAM,iBAAiB;;;;;;;kBAE5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB;;kBAE7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,iFAAiF;AACjF,eAAO,MAAM,mBAAmB;;;kBAG9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB;;;kBAGjC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE5E;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;
|
|
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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"}
|
|
@@ -45,6 +45,18 @@ export const SessionRevokeAllOutput = z.strictObject({
|
|
|
45
45
|
* the Rust spine's `API_TOKEN_NAME_LENGTH_MAX`.
|
|
46
46
|
*/
|
|
47
47
|
export const API_TOKEN_NAME_LENGTH_MAX = 255;
|
|
48
|
+
/**
|
|
49
|
+
* `error.data.reason` on any refusal of `account_token_create`'s `scope` —
|
|
50
|
+
* missing, `null`, an unknown `kind` or key, a malformed `methods`, an
|
|
51
|
+
* over-cap document. The field's declared `invalid_reason`.
|
|
52
|
+
*/
|
|
53
|
+
export const ERROR_TOKEN_SCOPE_INVALID = 'token_scope_invalid';
|
|
54
|
+
/**
|
|
55
|
+
* `error.data.reason` on any refusal of `account_token_create`'s `lifetime` —
|
|
56
|
+
* missing, `null`, an unknown `kind` or key, a `days` out of range. The
|
|
57
|
+
* field's declared `invalid_reason`.
|
|
58
|
+
*/
|
|
59
|
+
export const ERROR_TOKEN_LIFETIME_INVALID = 'token_lifetime_invalid';
|
|
48
60
|
/**
|
|
49
61
|
* Input for `account_token_create`.
|
|
50
62
|
*
|
|
@@ -69,11 +81,13 @@ export const TokenCreateInput = z.strictObject({
|
|
|
69
81
|
description: "What the token may do. `{kind:'full'}` for full account authority, or " +
|
|
70
82
|
"`{kind:'methods',methods:[…]}` to narrow it to named RPC methods — a " +
|
|
71
83
|
'narrowed token is RPC-only and reaches no non-RPC surface that reads ' +
|
|
72
|
-
'account data or carries authority.'
|
|
84
|
+
'account data or carries authority.',
|
|
85
|
+
invalid_reason: ERROR_TOKEN_SCOPE_INVALID
|
|
73
86
|
}),
|
|
74
87
|
lifetime: TokenLifetimeInput.meta({
|
|
75
88
|
description: "How long the token lives. `{kind:'eternal'}` never expires; " +
|
|
76
|
-
"`{kind:'ttl',days:N}` expires N days from mint."
|
|
89
|
+
"`{kind:'ttl',days:N}` expires N days from mint.",
|
|
90
|
+
invalid_reason: ERROR_TOKEN_LIFETIME_INVALID
|
|
77
91
|
})
|
|
78
92
|
});
|
|
79
93
|
/** Output for `account_token_create`. `token` is returned exactly once. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAwB9F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"account_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAwB9F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AA0B3D,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,yBAAyB,EAC/B,UAAS,oBAAyB,KAChC,KAAK,CAAC,SAAS,CAyLjB,CAAC"}
|
|
@@ -39,7 +39,7 @@ import { token_lifetime_to_expires_at } from './token_lifetime.js';
|
|
|
39
39
|
import { generate_api_token } from './api_token.js';
|
|
40
40
|
import { DEFAULT_MAX_TOKENS } from './account_route_schema.js';
|
|
41
41
|
import { to_iso8601_seconds } from '../timestamp.js';
|
|
42
|
-
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';
|
|
42
|
+
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, ERROR_TOKEN_SCOPE_INVALID } from './account_action_specs.js';
|
|
43
43
|
/**
|
|
44
44
|
* Create the self-service account RPC actions.
|
|
45
45
|
*
|
|
@@ -111,13 +111,16 @@ export const create_account_actions = (deps, options = {}) => {
|
|
|
111
111
|
// a validation error upstream, not a full-authority token.
|
|
112
112
|
const scope = token_scope_from_input(input.scope);
|
|
113
113
|
// Over the stored-document cap is a malformed request, refused before
|
|
114
|
-
// any write (the insert would otherwise throw it as a 500)
|
|
115
|
-
//
|
|
114
|
+
// any write (the insert would otherwise throw it as a 500), with the
|
|
115
|
+
// reason the schema declares for every other `scope` refusal. Twin of
|
|
116
|
+
// the Rust spine's `invalid_params` on `TokenScopeError::TooLarge`.
|
|
116
117
|
try {
|
|
117
118
|
serialize_token_scope(scope);
|
|
118
119
|
}
|
|
119
120
|
catch (err) {
|
|
120
|
-
throw jsonrpc_errors.invalid_params(`invalid scope: ${to_error_message(err)}
|
|
121
|
+
throw jsonrpc_errors.invalid_params(`invalid scope: ${to_error_message(err)}`, {
|
|
122
|
+
reason: ERROR_TOKEN_SCOPE_INVALID
|
|
123
|
+
});
|
|
121
124
|
}
|
|
122
125
|
// `input.lifetime` is required for the same reason — an omitted lifetime
|
|
123
126
|
// is a validation error, never an eternal token.
|
|
@@ -37,8 +37,9 @@ export interface ActorLookupRow {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Resolve a batch of actor ids to `(id, username, display_name)`. Empty
|
|
40
|
-
* input fast-paths to `[]`. Hard-deleted actors
|
|
41
|
-
*
|
|
40
|
+
* input fast-paths to `[]`. Hard-deleted and soft-deleted actors — and the
|
|
41
|
+
* actors of a soft-deleted account — drop out of the result silently,
|
|
42
|
+
* indistinguishable from never-existed.
|
|
42
43
|
*/
|
|
43
44
|
export declare const query_actors_by_ids: (deps: QueryDeps, ids: ReadonlyArray<Uuid>) => Promise<Array<ActorLookupRow>>;
|
|
44
45
|
//# sourceMappingURL=actor_lookup_queries.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actor_lookup_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/actor_lookup_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED
|
|
1
|
+
{"version":3,"file":"actor_lookup_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/actor_lookup_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,SAAS,EACf,KAAK,aAAa,CAAC,IAAI,CAAC,KACtB,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAW/B,CAAC"}
|
|
@@ -29,8 +29,9 @@
|
|
|
29
29
|
*/
|
|
30
30
|
/**
|
|
31
31
|
* Resolve a batch of actor ids to `(id, username, display_name)`. Empty
|
|
32
|
-
* input fast-paths to `[]`. Hard-deleted actors
|
|
33
|
-
*
|
|
32
|
+
* input fast-paths to `[]`. Hard-deleted and soft-deleted actors — and the
|
|
33
|
+
* actors of a soft-deleted account — drop out of the result silently,
|
|
34
|
+
* indistinguishable from never-existed.
|
|
34
35
|
*/
|
|
35
36
|
export const query_actors_by_ids = async (deps, ids) => {
|
|
36
37
|
if (ids.length === 0)
|
|
@@ -38,5 +39,7 @@ export const query_actors_by_ids = async (deps, ids) => {
|
|
|
38
39
|
return deps.db.query(`SELECT act.id, a.username, act.name AS display_name
|
|
39
40
|
FROM actor act
|
|
40
41
|
JOIN account a ON a.id = act.account_id
|
|
41
|
-
WHERE act.id = ANY($1)
|
|
42
|
+
WHERE act.id = ANY($1)
|
|
43
|
+
AND act.deleted_at IS NULL
|
|
44
|
+
AND a.deleted_at IS NULL`, [ids]);
|
|
42
45
|
};
|
|
@@ -26,8 +26,11 @@
|
|
|
26
26
|
* multiple matching role_grants in the supplied scope set into one row.
|
|
27
27
|
*
|
|
28
28
|
* When `scope_ids` is omitted (admin-only global path; the handler
|
|
29
|
-
* gates), no role_grant join — every actor with a matching prefix
|
|
30
|
-
* returned.
|
|
29
|
+
* gates), no role_grant join — every active actor with a matching prefix
|
|
30
|
+
* is returned.
|
|
31
|
+
*
|
|
32
|
+
* Both paths return only active actors of active accounts: a soft-deleted
|
|
33
|
+
* actor, or any actor of a soft-deleted account, is never a search result.
|
|
31
34
|
*
|
|
32
35
|
* ## Info-leak posture (see `auth/actor_search_action_specs.ts` §audit)
|
|
33
36
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actor_search_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/actor_search_queries.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"actor_search_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/actor_search_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,uCAAuC;AACvC,MAAM,WAAW,qBAAqB;IACrC,0FAA0F;IAC1F,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;CACd;AASD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC9B,MAAM,SAAS,EACf,OAAO,qBAAqB,KAC1B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAuC/B,CAAC"}
|
|
@@ -26,8 +26,11 @@
|
|
|
26
26
|
* multiple matching role_grants in the supplied scope set into one row.
|
|
27
27
|
*
|
|
28
28
|
* When `scope_ids` is omitted (admin-only global path; the handler
|
|
29
|
-
* gates), no role_grant join — every actor with a matching prefix
|
|
30
|
-
* returned.
|
|
29
|
+
* gates), no role_grant join — every active actor with a matching prefix
|
|
30
|
+
* is returned.
|
|
31
|
+
*
|
|
32
|
+
* Both paths return only active actors of active accounts: a soft-deleted
|
|
33
|
+
* actor, or any actor of a soft-deleted account, is never a search result.
|
|
31
34
|
*
|
|
32
35
|
* ## Info-leak posture (see `auth/actor_search_action_specs.ts` §audit)
|
|
33
36
|
*
|
|
@@ -69,7 +72,9 @@ export const query_actor_search = async (deps, input) => {
|
|
|
69
72
|
return deps.db.query(`SELECT act.id, a.username, act.name AS display_name
|
|
70
73
|
FROM actor act
|
|
71
74
|
JOIN account a ON a.id = act.account_id
|
|
72
|
-
WHERE
|
|
75
|
+
WHERE act.deleted_at IS NULL
|
|
76
|
+
AND a.deleted_at IS NULL
|
|
77
|
+
AND LOWER(act.name) LIKE $1 || '%' ESCAPE '\\'
|
|
73
78
|
ORDER BY display_name, id
|
|
74
79
|
LIMIT $2`, [escaped_prefix, input.limit]);
|
|
75
80
|
}
|
|
@@ -85,7 +90,9 @@ export const query_actor_search = async (deps, input) => {
|
|
|
85
90
|
AND rg.scope_id = ANY($2)
|
|
86
91
|
AND rg.revoked_at IS NULL
|
|
87
92
|
AND (rg.expires_at IS NULL OR rg.expires_at > NOW())
|
|
88
|
-
WHERE
|
|
93
|
+
WHERE act.deleted_at IS NULL
|
|
94
|
+
AND a.deleted_at IS NULL
|
|
95
|
+
AND LOWER(act.name) LIKE $1 || '%' ESCAPE '\\'
|
|
89
96
|
ORDER BY display_name, id
|
|
90
97
|
LIMIT $3`, [escaped_prefix, scope_ids, input.limit]);
|
|
91
98
|
};
|
|
@@ -286,10 +286,10 @@ export declare const ERROR_CANNOT_DELETE_KEEPER: "cannot_delete_keeper";
|
|
|
286
286
|
* `data.reason` (403) on `account_delete` / `account_purge` when the target
|
|
287
287
|
* is the **sole remaining active admin** — removing it would leave the
|
|
288
288
|
* system with no account that can authenticate into the admin surface (and
|
|
289
|
-
* `account_undelete` is itself admin-gated)
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
* admins
|
|
289
|
+
* `account_undelete` is itself admin-gated), and no web path re-grants admin.
|
|
290
|
+
* Soft-deleted admins don't count toward the tally (they can't log in), and
|
|
291
|
+
* the count locks the rows it counted, so two removals racing for the last
|
|
292
|
+
* two admins can't both pass. Mirrors the Rust
|
|
293
293
|
* `ERROR_CANNOT_DELETE_LAST_ADMIN`.
|
|
294
294
|
*/
|
|
295
295
|
export declare const ERROR_CANNOT_DELETE_LAST_ADMIN: "cannot_delete_last_admin";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"admin_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_action_specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ import { ActingActor } from '../http/auth_shape.js';
|
|
|
24
24
|
import { AdminSessionJson, AUDIT_LOG_DEFAULT_LIMIT, AuditEventTypeName, AuditLogEventWithUsernamesJson, AuditOutcome, RoleGrantHistoryEventJson } from './audit_log_schema.js';
|
|
25
25
|
import { InviteJson, InviteWithUsernamesJson } from './invite_schema.js';
|
|
26
26
|
import { AppSettingsWithUsernameJson } from './app_settings_schema.js';
|
|
27
|
+
import { ERROR_LIMIT_INVALID, ERROR_OFFSET_INVALID, ERROR_OUTCOME_INVALID, ERROR_SINCE_SEQ_INVALID } from '../http/error_schemas.js';
|
|
27
28
|
/** Max audit-log page size. */
|
|
28
29
|
export const AUDIT_LOG_LIST_LIMIT_MAX = 200;
|
|
29
30
|
/** Default `admin_account_list` page size. */
|
|
@@ -42,9 +43,15 @@ export const AdminAccountListInput = z
|
|
|
42
43
|
.max(ADMIN_ACCOUNT_LIST_LIMIT_MAX)
|
|
43
44
|
.nullish()
|
|
44
45
|
.meta({
|
|
45
|
-
description: `Max accounts to return (default ${ADMIN_ACCOUNT_LIST_DEFAULT_LIMIT}, max ${ADMIN_ACCOUNT_LIST_LIMIT_MAX})
|
|
46
|
+
description: `Max accounts to return (default ${ADMIN_ACCOUNT_LIST_DEFAULT_LIMIT}, max ${ADMIN_ACCOUNT_LIST_LIMIT_MAX}).`,
|
|
47
|
+
invalid_reason: ERROR_LIMIT_INVALID
|
|
46
48
|
}),
|
|
47
|
-
offset: z
|
|
49
|
+
offset: z
|
|
50
|
+
.number()
|
|
51
|
+
.int()
|
|
52
|
+
.min(0)
|
|
53
|
+
.nullish()
|
|
54
|
+
.meta({ description: 'Pagination offset.', invalid_reason: ERROR_OFFSET_INVALID }),
|
|
48
55
|
include_deleted: z.boolean().nullish().meta({
|
|
49
56
|
description: 'Include soft-deleted (tombstoned) accounts in the listing. Default false (active only). Used by the admin UI to surface accounts for reactivation via `account_undelete`.'
|
|
50
57
|
})
|
|
@@ -97,7 +104,8 @@ export const AuditLogListInput = z
|
|
|
97
104
|
description: 'Filter by event type. Accepts builtin or consumer-registered names (regex-validated).'
|
|
98
105
|
}),
|
|
99
106
|
outcome: AuditOutcome.nullish().meta({
|
|
100
|
-
description: 'Filter by outcome (`success` or `failure`).'
|
|
107
|
+
description: 'Filter by outcome (`success` or `failure`).',
|
|
108
|
+
invalid_reason: ERROR_OUTCOME_INVALID
|
|
101
109
|
}),
|
|
102
110
|
account_id: Uuid.nullish().meta({ description: 'Filter by actor account id.' }),
|
|
103
111
|
limit: z
|
|
@@ -107,11 +115,18 @@ export const AuditLogListInput = z
|
|
|
107
115
|
.max(AUDIT_LOG_LIST_LIMIT_MAX)
|
|
108
116
|
.nullish()
|
|
109
117
|
.meta({
|
|
110
|
-
description: `Max rows to return (default ${AUDIT_LOG_DEFAULT_LIMIT}, max ${AUDIT_LOG_LIST_LIMIT_MAX})
|
|
118
|
+
description: `Max rows to return (default ${AUDIT_LOG_DEFAULT_LIMIT}, max ${AUDIT_LOG_LIST_LIMIT_MAX}).`,
|
|
119
|
+
invalid_reason: ERROR_LIMIT_INVALID
|
|
111
120
|
}),
|
|
112
|
-
offset: z
|
|
121
|
+
offset: z
|
|
122
|
+
.number()
|
|
123
|
+
.int()
|
|
124
|
+
.min(0)
|
|
125
|
+
.nullish()
|
|
126
|
+
.meta({ description: 'Pagination offset.', invalid_reason: ERROR_OFFSET_INVALID }),
|
|
113
127
|
since_seq: z.number().int().min(0).nullish().meta({
|
|
114
|
-
description: 'Gap-fill from this seq forward. Used for SSE reconnection.'
|
|
128
|
+
description: 'Gap-fill from this seq forward. Used for SSE reconnection.',
|
|
129
|
+
invalid_reason: ERROR_SINCE_SEQ_INVALID
|
|
115
130
|
}),
|
|
116
131
|
acting: ActingActor
|
|
117
132
|
})
|
|
@@ -130,9 +145,15 @@ export const AuditLogRoleGrantHistoryInput = z
|
|
|
130
145
|
.max(AUDIT_LOG_LIST_LIMIT_MAX)
|
|
131
146
|
.nullish()
|
|
132
147
|
.meta({
|
|
133
|
-
description: `Max rows to return (default ${AUDIT_LOG_DEFAULT_LIMIT}, max ${AUDIT_LOG_LIST_LIMIT_MAX})
|
|
148
|
+
description: `Max rows to return (default ${AUDIT_LOG_DEFAULT_LIMIT}, max ${AUDIT_LOG_LIST_LIMIT_MAX}).`,
|
|
149
|
+
invalid_reason: ERROR_LIMIT_INVALID
|
|
134
150
|
}),
|
|
135
|
-
offset: z
|
|
151
|
+
offset: z
|
|
152
|
+
.number()
|
|
153
|
+
.int()
|
|
154
|
+
.min(0)
|
|
155
|
+
.nullish()
|
|
156
|
+
.meta({ description: 'Pagination offset.', invalid_reason: ERROR_OFFSET_INVALID }),
|
|
136
157
|
acting: ActingActor
|
|
137
158
|
})
|
|
138
159
|
.default({});
|
|
@@ -216,10 +237,10 @@ export const ERROR_CANNOT_DELETE_KEEPER = 'cannot_delete_keeper';
|
|
|
216
237
|
* `data.reason` (403) on `account_delete` / `account_purge` when the target
|
|
217
238
|
* is the **sole remaining active admin** — removing it would leave the
|
|
218
239
|
* system with no account that can authenticate into the admin surface (and
|
|
219
|
-
* `account_undelete` is itself admin-gated)
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* admins
|
|
240
|
+
* `account_undelete` is itself admin-gated), and no web path re-grants admin.
|
|
241
|
+
* Soft-deleted admins don't count toward the tally (they can't log in), and
|
|
242
|
+
* the count locks the rows it counted, so two removals racing for the last
|
|
243
|
+
* two admins can't both pass. Mirrors the Rust
|
|
223
244
|
* `ERROR_CANNOT_DELETE_LAST_ADMIN`.
|
|
224
245
|
*/
|
|
225
246
|
export const ERROR_CANNOT_DELETE_LAST_ADMIN = 'cannot_delete_last_admin';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAI/F,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"admin_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAI/F,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AA0C1B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AA0D3D,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,yBAAyB,EAC/B,UAAS,kBAAuB,KAC9B,KAAK,CAAC,SAAS,CAmjBjB,CAAC"}
|