@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,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account route specs for cookie-based session management.
|
|
3
|
+
*
|
|
4
|
+
* Returns `RouteSpec[]` — caller applies them to Hono via `apply_route_specs`.
|
|
5
|
+
*
|
|
6
|
+
* Provides:
|
|
7
|
+
* - `POST /login` — Exchange username + password for signed session cookie
|
|
8
|
+
* - `POST /logout` — Clear session cookie and revoke auth session
|
|
9
|
+
* - `GET /verify` — Check if current session is valid
|
|
10
|
+
* - `GET /sessions` — List auth sessions for current account
|
|
11
|
+
* - `POST /sessions/:id/revoke` — Revoke a single auth session (account-scoped)
|
|
12
|
+
* - `POST /sessions/revoke-all` — Revoke all auth sessions for current account
|
|
13
|
+
* - `POST /tokens/create` — Create an API token
|
|
14
|
+
* - `GET /tokens` — List API tokens for current account
|
|
15
|
+
* - `POST /tokens/:id/revoke` — Revoke an API token (account-scoped)
|
|
16
|
+
* - `POST /password` — Change password (revokes all sessions and API tokens)
|
|
17
|
+
*
|
|
18
|
+
* Signup is separate — see `signup_routes.ts` for invite-gated account creation.
|
|
19
|
+
* Defaults are closed/safe: accounts are created through bootstrap, admin action, or invite.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import type { SessionOptions } from './session_cookie.js';
|
|
24
|
+
import { type RouteSpec } from '../http/route_spec.js';
|
|
25
|
+
import { type RateLimiter } from '../rate_limiter.js';
|
|
26
|
+
import type { RouteFactoryDeps } from './deps.js';
|
|
27
|
+
/**
|
|
28
|
+
* Create the account status route spec.
|
|
29
|
+
*
|
|
30
|
+
* Handles both authenticated and unauthenticated requests:
|
|
31
|
+
* - Authenticated: returns `{account}` with 200
|
|
32
|
+
* - Unauthenticated: returns 401 with optional `bootstrap_available` flag
|
|
33
|
+
*
|
|
34
|
+
* This eliminates the need for a separate `/health` fetch on page load —
|
|
35
|
+
* the frontend gets both session state and bootstrap availability in one request.
|
|
36
|
+
*
|
|
37
|
+
* @param options - optional configuration (bootstrap_status for bootstrap detection)
|
|
38
|
+
* @returns a single account status route spec
|
|
39
|
+
*/
|
|
40
|
+
export declare const create_account_status_route_spec: (options?: AccountStatusOptions) => RouteSpec;
|
|
41
|
+
/** Options for the account status route spec. */
|
|
42
|
+
export interface AccountStatusOptions {
|
|
43
|
+
/** Override the default path (`/api/account/status`). */
|
|
44
|
+
path?: string;
|
|
45
|
+
/** Runtime bootstrap status — when available, 401 responses include `bootstrap_available`. */
|
|
46
|
+
bootstrap_status?: {
|
|
47
|
+
available: boolean;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Default maximum sessions per account. */
|
|
51
|
+
export declare const DEFAULT_MAX_SESSIONS = 5;
|
|
52
|
+
/** Default maximum API tokens per account. */
|
|
53
|
+
export declare const DEFAULT_MAX_TOKENS = 10;
|
|
54
|
+
/**
|
|
55
|
+
* Shared options for route factories that create sessions and rate-limit by IP.
|
|
56
|
+
*
|
|
57
|
+
* Extended by `AccountRouteOptions` and `SignupRouteOptions`.
|
|
58
|
+
* Consumers can destructure these from `AppServerContext` once and spread into multiple factories.
|
|
59
|
+
*/
|
|
60
|
+
export interface AuthSessionRouteOptions {
|
|
61
|
+
session_options: SessionOptions<string>;
|
|
62
|
+
/** Rate limiter for auth attempts, keyed by client IP. Pass `null` to disable. */
|
|
63
|
+
ip_rate_limiter: RateLimiter | null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Per-factory configuration for account route specs.
|
|
67
|
+
*/
|
|
68
|
+
export interface AccountRouteOptions extends AuthSessionRouteOptions {
|
|
69
|
+
/** Rate limiter for login attempts, keyed by submitted username. Pass `null` to disable. */
|
|
70
|
+
login_account_rate_limiter: RateLimiter | null;
|
|
71
|
+
/** Max active sessions per account. Evicts oldest on login. Default 5, `null` disables. */
|
|
72
|
+
max_sessions?: number | null;
|
|
73
|
+
/** Max API tokens per account. Evicts oldest on creation. Default 10, `null` disables. */
|
|
74
|
+
max_tokens?: number | null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create account route specs for session-based auth.
|
|
78
|
+
*
|
|
79
|
+
* All session/token revocation is account-scoped to prevent cross-account attacks.
|
|
80
|
+
*
|
|
81
|
+
* @param deps - stateless capabilities (keyring, password, log)
|
|
82
|
+
* @param options - per-factory configuration (session_options, ip_rate_limiter, login_account_rate_limiter)
|
|
83
|
+
* @returns route specs (not yet applied to Hono)
|
|
84
|
+
*/
|
|
85
|
+
export declare const create_account_route_specs: (deps: RouteFactoryDeps, options: AccountRouteOptions) => Array<RouteSpec>;
|
|
86
|
+
//# sourceMappingURL=account_routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AA+BxD,OAAO,EAAoC,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExF,OAAO,EAA+B,KAAK,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAElF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAGhD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gCAAgC,GAAI,UAAU,oBAAoB,KAAG,SA0BhF,CAAC;AAEH,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACpC,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE;QAAC,SAAS,EAAE,OAAO,CAAA;KAAC,CAAC;CACxC;AAED,4CAA4C;AAC5C,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,8CAA8C;AAC9C,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,kFAAkF;IAClF,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IACnE,4FAA4F;IAC5F,0BAA0B,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GACtC,MAAM,gBAAgB,EACtB,SAAS,mBAAmB,KAC1B,KAAK,CAAC,SAAS,CAkYjB,CAAC"}
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account route specs for cookie-based session management.
|
|
3
|
+
*
|
|
4
|
+
* Returns `RouteSpec[]` — caller applies them to Hono via `apply_route_specs`.
|
|
5
|
+
*
|
|
6
|
+
* Provides:
|
|
7
|
+
* - `POST /login` — Exchange username + password for signed session cookie
|
|
8
|
+
* - `POST /logout` — Clear session cookie and revoke auth session
|
|
9
|
+
* - `GET /verify` — Check if current session is valid
|
|
10
|
+
* - `GET /sessions` — List auth sessions for current account
|
|
11
|
+
* - `POST /sessions/:id/revoke` — Revoke a single auth session (account-scoped)
|
|
12
|
+
* - `POST /sessions/revoke-all` — Revoke all auth sessions for current account
|
|
13
|
+
* - `POST /tokens/create` — Create an API token
|
|
14
|
+
* - `GET /tokens` — List API tokens for current account
|
|
15
|
+
* - `POST /tokens/:id/revoke` — Revoke an API token (account-scoped)
|
|
16
|
+
* - `POST /password` — Change password (revokes all sessions and API tokens)
|
|
17
|
+
*
|
|
18
|
+
* Signup is separate — see `signup_routes.ts` for invite-gated account creation.
|
|
19
|
+
* Defaults are closed/safe: accounts are created through bootstrap, admin action, or invite.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
import { Blake3Hash } from '@fuzdev/fuz_util/hash_blake3.js';
|
|
25
|
+
import { clear_session_cookie } from './session_middleware.js';
|
|
26
|
+
import { create_session_and_set_cookie } from './session_lifecycle.js';
|
|
27
|
+
import { to_session_account, SessionAccountJson, AuthSessionJson, ClientApiTokenJson, UsernameProvided, } from './account_schema.js';
|
|
28
|
+
import { hash_session_token, query_session_revoke_by_hash, query_session_revoke_for_account, query_session_revoke_all_for_account, query_session_list_for_account, } from './session_queries.js';
|
|
29
|
+
import { query_account_by_username_or_email, query_update_account_password, } from './account_queries.js';
|
|
30
|
+
import { query_create_api_token, query_api_token_enforce_limit, query_api_token_list_for_account, query_revoke_api_token_for_account, query_revoke_all_api_tokens_for_account, } from './api_token_queries.js';
|
|
31
|
+
import { audit_log_fire_and_forget } from './audit_log_queries.js';
|
|
32
|
+
import { generate_api_token } from './api_token.js';
|
|
33
|
+
import { get_request_context, require_request_context } from './request_context.js';
|
|
34
|
+
import { get_route_input, get_route_params } from '../http/route_spec.js';
|
|
35
|
+
import { get_client_ip } from '../http/proxy.js';
|
|
36
|
+
import { rate_limit_exceeded_response } from '../rate_limiter.js';
|
|
37
|
+
import { Password, PasswordProvided } from './password.js';
|
|
38
|
+
import { ERROR_AUTHENTICATION_REQUIRED, ERROR_INVALID_CREDENTIALS } from '../http/error_schemas.js';
|
|
39
|
+
/**
|
|
40
|
+
* Create the account status route spec.
|
|
41
|
+
*
|
|
42
|
+
* Handles both authenticated and unauthenticated requests:
|
|
43
|
+
* - Authenticated: returns `{account}` with 200
|
|
44
|
+
* - Unauthenticated: returns 401 with optional `bootstrap_available` flag
|
|
45
|
+
*
|
|
46
|
+
* This eliminates the need for a separate `/health` fetch on page load —
|
|
47
|
+
* the frontend gets both session state and bootstrap availability in one request.
|
|
48
|
+
*
|
|
49
|
+
* @param options - optional configuration (bootstrap_status for bootstrap detection)
|
|
50
|
+
* @returns a single account status route spec
|
|
51
|
+
*/
|
|
52
|
+
export const create_account_status_route_spec = (options) => ({
|
|
53
|
+
method: 'GET',
|
|
54
|
+
path: options?.path ?? '/api/account/status',
|
|
55
|
+
auth: { type: 'none' },
|
|
56
|
+
description: 'Current account info (unauthenticated: 401 with bootstrap status)',
|
|
57
|
+
input: z.null(),
|
|
58
|
+
output: z.looseObject({ account: z.looseObject({}) }),
|
|
59
|
+
errors: {
|
|
60
|
+
401: z.looseObject({
|
|
61
|
+
error: z.literal(ERROR_AUTHENTICATION_REQUIRED),
|
|
62
|
+
bootstrap_available: z.boolean().optional(),
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
handler: (c) => {
|
|
66
|
+
const ctx = get_request_context(c);
|
|
67
|
+
if (ctx) {
|
|
68
|
+
return c.json({ account: to_session_account(ctx.account), permits: ctx.permits });
|
|
69
|
+
}
|
|
70
|
+
return c.json({
|
|
71
|
+
error: ERROR_AUTHENTICATION_REQUIRED,
|
|
72
|
+
...(options?.bootstrap_status?.available ? { bootstrap_available: true } : {}),
|
|
73
|
+
}, 401);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
/** Default maximum sessions per account. */
|
|
77
|
+
export const DEFAULT_MAX_SESSIONS = 5;
|
|
78
|
+
/** Default maximum API tokens per account. */
|
|
79
|
+
export const DEFAULT_MAX_TOKENS = 10;
|
|
80
|
+
/**
|
|
81
|
+
* Create account route specs for session-based auth.
|
|
82
|
+
*
|
|
83
|
+
* All session/token revocation is account-scoped to prevent cross-account attacks.
|
|
84
|
+
*
|
|
85
|
+
* @param deps - stateless capabilities (keyring, password, log)
|
|
86
|
+
* @param options - per-factory configuration (session_options, ip_rate_limiter, login_account_rate_limiter)
|
|
87
|
+
* @returns route specs (not yet applied to Hono)
|
|
88
|
+
*/
|
|
89
|
+
export const create_account_route_specs = (deps, options) => {
|
|
90
|
+
const { keyring, password, on_audit_event } = deps;
|
|
91
|
+
const { session_options, ip_rate_limiter, login_account_rate_limiter, max_sessions = DEFAULT_MAX_SESSIONS, max_tokens = DEFAULT_MAX_TOKENS, } = options;
|
|
92
|
+
return [
|
|
93
|
+
{
|
|
94
|
+
method: 'POST',
|
|
95
|
+
path: '/login',
|
|
96
|
+
auth: { type: 'none' },
|
|
97
|
+
description: 'Exchange credentials for session',
|
|
98
|
+
input: z.strictObject({
|
|
99
|
+
username: UsernameProvided,
|
|
100
|
+
password: PasswordProvided,
|
|
101
|
+
}),
|
|
102
|
+
output: z.strictObject({ ok: z.literal(true) }),
|
|
103
|
+
rate_limit: 'both',
|
|
104
|
+
errors: { 401: z.looseObject({ error: z.literal(ERROR_INVALID_CREDENTIALS) }) },
|
|
105
|
+
handler: async (c, route) => {
|
|
106
|
+
// Per-IP rate limit check (before any DB/password work)
|
|
107
|
+
const ip = ip_rate_limiter ? get_client_ip(c) : null;
|
|
108
|
+
if (ip_rate_limiter && ip) {
|
|
109
|
+
const check = ip_rate_limiter.check(ip);
|
|
110
|
+
if (!check.allowed) {
|
|
111
|
+
return rate_limit_exceeded_response(c, check.retry_after);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const { username: raw_username, password: pw } = get_route_input(c);
|
|
115
|
+
const username = raw_username.trim().toLowerCase();
|
|
116
|
+
// Per-account rate limit check (after input parsing, before DB work)
|
|
117
|
+
if (login_account_rate_limiter) {
|
|
118
|
+
const check = login_account_rate_limiter.check(username);
|
|
119
|
+
if (!check.allowed) {
|
|
120
|
+
return rate_limit_exceeded_response(c, check.retry_after);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const account = await query_account_by_username_or_email(route, username);
|
|
124
|
+
if (!account) {
|
|
125
|
+
// enumeration prevention: verify_dummy equalizes timing, and both failure
|
|
126
|
+
// paths return identical errors with identical rate limiting behavior
|
|
127
|
+
await password.verify_dummy(pw);
|
|
128
|
+
if (ip_rate_limiter && ip)
|
|
129
|
+
ip_rate_limiter.record(ip);
|
|
130
|
+
if (login_account_rate_limiter)
|
|
131
|
+
login_account_rate_limiter.record(username);
|
|
132
|
+
void audit_log_fire_and_forget(route, {
|
|
133
|
+
event_type: 'login',
|
|
134
|
+
outcome: 'failure',
|
|
135
|
+
ip: get_client_ip(c),
|
|
136
|
+
metadata: { username },
|
|
137
|
+
}, deps.log, on_audit_event);
|
|
138
|
+
return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
|
|
139
|
+
}
|
|
140
|
+
const valid = await password.verify_password(pw, account.password_hash);
|
|
141
|
+
if (!valid) {
|
|
142
|
+
if (ip_rate_limiter && ip)
|
|
143
|
+
ip_rate_limiter.record(ip);
|
|
144
|
+
if (login_account_rate_limiter)
|
|
145
|
+
login_account_rate_limiter.record(username);
|
|
146
|
+
void audit_log_fire_and_forget(route, {
|
|
147
|
+
event_type: 'login',
|
|
148
|
+
outcome: 'failure',
|
|
149
|
+
account_id: account.id,
|
|
150
|
+
ip: get_client_ip(c),
|
|
151
|
+
metadata: { username },
|
|
152
|
+
}, deps.log, on_audit_event);
|
|
153
|
+
return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
|
|
154
|
+
}
|
|
155
|
+
// Successful login — reset rate limits
|
|
156
|
+
if (ip_rate_limiter && ip)
|
|
157
|
+
ip_rate_limiter.reset(ip);
|
|
158
|
+
if (login_account_rate_limiter)
|
|
159
|
+
login_account_rate_limiter.reset(username);
|
|
160
|
+
await create_session_and_set_cookie({
|
|
161
|
+
keyring,
|
|
162
|
+
deps: route,
|
|
163
|
+
c,
|
|
164
|
+
account_id: account.id,
|
|
165
|
+
session_options,
|
|
166
|
+
max_sessions,
|
|
167
|
+
});
|
|
168
|
+
void audit_log_fire_and_forget(route, {
|
|
169
|
+
event_type: 'login',
|
|
170
|
+
account_id: account.id,
|
|
171
|
+
ip: get_client_ip(c),
|
|
172
|
+
}, deps.log, on_audit_event);
|
|
173
|
+
return c.json({ ok: true });
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
method: 'POST',
|
|
178
|
+
path: '/logout',
|
|
179
|
+
auth: { type: 'authenticated' },
|
|
180
|
+
description: 'Revoke current session and clear cookie',
|
|
181
|
+
input: z.null(),
|
|
182
|
+
output: z.strictObject({ ok: z.literal(true), username: z.string() }),
|
|
183
|
+
handler: async (c, route) => {
|
|
184
|
+
const ctx = require_request_context(c);
|
|
185
|
+
const session_token = c.get(session_options.context_key) ?? null;
|
|
186
|
+
if (session_token) {
|
|
187
|
+
const token_hash = hash_session_token(session_token);
|
|
188
|
+
await query_session_revoke_by_hash(route, token_hash);
|
|
189
|
+
}
|
|
190
|
+
clear_session_cookie(c, session_options);
|
|
191
|
+
void audit_log_fire_and_forget(route, {
|
|
192
|
+
event_type: 'logout',
|
|
193
|
+
actor_id: ctx.actor.id,
|
|
194
|
+
account_id: ctx.account.id,
|
|
195
|
+
ip: get_client_ip(c),
|
|
196
|
+
}, deps.log, on_audit_event);
|
|
197
|
+
return c.json({ ok: true, username: ctx.account.username });
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
method: 'GET',
|
|
202
|
+
path: '/verify',
|
|
203
|
+
auth: { type: 'authenticated' },
|
|
204
|
+
description: 'Check session validity',
|
|
205
|
+
input: z.null(),
|
|
206
|
+
output: z.strictObject({ ok: z.literal(true), account: SessionAccountJson }),
|
|
207
|
+
handler: (c) => {
|
|
208
|
+
const ctx = require_request_context(c);
|
|
209
|
+
return c.json({ ok: true, account: to_session_account(ctx.account) });
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
method: 'GET',
|
|
214
|
+
path: '/sessions',
|
|
215
|
+
auth: { type: 'authenticated' },
|
|
216
|
+
description: 'List auth sessions for current account',
|
|
217
|
+
input: z.null(),
|
|
218
|
+
output: z.strictObject({ sessions: z.array(AuthSessionJson) }),
|
|
219
|
+
handler: async (c, route) => {
|
|
220
|
+
const ctx = require_request_context(c);
|
|
221
|
+
const sessions = await query_session_list_for_account(route, ctx.account.id);
|
|
222
|
+
return c.json({ sessions });
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
method: 'POST',
|
|
227
|
+
path: '/sessions/:id/revoke',
|
|
228
|
+
auth: { type: 'authenticated' },
|
|
229
|
+
description: 'Revoke a single auth session (account-scoped)',
|
|
230
|
+
params: z.strictObject({ id: Blake3Hash }),
|
|
231
|
+
input: z.null(),
|
|
232
|
+
output: z.strictObject({ ok: z.literal(true), revoked: z.boolean() }),
|
|
233
|
+
handler: async (c, route) => {
|
|
234
|
+
const ctx = require_request_context(c);
|
|
235
|
+
const { id } = get_route_params(c);
|
|
236
|
+
const revoked = await query_session_revoke_for_account(route, id, ctx.account.id);
|
|
237
|
+
void audit_log_fire_and_forget(route, {
|
|
238
|
+
event_type: 'session_revoke',
|
|
239
|
+
outcome: revoked ? 'success' : 'failure',
|
|
240
|
+
actor_id: ctx.actor.id,
|
|
241
|
+
account_id: ctx.account.id,
|
|
242
|
+
ip: get_client_ip(c),
|
|
243
|
+
metadata: { session_id: id },
|
|
244
|
+
}, deps.log, on_audit_event);
|
|
245
|
+
return c.json({ ok: true, revoked });
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
method: 'POST',
|
|
250
|
+
path: '/sessions/revoke-all',
|
|
251
|
+
auth: { type: 'authenticated' },
|
|
252
|
+
description: 'Revoke all auth sessions for current account',
|
|
253
|
+
input: z.null(),
|
|
254
|
+
output: z.strictObject({ ok: z.literal(true), count: z.number() }),
|
|
255
|
+
handler: async (c, route) => {
|
|
256
|
+
const ctx = require_request_context(c);
|
|
257
|
+
const count = await query_session_revoke_all_for_account(route, ctx.account.id);
|
|
258
|
+
void audit_log_fire_and_forget(route, {
|
|
259
|
+
event_type: 'session_revoke_all',
|
|
260
|
+
actor_id: ctx.actor.id,
|
|
261
|
+
account_id: ctx.account.id,
|
|
262
|
+
ip: get_client_ip(c),
|
|
263
|
+
metadata: { count },
|
|
264
|
+
}, deps.log, on_audit_event);
|
|
265
|
+
return c.json({ ok: true, count });
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
method: 'POST',
|
|
270
|
+
path: '/tokens/create',
|
|
271
|
+
auth: { type: 'authenticated' },
|
|
272
|
+
description: 'Create API token (shown once)',
|
|
273
|
+
input: z.strictObject({
|
|
274
|
+
name: z.string().default('CLI token'),
|
|
275
|
+
}),
|
|
276
|
+
output: z.strictObject({
|
|
277
|
+
ok: z.literal(true),
|
|
278
|
+
token: z.string(),
|
|
279
|
+
id: z.string(),
|
|
280
|
+
name: z.string(),
|
|
281
|
+
}),
|
|
282
|
+
handler: async (c, route) => {
|
|
283
|
+
const ctx = require_request_context(c);
|
|
284
|
+
const { name } = get_route_input(c);
|
|
285
|
+
const { token, id, token_hash } = generate_api_token();
|
|
286
|
+
await query_create_api_token(route, id, ctx.account.id, name, token_hash);
|
|
287
|
+
if (max_tokens != null) {
|
|
288
|
+
await query_api_token_enforce_limit(route, ctx.account.id, max_tokens);
|
|
289
|
+
}
|
|
290
|
+
void audit_log_fire_and_forget(route, {
|
|
291
|
+
event_type: 'token_create',
|
|
292
|
+
actor_id: ctx.actor.id,
|
|
293
|
+
account_id: ctx.account.id,
|
|
294
|
+
ip: get_client_ip(c),
|
|
295
|
+
metadata: { token_id: id, name },
|
|
296
|
+
}, deps.log, on_audit_event);
|
|
297
|
+
return c.json({ ok: true, token, id, name });
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
method: 'GET',
|
|
302
|
+
path: '/tokens',
|
|
303
|
+
auth: { type: 'authenticated' },
|
|
304
|
+
description: 'List API tokens for current account',
|
|
305
|
+
input: z.null(),
|
|
306
|
+
output: z.strictObject({ tokens: z.array(ClientApiTokenJson) }),
|
|
307
|
+
handler: async (c, route) => {
|
|
308
|
+
const ctx = require_request_context(c);
|
|
309
|
+
const tokens = await query_api_token_list_for_account(route, ctx.account.id);
|
|
310
|
+
return c.json({ tokens });
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
method: 'POST',
|
|
315
|
+
path: '/tokens/:id/revoke',
|
|
316
|
+
auth: { type: 'authenticated' },
|
|
317
|
+
description: 'Revoke an API token (account-scoped)',
|
|
318
|
+
params: z.strictObject({ id: z.string().regex(/^tok_[A-Za-z0-9_-]{12}$/) }),
|
|
319
|
+
input: z.null(),
|
|
320
|
+
output: z.strictObject({ ok: z.literal(true), revoked: z.boolean() }),
|
|
321
|
+
handler: async (c, route) => {
|
|
322
|
+
const ctx = require_request_context(c);
|
|
323
|
+
const { id } = get_route_params(c);
|
|
324
|
+
const revoked = await query_revoke_api_token_for_account(route, id, ctx.account.id);
|
|
325
|
+
void audit_log_fire_and_forget(route, {
|
|
326
|
+
event_type: 'token_revoke',
|
|
327
|
+
outcome: revoked ? 'success' : 'failure',
|
|
328
|
+
actor_id: ctx.actor.id,
|
|
329
|
+
account_id: ctx.account.id,
|
|
330
|
+
ip: get_client_ip(c),
|
|
331
|
+
metadata: { token_id: id },
|
|
332
|
+
}, deps.log, on_audit_event);
|
|
333
|
+
return c.json({ ok: true, revoked });
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
method: 'POST',
|
|
338
|
+
path: '/password',
|
|
339
|
+
auth: { type: 'authenticated' },
|
|
340
|
+
description: 'Change password (revokes all sessions and API tokens)',
|
|
341
|
+
input: z.strictObject({
|
|
342
|
+
current_password: PasswordProvided,
|
|
343
|
+
new_password: Password,
|
|
344
|
+
}),
|
|
345
|
+
output: z.strictObject({
|
|
346
|
+
ok: z.literal(true),
|
|
347
|
+
sessions_revoked: z.number(),
|
|
348
|
+
tokens_revoked: z.number(),
|
|
349
|
+
}),
|
|
350
|
+
rate_limit: login_account_rate_limiter ? 'both' : 'ip',
|
|
351
|
+
handler: async (c, route) => {
|
|
352
|
+
// per-IP rate limit check (before argon2 work)
|
|
353
|
+
const ip = ip_rate_limiter ? get_client_ip(c) : null;
|
|
354
|
+
if (ip_rate_limiter && ip) {
|
|
355
|
+
const check = ip_rate_limiter.check(ip);
|
|
356
|
+
if (!check.allowed) {
|
|
357
|
+
return rate_limit_exceeded_response(c, check.retry_after);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const ctx = require_request_context(c);
|
|
361
|
+
const { current_password, new_password } = get_route_input(c);
|
|
362
|
+
// per-account rate limit check (after context resolution, before argon2 work)
|
|
363
|
+
if (login_account_rate_limiter) {
|
|
364
|
+
const check = login_account_rate_limiter.check(ctx.account.id);
|
|
365
|
+
if (!check.allowed) {
|
|
366
|
+
return rate_limit_exceeded_response(c, check.retry_after);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const valid = await password.verify_password(current_password, ctx.account.password_hash);
|
|
370
|
+
if (!valid) {
|
|
371
|
+
if (ip_rate_limiter && ip)
|
|
372
|
+
ip_rate_limiter.record(ip);
|
|
373
|
+
if (login_account_rate_limiter)
|
|
374
|
+
login_account_rate_limiter.record(ctx.account.id);
|
|
375
|
+
void audit_log_fire_and_forget(route, {
|
|
376
|
+
event_type: 'password_change',
|
|
377
|
+
outcome: 'failure',
|
|
378
|
+
actor_id: ctx.actor.id,
|
|
379
|
+
account_id: ctx.account.id,
|
|
380
|
+
ip: get_client_ip(c),
|
|
381
|
+
}, deps.log, on_audit_event);
|
|
382
|
+
return c.json({ error: ERROR_INVALID_CREDENTIALS }, 401);
|
|
383
|
+
}
|
|
384
|
+
// successful verification — reset rate limiters
|
|
385
|
+
if (ip_rate_limiter && ip)
|
|
386
|
+
ip_rate_limiter.reset(ip);
|
|
387
|
+
if (login_account_rate_limiter)
|
|
388
|
+
login_account_rate_limiter.reset(ctx.account.id);
|
|
389
|
+
const new_hash = await password.hash_password(new_password);
|
|
390
|
+
await query_update_account_password(route, ctx.account.id, new_hash, ctx.actor.id);
|
|
391
|
+
// revoke all sessions and API tokens (force re-auth everywhere)
|
|
392
|
+
const sessions_revoked = await query_session_revoke_all_for_account(route, ctx.account.id);
|
|
393
|
+
const tokens_revoked = await query_revoke_all_api_tokens_for_account(route, ctx.account.id);
|
|
394
|
+
clear_session_cookie(c, session_options);
|
|
395
|
+
void audit_log_fire_and_forget(route, {
|
|
396
|
+
event_type: 'password_change',
|
|
397
|
+
actor_id: ctx.actor.id,
|
|
398
|
+
account_id: ctx.account.id,
|
|
399
|
+
ip: get_client_ip(c),
|
|
400
|
+
metadata: { sessions_revoked, tokens_revoked },
|
|
401
|
+
}, deps.log, on_audit_event);
|
|
402
|
+
return c.json({ ok: true, sessions_revoked, tokens_revoked });
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
];
|
|
406
|
+
};
|