@fuzdev/fuz_app 0.1.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/actions/action_bridge.d.ts +65 -0
- package/dist/actions/action_bridge.d.ts.map +1 -0
- package/dist/actions/action_bridge.js +76 -0
- package/dist/actions/action_codegen.d.ts +97 -0
- package/dist/actions/action_codegen.d.ts.map +1 -0
- package/dist/actions/action_codegen.js +280 -0
- package/dist/actions/action_registry.d.ts +35 -0
- package/dist/actions/action_registry.d.ts.map +1 -0
- package/dist/actions/action_registry.js +83 -0
- package/dist/actions/action_spec.d.ts +169 -0
- package/dist/actions/action_spec.d.ts.map +1 -0
- package/dist/actions/action_spec.js +76 -0
- package/dist/auth/account_queries.d.ts +96 -0
- package/dist/auth/account_queries.d.ts.map +1 -0
- package/dist/auth/account_queries.js +172 -0
- package/dist/auth/account_routes.d.ts +86 -0
- package/dist/auth/account_routes.d.ts.map +1 -0
- package/dist/auth/account_routes.js +406 -0
- package/dist/auth/account_schema.d.ts +192 -0
- package/dist/auth/account_schema.d.ts.map +1 -0
- package/dist/auth/account_schema.js +105 -0
- package/dist/auth/admin_routes.d.ts +29 -0
- package/dist/auth/admin_routes.d.ts.map +1 -0
- package/dist/auth/admin_routes.js +193 -0
- package/dist/auth/api_token.d.ts +33 -0
- package/dist/auth/api_token.d.ts.map +1 -0
- package/dist/auth/api_token.js +36 -0
- package/dist/auth/api_token_queries.d.ts +80 -0
- package/dist/auth/api_token_queries.d.ts.map +1 -0
- package/dist/auth/api_token_queries.js +116 -0
- package/dist/auth/app_settings_queries.d.ts +33 -0
- package/dist/auth/app_settings_queries.d.ts.map +1 -0
- package/dist/auth/app_settings_queries.js +51 -0
- package/dist/auth/app_settings_routes.d.ts +27 -0
- package/dist/auth/app_settings_routes.d.ts.map +1 -0
- package/dist/auth/app_settings_routes.js +66 -0
- package/dist/auth/app_settings_schema.d.ts +35 -0
- package/dist/auth/app_settings_schema.d.ts.map +1 -0
- package/dist/auth/app_settings_schema.js +22 -0
- package/dist/auth/audit_log_queries.d.ts +90 -0
- package/dist/auth/audit_log_queries.d.ts.map +1 -0
- package/dist/auth/audit_log_queries.js +205 -0
- package/dist/auth/audit_log_routes.d.ts +33 -0
- package/dist/auth/audit_log_routes.d.ts.map +1 -0
- package/dist/auth/audit_log_routes.js +106 -0
- package/dist/auth/audit_log_schema.d.ts +259 -0
- package/dist/auth/audit_log_schema.d.ts.map +1 -0
- package/dist/auth/audit_log_schema.js +123 -0
- package/dist/auth/bearer_auth.d.ts +32 -0
- package/dist/auth/bearer_auth.d.ts.map +1 -0
- package/dist/auth/bearer_auth.js +90 -0
- package/dist/auth/bootstrap_account.d.ts +82 -0
- package/dist/auth/bootstrap_account.d.ts.map +1 -0
- package/dist/auth/bootstrap_account.js +97 -0
- package/dist/auth/bootstrap_routes.d.ts +74 -0
- package/dist/auth/bootstrap_routes.d.ts.map +1 -0
- package/dist/auth/bootstrap_routes.js +154 -0
- package/dist/auth/daemon_token.d.ts +49 -0
- package/dist/auth/daemon_token.d.ts.map +1 -0
- package/dist/auth/daemon_token.js +49 -0
- package/dist/auth/daemon_token_middleware.d.ts +93 -0
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -0
- package/dist/auth/daemon_token_middleware.js +167 -0
- package/dist/auth/ddl.d.ts +27 -0
- package/dist/auth/ddl.d.ts.map +1 -0
- package/dist/auth/ddl.js +111 -0
- package/dist/auth/deps.d.ts +52 -0
- package/dist/auth/deps.d.ts.map +1 -0
- package/dist/auth/deps.js +10 -0
- package/dist/auth/invite_queries.d.ts +68 -0
- package/dist/auth/invite_queries.d.ts.map +1 -0
- package/dist/auth/invite_queries.js +105 -0
- package/dist/auth/invite_routes.d.ts +18 -0
- package/dist/auth/invite_routes.d.ts.map +1 -0
- package/dist/auth/invite_routes.js +129 -0
- package/dist/auth/invite_schema.d.ts +51 -0
- package/dist/auth/invite_schema.d.ts.map +1 -0
- package/dist/auth/invite_schema.js +25 -0
- package/dist/auth/keyring.d.ts +87 -0
- package/dist/auth/keyring.d.ts.map +1 -0
- package/dist/auth/keyring.js +142 -0
- package/dist/auth/middleware.d.ts +40 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +64 -0
- package/dist/auth/migrations.d.ts +42 -0
- package/dist/auth/migrations.d.ts.map +1 -0
- package/dist/auth/migrations.js +79 -0
- package/dist/auth/password.d.ts +39 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +25 -0
- package/dist/auth/password_argon2.d.ts +43 -0
- package/dist/auth/password_argon2.d.ts.map +1 -0
- package/dist/auth/password_argon2.js +76 -0
- package/dist/auth/permit_queries.d.ts +72 -0
- package/dist/auth/permit_queries.d.ts.map +1 -0
- package/dist/auth/permit_queries.js +116 -0
- package/dist/auth/request_context.d.ts +114 -0
- package/dist/auth/request_context.d.ts.map +1 -0
- package/dist/auth/request_context.js +176 -0
- package/dist/auth/require_keeper.d.ts +20 -0
- package/dist/auth/require_keeper.d.ts.map +1 -0
- package/dist/auth/require_keeper.js +35 -0
- package/dist/auth/role_schema.d.ts +69 -0
- package/dist/auth/role_schema.d.ts.map +1 -0
- package/dist/auth/role_schema.js +70 -0
- package/dist/auth/route_guards.d.ts +21 -0
- package/dist/auth/route_guards.d.ts.map +1 -0
- package/dist/auth/route_guards.js +32 -0
- package/dist/auth/session_cookie.d.ts +158 -0
- package/dist/auth/session_cookie.d.ts.map +1 -0
- package/dist/auth/session_cookie.js +135 -0
- package/dist/auth/session_lifecycle.d.ts +35 -0
- package/dist/auth/session_lifecycle.d.ts.map +1 -0
- package/dist/auth/session_lifecycle.js +27 -0
- package/dist/auth/session_middleware.d.ts +33 -0
- package/dist/auth/session_middleware.d.ts.map +1 -0
- package/dist/auth/session_middleware.js +62 -0
- package/dist/auth/session_queries.d.ts +135 -0
- package/dist/auth/session_queries.d.ts.map +1 -0
- package/dist/auth/session_queries.js +186 -0
- package/dist/auth/signup_routes.d.ts +32 -0
- package/dist/auth/signup_routes.d.ts.map +1 -0
- package/dist/auth/signup_routes.js +150 -0
- package/dist/cli/args.d.ts +48 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +76 -0
- package/dist/cli/config.d.ts +48 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +77 -0
- package/dist/cli/daemon.d.ts +82 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +149 -0
- package/dist/cli/help.d.ts +85 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +138 -0
- package/dist/cli/logger.d.ts +46 -0
- package/dist/cli/logger.d.ts.map +1 -0
- package/dist/cli/logger.js +48 -0
- package/dist/cli/util.d.ts +36 -0
- package/dist/cli/util.d.ts.map +1 -0
- package/dist/cli/util.js +50 -0
- package/dist/crypto.d.ts +13 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +19 -0
- package/dist/db/assert_row.d.ts +18 -0
- package/dist/db/assert_row.d.ts.map +1 -0
- package/dist/db/assert_row.js +24 -0
- package/dist/db/create_db.d.ts +38 -0
- package/dist/db/create_db.d.ts.map +1 -0
- package/dist/db/create_db.js +57 -0
- package/dist/db/db.d.ts +97 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +76 -0
- package/dist/db/db_pg.d.ts +21 -0
- package/dist/db/db_pg.d.ts.map +1 -0
- package/dist/db/db_pg.js +45 -0
- package/dist/db/db_pglite.d.ts +21 -0
- package/dist/db/db_pglite.d.ts.map +1 -0
- package/dist/db/db_pglite.js +28 -0
- package/dist/db/migrate.d.ts +67 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +118 -0
- package/dist/db/pg_error.d.ts +16 -0
- package/dist/db/pg_error.d.ts.map +1 -0
- package/dist/db/pg_error.js +15 -0
- package/dist/db/query_deps.d.ts +14 -0
- package/dist/db/query_deps.d.ts.map +1 -0
- package/dist/db/query_deps.js +9 -0
- package/dist/db/sql_identifier.d.ts +27 -0
- package/dist/db/sql_identifier.d.ts.map +1 -0
- package/dist/db/sql_identifier.js +31 -0
- package/dist/db/status.d.ts +62 -0
- package/dist/db/status.d.ts.map +1 -0
- package/dist/db/status.js +116 -0
- package/dist/dev/setup.d.ts +159 -0
- package/dist/dev/setup.d.ts.map +1 -0
- package/dist/dev/setup.js +265 -0
- package/dist/env/dotenv.d.ts +25 -0
- package/dist/env/dotenv.d.ts.map +1 -0
- package/dist/env/dotenv.js +52 -0
- package/dist/env/load.d.ts +52 -0
- package/dist/env/load.d.ts.map +1 -0
- package/dist/env/load.js +79 -0
- package/dist/env/mask.d.ts +19 -0
- package/dist/env/mask.d.ts.map +1 -0
- package/dist/env/mask.js +26 -0
- package/dist/env/resolve.d.ts +126 -0
- package/dist/env/resolve.d.ts.map +1 -0
- package/dist/env/resolve.js +200 -0
- package/dist/hono_context.d.ts +48 -0
- package/dist/hono_context.d.ts.map +1 -0
- package/dist/hono_context.js +22 -0
- package/dist/http/common_routes.d.ts +52 -0
- package/dist/http/common_routes.d.ts.map +1 -0
- package/dist/http/common_routes.js +65 -0
- package/dist/http/db_routes.d.ts +57 -0
- package/dist/http/db_routes.d.ts.map +1 -0
- package/dist/http/db_routes.js +176 -0
- package/dist/http/error_schemas.d.ts +169 -0
- package/dist/http/error_schemas.d.ts.map +1 -0
- package/dist/http/error_schemas.js +178 -0
- package/dist/http/middleware_spec.d.ts +19 -0
- package/dist/http/middleware_spec.d.ts.map +1 -0
- package/dist/http/middleware_spec.js +9 -0
- package/dist/http/origin.d.ts +57 -0
- package/dist/http/origin.d.ts.map +1 -0
- package/dist/http/origin.js +207 -0
- package/dist/http/proxy.d.ts +112 -0
- package/dist/http/proxy.d.ts.map +1 -0
- package/dist/http/proxy.js +240 -0
- package/dist/http/route_spec.d.ts +197 -0
- package/dist/http/route_spec.d.ts.map +1 -0
- package/dist/http/route_spec.js +243 -0
- package/dist/http/schema_helpers.d.ts +64 -0
- package/dist/http/schema_helpers.d.ts.map +1 -0
- package/dist/http/schema_helpers.js +90 -0
- package/dist/http/surface.d.ts +132 -0
- package/dist/http/surface.d.ts.map +1 -0
- package/dist/http/surface.js +156 -0
- package/dist/http/surface_query.d.ts +77 -0
- package/dist/http/surface_query.d.ts.map +1 -0
- package/dist/http/surface_query.js +86 -0
- package/dist/rate_limiter.d.ts +94 -0
- package/dist/rate_limiter.d.ts.map +1 -0
- package/dist/rate_limiter.js +156 -0
- package/dist/realtime/sse.d.ts +80 -0
- package/dist/realtime/sse.d.ts.map +1 -0
- package/dist/realtime/sse.js +109 -0
- package/dist/realtime/sse_auth_guard.d.ts +93 -0
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -0
- package/dist/realtime/sse_auth_guard.js +111 -0
- package/dist/realtime/subscriber_registry.d.ts +85 -0
- package/dist/realtime/subscriber_registry.d.ts.map +1 -0
- package/dist/realtime/subscriber_registry.js +108 -0
- package/dist/runtime/deno.d.ts +21 -0
- package/dist/runtime/deno.d.ts.map +1 -0
- package/dist/runtime/deno.js +83 -0
- package/dist/runtime/deps.d.ts +113 -0
- package/dist/runtime/deps.d.ts.map +1 -0
- package/dist/runtime/deps.js +10 -0
- package/dist/runtime/fs.d.ts +15 -0
- package/dist/runtime/fs.d.ts.map +1 -0
- package/dist/runtime/fs.js +17 -0
- package/dist/runtime/mock.d.ts +81 -0
- package/dist/runtime/mock.d.ts.map +1 -0
- package/dist/runtime/mock.js +195 -0
- package/dist/runtime/node.d.ts +17 -0
- package/dist/runtime/node.d.ts.map +1 -0
- package/dist/runtime/node.js +117 -0
- package/dist/schema_meta.d.ts +16 -0
- package/dist/schema_meta.d.ts.map +1 -0
- package/dist/schema_meta.js +9 -0
- package/dist/sensitivity.d.ts +15 -0
- package/dist/sensitivity.d.ts.map +1 -0
- package/dist/sensitivity.js +9 -0
- package/dist/server/app_backend.d.ts +74 -0
- package/dist/server/app_backend.d.ts.map +1 -0
- package/dist/server/app_backend.js +39 -0
- package/dist/server/app_server.d.ts +201 -0
- package/dist/server/app_server.d.ts.map +1 -0
- package/dist/server/app_server.js +266 -0
- package/dist/server/env.d.ts +68 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +95 -0
- package/dist/server/startup.d.ts +22 -0
- package/dist/server/startup.d.ts.map +1 -0
- package/dist/server/startup.js +48 -0
- package/dist/server/static.d.ts +39 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +38 -0
- package/dist/server/validate_nginx.d.ts +34 -0
- package/dist/server/validate_nginx.d.ts.map +1 -0
- package/dist/server/validate_nginx.js +118 -0
- package/dist/testing/CLAUDE.md +3 -0
- package/dist/testing/admin_integration.d.ts +45 -0
- package/dist/testing/admin_integration.d.ts.map +1 -0
- package/dist/testing/admin_integration.js +840 -0
- package/dist/testing/adversarial_404.d.ts +15 -0
- package/dist/testing/adversarial_404.d.ts.map +1 -0
- package/dist/testing/adversarial_404.js +118 -0
- package/dist/testing/adversarial_headers.d.ts +36 -0
- package/dist/testing/adversarial_headers.d.ts.map +1 -0
- package/dist/testing/adversarial_headers.js +128 -0
- package/dist/testing/adversarial_input.d.ts +56 -0
- package/dist/testing/adversarial_input.d.ts.map +1 -0
- package/dist/testing/adversarial_input.js +494 -0
- package/dist/testing/app_server.d.ts +169 -0
- package/dist/testing/app_server.d.ts.map +1 -0
- package/dist/testing/app_server.js +240 -0
- package/dist/testing/assert_dev_env.d.ts +10 -0
- package/dist/testing/assert_dev_env.d.ts.map +1 -0
- package/dist/testing/assert_dev_env.js +13 -0
- package/dist/testing/assertions.d.ts +61 -0
- package/dist/testing/assertions.d.ts.map +1 -0
- package/dist/testing/assertions.js +96 -0
- package/dist/testing/attack_surface.d.ts +63 -0
- package/dist/testing/attack_surface.d.ts.map +1 -0
- package/dist/testing/attack_surface.js +224 -0
- package/dist/testing/audit_completeness.d.ts +29 -0
- package/dist/testing/audit_completeness.d.ts.map +1 -0
- package/dist/testing/audit_completeness.js +410 -0
- package/dist/testing/auth_apps.d.ts +55 -0
- package/dist/testing/auth_apps.d.ts.map +1 -0
- package/dist/testing/auth_apps.js +122 -0
- package/dist/testing/data_exposure.d.ts +62 -0
- package/dist/testing/data_exposure.d.ts.map +1 -0
- package/dist/testing/data_exposure.js +297 -0
- package/dist/testing/db.d.ts +111 -0
- package/dist/testing/db.d.ts.map +1 -0
- package/dist/testing/db.js +258 -0
- package/dist/testing/entities.d.ts +21 -0
- package/dist/testing/entities.d.ts.map +1 -0
- package/dist/testing/entities.js +42 -0
- package/dist/testing/error_coverage.d.ts +78 -0
- package/dist/testing/error_coverage.d.ts.map +1 -0
- package/dist/testing/error_coverage.js +135 -0
- package/dist/testing/integration.d.ts +37 -0
- package/dist/testing/integration.d.ts.map +1 -0
- package/dist/testing/integration.js +1139 -0
- package/dist/testing/integration_helpers.d.ts +107 -0
- package/dist/testing/integration_helpers.d.ts.map +1 -0
- package/dist/testing/integration_helpers.js +246 -0
- package/dist/testing/middleware.d.ts +125 -0
- package/dist/testing/middleware.d.ts.map +1 -0
- package/dist/testing/middleware.js +210 -0
- package/dist/testing/rate_limiting.d.ts +43 -0
- package/dist/testing/rate_limiting.d.ts.map +1 -0
- package/dist/testing/rate_limiting.js +216 -0
- package/dist/testing/round_trip.d.ts +37 -0
- package/dist/testing/round_trip.d.ts.map +1 -0
- package/dist/testing/round_trip.js +128 -0
- package/dist/testing/schema_generators.d.ts +33 -0
- package/dist/testing/schema_generators.d.ts.map +1 -0
- package/dist/testing/schema_generators.js +137 -0
- package/dist/testing/standard.d.ts +49 -0
- package/dist/testing/standard.d.ts.map +1 -0
- package/dist/testing/standard.js +16 -0
- package/dist/testing/stubs.d.ts +96 -0
- package/dist/testing/stubs.d.ts.map +1 -0
- package/dist/testing/stubs.js +192 -0
- package/dist/testing/surface_invariants.d.ts +189 -0
- package/dist/testing/surface_invariants.d.ts.map +1 -0
- package/dist/testing/surface_invariants.js +450 -0
- package/dist/ui/AccountSessions.svelte +75 -0
- package/dist/ui/AccountSessions.svelte.d.ts +19 -0
- package/dist/ui/AccountSessions.svelte.d.ts.map +1 -0
- package/dist/ui/AdminAccounts.svelte +107 -0
- package/dist/ui/AdminAccounts.svelte.d.ts +19 -0
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -0
- package/dist/ui/AdminAuditLog.svelte +144 -0
- package/dist/ui/AdminAuditLog.svelte.d.ts +4 -0
- package/dist/ui/AdminAuditLog.svelte.d.ts.map +1 -0
- package/dist/ui/AdminInvites.svelte +142 -0
- package/dist/ui/AdminInvites.svelte.d.ts +4 -0
- package/dist/ui/AdminInvites.svelte.d.ts.map +1 -0
- package/dist/ui/AdminOverview.svelte +337 -0
- package/dist/ui/AdminOverview.svelte.d.ts +4 -0
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -0
- package/dist/ui/AdminPermitHistory.svelte +61 -0
- package/dist/ui/AdminPermitHistory.svelte.d.ts +19 -0
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -0
- package/dist/ui/AdminSessions.svelte +85 -0
- package/dist/ui/AdminSessions.svelte.d.ts +19 -0
- package/dist/ui/AdminSessions.svelte.d.ts.map +1 -0
- package/dist/ui/AdminSettings.svelte +32 -0
- package/dist/ui/AdminSettings.svelte.d.ts +19 -0
- package/dist/ui/AdminSettings.svelte.d.ts.map +1 -0
- package/dist/ui/AdminSurface.svelte +42 -0
- package/dist/ui/AdminSurface.svelte.d.ts +4 -0
- package/dist/ui/AdminSurface.svelte.d.ts.map +1 -0
- package/dist/ui/AppShell.svelte +93 -0
- package/dist/ui/AppShell.svelte.d.ts +20 -0
- package/dist/ui/AppShell.svelte.d.ts.map +1 -0
- package/dist/ui/BootstrapForm.svelte +105 -0
- package/dist/ui/BootstrapForm.svelte.d.ts +4 -0
- package/dist/ui/BootstrapForm.svelte.d.ts.map +1 -0
- package/dist/ui/ColumnLayout.svelte +46 -0
- package/dist/ui/ColumnLayout.svelte.d.ts +11 -0
- package/dist/ui/ColumnLayout.svelte.d.ts.map +1 -0
- package/dist/ui/ConfirmButton.svelte +125 -0
- package/dist/ui/ConfirmButton.svelte.d.ts +54 -0
- package/dist/ui/ConfirmButton.svelte.d.ts.map +1 -0
- package/dist/ui/Datatable.svelte +185 -0
- package/dist/ui/Datatable.svelte.d.ts +35 -0
- package/dist/ui/Datatable.svelte.d.ts.map +1 -0
- package/dist/ui/LoginForm.svelte +82 -0
- package/dist/ui/LoginForm.svelte.d.ts +8 -0
- package/dist/ui/LoginForm.svelte.d.ts.map +1 -0
- package/dist/ui/LogoutButton.svelte +36 -0
- package/dist/ui/LogoutButton.svelte.d.ts +10 -0
- package/dist/ui/LogoutButton.svelte.d.ts.map +1 -0
- package/dist/ui/MenuLink.svelte +35 -0
- package/dist/ui/MenuLink.svelte.d.ts +12 -0
- package/dist/ui/MenuLink.svelte.d.ts.map +1 -0
- package/dist/ui/OpenSignupToggle.svelte +36 -0
- package/dist/ui/OpenSignupToggle.svelte.d.ts +19 -0
- package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -0
- package/dist/ui/PopoverButton.svelte +136 -0
- package/dist/ui/PopoverButton.svelte.d.ts +63 -0
- package/dist/ui/PopoverButton.svelte.d.ts.map +1 -0
- package/dist/ui/SignupForm.svelte +117 -0
- package/dist/ui/SignupForm.svelte.d.ts +7 -0
- package/dist/ui/SignupForm.svelte.d.ts.map +1 -0
- package/dist/ui/SurfaceExplorer.svelte +287 -0
- package/dist/ui/SurfaceExplorer.svelte.d.ts +8 -0
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -0
- package/dist/ui/account_sessions_state.svelte.d.ts +15 -0
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -0
- package/dist/ui/account_sessions_state.svelte.js +45 -0
- package/dist/ui/admin_accounts_state.svelte.d.ts +19 -0
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -0
- package/dist/ui/admin_accounts_state.svelte.js +65 -0
- package/dist/ui/admin_invites_state.svelte.d.ts +19 -0
- package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -0
- package/dist/ui/admin_invites_state.svelte.js +71 -0
- package/dist/ui/admin_sessions_state.svelte.d.ts +18 -0
- package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -0
- package/dist/ui/admin_sessions_state.svelte.js +62 -0
- package/dist/ui/app_settings_state.svelte.d.ts +14 -0
- package/dist/ui/app_settings_state.svelte.d.ts.map +1 -0
- package/dist/ui/app_settings_state.svelte.js +44 -0
- package/dist/ui/audit_log_state.svelte.d.ts +40 -0
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -0
- package/dist/ui/audit_log_state.svelte.js +153 -0
- package/dist/ui/auth_state.svelte.d.ts +85 -0
- package/dist/ui/auth_state.svelte.d.ts.map +1 -0
- package/dist/ui/auth_state.svelte.js +238 -0
- package/dist/ui/datatable.d.ts +25 -0
- package/dist/ui/datatable.d.ts.map +1 -0
- package/dist/ui/datatable.js +9 -0
- package/dist/ui/enter_advance.d.ts +13 -0
- package/dist/ui/enter_advance.d.ts.map +1 -0
- package/dist/ui/enter_advance.js +30 -0
- package/dist/ui/loadable.svelte.d.ts +55 -0
- package/dist/ui/loadable.svelte.d.ts.map +1 -0
- package/dist/ui/loadable.svelte.js +75 -0
- package/dist/ui/popover.svelte.d.ts +137 -0
- package/dist/ui/popover.svelte.d.ts.map +1 -0
- package/dist/ui/popover.svelte.js +288 -0
- package/dist/ui/position_helpers.d.ts +27 -0
- package/dist/ui/position_helpers.d.ts.map +1 -0
- package/dist/ui/position_helpers.js +81 -0
- package/dist/ui/sidebar_state.svelte.d.ts +30 -0
- package/dist/ui/sidebar_state.svelte.d.ts.map +1 -0
- package/dist/ui/sidebar_state.svelte.js +39 -0
- package/dist/ui/table_state.svelte.d.ts +63 -0
- package/dist/ui/table_state.svelte.d.ts.map +1 -0
- package/dist/ui/table_state.svelte.js +117 -0
- package/dist/ui/ui_fetch.d.ts +29 -0
- package/dist/ui/ui_fetch.d.ts.map +1 -0
- package/dist/ui/ui_fetch.js +37 -0
- package/dist/ui/ui_format.d.ts +63 -0
- package/dist/ui/ui_format.d.ts.map +1 -0
- package/dist/ui/ui_format.js +196 -0
- package/package.json +121 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adversarial input validation testing for route specs.
|
|
4
|
+
*
|
|
5
|
+
* Walks Zod schemas directly to generate payloads that must fail validation.
|
|
6
|
+
* Fires requests against a test app and asserts 400 responses before handlers
|
|
7
|
+
* are reached.
|
|
8
|
+
*
|
|
9
|
+
* Tests are focused: one representative wrong-type value per field, one format
|
|
10
|
+
* violation per constrained field, one null and one missing test per required
|
|
11
|
+
* field, plus whole-body structural attacks (non-object body, extra unknown keys).
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { test, assert, describe } from 'vitest';
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import { zod_unwrap_to_object, zod_extract_fields } from '@fuzdev/fuz_util/zod.js';
|
|
18
|
+
import { is_null_schema } from '../http/schema_helpers.js';
|
|
19
|
+
import { filter_routes_with_input, filter_routes_with_params, filter_routes_with_query, } from '../http/surface_query.js';
|
|
20
|
+
import { ValidationError, ERROR_INVALID_REQUEST_BODY, ERROR_INVALID_JSON_BODY, ERROR_INVALID_ROUTE_PARAMS, ERROR_INVALID_QUERY_PARAMS, } from '../http/error_schemas.js';
|
|
21
|
+
import { create_auth_test_apps, select_auth_app } from './auth_apps.js';
|
|
22
|
+
import { detect_format, generate_valid_value, resolve_valid_path } from './schema_generators.js';
|
|
23
|
+
// --- Payload generation ---
|
|
24
|
+
/** One wrong-type value per base type — one representative is sufficient. */
|
|
25
|
+
const wrong_type_for = (base_type) => {
|
|
26
|
+
switch (base_type) {
|
|
27
|
+
case 'string':
|
|
28
|
+
case 'uuid':
|
|
29
|
+
case 'email':
|
|
30
|
+
return { label: 'number instead of string', value: 42 };
|
|
31
|
+
case 'number':
|
|
32
|
+
case 'int':
|
|
33
|
+
return { label: 'string instead of number', value: 'not_a_number' };
|
|
34
|
+
case 'boolean':
|
|
35
|
+
return { label: 'number instead of boolean', value: 42 };
|
|
36
|
+
case 'array':
|
|
37
|
+
return { label: 'string instead of array', value: 'not_an_array' };
|
|
38
|
+
case 'object':
|
|
39
|
+
return { label: 'string instead of object', value: 'not_an_object' };
|
|
40
|
+
case 'enum':
|
|
41
|
+
return { label: 'number instead of enum', value: 42 };
|
|
42
|
+
default:
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
/** Format violation payloads — one per constraint type. */
|
|
47
|
+
const format_violation = (format) => {
|
|
48
|
+
switch (format) {
|
|
49
|
+
case 'uuid':
|
|
50
|
+
return { label: 'malformed uuid', value: 'not-a-uuid' };
|
|
51
|
+
case 'email':
|
|
52
|
+
return { label: 'malformed email', value: 'not-an-email' };
|
|
53
|
+
case 'date-time':
|
|
54
|
+
return { label: 'malformed datetime', value: 'not-a-date' };
|
|
55
|
+
case 'pattern':
|
|
56
|
+
return { label: 'pattern violation', value: "'; DROP TABLE --" };
|
|
57
|
+
default:
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
// --- Input test case generation ---
|
|
62
|
+
/**
|
|
63
|
+
* Generate adversarial test cases for a route's input schema.
|
|
64
|
+
*
|
|
65
|
+
* Produces focused, non-redundant cases:
|
|
66
|
+
* - Whole-body: send array instead of object, extra unknown key
|
|
67
|
+
* - Missing required fields (without defaults)
|
|
68
|
+
* - One wrong-type value per field
|
|
69
|
+
* - Null for required non-nullable fields
|
|
70
|
+
* - One format violation per constrained field
|
|
71
|
+
*/
|
|
72
|
+
export const generate_input_test_cases = (input_schema) => {
|
|
73
|
+
if (is_null_schema(input_schema))
|
|
74
|
+
return [];
|
|
75
|
+
const object_schema = zod_unwrap_to_object(input_schema);
|
|
76
|
+
if (!object_schema)
|
|
77
|
+
return [];
|
|
78
|
+
const fields = zod_extract_fields(object_schema);
|
|
79
|
+
const cases = [];
|
|
80
|
+
// build a base object with valid-ish values — must pass validation itself
|
|
81
|
+
// skip optional fields without defaults to avoid generating invalid nested values
|
|
82
|
+
const base = {};
|
|
83
|
+
for (const field of fields) {
|
|
84
|
+
if (!field.required && !field.has_default)
|
|
85
|
+
continue;
|
|
86
|
+
base[field.name] = generate_valid_value(field, object_schema.shape[field.name]);
|
|
87
|
+
}
|
|
88
|
+
const base_result = input_schema.safeParse(base);
|
|
89
|
+
if (!base_result.success) {
|
|
90
|
+
throw new Error(`adversarial_input: generated base object fails validation for schema — ` +
|
|
91
|
+
`fix generate_valid_value for: ${base_result.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join(', ')}`);
|
|
92
|
+
}
|
|
93
|
+
// whole-body structural: send array instead of object
|
|
94
|
+
cases.push({
|
|
95
|
+
label: 'non-object body (array)',
|
|
96
|
+
body: [1, 2, 3],
|
|
97
|
+
expected_error: ERROR_INVALID_JSON_BODY,
|
|
98
|
+
});
|
|
99
|
+
// whole-body structural: extra unknown key (enforces strictObject)
|
|
100
|
+
// only emit if the schema rejects unknown keys (i.e. uses z.strictObject)
|
|
101
|
+
const extra_key_result = input_schema.safeParse({ ...base, __adversarial_extra: 'rejected' });
|
|
102
|
+
if (!extra_key_result.success) {
|
|
103
|
+
cases.push({
|
|
104
|
+
label: 'extra unknown key',
|
|
105
|
+
body: { ...base, __adversarial_extra: 'should_be_rejected' },
|
|
106
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
for (const field of fields) {
|
|
110
|
+
const field_schema = object_schema.shape[field.name];
|
|
111
|
+
// missing required field (skip fields with defaults — Zod fills them)
|
|
112
|
+
if (field.required && !field.has_default) {
|
|
113
|
+
const without = {};
|
|
114
|
+
for (const [k, v] of Object.entries(base)) {
|
|
115
|
+
if (k !== field.name)
|
|
116
|
+
without[k] = v;
|
|
117
|
+
}
|
|
118
|
+
cases.push({
|
|
119
|
+
label: `missing: ${field.name}`,
|
|
120
|
+
body: without,
|
|
121
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// one wrong-type value
|
|
125
|
+
const wrong = wrong_type_for(field.base_type);
|
|
126
|
+
if (wrong) {
|
|
127
|
+
cases.push({
|
|
128
|
+
label: `wrong type: ${field.name} (${wrong.label})`,
|
|
129
|
+
body: { ...base, [field.name]: wrong.value },
|
|
130
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// null for required non-nullable fields
|
|
134
|
+
if (field.required && !field.nullable && field.base_type !== 'null') {
|
|
135
|
+
cases.push({
|
|
136
|
+
label: `null: ${field.name}`,
|
|
137
|
+
body: { ...base, [field.name]: null },
|
|
138
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// format violation for constrained string fields
|
|
142
|
+
const format = detect_format(field_schema);
|
|
143
|
+
if (format) {
|
|
144
|
+
const violation = format_violation(format);
|
|
145
|
+
if (violation) {
|
|
146
|
+
cases.push({
|
|
147
|
+
label: `format: ${field.name} (${violation.label})`,
|
|
148
|
+
body: { ...base, [field.name]: violation.value },
|
|
149
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// --- Boundary cases via JSON Schema introspection ---
|
|
154
|
+
try {
|
|
155
|
+
const json = z.toJSONSchema(field_schema);
|
|
156
|
+
// string length boundaries
|
|
157
|
+
if (field.base_type === 'string' ||
|
|
158
|
+
field.base_type === 'uuid' ||
|
|
159
|
+
field.base_type === 'email') {
|
|
160
|
+
if (typeof json.minLength === 'number' && json.minLength > 0) {
|
|
161
|
+
cases.push({
|
|
162
|
+
label: `empty string: ${field.name}`,
|
|
163
|
+
body: { ...base, [field.name]: '' },
|
|
164
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (typeof json.maxLength === 'number') {
|
|
168
|
+
cases.push({
|
|
169
|
+
label: `over maxLength: ${field.name} (${json.maxLength + 1} chars)`,
|
|
170
|
+
body: { ...base, [field.name]: 'x'.repeat(json.maxLength + 1) },
|
|
171
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// numeric boundaries
|
|
176
|
+
if (field.base_type === 'number' || field.base_type === 'int') {
|
|
177
|
+
if (typeof json.minimum === 'number') {
|
|
178
|
+
cases.push({
|
|
179
|
+
label: `below minimum: ${field.name} (${json.minimum - 1})`,
|
|
180
|
+
body: { ...base, [field.name]: json.minimum - 1 },
|
|
181
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (typeof json.maximum === 'number') {
|
|
185
|
+
cases.push({
|
|
186
|
+
label: `above maximum: ${field.name} (${json.maximum + 1})`,
|
|
187
|
+
body: { ...base, [field.name]: json.maximum + 1 },
|
|
188
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (typeof json.exclusiveMinimum === 'number') {
|
|
192
|
+
cases.push({
|
|
193
|
+
label: `at exclusive minimum: ${field.name} (${json.exclusiveMinimum})`,
|
|
194
|
+
body: { ...base, [field.name]: json.exclusiveMinimum },
|
|
195
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (typeof json.exclusiveMaximum === 'number') {
|
|
199
|
+
cases.push({
|
|
200
|
+
label: `at exclusive maximum: ${field.name} (${json.exclusiveMaximum})`,
|
|
201
|
+
body: { ...base, [field.name]: json.exclusiveMaximum },
|
|
202
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
// 0 and negative for positive-only fields
|
|
206
|
+
if (typeof json.minimum === 'number' && json.minimum > 0) {
|
|
207
|
+
cases.push({
|
|
208
|
+
label: `zero for positive-only: ${field.name}`,
|
|
209
|
+
body: { ...base, [field.name]: 0 },
|
|
210
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
211
|
+
});
|
|
212
|
+
cases.push({
|
|
213
|
+
label: `negative for positive-only: ${field.name}`,
|
|
214
|
+
body: { ...base, [field.name]: -1 },
|
|
215
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// array length boundaries
|
|
220
|
+
if (field.base_type === 'array') {
|
|
221
|
+
if (typeof json.minItems === 'number' && json.minItems > 0) {
|
|
222
|
+
cases.push({
|
|
223
|
+
label: `empty array for minItems > 0: ${field.name}`,
|
|
224
|
+
body: { ...base, [field.name]: [] },
|
|
225
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (typeof json.maxItems === 'number') {
|
|
229
|
+
// generate an array one item over the max (items are null — schema-agnostic)
|
|
230
|
+
cases.push({
|
|
231
|
+
label: `over maxItems: ${field.name} (${json.maxItems + 1} items)`,
|
|
232
|
+
body: { ...base, [field.name]: Array.from({ length: json.maxItems + 1 }, () => null) },
|
|
233
|
+
expected_error: ERROR_INVALID_REQUEST_BODY,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// schema can't be converted to JSON Schema, skip boundary cases
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return cases;
|
|
243
|
+
};
|
|
244
|
+
// --- Params test case generation ---
|
|
245
|
+
/**
|
|
246
|
+
* Generate adversarial test cases for a route's params schema.
|
|
247
|
+
*
|
|
248
|
+
* Params are always strings from URL segments. Only generates cases for
|
|
249
|
+
* format-constrained fields (uuid, pattern) since unconstrained string
|
|
250
|
+
* params accept any string value.
|
|
251
|
+
*/
|
|
252
|
+
export const generate_params_test_cases = (params_schema) => {
|
|
253
|
+
const fields = zod_extract_fields(params_schema);
|
|
254
|
+
const cases = [];
|
|
255
|
+
// build base params with valid-ish values
|
|
256
|
+
const base_params = {};
|
|
257
|
+
for (const field of fields) {
|
|
258
|
+
const field_schema = params_schema.shape[field.name];
|
|
259
|
+
const format = detect_format(field_schema);
|
|
260
|
+
if (format === 'uuid' || field.base_type === 'uuid') {
|
|
261
|
+
base_params[field.name] = '00000000-0000-0000-0000-000000000000';
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
base_params[field.name] = 'test_value';
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const field of fields) {
|
|
268
|
+
const field_schema = params_schema.shape[field.name];
|
|
269
|
+
const format = detect_format(field_schema);
|
|
270
|
+
if (!format)
|
|
271
|
+
continue; // unconstrained string — any value passes
|
|
272
|
+
const violation = format_violation(format);
|
|
273
|
+
if (violation) {
|
|
274
|
+
cases.push({
|
|
275
|
+
label: `${violation.label}: param ${field.name}`,
|
|
276
|
+
params: { ...base_params, [field.name]: violation.value },
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return cases;
|
|
281
|
+
};
|
|
282
|
+
// --- Query test case generation ---
|
|
283
|
+
/**
|
|
284
|
+
* Generate adversarial test cases for a route's query schema.
|
|
285
|
+
*
|
|
286
|
+
* Query params are always strings from the URL. Generates cases for:
|
|
287
|
+
* - Missing required fields
|
|
288
|
+
* - Format violations on constrained fields (uuid, pattern)
|
|
289
|
+
*/
|
|
290
|
+
export const generate_query_test_cases = (query_schema) => {
|
|
291
|
+
const fields = zod_extract_fields(query_schema);
|
|
292
|
+
const cases = [];
|
|
293
|
+
// build base query with valid-ish values
|
|
294
|
+
const base_query = {};
|
|
295
|
+
for (const field of fields) {
|
|
296
|
+
const field_schema = query_schema.shape[field.name];
|
|
297
|
+
const format = detect_format(field_schema);
|
|
298
|
+
if (format === 'uuid' || field.base_type === 'uuid') {
|
|
299
|
+
base_query[field.name] = '00000000-0000-0000-0000-000000000000';
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
base_query[field.name] = 'test_value';
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
for (const field of fields) {
|
|
306
|
+
// missing required field
|
|
307
|
+
if (field.required && !field.has_default) {
|
|
308
|
+
const without = {};
|
|
309
|
+
for (const [k, v] of Object.entries(base_query)) {
|
|
310
|
+
if (k !== field.name)
|
|
311
|
+
without[k] = v;
|
|
312
|
+
}
|
|
313
|
+
cases.push({
|
|
314
|
+
label: `missing query: ${field.name}`,
|
|
315
|
+
query: without,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
// format violation for constrained string fields
|
|
319
|
+
const field_schema = query_schema.shape[field.name];
|
|
320
|
+
const format = detect_format(field_schema);
|
|
321
|
+
if (!format)
|
|
322
|
+
continue;
|
|
323
|
+
const violation = format_violation(format);
|
|
324
|
+
if (violation) {
|
|
325
|
+
cases.push({
|
|
326
|
+
label: `${violation.label}: query ${field.name}`,
|
|
327
|
+
query: { ...base_query, [field.name]: violation.value },
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return cases;
|
|
332
|
+
};
|
|
333
|
+
// --- URL helpers ---
|
|
334
|
+
/** Build a URL path with adversarial param values. */
|
|
335
|
+
const build_fuzz_url = (route_path, params) => {
|
|
336
|
+
let url = route_path;
|
|
337
|
+
for (const [key, value] of Object.entries(params)) {
|
|
338
|
+
url = url.replace(`:${key}`, encodeURIComponent(value));
|
|
339
|
+
}
|
|
340
|
+
return url;
|
|
341
|
+
};
|
|
342
|
+
/** Build a URL with query string parameters. */
|
|
343
|
+
const build_query_url = (path, query) => {
|
|
344
|
+
const search = new URLSearchParams(query).toString();
|
|
345
|
+
return search ? `${path}?${search}` : path;
|
|
346
|
+
};
|
|
347
|
+
// --- Test runner ---
|
|
348
|
+
/**
|
|
349
|
+
* Generate adversarial input validation test suites.
|
|
350
|
+
*
|
|
351
|
+
* Tests input body validation and params validation for all routes.
|
|
352
|
+
* Uses correct auth credentials so auth guards pass and validation
|
|
353
|
+
* middleware is actually exercised.
|
|
354
|
+
*
|
|
355
|
+
* @param options - the test configuration
|
|
356
|
+
*/
|
|
357
|
+
export const describe_adversarial_input = (options) => {
|
|
358
|
+
const { build, roles } = options;
|
|
359
|
+
const { surface, route_specs } = build();
|
|
360
|
+
const routes_with_input = filter_routes_with_input(surface);
|
|
361
|
+
const routes_with_params = filter_routes_with_params(surface);
|
|
362
|
+
const routes_with_query = filter_routes_with_query(surface);
|
|
363
|
+
if (routes_with_input.length === 0 &&
|
|
364
|
+
routes_with_params.length === 0 &&
|
|
365
|
+
routes_with_query.length === 0)
|
|
366
|
+
return;
|
|
367
|
+
// lookup RouteSpec by method+path for Zod schema access
|
|
368
|
+
const spec_lookup = new Map();
|
|
369
|
+
for (const spec of route_specs) {
|
|
370
|
+
spec_lookup.set(`${spec.method} ${spec.path}`, spec);
|
|
371
|
+
}
|
|
372
|
+
const apps = create_auth_test_apps(route_specs, roles);
|
|
373
|
+
describe('adversarial input validation', () => {
|
|
374
|
+
// --- Input body tests ---
|
|
375
|
+
if (routes_with_input.length > 0) {
|
|
376
|
+
// every surface route with input must have a matching RouteSpec
|
|
377
|
+
const missing_specs = routes_with_input
|
|
378
|
+
.map((r) => `${r.method} ${r.path}`)
|
|
379
|
+
.filter((key) => !spec_lookup.has(key));
|
|
380
|
+
if (missing_specs.length > 0) {
|
|
381
|
+
throw new Error(`adversarial_input: surface routes with input have no matching RouteSpec: ${missing_specs.join(', ')}`);
|
|
382
|
+
}
|
|
383
|
+
let input_test_count = 0;
|
|
384
|
+
describe('input body', () => {
|
|
385
|
+
for (const route of routes_with_input) {
|
|
386
|
+
const key = `${route.method} ${route.path}`;
|
|
387
|
+
const spec = spec_lookup.get(key);
|
|
388
|
+
const test_cases = generate_input_test_cases(spec.input);
|
|
389
|
+
if (test_cases.length === 0)
|
|
390
|
+
continue;
|
|
391
|
+
input_test_count += test_cases.length;
|
|
392
|
+
const app = select_auth_app(apps, route.auth);
|
|
393
|
+
const url = resolve_valid_path(route.path, spec.params);
|
|
394
|
+
describe(key, () => {
|
|
395
|
+
for (const tc of test_cases) {
|
|
396
|
+
test(tc.label, async () => {
|
|
397
|
+
const res = await app.request(url, {
|
|
398
|
+
method: route.method,
|
|
399
|
+
headers: { 'Content-Type': 'application/json' },
|
|
400
|
+
body: JSON.stringify(tc.body),
|
|
401
|
+
});
|
|
402
|
+
assert.strictEqual(res.status, 400, `Expected 400 for ${key} [${tc.label}], got ${res.status}`);
|
|
403
|
+
const body = await res.json();
|
|
404
|
+
assert.strictEqual(body.error, tc.expected_error, `Expected ${tc.expected_error} for ${key} [${tc.label}], got: ${body.error}`);
|
|
405
|
+
// validate response body structure matches error schema
|
|
406
|
+
if (tc.expected_error === 'invalid_request_body') {
|
|
407
|
+
ValidationError.parse(body);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
test('generated input test cases', () => {
|
|
414
|
+
assert.ok(input_test_count > 0, 'No input test cases generated — schema walking may be broken');
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
// --- Params tests ---
|
|
419
|
+
if (routes_with_params.length > 0) {
|
|
420
|
+
let params_test_count = 0;
|
|
421
|
+
describe('params', () => {
|
|
422
|
+
for (const route of routes_with_params) {
|
|
423
|
+
const key = `${route.method} ${route.path}`;
|
|
424
|
+
const spec = spec_lookup.get(key);
|
|
425
|
+
if (!spec?.params)
|
|
426
|
+
continue;
|
|
427
|
+
const test_cases = generate_params_test_cases(spec.params);
|
|
428
|
+
if (test_cases.length === 0)
|
|
429
|
+
continue;
|
|
430
|
+
params_test_count += test_cases.length;
|
|
431
|
+
const app = select_auth_app(apps, route.auth);
|
|
432
|
+
describe(key, () => {
|
|
433
|
+
for (const tc of test_cases) {
|
|
434
|
+
test(tc.label, async () => {
|
|
435
|
+
const url = build_fuzz_url(route.path, tc.params);
|
|
436
|
+
const res = await app.request(url, { method: route.method });
|
|
437
|
+
assert.strictEqual(res.status, 400, `Expected 400 for ${key} [${tc.label}], got ${res.status}`);
|
|
438
|
+
const body = await res.json();
|
|
439
|
+
assert.strictEqual(body.error, ERROR_INVALID_ROUTE_PARAMS, `Expected ${ERROR_INVALID_ROUTE_PARAMS} for ${key} [${tc.label}], got: ${body.error}`);
|
|
440
|
+
// validate response body structure matches error schema
|
|
441
|
+
ValidationError.parse(body);
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
// params coverage check is softer — not all param routes have format constraints
|
|
447
|
+
if (params_test_count === 0) {
|
|
448
|
+
test('no params test cases generated (all params unconstrained)', () => {
|
|
449
|
+
// informational — unconstrained string params accept any value
|
|
450
|
+
assert.ok(true);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
// --- Query tests ---
|
|
456
|
+
if (routes_with_query.length > 0) {
|
|
457
|
+
let query_test_count = 0;
|
|
458
|
+
describe('query params', () => {
|
|
459
|
+
for (const route of routes_with_query) {
|
|
460
|
+
const key = `${route.method} ${route.path}`;
|
|
461
|
+
const spec = spec_lookup.get(key);
|
|
462
|
+
if (!spec?.query)
|
|
463
|
+
continue;
|
|
464
|
+
const test_cases = generate_query_test_cases(spec.query);
|
|
465
|
+
if (test_cases.length === 0)
|
|
466
|
+
continue;
|
|
467
|
+
query_test_count += test_cases.length;
|
|
468
|
+
const app = select_auth_app(apps, route.auth);
|
|
469
|
+
const base_url = resolve_valid_path(route.path, spec.params);
|
|
470
|
+
describe(key, () => {
|
|
471
|
+
for (const tc of test_cases) {
|
|
472
|
+
test(tc.label, async () => {
|
|
473
|
+
const url = build_query_url(base_url, tc.query);
|
|
474
|
+
const res = await app.request(url, { method: route.method });
|
|
475
|
+
assert.strictEqual(res.status, 400, `Expected 400 for ${key} [${tc.label}], got ${res.status}`);
|
|
476
|
+
const body = await res.json();
|
|
477
|
+
assert.strictEqual(body.error, ERROR_INVALID_QUERY_PARAMS, `Expected ${ERROR_INVALID_QUERY_PARAMS} for ${key} [${tc.label}], got: ${body.error}`);
|
|
478
|
+
// validate response body structure matches error schema
|
|
479
|
+
ValidationError.parse(body);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
// query coverage check is softer — not all query routes have format constraints
|
|
485
|
+
if (query_test_count === 0) {
|
|
486
|
+
test('no query test cases generated (all query params unconstrained)', () => {
|
|
487
|
+
// informational — unconstrained string query params accept any value
|
|
488
|
+
assert.ok(true);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Bootstrapped app server factory for integration tests.
|
|
4
|
+
*
|
|
5
|
+
* Creates a keeper account, API token, and signed session cookie on a
|
|
6
|
+
* database. By default uses a cached in-memory PGlite (shared WASM instance
|
|
7
|
+
* per vitest worker thread via `test_db.ts` module cache); pass `db` to use
|
|
8
|
+
* an existing database (any driver) instead.
|
|
9
|
+
*
|
|
10
|
+
* Also provides `create_test_app` — a combined helper that creates both
|
|
11
|
+
* a `TestAppServer` and a fully assembled Hono app with middleware and routes.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import type { Hono } from 'hono';
|
|
16
|
+
import { type Keyring } from '../auth/keyring.js';
|
|
17
|
+
import type { Db, DbType } from '../db/db.js';
|
|
18
|
+
import type { PasswordHashDeps } from '../auth/password.js';
|
|
19
|
+
import { type SessionOptions } from '../auth/session_cookie.js';
|
|
20
|
+
import type { AppBackend } from '../server/app_backend.js';
|
|
21
|
+
import { type AppServerOptions, type AppServerContext } from '../server/app_server.js';
|
|
22
|
+
import type { AppSurface } from '../http/surface.js';
|
|
23
|
+
import type { RouteSpec } from '../http/route_spec.js';
|
|
24
|
+
/**
|
|
25
|
+
* Fast password stub for tests that don't exercise login/password flows.
|
|
26
|
+
*
|
|
27
|
+
* Hashes are deterministic (`stub_hash_<password>`) and verify correctly,
|
|
28
|
+
* so auth bootstrap and session creation work without Argon2 overhead.
|
|
29
|
+
*/
|
|
30
|
+
export declare const stub_password_deps: PasswordHashDeps;
|
|
31
|
+
/** 64-hex-char test cookie secret — deterministic, never used in production. */
|
|
32
|
+
export declare const TEST_COOKIE_SECRET: string;
|
|
33
|
+
/**
|
|
34
|
+
* Options for `bootstrap_test_account`.
|
|
35
|
+
*/
|
|
36
|
+
export interface BootstrapTestAccountOptions {
|
|
37
|
+
db: Db;
|
|
38
|
+
keyring: Keyring;
|
|
39
|
+
session_options: SessionOptions<string>;
|
|
40
|
+
password: PasswordHashDeps;
|
|
41
|
+
username?: string;
|
|
42
|
+
password_value?: string;
|
|
43
|
+
roles?: Array<string>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Bootstrap a test account with credentials.
|
|
47
|
+
*
|
|
48
|
+
* Creates an account with actor, grants roles, creates an API token,
|
|
49
|
+
* creates a session, and signs a session cookie. Shared by
|
|
50
|
+
* `create_test_app_server` and `TestApp.create_account`.
|
|
51
|
+
*/
|
|
52
|
+
export declare const bootstrap_test_account: (options: BootstrapTestAccountOptions) => Promise<{
|
|
53
|
+
account: {
|
|
54
|
+
id: string;
|
|
55
|
+
username: string;
|
|
56
|
+
};
|
|
57
|
+
actor: {
|
|
58
|
+
id: string;
|
|
59
|
+
};
|
|
60
|
+
api_token: string;
|
|
61
|
+
session_cookie: string;
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* An `AppBackend` with a bootstrapped account, API token, and session cookie.
|
|
65
|
+
*/
|
|
66
|
+
export interface TestAppServer extends AppBackend {
|
|
67
|
+
/** The bootstrapped account. */
|
|
68
|
+
account: {
|
|
69
|
+
id: string;
|
|
70
|
+
username: string;
|
|
71
|
+
};
|
|
72
|
+
/** The actor linked to the account. */
|
|
73
|
+
actor: {
|
|
74
|
+
id: string;
|
|
75
|
+
};
|
|
76
|
+
/** Raw API token for Bearer auth. */
|
|
77
|
+
api_token: string;
|
|
78
|
+
/** Signed session cookie value for cookie auth. */
|
|
79
|
+
session_cookie: string;
|
|
80
|
+
/** Keyring used for cookie signing — exposed for forging expired/tampered cookies in tests. */
|
|
81
|
+
keyring: Keyring;
|
|
82
|
+
/** Release test resources (no-op when DB is injected or factory-cached). */
|
|
83
|
+
cleanup: () => Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Configuration for `create_test_app_server`.
|
|
87
|
+
*/
|
|
88
|
+
export interface TestAppServerOptions {
|
|
89
|
+
/** Session options — needed for cookie signing. */
|
|
90
|
+
session_options: SessionOptions<string>;
|
|
91
|
+
/** Existing database — skips internal DB creation when provided. Caller owns the DB lifecycle. */
|
|
92
|
+
db?: Db;
|
|
93
|
+
/** Database driver type — only used when `db` is provided. Default: `'pglite-memory'`. */
|
|
94
|
+
db_type?: DbType;
|
|
95
|
+
/** Password implementation. Default: `stub_password_deps`. Pass `argon2_password_deps` for tests that exercise login. */
|
|
96
|
+
password?: PasswordHashDeps;
|
|
97
|
+
/** Username for the bootstrapped account. Default: `'keeper'`. */
|
|
98
|
+
username?: string;
|
|
99
|
+
/** Password for the bootstrapped account. Default: `'test-password-123'`. */
|
|
100
|
+
password_value?: string;
|
|
101
|
+
/** Roles to grant. Default: `[ROLE_KEEPER]`. */
|
|
102
|
+
roles?: Array<string>;
|
|
103
|
+
}
|
|
104
|
+
export declare const create_test_app_server: (options: TestAppServerOptions) => Promise<TestAppServer>;
|
|
105
|
+
/**
|
|
106
|
+
* Configuration for `create_test_app`.
|
|
107
|
+
*/
|
|
108
|
+
export interface CreateTestAppOptions extends TestAppServerOptions {
|
|
109
|
+
/** Route spec factory — called with the assembled `AppServerContext`. */
|
|
110
|
+
create_route_specs: (context: AppServerContext) => Array<RouteSpec>;
|
|
111
|
+
/** Optional overrides for `AppServerOptions` (backend, session_options, and create_route_specs are managed). */
|
|
112
|
+
app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A bootstrapped test account with credentials.
|
|
116
|
+
*/
|
|
117
|
+
export interface TestAccount {
|
|
118
|
+
account: {
|
|
119
|
+
id: string;
|
|
120
|
+
username: string;
|
|
121
|
+
};
|
|
122
|
+
actor: {
|
|
123
|
+
id: string;
|
|
124
|
+
};
|
|
125
|
+
/** Signed session cookie value. */
|
|
126
|
+
session_cookie: string;
|
|
127
|
+
/** Raw API token for Bearer auth. */
|
|
128
|
+
api_token: string;
|
|
129
|
+
/** Build request headers with this account's session cookie. */
|
|
130
|
+
create_session_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
131
|
+
/** Build request headers with this account's Bearer token. */
|
|
132
|
+
create_bearer_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A fully assembled test app — Hono app + backend + helpers.
|
|
136
|
+
*/
|
|
137
|
+
export interface TestApp {
|
|
138
|
+
app: Hono;
|
|
139
|
+
backend: TestAppServer;
|
|
140
|
+
surface: AppSurface;
|
|
141
|
+
route_specs: Array<RouteSpec>;
|
|
142
|
+
/** Build request headers with the bootstrapped session cookie. */
|
|
143
|
+
create_session_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
144
|
+
/** Build request headers with the bootstrapped Bearer token. */
|
|
145
|
+
create_bearer_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
146
|
+
/** Create an additional account with credentials. */
|
|
147
|
+
create_account: (options?: {
|
|
148
|
+
username?: string;
|
|
149
|
+
password_value?: string;
|
|
150
|
+
roles?: Array<string>;
|
|
151
|
+
}) => Promise<TestAccount>;
|
|
152
|
+
/** Cleanup resources (delegates to TestAppServer.cleanup). */
|
|
153
|
+
cleanup: () => Promise<void>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Create a fully assembled test app with a Hono server, middleware, and routes.
|
|
157
|
+
*
|
|
158
|
+
* Combines `create_test_app_server` + `create_app_server` into a single call.
|
|
159
|
+
* Disables rate limiters and logging by default (test-friendly).
|
|
160
|
+
*
|
|
161
|
+
* A fresh Hono app is created each call — middleware closures bind to the
|
|
162
|
+
* server's deps (db, keyring), so reuse across servers is unsafe.
|
|
163
|
+
* The expensive resource (PGlite WASM) is cached separately in `test_db.ts`.
|
|
164
|
+
*
|
|
165
|
+
* @param options - test app configuration
|
|
166
|
+
* @returns a `TestApp` ready for HTTP testing
|
|
167
|
+
*/
|
|
168
|
+
export declare const create_test_app: (options: CreateTestAppOptions) => Promise<TestApp>;
|
|
169
|
+
//# sourceMappingURL=app_server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAK/B,OAAO,EAA2B,KAAK,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAE1E,OAAO,KAAK,EAAC,EAAE,EAAE,MAAM,EAAC,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AAU1D,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG3F,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAKrD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAIhC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AASjD;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,EAAE,EAAE,EAAE,CAAC;IACP,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAClC,SAAS,2BAA2B,KAClC,OAAO,CAAC;IACV,OAAO,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC;IACxC,KAAK,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACvB,CAyCA,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,UAAU;IAChD,gCAAgC;IAChC,OAAO,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC;IACxC,uCAAuC;IACvC,KAAK,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,CAAC;IACpB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,+FAA+F;IAC/F,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,mDAAmD;IACnD,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,kGAAkG;IAClG,EAAE,CAAC,EAAE,EAAE,CAAC;IACR,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yHAAyH;IACzH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAqBD,eAAO,MAAM,sBAAsB,GAClC,SAAS,oBAAoB,KAC3B,OAAO,CAAC,aAAa,CAsFvB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IACjE,yEAAyE;IACzE,kBAAkB,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IACpE,gHAAgH;IAChH,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;CACF;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC;IACxC,KAAK,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,CAAC;IACpB,mCAAmC;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,sBAAsB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnF,8DAA8D;IAC9D,qBAAqB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClF;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACvB,GAAG,EAAE,IAAI,CAAC;IACV,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;IACpB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9B,kEAAkE;IAClE,sBAAsB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnF,gEAAgE;IAChE,qBAAqB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClF,qDAAqD;IACrD,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;KACtB,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3B,8DAA8D;IAC9D,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,GAAU,SAAS,oBAAoB,KAAG,OAAO,CAAC,OAAO,CA+EpF,CAAC"}
|