@fuzdev/fuz_app 0.54.0 → 0.56.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 +214 -103
- 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 +32 -0
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +35 -15
- 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 +141 -22
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +106 -187
- 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 +46 -40
- 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 +15 -10
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +54 -7
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +0 -4
- 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 +794 -410
- 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 +7 -13
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +26 -35
- package/dist/auth/account_queries.d.ts +52 -16
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +87 -38
- package/dist/auth/account_routes.d.ts +9 -11
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +118 -46
- package/dist/auth/account_schema.d.ts +46 -35
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +21 -28
- package/dist/auth/admin_action_specs.d.ts +100 -32
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +64 -33
- package/dist/auth/admin_actions.d.ts +13 -19
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +37 -41
- 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 -48
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +20 -56
- 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 +92 -32
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +75 -46
- 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/bearer_auth.d.ts +9 -7
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +13 -21
- 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 -42
- 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 +23 -11
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +28 -22
- 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 -18
- 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 +9 -4
- package/dist/auth/migrations.d.ts +37 -14
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +79 -32
- package/dist/auth/request_context.d.ts +331 -61
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +378 -95
- package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +163 -94
- 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/role_grant_offer_actions.js +473 -0
- package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +90 -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/role_grant_offer_queries.d.ts +242 -0
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_queries.js +533 -0
- 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} +60 -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 +6 -1
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +3 -1
- package/dist/auth/self_service_role_actions.d.ts +34 -27
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +68 -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 +12 -8
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +10 -7
- package/dist/dev/setup.d.ts +2 -2
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +9 -7
- package/dist/env/load.d.ts +1 -1
- package/dist/env/load.js +1 -1
- package/dist/hono_context.d.ts +64 -5
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +38 -2
- package/dist/http/CLAUDE.md +264 -87
- 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 +132 -19
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +132 -40
- package/dist/http/jsonrpc_errors.d.ts +27 -2
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +26 -2
- 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 +113 -41
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +130 -52
- package/dist/http/schema_helpers.d.ts +3 -2
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +9 -2
- package/dist/http/surface.d.ts +2 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +1 -2
- 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 +36 -31
- package/dist/server/validate_nginx.d.ts +1 -1
- package/dist/server/validate_nginx.js +1 -1
- package/dist/testing/CLAUDE.md +73 -55
- 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 +100 -96
- package/dist/testing/adversarial_headers.js +1 -1
- 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 +18 -17
- 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 +53 -39
- 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 +28 -22
- 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 +10 -8
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +22 -18
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +13 -14
- package/dist/testing/integration_helpers.d.ts +8 -6
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +29 -23
- package/dist/testing/middleware.d.ts +15 -11
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +75 -32
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +40 -24
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +3 -1
- 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 +2 -2
- 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 +24 -12
- 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 +65 -59
- package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +37 -22
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts +20 -0
- 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 +25 -18
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +28 -17
- 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} +39 -31
- 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} +25 -19
- 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 -227
- 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_actions.js +0 -452
- 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 +0 -183
- package/dist/auth/permit_offer_queries.d.ts.map +0 -1
- package/dist/auth/permit_offer_queries.js +0 -408
- package/dist/auth/permit_offer_schema.d.ts +0 -103
- package/dist/auth/permit_offer_schema.d.ts.map +0 -1
- package/dist/auth/permit_queries.d.ts +0 -210
- package/dist/auth/permit_queries.d.ts.map +0 -1
- package/dist/auth/permit_queries.js +0 -294
- 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 -21
- package/dist/auth/route_guards.d.ts.map +0 -1
- package/dist/auth/route_guards.js +0 -32
- 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 +0 -14
- 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
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -8,7 +8,7 @@ dispatcher, every transport adapter, the event state machine, and the
|
|
|
8
8
|
reactive frontend client.
|
|
9
9
|
|
|
10
10
|
For narrative context (consumer wiring examples, client-authoritative vs
|
|
11
|
-
server-authoritative dispatch,
|
|
11
|
+
server-authoritative dispatch, role-grant-offer UI integration) see
|
|
12
12
|
../../docs/usage.md §Deriving Route/Event Specs, §Single JSON-RPC 2.0 Endpoint,
|
|
13
13
|
§WebSocket Endpoint. For DEV-only output validation semantics see
|
|
14
14
|
../../docs/architecture.md §DEV-only Output Validation. For the SAES
|
|
@@ -28,17 +28,17 @@ codegen helpers are post-SAES-RPC-closeout stable.
|
|
|
28
28
|
|
|
29
29
|
Canonical source of truth. Three concrete kinds discriminate on `kind`:
|
|
30
30
|
|
|
31
|
-
| Kind | `auth`
|
|
32
|
-
| --------------------- |
|
|
33
|
-
| `request_response` | `
|
|
34
|
-
| `remote_notification` | `null`
|
|
35
|
-
| `local_call` | `null`
|
|
31
|
+
| Kind | `auth` | `side_effects` | `output` | `async` |
|
|
32
|
+
| --------------------- | ---------------------- | -------------- | ----------- | ------- |
|
|
33
|
+
| `request_response` | `RouteAuth` (non-null) | arbitrary | arbitrary | `true` |
|
|
34
|
+
| `remote_notification` | `null` | `true` | `z.ZodVoid` | `true` |
|
|
35
|
+
| `local_call` | `null` | arbitrary | arbitrary | boolean |
|
|
36
36
|
|
|
37
37
|
Enums + unions:
|
|
38
38
|
|
|
39
39
|
- `ActionKind` — `'request_response' | 'remote_notification' | 'local_call'`
|
|
40
40
|
- `ActionInitiator` — `'frontend' | 'backend' | 'both'`
|
|
41
|
-
- `
|
|
41
|
+
- `RouteAuth` — flat record `{account, actor, roles?, credential_types?}` from `http/auth_shape.ts`. Each axis (`account`, `actor`) is `'none' | 'optional' | 'required'`; `roles` and `credential_types` are optional any-of arrays. Cross-axis invariants: roles imply `actor: 'required'`; `account: 'none'` implies `actor: 'none'` (no accountless actors in v1); the unrestricted leaf (`account: 'none', actor: 'none'`) cannot declare roles or credential gates. The biconditional `actor !== 'none' ⟺ input declares acting?: ActingActor` is enforced at registration time via `assert_route_auth_acting_biconditional`.
|
|
42
42
|
- `ActionSpecUnion` — discriminated union of the three variants
|
|
43
43
|
- `ActionEventPhase` — `'send_request' | 'receive_request' | 'send_response' | 'receive_response' | 'send_error' | 'receive_error' | 'send' | 'receive' | 'execute'`
|
|
44
44
|
- `is_action_spec(value)` — structural type guard
|
|
@@ -53,10 +53,10 @@ declarative metadata for consumers (codegen, UI form-state matching, docs)
|
|
|
53
53
|
to read off the spec instead of scanning handler code. No runtime
|
|
54
54
|
enforcement — drift between declared reasons and what handlers actually
|
|
55
55
|
throw is caught per-module by source-scanning unit tests (see
|
|
56
|
-
`../../test/auth/
|
|
56
|
+
`../../test/auth/role_grant_offer_actions.error_reasons.test.ts`). Reuses
|
|
57
57
|
the same `as const` string constants the handler throws (e.g.
|
|
58
|
-
`
|
|
59
|
-
`
|
|
58
|
+
`ERROR_ROLE_GRANT_OFFER_*` from `../auth/role_grant_offer_action_specs.ts`,
|
|
59
|
+
`ERROR_ROLE_GRANT_NOT_FOUND` from `../http/error_schemas.ts`) so call
|
|
60
60
|
sites can import either side. Standard transport errors (validation,
|
|
61
61
|
auth, rate-limit) stay implicit.
|
|
62
62
|
|
|
@@ -65,8 +65,10 @@ the dispatcher's per-action rate-limit hook. Same hook fires on the HTTP
|
|
|
65
65
|
RPC dispatcher (`create_rpc_endpoint`) and the WebSocket dispatcher
|
|
66
66
|
(`register_action_ws`) — one budget per action, not per transport.
|
|
67
67
|
`'ip'` keys on the resolved client IP; `'account'` keys on
|
|
68
|
-
`request_context.
|
|
69
|
-
|
|
68
|
+
`request_context.account.id` (post-auth, account-grain — every
|
|
69
|
+
authenticated action has an account regardless of whether an actor was
|
|
70
|
+
resolved) and is rejected at registration when paired with
|
|
71
|
+
`auth.account !== 'required'` (no account to key on); `'both'` runs
|
|
70
72
|
both checks. **Throttle-requests semantics** — every invocation records,
|
|
71
73
|
regardless of outcome (different from REST login's throttle-failures
|
|
72
74
|
that resets on success). The motivating threat is admin mutation oracles
|
|
@@ -147,7 +149,7 @@ not the runtime):
|
|
|
147
149
|
### Primitives
|
|
148
150
|
|
|
149
151
|
- `ImportBuilder` — tracks value / type / namespace imports; emits `import type` when every entry on a module is a type (tree-shaking). Namespace (`* as specs`) entries are emitted verbatim. Public surface: `add`, `add_type`, `add_many`, `add_types`, `build`, `preview`, `has_imports`, `import_count`, `clear`.
|
|
150
|
-
- `get_executor_phases(spec, executor)` — phases a given executor (`'frontend' | 'backend'`) participates in for the spec.
|
|
152
|
+
- `get_executor_phases(spec, executor)` — phases a given executor (`'frontend' | 'backend'`) participates in for the spec. Branch-aware: the backend `can_receive` branch only pushes `send_error` when `!can_send`, so `initiator: 'both'` doesn't double-count and no `Set` dedup is needed.
|
|
151
153
|
- `get_handler_return_type(spec, phase, imports, collections_path?)` — the TS type a phase handler must return; triggers the `ActionOutputs` import (sourced from `collections_path`, default `'./action_collections.js'`) as a side effect.
|
|
152
154
|
- `generate_phase_handlers(spec, executor, imports, {action_event_type?, collections_path?})` — emits the typed handler-map fragment for one action; consumers compose these into `ActionHandlers` types. Returns `''` when the spec contributes no phases on the given executor (e.g. a backend-only `local_call` asked for `'frontend'`) so wrappers' `.filter(Boolean)` drops the row entirely instead of emitting a useless `${method}?: never` for a method that doesn't belong on this side.
|
|
153
155
|
- `generate_actions_api_method_signature(spec, imports, {sync_returns_value?, collections_path?})` — single source of truth for the typed `FrontendActionsApi` method shape. Threads `options?: RpcClientCallOptions` (`{signal?, transport_name?, queue?}`) onto every async method — `request_response`, `remote_notification`, and async `local_call` — and wraps the return in `Promise<Result<...>>`. Registers exactly the imports the emitted line references on `imports` — `ActionInputs` only when the spec has input, `RpcClientCallOptions` only when async, `Result` / `JsonrpcErrorObject` only when the return wraps in `Result`. Mirrors the leaf-level pattern `get_handler_return_type` already follows so wrappers no longer pre-register imports a per-spec emit might not actually use.
|
|
@@ -158,6 +160,7 @@ not the runtime):
|
|
|
158
160
|
- `DEFAULT_COLLECTIONS_PATH = './action_collections.js'` — shared default for every helper that takes a `collections_path?`.
|
|
159
161
|
- `DEFAULT_SPECS_MODULE = './action_specs.js'` — shared default for helpers that emit `specs.{method}_action_spec` and need a `* as specs` namespace import.
|
|
160
162
|
- `DEFAULT_METATYPES_PATH = './action_metatypes.js'` — shared default for the sibling module carrying the generated `ActionMethod` enum.
|
|
163
|
+
- `resolve_spec_qualifier(imports, {specs_module?, qualify_spec?})` — the standard default-vs-callback resolver every multi-source-aware helper in this module uses. With `qualify_spec` set, returns the callback verbatim (consumer owns its namespace setup); otherwise registers `* as specs from specs_module` (default `DEFAULT_SPECS_MODULE`) on `imports` and returns `(s) => 'specs.' + to_action_spec_identifier(s.method)`. Reuse from custom codegen helpers instead of reimplementing the defaulting + import-registration dance.
|
|
161
164
|
|
|
162
165
|
### High-level helpers
|
|
163
166
|
|
|
@@ -179,9 +182,9 @@ protocol actions in their typed API.
|
|
|
179
182
|
**Consumer tiers and namespace handling.** Single-source consumers (zzz,
|
|
180
183
|
undying — every spec lives in one local `action_specs.ts`) drop straight
|
|
181
184
|
into the helpers and accept the default `* as specs from specs_module`
|
|
182
|
-
namespace import. Multi-source consumers (
|
|
185
|
+
namespace import. Multi-source consumers (zap, visiones — which stitch
|
|
183
186
|
local specs together with `all_admin_action_specs` /
|
|
184
|
-
`
|
|
187
|
+
`all_role_grant_offer_action_specs` / `all_account_action_specs` /
|
|
185
188
|
`all_self_service_role_action_specs` from fuz_app) call
|
|
186
189
|
`create_namespace_qualifier(sources, imports)` once, then pass the
|
|
187
190
|
returned `qualify_spec` callback to the multi-source helpers
|
|
@@ -194,7 +197,7 @@ multi-namespace imports. The helper appends `.input` / `.output` to the
|
|
|
194
197
|
qualified identifier in `generate_action_inputs_outputs` automatically;
|
|
195
198
|
the callback returns the bare spec identifier.
|
|
196
199
|
|
|
197
|
-
Tier 1 (HTTP-only, e.g.
|
|
200
|
+
Tier 1 (HTTP-only, e.g. zap/visiones) emits a smaller surface — typically just
|
|
198
201
|
`ActionMethod` + `FrontendActionsApi` + `ActionInputs` / `ActionOutputs`
|
|
199
202
|
interfaces — and never calls `generate_typed_action_event_alias` or
|
|
200
203
|
`generate_frontend_action_handlers`. Tier 2 (`TypedActionEvent`-aware, e.g.
|
|
@@ -215,42 +218,69 @@ and `FrontendActionHandlers`.
|
|
|
215
218
|
### Wrapper + multi-source helper
|
|
216
219
|
|
|
217
220
|
- `compose_gen_file({origin_path, imports, blocks})` — encapsulates the per-`*.gen.ts` boilerplate (banner + `imports.build()` + blocks join + template literal). Returns the full file body. Each consumer producer collapses to one `compose_gen_file` call wrapping the helper invocations.
|
|
218
|
-
- `create_namespace_qualifier(sources, imports)` — multi-source consumer helper. Takes `ReadonlyArray<{ns, module, specs}>`, registers `import * as ns from module` for each on `imports`, builds the `method_to_ns` lookup with duplicate-method detection, returns `{qualify_spec, all_specs}` ready to thread through the high-level helpers. Closes the per-file boilerplate gap that kept
|
|
221
|
+
- `create_namespace_qualifier(sources, imports)` — multi-source consumer helper. Takes `ReadonlyArray<{ns, module, specs}>`, registers `import * as ns from module` for each on `imports`, builds the `method_to_ns` lookup with duplicate-method detection, returns `{qualify_spec, all_specs}` ready to thread through the high-level helpers. Closes the per-file boilerplate gap that kept zap + visiones on hand-rolled template strings even after the `qualify_spec?` callback landed (the per-call callback wasn't enough — the import dance + dup-check was the real boilerplate).
|
|
219
222
|
|
|
220
223
|
## HTTP bridge (`action_bridge.ts`)
|
|
221
224
|
|
|
222
225
|
Derives transport-specific specs from action specs. HTTP-specific concerns
|
|
223
226
|
(path, handler, errors) come from options, not the action spec.
|
|
224
227
|
|
|
225
|
-
- `create_action_route_spec(spec, options)` — one action → one `RouteSpec`. HTTP method defaults by `side_effects` (`true` → POST, `false` → GET; override via `options.http_method`).
|
|
228
|
+
- `create_action_route_spec(spec, options)` — one action → one `RouteSpec`. HTTP method defaults by `side_effects` (`true` → POST, `false` → GET; override via `options.http_method`). `route.auth` is `spec.auth` verbatim (the same `RouteAuth` shape governs both surfaces). `options.errors: RouteErrorSchemas` attaches transport-specific (HTTP status–keyed) error shapes. `transaction: spec.side_effects`. Throws if `spec.auth` is null.
|
|
226
229
|
- `create_action_event_spec(spec, {channel?})` — one notification action → one `EventSpec` for SSE surface + `create_validated_broadcaster`. Throws on non-`remote_notification` kind.
|
|
227
|
-
- `
|
|
230
|
+
- `derive_http_method(side_effects)` — exported for consumers that build custom bridges.
|
|
228
231
|
|
|
229
232
|
## Single JSON-RPC 2.0 endpoint (`action_rpc.ts`)
|
|
230
233
|
|
|
231
234
|
`create_rpc_endpoint({path, actions, log}): RouteSpec[]` produces **two**
|
|
232
235
|
route specs on the same path (GET + POST) that share one internal
|
|
233
236
|
dispatcher. Per-action auth lives inside the dispatcher; the outer routes
|
|
234
|
-
use `auth: {
|
|
237
|
+
use `auth: {account: 'none', actor: 'none'}` and `transaction: false`.
|
|
235
238
|
|
|
236
|
-
|
|
239
|
+
The HTTP RPC dispatcher is a thin shim around `perform_action`
|
|
240
|
+
(`actions/perform_action.ts`). The shim owns the wire-shape concerns
|
|
241
|
+
(envelope parsing, GET vs POST split, `c.json` binding); the
|
|
242
|
+
auth/validation/dispatch pipeline is shared with the WebSocket
|
|
243
|
+
dispatcher.
|
|
244
|
+
|
|
245
|
+
Phase order: **401 → 400 → 403 → handler** — validate first, authorize
|
|
246
|
+
after. The trade-off is that an unauthorized caller sees the validation
|
|
247
|
+
step; the alternative ordering (403-before-400) was rejected because
|
|
248
|
+
defense-in-depth via attack-surface obscurity is illusory when the
|
|
249
|
+
surface is published in `library.json` codegen anyway.
|
|
250
|
+
|
|
251
|
+
Shim responsibilities:
|
|
237
252
|
|
|
238
253
|
1. **Parse envelope** — POST body as `JsonrpcRequest` (parse errors → JSON-RPC `parse_error` 400). GET reads `method`, `id`, `params` from query string; missing `method`/`id` → 400 `invalid_request`. Integer `id` normalization: `?id=42` matches `{id: 42}`.
|
|
239
|
-
2. **Lookup method** — `Map<method, RpcAction>`. Unknown method → `method_not_found`. Duplicate methods throw at construction.
|
|
240
|
-
3. **GET read restriction** — GET is rejected for `side_effects: true` actions (`invalid_request` with "must use POST").
|
|
241
|
-
4. **
|
|
242
|
-
5. **
|
|
243
|
-
6. **
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
2. **Lookup method** — `Map<method, RpcAction>`. Unknown method → `method_not_found`. Duplicate methods throw at construction. Registration also runs `assert_route_auth_acting_biconditional(spec.auth, {input: spec.input}, ...)` to enforce invariant 2 — the helper takes a `{input, query?}` slot set so REST (input + query bi-located) and actions (input-only) share one entry point with surface-appropriate error messages.
|
|
255
|
+
3. **GET read restriction** — GET is rejected for `side_effects: true` actions (`invalid_request` with "must use POST"). HTTP-only.
|
|
256
|
+
4. **Build PerformActionInput** — read `account_id` / `credential_type` from `c.var`, resolve `client_ip` via `get_client_ip`, pass `c.req.raw.signal` as `signal`, build a DEV-warn-and-drop `notify`. Test-preset escape hatch reads `TEST_CONTEXT_PRESET_KEY` + `REQUEST_CONTEXT_KEY` and forwards as `preset.request_context`.
|
|
257
|
+
5. **Call `perform_action`** — runs steps 1–6 of the shared pipeline (see §Shared dispatch core below).
|
|
258
|
+
6. **Bind result** — `perform_action_result_to_envelope(id, result)` builds the JSON-RPC wire envelope; `c.json(envelope, result.status)` returns it.
|
|
259
|
+
|
|
260
|
+
The shared core inside `perform_action` runs:
|
|
261
|
+
|
|
262
|
+
- Pre-validation auth (401), input validation (400), authorization phase (with `apply_authorization_phase` resolving the actor from `validated_input.acting`), post-authorization auth (403 — credential gate first, role gate second), rate limit (429), transactional dispatch + DEV output validation, error normalization.
|
|
263
|
+
|
|
264
|
+
Resolution failures from the authorization phase come back as
|
|
265
|
+
`AuthorizationResult.ok === false` carrying `{status, body}` —
|
|
266
|
+
`perform_action` folds this into a JSON-RPC envelope where `error.code`
|
|
267
|
+
maps from `http_status_to_jsonrpc_error_code(result.status)`,
|
|
268
|
+
`error.message` is the reason string, and `error.data: {reason, ...rest}`
|
|
269
|
+
flattens any diagnostic fields (e.g. `available[]` for `actor_required`).
|
|
270
|
+
The two 500 reasons stay distinct: `no_actors_on_account` (signup
|
|
271
|
+
invariant violation — the actor enumeration came back empty);
|
|
272
|
+
`account_vanished` (torn read after resolve). REST emits the same `body`
|
|
273
|
+
directly via `c.json(body, status)` for surface consistency.
|
|
274
|
+
|
|
275
|
+
Error paths: `ThrownJsonrpcError` (duck-typed via `err instanceof Error
|
|
276
|
+
&& typeof err.code === 'number'`) preserves code + data verbatim. Duck-
|
|
277
|
+
typing avoids cross-copy `instanceof` misses when consumers throw their
|
|
278
|
+
own `ThrownJsonrpcError` (e.g. zzz). Generic thrown errors become
|
|
279
|
+
`internal_error` 500; message is the raw error under `DEV`, "internal
|
|
280
|
+
server error" otherwise. The HTTP shim's outer `c.json` then binds the
|
|
281
|
+
status.
|
|
282
|
+
|
|
283
|
+
Per-request handler shape (uniform across HTTP RPC + WS):
|
|
254
284
|
|
|
255
285
|
```ts
|
|
256
286
|
type ActionHandler<TInput, TOutput> = (
|
|
@@ -261,12 +291,14 @@ type ActionHandler<TInput, TOutput> = (
|
|
|
261
291
|
interface ActionContext {
|
|
262
292
|
auth: RequestContext | null; // null for public actions
|
|
263
293
|
request_id: JsonrpcRequestId;
|
|
294
|
+
connection_id?: Uuid; // populated on WS, undefined on HTTP
|
|
264
295
|
db: Db; // transaction for mutations, pool for reads
|
|
265
|
-
|
|
266
|
-
|
|
296
|
+
pending_effects: Array<Promise<void>>; // eager pool writes already in flight — see http/CLAUDE.md §Pending Effects
|
|
297
|
+
post_commit_effects: Array<() => void | Promise<void>>; // deferred — push via `emit_after_commit`
|
|
298
|
+
client_ip: string;
|
|
267
299
|
log: Logger;
|
|
268
|
-
notify: (method, params) => void; // HTTP: DEV-mode warn + drop (no streaming channel)
|
|
269
|
-
signal: AbortSignal; //
|
|
300
|
+
notify: (method, params) => void; // HTTP: DEV-mode warn + drop (no streaming channel); WS: socket-scoped
|
|
301
|
+
signal: AbortSignal; // HTTP: client-disconnect; WS: AbortSignal.any([socket_close, request_cancel])
|
|
270
302
|
}
|
|
271
303
|
|
|
272
304
|
interface RpcAction {
|
|
@@ -275,31 +307,65 @@ interface RpcAction {
|
|
|
275
307
|
}
|
|
276
308
|
```
|
|
277
309
|
|
|
278
|
-
### `rpc_action(spec, handler)` — typed binder
|
|
310
|
+
### `rpc_action(spec, handler)` — typed binder with conditional `ctx.auth` narrowing
|
|
279
311
|
|
|
280
312
|
`rpc_action<TSpec extends RequestResponseActionSpec>(spec, handler)`
|
|
281
|
-
returns a `RpcAction` with the handler's input / output types pinned
|
|
282
|
-
`z.infer<TSpec['input']>`
|
|
313
|
+
returns a `RpcAction` with the handler's input / output types pinned
|
|
314
|
+
to `z.infer<TSpec['input']>` / `z.infer<TSpec['output']>` and the
|
|
315
|
+
handler's `ctx.auth` slot tightened to the narrowest shape the
|
|
316
|
+
dispatcher's runtime guarantee allows. The conditional `HandlerForSpec<TSpec>`
|
|
317
|
+
discriminates on the spec literal:
|
|
318
|
+
|
|
319
|
+
| Spec auth axes | Selected handler type | `ctx.auth` |
|
|
320
|
+
| ------------------------------------------------------ | --------------------- | ------------------------ |
|
|
321
|
+
| `auth.actor === 'required'` | `ActorActionHandler` | `RequestActorContext` |
|
|
322
|
+
| `auth.account === 'required' && auth.actor === 'none'` | `AuthActionHandler` | `RequestContext` |
|
|
323
|
+
| else (public, optional axes) | `ActionHandler` | `RequestContext \| null` |
|
|
324
|
+
|
|
283
325
|
Use this at every spec → handler binding site so handler-type errors
|
|
284
326
|
surface at the factory call instead of at runtime:
|
|
285
327
|
|
|
286
328
|
```ts
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
329
|
+
// actor-implying spec → ctx.auth: RequestActorContext (actor non-null)
|
|
330
|
+
rpc_action(role_grant_revoke_action_spec, async (input, ctx) => {
|
|
331
|
+
const revoker_id = ctx.auth.actor.id;
|
|
290
332
|
// …
|
|
291
|
-
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// account-grain spec → ctx.auth: RequestContext (actor: null)
|
|
336
|
+
rpc_action(account_verify_action_spec, (_input, ctx) => {
|
|
337
|
+
return to_session_account(ctx.auth.account);
|
|
338
|
+
});
|
|
292
339
|
```
|
|
293
340
|
|
|
341
|
+
The bracketed form `[T] extends ['required']` defeats distributive
|
|
342
|
+
conditionals so a degraded `AuthAxisState` union (when the spec was
|
|
343
|
+
typed without preserving its literal) falls through to the loosest
|
|
344
|
+
tier instead of collapsing to the narrowest. Specs declared with
|
|
345
|
+
`satisfies RequestResponseActionSpec` (canonical) preserve the
|
|
346
|
+
literals — typing a spec directly as `RequestResponseActionSpec`
|
|
347
|
+
widens the axes and silently drops the ergonomic narrowing (the
|
|
348
|
+
binder still compiles; consumers just lose the auto-narrow on
|
|
349
|
+
`ctx.auth`).
|
|
350
|
+
|
|
294
351
|
zzz uses a codegen-driven `Record<Method, Handler>` map for the same
|
|
295
352
|
narrowing — ideal when handlers are stateless free functions. fuz_app's
|
|
296
|
-
handlers close over factory-captured deps (`log`, `
|
|
353
|
+
handlers close over factory-captured deps (`log`, `audit`,
|
|
297
354
|
`options.app_settings`, `options.max_tokens`), so per-pair typing via
|
|
298
355
|
`rpc_action()` is the right shape here: the binding happens at
|
|
299
356
|
construction time and the handler keeps its closure. Applied across
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
357
|
+
all four registries — `admin_actions.ts`,
|
|
358
|
+
`role_grant_offer_actions.ts`, `self_service_role_actions.ts` (every
|
|
359
|
+
spec there is actor-implying), and `account_actions.ts` (account-grain).
|
|
360
|
+
The conditional auto-selects the right tier per spec; consumers don't
|
|
361
|
+
pick a binder.
|
|
362
|
+
|
|
363
|
+
The earlier two-binder split (`rpc_action` + `rpc_actor_action`) was
|
|
364
|
+
collapsed once the symmetric account-grain narrowing landed. Same
|
|
365
|
+
runtime; the second symbol no longer added information the spec
|
|
366
|
+
literal didn't already carry. Uniform binding keeps a future handler
|
|
367
|
+
that gains `ctx.auth.actor` reads from accidentally landing on a
|
|
368
|
+
looser narrow — the spec literal drives the type either way.
|
|
303
369
|
|
|
304
370
|
## Transports (`transports.ts`, `transports_http.ts`, `transports_ws.ts`, `transports_ws_backend.ts`)
|
|
305
371
|
|
|
@@ -380,7 +446,7 @@ Fan-out:
|
|
|
380
446
|
|
|
381
447
|
- `send(notification)` — broadcasts to every connection (current `send(request)` returns an internal_error "not yet implemented" — backend cannot initiate request-response).
|
|
382
448
|
- `broadcast_filtered(message, predicate)` — per-connection predicate over `ConnectionIdentity`; skips non-matching. Returns count.
|
|
383
|
-
- `send_to_account(account_id, message)` — targeted wrapper over `broadcast_filtered`. Mirrors `close_sockets_for_account` on the send side (every connection for the account). Structurally satisfies the `NotificationSender` interface from `auth/
|
|
449
|
+
- `send_to_account(account_id, message)` — targeted wrapper over `broadcast_filtered`. Mirrors `close_sockets_for_account` on the send side (every connection for the account). Structurally satisfies the `NotificationSender` interface from `auth/role_grant_offer_notifications.ts` (see `../auth/CLAUDE.md` §WS notifications).
|
|
384
450
|
- `get_connection_count()` — telemetry counter over the connection map.
|
|
385
451
|
|
|
386
452
|
Return values are bookkeeping, not delivery receipts — `0` means no live
|
|
@@ -395,7 +461,7 @@ guard in `realtime/sse_auth_guard.ts` but targets the WS transport.
|
|
|
395
461
|
|
|
396
462
|
`WS_DISCONNECT_EVENT_TYPES` (ReadonlySet): `session_revoke`,
|
|
397
463
|
`token_revoke`, `session_revoke_all`, `token_revoke_all`, `password_change`.
|
|
398
|
-
`
|
|
464
|
+
`role_grant_revoke` is intentionally **omitted** — the WS transport does not
|
|
399
465
|
track per-connection role requirements, so role-scoped disconnection would
|
|
400
466
|
require either closing all sockets (too aggressive) or new per-connection
|
|
401
467
|
role tracking (out of scope). Consumers that need it compose their own
|
|
@@ -440,57 +506,74 @@ Composes the standard upgrade stack:
|
|
|
440
506
|
|
|
441
507
|
1. `verify_request_source(allowed_origins)`
|
|
442
508
|
2. `require_auth`
|
|
443
|
-
3.
|
|
444
|
-
4.
|
|
509
|
+
3. upgrade-time authorization phase — resolves the acting actor and seeds `REQUEST_CONTEXT_KEY` for the inner `register_action_ws`'s upgrade-time identity capture
|
|
510
|
+
4. optional `require_role([required_role])` (single-element array form)
|
|
511
|
+
5. delegates to `register_action_ws`
|
|
445
512
|
|
|
446
|
-
Extends `RegisterActionWsOptions
|
|
513
|
+
Extends `RegisterActionWsOptions` with `allowed_origins: Array<RegExp>`
|
|
447
514
|
and optional `required_role: RoleName`. Returns `{transport}`. Note:
|
|
448
515
|
`required_role` is a **coarse upgrade-time gate** — per-action `auth` in
|
|
449
|
-
each spec still applies at dispatch time
|
|
450
|
-
`require_auth` / `require_role` are from
|
|
451
|
-
`../auth/CLAUDE.md` §Middleware for their semantics.)
|
|
516
|
+
each spec still applies at dispatch time via `perform_action`.
|
|
517
|
+
(`verify_request_source` and `require_auth` / `require_role` are from
|
|
518
|
+
`../auth/`; see `../auth/CLAUDE.md` §Middleware for their semantics.)
|
|
452
519
|
|
|
453
520
|
### `register_action_ws` (`register_action_ws.ts`) — lower-level
|
|
454
521
|
|
|
455
522
|
Exposed for tests (`create_ws_test_harness`) that need to drive the
|
|
456
523
|
dispatcher without the origin/auth front-stack.
|
|
457
524
|
|
|
458
|
-
Actions are passed as `ReadonlyArray<Action
|
|
525
|
+
Actions are passed as `ReadonlyArray<Action>` — the composable
|
|
459
526
|
`{spec, handler?}` tuple shared with `create_rpc_client`. The dispatcher
|
|
460
|
-
fans the array into a `spec_by_method` map (drives
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
`
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
`
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
527
|
+
fans the array into a `spec_by_method` map (drives envelope-shape
|
|
528
|
+
validation) and an `action_map: Map<string, RpcAction>` (drives
|
|
529
|
+
invocation, only request_response specs with a handler). Specs without
|
|
530
|
+
a handler (client-only / dispatcher-handled like `cancel`) miss
|
|
531
|
+
`action_map` and surface as `method_not_found` if the wire targets them.
|
|
532
|
+
|
|
533
|
+
Required deps: `db: Db` (pool-level, used by `perform_action` for both the
|
|
534
|
+
per-message authorization phase and the transactional dispatch wrap when
|
|
535
|
+
`spec.side_effects: true`). Audit fan-out and other rollback-resilient
|
|
536
|
+
fire-and-forget writes run through `AppDeps.audit` from each action
|
|
537
|
+
factory's closure — the dispatcher never holds a separate pool reference.
|
|
538
|
+
|
|
539
|
+
Per-message dispatch delegates to `perform_action` (`actions/perform_action.ts`)
|
|
540
|
+
— the shared core that HTTP RPC also calls. `register_action_ws` only owns
|
|
541
|
+
WS-specific concerns:
|
|
542
|
+
|
|
543
|
+
- **Wire envelope parsing** — JSON.parse → batch rejection → notification interception (cancel, silent drop) → per-message dispatch.
|
|
544
|
+
- **Cancel-notification interception** — `{request_id → AbortController}` map; aborts the matching pending controller before the cancel bubbles past the dispatcher.
|
|
545
|
+
- **Socket-scoped notify** — `(method, params) => ws.send(notification)`, threaded into `perform_action` as `notify`.
|
|
546
|
+
- **Composed abort signal** — `AbortSignal.any([socket_close, per_request_cancel])`, threaded into `perform_action` as `signal`.
|
|
547
|
+
- **Connection lifecycle** — `transport.add_connection` / `remove_connection`, `on_socket_open` / `_close` hooks, server heartbeat.
|
|
548
|
+
|
|
549
|
+
Per-message authorization phase: `perform_action` calls
|
|
550
|
+
`apply_authorization_phase` per-message (HTTP and WS uniformly). Role grant
|
|
551
|
+
changes during a connection lifetime are picked up on the next message —
|
|
552
|
+
no in-place refresh, no socket-close on `role_grant_revoke`. Authentication
|
|
553
|
+
invalidation (`session_revoke`, `password_change`, `token_revoke_all`)
|
|
554
|
+
still closes the socket via `create_ws_auth_guard`.
|
|
555
|
+
|
|
556
|
+
Per-message wire behavior (every step delegated to `perform_action`
|
|
557
|
+
except the WS-specific framing):
|
|
481
558
|
|
|
482
559
|
- **Batch JSON-RPC rejected** — arrays get `invalid_request`.
|
|
483
560
|
- **Notifications** — method + no id. Intercepted: `cancel` aborts the matching per-request controller; other notifications are silenced per JSON-RPC spec (no consumer notification handlers yet).
|
|
484
|
-
- **Per-action auth** —
|
|
485
|
-
- **
|
|
486
|
-
- **DEV-only output validation** — `spec.output.safeParse(output)` under `DEV`; logs error on mismatch, never throws, sends result unchanged. Uniform with RPC + REST surfaces.
|
|
487
|
-
- **Error handling** — `ThrownJsonrpcError` preserves code + data; generic throws are wrapped via `create_jsonrpc_error_response_from_thrown`. `ThrownJsonrpcError` is logged at `debug` (expected protocol outcome); generic errors at `error`.
|
|
561
|
+
- **Per-action auth + validation + dispatch** — uniform with HTTP RPC via `perform_action`: pre-validation auth (401) → input validation (400) → authorization phase → post-authorization auth (403) → rate limit (429) → handler under transaction (when `side_effects: true`) → DEV output validation.
|
|
562
|
+
- **Error handling** — handler throws normalize via `perform_action`'s thrown-error path. `ThrownJsonrpcError` preserves code + data; generic throws become `internal_error`. The WS shim sends the resulting envelope over the socket.
|
|
488
563
|
|
|
489
564
|
Two abort signals, composed via `AbortSignal.any`:
|
|
490
565
|
|
|
491
566
|
- `socket_abort_controller` — per-socket, fires on close. Drives every handler's `ctx.signal` on that socket.
|
|
492
567
|
- `pending_controllers: Map<JsonrpcRequestId, AbortController>` — per-request. Registered before dispatch, cleared in `finally` so late cancels for a completed id (or a reused id) can't null-abort the wrong handler. Unknown cancels no-op.
|
|
493
568
|
|
|
569
|
+
Per-message side-effect queues: `pending_effects: Array<Promise<void>>`
|
|
570
|
+
(eager) drains via `flush_pending_effects`; `post_commit_effects: Array<() => void | Promise<void>>`
|
|
571
|
+
(deferred — pushed by handlers via `emit_after_commit`) drains via
|
|
572
|
+
`flush_post_commit_effects`. Both flush in the same `try/finally` that
|
|
573
|
+
releases the request controller, so fire-and-forget audit / notification
|
|
574
|
+
effects pushed by the handler complete (or reject visibly) before the
|
|
575
|
+
next message dispatches. See `../http/CLAUDE.md` §Pending Effects.
|
|
576
|
+
|
|
494
577
|
Lifecycle hooks on `RegisterActionWsOptions`:
|
|
495
578
|
|
|
496
579
|
- `on_socket_open({ws, connection_id, identity, notify, signal})` — fires after `transport.add_connection` but before the first message. Awaited. Throws log + close with `1011 'socket bootstrap failed'` + send an `internal_error` frame.
|
|
@@ -850,7 +933,7 @@ silently no-op because `lookup_action_handler` always returns
|
|
|
850
933
|
|
|
851
934
|
`transport_for_method` and `on_action_event` are pure pass-throughs to
|
|
852
935
|
`create_rpc_client` — exposed so consumers needing per-method routing
|
|
853
|
-
(
|
|
936
|
+
(zap-style WS-for-actions / HTTP-for-rest split) or per-dispatch event
|
|
854
937
|
wiring (zzz-style reactive Cells observing `ActionEvent` lifecycle)
|
|
855
938
|
don't have to drop down to manual `create_rpc_client` construction
|
|
856
939
|
(which forfeits the bundled `api` / `api_result` pair).
|
|
@@ -888,28 +971,56 @@ natural fit when consumers already generate per-method type maps).
|
|
|
888
971
|
## Shared type surface (`action_types.ts`)
|
|
889
972
|
|
|
890
973
|
Sits above `action_spec.ts` (pure Zod) and below the dispatchers
|
|
891
|
-
(`register_action_ws.ts`, `action_rpc.ts`).
|
|
892
|
-
primitives (e.g. `heartbeat_action`) can name the
|
|
893
|
-
in server-only modules.
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
974
|
+
(`register_action_ws.ts`, `action_rpc.ts`, `perform_action.ts`).
|
|
975
|
+
Extracted so composable primitives (e.g. `heartbeat_action`) can name the
|
|
976
|
+
types without pulling in server-only modules.
|
|
977
|
+
|
|
978
|
+
This is the polymorphic `Action` shape only. The unified `ActionContext`
|
|
979
|
+
from `action_rpc.ts` is the single handler context across every
|
|
980
|
+
transport; `ActionHandler` is the single handler signature.
|
|
981
|
+
|
|
982
|
+
- `Action<TSpec>` — `{spec: TSpec, handler?: ActionHandler}`. The composable unit passed to both sides' `actions` arrays. Polymorphic on `kind`: `request_response` specs require a handler for dispatch; `remote_notification` specs may declare a stub for symmetry but are dispatcher-handled (e.g. `cancel`); `local_call` specs never reach a network dispatcher. The WS dispatcher only invokes handlers on `request_response` actions; everything else is registry-only.
|
|
983
|
+
|
|
984
|
+
`RpcAction = Action<RequestResponseActionSpec> & {handler: ActionHandler}`
|
|
985
|
+
is the narrowing the HTTP RPC dispatcher accepts (`create_rpc_endpoint`)
|
|
986
|
+
and the `rpc_action` binder produces (the actor-axis narrowing now lives
|
|
987
|
+
in `HandlerForSpec<TSpec>` — there's no longer a separate
|
|
988
|
+
`rpc_actor_action`).
|
|
989
|
+
|
|
990
|
+
## Shared dispatch core (`perform_action.ts`)
|
|
991
|
+
|
|
992
|
+
The transport-agnostic post-parse pipeline shared by HTTP RPC and
|
|
993
|
+
WebSocket. Each transport assembles a `PerformActionInput` from its wire
|
|
994
|
+
envelope + connection identity, calls `perform_action(input, deps)`,
|
|
995
|
+
and binds the discriminated `PerformActionResult` to its wire shape.
|
|
996
|
+
|
|
997
|
+
Pipeline (401 → 400 → 403 → handler):
|
|
998
|
+
|
|
999
|
+
1. Pre-validation auth (401) — short-circuits unauthenticated callers on `'required'` axes before input validation.
|
|
1000
|
+
2. Validate params (400) — `spec.input.safeParse` with `z.void()` / `?? {}` rules.
|
|
1001
|
+
3. Authorization phase — `apply_authorization_phase` against `account_id` + `validated_input.acting`. Test escape hatch lives in the caller — pass `preset.request_context` to skip the live phase.
|
|
1002
|
+
4. Post-authorization auth (403) — credential-type gate first, role gate second.
|
|
1003
|
+
5. Rate limit (429) — per-action IP / account throttling, throttle-requests semantics (every invocation records).
|
|
1004
|
+
6. Dispatch + DEV output validation + error normalization — `spec.side_effects` picks transaction (`deps.db.transaction`) vs pool. Handler throws roll back the transaction; `ThrownJsonrpcError` preserves code + data, generic throws become `internal_error`.
|
|
1005
|
+
|
|
1006
|
+
`PerformActionInput` carries `account_id`, `credential_type`, `client_ip`,
|
|
1007
|
+
`signal`, `notify`, optional `connection_id`, optional `preset`.
|
|
1008
|
+
`PerformActionDeps` carries `db` (pool-level), `pending_effects`, `log`,
|
|
1009
|
+
the two rate limiters. Audit writes are out-of-band: factories close over
|
|
1010
|
+
`AppDeps.audit` independently. `PerformActionResult` is `{kind: 'ok',
|
|
1011
|
+
result} | {kind: 'error', error, status}`; `perform_action_result_to_envelope(id, result)`
|
|
1012
|
+
builds the JSON-RPC wire shape both transports send.
|
|
901
1013
|
|
|
902
1014
|
## DEV-only output validation — uniform across surfaces
|
|
903
1015
|
|
|
904
|
-
The critical invariant:
|
|
905
|
-
output validation and
|
|
1016
|
+
The critical invariant: every action-handler surface applies DEV-only
|
|
1017
|
+
output validation and produces the **same failure mode** — log an error,
|
|
906
1018
|
return the response unchanged, do not throw, do not mutate status.
|
|
907
1019
|
|
|
908
|
-
| Surface
|
|
909
|
-
|
|
|
910
|
-
| REST bridge
|
|
911
|
-
|
|
|
912
|
-
| WebSocket | `register_action_ws.ts` — `if (DEV) spec.output.safeParse(output)` | short-circuit (no parse) |
|
|
1020
|
+
| Surface | Code location | Hot path under production |
|
|
1021
|
+
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
1022
|
+
| REST bridge | `http/route_spec.ts` — `wrap_output_validation` (applied via `apply_route_specs`; inherited by `create_action_route_spec`) | short-circuit (no parse) |
|
|
1023
|
+
| HTTP RPC + WebSocket dispatch | `actions/perform_action.ts` — `if (DEV) spec.output.safeParse(output)` inside the shared dispatch core | short-circuit (no parse) |
|
|
913
1024
|
|
|
914
1025
|
Caller-facing `input` schemas are validated **always** (DEV + production) —
|
|
915
1026
|
they're the contract with external callers. Server-authored `output`
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
import type { z } from 'zod';
|
|
11
|
-
import type { ActionSpec,
|
|
12
|
-
import type { RouteSpec,
|
|
11
|
+
import type { ActionSpec, ActionSideEffects } from './action_spec.js';
|
|
12
|
+
import type { RouteSpec, RouteMethod, RouteHandler } from '../http/route_spec.js';
|
|
13
|
+
import type { RouteAuth } from '../http/auth_shape.js';
|
|
13
14
|
import type { EventSpec } from '../realtime/sse.js';
|
|
14
15
|
import type { RouteErrorSchemas } from '../http/error_schemas.js';
|
|
15
16
|
/** Options for deriving a `RouteSpec` from an `ActionSpec`. */
|
|
@@ -22,7 +23,11 @@ export interface ActionRouteOptions {
|
|
|
22
23
|
query?: z.ZodObject;
|
|
23
24
|
/** Override the default HTTP method (default: `side_effects` → POST, else GET). */
|
|
24
25
|
http_method?: RouteMethod;
|
|
25
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Override the route's auth shape — defaults to the action spec's `auth`
|
|
28
|
+
* (the canonical four-axis shape from `http/auth_shape.ts` is shared
|
|
29
|
+
* verbatim between action specs and route specs, so no mapping is needed).
|
|
30
|
+
*/
|
|
26
31
|
auth?: RouteAuth;
|
|
27
32
|
/** Handler-specific error schemas (HTTP status code → Zod schema). Transport-specific — not on ActionSpec. */
|
|
28
33
|
errors?: RouteErrorSchemas;
|
|
@@ -31,8 +36,6 @@ export interface ActionRouteOptions {
|
|
|
31
36
|
export interface ActionEventOptions {
|
|
32
37
|
channel?: string;
|
|
33
38
|
}
|
|
34
|
-
/** Map an `ActionAuth` value to a `RouteAuth`. */
|
|
35
|
-
export declare const map_action_auth: (auth: ActionSpecAuth) => RouteAuth;
|
|
36
39
|
/** Derive the default HTTP method from side effects. */
|
|
37
40
|
export declare const derive_http_method: (side_effects: ActionSideEffects) => RouteMethod;
|
|
38
41
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_bridge.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAE3B,OAAO,KAAK,EAAC,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"action_bridge.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAE3B,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAE,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAEhE,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,uGAAuG;IACvG,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,8GAA8G;IAC9G,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,GAAI,cAAc,iBAAiB,KAAG,WAEpE,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,UAAU,EAChB,SAAS,kBAAkB,KACzB,SAmBF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,UAAU,EAChB,UAAU,kBAAkB,KAC1B,SAYF,CAAC"}
|
|
@@ -7,16 +7,6 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
-
/** Map an `ActionAuth` value to a `RouteAuth`. */
|
|
11
|
-
export const map_action_auth = (auth) => {
|
|
12
|
-
if (auth === 'public')
|
|
13
|
-
return { type: 'none' };
|
|
14
|
-
if (auth === 'authenticated')
|
|
15
|
-
return { type: 'authenticated' };
|
|
16
|
-
if (auth === 'keeper')
|
|
17
|
-
return { type: 'keeper' };
|
|
18
|
-
return { type: 'role', role: auth.role };
|
|
19
|
-
};
|
|
20
10
|
/** Derive the default HTTP method from side effects. */
|
|
21
11
|
export const derive_http_method = (side_effects) => {
|
|
22
12
|
return side_effects ? 'POST' : 'GET';
|
|
@@ -45,7 +35,7 @@ export const create_action_route_spec = (spec, options) => {
|
|
|
45
35
|
return {
|
|
46
36
|
method: options.http_method ?? derive_http_method(spec.side_effects),
|
|
47
37
|
path: options.path,
|
|
48
|
-
auth: options.auth ??
|
|
38
|
+
auth: options.auth ?? spec.auth,
|
|
49
39
|
handler: options.handler,
|
|
50
40
|
description: spec.description,
|
|
51
41
|
...(options.params ? { params: options.params } : {}),
|
|
@@ -154,6 +154,19 @@ export declare const to_action_spec_output_identifier: (method: string) => strin
|
|
|
154
154
|
* follows so wrappers no longer pre-register imports a per-spec emit might
|
|
155
155
|
* not actually use.
|
|
156
156
|
*
|
|
157
|
+
* **Optional-input detection.** The emitted parameter is `input?:` (caller
|
|
158
|
+
* may omit the argument) when either (a) the schema accepts `undefined` —
|
|
159
|
+
* `z.optional(z.strictObject(...))` and similar wrappers — or (b) the
|
|
160
|
+
* schema accepts the empty object `{}` — `z.strictObject({acting:
|
|
161
|
+
ActingActor})` and other all-optional-fields strict objects. The second
|
|
162
|
+
* probe mirrors the dispatcher's HTTP convention (`raw_params ?? {}` for
|
|
163
|
+
* non-`z.void()` schemas in `actions/action_rpc.ts` / `http/route_spec.ts`):
|
|
164
|
+
* if a request with no params reaches the handler, this is the value the
|
|
165
|
+
* schema is asked to validate. A schema with required fields fails both
|
|
166
|
+
* probes and stays `input:` (required at the typed surface). Refinements
|
|
167
|
+
* and transforms run as part of `safeParse`, so their accept/reject
|
|
168
|
+
* decisions feed into the optional/required choice naturally.
|
|
169
|
+
*
|
|
157
170
|
* @param options.sync_returns_value - When true (default), sync `local_call`
|
|
158
171
|
* methods return the output value directly; when false they're wrapped in
|
|
159
172
|
* `Result<{value, error}>` like async methods. Set to `false` if your
|
|
@@ -170,6 +183,25 @@ export declare const generate_actions_api_method_signature: (spec: ActionSpecUni
|
|
|
170
183
|
export type ActionMethodEnumKind = 'all' | 'request_response' | 'remote_notification' | 'local_call' | 'frontend' | 'backend' | 'frontend_handled' | 'backend_handled' | 'broadcast';
|
|
171
184
|
/** Default emit set — every enum kind. */
|
|
172
185
|
export declare const ACTION_METHOD_ENUM_KINDS_ALL: ReadonlySet<ActionMethodEnumKind>;
|
|
186
|
+
/**
|
|
187
|
+
* Resolve a per-spec identifier qualifier with the standard default-vs-callback
|
|
188
|
+
* dance. When `qualify_spec` is set, returns the caller's callback verbatim
|
|
189
|
+
* and registers no imports — the caller owns its namespace setup (the
|
|
190
|
+
* multi-source case where specs come from several modules). Otherwise,
|
|
191
|
+
* registers `* as specs from specs_module` (defaulting to
|
|
192
|
+
* `'./action_specs.js'`) on `imports` and returns
|
|
193
|
+
* `(spec) => 'specs.' + to_action_spec_identifier(spec.method)`.
|
|
194
|
+
*
|
|
195
|
+
* Used internally by every multi-source-aware helper in this module
|
|
196
|
+
* (`generate_action_specs_record`, `generate_action_inputs_outputs`,
|
|
197
|
+
* `generate_backend_actions_api`); exported so consumers writing their own
|
|
198
|
+
* codegen helpers can reuse the same defaulting + import-registration
|
|
199
|
+
* behavior instead of reimplementing it.
|
|
200
|
+
*/
|
|
201
|
+
export declare const resolve_spec_qualifier: (imports: ImportBuilder, options?: {
|
|
202
|
+
specs_module?: string;
|
|
203
|
+
qualify_spec?: (spec: ActionSpecUnion) => string;
|
|
204
|
+
}) => ((spec: ActionSpecUnion) => string);
|
|
173
205
|
/**
|
|
174
206
|
* Emit one or more `z.enum([...])` declarations for action method names —
|
|
175
207
|
* `ActionMethod`, `RequestResponseActionMethod`, `RemoteNotificationActionMethod`,
|