@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,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invite database queries.
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for the invite table — creating invites,
|
|
5
|
+
* finding unclaimed matches, claiming, and cleanup.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { assert_row } from '../db/assert_row.js';
|
|
10
|
+
/**
|
|
11
|
+
* Create a new invite.
|
|
12
|
+
*
|
|
13
|
+
* @param deps - query dependencies
|
|
14
|
+
* @param input - the invite fields
|
|
15
|
+
* @returns the created invite
|
|
16
|
+
*/
|
|
17
|
+
export const query_create_invite = async (deps, input) => {
|
|
18
|
+
const row = await deps.db.query_one(`INSERT INTO invite (email, username, created_by)
|
|
19
|
+
VALUES ($1, $2, $3)
|
|
20
|
+
RETURNING *`, [input.email ?? null, input.username ?? null, input.created_by]);
|
|
21
|
+
return assert_row(row, 'INSERT INTO invite');
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Find an unclaimed invite by email (case-insensitive).
|
|
25
|
+
*/
|
|
26
|
+
export const query_invite_find_unclaimed_by_email = async (deps, email) => {
|
|
27
|
+
return deps.db.query_one(`SELECT * FROM invite WHERE LOWER(email) = LOWER($1) AND claimed_at IS NULL`, [email]);
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Find an unclaimed invite by username (case-insensitive).
|
|
31
|
+
*/
|
|
32
|
+
export const query_invite_find_unclaimed_by_username = async (deps, username) => {
|
|
33
|
+
return deps.db.query_one(`SELECT * FROM invite WHERE LOWER(username) = LOWER($1) AND claimed_at IS NULL`, [username]);
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Find an unclaimed invite matching email and/or username using three scoping modes:
|
|
37
|
+
*
|
|
38
|
+
* - **Email-only invite** (email set, username NULL) → matches only if signup provides matching email.
|
|
39
|
+
* - **Username-only invite** (username set, email NULL) → matches only if signup provides matching username.
|
|
40
|
+
* - **Both-field invite** (both set) → requires BOTH email and username to match.
|
|
41
|
+
*
|
|
42
|
+
* @param deps - query dependencies
|
|
43
|
+
* @param email - email to match (or null if signup provides none)
|
|
44
|
+
* @param username - username to match
|
|
45
|
+
* @returns the matching invite, or `undefined`
|
|
46
|
+
*/
|
|
47
|
+
export const query_invite_find_unclaimed_match = async (deps, email, username) => {
|
|
48
|
+
return deps.db.query_one(`SELECT * FROM invite WHERE claimed_at IS NULL AND (
|
|
49
|
+
(email IS NOT NULL AND username IS NULL
|
|
50
|
+
AND $1::text IS NOT NULL AND LOWER(email) = LOWER($1::text))
|
|
51
|
+
OR
|
|
52
|
+
(username IS NOT NULL AND email IS NULL
|
|
53
|
+
AND LOWER(username) = LOWER($2))
|
|
54
|
+
OR
|
|
55
|
+
(email IS NOT NULL AND username IS NOT NULL
|
|
56
|
+
AND $1::text IS NOT NULL AND LOWER(email) = LOWER($1::text)
|
|
57
|
+
AND LOWER(username) = LOWER($2))
|
|
58
|
+
) ORDER BY created_at ASC, id ASC LIMIT 1`, [email, username]);
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Claim an invite by setting the claimed_by and claimed_at fields.
|
|
62
|
+
*
|
|
63
|
+
* @param deps - query dependencies
|
|
64
|
+
* @param invite_id - the invite to claim
|
|
65
|
+
* @param account_id - the account claiming the invite
|
|
66
|
+
* @returns true if the invite was claimed, false if already claimed or not found
|
|
67
|
+
*/
|
|
68
|
+
export const query_invite_claim = async (deps, invite_id, account_id) => {
|
|
69
|
+
const rows = await deps.db.query(`UPDATE invite SET claimed_by = $1, claimed_at = NOW()
|
|
70
|
+
WHERE id = $2 AND claimed_at IS NULL
|
|
71
|
+
RETURNING id`, [account_id, invite_id]);
|
|
72
|
+
return rows.length > 0;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* List all invites, newest first.
|
|
76
|
+
*/
|
|
77
|
+
export const query_invite_list_all = async (deps) => {
|
|
78
|
+
return deps.db.query(`SELECT * FROM invite ORDER BY created_at DESC`);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* List all invites with resolved creator/claimer usernames, newest first.
|
|
82
|
+
*
|
|
83
|
+
* @param deps - query dependencies
|
|
84
|
+
* @returns invites with `created_by_username` and `claimed_by_username`
|
|
85
|
+
*/
|
|
86
|
+
export const query_invite_list_all_with_usernames = async (deps) => {
|
|
87
|
+
return deps.db.query(`SELECT i.*,
|
|
88
|
+
act.name AS created_by_username,
|
|
89
|
+
a.username AS claimed_by_username
|
|
90
|
+
FROM invite i
|
|
91
|
+
LEFT JOIN actor act ON act.id = i.created_by
|
|
92
|
+
LEFT JOIN account a ON a.id = i.claimed_by
|
|
93
|
+
ORDER BY i.created_at DESC`);
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Delete an unclaimed invite.
|
|
97
|
+
*
|
|
98
|
+
* @param deps - query dependencies
|
|
99
|
+
* @param id - the invite id
|
|
100
|
+
* @returns true if deleted, false if not found or already claimed
|
|
101
|
+
*/
|
|
102
|
+
export const query_invite_delete_unclaimed = async (deps, id) => {
|
|
103
|
+
const rows = await deps.db.query(`DELETE FROM invite WHERE id = $1 AND claimed_at IS NULL RETURNING id`, [id]);
|
|
104
|
+
return rows.length > 0;
|
|
105
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin invite route specs for invite-based signup.
|
|
3
|
+
*
|
|
4
|
+
* All routes require the `admin` role. Provides CRUD for invites
|
|
5
|
+
* that gate who can sign up.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { type RouteSpec } from '../http/route_spec.js';
|
|
10
|
+
import type { RouteFactoryDeps } from './deps.js';
|
|
11
|
+
/**
|
|
12
|
+
* Create admin invite route specs.
|
|
13
|
+
*
|
|
14
|
+
* @param deps - stateless capabilities (log)
|
|
15
|
+
* @returns route specs for invite management
|
|
16
|
+
*/
|
|
17
|
+
export declare const create_invite_route_specs: (deps: Pick<RouteFactoryDeps, "log" | "on_audit_event">) => Array<RouteSpec>;
|
|
18
|
+
//# sourceMappingURL=invite_routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/invite_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAoC,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAYxF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAUhD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACrC,MAAM,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,gBAAgB,CAAC,KACpD,KAAK,CAAC,SAAS,CAwHjB,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin invite route specs for invite-based signup.
|
|
3
|
+
*
|
|
4
|
+
* All routes require the `admin` role. Provides CRUD for invites
|
|
5
|
+
* that gate who can sign up.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { get_route_input, get_route_params } from '../http/route_spec.js';
|
|
11
|
+
import { require_request_context } from './request_context.js';
|
|
12
|
+
import { get_client_ip } from '../http/proxy.js';
|
|
13
|
+
import { audit_log_fire_and_forget } from './audit_log_queries.js';
|
|
14
|
+
import { query_account_by_username, query_account_by_email } from './account_queries.js';
|
|
15
|
+
import { query_create_invite, query_invite_list_all_with_usernames, query_invite_delete_unclaimed, } from './invite_queries.js';
|
|
16
|
+
import { InviteJson, InviteWithUsernamesJson } from './invite_schema.js';
|
|
17
|
+
import { Username, Email } from './account_schema.js';
|
|
18
|
+
import { is_pg_unique_violation } from '../db/pg_error.js';
|
|
19
|
+
import { ERROR_INVITE_NOT_FOUND, ERROR_INVITE_MISSING_IDENTIFIER, ERROR_INVITE_DUPLICATE, ERROR_INVITE_ACCOUNT_EXISTS_USERNAME, ERROR_INVITE_ACCOUNT_EXISTS_EMAIL, } from '../http/error_schemas.js';
|
|
20
|
+
/**
|
|
21
|
+
* Create admin invite route specs.
|
|
22
|
+
*
|
|
23
|
+
* @param deps - stateless capabilities (log)
|
|
24
|
+
* @returns route specs for invite management
|
|
25
|
+
*/
|
|
26
|
+
export const create_invite_route_specs = (deps) => {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
method: 'POST',
|
|
30
|
+
path: '/invites',
|
|
31
|
+
auth: { type: 'role', role: 'admin' },
|
|
32
|
+
description: 'Create an invite',
|
|
33
|
+
input: z.strictObject({
|
|
34
|
+
email: Email.nullish(),
|
|
35
|
+
username: Username.nullish(),
|
|
36
|
+
}),
|
|
37
|
+
output: z.strictObject({ ok: z.literal(true), invite: InviteJson }),
|
|
38
|
+
errors: {
|
|
39
|
+
400: z.looseObject({ error: z.literal(ERROR_INVITE_MISSING_IDENTIFIER) }),
|
|
40
|
+
409: z.looseObject({
|
|
41
|
+
error: z.enum([
|
|
42
|
+
ERROR_INVITE_DUPLICATE,
|
|
43
|
+
ERROR_INVITE_ACCOUNT_EXISTS_USERNAME,
|
|
44
|
+
ERROR_INVITE_ACCOUNT_EXISTS_EMAIL,
|
|
45
|
+
]),
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
handler: async (c, route) => {
|
|
49
|
+
const ctx = require_request_context(c);
|
|
50
|
+
const { email, username } = get_route_input(c);
|
|
51
|
+
if (!email && !username) {
|
|
52
|
+
return c.json({ error: ERROR_INVITE_MISSING_IDENTIFIER }, 400);
|
|
53
|
+
}
|
|
54
|
+
if (username) {
|
|
55
|
+
const existing = await query_account_by_username(route, username);
|
|
56
|
+
if (existing) {
|
|
57
|
+
return c.json({ error: ERROR_INVITE_ACCOUNT_EXISTS_USERNAME }, 409);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (email) {
|
|
61
|
+
const existing = await query_account_by_email(route, email);
|
|
62
|
+
if (existing) {
|
|
63
|
+
return c.json({ error: ERROR_INVITE_ACCOUNT_EXISTS_EMAIL }, 409);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let invite;
|
|
67
|
+
try {
|
|
68
|
+
invite = await query_create_invite(route, {
|
|
69
|
+
email: email ?? null,
|
|
70
|
+
username: username ?? null,
|
|
71
|
+
created_by: ctx.actor.id,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
if (is_pg_unique_violation(e)) {
|
|
76
|
+
return c.json({ error: ERROR_INVITE_DUPLICATE }, 409);
|
|
77
|
+
}
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
void audit_log_fire_and_forget(route, {
|
|
81
|
+
event_type: 'invite_create',
|
|
82
|
+
actor_id: ctx.actor.id,
|
|
83
|
+
account_id: ctx.account.id,
|
|
84
|
+
ip: get_client_ip(c),
|
|
85
|
+
metadata: { invite_id: invite.id, email: email ?? null, username: username ?? null },
|
|
86
|
+
}, deps.log, deps.on_audit_event);
|
|
87
|
+
return c.json({ ok: true, invite });
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
method: 'GET',
|
|
92
|
+
path: '/invites',
|
|
93
|
+
auth: { type: 'role', role: 'admin' },
|
|
94
|
+
description: 'List all invites',
|
|
95
|
+
input: z.null(),
|
|
96
|
+
output: z.strictObject({ invites: z.array(InviteWithUsernamesJson) }),
|
|
97
|
+
handler: async (c, route) => {
|
|
98
|
+
const invites = await query_invite_list_all_with_usernames(route);
|
|
99
|
+
return c.json({ invites });
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
method: 'DELETE',
|
|
104
|
+
path: '/invites/:id',
|
|
105
|
+
auth: { type: 'role', role: 'admin' },
|
|
106
|
+
description: 'Delete an unclaimed invite',
|
|
107
|
+
params: z.strictObject({ id: z.uuid() }),
|
|
108
|
+
input: z.null(),
|
|
109
|
+
output: z.strictObject({ ok: z.literal(true) }),
|
|
110
|
+
errors: { 404: z.looseObject({ error: z.literal(ERROR_INVITE_NOT_FOUND) }) },
|
|
111
|
+
handler: async (c, route) => {
|
|
112
|
+
const { id } = get_route_params(c);
|
|
113
|
+
const deleted = await query_invite_delete_unclaimed(route, id);
|
|
114
|
+
if (!deleted) {
|
|
115
|
+
return c.json({ error: ERROR_INVITE_NOT_FOUND }, 404);
|
|
116
|
+
}
|
|
117
|
+
const ctx = require_request_context(c);
|
|
118
|
+
void audit_log_fire_and_forget(route, {
|
|
119
|
+
event_type: 'invite_delete',
|
|
120
|
+
actor_id: ctx.actor.id,
|
|
121
|
+
account_id: ctx.account.id,
|
|
122
|
+
ip: get_client_ip(c),
|
|
123
|
+
metadata: { invite_id: id },
|
|
124
|
+
}, deps.log, deps.on_audit_event);
|
|
125
|
+
return c.json({ ok: true });
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invite types and client-safe schemas.
|
|
3
|
+
*
|
|
4
|
+
* Defines the runtime types for the invite system: invite creation,
|
|
5
|
+
* matching, and claiming.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { Username, Email } from './account_schema.js';
|
|
11
|
+
/** Invite row from the database. */
|
|
12
|
+
export interface Invite {
|
|
13
|
+
id: string;
|
|
14
|
+
email: Email | null;
|
|
15
|
+
username: Username | null;
|
|
16
|
+
claimed_by: string | null;
|
|
17
|
+
claimed_at: string | null;
|
|
18
|
+
created_at: string;
|
|
19
|
+
created_by: string | null;
|
|
20
|
+
}
|
|
21
|
+
/** Zod schema for client-safe invite data. */
|
|
22
|
+
export declare const InviteJson: z.ZodObject<{
|
|
23
|
+
id: z.ZodString;
|
|
24
|
+
email: z.ZodNullable<z.ZodEmail>;
|
|
25
|
+
username: z.ZodNullable<z.ZodString>;
|
|
26
|
+
claimed_by: z.ZodNullable<z.ZodString>;
|
|
27
|
+
claimed_at: z.ZodNullable<z.ZodString>;
|
|
28
|
+
created_at: z.ZodString;
|
|
29
|
+
created_by: z.ZodNullable<z.ZodString>;
|
|
30
|
+
}, z.core.$strict>;
|
|
31
|
+
export type InviteJson = z.infer<typeof InviteJson>;
|
|
32
|
+
/** Zod schema for invite data with resolved creator/claimer usernames. */
|
|
33
|
+
export declare const InviteWithUsernamesJson: z.ZodObject<{
|
|
34
|
+
id: z.ZodString;
|
|
35
|
+
email: z.ZodNullable<z.ZodEmail>;
|
|
36
|
+
username: z.ZodNullable<z.ZodString>;
|
|
37
|
+
claimed_by: z.ZodNullable<z.ZodString>;
|
|
38
|
+
claimed_at: z.ZodNullable<z.ZodString>;
|
|
39
|
+
created_at: z.ZodString;
|
|
40
|
+
created_by: z.ZodNullable<z.ZodString>;
|
|
41
|
+
created_by_username: z.ZodNullable<z.ZodString>;
|
|
42
|
+
claimed_by_username: z.ZodNullable<z.ZodString>;
|
|
43
|
+
}, z.core.$strict>;
|
|
44
|
+
export type InviteWithUsernamesJson = z.infer<typeof InviteWithUsernamesJson>;
|
|
45
|
+
/** Input for creating an invite. */
|
|
46
|
+
export interface CreateInviteInput {
|
|
47
|
+
email?: Email | null;
|
|
48
|
+
username?: Username | null;
|
|
49
|
+
created_by: string | null;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=invite_schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/invite_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAEpD,oCAAoC;AACpC,MAAM,WAAW,MAAM;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,8CAA8C;AAC9C,eAAO,MAAM,UAAU;;;;;;;;kBAQrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB;;;;;;;;;;kBAGlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IACjC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invite types and client-safe schemas.
|
|
3
|
+
*
|
|
4
|
+
* Defines the runtime types for the invite system: invite creation,
|
|
5
|
+
* matching, and claiming.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { Username, Email } from './account_schema.js';
|
|
11
|
+
/** Zod schema for client-safe invite data. */
|
|
12
|
+
export const InviteJson = z.strictObject({
|
|
13
|
+
id: z.string(),
|
|
14
|
+
email: Email.nullable(),
|
|
15
|
+
username: Username.nullable(),
|
|
16
|
+
claimed_by: z.string().nullable(),
|
|
17
|
+
claimed_at: z.string().nullable(),
|
|
18
|
+
created_at: z.string(),
|
|
19
|
+
created_by: z.string().nullable(),
|
|
20
|
+
});
|
|
21
|
+
/** Zod schema for invite data with resolved creator/claimer usernames. */
|
|
22
|
+
export const InviteWithUsernamesJson = InviteJson.extend({
|
|
23
|
+
created_by_username: z.string().nullable(),
|
|
24
|
+
claimed_by_username: z.string().nullable(),
|
|
25
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key ring for cookie signing.
|
|
3
|
+
*
|
|
4
|
+
* Encapsulates secret keys and crypto operations. Keys are never exposed -
|
|
5
|
+
* only sign/verify operations are available. This prevents accidental
|
|
6
|
+
* logging or leakage of secrets.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const keyring = create_keyring(process.env.SECRET_COOKIE_KEYS);
|
|
11
|
+
* if (!keyring) throw new Error('No keys configured');
|
|
12
|
+
*
|
|
13
|
+
* const signed = await keyring.sign('user:123:1700000000');
|
|
14
|
+
* const result = await keyring.verify(signed);
|
|
15
|
+
* // result = { value: 'user:123:1700000000', key_index: 0 }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Opaque keyring that encapsulates secret keys.
|
|
22
|
+
* Only exposes sign/verify operations, never the raw keys.
|
|
23
|
+
*/
|
|
24
|
+
export interface Keyring {
|
|
25
|
+
/**
|
|
26
|
+
* Sign a value with HMAC SHA-256.
|
|
27
|
+
* @returns signed value in format: `value.signature`
|
|
28
|
+
*/
|
|
29
|
+
sign: (value: string) => Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Verify a signed value and extract the original.
|
|
32
|
+
* Tries all keys in order to support key rotation.
|
|
33
|
+
* @returns object with value and key_index, or null if invalid
|
|
34
|
+
*/
|
|
35
|
+
verify: (signed_value: string) => Promise<{
|
|
36
|
+
value: string;
|
|
37
|
+
key_index: number;
|
|
38
|
+
} | null>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a keyring from environment variable.
|
|
42
|
+
*
|
|
43
|
+
* Keys are separated by `__` for rotation support. First key is used
|
|
44
|
+
* for signing, all keys are tried for verification.
|
|
45
|
+
*
|
|
46
|
+
* CryptoKeys are cached on first use for performance.
|
|
47
|
+
*
|
|
48
|
+
* **Security: key rotation is an operational concern.** Old keys remain valid
|
|
49
|
+
* for verification indefinitely — a leaked old key can forge session cookies
|
|
50
|
+
* until it is removed from `SECRET_COOKIE_KEYS`. After rotating to a new
|
|
51
|
+
* signing key, remove the old key within a grace period (e.g. 24–48 hours,
|
|
52
|
+
* long enough for active sessions to re-sign with the new key via cookie
|
|
53
|
+
* refresh). Treat `SECRET_COOKIE_KEYS` changes as security-critical deploys.
|
|
54
|
+
*
|
|
55
|
+
* @param env_value - the SECRET_COOKIE_KEYS environment variable
|
|
56
|
+
* @returns keyring or null if no keys configured
|
|
57
|
+
*/
|
|
58
|
+
export declare const create_keyring: (env_value: string | undefined) => Keyring | null;
|
|
59
|
+
/**
|
|
60
|
+
* Validate key ring configuration.
|
|
61
|
+
*
|
|
62
|
+
* @param env_value - the SECRET_COOKIE_KEYS environment variable
|
|
63
|
+
* @returns array of validation errors (empty if valid)
|
|
64
|
+
*/
|
|
65
|
+
export declare const validate_keyring: (env_value: string | undefined) => Array<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Result of `create_validated_keyring`.
|
|
68
|
+
* Discriminated union — callers handle the error case their own way.
|
|
69
|
+
*/
|
|
70
|
+
export type ValidatedKeyringResult = {
|
|
71
|
+
ok: true;
|
|
72
|
+
keyring: Keyring;
|
|
73
|
+
} | {
|
|
74
|
+
ok: false;
|
|
75
|
+
errors: Array<string>;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Validate and create a keyring in one step.
|
|
79
|
+
*
|
|
80
|
+
* Returns a discriminated union so callers handle exit/logging their own way
|
|
81
|
+
* (e.g. `Deno.exit(1)` vs `runtime.exit(1)`).
|
|
82
|
+
*
|
|
83
|
+
* @param env_value - the SECRET_COOKIE_KEYS environment variable
|
|
84
|
+
* @returns `{ok: true, keyring}` or `{ok: false, errors}`
|
|
85
|
+
*/
|
|
86
|
+
export declare const create_validated_keyring: (env_value: string | undefined) => ValidatedKeyringResult;
|
|
87
|
+
//# sourceMappingURL=keyring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyring.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/keyring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzC;;;;OAIG;IACH,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI,CAAC,CAAC;CACrF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,OAAO,GAAG,IAkCxE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,KAAK,CAAC,MAAM,CAW5E,CAAC;AA6CF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAC/B;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,GAC5B;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAC,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,sBAUxE,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key ring for cookie signing.
|
|
3
|
+
*
|
|
4
|
+
* Encapsulates secret keys and crypto operations. Keys are never exposed -
|
|
5
|
+
* only sign/verify operations are available. This prevents accidental
|
|
6
|
+
* logging or leakage of secrets.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const keyring = create_keyring(process.env.SECRET_COOKIE_KEYS);
|
|
11
|
+
* if (!keyring) throw new Error('No keys configured');
|
|
12
|
+
*
|
|
13
|
+
* const signed = await keyring.sign('user:123:1700000000');
|
|
14
|
+
* const result = await keyring.verify(signed);
|
|
15
|
+
* // result = { value: 'user:123:1700000000', key_index: 0 }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
const KEY_SEPARATOR = '__';
|
|
21
|
+
const MIN_KEY_LENGTH = 32;
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
/**
|
|
24
|
+
* Create a keyring from environment variable.
|
|
25
|
+
*
|
|
26
|
+
* Keys are separated by `__` for rotation support. First key is used
|
|
27
|
+
* for signing, all keys are tried for verification.
|
|
28
|
+
*
|
|
29
|
+
* CryptoKeys are cached on first use for performance.
|
|
30
|
+
*
|
|
31
|
+
* **Security: key rotation is an operational concern.** Old keys remain valid
|
|
32
|
+
* for verification indefinitely — a leaked old key can forge session cookies
|
|
33
|
+
* until it is removed from `SECRET_COOKIE_KEYS`. After rotating to a new
|
|
34
|
+
* signing key, remove the old key within a grace period (e.g. 24–48 hours,
|
|
35
|
+
* long enough for active sessions to re-sign with the new key via cookie
|
|
36
|
+
* refresh). Treat `SECRET_COOKIE_KEYS` changes as security-critical deploys.
|
|
37
|
+
*
|
|
38
|
+
* @param env_value - the SECRET_COOKIE_KEYS environment variable
|
|
39
|
+
* @returns keyring or null if no keys configured
|
|
40
|
+
*/
|
|
41
|
+
export const create_keyring = (env_value) => {
|
|
42
|
+
const secrets = parse_keys(env_value);
|
|
43
|
+
if (secrets.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
// Cache CryptoKey promises - imported once on first use
|
|
46
|
+
const key_cache = [];
|
|
47
|
+
const get_key = (index) => {
|
|
48
|
+
if (!key_cache[index]) {
|
|
49
|
+
key_cache[index] = create_hmac_key(secrets[index]);
|
|
50
|
+
}
|
|
51
|
+
return key_cache[index];
|
|
52
|
+
};
|
|
53
|
+
// Create the opaque key ring - secrets captured in closure, never exposed
|
|
54
|
+
return {
|
|
55
|
+
async sign(value) {
|
|
56
|
+
const key = await get_key(0);
|
|
57
|
+
return sign_with_crypto_key(value, key);
|
|
58
|
+
},
|
|
59
|
+
async verify(signed_value) {
|
|
60
|
+
for (let i = 0; i < secrets.length; i++) {
|
|
61
|
+
// eslint-disable-next-line no-await-in-loop
|
|
62
|
+
const key = await get_key(i);
|
|
63
|
+
// eslint-disable-next-line no-await-in-loop
|
|
64
|
+
const result = await verify_with_crypto_key(signed_value, key);
|
|
65
|
+
if (result !== false) {
|
|
66
|
+
return { value: result, key_index: i };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Validate key ring configuration.
|
|
75
|
+
*
|
|
76
|
+
* @param env_value - the SECRET_COOKIE_KEYS environment variable
|
|
77
|
+
* @returns array of validation errors (empty if valid)
|
|
78
|
+
*/
|
|
79
|
+
export const validate_keyring = (env_value) => {
|
|
80
|
+
const keys = parse_keys(env_value);
|
|
81
|
+
const errors = [];
|
|
82
|
+
for (const [i, key] of keys.entries()) {
|
|
83
|
+
if (key.length < MIN_KEY_LENGTH) {
|
|
84
|
+
errors.push(`Key ${i + 1} is too short (${key.length} chars, min ${MIN_KEY_LENGTH})`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return errors;
|
|
88
|
+
};
|
|
89
|
+
const create_hmac_key = (secret) => {
|
|
90
|
+
return crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
|
|
91
|
+
};
|
|
92
|
+
const sign_with_crypto_key = async (value, key) => {
|
|
93
|
+
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(value));
|
|
94
|
+
const signature_base64 = btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
95
|
+
return `${value}.${signature_base64}`;
|
|
96
|
+
};
|
|
97
|
+
const verify_with_crypto_key = async (signed_value, key) => {
|
|
98
|
+
const dot_index = signed_value.lastIndexOf('.');
|
|
99
|
+
if (dot_index === -1)
|
|
100
|
+
return false;
|
|
101
|
+
const value = signed_value.slice(0, dot_index);
|
|
102
|
+
const signature_base64 = signed_value.slice(dot_index + 1);
|
|
103
|
+
let signature;
|
|
104
|
+
try {
|
|
105
|
+
const decoded = atob(signature_base64);
|
|
106
|
+
const bytes = new Uint8Array(decoded.length);
|
|
107
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
108
|
+
bytes[i] = decoded.charCodeAt(i);
|
|
109
|
+
}
|
|
110
|
+
signature = bytes.buffer;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
const valid = await crypto.subtle.verify('HMAC', key, signature, encoder.encode(value));
|
|
116
|
+
return valid ? value : false;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Validate and create a keyring in one step.
|
|
120
|
+
*
|
|
121
|
+
* Returns a discriminated union so callers handle exit/logging their own way
|
|
122
|
+
* (e.g. `Deno.exit(1)` vs `runtime.exit(1)`).
|
|
123
|
+
*
|
|
124
|
+
* @param env_value - the SECRET_COOKIE_KEYS environment variable
|
|
125
|
+
* @returns `{ok: true, keyring}` or `{ok: false, errors}`
|
|
126
|
+
*/
|
|
127
|
+
export const create_validated_keyring = (env_value) => {
|
|
128
|
+
const errors = validate_keyring(env_value);
|
|
129
|
+
if (errors.length > 0) {
|
|
130
|
+
return { ok: false, errors };
|
|
131
|
+
}
|
|
132
|
+
const keyring = create_keyring(env_value);
|
|
133
|
+
if (!keyring) {
|
|
134
|
+
return { ok: false, errors: ['SECRET_COOKIE_KEYS is required'] };
|
|
135
|
+
}
|
|
136
|
+
return { ok: true, keyring };
|
|
137
|
+
};
|
|
138
|
+
const parse_keys = (env_value) => {
|
|
139
|
+
if (!env_value)
|
|
140
|
+
return [];
|
|
141
|
+
return env_value.split(KEY_SEPARATOR).filter((k) => k.length > 0);
|
|
142
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth middleware stack factory.
|
|
3
|
+
*
|
|
4
|
+
* Creates the standard middleware layers (origin, session, request_context,
|
|
5
|
+
* bearer_auth, optional daemon_token) from configuration.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { SessionOptions } from './session_cookie.js';
|
|
10
|
+
import type { AppDeps } from './deps.js';
|
|
11
|
+
import type { DaemonTokenState } from './daemon_token.js';
|
|
12
|
+
import type { RateLimiter } from '../rate_limiter.js';
|
|
13
|
+
import type { MiddlewareSpec } from '../http/middleware_spec.js';
|
|
14
|
+
/**
|
|
15
|
+
* Per-factory configuration for the standard auth middleware stack.
|
|
16
|
+
*/
|
|
17
|
+
export interface AuthMiddlewareOptions {
|
|
18
|
+
allowed_origins: Array<RegExp>;
|
|
19
|
+
session_options: SessionOptions<string>;
|
|
20
|
+
/** Path pattern for middleware (default: `'/api/*'`). */
|
|
21
|
+
path?: string;
|
|
22
|
+
/** Daemon token state for keeper auth. Omit to disable daemon token middleware. */
|
|
23
|
+
daemon_token_state?: DaemonTokenState;
|
|
24
|
+
/** Rate limiter for bearer token auth attempts (per-IP). Pass `null` to disable. */
|
|
25
|
+
bearer_ip_rate_limiter: RateLimiter | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create the auth middleware stack.
|
|
29
|
+
*
|
|
30
|
+
* Returns `[origin, session, request_context, bearer_auth]` middleware specs
|
|
31
|
+
* for the given path pattern. When `daemon_token_state` is provided, appends
|
|
32
|
+
* a 5th `daemon_token` layer. Apps can append extra entries for non-standard
|
|
33
|
+
* paths (e.g., tx's `/tx` binary endpoint).
|
|
34
|
+
*
|
|
35
|
+
* @param deps - stateless capabilities (keyring, db)
|
|
36
|
+
* @param options - middleware configuration (allowed_origins, session_options, path, daemon_token_state)
|
|
37
|
+
* @returns the middleware spec array
|
|
38
|
+
*/
|
|
39
|
+
export declare const create_auth_middleware_specs: (deps: AppDeps, options: AuthMiddlewareOptions) => Promise<Array<MiddlewareSpec>>;
|
|
40
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAG/D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,gBAAgB,CAAC;IACtC,oFAAoF;IACpF,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,GACxC,MAAM,OAAO,EACb,SAAS,qBAAqB,KAC5B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CA+D/B,CAAC"}
|