@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,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE (Server-Sent Events) streaming utilities for Hono.
|
|
3
|
+
*
|
|
4
|
+
* Provides generic helpers for creating SSE response streams
|
|
5
|
+
* and a notification type aligned with JSON-RPC 2.0.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { streamSSE } from 'hono/streaming';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { DEV } from 'esm-env';
|
|
12
|
+
/**
|
|
13
|
+
* Create an SSE response for a Hono context.
|
|
14
|
+
*
|
|
15
|
+
* Wraps Hono's `streamSSE` to provide a `{response, stream}` API
|
|
16
|
+
* compatible with `SubscriberRegistry` push-based broadcasting.
|
|
17
|
+
* The callback suspends via a promise that resolves on client disconnect
|
|
18
|
+
* or explicit `close()`, keeping the stream alive for external sends.
|
|
19
|
+
*
|
|
20
|
+
* Uses `hono_stream.write()` directly (not `writeSSE`) to avoid
|
|
21
|
+
* Hono's HTML callback resolution — keeps the same `data: JSON\n\n` format.
|
|
22
|
+
*
|
|
23
|
+
* @param c - Hono context
|
|
24
|
+
* @returns object with response and stream controller
|
|
25
|
+
*/
|
|
26
|
+
export const create_sse_response = (c, log) => {
|
|
27
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
28
|
+
const close_listeners = [];
|
|
29
|
+
let resolved = false;
|
|
30
|
+
const do_close = () => {
|
|
31
|
+
if (resolved)
|
|
32
|
+
return;
|
|
33
|
+
resolved = true;
|
|
34
|
+
resolve();
|
|
35
|
+
for (const fn of close_listeners) {
|
|
36
|
+
try {
|
|
37
|
+
fn();
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
log.error('on_close listener threw:', e);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
let sse_stream;
|
|
45
|
+
const response = streamSSE(c, async (hono_stream) => {
|
|
46
|
+
sse_stream = {
|
|
47
|
+
send(data) {
|
|
48
|
+
if (resolved || hono_stream.aborted)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
// JSON.stringify (no space arg) never produces literal newlines,
|
|
52
|
+
// so single-line `data:` framing is safe per the SSE spec.
|
|
53
|
+
void hono_stream.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
log.error('send failed to serialize data:', e);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
comment(text) {
|
|
60
|
+
if (resolved || hono_stream.aborted)
|
|
61
|
+
return;
|
|
62
|
+
void hono_stream.write(`: ${text}\n`);
|
|
63
|
+
},
|
|
64
|
+
close: do_close,
|
|
65
|
+
on_close(fn) {
|
|
66
|
+
close_listeners.push(fn);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
hono_stream.onAbort(do_close);
|
|
70
|
+
// flush an SSE comment to push headers through proxies (Vite, nginx),
|
|
71
|
+
// ensuring EventSource fires onopen without waiting for the first data event
|
|
72
|
+
void hono_stream.write(SSE_CONNECTED_COMMENT);
|
|
73
|
+
await promise;
|
|
74
|
+
});
|
|
75
|
+
return { response, stream: sse_stream };
|
|
76
|
+
};
|
|
77
|
+
/** SSE comment sent on connect to flush headers through proxies. Exported for test assertions. */
|
|
78
|
+
export const SSE_CONNECTED_COMMENT = `: connected\n\n`;
|
|
79
|
+
/**
|
|
80
|
+
* Create a broadcaster that validates events in DEV mode.
|
|
81
|
+
*
|
|
82
|
+
* In DEV: warns on unknown methods and invalid params.
|
|
83
|
+
* In production: passes through with zero overhead.
|
|
84
|
+
*
|
|
85
|
+
* @param broadcaster - duck-typed broadcaster (e.g. `SubscriberRegistry`)
|
|
86
|
+
* @param event_specs - event specs to validate against
|
|
87
|
+
* @returns validated broadcaster wrapper (passthrough in production)
|
|
88
|
+
*/
|
|
89
|
+
export const create_validated_broadcaster = (broadcaster, event_specs, log) => {
|
|
90
|
+
if (!DEV) {
|
|
91
|
+
return broadcaster;
|
|
92
|
+
}
|
|
93
|
+
const spec_map = new Map(event_specs.map((s) => [s.method, s]));
|
|
94
|
+
return {
|
|
95
|
+
broadcast: (channel, data) => {
|
|
96
|
+
const spec = spec_map.get(data.method);
|
|
97
|
+
if (!spec) {
|
|
98
|
+
log.warn(`Unknown event method: '${data.method}'`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const result = spec.params.safeParse(data.params);
|
|
102
|
+
if (!result.success) {
|
|
103
|
+
log.warn(`Params mismatch for '${data.method}':`, result.error.issues);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
broadcaster.broadcast(channel, data);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE auth guard and convenience factory for audit log SSE.
|
|
3
|
+
*
|
|
4
|
+
* `create_sse_auth_guard` bridges audit events to `SubscriberRegistry.close_by_identity()`,
|
|
5
|
+
* closing SSE streams when a subscriber's access is revoked (role revocation or
|
|
6
|
+
* session invalidation).
|
|
7
|
+
*
|
|
8
|
+
* `create_audit_log_sse` is a convenience factory that combines the registry,
|
|
9
|
+
* guard, and broadcaster — making the secure path the easy path for consumers.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
14
|
+
import { type AuditLogEvent } from '../auth/audit_log_schema.js';
|
|
15
|
+
import { SubscriberRegistry } from './subscriber_registry.js';
|
|
16
|
+
import type { SseStream, SseNotification, SseEventSpec } from './sse.js';
|
|
17
|
+
/**
|
|
18
|
+
* Audit event types that trigger SSE stream disconnection.
|
|
19
|
+
*
|
|
20
|
+
* `permit_revoke` requires the revoked role to match the guard's `required_role`.
|
|
21
|
+
* `session_revoke_all` and `password_change` close unconditionally for the target account.
|
|
22
|
+
*/
|
|
23
|
+
export declare const DISCONNECT_EVENT_TYPES: ReadonlySet<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Create an audit event handler that closes SSE streams on auth changes.
|
|
26
|
+
*
|
|
27
|
+
* Closes streams when:
|
|
28
|
+
* - `permit_revoke` fires for the `required_role` targeting a connected subscriber
|
|
29
|
+
* - `session_revoke_all` targets a connected subscriber (consistent invalidation)
|
|
30
|
+
* - `password_change` targets a connected subscriber (sessions revoked implicitly)
|
|
31
|
+
*
|
|
32
|
+
* The registry must use `account_id` as the identity key when subscribing
|
|
33
|
+
* (passed as the third argument to `registry.subscribe()`).
|
|
34
|
+
*
|
|
35
|
+
* @param registry - the subscriber registry to guard
|
|
36
|
+
* @param required_role - the role that grants access to the SSE endpoint
|
|
37
|
+
* @param log - logger for disconnect events
|
|
38
|
+
* @returns an `on_audit_event` callback
|
|
39
|
+
*/
|
|
40
|
+
export declare const create_sse_auth_guard: <T>(registry: SubscriberRegistry<T>, required_role: string, log: Logger) => ((event: AuditLogEvent) => void);
|
|
41
|
+
/**
|
|
42
|
+
* Convenience factory result for audit log SSE.
|
|
43
|
+
*
|
|
44
|
+
* Satisfies `AuditLogRouteOptions['stream']` and provides the combined
|
|
45
|
+
* `on_audit_event` callback (broadcast + guard).
|
|
46
|
+
*/
|
|
47
|
+
export interface AuditLogSse {
|
|
48
|
+
/** Subscribe function — pass as part of `stream` option to `create_audit_log_route_specs`. */
|
|
49
|
+
subscribe: (stream: SseStream<SseNotification>, channels?: Array<string>, identity?: string) => () => void;
|
|
50
|
+
/** Logger — pass as part of `stream` option to `create_audit_log_route_specs`. */
|
|
51
|
+
log: Logger;
|
|
52
|
+
/** Combined broadcast + guard callback. Pass as `on_audit_event` on `CreateAppBackendOptions`. */
|
|
53
|
+
on_audit_event: (event: AuditLogEvent) => void;
|
|
54
|
+
/** The underlying registry — exposed for subscriber count monitoring. */
|
|
55
|
+
registry: SubscriberRegistry<SseNotification>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create a complete audit log SSE setup with broadcasting and auth guard.
|
|
59
|
+
*
|
|
60
|
+
* Combines `SubscriberRegistry`, `create_sse_auth_guard`, and the broadcast
|
|
61
|
+
* call into a single object. The result satisfies `AuditLogRouteOptions['stream']`
|
|
62
|
+
* and provides the `on_audit_event` callback for `CreateAppBackendOptions`.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const audit_sse = create_audit_log_sse({log});
|
|
67
|
+
*
|
|
68
|
+
* // In create_app_backend options:
|
|
69
|
+
* on_audit_event: audit_sse.on_audit_event,
|
|
70
|
+
*
|
|
71
|
+
* // In create_route_specs:
|
|
72
|
+
* create_audit_log_route_specs({stream: audit_sse});
|
|
73
|
+
*
|
|
74
|
+
* // In create_app_server options:
|
|
75
|
+
* event_specs: AUDIT_LOG_EVENT_SPECS,
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @param options - factory options
|
|
79
|
+
* @returns audit log SSE setup (stream options + on_audit_event + registry)
|
|
80
|
+
*/
|
|
81
|
+
/**
|
|
82
|
+
* SSE event specs for audit log events.
|
|
83
|
+
*
|
|
84
|
+
* One spec per `AUDIT_EVENT_TYPES` entry, all sharing the `AuditLogEventJson` params schema.
|
|
85
|
+
* Pass to `create_app_server`'s `event_specs` for surface generation and DEV validation.
|
|
86
|
+
*/
|
|
87
|
+
export declare const AUDIT_LOG_EVENT_SPECS: Array<SseEventSpec>;
|
|
88
|
+
export declare const create_audit_log_sse: (options: {
|
|
89
|
+
/** Role required to access the SSE endpoint. Default `'admin'`. */
|
|
90
|
+
role?: string;
|
|
91
|
+
log: Logger;
|
|
92
|
+
}) => AuditLogSse;
|
|
93
|
+
//# sourceMappingURL=sse_auth_guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse_auth_guard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse_auth_guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAGN,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAC,SAAS,EAAE,eAAe,EAAE,YAAY,EAAC,MAAM,UAAU,CAAC;AAEvE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAIrD,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACtC,UAAU,kBAAkB,CAAC,CAAC,CAAC,EAC/B,eAAe,MAAM,EACrB,KAAK,MAAM,KACT,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAqBjC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,8FAA8F;IAC9F,SAAS,EAAE,CACV,MAAM,EAAE,SAAS,CAAC,eAAe,CAAC,EAClC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,EACxB,QAAQ,CAAC,EAAE,MAAM,KACb,MAAM,IAAI,CAAC;IAChB,kFAAkF;IAClF,GAAG,EAAE,MAAM,CAAC;IACZ,kGAAkG;IAClG,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,yEAAyE;IACzE,QAAQ,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,YAAY,CAOrD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,SAAS;IAC7C,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ,KAAG,WAcH,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE auth guard and convenience factory for audit log SSE.
|
|
3
|
+
*
|
|
4
|
+
* `create_sse_auth_guard` bridges audit events to `SubscriberRegistry.close_by_identity()`,
|
|
5
|
+
* closing SSE streams when a subscriber's access is revoked (role revocation or
|
|
6
|
+
* session invalidation).
|
|
7
|
+
*
|
|
8
|
+
* `create_audit_log_sse` is a convenience factory that combines the registry,
|
|
9
|
+
* guard, and broadcaster — making the secure path the easy path for consumers.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { AUDIT_EVENT_TYPES, AuditLogEventJson, } from '../auth/audit_log_schema.js';
|
|
14
|
+
import { SubscriberRegistry } from './subscriber_registry.js';
|
|
15
|
+
/**
|
|
16
|
+
* Audit event types that trigger SSE stream disconnection.
|
|
17
|
+
*
|
|
18
|
+
* `permit_revoke` requires the revoked role to match the guard's `required_role`.
|
|
19
|
+
* `session_revoke_all` and `password_change` close unconditionally for the target account.
|
|
20
|
+
*/
|
|
21
|
+
export const DISCONNECT_EVENT_TYPES = new Set([
|
|
22
|
+
'permit_revoke', // role revoked — user lost access
|
|
23
|
+
'session_revoke_all', // all sessions invalidated — user should be kicked
|
|
24
|
+
'password_change', // password changed — all sessions revoked implicitly
|
|
25
|
+
]);
|
|
26
|
+
/**
|
|
27
|
+
* Create an audit event handler that closes SSE streams on auth changes.
|
|
28
|
+
*
|
|
29
|
+
* Closes streams when:
|
|
30
|
+
* - `permit_revoke` fires for the `required_role` targeting a connected subscriber
|
|
31
|
+
* - `session_revoke_all` targets a connected subscriber (consistent invalidation)
|
|
32
|
+
* - `password_change` targets a connected subscriber (sessions revoked implicitly)
|
|
33
|
+
*
|
|
34
|
+
* The registry must use `account_id` as the identity key when subscribing
|
|
35
|
+
* (passed as the third argument to `registry.subscribe()`).
|
|
36
|
+
*
|
|
37
|
+
* @param registry - the subscriber registry to guard
|
|
38
|
+
* @param required_role - the role that grants access to the SSE endpoint
|
|
39
|
+
* @param log - logger for disconnect events
|
|
40
|
+
* @returns an `on_audit_event` callback
|
|
41
|
+
*/
|
|
42
|
+
export const create_sse_auth_guard = (registry, required_role, log) => {
|
|
43
|
+
return (event) => {
|
|
44
|
+
if (!DISCONNECT_EVENT_TYPES.has(event.event_type))
|
|
45
|
+
return;
|
|
46
|
+
// permit_revoke requires matching the specific role
|
|
47
|
+
if (event.event_type === 'permit_revoke') {
|
|
48
|
+
if (event.metadata?.role !== required_role)
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// resolve the affected account — admin actions set target_account_id,
|
|
52
|
+
// self-service actions (password_change, own session_revoke_all) only set account_id
|
|
53
|
+
const target = event.target_account_id ?? event.account_id;
|
|
54
|
+
if (!target)
|
|
55
|
+
return;
|
|
56
|
+
const closed = registry.close_by_identity(target);
|
|
57
|
+
if (closed > 0) {
|
|
58
|
+
log.info(`SSE auth guard: closed ${closed} stream(s) for account ${target} (${event.event_type})`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Create a complete audit log SSE setup with broadcasting and auth guard.
|
|
64
|
+
*
|
|
65
|
+
* Combines `SubscriberRegistry`, `create_sse_auth_guard`, and the broadcast
|
|
66
|
+
* call into a single object. The result satisfies `AuditLogRouteOptions['stream']`
|
|
67
|
+
* and provides the `on_audit_event` callback for `CreateAppBackendOptions`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const audit_sse = create_audit_log_sse({log});
|
|
72
|
+
*
|
|
73
|
+
* // In create_app_backend options:
|
|
74
|
+
* on_audit_event: audit_sse.on_audit_event,
|
|
75
|
+
*
|
|
76
|
+
* // In create_route_specs:
|
|
77
|
+
* create_audit_log_route_specs({stream: audit_sse});
|
|
78
|
+
*
|
|
79
|
+
* // In create_app_server options:
|
|
80
|
+
* event_specs: AUDIT_LOG_EVENT_SPECS,
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @param options - factory options
|
|
84
|
+
* @returns audit log SSE setup (stream options + on_audit_event + registry)
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* SSE event specs for audit log events.
|
|
88
|
+
*
|
|
89
|
+
* One spec per `AUDIT_EVENT_TYPES` entry, all sharing the `AuditLogEventJson` params schema.
|
|
90
|
+
* Pass to `create_app_server`'s `event_specs` for surface generation and DEV validation.
|
|
91
|
+
*/
|
|
92
|
+
export const AUDIT_LOG_EVENT_SPECS = AUDIT_EVENT_TYPES.map((event_type) => ({
|
|
93
|
+
method: event_type,
|
|
94
|
+
params: AuditLogEventJson,
|
|
95
|
+
description: `Audit log: ${event_type.replaceAll('_', ' ')}`,
|
|
96
|
+
channel: 'audit_log',
|
|
97
|
+
}));
|
|
98
|
+
export const create_audit_log_sse = (options) => {
|
|
99
|
+
const role = options.role ?? 'admin';
|
|
100
|
+
const registry = new SubscriberRegistry();
|
|
101
|
+
const guard = create_sse_auth_guard(registry, role, options.log);
|
|
102
|
+
return {
|
|
103
|
+
subscribe: registry.subscribe.bind(registry),
|
|
104
|
+
log: options.log,
|
|
105
|
+
on_audit_event: (event) => {
|
|
106
|
+
registry.broadcast('audit_log', { method: event.event_type, params: event });
|
|
107
|
+
guard(event);
|
|
108
|
+
},
|
|
109
|
+
registry,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic subscriber registry for broadcasting to SSE clients.
|
|
3
|
+
*
|
|
4
|
+
* Supports channel-based filtering — subscribers connect with optional
|
|
5
|
+
* channel filters, and broadcasts reach only matching subscribers.
|
|
6
|
+
* Optional identity keys enable force-closing subscribers by identity
|
|
7
|
+
* (e.g., close all streams for a specific account when their permissions change).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { SseStream } from './sse.js';
|
|
12
|
+
export interface Subscriber<T> {
|
|
13
|
+
stream: SseStream<T>;
|
|
14
|
+
/** Channels this subscriber listens to. `null` means all channels. */
|
|
15
|
+
channels: Set<string> | null;
|
|
16
|
+
/** Optional identity key for targeted disconnection (e.g., account_id). */
|
|
17
|
+
identity: string | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generic subscriber registry with channel-based filtering and identity-keyed disconnection.
|
|
21
|
+
*
|
|
22
|
+
* Subscribers connect with optional channel filters and an optional identity key.
|
|
23
|
+
* Broadcasts go to a specific channel and reach only matching subscribers.
|
|
24
|
+
* `close_by_identity` force-closes all subscribers with a given identity —
|
|
25
|
+
* use for auth revocation (close streams when a user's permissions change).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const registry = new SubscriberRegistry<SseNotification>();
|
|
30
|
+
*
|
|
31
|
+
* // subscriber connects (from SSE endpoint)
|
|
32
|
+
* const unsubscribe = registry.subscribe(stream, ['runs']);
|
|
33
|
+
*
|
|
34
|
+
* // when a run changes
|
|
35
|
+
* registry.broadcast('runs', {method: 'run_created', params: {run}});
|
|
36
|
+
*
|
|
37
|
+
* // subscriber disconnects
|
|
38
|
+
* unsubscribe();
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* // identity-keyed subscription for auth revocation
|
|
44
|
+
* const unsubscribe = registry.subscribe(stream, ['audit_log'], account_id);
|
|
45
|
+
*
|
|
46
|
+
* // when admin revokes the user's role — close their streams
|
|
47
|
+
* registry.close_by_identity(account_id);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class SubscriberRegistry<T> {
|
|
51
|
+
#private;
|
|
52
|
+
/** Number of active subscribers. */
|
|
53
|
+
get count(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Add a subscriber.
|
|
56
|
+
*
|
|
57
|
+
* @param stream - SSE stream to send data to
|
|
58
|
+
* @param channels - channels to subscribe to (`undefined` or empty = all channels)
|
|
59
|
+
* @param identity - optional identity key for targeted disconnection
|
|
60
|
+
* @returns unsubscribe function
|
|
61
|
+
*/
|
|
62
|
+
subscribe(stream: SseStream<T>, channels?: Array<string>, identity?: string): () => void;
|
|
63
|
+
/**
|
|
64
|
+
* Broadcast data to all subscribers on a channel.
|
|
65
|
+
*
|
|
66
|
+
* Subscribers with no channel filter receive all broadcasts.
|
|
67
|
+
* Subscribers with a channel filter only receive matching broadcasts.
|
|
68
|
+
*
|
|
69
|
+
* @param channel - the channel to broadcast on
|
|
70
|
+
* @param data - the data to send
|
|
71
|
+
*/
|
|
72
|
+
broadcast(channel: string, data: T): void;
|
|
73
|
+
/**
|
|
74
|
+
* Force-close all subscribers with the given identity.
|
|
75
|
+
*
|
|
76
|
+
* Closes each matching stream and removes the subscriber from the registry.
|
|
77
|
+
* Use for auth revocation — when a user's permissions change, close their
|
|
78
|
+
* SSE connections so they must reconnect and re-authenticate.
|
|
79
|
+
*
|
|
80
|
+
* @param identity - the identity key to match
|
|
81
|
+
* @returns the number of subscribers closed
|
|
82
|
+
*/
|
|
83
|
+
close_by_identity(identity: string): number;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=subscriber_registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriber_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/subscriber_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,sEAAsE;IACtE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,kBAAkB,CAAC,CAAC;;IAGhC,oCAAoC;IACpC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;;;;;;OAOG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI;IAYxF;;;;;;;;OAQG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAQzC;;;;;;;;;OASG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAe3C"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic subscriber registry for broadcasting to SSE clients.
|
|
3
|
+
*
|
|
4
|
+
* Supports channel-based filtering — subscribers connect with optional
|
|
5
|
+
* channel filters, and broadcasts reach only matching subscribers.
|
|
6
|
+
* Optional identity keys enable force-closing subscribers by identity
|
|
7
|
+
* (e.g., close all streams for a specific account when their permissions change).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Generic subscriber registry with channel-based filtering and identity-keyed disconnection.
|
|
13
|
+
*
|
|
14
|
+
* Subscribers connect with optional channel filters and an optional identity key.
|
|
15
|
+
* Broadcasts go to a specific channel and reach only matching subscribers.
|
|
16
|
+
* `close_by_identity` force-closes all subscribers with a given identity —
|
|
17
|
+
* use for auth revocation (close streams when a user's permissions change).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const registry = new SubscriberRegistry<SseNotification>();
|
|
22
|
+
*
|
|
23
|
+
* // subscriber connects (from SSE endpoint)
|
|
24
|
+
* const unsubscribe = registry.subscribe(stream, ['runs']);
|
|
25
|
+
*
|
|
26
|
+
* // when a run changes
|
|
27
|
+
* registry.broadcast('runs', {method: 'run_created', params: {run}});
|
|
28
|
+
*
|
|
29
|
+
* // subscriber disconnects
|
|
30
|
+
* unsubscribe();
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // identity-keyed subscription for auth revocation
|
|
36
|
+
* const unsubscribe = registry.subscribe(stream, ['audit_log'], account_id);
|
|
37
|
+
*
|
|
38
|
+
* // when admin revokes the user's role — close their streams
|
|
39
|
+
* registry.close_by_identity(account_id);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class SubscriberRegistry {
|
|
43
|
+
#subscribers = new Set();
|
|
44
|
+
/** Number of active subscribers. */
|
|
45
|
+
get count() {
|
|
46
|
+
return this.#subscribers.size;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Add a subscriber.
|
|
50
|
+
*
|
|
51
|
+
* @param stream - SSE stream to send data to
|
|
52
|
+
* @param channels - channels to subscribe to (`undefined` or empty = all channels)
|
|
53
|
+
* @param identity - optional identity key for targeted disconnection
|
|
54
|
+
* @returns unsubscribe function
|
|
55
|
+
*/
|
|
56
|
+
subscribe(stream, channels, identity) {
|
|
57
|
+
const subscriber = {
|
|
58
|
+
stream,
|
|
59
|
+
channels: channels && channels.length > 0 ? new Set(channels) : null,
|
|
60
|
+
identity: identity ?? null,
|
|
61
|
+
};
|
|
62
|
+
this.#subscribers.add(subscriber);
|
|
63
|
+
return () => {
|
|
64
|
+
this.#subscribers.delete(subscriber);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Broadcast data to all subscribers on a channel.
|
|
69
|
+
*
|
|
70
|
+
* Subscribers with no channel filter receive all broadcasts.
|
|
71
|
+
* Subscribers with a channel filter only receive matching broadcasts.
|
|
72
|
+
*
|
|
73
|
+
* @param channel - the channel to broadcast on
|
|
74
|
+
* @param data - the data to send
|
|
75
|
+
*/
|
|
76
|
+
broadcast(channel, data) {
|
|
77
|
+
for (const subscriber of this.#subscribers) {
|
|
78
|
+
if (subscriber.channels === null || subscriber.channels.has(channel)) {
|
|
79
|
+
subscriber.stream.send(data);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Force-close all subscribers with the given identity.
|
|
85
|
+
*
|
|
86
|
+
* Closes each matching stream and removes the subscriber from the registry.
|
|
87
|
+
* Use for auth revocation — when a user's permissions change, close their
|
|
88
|
+
* SSE connections so they must reconnect and re-authenticate.
|
|
89
|
+
*
|
|
90
|
+
* @param identity - the identity key to match
|
|
91
|
+
* @returns the number of subscribers closed
|
|
92
|
+
*/
|
|
93
|
+
close_by_identity(identity) {
|
|
94
|
+
// collect first, then close — avoids mutating the Set during iteration
|
|
95
|
+
// (stream.close() fires on_close listeners which may call unsubscribe)
|
|
96
|
+
const to_close = [];
|
|
97
|
+
for (const subscriber of this.#subscribers) {
|
|
98
|
+
if (subscriber.identity === identity) {
|
|
99
|
+
to_close.push(subscriber);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const subscriber of to_close) {
|
|
103
|
+
subscriber.stream.close();
|
|
104
|
+
this.#subscribers.delete(subscriber);
|
|
105
|
+
}
|
|
106
|
+
return to_close.length;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deno implementation of `RuntimeDeps`.
|
|
3
|
+
*
|
|
4
|
+
* Provides `create_deno_runtime(args)` — a factory returning a `RuntimeDeps`
|
|
5
|
+
* backed by Deno APIs. Only imported by Deno entry points (compiled binaries
|
|
6
|
+
* for tx, zzz, etc.).
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { RuntimeDeps } from './deps.js';
|
|
11
|
+
/**
|
|
12
|
+
* Create a runtime backed by Deno APIs.
|
|
13
|
+
*
|
|
14
|
+
* Returns an object satisfying all `*Deps` interfaces from `deps.ts`.
|
|
15
|
+
* Pass to shared functions that accept `EnvDeps`, `FsReadDeps`, etc.
|
|
16
|
+
*
|
|
17
|
+
* @param args - CLI arguments (typically `Deno.args`)
|
|
18
|
+
* @returns runtime implementation using Deno APIs
|
|
19
|
+
*/
|
|
20
|
+
export declare const create_deno_runtime: (args: ReadonlyArray<string>) => RuntimeDeps;
|
|
21
|
+
//# sourceMappingURL=deno.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deno.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/deno.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAA4B,MAAM,WAAW,CAAC;AAoCtE;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,aAAa,CAAC,MAAM,CAAC,KAAG,WAmEhE,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deno implementation of `RuntimeDeps`.
|
|
3
|
+
*
|
|
4
|
+
* Provides `create_deno_runtime(args)` — a factory returning a `RuntimeDeps`
|
|
5
|
+
* backed by Deno APIs. Only imported by Deno entry points (compiled binaries
|
|
6
|
+
* for tx, zzz, etc.).
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Create a runtime backed by Deno APIs.
|
|
12
|
+
*
|
|
13
|
+
* Returns an object satisfying all `*Deps` interfaces from `deps.ts`.
|
|
14
|
+
* Pass to shared functions that accept `EnvDeps`, `FsReadDeps`, etc.
|
|
15
|
+
*
|
|
16
|
+
* @param args - CLI arguments (typically `Deno.args`)
|
|
17
|
+
* @returns runtime implementation using Deno APIs
|
|
18
|
+
*/
|
|
19
|
+
export const create_deno_runtime = (args) => ({
|
|
20
|
+
// === Environment ===
|
|
21
|
+
env_get: (name) => Deno.env.get(name),
|
|
22
|
+
env_set: (name, value) => Deno.env.set(name, value),
|
|
23
|
+
env_all: () => Deno.env.toObject(),
|
|
24
|
+
// === Process ===
|
|
25
|
+
args,
|
|
26
|
+
cwd: () => Deno.cwd(),
|
|
27
|
+
exit: (code) => Deno.exit(code),
|
|
28
|
+
// === Local File System ===
|
|
29
|
+
stat: async (path) => {
|
|
30
|
+
try {
|
|
31
|
+
const s = await Deno.stat(path);
|
|
32
|
+
return { is_file: s.isFile, is_directory: s.isDirectory };
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
mkdir: (path, options) => Deno.mkdir(path, options),
|
|
39
|
+
read_file: (path) => Deno.readTextFile(path),
|
|
40
|
+
write_file: (path, content) => Deno.writeTextFile(path, content),
|
|
41
|
+
rename: (old_path, new_path) => Deno.rename(old_path, new_path),
|
|
42
|
+
remove: (path, options) => Deno.remove(path, options),
|
|
43
|
+
// === Local Commands ===
|
|
44
|
+
run_command: async (cmd, args) => {
|
|
45
|
+
try {
|
|
46
|
+
const proc = new Deno.Command(cmd, {
|
|
47
|
+
args,
|
|
48
|
+
stdout: 'piped',
|
|
49
|
+
stderr: 'piped',
|
|
50
|
+
});
|
|
51
|
+
const result = await proc.output();
|
|
52
|
+
return {
|
|
53
|
+
success: result.code === 0,
|
|
54
|
+
code: result.code,
|
|
55
|
+
stdout: new TextDecoder().decode(result.stdout),
|
|
56
|
+
stderr: new TextDecoder().decode(result.stderr),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
code: 1,
|
|
64
|
+
stdout: '',
|
|
65
|
+
stderr: `Failed to execute command: ${message}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
run_command_inherit: async (cmd, args) => {
|
|
70
|
+
const proc = new Deno.Command(cmd, {
|
|
71
|
+
args,
|
|
72
|
+
stdout: 'inherit',
|
|
73
|
+
stderr: 'inherit',
|
|
74
|
+
});
|
|
75
|
+
const result = await proc.output();
|
|
76
|
+
return result.code;
|
|
77
|
+
},
|
|
78
|
+
// === Terminal I/O ===
|
|
79
|
+
stdout_write: (data) => Deno.stdout.write(data),
|
|
80
|
+
stdin_read: (buffer) => Deno.stdin.read(buffer),
|
|
81
|
+
// === Logging ===
|
|
82
|
+
warn: (...args) => console.warn(...args),
|
|
83
|
+
});
|