@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
|
@@ -25,8 +25,10 @@ import { create_app_surface_spec, } from '../http/surface.js';
|
|
|
25
25
|
import { apply_middleware_specs, apply_route_specs, prefix_route_specs, } from '../http/route_spec.js';
|
|
26
26
|
import { check_bootstrap_status, create_bootstrap_route_specs, } from '../auth/bootstrap_routes.js';
|
|
27
27
|
import { create_surface_route_spec } from '../http/common_routes.js';
|
|
28
|
+
import { flush_pending_effects, flush_post_commit_effects } from '../http/pending_effects.js';
|
|
28
29
|
import { create_auth_middleware_specs } from '../auth/middleware.js';
|
|
29
|
-
import { fuz_auth_guard_resolver } from '../auth/
|
|
30
|
+
import { fuz_auth_guard_resolver } from '../auth/auth_guard_resolver.js';
|
|
31
|
+
import { create_fuz_authorization_handler } from '../auth/request_context.js';
|
|
30
32
|
import { ERROR_PAYLOAD_TOO_LARGE } from '../http/error_schemas.js';
|
|
31
33
|
import { create_rpc_endpoint } from '../actions/action_rpc.js';
|
|
32
34
|
/** Default maximum request body size: 1 MiB. */
|
|
@@ -39,15 +41,15 @@ export const DEFAULT_MAX_BODY_SIZE = 1024 * 1024;
|
|
|
39
41
|
* static serving. Database migrations belong to the backend lifecycle —
|
|
40
42
|
* pass `migration_namespaces` to `create_app_backend`.
|
|
41
43
|
*
|
|
42
|
-
* When `audit_log_sse` is set,
|
|
43
|
-
* `
|
|
44
|
-
* callback — `backend.deps` itself is not mutated.
|
|
44
|
+
* When `audit_log_sse` is set, the SSE registry's listener is appended to
|
|
45
|
+
* `backend.deps.audit.on_event_chain` — no shallow-copy of `AppDeps`.
|
|
45
46
|
*
|
|
46
47
|
* @returns assembled Hono app, backend, surface build, and bootstrap status
|
|
47
48
|
*/
|
|
48
49
|
export const create_app_server = async (options) => {
|
|
49
50
|
const { backend } = options;
|
|
50
|
-
const {
|
|
51
|
+
const { deps } = backend;
|
|
52
|
+
const { log } = deps;
|
|
51
53
|
// Rate limiter defaults (undefined = default, null = disable)
|
|
52
54
|
const ip_rate_limiter = options.ip_rate_limiter === undefined ? create_rate_limiter() : options.ip_rate_limiter;
|
|
53
55
|
const login_account_rate_limiter = options.login_account_rate_limiter === undefined
|
|
@@ -65,22 +67,18 @@ export const create_app_server = async (options) => {
|
|
|
65
67
|
const action_account_rate_limiter = options.action_account_rate_limiter === undefined
|
|
66
68
|
? create_rate_limiter(DEFAULT_ACTION_ACCOUNT_RATE_LIMIT)
|
|
67
69
|
: options.action_account_rate_limiter;
|
|
68
|
-
// Factory-managed audit SSE
|
|
70
|
+
// Factory-managed audit SSE — appends a listener to the bound emitter's
|
|
71
|
+
// chain so SSE fan-out runs alongside the consumer's `on_audit_event`
|
|
72
|
+
// without rebuilding `AppDeps`.
|
|
69
73
|
const audit_sse = options.audit_log_sse
|
|
70
74
|
? create_audit_log_sse({
|
|
71
75
|
log,
|
|
72
76
|
role: typeof options.audit_log_sse === 'object' ? options.audit_log_sse.role : undefined,
|
|
73
77
|
})
|
|
74
78
|
: null;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
on_audit_event: (event) => {
|
|
79
|
-
audit_sse.on_audit_event(event);
|
|
80
|
-
backend.deps.on_audit_event(event);
|
|
81
|
-
},
|
|
82
|
-
}
|
|
83
|
-
: backend.deps;
|
|
79
|
+
if (audit_sse) {
|
|
80
|
+
deps.audit.on_event_chain.push(audit_sse.on_audit_event);
|
|
81
|
+
}
|
|
84
82
|
// Proxy middleware
|
|
85
83
|
const proxy_spec = create_proxy_middleware_spec({ ...options.proxy, log });
|
|
86
84
|
// Auth middleware
|
|
@@ -215,31 +213,37 @@ export const create_app_server = async (options) => {
|
|
|
215
213
|
log_startup_summary(surface_spec.surface, log, options.env_values);
|
|
216
214
|
// Hono app assembly
|
|
217
215
|
const app = new Hono();
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
216
|
+
// Two-queue side-effect flush. `pending_effects` collects eager
|
|
217
|
+
// fire-and-forget promises (audit emits, session touch, api-token
|
|
218
|
+
// usage). `post_commit_effects` collects deferred thunks pushed via
|
|
219
|
+
// `emit_after_commit` (WS notifications, anything that must observe a
|
|
220
|
+
// committed transaction). Both queues drain here, after the handler
|
|
221
|
+
// (and any wrapping `db.transaction`) returns. In test mode both are
|
|
222
|
+
// awaited before the response returns; in production, eager-queue
|
|
223
|
+
// rejections are reported via `on_effect_error`.
|
|
221
224
|
app.use('*', async (c, next) => {
|
|
222
225
|
c.set('pending_effects', []);
|
|
226
|
+
c.set('post_commit_effects', []);
|
|
223
227
|
try {
|
|
224
228
|
await next();
|
|
225
229
|
}
|
|
226
230
|
finally {
|
|
227
|
-
const
|
|
228
|
-
|
|
231
|
+
const eager = c.var.pending_effects;
|
|
232
|
+
const deferred = c.var.post_commit_effects;
|
|
233
|
+
if (eager.length || deferred.length) {
|
|
229
234
|
if (options.await_pending_effects) {
|
|
230
|
-
await
|
|
235
|
+
await flush_pending_effects(eager, log);
|
|
236
|
+
await flush_post_commit_effects(deferred, log);
|
|
231
237
|
}
|
|
232
238
|
else {
|
|
233
|
-
const
|
|
239
|
+
const error_ctx = { method: c.req.method, path: c.req.path };
|
|
234
240
|
const callback = options.on_effect_error;
|
|
235
|
-
void
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
});
|
|
241
|
+
void flush_pending_effects(eager, log, callback ? (reason) => callback(reason, error_ctx) : undefined);
|
|
242
|
+
// `flush_post_commit_effects` is non-throwing: per-thunk
|
|
243
|
+
// errors are routed through `log.error` inside the helper,
|
|
244
|
+
// so production fire-and-forget skips the `on_effect_error`
|
|
245
|
+
// fan-out (deferred thunks are wrapped end-to-end already).
|
|
246
|
+
void flush_post_commit_effects(deferred, log);
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
}
|
|
@@ -257,7 +261,8 @@ export const create_app_server = async (options) => {
|
|
|
257
261
|
}));
|
|
258
262
|
}
|
|
259
263
|
apply_middleware_specs(app, middleware_specs);
|
|
260
|
-
|
|
264
|
+
const authorize = create_fuz_authorization_handler({ db: deps.db });
|
|
265
|
+
apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db, authorize);
|
|
261
266
|
// Post-route middleware (before static serving)
|
|
262
267
|
if (options.post_route_middleware) {
|
|
263
268
|
apply_middleware_specs(app, options.post_route_middleware);
|
|
@@ -24,7 +24,7 @@ export interface NginxValidationResult {
|
|
|
24
24
|
*
|
|
25
25
|
* Checks for required security headers, Authorization stripping in `/api`
|
|
26
26
|
* blocks, and the nginx `add_header` inheritance gotcha. Designed for
|
|
27
|
-
* fuz_app consumer deploy configs (
|
|
27
|
+
* fuz_app consumer deploy configs (zap.ts `NGINX_CONFIG` constants).
|
|
28
28
|
*
|
|
29
29
|
* Limitations: string pattern matching, not a real nginx parser. Catches
|
|
30
30
|
* common omissions in fuz_app deploy configs but won't catch all possible
|
|
@@ -92,7 +92,7 @@ const location_matches_api = (block) => {
|
|
|
92
92
|
*
|
|
93
93
|
* Checks for required security headers, Authorization stripping in `/api`
|
|
94
94
|
* blocks, and the nginx `add_header` inheritance gotcha. Designed for
|
|
95
|
-
* fuz_app consumer deploy configs (
|
|
95
|
+
* fuz_app consumer deploy configs (zap.ts `NGINX_CONFIG` constants).
|
|
96
96
|
*
|
|
97
97
|
* Limitations: string pattern matching, not a real nginx parser. Catches
|
|
98
98
|
* common omissions in fuz_app deploy configs but won't catch all possible
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -36,8 +36,10 @@ module load.
|
|
|
36
36
|
| `create_stub_db()` | Returns a real `Db` whose `client.query` yields `{rows: []}` and whose `transaction(fn)` synchronously calls `fn(inner_stub_db)`. Safe for `apply_route_specs`'s declarative transaction wrapper. |
|
|
37
37
|
| `stub_handler()` | Returns a fresh `Response('stub')`. |
|
|
38
38
|
| `stub_mw` | Pass-through middleware handler (`async (_c, next) => next()`). |
|
|
39
|
-
| `stub_app_deps` | Frozen `AppDeps` — every capability is a throwing stub, `
|
|
40
|
-
| `create_stub_app_deps()` | Factory returning fresh `AppDeps` with no-op FS/keyring/password, a `create_noop_stub` DB, silent `Logger`.
|
|
39
|
+
| `stub_app_deps` | Frozen `AppDeps` — every capability is a throwing stub, `audit` is a no-op `AuditEmitter` from `create_test_audit_emitter`. |
|
|
40
|
+
| `create_stub_app_deps()` | Factory returning fresh `AppDeps` with no-op FS/keyring/password, a `create_noop_stub` DB, silent `Logger`, no-op `audit`. |
|
|
41
|
+
| `create_test_audit_emitter()` | No-op `AuditEmitter` for tests that don't assert on audit fan-out. `emit` / `emit_role_grant_target` are no-ops; `emit_pool` resolves immediately; `notify` is a no-op; `on_event_chain` is empty. |
|
|
42
|
+
| `create_stub_audit_sse()` | No-op `AuditLogSse` for surface-test wiring without booting real SSE. `subscribe` returns a no-op cleanup; `on_audit_event` is a no-op; the `registry` is a fresh `SubscriberRegistry` (live `.size` / `.close_*` for tests touching registry state, isolated per call). For real SSE plumbing, build via `create_audit_log_sse` against `create_test_app`. |
|
|
41
43
|
| `create_stub_api_middleware({include_daemon_token?})` | Stub `MiddlewareSpec[]` matching `create_auth_middleware_specs`'s output (origin/session/request_context/bearer_auth, optional daemon_token) for surface generation without booting real auth. See `../auth/CLAUDE.md` §Middleware for the real stack. |
|
|
42
44
|
| `create_stub_app_server_context(session_options)` | Stub `AppServerContext` — rate limiters null, `bootstrap_status.available: false`, `app_settings.open_signup: false`. |
|
|
43
45
|
| `create_test_app_surface_spec(options)` | Builds an `AppSurfaceSpec` that mirrors `create_app_server`'s route assembly: consumer routes + factory-managed bootstrap routes (prefixed via `bootstrap_route_prefix`, default `'/api/account'`) + stub middleware + surface generation. `CreateTestAppSurfaceSpecOptions` accepts `session_options`, `create_route_specs`, `env_schema?`, `event_specs?`, `rpc_endpoints?`, `transform_middleware?`, `bootstrap_route_prefix?`. Single source of truth for attack-surface tests — track `create_app_server` wiring changes here. |
|
|
@@ -58,14 +60,14 @@ factories.
|
|
|
58
60
|
Override types widen branded `Uuid` fields to `string` so tests pass
|
|
59
61
|
literal ids without per-site casts — the factory brands internally.
|
|
60
62
|
Exported as `TestAccountOverrides` / `TestActorOverrides` /
|
|
61
|
-
`
|
|
63
|
+
`TestRoleGrantOverrides` / `TestAuditEventOverrides`.
|
|
62
64
|
|
|
63
65
|
| Factory | Default id / role |
|
|
64
66
|
| ------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
65
67
|
| `create_test_account(overrides?)` | `{id: 'acct-test', username: 'test_user', …}` |
|
|
66
68
|
| `create_test_actor(overrides?)` | `{id: 'actor-test', account_id: 'acct-test', …}` |
|
|
67
|
-
| `
|
|
68
|
-
| `create_test_context(
|
|
69
|
+
| `create_test_role_grant(overrides?)` | `{id: 'role-grant-test', actor_id: 'actor-test', role: 'admin', scope_id: null, …}` |
|
|
70
|
+
| `create_test_context(role_grants?)` | `{account, actor, role_grants}` — pass `[{role: 'keeper'}, {role: 'admin'}]` for multi-role. |
|
|
69
71
|
| `create_test_audit_event(overrides?)` | `{id: 'evt-test', event_type: 'login', outcome: 'success', …}` — for SSE guard / audit tests. |
|
|
70
72
|
|
|
71
73
|
### `mock_fs.ts` — in-memory filesystem
|
|
@@ -75,6 +77,17 @@ Missing-path reads throw an `Error` with `.code = 'ENOENT'` so callers
|
|
|
75
77
|
exercise the same branches as `node:fs`. Use for DI-based filesystem
|
|
76
78
|
tests; never replaces `node:fs` globally.
|
|
77
79
|
|
|
80
|
+
### `db_entities.ts` — DB-backed entity factories
|
|
81
|
+
|
|
82
|
+
`create_test_account_with_actor(db, {username, password_hash?})` wraps
|
|
83
|
+
`query_create_account_with_actor` with a default `password_hash` (`'hash'`).
|
|
84
|
+
Returns `{account, actor}`. Replaces the per-file `create_user` /
|
|
85
|
+
`create_test_actor` / `create_test_account` helpers that had accumulated
|
|
86
|
+
across the auth test suite. Use for query-level tests that need real
|
|
87
|
+
DB rows but not a full session/token bundle. For tests that also need
|
|
88
|
+
an API token + session cookie + role_grants, use `bootstrap_test_account`
|
|
89
|
+
from `app_server.ts` instead.
|
|
90
|
+
|
|
78
91
|
## Database — `db.ts`
|
|
79
92
|
|
|
80
93
|
Factory builders for parameterized DB tests. Consumer projects pass their
|
|
@@ -88,7 +101,7 @@ factories accept any migration namespace set.
|
|
|
88
101
|
| `reset_pglite(db)` | `DROP SCHEMA public CASCADE` + recreate. Reuses a live PGlite instance. |
|
|
89
102
|
| `create_pglite_factory(init_schema)` | In-memory; no external deps; `skip: false`. See WASM caching below. |
|
|
90
103
|
| `create_pg_factory(init_schema, test_url?)` | PostgreSQL; `skip: true` when `test_url` is missing; drops `schema_version` before `init_schema` so migrations re-evaluate against actual tables (prevents stale tracker rows from skipping migrations when DDL changes between test sessions); pool is reused + cleaned up across `create()` calls. |
|
|
91
|
-
| `AUTH_TRUNCATE_TABLES` | `['invite', 'api_token', 'auth_session', '
|
|
104
|
+
| `AUTH_TRUNCATE_TABLES` | `['invite', 'api_token', 'auth_session', 'role_grant', 'role_grant_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it. |
|
|
92
105
|
| `AUTH_INTEGRATION_TRUNCATE_TABLES` | `AUTH_TRUNCATE_TABLES + ['audit_log']` — for integration suites that exercise the audit path. |
|
|
93
106
|
| `AUTH_DROP_TABLES` | Full set from `AUTH_MIGRATIONS` in drop order; call `drop_auth_schema(db)` at the top of `init_schema` on persistent pg databases that may hold stale DDL from previous fuz_app versions. |
|
|
94
107
|
| `drop_auth_schema(db)` | `DROP TABLE IF EXISTS <table> CASCADE` for every entry in `AUTH_DROP_TABLES` plus `schema_version`. Safe on fresh DBs. |
|
|
@@ -157,16 +170,20 @@ bind to the server's deps (db, keyring). Hono assembly is cheap
|
|
|
157
170
|
|
|
158
171
|
Pre-built Hono apps at each auth level (public / authed / keeper / per-role)
|
|
159
172
|
for attack-surface testing. No middleware stack — a single `/*` middleware
|
|
160
|
-
injects
|
|
161
|
-
`'session'`)
|
|
162
|
-
|
|
173
|
+
injects `ACCOUNT_ID_KEY` + `REQUEST_CONTEXT_KEY` + `CREDENTIAL_TYPE_KEY`
|
|
174
|
+
(default `'session'`) plus the `TEST_CONTEXT_PRESET_KEY` flag (so the
|
|
175
|
+
dispatcher's authorization phase trusts the pre-baked context and skips
|
|
176
|
+
its DB-backed actor resolution), then hands off to `apply_route_specs`
|
|
177
|
+
with `fuz_auth_guard_resolver` + `create_fuz_authorization_handler`.
|
|
178
|
+
Production middleware never sets `TEST_CONTEXT_PRESET_KEY`, so the escape
|
|
179
|
+
hatch is test-only by construction.
|
|
163
180
|
|
|
164
181
|
| Helper | Role |
|
|
165
182
|
| ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
166
|
-
| `create_test_request_context(role?)` | Minimal `RequestContext` — one account, one actor, one
|
|
183
|
+
| `create_test_request_context(role?)` | Minimal `RequestContext` — one account, one actor, one role_grant for `role` (or none). |
|
|
167
184
|
| `create_test_app_from_specs(specs, auth_ctx?, credential_type?)` | Hono app with pre-set context + `apply_route_specs`. `credential_type` defaults to `'session'` when an auth context is supplied — override for `'daemon_token'` / `'api_token'` tests. |
|
|
168
185
|
| `AuthTestApps` | `{public, authed, keeper, by_role: Map<string, Hono>}`. |
|
|
169
|
-
| `create_auth_test_apps(specs, roles)` | Builds one app per auth level. Keeper app uses `credential_type: 'daemon_token'` so `
|
|
186
|
+
| `create_auth_test_apps(specs, roles)` | Builds one app per auth level. Keeper app uses `credential_type: 'daemon_token'` so `require_credential_types(['daemon_token'])` passes. |
|
|
170
187
|
| `select_auth_app(apps, auth)` | Map `RouteAuth` → matching Hono app. Throws for missing `role:*` entries. |
|
|
171
188
|
| `resolve_test_path(path)` | `:foo` → `test_foo` — adequate for routes without format-constrained params. |
|
|
172
189
|
|
|
@@ -297,20 +314,20 @@ Walks Zod schemas to generate valid values for adversarial/round-trip tests.
|
|
|
297
314
|
|
|
298
315
|
### `integration_helpers.ts` — route lookup + body checks
|
|
299
316
|
|
|
300
|
-
| Helper | Role
|
|
301
|
-
| ------------------------------------------------------------------ |
|
|
302
|
-
| `find_route_spec(specs, method, path)` | Exact match then parameterized match (`:foo` matches any segment).
|
|
303
|
-
| `find_auth_route(specs, suffix, method)` | Suffix-ending match for REST auth routes — decouples tests from consumer prefix. `suffix` is typed as `RestAuthRouteSuffix` and throws at runtime on unknown values (
|
|
304
|
-
| `assert_response_matches_spec(specs, method, path, response)` | 2xx → validates against `spec.output`; non-2xx → validates against merged error schemas for that status. Non-JSON responses allowed only when no schema applies.
|
|
305
|
-
| `create_expired_test_cookie(keyring, session_options)` | Validly signed cookie with `expires_at` in 1970.
|
|
306
|
-
| `check_error_response_fields(body)` | Returns the list of fields outside `KNOWN_SAFE_ERROR_FIELDS` (`error`, `issues`, `
|
|
307
|
-
| `assert_no_error_info_leakage(body, context)` | Rejects field-name patterns (`stack`, `trace`, `sql`, …) + value patterns (`node_modules`, stack-like `at …`, `.ts:NN`).
|
|
308
|
-
| `assert_rate_limit_retry_after_header(response, body)` | `Retry-After` numeric header equals `Math.ceil(body.retry_after)`.
|
|
309
|
-
| `SENSITIVE_FIELD_BLOCKLIST` | `['password_hash', 'token_hash']` — never in any response body.
|
|
310
|
-
| `ADMIN_ONLY_FIELD_BLOCKLIST` | `['updated_by', 'created_by']` — never in non-admin response bodies.
|
|
311
|
-
| `collect_json_keys_recursive(value)` | Deep walk; returns `Set<string>` of every key at every nesting depth.
|
|
312
|
-
| `assert_no_sensitive_fields_in_json(body, blocklist, context)` | Rejects any key in the blocklist at any depth.
|
|
313
|
-
| `pick_auth_headers(spec, test_app, authed_account, admin_account)` | `RouteAuth` → appropriate test credentials; role `admin` uses `admin_account`, other roles use bootstrapped keeper, `keeper` uses daemon token.
|
|
317
|
+
| Helper | Role |
|
|
318
|
+
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
319
|
+
| `find_route_spec(specs, method, path)` | Exact match then parameterized match (`:foo` matches any segment). |
|
|
320
|
+
| `find_auth_route(specs, suffix, method)` | Suffix-ending match for REST auth routes — decouples tests from consumer prefix. `suffix` is typed as `RestAuthRouteSuffix` and throws at runtime on unknown values (only login/logout/password/verify/signup/bootstrap remain on REST). |
|
|
321
|
+
| `assert_response_matches_spec(specs, method, path, response)` | 2xx → validates against `spec.output`; non-2xx → validates against merged error schemas for that status. Non-JSON responses allowed only when no schema applies. |
|
|
322
|
+
| `create_expired_test_cookie(keyring, session_options)` | Validly signed cookie with `expires_at` in 1970. |
|
|
323
|
+
| `check_error_response_fields(body)` | Returns the list of fields outside `KNOWN_SAFE_ERROR_FIELDS` (`error`, `issues`, `required_roles`, `required_credential_types`, `retry_after`, `has_references`, `ok`). |
|
|
324
|
+
| `assert_no_error_info_leakage(body, context)` | Rejects field-name patterns (`stack`, `trace`, `sql`, …) + value patterns (`node_modules`, stack-like `at …`, `.ts:NN`). |
|
|
325
|
+
| `assert_rate_limit_retry_after_header(response, body)` | `Retry-After` numeric header equals `Math.ceil(body.retry_after)`. |
|
|
326
|
+
| `SENSITIVE_FIELD_BLOCKLIST` | `['password_hash', 'token_hash']` — never in any response body. |
|
|
327
|
+
| `ADMIN_ONLY_FIELD_BLOCKLIST` | `['updated_by', 'created_by']` — never in non-admin response bodies. |
|
|
328
|
+
| `collect_json_keys_recursive(value)` | Deep walk; returns `Set<string>` of every key at every nesting depth. |
|
|
329
|
+
| `assert_no_sensitive_fields_in_json(body, blocklist, context)` | Rejects any key in the blocklist at any depth. |
|
|
330
|
+
| `pick_auth_headers(spec, test_app, authed_account, admin_account)` | `RouteAuth` → appropriate test credentials; role `admin` uses `admin_account`, other roles use bootstrapped keeper, `keeper` uses daemon token. |
|
|
314
331
|
|
|
315
332
|
## Attack surface suites
|
|
316
333
|
|
|
@@ -383,28 +400,30 @@ validation. Extra cases append to the standard list.
|
|
|
383
400
|
## Middleware stack — `middleware.ts`
|
|
384
401
|
|
|
385
402
|
Module-level `vi.mock()` for the four query modules bearer auth touches:
|
|
386
|
-
`api_token_queries`, `account_queries`, `
|
|
403
|
+
`api_token_queries`, `account_queries`, `role_grant_queries`. Because
|
|
387
404
|
`vi.mock()` is hoisted, these run before any imports resolve — so any
|
|
388
405
|
test file that imports from `middleware.ts` gets these mocks globally.
|
|
389
406
|
Pair with `vi.restoreAllMocks()` in `afterEach` when mixing into
|
|
390
407
|
`.db.test.ts` files (see DB test caveat below).
|
|
391
408
|
|
|
392
|
-
| Helper | Role
|
|
393
|
-
| ----------------------------------------------------------------- |
|
|
394
|
-
| `BearerAuthTestOptions`, `BearerAuthTestCase` | Test-case table shape for the bearer auth runner.
|
|
395
|
-
| `create_bearer_auth_mocks(tc)` | Configures the module-level mocks per test case; returns spy references.
|
|
396
|
-
| `TEST_CLIENT_IP = '127.0.0.1'` | IP set by the proxy stub in `create_bearer_auth_test_app`.
|
|
397
|
-
| `create_bearer_auth_test_app(tc, ip_rate_limiter?)` | Hono app with bearer middleware + echo route at `/api/test` returning `{ok,
|
|
398
|
-
| `describe_bearer_auth_cases(suite_name, cases, ip_rate_limiter?)` | Table-driven runner — one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation.
|
|
399
|
-
| `TEST_MIDDLEWARE_PATH = '/api/test'` | Path used by the echo route in the stack factory.
|
|
400
|
-
| `create_test_middleware_stack_app(options?)` | Real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`.
|
|
409
|
+
| Helper | Role |
|
|
410
|
+
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
411
|
+
| `BearerAuthTestOptions`, `BearerAuthTestCase` | Test-case table shape for the bearer auth runner. |
|
|
412
|
+
| `create_bearer_auth_mocks(tc)` | Configures the module-level mocks per test case; returns spy references. |
|
|
413
|
+
| `TEST_CLIENT_IP = '127.0.0.1'` | IP set by the proxy stub in `create_bearer_auth_test_app`. |
|
|
414
|
+
| `create_bearer_auth_test_app(tc, ip_rate_limiter?)` | Hono app with bearer middleware + echo route at `/api/test` returning `{ok, account_id, credential_type, api_token_id, request_context_set}` — the account-grain identity bearer auth writes, plus a flag for tests that pre-populate `REQUEST_CONTEXT_KEY` via `pre_context`. |
|
|
415
|
+
| `describe_bearer_auth_cases(suite_name, cases, ip_rate_limiter?)` | Table-driven runner — one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation. |
|
|
416
|
+
| `TEST_MIDDLEWARE_PATH = '/api/test'` | Path used by the echo route in the stack factory. |
|
|
417
|
+
| `create_test_middleware_stack_app(options?)` | Real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`. |
|
|
401
418
|
|
|
402
419
|
The echo route under `create_bearer_auth_test_app` deliberately surfaces
|
|
403
|
-
every middleware-written context variable (`
|
|
404
|
-
`CREDENTIAL_TYPE_KEY`, `AUTH_API_TOKEN_ID_KEY`)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
420
|
+
every middleware-written context variable (`ACCOUNT_ID_KEY`,
|
|
421
|
+
`CREDENTIAL_TYPE_KEY`, `AUTH_API_TOKEN_ID_KEY`) — bearer middleware
|
|
422
|
+
writes account-grain identity only; the dispatcher's authorization phase
|
|
423
|
+
owns `REQUEST_CONTEXT_KEY`. The `request_context_set` flag covers the
|
|
424
|
+
test-only `pre_context` injection path. When public auth surface gains a
|
|
425
|
+
new context variable, header, or field, update this echo alongside the
|
|
426
|
+
assertions in `src/test/auth/*.test.ts` — the two move together.
|
|
408
427
|
|
|
409
428
|
## Round-trip suites
|
|
410
429
|
|
|
@@ -464,7 +483,7 @@ Three layers:
|
|
|
464
483
|
1. **Primitives** — `create_fake_ws()`, `create_fake_hono_context(opts)`,
|
|
465
484
|
`create_stub_upgrade()`, `MinimalActionEnvironment`,
|
|
466
485
|
`dispatch_ws_message(on_message, event, ws)`.
|
|
467
|
-
2. **Harness** — `create_ws_test_harness
|
|
486
|
+
2. **Harness** — `create_ws_test_harness({actions, transport?, heartbeat?, log?, on_socket_open?, on_socket_close?})` → `WsTestHarness`. `connect(identity?)` is async and resolves after `on_socket_open` completes, so broadcasts sent immediately after `await harness.connect()` reach the client. The harness threads its own `create_stub_db()` into the dispatcher's `db` slot so handlers declaring `side_effects: true` execute under the same transaction wrap they would in production (the stub's `transaction(fn)` synchronously calls `fn(stub_db)`); domain deps reach handlers via factory closures, the same way HTTP RPC factories already wire them. Audit fan-out runs through whatever `audit` emitter the consumer supplied to its action factory closure (typically `create_test_audit_emitter()` for unit harnesses).
|
|
468
487
|
3. **Round-trip helpers** — `is_notification(method)`,
|
|
469
488
|
`is_notification_with<P>(method, match)` (type-guard combinator —
|
|
470
489
|
narrows `wait_for` return type), `is_response_for(id)`.
|
|
@@ -551,9 +570,9 @@ Options: `{session_options, create_route_specs, app_options?, db_factories?}`.
|
|
|
551
570
|
|
|
552
571
|
### `admin_integration.ts` — `describe_standard_admin_integration_tests`
|
|
553
572
|
|
|
554
|
-
7 test groups covering admin surface: account listing,
|
|
555
|
-
lifecycle (via `
|
|
556
|
-
**not** REST; see `../auth/CLAUDE.md` for `
|
|
573
|
+
7 test groups covering admin surface: account listing, role_grant grant
|
|
574
|
+
lifecycle (via `role_grant_offer_create` + `role_grant_revoke` RPC flows —
|
|
575
|
+
**not** REST; see `../auth/CLAUDE.md` for `role_grant_offer_action_specs.ts` + `role_grant_offer_actions.ts`), session / token management, audit log reads (RPC),
|
|
557
576
|
admin-to-admin isolation, error coverage, response schema validation.
|
|
558
577
|
|
|
559
578
|
Required options: `{session_options, create_route_specs, roles: RoleSchemaResult, rpc_endpoints: RpcEndpointsSuiteOption, admin_prefix?, app_options?, db_factories?}`.
|
|
@@ -571,22 +590,21 @@ once with a stub ctx for path lookup and `create_app_server` invokes it
|
|
|
571
590
|
again per-test for live dispatch.
|
|
572
591
|
|
|
573
592
|
**Hard-fails via `require_rpc_endpoint_path`** at setup time when
|
|
574
|
-
`rpc_endpoints` is empty — admin
|
|
575
|
-
revoke-all plus audit-log list/history are
|
|
576
|
-
|
|
577
|
-
clear setup error.
|
|
593
|
+
`rpc_endpoints` is empty — admin role_grant grant/revoke plus session/token
|
|
594
|
+
revoke-all plus audit-log list/history are RPC-only. A confusing test
|
|
595
|
+
failure mid-suite is worse than a clear setup error.
|
|
578
596
|
|
|
579
597
|
The suite also exercises `account_token_create` (and
|
|
580
598
|
`account_token_revoke`) for the cross-admin isolation + audit-trail
|
|
581
|
-
scenarios. Wire the account actions alongside admin /
|
|
599
|
+
scenarios. Wire the account actions alongside admin / role-grant-offer —
|
|
582
600
|
the easiest path is `create_standard_rpc_actions`, which bundles all
|
|
583
601
|
three. Consumers that only wire admin will hit `method not found:
|
|
584
602
|
account_token_create` on first run.
|
|
585
603
|
|
|
586
604
|
Error-coverage scope is narrowed to the REST suffixes still on the
|
|
587
605
|
admin surface (`/audit/stream`); the RPC surface is covered by
|
|
588
|
-
`describe_rpc_round_trip_tests`.
|
|
589
|
-
|
|
606
|
+
`describe_rpc_round_trip_tests`. The scoped REST surface is 0–1
|
|
607
|
+
routes — when the scoped count is ≤1, the `afterAll` hook logs
|
|
590
608
|
`[error coverage] skipped admin REST coverage assertion — …` and
|
|
591
609
|
does not fail. The 20% `DEFAULT_INTEGRATION_ERROR_COVERAGE` baseline
|
|
592
610
|
is a REST-era threshold; the RPC surface has its own coverage via
|
|
@@ -599,9 +617,9 @@ branch.
|
|
|
599
617
|
Verifies every auth mutation produces the expected `audit_log` row by
|
|
600
618
|
querying the table after each request. Uses the real middleware stack.
|
|
601
619
|
Same `rpc_endpoints` hard-fail as the admin suite — the mutation-audit
|
|
602
|
-
tests drive
|
|
603
|
-
create/delete through `
|
|
604
|
-
`
|
|
620
|
+
tests drive role_grant flow, session/token revoke-all, and invite
|
|
621
|
+
create/delete through `role_grant_offer_create_action_spec` /
|
|
622
|
+
`role_grant_revoke_action_spec` / `admin_session_revoke_all_action_spec` /
|
|
605
623
|
`admin_token_revoke_all_action_spec` / `app_settings_update_action_spec` /
|
|
606
624
|
`invite_create_action_spec` / `invite_delete_action_spec`.
|
|
607
625
|
|
|
@@ -670,7 +688,7 @@ Registry lookups:
|
|
|
670
688
|
- unauthenticated → `unauthenticated` (code -32001)
|
|
671
689
|
- wrong role → `forbidden` (-32002)
|
|
672
690
|
- authenticated without role → `forbidden`
|
|
673
|
-
- **keeper rejects non-daemon credentials** — session and api_token credentials are rejected even when the account has the keeper role (only `daemon_token` passes).
|
|
691
|
+
- **keeper rejects non-daemon credentials** — session and api_token credentials are rejected even when the account has the keeper role (only `daemon_token` passes). The credential-type gate fires before the role gate (see `../auth/CLAUDE.md` §`request_context.ts` for `require_credential_types`).
|
|
674
692
|
- correct auth passes (not 401/403)
|
|
675
693
|
- GET unauthenticated for `side_effects: false` reads
|
|
676
694
|
2. **RPC adversarial envelopes** — fixed set exercising dispatcher steps 1–2: non-JSON body, wrong `jsonrpc` version, missing `jsonrpc` / `method` / `id`, batch array, unknown method, GET missing `method`/`id`, GET invalid JSON params, GET non-object params, GET mutation method → `invalid_request`.
|
|
@@ -17,7 +17,7 @@ export interface StandardAdminIntegrationTestOptions {
|
|
|
17
17
|
/** Role schema result from `create_role_schema()` — used to determine valid/invalid/web-grantable roles. */
|
|
18
18
|
roles: RoleSchemaResult;
|
|
19
19
|
/**
|
|
20
|
-
* RPC endpoint specs — the source `RpcAction` arrays. Required;
|
|
20
|
+
* RPC endpoint specs — the source `RpcAction` arrays. Required; role_grant
|
|
21
21
|
* grant/revoke are RPC-only and the suite hard-fails without them.
|
|
22
22
|
*
|
|
23
23
|
* Accepts either an array (eager) or a factory
|
|
@@ -48,17 +48,16 @@ export interface StandardAdminIntegrationTestOptions {
|
|
|
48
48
|
/**
|
|
49
49
|
* Standard admin integration test suite for fuz_app admin routes.
|
|
50
50
|
*
|
|
51
|
-
* Exercises account listing,
|
|
51
|
+
* Exercises account listing, role_grant grant/revoke (via RPC), session
|
|
52
52
|
* management, token management, audit log reads, admin-to-admin
|
|
53
53
|
* isolation, and 401/403 error-coverage on the admin REST surface.
|
|
54
54
|
* Output-schema conformance is not in scope — see the module docstring
|
|
55
55
|
* for the suites that cover it.
|
|
56
56
|
*
|
|
57
57
|
* @throws Error at setup time when `options.rpc_endpoints` is empty — admin
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* than `method not found` mid-suite.
|
|
58
|
+
* role_grant grant/revoke, session/token revoke-all, and audit-log reads
|
|
59
|
+
* are RPC-only. Hard-fails via `require_rpc_endpoint_path` so consumers
|
|
60
|
+
* see a clear setup error rather than `method not found` mid-suite.
|
|
62
61
|
*/
|
|
63
62
|
export declare const describe_standard_admin_integration_tests: (options: StandardAdminIntegrationTestOptions) => void;
|
|
64
63
|
//# sourceMappingURL=admin_integration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAGtF,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAoB1B;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAmCD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IA+1BF,CAAC"}
|