@fuzdev/fuz_app 0.51.0 → 0.53.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 +43 -10
- package/dist/actions/action_bridge.d.ts +3 -1
- package/dist/actions/action_bridge.d.ts.map +1 -1
- package/dist/actions/action_bridge.js +3 -1
- package/dist/actions/action_codegen.d.ts +28 -43
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +31 -50
- package/dist/actions/action_event.d.ts +44 -1
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +44 -1
- package/dist/actions/action_event_helpers.d.ts +26 -0
- package/dist/actions/action_event_helpers.d.ts.map +1 -1
- package/dist/actions/action_event_helpers.js +26 -1
- package/dist/actions/action_peer.d.ts +17 -0
- package/dist/actions/action_peer.d.ts.map +1 -1
- package/dist/actions/action_peer.js +8 -9
- package/dist/actions/action_registry.d.ts +1 -5
- package/dist/actions/action_registry.d.ts.map +1 -1
- package/dist/actions/action_registry.js +5 -11
- package/dist/actions/action_rpc.d.ts +20 -0
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +45 -20
- package/dist/actions/action_spec.d.ts +75 -6
- package/dist/actions/action_spec.d.ts.map +1 -1
- package/dist/actions/action_spec.js +36 -6
- package/dist/actions/frontend_rpc_client.d.ts +1 -9
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +1 -9
- package/dist/actions/register_action_ws.d.ts +19 -0
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +44 -1
- package/dist/actions/register_ws_endpoint.d.ts +3 -0
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +3 -0
- package/dist/actions/request_tracker.svelte.d.ts +24 -16
- package/dist/actions/request_tracker.svelte.d.ts.map +1 -1
- package/dist/actions/request_tracker.svelte.js +24 -16
- package/dist/actions/rpc_client.d.ts +0 -1
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +3 -17
- package/dist/actions/socket.svelte.d.ts +35 -16
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +33 -14
- package/dist/actions/transports.d.ts +15 -5
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +15 -15
- package/dist/actions/transports_http.d.ts +7 -0
- package/dist/actions/transports_http.d.ts.map +1 -1
- package/dist/actions/transports_http.js +7 -0
- package/dist/actions/transports_ws.d.ts +13 -0
- package/dist/actions/transports_ws.d.ts.map +1 -1
- package/dist/actions/transports_ws.js +13 -0
- package/dist/actions/transports_ws_auth_guard.d.ts +6 -4
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +6 -4
- package/dist/actions/transports_ws_backend.d.ts +14 -1
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +14 -10
- package/dist/auth/CLAUDE.md +64 -18
- package/dist/auth/account_queries.d.ts +7 -0
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +7 -0
- package/dist/auth/admin_action_specs.d.ts +5 -0
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +5 -0
- package/dist/auth/admin_actions.d.ts +1 -0
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +1 -0
- package/dist/auth/api_token_queries.d.ts +6 -0
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +6 -0
- package/dist/auth/app_settings_queries.d.ts +4 -0
- package/dist/auth/app_settings_queries.d.ts.map +1 -1
- package/dist/auth/app_settings_queries.js +4 -0
- package/dist/auth/audit_log_queries.d.ts +5 -0
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +5 -0
- package/dist/auth/audit_log_routes.d.ts +2 -2
- package/dist/auth/audit_log_routes.js +2 -2
- package/dist/auth/audit_log_schema.d.ts +2 -0
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +134 -55
- package/dist/auth/bearer_auth.d.ts +2 -0
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +2 -0
- package/dist/auth/bootstrap_account.d.ts +3 -0
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +3 -0
- package/dist/auth/cleanup.d.ts +6 -0
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +6 -0
- package/dist/auth/daemon_token_middleware.d.ts +4 -0
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +4 -0
- package/dist/auth/invite_queries.d.ts +3 -0
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +3 -0
- package/dist/auth/permit_offer_action_specs.d.ts +6 -0
- package/dist/auth/permit_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/permit_offer_action_specs.js +11 -0
- package/dist/auth/permit_offer_queries.d.ts +18 -0
- package/dist/auth/permit_offer_queries.d.ts.map +1 -1
- package/dist/auth/permit_offer_queries.js +18 -0
- package/dist/auth/permit_queries.d.ts +7 -0
- package/dist/auth/permit_queries.d.ts.map +1 -1
- package/dist/auth/permit_queries.js +7 -0
- package/dist/auth/request_context.d.ts +1 -0
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +1 -0
- package/dist/auth/role_schema.d.ts +2 -0
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +2 -0
- package/dist/auth/self_service_role_actions.d.ts +1 -0
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +1 -0
- package/dist/auth/session_lifecycle.d.ts +2 -0
- package/dist/auth/session_lifecycle.d.ts.map +1 -1
- package/dist/auth/session_lifecycle.js +2 -0
- package/dist/auth/session_middleware.d.ts +1 -0
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +1 -0
- package/dist/auth/session_queries.d.ts +9 -0
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +9 -0
- package/dist/cli/config.d.ts +1 -2
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +1 -2
- package/dist/cli/daemon.d.ts +6 -1
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +6 -1
- package/dist/db/assert_row.d.ts +2 -1
- package/dist/db/assert_row.d.ts.map +1 -1
- package/dist/db/assert_row.js +2 -1
- package/dist/db/create_db.d.ts +3 -1
- package/dist/db/create_db.d.ts.map +1 -1
- package/dist/db/create_db.js +3 -1
- package/dist/db/db.d.ts +15 -4
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +14 -3
- package/dist/db/db_pg.d.ts +4 -3
- package/dist/db/db_pg.d.ts.map +1 -1
- package/dist/db/db_pg.js +7 -5
- package/dist/db/db_pglite.d.ts +4 -4
- package/dist/db/db_pglite.js +4 -4
- package/dist/db/migrate.d.ts +7 -4
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +5 -2
- package/dist/db/sql_identifier.d.ts +2 -1
- package/dist/db/sql_identifier.d.ts.map +1 -1
- package/dist/db/sql_identifier.js +2 -1
- package/dist/db/status.d.ts +4 -1
- package/dist/db/status.d.ts.map +1 -1
- package/dist/db/status.js +5 -2
- package/dist/dev/setup.d.ts +15 -2
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +15 -2
- package/dist/env/dotenv.d.ts +2 -1
- package/dist/env/dotenv.d.ts.map +1 -1
- package/dist/env/dotenv.js +2 -1
- package/dist/env/load.d.ts +1 -3
- package/dist/env/load.d.ts.map +1 -1
- package/dist/env/load.js +1 -3
- package/dist/env/resolve.d.ts +1 -1
- package/dist/env/resolve.js +1 -1
- package/dist/env/update_env_variable.d.ts +2 -0
- package/dist/env/update_env_variable.d.ts.map +1 -1
- package/dist/env/update_env_variable.js +2 -0
- package/dist/hono_context.d.ts +2 -5
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +2 -5
- package/dist/http/common_routes.d.ts +0 -8
- package/dist/http/common_routes.d.ts.map +1 -1
- package/dist/http/common_routes.js +0 -8
- package/dist/http/db_routes.d.ts +0 -3
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +0 -3
- package/dist/http/error_schemas.d.ts +12 -11
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +11 -7
- package/dist/http/jsonrpc_errors.d.ts +0 -6
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +0 -6
- package/dist/http/origin.d.ts +6 -13
- package/dist/http/origin.d.ts.map +1 -1
- package/dist/http/origin.js +7 -14
- package/dist/http/pending_effects.d.ts +4 -0
- package/dist/http/pending_effects.d.ts.map +1 -1
- package/dist/http/pending_effects.js +4 -0
- package/dist/http/proxy.d.ts +3 -6
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +3 -6
- package/dist/http/route_spec.d.ts +14 -35
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +17 -22
- package/dist/http/schema_helpers.d.ts +0 -4
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +0 -4
- package/dist/http/surface.d.ts +2 -12
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +1 -12
- package/dist/rate_limiter.d.ts +30 -1
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +40 -1
- package/dist/realtime/sse.d.ts +7 -2
- package/dist/realtime/sse.d.ts.map +1 -1
- package/dist/realtime/sse.js +3 -2
- package/dist/realtime/sse_auth_guard.d.ts +21 -21
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +24 -24
- package/dist/realtime/subscriber_registry.d.ts +4 -5
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +4 -5
- package/dist/runtime/fs.d.ts +5 -3
- package/dist/runtime/fs.d.ts.map +1 -1
- package/dist/runtime/fs.js +5 -3
- package/dist/runtime/mock.d.ts +6 -3
- package/dist/runtime/mock.d.ts.map +1 -1
- package/dist/runtime/mock.js +6 -3
- package/dist/server/app_backend.d.ts +1 -0
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +1 -0
- package/dist/server/app_server.d.ts +31 -5
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +23 -7
- package/dist/server/startup.d.ts +0 -2
- package/dist/server/startup.d.ts.map +1 -1
- package/dist/server/startup.js +0 -2
- package/dist/server/static.d.ts +0 -1
- package/dist/server/static.d.ts.map +1 -1
- package/dist/server/static.js +0 -1
- package/dist/server/validate_nginx.d.ts +3 -3
- package/dist/server/validate_nginx.d.ts.map +1 -1
- package/dist/server/validate_nginx.js +0 -3
- package/dist/testing/CLAUDE.md +1 -1
- package/dist/testing/admin_integration.d.ts +5 -1
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +8 -6
- package/dist/testing/adversarial_404.d.ts +0 -2
- package/dist/testing/adversarial_404.d.ts.map +1 -1
- package/dist/testing/adversarial_404.js +0 -2
- package/dist/testing/adversarial_headers.d.ts +5 -4
- package/dist/testing/adversarial_headers.d.ts.map +1 -1
- package/dist/testing/adversarial_headers.js +5 -4
- package/dist/testing/adversarial_input.d.ts +4 -2
- package/dist/testing/adversarial_input.d.ts.map +1 -1
- package/dist/testing/adversarial_input.js +4 -2
- package/dist/testing/app_server.d.ts +25 -0
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +11 -2
- package/dist/testing/assertions.d.ts +23 -11
- package/dist/testing/assertions.d.ts.map +1 -1
- package/dist/testing/assertions.js +23 -11
- package/dist/testing/attack_surface.d.ts +0 -4
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +0 -4
- package/dist/testing/audit_completeness.d.ts +4 -1
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +4 -1
- package/dist/testing/auth_apps.d.ts +5 -10
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +5 -10
- package/dist/testing/data_exposure.d.ts +0 -11
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +0 -11
- package/dist/testing/db.d.ts +9 -7
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +9 -7
- package/dist/testing/error_coverage.d.ts +9 -14
- package/dist/testing/error_coverage.d.ts.map +1 -1
- package/dist/testing/error_coverage.js +9 -14
- package/dist/testing/integration.d.ts +4 -1
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +4 -1
- package/dist/testing/integration_helpers.d.ts +5 -34
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +5 -41
- package/dist/testing/middleware.d.ts +5 -10
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +5 -10
- package/dist/testing/mock_fs.d.ts +0 -2
- package/dist/testing/mock_fs.d.ts.map +1 -1
- package/dist/testing/mock_fs.js +0 -2
- package/dist/testing/rate_limiting.d.ts +3 -1
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +3 -1
- package/dist/testing/round_trip.d.ts +0 -2
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +0 -2
- package/dist/testing/rpc_attack_surface.d.ts +0 -2
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +0 -2
- package/dist/testing/rpc_helpers.d.ts +21 -14
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +21 -14
- package/dist/testing/rpc_round_trip.d.ts +0 -2
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +0 -2
- package/dist/testing/schema_generators.d.ts +5 -3
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +22 -3
- package/dist/testing/sse_round_trip.d.ts +3 -1
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +3 -1
- package/dist/testing/standard.d.ts +0 -2
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +0 -2
- package/dist/testing/stubs.d.ts +8 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +10 -3
- package/dist/testing/surface_invariants.d.ts +14 -3
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +14 -3
- package/dist/testing/ws_round_trip.d.ts +13 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/ui/AccountSessions.svelte +9 -0
- package/dist/ui/AccountSessions.svelte.d.ts.map +1 -1
- package/dist/ui/AdminAccounts.svelte +10 -0
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/AdminAuditLog.svelte +10 -0
- package/dist/ui/AdminAuditLog.svelte.d.ts.map +1 -1
- package/dist/ui/AdminInvites.svelte +9 -0
- package/dist/ui/AdminInvites.svelte.d.ts.map +1 -1
- package/dist/ui/AdminOverview.svelte +10 -0
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/AdminPermitHistory.svelte +9 -0
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -1
- package/dist/ui/AdminSessions.svelte +10 -0
- package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
- package/dist/ui/AdminSettings.svelte +9 -0
- package/dist/ui/AdminSettings.svelte.d.ts.map +1 -1
- package/dist/ui/AdminSurface.svelte +9 -0
- package/dist/ui/AdminSurface.svelte.d.ts.map +1 -1
- package/dist/ui/AppShell.svelte +24 -0
- package/dist/ui/AppShell.svelte.d.ts +23 -0
- package/dist/ui/AppShell.svelte.d.ts.map +1 -1
- package/dist/ui/BootstrapForm.svelte +17 -0
- package/dist/ui/BootstrapForm.svelte.d.ts +4 -0
- package/dist/ui/BootstrapForm.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +1 -1
- package/dist/ui/ColumnLayout.svelte +11 -0
- package/dist/ui/ColumnLayout.svelte.d.ts +10 -0
- package/dist/ui/ColumnLayout.svelte.d.ts.map +1 -1
- package/dist/ui/Datatable.svelte +18 -0
- package/dist/ui/Datatable.svelte.d.ts +17 -0
- package/dist/ui/Datatable.svelte.d.ts.map +1 -1
- package/dist/ui/LoginForm.svelte +18 -0
- package/dist/ui/LoginForm.svelte.d.ts +9 -0
- package/dist/ui/LoginForm.svelte.d.ts.map +1 -1
- package/dist/ui/LogoutButton.svelte +9 -0
- package/dist/ui/LogoutButton.svelte.d.ts +8 -0
- package/dist/ui/LogoutButton.svelte.d.ts.map +1 -1
- package/dist/ui/MenuLink.svelte +10 -0
- package/dist/ui/MenuLink.svelte.d.ts +9 -0
- package/dist/ui/MenuLink.svelte.d.ts.map +1 -1
- package/dist/ui/OpenSignupToggle.svelte +9 -0
- package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
- package/dist/ui/SignupForm.svelte +16 -0
- package/dist/ui/SignupForm.svelte.d.ts +4 -0
- package/dist/ui/SignupForm.svelte.d.ts.map +1 -1
- package/dist/ui/SurfaceExplorer.svelte +9 -0
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.d.ts +6 -1
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +7 -2
- package/dist/ui/auth_state.svelte.d.ts +16 -4
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +16 -4
- package/dist/ui/form_state.svelte.d.ts +9 -0
- package/dist/ui/form_state.svelte.d.ts.map +1 -1
- package/dist/ui/form_state.svelte.js +9 -0
- package/dist/ui/loadable.svelte.d.ts +6 -1
- package/dist/ui/loadable.svelte.d.ts.map +1 -1
- package/dist/ui/loadable.svelte.js +6 -1
- package/dist/ui/permit_offers_state.svelte.d.ts +2 -0
- package/dist/ui/permit_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/permit_offers_state.svelte.js +2 -0
- package/dist/ui/popover.svelte.d.ts +17 -4
- package/dist/ui/popover.svelte.d.ts.map +1 -1
- package/dist/ui/popover.svelte.js +17 -4
- package/dist/ui/position_helpers.d.ts +1 -3
- package/dist/ui/position_helpers.d.ts.map +1 -1
- package/dist/ui/position_helpers.js +1 -3
- package/dist/ui/sidebar_state.svelte.d.ts +21 -9
- package/dist/ui/sidebar_state.svelte.d.ts.map +1 -1
- package/dist/ui/sidebar_state.svelte.js +16 -2
- package/dist/ui/table_state.svelte.d.ts +14 -0
- package/dist/ui/table_state.svelte.d.ts.map +1 -1
- package/dist/ui/table_state.svelte.js +14 -0
- package/dist/ui/ui_fetch.d.ts +1 -7
- package/dist/ui/ui_fetch.d.ts.map +1 -1
- package/dist/ui/ui_fetch.js +1 -7
- package/dist/ui/ui_format.d.ts +2 -14
- package/dist/ui/ui_format.d.ts.map +1 -1
- package/dist/ui/ui_format.js +2 -14
- package/package.json +2 -2
|
@@ -40,10 +40,22 @@ export class ActionEvent {
|
|
|
40
40
|
}
|
|
41
41
|
// TODO rethink the reactivity of this class, maybe just use `$state` or `$state.raw`?
|
|
42
42
|
// does that have any negative implications when used on the backend?
|
|
43
|
+
/**
|
|
44
|
+
* Subscribe a listener fired on every `data` transition.
|
|
45
|
+
*
|
|
46
|
+
* @param listener - called with `(new_data, old_data, event)` after each mutation
|
|
47
|
+
* @returns unsubscribe function
|
|
48
|
+
* @mutates this - adds `listener` to the internal observer set
|
|
49
|
+
*/
|
|
43
50
|
observe(listener) {
|
|
44
51
|
this.#listeners.add(listener);
|
|
45
52
|
return () => this.#listeners.delete(listener);
|
|
46
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Replace the event's `data` and notify observers.
|
|
56
|
+
*
|
|
57
|
+
* @mutates this - sets `data` and fires every registered observer in insertion order
|
|
58
|
+
*/
|
|
47
59
|
set_data(new_data) {
|
|
48
60
|
const old_data = this.#data;
|
|
49
61
|
this.#data = new_data;
|
|
@@ -54,6 +66,11 @@ export class ActionEvent {
|
|
|
54
66
|
}
|
|
55
67
|
/**
|
|
56
68
|
* Parse input data according to the action's schema.
|
|
69
|
+
*
|
|
70
|
+
* @returns `this` for chaining with `handle_async` / `handle_sync`
|
|
71
|
+
* @mutates this - transitions step from `initial` to `parsed` (or to
|
|
72
|
+
* `failed` / `receive_error` on validation or response error)
|
|
73
|
+
* @throws Error if called from a step other than `initial`
|
|
57
74
|
*/
|
|
58
75
|
parse() {
|
|
59
76
|
if (this.#data.step !== 'initial') {
|
|
@@ -93,6 +110,14 @@ export class ActionEvent {
|
|
|
93
110
|
}
|
|
94
111
|
/**
|
|
95
112
|
* Execute the handler for the current phase.
|
|
113
|
+
*
|
|
114
|
+
* @mutates this - transitions step `parsed → handling → handled`, or to
|
|
115
|
+
* `failed` / `send_error` / `receive_error` on handler throw. No-op
|
|
116
|
+
* when already `failed`.
|
|
117
|
+
* @throws Error if called from a step other than `parsed` (or `failed`,
|
|
118
|
+
* which no-ops). Handler-thrown `ThrownJsonrpcError` is caught and
|
|
119
|
+
* routed through error phases; other throws are wrapped as
|
|
120
|
+
* `internal_error`.
|
|
96
121
|
*/
|
|
97
122
|
// TODO add timeout support
|
|
98
123
|
// TODO add cancellation support
|
|
@@ -136,7 +161,12 @@ export class ActionEvent {
|
|
|
136
161
|
}
|
|
137
162
|
}
|
|
138
163
|
/**
|
|
139
|
-
* Execute handler synchronously (only for sync local_call actions).
|
|
164
|
+
* Execute handler synchronously (only for sync `local_call` actions).
|
|
165
|
+
*
|
|
166
|
+
* @mutates this - transitions step `parsed → handling → handled`, or to
|
|
167
|
+
* `failed` on handler throw. No-op when already `failed`.
|
|
168
|
+
* @throws Error if the spec is not a sync `local_call`, or if called
|
|
169
|
+
* from a step other than `parsed` (or `failed`, which no-ops).
|
|
140
170
|
*/
|
|
141
171
|
handle_sync() {
|
|
142
172
|
if (this.spec.kind !== 'local_call' || this.spec.async) {
|
|
@@ -168,6 +198,14 @@ export class ActionEvent {
|
|
|
168
198
|
}
|
|
169
199
|
/**
|
|
170
200
|
* Transition to a new phase.
|
|
201
|
+
*
|
|
202
|
+
* @param phase - the next phase to transition into
|
|
203
|
+
* @mutates this - replaces `data` with a fresh phase-initial record,
|
|
204
|
+
* carrying forward `request` / `response` / `error` / `output` as
|
|
205
|
+
* appropriate for the kind/phase pair
|
|
206
|
+
* @throws Error if called from a step other than `handled` (or
|
|
207
|
+
* `failed`, which no-ops), or if the phase transition is illegal for
|
|
208
|
+
* the current phase
|
|
171
209
|
*/
|
|
172
210
|
transition(phase) {
|
|
173
211
|
if (this.#data.step === 'failed') {
|
|
@@ -340,6 +378,9 @@ export class ActionEvent {
|
|
|
340
378
|
// TODO not sure about this helper's design/location (should it be internal to the class constructor? a static method?)
|
|
341
379
|
/**
|
|
342
380
|
* Create an action event from a spec and initial input.
|
|
381
|
+
*
|
|
382
|
+
* @throws Error if `initial_phase` is omitted and the executor cannot
|
|
383
|
+
* initiate the action (per `spec.initiator`)
|
|
343
384
|
*/
|
|
344
385
|
export const create_action_event = (environment, spec, input, initial_phase) => {
|
|
345
386
|
const phase = initial_phase || get_initial_phase(spec.kind, spec.initiator, environment.executor);
|
|
@@ -351,6 +392,8 @@ export const create_action_event = (environment, spec, input, initial_phase) =>
|
|
|
351
392
|
};
|
|
352
393
|
/**
|
|
353
394
|
* Reconstruct an action event from serialized JSON data.
|
|
395
|
+
*
|
|
396
|
+
* @throws Error if the JSON's `method` field has no spec registered in `environment`
|
|
354
397
|
*/
|
|
355
398
|
export const create_action_event_from_json = (json, environment) => {
|
|
356
399
|
const spec = environment.lookup_action_spec(json.method);
|
|
@@ -58,13 +58,39 @@ export declare const is_notification_send_with_parsed_input: <TMethod extends st
|
|
|
58
58
|
step: "parsed" | "handling";
|
|
59
59
|
input: unknown;
|
|
60
60
|
};
|
|
61
|
+
/**
|
|
62
|
+
* Validate that a step transition is legal per `ACTION_EVENT_STEP_TRANSITIONS`.
|
|
63
|
+
*
|
|
64
|
+
* @throws Error if `from → to` is not a permitted transition
|
|
65
|
+
*/
|
|
61
66
|
export declare const validate_step_transition: (from: ActionEventStep, to: ActionEventStep) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Validate that `phase` is one of the phases allowed for `kind` per
|
|
69
|
+
* `ACTION_EVENT_PHASE_BY_KIND`.
|
|
70
|
+
*
|
|
71
|
+
* @throws Error if `phase` is not valid for `kind`
|
|
72
|
+
*/
|
|
62
73
|
export declare const validate_phase_for_kind: (kind: ActionKind, phase: ActionEventPhase) => void;
|
|
74
|
+
/**
|
|
75
|
+
* Validate that a phase chain is legal per `ACTION_EVENT_PHASE_TRANSITIONS`.
|
|
76
|
+
*
|
|
77
|
+
* @throws Error if `from → to` is not the permitted next phase (or `from` is terminal)
|
|
78
|
+
*/
|
|
63
79
|
export declare const validate_phase_transition: (from: ActionEventPhase, to: ActionEventPhase) => void;
|
|
64
80
|
export declare const get_initial_phase: (kind: ActionKind, initiator: ActionInitiator, executor: ActionExecutor) => ActionEventPhase | null;
|
|
65
81
|
export declare const should_validate_output: (kind: ActionKind, phase: ActionEventPhase) => boolean;
|
|
66
82
|
export declare const is_action_complete: (data: ActionEventData) => boolean;
|
|
67
83
|
export declare const create_initial_data: (kind: ActionKind, phase: ActionEventPhase, method: string, executor: ActionExecutor, input: unknown) => ActionEventData;
|
|
84
|
+
/**
|
|
85
|
+
* Pull the terminal `Result` from an action event.
|
|
86
|
+
*
|
|
87
|
+
* `data.error` populated → error path (covers both explicit `failed` and
|
|
88
|
+
* the unhandled `receive_error` / `send_error` case where no handler was
|
|
89
|
+
* registered for the error phase). `step === 'handled'` → success path.
|
|
90
|
+
*
|
|
91
|
+
* @throws Error if the event is in a non-terminal state (programming error —
|
|
92
|
+
* callers should check `is_action_complete` first)
|
|
93
|
+
*/
|
|
68
94
|
export declare const extract_action_result: (event: ActionEvent) => Result<{
|
|
69
95
|
value: ActionEventData["output"];
|
|
70
96
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_event_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_helpers.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"action_event_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,17 +27,32 @@ export const is_failed = (data) => data.step === 'failed';
|
|
|
27
27
|
// are created when transitioning from 'parsed' to 'handling'
|
|
28
28
|
export const is_send_request_with_parsed_input = (data) => is_send_request(data) && (data.step === 'parsed' || data.step === 'handling');
|
|
29
29
|
export const is_notification_send_with_parsed_input = (data) => is_notification_send(data) && (data.step === 'parsed' || data.step === 'handling');
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Validate that a step transition is legal per `ACTION_EVENT_STEP_TRANSITIONS`.
|
|
32
|
+
*
|
|
33
|
+
* @throws Error if `from → to` is not a permitted transition
|
|
34
|
+
*/
|
|
31
35
|
export const validate_step_transition = (from, to) => {
|
|
32
36
|
if (!ACTION_EVENT_STEP_TRANSITIONS[from].includes(to)) {
|
|
33
37
|
throw new Error(`Invalid step transition from '${from}' to '${to}'`);
|
|
34
38
|
}
|
|
35
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Validate that `phase` is one of the phases allowed for `kind` per
|
|
42
|
+
* `ACTION_EVENT_PHASE_BY_KIND`.
|
|
43
|
+
*
|
|
44
|
+
* @throws Error if `phase` is not valid for `kind`
|
|
45
|
+
*/
|
|
36
46
|
export const validate_phase_for_kind = (kind, phase) => {
|
|
37
47
|
if (!ACTION_EVENT_PHASE_BY_KIND[kind].includes(phase)) {
|
|
38
48
|
throw new Error(`Invalid phase '${phase}' for ${kind} action`);
|
|
39
49
|
}
|
|
40
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Validate that a phase chain is legal per `ACTION_EVENT_PHASE_TRANSITIONS`.
|
|
53
|
+
*
|
|
54
|
+
* @throws Error if `from → to` is not the permitted next phase (or `from` is terminal)
|
|
55
|
+
*/
|
|
41
56
|
export const validate_phase_transition = (from, to) => {
|
|
42
57
|
const expected = ACTION_EVENT_PHASE_TRANSITIONS[from];
|
|
43
58
|
if (expected !== to) {
|
|
@@ -81,6 +96,16 @@ export const create_initial_data = (kind, phase, method, executor, input) => ({
|
|
|
81
96
|
response: null,
|
|
82
97
|
notification: null,
|
|
83
98
|
});
|
|
99
|
+
/**
|
|
100
|
+
* Pull the terminal `Result` from an action event.
|
|
101
|
+
*
|
|
102
|
+
* `data.error` populated → error path (covers both explicit `failed` and
|
|
103
|
+
* the unhandled `receive_error` / `send_error` case where no handler was
|
|
104
|
+
* registered for the error phase). `step === 'handled'` → success path.
|
|
105
|
+
*
|
|
106
|
+
* @throws Error if the event is in a non-terminal state (programming error —
|
|
107
|
+
* callers should check `is_action_complete` first)
|
|
108
|
+
*/
|
|
84
109
|
export const extract_action_result = (event) => {
|
|
85
110
|
const { data } = event;
|
|
86
111
|
// `data.error` populated → error path. This covers two cases:
|
|
@@ -31,8 +31,25 @@ export declare class ActionPeer {
|
|
|
31
31
|
readonly transports: Transports;
|
|
32
32
|
default_send_options: Omit<ActionPeerSendOptions, 'signal'>;
|
|
33
33
|
constructor(options: ActionPeerOptions);
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a transport (per-call name → default name → registry default)
|
|
36
|
+
* and forward the message. Catches unexpected throws and converts them
|
|
37
|
+
* to JSON-RPC error responses — this method never throws.
|
|
38
|
+
*
|
|
39
|
+
* @returns the response envelope for requests, or `null` for successful
|
|
40
|
+
* notifications (`JsonrpcErrorResponse` if the notification's transport
|
|
41
|
+
* send failed)
|
|
42
|
+
*/
|
|
34
43
|
send(message: JsonrpcRequest, options?: ActionPeerSendOptions): Promise<JsonrpcResponseOrError>;
|
|
35
44
|
send(message: JsonrpcNotification, options?: ActionPeerSendOptions): Promise<JsonrpcErrorResponse | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Dispatch an inbound JSON-RPC message — request, notification, or
|
|
47
|
+
* malformed envelope. Never throws; unexpected failures become
|
|
48
|
+
* JSON-RPC error responses.
|
|
49
|
+
*
|
|
50
|
+
* @returns response message for requests, `null` for notifications, or
|
|
51
|
+
* an `invalid_request` error for malformed input
|
|
52
|
+
*/
|
|
36
53
|
receive(message: unknown): Promise<JsonrpcMessageFromServerToClient | null>;
|
|
37
54
|
}
|
|
38
55
|
//# sourceMappingURL=action_peer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_peer.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_peer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEN,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,EAAC,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IAClE,cAAc,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,sBAAsB,CAAC;IAGpC,UAAU,CAAC,EAAE,UAAU,CAAC;IAKxB,oBAAoB,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;CAC7D;AAED,qBAAa,UAAU;;IACtB,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAMhC,oBAAoB,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;gBAEhD,OAAO,EAAE,iBAAiB;
|
|
1
|
+
{"version":3,"file":"action_peer.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_peer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEN,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,EAAC,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAC,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IAClE,cAAc,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,sBAAsB,CAAC;IAGpC,UAAU,CAAC,EAAE,UAAU,CAAC;IAKxB,oBAAoB,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;CAC7D;AAED,qBAAa,UAAU;;IACtB,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAMhC,oBAAoB,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;gBAEhD,OAAO,EAAE,iBAAiB;IAMtC;;;;;;;;OAQG;IAEG,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA8CvC;;;;;;;OAOG;IACG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC;CAgIjF"}
|
|
@@ -48,6 +48,14 @@ export class ActionPeer {
|
|
|
48
48
|
return create_jsonrpc_error_response_from_thrown(to_jsonrpc_message_id(message), error);
|
|
49
49
|
} // TODO finally?
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Dispatch an inbound JSON-RPC message — request, notification, or
|
|
53
|
+
* malformed envelope. Never throws; unexpected failures become
|
|
54
|
+
* JSON-RPC error responses.
|
|
55
|
+
*
|
|
56
|
+
* @returns response message for requests, `null` for notifications, or
|
|
57
|
+
* an `invalid_request` error for malformed input
|
|
58
|
+
*/
|
|
51
59
|
async receive(message) {
|
|
52
60
|
try {
|
|
53
61
|
const result = await this.#receive_message(message);
|
|
@@ -59,9 +67,6 @@ export class ActionPeer {
|
|
|
59
67
|
return create_jsonrpc_error_response_from_thrown(to_jsonrpc_message_id(message), error);
|
|
60
68
|
} // TODO finally?
|
|
61
69
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Processes a single JSON-RPC message, returning a response message if any.
|
|
64
|
-
*/
|
|
65
70
|
async #receive_message(message) {
|
|
66
71
|
if (is_jsonrpc_request(message)) {
|
|
67
72
|
return this.#receive_request(message);
|
|
@@ -74,9 +79,6 @@ export class ActionPeer {
|
|
|
74
79
|
return create_jsonrpc_error_response(to_jsonrpc_message_id(message), jsonrpc_error_messages.invalid_request());
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Processes a JSON-RPC request. Returns the response message.
|
|
79
|
-
*/
|
|
80
82
|
async #receive_request(request) {
|
|
81
83
|
const spec = this.environment.lookup_action_spec(request.method);
|
|
82
84
|
if (!spec) {
|
|
@@ -122,9 +124,6 @@ export class ActionPeer {
|
|
|
122
124
|
return create_jsonrpc_error_response_from_thrown(request.id, error);
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
|
-
/**
|
|
126
|
-
* Processes a JSON-RPC notification. Returns nothing, no response exists.
|
|
127
|
-
*/
|
|
128
127
|
async #receive_notification(notification) {
|
|
129
128
|
const spec = this.environment.lookup_action_spec(notification.method);
|
|
130
129
|
if (!spec) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `ActionRegistry` — query and filter utility over `ActionSpecUnion[]`.
|
|
3
3
|
*
|
|
4
|
-
* Vocabulary (
|
|
4
|
+
* Vocabulary (see the `docs/` directory):
|
|
5
5
|
* - `*_handled_*` — request_response specs the named side **receives**
|
|
6
6
|
* (so the named side owns the handler). Used by codegen to emit typed
|
|
7
7
|
* handler maps.
|
|
@@ -27,10 +27,6 @@
|
|
|
27
27
|
* @module
|
|
28
28
|
*/
|
|
29
29
|
import type { ActionSpecUnion, RequestResponseActionSpec, RemoteNotificationActionSpec, LocalCallActionSpec } from './action_spec.js';
|
|
30
|
-
/**
|
|
31
|
-
* Utility class to manage and query action specifications.
|
|
32
|
-
* Provides helper methods to get actions by various criteria.
|
|
33
|
-
*/
|
|
34
30
|
export declare class ActionRegistry {
|
|
35
31
|
#private;
|
|
36
32
|
readonly specs: Array<ActionSpecUnion>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EACX,eAAe,EACf,yBAAyB,EACzB,4BAA4B,EAC5B,mBAAmB,EACnB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"action_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EACX,eAAe,EACf,yBAAyB,EACzB,4BAA4B,EAC5B,mBAAmB,EACnB,MAAM,kBAAkB,CAAC;AAO1B,qBAAa,cAAc;;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;gBAE3B,KAAK,EAAE,KAAK,CAAC,eAAe,CAAC;IAKzC,IAAI,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAEjD;IAED,IAAI,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,CAE3B;IAID,IAAI,sBAAsB,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAE7D;IAED,IAAI,yBAAyB,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAEnE;IAED,IAAI,gBAAgB,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAEjD;IAED,IAAI,wBAAwB,IAAI,KAAK,CAAC,MAAM,CAAC,CAE5C;IAED,IAAI,2BAA2B,IAAI,KAAK,CAAC,MAAM,CAAC,CAE/C;IAED,IAAI,kBAAkB,IAAI,KAAK,CAAC,MAAM,CAAC,CAEtC;IAOD,IAAI,0BAA0B,IAAI,KAAK,CAAC,eAAe,CAAC,CAEvD;IAED,IAAI,yBAAyB,IAAI,KAAK,CAAC,eAAe,CAAC,CAEtD;IAED,IAAI,4BAA4B,IAAI,KAAK,CAAC,MAAM,CAAC,CAEhD;IAED,IAAI,2BAA2B,IAAI,KAAK,CAAC,MAAM,CAAC,CAE/C;IAOD,IAAI,sBAAsB,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAE7D;IAED,IAAI,qBAAqB,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAE5D;IAED,IAAI,wBAAwB,IAAI,KAAK,CAAC,MAAM,CAAC,CAE5C;IAED,IAAI,uBAAuB,IAAI,KAAK,CAAC,MAAM,CAAC,CAE3C;IASD,IAAI,eAAe,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAKzD;IAED,IAAI,iBAAiB,IAAI,KAAK,CAAC,MAAM,CAAC,CAErC;IAED,IAAI,uBAAuB,IAAI,KAAK,CAAC,eAAe,CAAC,CAKpD;IAED,IAAI,yBAAyB,IAAI,KAAK,CAAC,MAAM,CAAC,CAE7C;IAID,IAAI,yBAAyB,IAAI,KAAK,CAAC,eAAe,CAAC,CAEtD;IAED,IAAI,yBAAyB,IAAI,KAAK,CAAC,eAAe,CAAC,CAEtD;IAED,IAAI,2BAA2B,IAAI,KAAK,CAAC,MAAM,CAAC,CAE/C;IAED,IAAI,2BAA2B,IAAI,KAAK,CAAC,MAAM,CAAC,CAE/C;IAID,IAAI,YAAY,IAAI,KAAK,CAAC,eAAe,CAAC,CAEzC;IAED,IAAI,mBAAmB,IAAI,KAAK,CAAC,eAAe,CAAC,CAEhD;IAED,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC,CAElC;IAED,IAAI,qBAAqB,IAAI,KAAK,CAAC,MAAM,CAAC,CAEzC;CAaD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `ActionRegistry` — query and filter utility over `ActionSpecUnion[]`.
|
|
3
3
|
*
|
|
4
|
-
* Vocabulary (
|
|
4
|
+
* Vocabulary (see the `docs/` directory):
|
|
5
5
|
* - `*_handled_*` — request_response specs the named side **receives**
|
|
6
6
|
* (so the named side owns the handler). Used by codegen to emit typed
|
|
7
7
|
* handler maps.
|
|
@@ -26,16 +26,10 @@
|
|
|
26
26
|
*
|
|
27
27
|
* @module
|
|
28
28
|
*/
|
|
29
|
-
//
|
|
30
|
-
// `
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
// used by codegen. The auth + initiator-direction getters are pre-built for
|
|
34
|
-
// future use. Revisit which getters to keep when the action system matures.
|
|
35
|
-
/**
|
|
36
|
-
* Utility class to manage and query action specifications.
|
|
37
|
-
* Provides helper methods to get actions by various criteria.
|
|
38
|
-
*/
|
|
29
|
+
// The auth (`public_*`, `authenticated_*`) and initiator-direction
|
|
30
|
+
// (`backend_to_frontend_*`, `frontend_to_backend_*`) getters are pre-built
|
|
31
|
+
// API surface unused by codegen today; kept low-cost for future filtering
|
|
32
|
+
// without a registry change.
|
|
39
33
|
export class ActionRegistry {
|
|
40
34
|
specs;
|
|
41
35
|
constructor(specs) {
|
|
@@ -18,6 +18,7 @@ import { type RouteSpec } from '../http/route_spec.js';
|
|
|
18
18
|
import { type RequestContext } from '../auth/request_context.js';
|
|
19
19
|
import type { Db } from '../db/db.js';
|
|
20
20
|
import { type JsonrpcRequestId } from '../http/jsonrpc.js';
|
|
21
|
+
import type { RateLimiter } from '../rate_limiter.js';
|
|
21
22
|
/**
|
|
22
23
|
* Per-request context provided to RPC action handlers.
|
|
23
24
|
*
|
|
@@ -108,6 +109,21 @@ export interface CreateRpcEndpointOptions {
|
|
|
108
109
|
actions: Array<RpcAction>;
|
|
109
110
|
/** Logger instance for handler context. */
|
|
110
111
|
log: Logger;
|
|
112
|
+
/**
|
|
113
|
+
* Per-IP rate limiter consulted for actions whose spec declares
|
|
114
|
+
* `rate_limit: 'ip'` or `'both'`. `null` disables the IP check.
|
|
115
|
+
* Per-action gate via `action.spec.rate_limit`. Same limiter is
|
|
116
|
+
* shared with the WebSocket action dispatcher — one budget per
|
|
117
|
+
* action, not per transport.
|
|
118
|
+
*/
|
|
119
|
+
action_ip_rate_limiter?: RateLimiter | null;
|
|
120
|
+
/**
|
|
121
|
+
* Per-actor rate limiter consulted for actions whose spec declares
|
|
122
|
+
* `rate_limit: 'account'` or `'both'`. Keyed on
|
|
123
|
+
* `request_context.actor.id`. `null` disables the account check.
|
|
124
|
+
* Same limiter is shared with the WebSocket action dispatcher.
|
|
125
|
+
*/
|
|
126
|
+
action_account_rate_limiter?: RateLimiter | null;
|
|
111
127
|
}
|
|
112
128
|
/**
|
|
113
129
|
* Single JSON-RPC 2.0 endpoint — the canonical RPC transport binding.
|
|
@@ -132,6 +148,10 @@ export interface CreateRpcEndpointOptions {
|
|
|
132
148
|
*
|
|
133
149
|
* @param options - endpoint path, actions, and logger
|
|
134
150
|
* @returns route specs (GET + POST) ready for `apply_route_specs`
|
|
151
|
+
* @throws Error if two actions share the same `spec.method` (registration-time
|
|
152
|
+
* duplicate detection); also throws if any action's `spec.input` is
|
|
153
|
+
* `z.null()` (JSON-RPC 2.0 §4.2 forbids `params: null` on the wire — use
|
|
154
|
+
* `z.void()` for parameterless methods).
|
|
135
155
|
*/
|
|
136
156
|
export declare const create_rpc_endpoint: (options: CreateRpcEndpointOptions) => Array<RouteSpec>;
|
|
137
157
|
//# sourceMappingURL=action_rpc.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE9F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,OAAO,EAGN,KAAK,gBAAgB,EAGrB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE9F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,OAAO,EAGN,KAAK,gBAAgB,EAGrB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,+DAA+D;IAC/D,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,EAAE,CAAC;IACP,oFAAoF;IACpF,aAAa,EAAE,EAAE,CAAC;IAClB,2EAA2E;IAC3E,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,CACxD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,aAAa,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,yBAAyB,EACjE,MAAM,KAAK,EACX,SAAS,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KACvE,SAGD,CAAC;AAEH,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACxC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5C;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACjD;AAkDD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,wBAAwB,KAAG,KAAK,CAAC,SAAS,CAkTtF,CAAC"}
|
|
@@ -43,13 +43,6 @@ export const rpc_action = (spec, handler) => ({
|
|
|
43
43
|
spec,
|
|
44
44
|
handler: handler,
|
|
45
45
|
});
|
|
46
|
-
/**
|
|
47
|
-
* Format a JSON-RPC error response.
|
|
48
|
-
*
|
|
49
|
-
* @param id - the request id (null if unknown)
|
|
50
|
-
* @param error - the error object
|
|
51
|
-
* @returns a JSON-RPC error response object
|
|
52
|
-
*/
|
|
53
46
|
const jsonrpc_error_response = (id, error) => ({
|
|
54
47
|
jsonrpc: JSONRPC_VERSION,
|
|
55
48
|
id,
|
|
@@ -58,10 +51,7 @@ const jsonrpc_error_response = (id, error) => ({
|
|
|
58
51
|
/**
|
|
59
52
|
* Check auth for an action spec against the request context.
|
|
60
53
|
*
|
|
61
|
-
* @
|
|
62
|
-
* @param request_context - the resolved identity (null if unauthenticated)
|
|
63
|
-
* @param credential_type - how the request was authenticated (session, api_token, daemon_token)
|
|
64
|
-
* @returns an error json if auth fails, or null if authorized
|
|
54
|
+
* @returns a JSON-RPC error object if auth fails, or `null` if authorized
|
|
65
55
|
*/
|
|
66
56
|
const check_action_auth = (auth, request_context, credential_type) => {
|
|
67
57
|
if (auth === 'public')
|
|
@@ -118,9 +108,13 @@ const check_action_auth = (auth, request_context, credential_type) => {
|
|
|
118
108
|
*
|
|
119
109
|
* @param options - endpoint path, actions, and logger
|
|
120
110
|
* @returns route specs (GET + POST) ready for `apply_route_specs`
|
|
111
|
+
* @throws Error if two actions share the same `spec.method` (registration-time
|
|
112
|
+
* duplicate detection); also throws if any action's `spec.input` is
|
|
113
|
+
* `z.null()` (JSON-RPC 2.0 §4.2 forbids `params: null` on the wire — use
|
|
114
|
+
* `z.void()` for parameterless methods).
|
|
121
115
|
*/
|
|
122
116
|
export const create_rpc_endpoint = (options) => {
|
|
123
|
-
const { path: endpoint_path, actions, log } = options;
|
|
117
|
+
const { path: endpoint_path, actions, log, action_ip_rate_limiter = null, action_account_rate_limiter = null, } = options;
|
|
124
118
|
// build action lookup map
|
|
125
119
|
const action_map = new Map();
|
|
126
120
|
for (const action of actions) {
|
|
@@ -130,18 +124,18 @@ export const create_rpc_endpoint = (options) => {
|
|
|
130
124
|
if (is_null_schema(action.spec.input)) {
|
|
131
125
|
throw new Error(`RPC action "${action.spec.method}" uses z.null() for input — JSON-RPC 2.0 §4.2 forbids "params": null on the wire (must be omitted or be a Structured value). Use z.void() for parameterless methods.`);
|
|
132
126
|
}
|
|
127
|
+
// Reject account-keyed rate limiting on public actions — there's no
|
|
128
|
+
// actor post-auth, so the account bucket has no key to consume.
|
|
129
|
+
if ((action.spec.rate_limit === 'account' || action.spec.rate_limit === 'both') &&
|
|
130
|
+
action.spec.auth === 'public') {
|
|
131
|
+
throw new Error(`RPC action "${action.spec.method}" declares rate_limit: '${action.spec.rate_limit}' but auth: 'public' — no actor available for account-keyed limiting. Use 'ip' or change auth.`);
|
|
132
|
+
}
|
|
133
133
|
action_map.set(action.spec.method, action);
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
136
136
|
* Core dispatcher — shared by GET and POST handlers.
|
|
137
137
|
*
|
|
138
|
-
* @param
|
|
139
|
-
* @param route - route context with db and pending_effects
|
|
140
|
-
* @param method_name - the JSON-RPC method name
|
|
141
|
-
* @param raw_params - the raw params (parsed from body or query string)
|
|
142
|
-
* @param id - the request id
|
|
143
|
-
* @param restrict_to_reads - true for GET requests (reject side_effects actions)
|
|
144
|
-
* @returns a Response
|
|
138
|
+
* @param restrict_to_reads - `true` for GET (rejects `side_effects: true` actions)
|
|
145
139
|
*/
|
|
146
140
|
const dispatch = async (c, route, method_name, raw_params, id, restrict_to_reads) => {
|
|
147
141
|
// step 2: lookup method
|
|
@@ -165,6 +159,38 @@ export const create_rpc_endpoint = (options) => {
|
|
|
165
159
|
const error = jsonrpc_error_response(id, auth_error);
|
|
166
160
|
return c.json(error, jsonrpc_error_code_to_http_status(auth_error.code));
|
|
167
161
|
}
|
|
162
|
+
// step 3.5: rate limit — throttle-requests semantics (record on every
|
|
163
|
+
// invocation, no success-reset). Suits admin mutation oracles where
|
|
164
|
+
// the *successful* call is the threat. Different from REST login's
|
|
165
|
+
// throttle-failures pattern that resets on success. Silent partial
|
|
166
|
+
// enforcement: a key is checked iff its bucket's limiter is wired —
|
|
167
|
+
// `rate_limit: 'both'` with only one limiter set runs only that side.
|
|
168
|
+
const rate_limit = action.spec.rate_limit;
|
|
169
|
+
const client_ip = get_client_ip(c);
|
|
170
|
+
if (rate_limit) {
|
|
171
|
+
const ip_check = action_ip_rate_limiter && (rate_limit === 'ip' || rate_limit === 'both');
|
|
172
|
+
const account_check = action_account_rate_limiter &&
|
|
173
|
+
request_context &&
|
|
174
|
+
(rate_limit === 'account' || rate_limit === 'both');
|
|
175
|
+
const reject = (retry_after) => {
|
|
176
|
+
const error = jsonrpc_error_response(id, jsonrpc_error_messages.rate_limited('rate limited', { retry_after }));
|
|
177
|
+
return c.json(error, jsonrpc_error_code_to_http_status(JSONRPC_ERROR_CODES.rate_limited));
|
|
178
|
+
};
|
|
179
|
+
if (ip_check) {
|
|
180
|
+
const result = action_ip_rate_limiter.check(client_ip);
|
|
181
|
+
if (!result.allowed)
|
|
182
|
+
return reject(result.retry_after);
|
|
183
|
+
}
|
|
184
|
+
if (account_check) {
|
|
185
|
+
const result = action_account_rate_limiter.check(request_context.actor.id);
|
|
186
|
+
if (!result.allowed)
|
|
187
|
+
return reject(result.retry_after);
|
|
188
|
+
}
|
|
189
|
+
if (ip_check)
|
|
190
|
+
action_ip_rate_limiter.record(client_ip);
|
|
191
|
+
if (account_check)
|
|
192
|
+
action_account_rate_limiter.record(request_context.actor.id);
|
|
193
|
+
}
|
|
168
194
|
// step 4: validate params
|
|
169
195
|
// Missing `params` on the envelope maps to `undefined` for `z.void()`
|
|
170
196
|
// input schemas and `{}` for object inputs (matches HTTP's "empty
|
|
@@ -191,7 +217,6 @@ export const create_rpc_endpoint = (options) => {
|
|
|
191
217
|
}
|
|
192
218
|
};
|
|
193
219
|
const signal = c.req.raw.signal;
|
|
194
|
-
const client_ip = get_client_ip(c);
|
|
195
220
|
const execute = async (db) => {
|
|
196
221
|
const action_context = {
|
|
197
222
|
auth: request_context,
|