@fuzdev/fuz_app 0.55.0 → 0.57.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 +211 -155
- package/dist/actions/action_bridge.d.ts +8 -5
- package/dist/actions/action_bridge.d.ts.map +1 -1
- package/dist/actions/action_bridge.js +1 -11
- package/dist/actions/action_codegen.d.ts +19 -0
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +20 -14
- package/dist/actions/action_registry.d.ts.map +1 -1
- package/dist/actions/action_registry.js +5 -2
- package/dist/actions/action_rpc.d.ts +110 -44
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +92 -287
- package/dist/actions/action_spec.d.ts +55 -16
- package/dist/actions/action_spec.d.ts.map +1 -1
- package/dist/actions/action_spec.js +16 -11
- package/dist/actions/action_types.d.ts +28 -60
- package/dist/actions/action_types.d.ts.map +1 -1
- package/dist/actions/action_types.js +13 -5
- package/dist/actions/broadcast_api.d.ts +2 -2
- package/dist/actions/broadcast_api.js +2 -2
- package/dist/actions/compile_action_registry.d.ts +50 -0
- package/dist/actions/compile_action_registry.d.ts.map +1 -0
- package/dist/actions/compile_action_registry.js +69 -0
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +5 -4
- package/dist/actions/perform_action.d.ts +145 -0
- package/dist/actions/perform_action.d.ts.map +1 -0
- package/dist/actions/perform_action.js +258 -0
- package/dist/actions/register_action_ws.d.ts +44 -38
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +101 -159
- package/dist/actions/register_ws_endpoint.d.ts +2 -10
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +32 -10
- package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
- package/dist/actions/transports_ws_auth_guard.js +1 -1
- package/dist/actions/transports_ws_backend.d.ts +1 -1
- package/dist/actions/transports_ws_backend.js +1 -1
- package/dist/auth/CLAUDE.md +673 -442
- package/dist/auth/account_action_specs.d.ts +28 -7
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +7 -7
- package/dist/auth/account_actions.d.ts +8 -14
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +26 -32
- package/dist/auth/account_queries.d.ts +46 -13
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +73 -33
- package/dist/auth/account_routes.d.ts +4 -3
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +58 -33
- package/dist/auth/account_schema.d.ts +46 -54
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +21 -48
- package/dist/auth/admin_action_specs.d.ts +55 -21
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +42 -26
- package/dist/auth/admin_actions.d.ts +14 -21
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +47 -44
- package/dist/auth/audit_emitter.d.ts +160 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -0
- package/dist/auth/audit_emitter.js +83 -0
- package/dist/auth/audit_log_queries.d.ts +17 -87
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +17 -96
- package/dist/auth/audit_log_routes.d.ts +1 -1
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +7 -3
- package/dist/auth/audit_log_schema.d.ts +48 -42
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +56 -43
- package/dist/auth/auth_guard_resolver.d.ts +44 -0
- package/dist/auth/auth_guard_resolver.d.ts.map +1 -0
- package/dist/auth/auth_guard_resolver.js +56 -0
- package/dist/auth/bootstrap_account.d.ts +7 -7
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +7 -7
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +11 -10
- package/dist/auth/cleanup.d.ts +20 -26
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +33 -47
- package/dist/auth/credential_type_schema.d.ts +115 -0
- package/dist/auth/credential_type_schema.d.ts.map +1 -0
- package/dist/auth/credential_type_schema.js +127 -0
- package/dist/auth/daemon_token_middleware.d.ts +1 -1
- package/dist/auth/daemon_token_middleware.js +3 -3
- package/dist/auth/ddl.d.ts +2 -2
- package/dist/auth/ddl.d.ts.map +1 -1
- package/dist/auth/ddl.js +6 -6
- package/dist/auth/deps.d.ts +7 -32
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/grant_path_schema.d.ts +117 -0
- package/dist/auth/grant_path_schema.d.ts.map +1 -0
- package/dist/auth/grant_path_schema.js +137 -0
- package/dist/auth/invite_queries.d.ts +12 -1
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +12 -1
- package/dist/auth/invite_schema.d.ts +1 -1
- package/dist/auth/invite_schema.d.ts.map +1 -1
- package/dist/auth/invite_schema.js +1 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +5 -2
- package/dist/auth/migrations.d.ts +22 -7
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +64 -25
- package/dist/auth/request_context.d.ts +157 -170
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +224 -268
- package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +130 -100
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_action_specs.js +262 -0
- package/dist/auth/role_grant_offer_actions.d.ts +104 -0
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -0
- package/dist/auth/{permit_offer_actions.js → role_grant_offer_actions.js} +153 -140
- package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +80 -70
- package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_notifications.js +182 -0
- package/dist/auth/{permit_offer_queries.d.ts → role_grant_offer_queries.d.ts} +64 -64
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
- package/dist/auth/{permit_offer_queries.js → role_grant_offer_queries.js} +136 -123
- package/dist/auth/role_grant_offer_schema.d.ts +150 -0
- package/dist/auth/role_grant_offer_schema.d.ts.map +1 -0
- package/dist/auth/{permit_offer_schema.js → role_grant_offer_schema.js} +55 -36
- package/dist/auth/role_grant_queries.d.ts +231 -0
- package/dist/auth/role_grant_queries.d.ts.map +1 -0
- package/dist/auth/role_grant_queries.js +320 -0
- package/dist/auth/role_schema.d.ts +150 -40
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +144 -45
- package/dist/auth/scope_kind_schema.d.ts +96 -0
- package/dist/auth/scope_kind_schema.d.ts.map +1 -0
- package/dist/auth/scope_kind_schema.js +94 -0
- package/dist/auth/self_service_role_action_specs.d.ts +4 -1
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +2 -2
- package/dist/auth/self_service_role_actions.d.ts +35 -29
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +58 -48
- package/dist/auth/session_cookie.d.ts +43 -6
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +31 -5
- package/dist/auth/session_middleware.d.ts +37 -3
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +33 -7
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +48 -19
- package/dist/auth/standard_action_specs.d.ts +2 -2
- package/dist/auth/standard_action_specs.js +4 -4
- package/dist/auth/standard_rpc_actions.d.ts +23 -19
- package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
- package/dist/auth/standard_rpc_actions.js +12 -12
- package/dist/db/migrate.d.ts +1 -1
- package/dist/db/migrate.js +1 -1
- package/dist/dev/setup.d.ts +2 -2
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +4 -4
- package/dist/env/load.d.ts +1 -1
- package/dist/env/load.js +1 -1
- package/dist/hono_context.d.ts +27 -45
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +14 -28
- package/dist/http/CLAUDE.md +235 -121
- package/dist/http/auth_shape.d.ts +191 -0
- package/dist/http/auth_shape.d.ts.map +1 -0
- package/dist/http/auth_shape.js +237 -0
- package/dist/http/common_routes.js +3 -3
- package/dist/http/db_routes.d.ts +4 -0
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +44 -7
- package/dist/http/error_schemas.d.ts +72 -39
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +81 -33
- package/dist/http/pending_effects.d.ts +71 -18
- package/dist/http/pending_effects.d.ts.map +1 -1
- package/dist/http/pending_effects.js +87 -18
- package/dist/http/proxy.d.ts +52 -5
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +92 -14
- package/dist/http/route_spec.d.ts +89 -75
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +54 -72
- package/dist/http/schema_helpers.d.ts +3 -14
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +2 -14
- package/dist/http/surface.d.ts +2 -10
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +3 -4
- package/dist/http/surface_query.d.ts +39 -35
- package/dist/http/surface_query.d.ts.map +1 -1
- package/dist/http/surface_query.js +79 -36
- package/dist/primitive_schemas.d.ts +39 -0
- package/dist/primitive_schemas.d.ts.map +1 -0
- package/dist/primitive_schemas.js +40 -0
- package/dist/realtime/sse_auth_guard.d.ts +5 -5
- package/dist/realtime/sse_auth_guard.js +9 -9
- package/dist/runtime/mock.d.ts +1 -1
- package/dist/runtime/mock.js +1 -1
- package/dist/server/app_backend.d.ts +14 -11
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +12 -8
- package/dist/server/app_server.d.ts +7 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +35 -40
- package/dist/server/validate_nginx.d.ts +1 -1
- package/dist/server/validate_nginx.js +1 -1
- package/dist/testing/CLAUDE.md +50 -38
- package/dist/testing/admin_integration.d.ts +5 -6
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +87 -85
- package/dist/testing/app_server.d.ts +11 -14
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +16 -15
- package/dist/testing/assertions.d.ts.map +1 -1
- package/dist/testing/assertions.js +2 -1
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +15 -9
- package/dist/testing/audit_completeness.d.ts +2 -2
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +36 -36
- package/dist/testing/auth_apps.d.ts +5 -4
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +22 -19
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +5 -5
- package/dist/testing/db.d.ts +1 -1
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +4 -4
- package/dist/testing/db_entities.d.ts +22 -0
- package/dist/testing/db_entities.d.ts.map +1 -0
- package/dist/testing/db_entities.js +28 -0
- package/dist/testing/entities.d.ts +8 -7
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +21 -18
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +13 -14
- package/dist/testing/integration_helpers.d.ts +4 -4
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +20 -18
- package/dist/testing/middleware.d.ts +4 -4
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +12 -11
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +40 -24
- package/dist/testing/rpc_round_trip.d.ts +1 -1
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +14 -13
- package/dist/testing/sse_round_trip.d.ts +3 -4
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +7 -11
- package/dist/testing/standard.d.ts +1 -1
- package/dist/testing/stubs.d.ts +25 -0
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +43 -2
- package/dist/testing/surface_invariants.d.ts +14 -6
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +119 -43
- package/dist/testing/ws_round_trip.d.ts +12 -13
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +19 -11
- package/dist/ui/AdminAccounts.svelte +23 -20
- package/dist/ui/AdminOverview.svelte +15 -13
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
- package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
- package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
- package/dist/ui/BootstrapForm.svelte +1 -1
- package/dist/ui/CLAUDE.md +60 -60
- package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +27 -26
- package/dist/ui/{PermitOfferForm.svelte.d.ts → RoleGrantOfferForm.svelte.d.ts} +7 -7
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
- package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
- package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
- package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
- package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
- package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
- package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
- package/dist/ui/SignupForm.svelte +1 -1
- package/dist/ui/SurfaceExplorer.svelte +35 -15
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.js +2 -3
- package/dist/ui/admin_accounts_state.svelte.d.ts +18 -18
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +16 -16
- package/dist/ui/admin_rpc_adapters.d.ts +20 -20
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.js +17 -17
- package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
- package/dist/ui/admin_sessions_state.svelte.js +2 -2
- package/dist/ui/audit_log_state.svelte.d.ts +7 -7
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +6 -6
- package/dist/ui/auth_state.svelte.d.ts +3 -3
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +6 -6
- package/dist/ui/format_scope.d.ts +2 -2
- package/dist/ui/format_scope.js +2 -2
- package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +30 -30
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
- package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +18 -18
- package/dist/ui/ui_format.js +2 -2
- package/package.json +3 -3
- package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
- package/dist/auth/permit_offer_action_specs.js +0 -258
- package/dist/auth/permit_offer_actions.d.ts +0 -110
- package/dist/auth/permit_offer_actions.d.ts.map +0 -1
- package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
- package/dist/auth/permit_offer_notifications.js +0 -182
- package/dist/auth/permit_offer_queries.d.ts.map +0 -1
- package/dist/auth/permit_offer_schema.d.ts +0 -125
- package/dist/auth/permit_offer_schema.d.ts.map +0 -1
- package/dist/auth/permit_queries.d.ts +0 -222
- package/dist/auth/permit_queries.d.ts.map +0 -1
- package/dist/auth/permit_queries.js +0 -305
- package/dist/auth/require_keeper.d.ts +0 -20
- package/dist/auth/require_keeper.d.ts.map +0 -1
- package/dist/auth/require_keeper.js +0 -35
- package/dist/auth/route_guards.d.ts +0 -27
- package/dist/auth/route_guards.d.ts.map +0 -1
- package/dist/auth/route_guards.js +0 -38
- package/dist/auth/session_lifecycle.d.ts +0 -37
- package/dist/auth/session_lifecycle.d.ts.map +0 -1
- package/dist/auth/session_lifecycle.js +0 -29
- package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
- package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
-
import type
|
|
15
|
+
import { type RouteAuth } from './auth_shape.js';
|
|
16
16
|
/** Request body failed Zod validation. */
|
|
17
17
|
export declare const ERROR_INVALID_REQUEST_BODY: "invalid_request_body";
|
|
18
18
|
/** Request body is not valid JSON or not an object. */
|
|
@@ -25,6 +25,16 @@ export declare const ERROR_INVALID_QUERY_PARAMS: "invalid_query_params";
|
|
|
25
25
|
export declare const ERROR_AUTHENTICATION_REQUIRED: "authentication_required";
|
|
26
26
|
/** Authenticated but missing required role. */
|
|
27
27
|
export declare const ERROR_INSUFFICIENT_PERMISSIONS: "insufficient_permissions";
|
|
28
|
+
/**
|
|
29
|
+
* Route requires a credential type the request didn't arrive on.
|
|
30
|
+
* Symmetric with `ERROR_INSUFFICIENT_PERMISSIONS` + `required_roles`:
|
|
31
|
+
* the body carries `required_credential_types: ReadonlyArray<string>`
|
|
32
|
+
* — what the route demanded, not what arrived. Today the only
|
|
33
|
+
* credential gate is keeper (`['daemon_token']`); future gates
|
|
34
|
+
* (`agent_token`, `group_actor_token`) reuse the same literal and
|
|
35
|
+
* label themselves through the array.
|
|
36
|
+
*/
|
|
37
|
+
export declare const ERROR_CREDENTIAL_TYPE_REQUIRED: "credential_type_required";
|
|
28
38
|
/** Rate limiter rejected the request. */
|
|
29
39
|
export declare const ERROR_RATE_LIMIT_EXCEEDED: "rate_limit_exceeded";
|
|
30
40
|
/** Username or password is wrong (intentionally vague for enumeration prevention). */
|
|
@@ -74,8 +84,6 @@ export declare const ERROR_NO_ACTORS_ON_ACCOUNT: "no_actors_on_account";
|
|
|
74
84
|
* `ERROR_NO_ACTORS_ON_ACCOUNT` (the actor list enumerated empty).
|
|
75
85
|
*/
|
|
76
86
|
export declare const ERROR_ACCOUNT_VANISHED: "account_vanished";
|
|
77
|
-
/** Keeper routes require daemon_token credential type. */
|
|
78
|
-
export declare const ERROR_KEEPER_REQUIRES_DAEMON_TOKEN: "keeper_requires_daemon_token";
|
|
79
87
|
/** Daemon token header present but malformed or not matching current/previous token. */
|
|
80
88
|
export declare const ERROR_INVALID_DAEMON_TOKEN: "invalid_daemon_token";
|
|
81
89
|
/** Daemon token valid but keeper account not yet resolved (pre-bootstrap). */
|
|
@@ -104,8 +112,8 @@ export declare const ERROR_INVITE_ACCOUNT_EXISTS_USERNAME: "invite_account_exist
|
|
|
104
112
|
export declare const ERROR_INVITE_ACCOUNT_EXISTS_EMAIL: "invite_account_exists_email";
|
|
105
113
|
/** Admin tried to grant a role that is not web-grantable. */
|
|
106
114
|
export declare const ERROR_ROLE_NOT_WEB_GRANTABLE: "role_not_web_grantable";
|
|
107
|
-
/**
|
|
108
|
-
export declare const
|
|
115
|
+
/** Role grant ID not found or not owned by the target actor. */
|
|
116
|
+
export declare const ERROR_ROLE_GRANT_NOT_FOUND: "role_grant_not_found";
|
|
109
117
|
/** Query parameter `event_type` is not a valid audit event type. */
|
|
110
118
|
export declare const ERROR_INVALID_EVENT_TYPE: "invalid_event_type";
|
|
111
119
|
/** DELETE blocked by a foreign key constraint. */
|
|
@@ -124,31 +132,61 @@ export declare const ApiError: z.ZodObject<{
|
|
|
124
132
|
}, z.core.$loose>;
|
|
125
133
|
export type ApiError = z.infer<typeof ApiError>;
|
|
126
134
|
/**
|
|
127
|
-
* Input validation error — returned when
|
|
135
|
+
* Input validation error — returned when params / query / body fails Zod
|
|
136
|
+
* parsing, or when the request body is not valid JSON.
|
|
128
137
|
*
|
|
129
|
-
* `
|
|
138
|
+
* `error` is one of the four validation codes the framework emits.
|
|
139
|
+
* `issues` carries Zod's validation issues for diagnostic display on the
|
|
140
|
+
* three schema-failure cases (`invalid_request_body`,
|
|
141
|
+
* `invalid_route_params`, `invalid_query_params`). The `invalid_json_body`
|
|
142
|
+
* case (request body parse failure or non-object root) emits no `issues`,
|
|
143
|
+
* so the field is optional.
|
|
130
144
|
*/
|
|
131
145
|
export declare const ValidationError: z.ZodObject<{
|
|
132
|
-
error: z.
|
|
133
|
-
|
|
146
|
+
error: z.ZodEnum<{
|
|
147
|
+
invalid_request_body: "invalid_request_body";
|
|
148
|
+
invalid_json_body: "invalid_json_body";
|
|
149
|
+
invalid_route_params: "invalid_route_params";
|
|
150
|
+
invalid_query_params: "invalid_query_params";
|
|
151
|
+
}>;
|
|
152
|
+
issues: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
134
153
|
code: z.ZodString;
|
|
135
154
|
message: z.ZodString;
|
|
136
155
|
path: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
137
|
-
}, z.core.$loose
|
|
156
|
+
}, z.core.$loose>>>;
|
|
138
157
|
}, z.core.$loose>;
|
|
139
158
|
export type ValidationError = z.infer<typeof ValidationError>;
|
|
140
|
-
/**
|
|
159
|
+
/**
|
|
160
|
+
* Permission error — returned by `require_role()` and the dispatcher's
|
|
161
|
+
* post-authorization role gate when the actor's role_grants don't include any
|
|
162
|
+
* of the route's `auth.roles`.
|
|
163
|
+
*
|
|
164
|
+
* `required_roles` carries the full disjunction the route declared
|
|
165
|
+
* (`auth.roles` from the new flat-record shape). Single-role specs surface
|
|
166
|
+
* as a one-element array; multi-role disjunctions show every admittable
|
|
167
|
+
* role so clients can render targeted copy ("requires admin or steward").
|
|
168
|
+
*/
|
|
141
169
|
export declare const PermissionError: z.ZodObject<{
|
|
142
170
|
error: z.ZodLiteral<"insufficient_permissions">;
|
|
143
|
-
|
|
171
|
+
required_roles: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
144
172
|
}, z.core.$loose>;
|
|
145
173
|
export type PermissionError = z.infer<typeof PermissionError>;
|
|
146
|
-
/**
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Credential-type error — returned by the dispatcher's post-authorization
|
|
176
|
+
* credential gate (and the `require_credential_types` REST middleware) when
|
|
177
|
+
* the request's credential type isn't in the route's
|
|
178
|
+
* `auth.credential_types` allowlist.
|
|
179
|
+
*
|
|
180
|
+
* `required_credential_types` carries what the route declared
|
|
181
|
+
* (`['daemon_token']` for keeper; future gates carry their own labels).
|
|
182
|
+
* Symmetric with `PermissionError`'s `required_roles`: clients see what
|
|
183
|
+
* the route demanded, not what their credential is.
|
|
184
|
+
*/
|
|
185
|
+
export declare const CredentialTypeRequiredError: z.ZodObject<{
|
|
186
|
+
error: z.ZodLiteral<"credential_type_required">;
|
|
187
|
+
required_credential_types: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
150
188
|
}, z.core.$loose>;
|
|
151
|
-
export type
|
|
189
|
+
export type CredentialTypeRequiredError = z.infer<typeof CredentialTypeRequiredError>;
|
|
152
190
|
/** Rate limit error — returned when a rate limiter rejects the request. */
|
|
153
191
|
export declare const RateLimitError: z.ZodObject<{
|
|
154
192
|
error: z.ZodLiteral<"rate_limit_exceeded">;
|
|
@@ -169,7 +207,7 @@ export type ForeignKeyError = z.infer<typeof ForeignKeyError>;
|
|
|
169
207
|
* Authorization-phase failure shapes. Surfaced when the dispatcher's
|
|
170
208
|
* `apply_authorization_phase` rejects a request before the handler runs —
|
|
171
209
|
* the route is acting-aware (input declares `acting?: ActingActor` or
|
|
172
|
-
* auth requires
|
|
210
|
+
* auth requires role_grants), but actor resolution failed.
|
|
173
211
|
*
|
|
174
212
|
* 400: `actor_required` (with `available[]`) for unspecified-actor on
|
|
175
213
|
* a multi-actor account; `actor_not_on_account` for a supplied actor
|
|
@@ -180,7 +218,7 @@ export type ForeignKeyError = z.infer<typeof ForeignKeyError>;
|
|
|
180
218
|
* race (account/actor row deleted between credential validation and
|
|
181
219
|
* the dispatcher's follow-up read).
|
|
182
220
|
*
|
|
183
|
-
* Used by `derive_error_schemas` when `
|
|
221
|
+
* Used by `derive_error_schemas` when `auth.actor !== 'none'` so the
|
|
184
222
|
* merged error surface matches what the dispatcher actually emits.
|
|
185
223
|
*/
|
|
186
224
|
export declare const ActorRequiredError: z.ZodObject<{
|
|
@@ -232,24 +270,20 @@ export type RateLimitKey = z.infer<typeof RateLimitKey>;
|
|
|
232
270
|
* Route handlers can declare additional error schemas via `RouteSpec.errors`;
|
|
233
271
|
* explicit entries override auto-derived ones for the same status code.
|
|
234
272
|
*
|
|
235
|
-
* Derivation rules:
|
|
236
|
-
* - **Has input
|
|
237
|
-
* -
|
|
238
|
-
* -
|
|
239
|
-
*
|
|
240
|
-
* -
|
|
241
|
-
* -
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* `
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* `acting_aware` is computed at the merge call site (it requires inspecting
|
|
250
|
-
* the input schema for `acting?: ActingActor`, which lives in `auth/`). This
|
|
251
|
-
* keeps `http/` auth-agnostic — the per-route flag flows in via the optional
|
|
252
|
-
* `is_acting_aware` callback on `apply_route_specs` / `generate_app_surface`.
|
|
273
|
+
* Derivation rules under the new flat-record auth shape:
|
|
274
|
+
* - **Has input / params / query schema**: 400 (`ValidationError`).
|
|
275
|
+
* - **`auth.account === 'required'`** or **`auth.actor === 'required'`**: 401
|
|
276
|
+
* (`ApiError`) — pre-validation 401 fires when the credential isn't there.
|
|
277
|
+
* `'optional'` does not derive 401.
|
|
278
|
+
* - **`auth.roles?.length`**: 403 (`PermissionError` carrying `required_roles`).
|
|
279
|
+
* - **`auth.credential_types?.length`**: 403 (`CredentialTypeRequiredError`
|
|
280
|
+
* carrying `required_credential_types` — symmetric with `PermissionError`).
|
|
281
|
+
* Today the only credential gate is keeper; future gates reuse the literal.
|
|
282
|
+
* - **`auth.actor !== 'none'`** (`'optional'` or `'required'`): extends 400
|
|
283
|
+
* with `ActorRequiredError` / `ActorNotOnAccountError` and adds 500 union
|
|
284
|
+
* of `NoActorsOnAccountError` / `AccountVanishedError`. The dispatcher's
|
|
285
|
+
* authorization phase emits these whenever it tries to resolve an actor.
|
|
286
|
+
* - **rate_limit**: 429 (`RateLimitError` with `retry_after`).
|
|
253
287
|
*/
|
|
254
288
|
export interface DeriveErrorSchemasOptions {
|
|
255
289
|
auth: RouteAuth;
|
|
@@ -257,7 +291,6 @@ export interface DeriveErrorSchemasOptions {
|
|
|
257
291
|
has_params?: boolean;
|
|
258
292
|
has_query?: boolean;
|
|
259
293
|
rate_limit?: RateLimitKey;
|
|
260
|
-
acting_aware?: boolean;
|
|
261
294
|
}
|
|
262
|
-
export declare const derive_error_schemas: ({ auth, has_input, has_params, has_query, rate_limit,
|
|
295
|
+
export declare const derive_error_schemas: ({ auth, has_input, has_params, has_query, rate_limit, }: DeriveErrorSchemasOptions) => RouteErrorSchemas;
|
|
263
296
|
//# sourceMappingURL=error_schemas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
+
import { needs_actor } from './auth_shape.js';
|
|
15
16
|
// --- Core: Validation (auto-derived by route spec middleware) ---
|
|
16
17
|
/** Request body failed Zod validation. */
|
|
17
18
|
export const ERROR_INVALID_REQUEST_BODY = 'invalid_request_body';
|
|
@@ -26,6 +27,16 @@ export const ERROR_INVALID_QUERY_PARAMS = 'invalid_query_params';
|
|
|
26
27
|
export const ERROR_AUTHENTICATION_REQUIRED = 'authentication_required';
|
|
27
28
|
/** Authenticated but missing required role. */
|
|
28
29
|
export const ERROR_INSUFFICIENT_PERMISSIONS = 'insufficient_permissions';
|
|
30
|
+
/**
|
|
31
|
+
* Route requires a credential type the request didn't arrive on.
|
|
32
|
+
* Symmetric with `ERROR_INSUFFICIENT_PERMISSIONS` + `required_roles`:
|
|
33
|
+
* the body carries `required_credential_types: ReadonlyArray<string>`
|
|
34
|
+
* — what the route demanded, not what arrived. Today the only
|
|
35
|
+
* credential gate is keeper (`['daemon_token']`); future gates
|
|
36
|
+
* (`agent_token`, `group_actor_token`) reuse the same literal and
|
|
37
|
+
* label themselves through the array.
|
|
38
|
+
*/
|
|
39
|
+
export const ERROR_CREDENTIAL_TYPE_REQUIRED = 'credential_type_required';
|
|
29
40
|
/** Rate limiter rejected the request. */
|
|
30
41
|
export const ERROR_RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded';
|
|
31
42
|
/** Username or password is wrong (intentionally vague for enumeration prevention). */
|
|
@@ -77,8 +88,6 @@ export const ERROR_NO_ACTORS_ON_ACCOUNT = 'no_actors_on_account';
|
|
|
77
88
|
*/
|
|
78
89
|
export const ERROR_ACCOUNT_VANISHED = 'account_vanished';
|
|
79
90
|
// --- Keeper / daemon token ---
|
|
80
|
-
/** Keeper routes require daemon_token credential type. */
|
|
81
|
-
export const ERROR_KEEPER_REQUIRES_DAEMON_TOKEN = 'keeper_requires_daemon_token';
|
|
82
91
|
/** Daemon token header present but malformed or not matching current/previous token. */
|
|
83
92
|
export const ERROR_INVALID_DAEMON_TOKEN = 'invalid_daemon_token';
|
|
84
93
|
/** Daemon token valid but keeper account not yet resolved (pre-bootstrap). */
|
|
@@ -110,8 +119,8 @@ export const ERROR_INVITE_ACCOUNT_EXISTS_EMAIL = 'invite_account_exists_email';
|
|
|
110
119
|
// --- Admin routes ---
|
|
111
120
|
/** Admin tried to grant a role that is not web-grantable. */
|
|
112
121
|
export const ERROR_ROLE_NOT_WEB_GRANTABLE = 'role_not_web_grantable';
|
|
113
|
-
/**
|
|
114
|
-
export const
|
|
122
|
+
/** Role grant ID not found or not owned by the target actor. */
|
|
123
|
+
export const ERROR_ROLE_GRANT_NOT_FOUND = 'role_grant_not_found';
|
|
115
124
|
/** Query parameter `event_type` is not a valid audit event type. */
|
|
116
125
|
export const ERROR_INVALID_EVENT_TYPE = 'invalid_event_type';
|
|
117
126
|
// --- DB table browser ---
|
|
@@ -130,27 +139,59 @@ export const ERROR_DATABASE_CONNECTION_FAILED = 'database_connection_failed';
|
|
|
130
139
|
/** Base API error — all JSON error responses have at least `{error: string}`. */
|
|
131
140
|
export const ApiError = z.looseObject({ error: z.string() });
|
|
132
141
|
/**
|
|
133
|
-
* Input validation error — returned when
|
|
142
|
+
* Input validation error — returned when params / query / body fails Zod
|
|
143
|
+
* parsing, or when the request body is not valid JSON.
|
|
134
144
|
*
|
|
135
|
-
* `
|
|
145
|
+
* `error` is one of the four validation codes the framework emits.
|
|
146
|
+
* `issues` carries Zod's validation issues for diagnostic display on the
|
|
147
|
+
* three schema-failure cases (`invalid_request_body`,
|
|
148
|
+
* `invalid_route_params`, `invalid_query_params`). The `invalid_json_body`
|
|
149
|
+
* case (request body parse failure or non-object root) emits no `issues`,
|
|
150
|
+
* so the field is optional.
|
|
136
151
|
*/
|
|
137
152
|
export const ValidationError = z.looseObject({
|
|
138
|
-
error: z.
|
|
139
|
-
|
|
153
|
+
error: z.enum([
|
|
154
|
+
ERROR_INVALID_REQUEST_BODY,
|
|
155
|
+
ERROR_INVALID_JSON_BODY,
|
|
156
|
+
ERROR_INVALID_ROUTE_PARAMS,
|
|
157
|
+
ERROR_INVALID_QUERY_PARAMS,
|
|
158
|
+
]),
|
|
159
|
+
issues: z
|
|
160
|
+
.array(z.looseObject({
|
|
140
161
|
code: z.string(),
|
|
141
162
|
message: z.string(),
|
|
142
163
|
path: z.array(z.union([z.string(), z.number()])),
|
|
143
|
-
}))
|
|
164
|
+
}))
|
|
165
|
+
.optional(),
|
|
144
166
|
});
|
|
145
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* Permission error — returned by `require_role()` and the dispatcher's
|
|
169
|
+
* post-authorization role gate when the actor's role_grants don't include any
|
|
170
|
+
* of the route's `auth.roles`.
|
|
171
|
+
*
|
|
172
|
+
* `required_roles` carries the full disjunction the route declared
|
|
173
|
+
* (`auth.roles` from the new flat-record shape). Single-role specs surface
|
|
174
|
+
* as a one-element array; multi-role disjunctions show every admittable
|
|
175
|
+
* role so clients can render targeted copy ("requires admin or steward").
|
|
176
|
+
*/
|
|
146
177
|
export const PermissionError = z.looseObject({
|
|
147
178
|
error: z.literal(ERROR_INSUFFICIENT_PERMISSIONS),
|
|
148
|
-
|
|
179
|
+
required_roles: z.array(z.string()).readonly(),
|
|
149
180
|
});
|
|
150
|
-
/**
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Credential-type error — returned by the dispatcher's post-authorization
|
|
183
|
+
* credential gate (and the `require_credential_types` REST middleware) when
|
|
184
|
+
* the request's credential type isn't in the route's
|
|
185
|
+
* `auth.credential_types` allowlist.
|
|
186
|
+
*
|
|
187
|
+
* `required_credential_types` carries what the route declared
|
|
188
|
+
* (`['daemon_token']` for keeper; future gates carry their own labels).
|
|
189
|
+
* Symmetric with `PermissionError`'s `required_roles`: clients see what
|
|
190
|
+
* the route demanded, not what their credential is.
|
|
191
|
+
*/
|
|
192
|
+
export const CredentialTypeRequiredError = z.looseObject({
|
|
193
|
+
error: z.literal(ERROR_CREDENTIAL_TYPE_REQUIRED),
|
|
194
|
+
required_credential_types: z.array(z.string()).readonly(),
|
|
154
195
|
});
|
|
155
196
|
/** Rate limit error — returned when a rate limiter rejects the request. */
|
|
156
197
|
export const RateLimitError = z.looseObject({
|
|
@@ -169,7 +210,7 @@ export const ForeignKeyError = z.looseObject({
|
|
|
169
210
|
* Authorization-phase failure shapes. Surfaced when the dispatcher's
|
|
170
211
|
* `apply_authorization_phase` rejects a request before the handler runs —
|
|
171
212
|
* the route is acting-aware (input declares `acting?: ActingActor` or
|
|
172
|
-
* auth requires
|
|
213
|
+
* auth requires role_grants), but actor resolution failed.
|
|
173
214
|
*
|
|
174
215
|
* 400: `actor_required` (with `available[]`) for unspecified-actor on
|
|
175
216
|
* a multi-actor account; `actor_not_on_account` for a supplied actor
|
|
@@ -180,7 +221,7 @@ export const ForeignKeyError = z.looseObject({
|
|
|
180
221
|
* race (account/actor row deleted between credential validation and
|
|
181
222
|
* the dispatcher's follow-up read).
|
|
182
223
|
*
|
|
183
|
-
* Used by `derive_error_schemas` when `
|
|
224
|
+
* Used by `derive_error_schemas` when `auth.actor !== 'none'` so the
|
|
184
225
|
* merged error surface matches what the dispatcher actually emits.
|
|
185
226
|
*/
|
|
186
227
|
export const ActorRequiredError = z.looseObject({
|
|
@@ -207,10 +248,10 @@ export const AccountVanishedError = z.looseObject({
|
|
|
207
248
|
* - `'both'` — both keys.
|
|
208
249
|
*/
|
|
209
250
|
export const RateLimitKey = z.enum(['ip', 'account', 'both']);
|
|
210
|
-
export const derive_error_schemas = ({ auth, has_input = false, has_params = false, has_query = false, rate_limit,
|
|
251
|
+
export const derive_error_schemas = ({ auth, has_input = false, has_params = false, has_query = false, rate_limit, }) => {
|
|
211
252
|
const errors = {};
|
|
212
253
|
const has_validation = has_input || has_params || has_query;
|
|
213
|
-
if (
|
|
254
|
+
if (needs_actor(auth)) {
|
|
214
255
|
errors[400] = has_validation
|
|
215
256
|
? z.union([ValidationError, ActorRequiredError, ActorNotOnAccountError])
|
|
216
257
|
: z.union([ActorRequiredError, ActorNotOnAccountError]);
|
|
@@ -219,20 +260,27 @@ export const derive_error_schemas = ({ auth, has_input = false, has_params = fal
|
|
|
219
260
|
else if (has_validation) {
|
|
220
261
|
errors[400] = ValidationError;
|
|
221
262
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
263
|
+
// 401 fires when the dispatcher's pre-validation gate rejects an
|
|
264
|
+
// unauthenticated caller — `account === 'required'` (no credential) or
|
|
265
|
+
// `actor === 'required'` (no credential to resolve an actor against,
|
|
266
|
+
// per registry-time invariant 3 forbidding accountless actors in v1).
|
|
267
|
+
if (auth.account === 'required' || auth.actor === 'required') {
|
|
268
|
+
errors[401] = ApiError;
|
|
269
|
+
}
|
|
270
|
+
// 403 fires when `auth.roles` or `auth.credential_types` rejects a
|
|
271
|
+
// resolved request context. With both axes set, the 403 body could be
|
|
272
|
+
// either shape — emit the union so DEV-mode error-schema validation
|
|
273
|
+
// accepts whichever the dispatcher produced.
|
|
274
|
+
const has_role_gate = !!auth.roles?.length;
|
|
275
|
+
const has_credential_gate = !!auth.credential_types?.length;
|
|
276
|
+
if (has_role_gate && has_credential_gate) {
|
|
277
|
+
errors[403] = z.union([PermissionError, CredentialTypeRequiredError]);
|
|
278
|
+
}
|
|
279
|
+
else if (has_role_gate) {
|
|
280
|
+
errors[403] = PermissionError;
|
|
281
|
+
}
|
|
282
|
+
else if (has_credential_gate) {
|
|
283
|
+
errors[403] = CredentialTypeRequiredError;
|
|
236
284
|
}
|
|
237
285
|
if (rate_limit) {
|
|
238
286
|
errors[429] = RateLimitError;
|
|
@@ -1,33 +1,86 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Two-queue side-effect machinery for request handlers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `pending_effects` runs after the response is sent (see the request-context
|
|
7
|
-
* middleware), so this helper is the canonical home for post-commit fan-out.
|
|
4
|
+
* Handlers register fire-and-forget work in one of two queues, distinguished
|
|
5
|
+
* by their timing contract:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* - `pending_effects: Array<Promise<void>>` — eager. Producers push pool
|
|
8
|
+
* writes that are already in flight (audit emits, session-touch UPDATE,
|
|
9
|
+
* api-token usage tracking). The pool write is rollback-resilient by
|
|
10
|
+
* virtue of running outside the request transaction; pushing the
|
|
11
|
+
* in-flight handle lets test mode (`await_pending_effects: true`) await
|
|
12
|
+
* it.
|
|
13
|
+
* - `post_commit_effects: Array<() => void | Promise<void>>` — deferred.
|
|
14
|
+
* Producers go through `emit_after_commit(ctx, fn)`; the flush
|
|
15
|
+
* middleware is the only site that ever invokes the thunk, and it does
|
|
16
|
+
* so after the request handler (and its wrapping `db.transaction`)
|
|
17
|
+
* returns. Used for WS sends and any work that must observe a committed
|
|
18
|
+
* transaction.
|
|
19
|
+
*
|
|
20
|
+
* The split exists because the two shapes encode different contracts:
|
|
21
|
+
* eager pushers are saying "wait for this work that's already started";
|
|
22
|
+
* thunk pushers are saying "run this after the handler returns." Burying
|
|
23
|
+
* both behind one `Array<PendingEffect>` made `c.var.pending_effects.push(x)`
|
|
24
|
+
* ambiguous at the call site. With separate queues, the field name is
|
|
25
|
+
* the contract.
|
|
26
|
+
*
|
|
27
|
+
* Both `RouteContext` (HTTP routes) and `ActionContext` (RPC + WS
|
|
28
|
+
* actions) carry both queues by convention, so this module stays in
|
|
29
|
+
* `http/` (every transport depends on it).
|
|
12
30
|
*
|
|
13
31
|
* @module
|
|
14
32
|
*/
|
|
15
33
|
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
16
|
-
/**
|
|
17
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Minimal structural context required by `emit_after_commit`. Both
|
|
36
|
+
* `RouteContext` and `ActionContext` satisfy this — they each carry
|
|
37
|
+
* `log` and `post_commit_effects`.
|
|
38
|
+
*/
|
|
39
|
+
export interface EmitAfterCommitContext {
|
|
18
40
|
log: Logger;
|
|
19
|
-
|
|
41
|
+
post_commit_effects: Array<() => void | Promise<void>>;
|
|
20
42
|
}
|
|
21
43
|
/**
|
|
22
44
|
* Defer a side effect until after the handler's transaction commits.
|
|
23
45
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
46
|
+
* Pushes a raw thunk onto `ctx.post_commit_effects` — the flush
|
|
47
|
+
* middleware (in `server/app_server.ts` and the per-message WS dispatcher)
|
|
48
|
+
* is the only site that ever invokes `fn`. This is load-bearing: a
|
|
49
|
+
* previous implementation queued `Promise.resolve().then(fn)`, which
|
|
50
|
+
* JavaScript's microtask scheduler drains before the wrapping
|
|
51
|
+
* `await db.query('COMMIT')` resumes — `fn` fired mid-transaction and a
|
|
52
|
+
* rollback would leak a notification for state that never landed.
|
|
53
|
+
*
|
|
54
|
+
* The thunk shape closes that gap by deferring the work to flush time.
|
|
55
|
+
* The flush owns the per-thunk `try/catch` + `log.error` so any
|
|
56
|
+
* directly-pushed thunk (tests included) cannot escape the safety net.
|
|
57
|
+
*
|
|
58
|
+
* @param ctx - context carrying `log` and the `post_commit_effects` queue
|
|
59
|
+
* @param fn - side effect to run after commit; may return `void` or `Promise<void>`
|
|
60
|
+
* @mutates `ctx.post_commit_effects` - appends `fn` verbatim
|
|
61
|
+
*/
|
|
62
|
+
export declare const emit_after_commit: (ctx: EmitAfterCommitContext, fn: () => void | Promise<void>) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Drain an eager `pending_effects` queue: `Promise.allSettled` the
|
|
65
|
+
* in-flight handles, route every rejection through `log.error`, and
|
|
66
|
+
* fan out to `on_rejection` when supplied (production wires this to
|
|
67
|
+
* `on_effect_error` for monitoring).
|
|
68
|
+
*
|
|
69
|
+
* Returned promise resolves once every effect has settled. Never
|
|
70
|
+
* rejects. No-op when `effects` is empty (common on read-only
|
|
71
|
+
* requests).
|
|
72
|
+
*
|
|
73
|
+
* Symmetric with `flush_post_commit_effects` for the deferred queue.
|
|
74
|
+
*/
|
|
75
|
+
export declare const flush_pending_effects: (effects: ReadonlyArray<Promise<void>>, log: Logger, on_rejection?: (reason: unknown) => void) => Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Drain a `post_commit_effects` queue: invoke each thunk under
|
|
78
|
+
* `try/catch`, collect any returned promises, and `Promise.allSettled`
|
|
79
|
+
* them. Synchronous throws and async rejections are routed through
|
|
80
|
+
* `log.error` so one failing effect cannot starve siblings.
|
|
27
81
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @mutates `ctx.pending_effects` - appends a never-rejecting promise wrapping `fn`
|
|
82
|
+
* Returned promise resolves once every thunk has finished. Never
|
|
83
|
+
* rejects.
|
|
31
84
|
*/
|
|
32
|
-
export declare const
|
|
85
|
+
export declare const flush_post_commit_effects: (effects: ReadonlyArray<() => void | Promise<void>>, log: Logger) => Promise<void>;
|
|
33
86
|
//# sourceMappingURL=pending_effects.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pending_effects.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/pending_effects.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pending_effects.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/pending_effects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,KAAK,sBAAsB,EAC3B,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAC5B,IAEF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,GACjC,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EACrC,KAAK,MAAM,EACX,eAAe,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,KACtC,OAAO,CAAC,IAAI,CASd,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACrC,SAAS,aAAa,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAClD,KAAK,MAAM,KACT,OAAO,CAAC,IAAI,CAiBd,CAAC"}
|
|
@@ -1,35 +1,104 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Two-queue side-effect machinery for request handlers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `pending_effects` runs after the response is sent (see the request-context
|
|
7
|
-
* middleware), so this helper is the canonical home for post-commit fan-out.
|
|
4
|
+
* Handlers register fire-and-forget work in one of two queues, distinguished
|
|
5
|
+
* by their timing contract:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* - `pending_effects: Array<Promise<void>>` — eager. Producers push pool
|
|
8
|
+
* writes that are already in flight (audit emits, session-touch UPDATE,
|
|
9
|
+
* api-token usage tracking). The pool write is rollback-resilient by
|
|
10
|
+
* virtue of running outside the request transaction; pushing the
|
|
11
|
+
* in-flight handle lets test mode (`await_pending_effects: true`) await
|
|
12
|
+
* it.
|
|
13
|
+
* - `post_commit_effects: Array<() => void | Promise<void>>` — deferred.
|
|
14
|
+
* Producers go through `emit_after_commit(ctx, fn)`; the flush
|
|
15
|
+
* middleware is the only site that ever invokes the thunk, and it does
|
|
16
|
+
* so after the request handler (and its wrapping `db.transaction`)
|
|
17
|
+
* returns. Used for WS sends and any work that must observe a committed
|
|
18
|
+
* transaction.
|
|
19
|
+
*
|
|
20
|
+
* The split exists because the two shapes encode different contracts:
|
|
21
|
+
* eager pushers are saying "wait for this work that's already started";
|
|
22
|
+
* thunk pushers are saying "run this after the handler returns." Burying
|
|
23
|
+
* both behind one `Array<PendingEffect>` made `c.var.pending_effects.push(x)`
|
|
24
|
+
* ambiguous at the call site. With separate queues, the field name is
|
|
25
|
+
* the contract.
|
|
26
|
+
*
|
|
27
|
+
* Both `RouteContext` (HTTP routes) and `ActionContext` (RPC + WS
|
|
28
|
+
* actions) carry both queues by convention, so this module stays in
|
|
29
|
+
* `http/` (every transport depends on it).
|
|
12
30
|
*
|
|
13
31
|
* @module
|
|
14
32
|
*/
|
|
15
33
|
/**
|
|
16
34
|
* Defer a side effect until after the handler's transaction commits.
|
|
17
35
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
36
|
+
* Pushes a raw thunk onto `ctx.post_commit_effects` — the flush
|
|
37
|
+
* middleware (in `server/app_server.ts` and the per-message WS dispatcher)
|
|
38
|
+
* is the only site that ever invokes `fn`. This is load-bearing: a
|
|
39
|
+
* previous implementation queued `Promise.resolve().then(fn)`, which
|
|
40
|
+
* JavaScript's microtask scheduler drains before the wrapping
|
|
41
|
+
* `await db.query('COMMIT')` resumes — `fn` fired mid-transaction and a
|
|
42
|
+
* rollback would leak a notification for state that never landed.
|
|
21
43
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
44
|
+
* The thunk shape closes that gap by deferring the work to flush time.
|
|
45
|
+
* The flush owns the per-thunk `try/catch` + `log.error` so any
|
|
46
|
+
* directly-pushed thunk (tests included) cannot escape the safety net.
|
|
47
|
+
*
|
|
48
|
+
* @param ctx - context carrying `log` and the `post_commit_effects` queue
|
|
49
|
+
* @param fn - side effect to run after commit; may return `void` or `Promise<void>`
|
|
50
|
+
* @mutates `ctx.post_commit_effects` - appends `fn` verbatim
|
|
25
51
|
*/
|
|
26
52
|
export const emit_after_commit = (ctx, fn) => {
|
|
27
|
-
ctx.
|
|
53
|
+
ctx.post_commit_effects.push(fn);
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Drain an eager `pending_effects` queue: `Promise.allSettled` the
|
|
57
|
+
* in-flight handles, route every rejection through `log.error`, and
|
|
58
|
+
* fan out to `on_rejection` when supplied (production wires this to
|
|
59
|
+
* `on_effect_error` for monitoring).
|
|
60
|
+
*
|
|
61
|
+
* Returned promise resolves once every effect has settled. Never
|
|
62
|
+
* rejects. No-op when `effects` is empty (common on read-only
|
|
63
|
+
* requests).
|
|
64
|
+
*
|
|
65
|
+
* Symmetric with `flush_post_commit_effects` for the deferred queue.
|
|
66
|
+
*/
|
|
67
|
+
export const flush_pending_effects = async (effects, log, on_rejection) => {
|
|
68
|
+
if (effects.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
const results = await Promise.allSettled(effects);
|
|
71
|
+
for (const result of results) {
|
|
72
|
+
if (result.status === 'rejected') {
|
|
73
|
+
log.error('pending effect rejected:', result.reason);
|
|
74
|
+
on_rejection?.(result.reason);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Drain a `post_commit_effects` queue: invoke each thunk under
|
|
80
|
+
* `try/catch`, collect any returned promises, and `Promise.allSettled`
|
|
81
|
+
* them. Synchronous throws and async rejections are routed through
|
|
82
|
+
* `log.error` so one failing effect cannot starve siblings.
|
|
83
|
+
*
|
|
84
|
+
* Returned promise resolves once every thunk has finished. Never
|
|
85
|
+
* rejects.
|
|
86
|
+
*/
|
|
87
|
+
export const flush_post_commit_effects = async (effects, log) => {
|
|
88
|
+
const promises = [];
|
|
89
|
+
for (const fn of effects) {
|
|
28
90
|
try {
|
|
29
|
-
fn();
|
|
91
|
+
const result = fn();
|
|
92
|
+
if (result instanceof Promise) {
|
|
93
|
+
promises.push(result.catch((err) => {
|
|
94
|
+
log.error('post-commit side effect failed:', err);
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
30
97
|
}
|
|
31
98
|
catch (err) {
|
|
32
|
-
|
|
99
|
+
log.error('post-commit side effect failed:', err);
|
|
33
100
|
}
|
|
34
|
-
}
|
|
101
|
+
}
|
|
102
|
+
if (promises.length)
|
|
103
|
+
await Promise.allSettled(promises);
|
|
35
104
|
};
|