@antasphere/chassis-server 1.0.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 +82 -0
- package/dist/accounts/deletion.d.ts +163 -0
- package/dist/accounts/deletion.d.ts.map +1 -0
- package/dist/accounts/deletion.js +360 -0
- package/dist/accounts/deletion.js.map +1 -0
- package/dist/accounts/erasure-log.d.ts +66 -0
- package/dist/accounts/erasure-log.d.ts.map +1 -0
- package/dist/accounts/erasure-log.js +117 -0
- package/dist/accounts/erasure-log.js.map +1 -0
- package/dist/accounts/index.d.ts +6 -0
- package/dist/accounts/index.d.ts.map +1 -0
- package/dist/accounts/index.js +6 -0
- package/dist/accounts/index.js.map +1 -0
- package/dist/accounts/mint-refusal.d.ts +47 -0
- package/dist/accounts/mint-refusal.d.ts.map +1 -0
- package/dist/accounts/mint-refusal.js +59 -0
- package/dist/accounts/mint-refusal.js.map +1 -0
- package/dist/accounts/signup-duplicate.d.ts +14 -0
- package/dist/accounts/signup-duplicate.d.ts.map +1 -0
- package/dist/accounts/signup-duplicate.js +25 -0
- package/dist/accounts/signup-duplicate.js.map +1 -0
- package/dist/accounts/superadmin.d.ts +27 -0
- package/dist/accounts/superadmin.d.ts.map +1 -0
- package/dist/accounts/superadmin.js +46 -0
- package/dist/accounts/superadmin.js.map +1 -0
- package/dist/api/apikeys.d.ts +14 -0
- package/dist/api/apikeys.d.ts.map +1 -0
- package/dist/api/apikeys.js +124 -0
- package/dist/api/apikeys.js.map +1 -0
- package/dist/api/audit.d.ts +4 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +75 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/break-glass.d.ts +48 -0
- package/dist/api/break-glass.d.ts.map +1 -0
- package/dist/api/break-glass.js +217 -0
- package/dist/api/break-glass.js.map +1 -0
- package/dist/api/cli-auth.d.ts +84 -0
- package/dist/api/cli-auth.d.ts.map +1 -0
- package/dist/api/cli-auth.js +177 -0
- package/dist/api/cli-auth.js.map +1 -0
- package/dist/api/create-api.d.ts +123 -0
- package/dist/api/create-api.d.ts.map +1 -0
- package/dist/api/create-api.js +1165 -0
- package/dist/api/create-api.js.map +1 -0
- package/dist/api/demo-passes.d.ts +45 -0
- package/dist/api/demo-passes.d.ts.map +1 -0
- package/dist/api/demo-passes.js +143 -0
- package/dist/api/demo-passes.js.map +1 -0
- package/dist/api/errors.d.ts +5 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +5 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/export.d.ts +63 -0
- package/dist/api/export.d.ts.map +1 -0
- package/dist/api/export.js +393 -0
- package/dist/api/export.js.map +1 -0
- package/dist/api/files.d.ts +40 -0
- package/dist/api/files.d.ts.map +1 -0
- package/dist/api/files.js +150 -0
- package/dist/api/files.js.map +1 -0
- package/dist/api/index.d.ts +17 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +17 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/invitations.d.ts +50 -0
- package/dist/api/invitations.d.ts.map +1 -0
- package/dist/api/invitations.js +313 -0
- package/dist/api/invitations.js.map +1 -0
- package/dist/api/members.d.ts +25 -0
- package/dist/api/members.d.ts.map +1 -0
- package/dist/api/members.js +522 -0
- package/dist/api/members.js.map +1 -0
- package/dist/api/onboarding.d.ts +26 -0
- package/dist/api/onboarding.d.ts.map +1 -0
- package/dist/api/onboarding.js +23 -0
- package/dist/api/onboarding.js.map +1 -0
- package/dist/api/openapi-doc.d.ts +21 -0
- package/dist/api/openapi-doc.d.ts.map +1 -0
- package/dist/api/openapi-doc.js +25 -0
- package/dist/api/openapi-doc.js.map +1 -0
- package/dist/api/projects.d.ts +24 -0
- package/dist/api/projects.d.ts.map +1 -0
- package/dist/api/projects.js +624 -0
- package/dist/api/projects.js.map +1 -0
- package/dist/api/scope-routes.d.ts +12 -0
- package/dist/api/scope-routes.d.ts.map +1 -0
- package/dist/api/scope-routes.js +2 -0
- package/dist/api/scope-routes.js.map +1 -0
- package/dist/api/sso-connect.d.ts +70 -0
- package/dist/api/sso-connect.d.ts.map +1 -0
- package/dist/api/sso-connect.js +164 -0
- package/dist/api/sso-connect.js.map +1 -0
- package/dist/api/sso-logout.d.ts +41 -0
- package/dist/api/sso-logout.d.ts.map +1 -0
- package/dist/api/sso-logout.js +34 -0
- package/dist/api/sso-logout.js.map +1 -0
- package/dist/api/teams.d.ts +43 -0
- package/dist/api/teams.d.ts.map +1 -0
- package/dist/api/teams.js +447 -0
- package/dist/api/teams.js.map +1 -0
- package/dist/api/workspaces.d.ts +114 -0
- package/dist/api/workspaces.d.ts.map +1 -0
- package/dist/api/workspaces.js +462 -0
- package/dist/api/workspaces.js.map +1 -0
- package/dist/apikeys/index.d.ts +3 -0
- package/dist/apikeys/index.d.ts.map +1 -0
- package/dist/apikeys/index.js +3 -0
- package/dist/apikeys/index.js.map +1 -0
- package/dist/apikeys/peppers.d.ts +53 -0
- package/dist/apikeys/peppers.d.ts.map +1 -0
- package/dist/apikeys/peppers.js +97 -0
- package/dist/apikeys/peppers.js.map +1 -0
- package/dist/apikeys/service.d.ts +56 -0
- package/dist/apikeys/service.d.ts.map +1 -0
- package/dist/apikeys/service.js +196 -0
- package/dist/apikeys/service.js.map +1 -0
- package/dist/app.d.ts +65 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +142 -0
- package/dist/app.js.map +1 -0
- package/dist/audit/filters.d.ts +38 -0
- package/dist/audit/filters.d.ts.map +1 -0
- package/dist/audit/filters.js +97 -0
- package/dist/audit/filters.js.map +1 -0
- package/dist/audit/index.d.ts +3 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +3 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/service.d.ts +65 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +103 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/boot.d.ts +8 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +822 -0
- package/dist/boot.js.map +1 -0
- package/dist/constant-time.d.ts +3 -0
- package/dist/constant-time.d.ts.map +1 -0
- package/dist/constant-time.js +10 -0
- package/dist/constant-time.js.map +1 -0
- package/dist/email/driver.d.ts +16 -0
- package/dist/email/driver.d.ts.map +1 -0
- package/dist/email/driver.js +136 -0
- package/dist/email/driver.js.map +1 -0
- package/dist/email/index.d.ts +4 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +4 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/shell.d.ts +72 -0
- package/dist/email/shell.d.ts.map +1 -0
- package/dist/email/shell.js +146 -0
- package/dist/email/shell.js.map +1 -0
- package/dist/email/templates.d.ts +83 -0
- package/dist/email/templates.d.ts.map +1 -0
- package/dist/email/templates.js +96 -0
- package/dist/email/templates.js.map +1 -0
- package/dist/entitlements/check.d.ts +140 -0
- package/dist/entitlements/check.d.ts.map +1 -0
- package/dist/entitlements/check.js +276 -0
- package/dist/entitlements/check.js.map +1 -0
- package/dist/entitlements/clock-skew.d.ts +27 -0
- package/dist/entitlements/clock-skew.d.ts.map +1 -0
- package/dist/entitlements/clock-skew.js +58 -0
- package/dist/entitlements/clock-skew.js.map +1 -0
- package/dist/entitlements/gate.d.ts +113 -0
- package/dist/entitlements/gate.d.ts.map +1 -0
- package/dist/entitlements/gate.js +430 -0
- package/dist/entitlements/gate.js.map +1 -0
- package/dist/entitlements/hub-machine-token.d.ts +83 -0
- package/dist/entitlements/hub-machine-token.d.ts.map +1 -0
- package/dist/entitlements/hub-machine-token.js +175 -0
- package/dist/entitlements/hub-machine-token.js.map +1 -0
- package/dist/entitlements/hub-subject.d.ts +32 -0
- package/dist/entitlements/hub-subject.d.ts.map +1 -0
- package/dist/entitlements/hub-subject.js +68 -0
- package/dist/entitlements/hub-subject.js.map +1 -0
- package/dist/entitlements/index.d.ts +9 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +9 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/entitlements/poster.d.ts +81 -0
- package/dist/entitlements/poster.d.ts.map +1 -0
- package/dist/entitlements/poster.js +169 -0
- package/dist/entitlements/poster.js.map +1 -0
- package/dist/entitlements/profiles.d.ts +121 -0
- package/dist/entitlements/profiles.d.ts.map +1 -0
- package/dist/entitlements/profiles.js +212 -0
- package/dist/entitlements/profiles.js.map +1 -0
- package/dist/entitlements/slot.d.ts +33 -0
- package/dist/entitlements/slot.d.ts.map +1 -0
- package/dist/entitlements/slot.js +75 -0
- package/dist/entitlements/slot.js.map +1 -0
- package/dist/env.d.ts +293 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +383 -0
- package/dist/env.js.map +1 -0
- package/dist/files/http.d.ts +23 -0
- package/dist/files/http.d.ts.map +1 -0
- package/dist/files/http.js +66 -0
- package/dist/files/http.js.map +1 -0
- package/dist/files/index.d.ts +5 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +5 -0
- package/dist/files/index.js.map +1 -0
- package/dist/files/serve.d.ts +43 -0
- package/dist/files/serve.d.ts.map +1 -0
- package/dist/files/serve.js +71 -0
- package/dist/files/serve.js.map +1 -0
- package/dist/files/service.d.ts +69 -0
- package/dist/files/service.d.ts.map +1 -0
- package/dist/files/service.js +188 -0
- package/dist/files/service.js.map +1 -0
- package/dist/files/spool.d.ts +21 -0
- package/dist/files/spool.d.ts.map +1 -0
- package/dist/files/spool.js +47 -0
- package/dist/files/spool.js.map +1 -0
- package/dist/identity/better-auth.d.ts +3927 -0
- package/dist/identity/better-auth.d.ts.map +1 -0
- package/dist/identity/better-auth.js +896 -0
- package/dist/identity/better-auth.js.map +1 -0
- package/dist/identity/demo-pass-plugin.d.ts +29 -0
- package/dist/identity/demo-pass-plugin.d.ts.map +1 -0
- package/dist/identity/demo-pass-plugin.js +88 -0
- package/dist/identity/demo-pass-plugin.js.map +1 -0
- package/dist/identity/demo-pass-rules.d.ts +84 -0
- package/dist/identity/demo-pass-rules.d.ts.map +1 -0
- package/dist/identity/demo-pass-rules.js +223 -0
- package/dist/identity/demo-pass-rules.js.map +1 -0
- package/dist/identity/demo-pass.d.ts +159 -0
- package/dist/identity/demo-pass.d.ts.map +1 -0
- package/dist/identity/demo-pass.js +319 -0
- package/dist/identity/demo-pass.js.map +1 -0
- package/dist/identity/hub-grant.d.ts +182 -0
- package/dist/identity/hub-grant.d.ts.map +1 -0
- package/dist/identity/hub-grant.js +594 -0
- package/dist/identity/hub-grant.js.map +1 -0
- package/dist/identity/hub-jwt.d.ts +22 -0
- package/dist/identity/hub-jwt.d.ts.map +1 -0
- package/dist/identity/hub-jwt.js +77 -0
- package/dist/identity/hub-jwt.js.map +1 -0
- package/dist/identity/hub-live-gate.d.ts +17 -0
- package/dist/identity/hub-live-gate.d.ts.map +1 -0
- package/dist/identity/hub-live-gate.js +146 -0
- package/dist/identity/hub-live-gate.js.map +1 -0
- package/dist/identity/hub-logout.d.ts +88 -0
- package/dist/identity/hub-logout.d.ts.map +1 -0
- package/dist/identity/hub-logout.js +158 -0
- package/dist/identity/hub-logout.js.map +1 -0
- package/dist/identity/hub-projection.d.ts +103 -0
- package/dist/identity/hub-projection.d.ts.map +1 -0
- package/dist/identity/hub-projection.js +130 -0
- package/dist/identity/hub-projection.js.map +1 -0
- package/dist/identity/hub-reconcile.d.ts +151 -0
- package/dist/identity/hub-reconcile.d.ts.map +1 -0
- package/dist/identity/hub-reconcile.js +400 -0
- package/dist/identity/hub-reconcile.js.map +1 -0
- package/dist/identity/hub-sso.d.ts +363 -0
- package/dist/identity/hub-sso.d.ts.map +1 -0
- package/dist/identity/hub-sso.js +536 -0
- package/dist/identity/hub-sso.js.map +1 -0
- package/dist/identity/hub-user-client.d.ts +222 -0
- package/dist/identity/hub-user-client.d.ts.map +1 -0
- package/dist/identity/hub-user-client.js +406 -0
- package/dist/identity/hub-user-client.js.map +1 -0
- package/dist/identity/index.d.ts +13 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +13 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/oauth-jwt.d.ts +32 -0
- package/dist/identity/oauth-jwt.d.ts.map +1 -0
- package/dist/identity/oauth-jwt.js +122 -0
- package/dist/identity/oauth-jwt.js.map +1 -0
- package/dist/identity/resolve-membership.d.ts +28 -0
- package/dist/identity/resolve-membership.d.ts.map +1 -0
- package/dist/identity/resolve-membership.js +69 -0
- package/dist/identity/resolve-membership.js.map +1 -0
- package/dist/identity/signing-key.d.ts +49 -0
- package/dist/identity/signing-key.d.ts.map +1 -0
- package/dist/identity/signing-key.js +144 -0
- package/dist/identity/signing-key.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/invitations/index.d.ts +2 -0
- package/dist/invitations/index.d.ts.map +1 -0
- package/dist/invitations/index.js +2 -0
- package/dist/invitations/index.js.map +1 -0
- package/dist/invitations/service.d.ts +36 -0
- package/dist/invitations/service.d.ts.map +1 -0
- package/dist/invitations/service.js +122 -0
- package/dist/invitations/service.js.map +1 -0
- package/dist/jobs/index.d.ts +3 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +3 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/pgboss.d.ts +119 -0
- package/dist/jobs/pgboss.d.ts.map +1 -0
- package/dist/jobs/pgboss.js +521 -0
- package/dist/jobs/pgboss.js.map +1 -0
- package/dist/jobs/timers.d.ts +127 -0
- package/dist/jobs/timers.d.ts.map +1 -0
- package/dist/jobs/timers.js +228 -0
- package/dist/jobs/timers.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +64 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/errors.d.ts +37 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +77 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/http.d.ts +35 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/http.js +80 -0
- package/dist/mcp/http.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/inputs.d.ts +19 -0
- package/dist/mcp/inputs.d.ts.map +1 -0
- package/dist/mcp/inputs.js +28 -0
- package/dist/mcp/inputs.js.map +1 -0
- package/dist/mcp/projects.d.ts +31 -0
- package/dist/mcp/projects.d.ts.map +1 -0
- package/dist/mcp/projects.js +315 -0
- package/dist/mcp/projects.js.map +1 -0
- package/dist/mcp/server.d.ts +52 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +93 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/teams.d.ts +7 -0
- package/dist/mcp/teams.d.ts.map +1 -0
- package/dist/mcp/teams.js +62 -0
- package/dist/mcp/teams.js.map +1 -0
- package/dist/mcp/tool-kit.d.ts +67 -0
- package/dist/mcp/tool-kit.d.ts.map +1 -0
- package/dist/mcp/tool-kit.js +74 -0
- package/dist/mcp/tool-kit.js.map +1 -0
- package/dist/members/removal.d.ts +95 -0
- package/dist/members/removal.d.ts.map +1 -0
- package/dist/members/removal.js +143 -0
- package/dist/members/removal.js.map +1 -0
- package/dist/middleware/auth-body.d.ts +25 -0
- package/dist/middleware/auth-body.d.ts.map +1 -0
- package/dist/middleware/auth-body.js +55 -0
- package/dist/middleware/auth-body.js.map +1 -0
- package/dist/middleware/auth-context.d.ts +170 -0
- package/dist/middleware/auth-context.d.ts.map +1 -0
- package/dist/middleware/auth-context.js +251 -0
- package/dist/middleware/auth-context.js.map +1 -0
- package/dist/middleware/body-cap.d.ts +17 -0
- package/dist/middleware/body-cap.d.ts.map +1 -0
- package/dist/middleware/body-cap.js +31 -0
- package/dist/middleware/body-cap.js.map +1 -0
- package/dist/middleware/body-refusal.d.ts +20 -0
- package/dist/middleware/body-refusal.d.ts.map +1 -0
- package/dist/middleware/body-refusal.js +5 -0
- package/dist/middleware/body-refusal.js.map +1 -0
- package/dist/middleware/cross-site.d.ts +61 -0
- package/dist/middleware/cross-site.d.ts.map +1 -0
- package/dist/middleware/cross-site.js +59 -0
- package/dist/middleware/cross-site.js.map +1 -0
- package/dist/middleware/hub-managed.d.ts +45 -0
- package/dist/middleware/hub-managed.d.ts.map +1 -0
- package/dist/middleware/hub-managed.js +56 -0
- package/dist/middleware/hub-managed.js.map +1 -0
- package/dist/middleware/idempotency.d.ts +14 -0
- package/dist/middleware/idempotency.d.ts.map +1 -0
- package/dist/middleware/idempotency.js +222 -0
- package/dist/middleware/idempotency.js.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +12 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/json-depth.d.ts +32 -0
- package/dist/middleware/json-depth.d.ts.map +1 -0
- package/dist/middleware/json-depth.js +80 -0
- package/dist/middleware/json-depth.js.map +1 -0
- package/dist/middleware/no-store.d.ts +21 -0
- package/dist/middleware/no-store.d.ts.map +1 -0
- package/dist/middleware/no-store.js +32 -0
- package/dist/middleware/no-store.js.map +1 -0
- package/dist/middleware/oauth-public.d.ts +16 -0
- package/dist/middleware/oauth-public.d.ts.map +1 -0
- package/dist/middleware/oauth-public.js +50 -0
- package/dist/middleware/oauth-public.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +182 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +277 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/request-id.d.ts +10 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +42 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/middleware/scopes.d.ts +33 -0
- package/dist/middleware/scopes.d.ts.map +1 -0
- package/dist/middleware/scopes.js +139 -0
- package/dist/middleware/scopes.js.map +1 -0
- package/dist/middleware/security-headers.d.ts +53 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +96 -0
- package/dist/middleware/security-headers.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +3 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/metrics.d.ts +17 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +82 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/otel.d.ts +20 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +54 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/pagination.d.ts +57 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +90 -0
- package/dist/pagination.js.map +1 -0
- package/dist/platform/edition.d.ts +57 -0
- package/dist/platform/edition.d.ts.map +1 -0
- package/dist/platform/edition.js +90 -0
- package/dist/platform/edition.js.map +1 -0
- package/dist/platform/entitlements.d.ts +26 -0
- package/dist/platform/entitlements.d.ts.map +1 -0
- package/dist/platform/entitlements.js +28 -0
- package/dist/platform/entitlements.js.map +1 -0
- package/dist/platform/events.d.ts +87 -0
- package/dist/platform/events.d.ts.map +1 -0
- package/dist/platform/events.js +32 -0
- package/dist/platform/events.js.map +1 -0
- package/dist/platform/index.d.ts +8 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +8 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/local-identity.d.ts +39 -0
- package/dist/platform/local-identity.d.ts.map +1 -0
- package/dist/platform/local-identity.js +87 -0
- package/dist/platform/local-identity.js.map +1 -0
- package/dist/platform/registry.d.ts +23 -0
- package/dist/platform/registry.d.ts.map +1 -0
- package/dist/platform/registry.js +5 -0
- package/dist/platform/registry.js.map +1 -0
- package/dist/platform/usage.d.ts +11 -0
- package/dist/platform/usage.d.ts.map +1 -0
- package/dist/platform/usage.js +12 -0
- package/dist/platform/usage.js.map +1 -0
- package/dist/platform/workspaces.d.ts +25 -0
- package/dist/platform/workspaces.d.ts.map +1 -0
- package/dist/platform/workspaces.js +44 -0
- package/dist/platform/workspaces.js.map +1 -0
- package/dist/projects/access.d.ts +40 -0
- package/dist/projects/access.d.ts.map +1 -0
- package/dist/projects/access.js +133 -0
- package/dist/projects/access.js.map +1 -0
- package/dist/projects/index.d.ts +2 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +2 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/route-label.d.ts +23 -0
- package/dist/route-label.d.ts.map +1 -0
- package/dist/route-label.js +29 -0
- package/dist/route-label.js.map +1 -0
- package/dist/routes/health.d.ts +30 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +54 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +3 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/wellknown.d.ts +11 -0
- package/dist/routes/wellknown.d.ts.map +1 -0
- package/dist/routes/wellknown.js +45 -0
- package/dist/routes/wellknown.js.map +1 -0
- package/dist/secret.d.ts +30 -0
- package/dist/secret.d.ts.map +1 -0
- package/dist/secret.js +97 -0
- package/dist/secret.js.map +1 -0
- package/dist/setup-transport.d.ts +23 -0
- package/dist/setup-transport.d.ts.map +1 -0
- package/dist/setup-transport.js +52 -0
- package/dist/setup-transport.js.map +1 -0
- package/dist/state.d.ts +21 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +4 -0
- package/dist/state.js.map +1 -0
- package/dist/storage/driver.d.ts +38 -0
- package/dist/storage/driver.d.ts.map +1 -0
- package/dist/storage/driver.js +14 -0
- package/dist/storage/driver.js.map +1 -0
- package/dist/storage/factory.d.ts +4 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/factory.js +20 -0
- package/dist/storage/factory.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +4 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/local.d.ts +21 -0
- package/dist/storage/local.d.ts.map +1 -0
- package/dist/storage/local.js +88 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/storage/s3.d.ts +29 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +82 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/testing/fake-hub.d.ts +425 -0
- package/dist/testing/fake-hub.d.ts.map +1 -0
- package/dist/testing/fake-hub.js +1074 -0
- package/dist/testing/fake-hub.js.map +1 -0
- package/dist/testing/helpers.d.ts +124 -0
- package/dist/testing/helpers.d.ts.map +1 -0
- package/dist/testing/helpers.js +174 -0
- package/dist/testing/helpers.js.map +1 -0
- package/dist/testing/index.d.ts +12 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +12 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/setup-origins.d.ts +21 -0
- package/dist/testing/setup-origins.d.ts.map +1 -0
- package/dist/testing/setup-origins.js +57 -0
- package/dist/testing/setup-origins.js.map +1 -0
- package/dist/testing/sso-helpers.d.ts +43 -0
- package/dist/testing/sso-helpers.d.ts.map +1 -0
- package/dist/testing/sso-helpers.js +159 -0
- package/dist/testing/sso-helpers.js.map +1 -0
- package/dist/tool-definition.d.ts +382 -0
- package/dist/tool-definition.d.ts.map +1 -0
- package/dist/tool-definition.js +46 -0
- package/dist/tool-definition.js.map +1 -0
- package/dist/util/index.d.ts +8 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +8 -0
- package/dist/util/index.js.map +1 -0
- package/package.json +161 -0
- package/src/accounts/deletion.ts +389 -0
- package/src/accounts/erasure-log.ts +140 -0
- package/src/accounts/index.ts +5 -0
- package/src/accounts/mint-refusal.ts +67 -0
- package/src/accounts/signup-duplicate.ts +21 -0
- package/src/accounts/superadmin.ts +46 -0
- package/src/api/apikeys.ts +147 -0
- package/src/api/audit.ts +83 -0
- package/src/api/break-glass.ts +294 -0
- package/src/api/cli-auth.ts +308 -0
- package/src/api/create-api.ts +1403 -0
- package/src/api/demo-passes.ts +207 -0
- package/src/api/errors.ts +13 -0
- package/src/api/export.ts +482 -0
- package/src/api/files.ts +200 -0
- package/src/api/index.ts +29 -0
- package/src/api/invitations.ts +396 -0
- package/src/api/members.ts +617 -0
- package/src/api/onboarding.ts +50 -0
- package/src/api/openapi-doc.ts +34 -0
- package/src/api/projects.ts +788 -0
- package/src/api/scope-routes.ts +12 -0
- package/src/api/sso-connect.ts +246 -0
- package/src/api/sso-logout.ts +76 -0
- package/src/api/teams.ts +575 -0
- package/src/api/workspaces.ts +649 -0
- package/src/apikeys/index.ts +2 -0
- package/src/apikeys/peppers.ts +118 -0
- package/src/apikeys/service.ts +223 -0
- package/src/app.ts +228 -0
- package/src/audit/filters.ts +101 -0
- package/src/audit/index.ts +9 -0
- package/src/audit/service.ts +154 -0
- package/src/boot.ts +953 -0
- package/src/constant-time.ts +9 -0
- package/src/email/driver.ts +139 -0
- package/src/email/index.ts +26 -0
- package/src/email/shell.ts +201 -0
- package/src/email/templates.ts +184 -0
- package/src/entitlements/check.ts +435 -0
- package/src/entitlements/clock-skew.ts +58 -0
- package/src/entitlements/gate.ts +636 -0
- package/src/entitlements/hub-machine-token.ts +205 -0
- package/src/entitlements/hub-subject.ts +77 -0
- package/src/entitlements/index.ts +37 -0
- package/src/entitlements/poster.ts +265 -0
- package/src/entitlements/profiles.ts +303 -0
- package/src/entitlements/slot.ts +105 -0
- package/src/env.ts +456 -0
- package/src/files/http.ts +77 -0
- package/src/files/index.ts +4 -0
- package/src/files/serve.ts +115 -0
- package/src/files/service.ts +209 -0
- package/src/files/spool.ts +58 -0
- package/src/identity/better-auth.ts +1103 -0
- package/src/identity/demo-pass-plugin.ts +121 -0
- package/src/identity/demo-pass-rules.ts +229 -0
- package/src/identity/demo-pass.ts +390 -0
- package/src/identity/hub-grant.ts +704 -0
- package/src/identity/hub-jwt.ts +78 -0
- package/src/identity/hub-live-gate.ts +167 -0
- package/src/identity/hub-logout.ts +174 -0
- package/src/identity/hub-projection.ts +251 -0
- package/src/identity/hub-reconcile.ts +572 -0
- package/src/identity/hub-sso.ts +696 -0
- package/src/identity/hub-user-client.ts +554 -0
- package/src/identity/index.ts +56 -0
- package/src/identity/oauth-jwt.ts +128 -0
- package/src/identity/resolve-membership.ts +104 -0
- package/src/identity/signing-key.ts +164 -0
- package/src/index.ts +65 -0
- package/src/invitations/index.ts +1 -0
- package/src/invitations/service.ts +171 -0
- package/src/jobs/index.ts +25 -0
- package/src/jobs/pgboss.ts +594 -0
- package/src/jobs/timers.ts +287 -0
- package/src/logger.ts +67 -0
- package/src/mcp/errors.ts +111 -0
- package/src/mcp/http.ts +129 -0
- package/src/mcp/index.ts +28 -0
- package/src/mcp/inputs.ts +33 -0
- package/src/mcp/projects.ts +480 -0
- package/src/mcp/server.ts +174 -0
- package/src/mcp/teams.ts +97 -0
- package/src/mcp/tool-kit.ts +148 -0
- package/src/members/removal.ts +216 -0
- package/src/middleware/auth-body.ts +58 -0
- package/src/middleware/auth-context.ts +384 -0
- package/src/middleware/body-cap.ts +33 -0
- package/src/middleware/body-refusal.ts +23 -0
- package/src/middleware/cross-site.ts +122 -0
- package/src/middleware/hub-managed.ts +61 -0
- package/src/middleware/idempotency.ts +264 -0
- package/src/middleware/index.ts +33 -0
- package/src/middleware/json-depth.ts +74 -0
- package/src/middleware/no-store.ts +30 -0
- package/src/middleware/oauth-public.ts +54 -0
- package/src/middleware/rate-limit.ts +432 -0
- package/src/middleware/request-id.ts +54 -0
- package/src/middleware/scopes.ts +150 -0
- package/src/middleware/security-headers.ts +129 -0
- package/src/observability/index.ts +2 -0
- package/src/observability/metrics.ts +102 -0
- package/src/observability/otel.ts +79 -0
- package/src/pagination.ts +118 -0
- package/src/platform/edition.ts +140 -0
- package/src/platform/entitlements.ts +47 -0
- package/src/platform/events.ts +71 -0
- package/src/platform/index.ts +7 -0
- package/src/platform/local-identity.ts +90 -0
- package/src/platform/registry.ts +28 -0
- package/src/platform/usage.ts +13 -0
- package/src/platform/workspaces.ts +41 -0
- package/src/projects/access.ts +160 -0
- package/src/projects/index.ts +7 -0
- package/src/route-label.ts +29 -0
- package/src/routes/health.ts +79 -0
- package/src/routes/index.ts +2 -0
- package/src/routes/wellknown.ts +67 -0
- package/src/secret.ts +115 -0
- package/src/setup-transport.ts +46 -0
- package/src/state.ts +23 -0
- package/src/storage/driver.ts +48 -0
- package/src/storage/factory.ts +34 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/local.ts +93 -0
- package/src/storage/s3.ts +109 -0
- package/src/testing/fake-hub.ts +1316 -0
- package/src/testing/helpers.ts +254 -0
- package/src/testing/index.ts +11 -0
- package/src/testing/setup-origins.ts +58 -0
- package/src/testing/sso-helpers.ts +178 -0
- package/src/tool-definition.ts +463 -0
- package/src/util/index.ts +17 -0
- package/test/fixtures/onboarding-backfill.sql +13 -0
- package/test/fixtures/operator-user-id-backfill.sql +18 -0
- package/test/host/dr-lib.sh +253 -0
- package/test/host/drizzle/0000_chassis_baseline.sql +438 -0
- package/test/host/drizzle/0001_last_owner_guard.sql +42 -0
- package/test/host/drizzle/meta/0000_snapshot.json +3566 -0
- package/test/host/drizzle/meta/_journal.json +20 -0
- package/test/host/drizzle.config.ts +17 -0
- package/test/host/identity.ts +41 -0
- package/test/host/minimal-host.ts +35 -0
- package/test/host/minimal-tool.ts +123 -0
- package/test/integration/account-oracle-uniformity.test.ts +284 -0
- package/test/integration/account-recovery.test.ts +236 -0
- package/test/integration/account.test.ts +120 -0
- package/test/integration/api-quota.test.ts +208 -0
- package/test/integration/apikey-expiry.test.ts +178 -0
- package/test/integration/apikey-pepper-rotation.test.ts +190 -0
- package/test/integration/boot-posture.test.ts +169 -0
- package/test/integration/break-glass.test.ts +484 -0
- package/test/integration/cloud-lifecycle.test.ts +233 -0
- package/test/integration/credential-boundaries.test.ts +195 -0
- package/test/integration/default-workspace.test.ts +414 -0
- package/test/integration/demo-pass-rules.test.ts +332 -0
- package/test/integration/demo-pass.test.ts +1222 -0
- package/test/integration/dr-verify-real-dump.test.ts +154 -0
- package/test/integration/edition.test.ts +868 -0
- package/test/integration/email-change.test.ts +394 -0
- package/test/integration/empty-tool.test.ts +267 -0
- package/test/integration/entitlements-null-hook.test.ts +187 -0
- package/test/integration/entitlements.test.ts +693 -0
- package/test/integration/export-entries.test.ts +321 -0
- package/test/integration/files.test.ts +320 -0
- package/test/integration/first-boot-claim.test.ts +131 -0
- package/test/integration/gdpr.test.ts +532 -0
- package/test/integration/helpers.ts +29 -0
- package/test/integration/hub-grant.test.ts +505 -0
- package/test/integration/hub-live-gate.test.ts +612 -0
- package/test/integration/hub-managed-membership.test.ts +559 -0
- package/test/integration/hub-org-selector.test.ts +281 -0
- package/test/integration/hub-reconcile.test.ts +646 -0
- package/test/integration/hub-sso.test.ts +704 -0
- package/test/integration/hub-teams.test.ts +771 -0
- package/test/integration/idempotency.test.ts +261 -0
- package/test/integration/invite-verification.test.ts +210 -0
- package/test/integration/last-owner-race.test.ts +263 -0
- package/test/integration/m9-fixes.test.ts +290 -0
- package/test/integration/mcp-projects.test.ts +463 -0
- package/test/integration/member-removal-race.test.ts +466 -0
- package/test/integration/member-removal.test.ts +794 -0
- package/test/integration/oauth-mcp.test.ts +477 -0
- package/test/integration/oauth-workspace.test.ts +371 -0
- package/test/integration/observability.test.ts +183 -0
- package/test/integration/onboarding.test.ts +268 -0
- package/test/integration/orphan-purge.test.ts +451 -0
- package/test/integration/pagination.test.ts +344 -0
- package/test/integration/platform-core.test.ts +305 -0
- package/test/integration/platform.test.ts +246 -0
- package/test/integration/pool-survives-restart.test.ts +80 -0
- package/test/integration/projects-cloud.test.ts +193 -0
- package/test/integration/projects.test.ts +1310 -0
- package/test/integration/security-fixes.test.ts +190 -0
- package/test/integration/setup-transport.test.ts +118 -0
- package/test/integration/signin-wall.test.ts +103 -0
- package/test/integration/signing-key-rotation.test.ts +349 -0
- package/test/integration/sso-helpers.ts +15 -0
- package/test/integration/sso-logout.test.ts +283 -0
- package/test/integration/teams-cloud.test.ts +194 -0
- package/test/integration/teams.test.ts +551 -0
- package/test/integration/timers.test.ts +377 -0
- package/test/integration/two-factor.test.ts +301 -0
- package/test/integration/usage-window.test.ts +161 -0
- package/test/integration/workspace-create-cloud.test.ts +523 -0
- package/test/integration/workspace-create.test.ts +510 -0
- package/test/integration/workspace-scoping.test.ts +530 -0
- package/test/integration/zz-adv-replay-owner.test.ts +205 -0
- package/test/unit/apikey-peppers.test.ts +110 -0
- package/test/unit/apikey-prefix.test.ts +34 -0
- package/test/unit/audit-filters.test.ts +135 -0
- package/test/unit/auth-origins.test.ts +92 -0
- package/test/unit/body-cap.test.ts +84 -0
- package/test/unit/clock-skew.test.ts +68 -0
- package/test/unit/cross-site.test.ts +166 -0
- package/test/unit/declared-credits.test.ts +13 -0
- package/test/unit/demo-pass-rules.test.ts +192 -0
- package/test/unit/email-driver.test.ts +127 -0
- package/test/unit/end-pool.test.ts +181 -0
- package/test/unit/entitlement-check.test.ts +492 -0
- package/test/unit/entitlement-gate.test.ts +1333 -0
- package/test/unit/entitlement-profiles.test.ts +289 -0
- package/test/unit/erasure-log.test.ts +72 -0
- package/test/unit/error-mapping.test.ts +89 -0
- package/test/unit/export-entries.test.ts +85 -0
- package/test/unit/export-sanitize.test.ts +27 -0
- package/test/unit/files-head-route.test.ts +155 -0
- package/test/unit/files-http.test.ts +97 -0
- package/test/unit/head-rewrite.test.ts +72 -0
- package/test/unit/hub-create-org.test.ts +181 -0
- package/test/unit/hub-jwt.test.ts +93 -0
- package/test/unit/hub-sso-params.test.ts +39 -0
- package/test/unit/hub-subject.test.ts +83 -0
- package/test/unit/idempotency-crypto.test.ts +45 -0
- package/test/unit/json-depth.test.ts +88 -0
- package/test/unit/logger-redaction.test.ts +66 -0
- package/test/unit/mcp-errors.test.ts +110 -0
- package/test/unit/mcp-inputs.test.ts +106 -0
- package/test/unit/mcp-project-hints.test.ts +26 -0
- package/test/unit/no-store.test.ts +49 -0
- package/test/unit/no-tool-migration-filename.test.ts +70 -0
- package/test/unit/observability.test.ts +64 -0
- package/test/unit/openapi-doc.test.ts +93 -0
- package/test/unit/rate-limit-consume-on.test.ts +76 -0
- package/test/unit/rate-limit.test.ts +39 -0
- package/test/unit/readyz-storage.test.ts +157 -0
- package/test/unit/request-quota.test.ts +146 -0
- package/test/unit/scopes.test.ts +66 -0
- package/test/unit/security-headers.test.ts +131 -0
- package/test/unit/serve-content-type.test.ts +74 -0
- package/test/unit/setup-transport.test.ts +29 -0
- package/test/unit/storage-local.test.ts +53 -0
- package/test/unit/superadmin.test.ts +32 -0
- package/test/unit/timers.test.ts +287 -0
- package/test/unit/tool-definition-guards.test.ts +166 -0
- package/test/unit/tool-entitlements-guard.test.ts +168 -0
- package/test/unit/usage-poster.test.ts +542 -0
- package/test/unit/usage-window.test.ts +48 -0
- package/test/unit/workspace-create-audit.test.ts +48 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import type { MiddlewareHandler } from 'hono';
|
|
3
|
+
import type { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
4
|
+
import { and, eq } from 'drizzle-orm';
|
|
5
|
+
import { idempotencyKeys, type Db } from '@antasphere/chassis-db';
|
|
6
|
+
import { apiError } from '../api/errors.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Idempotency-Key middleware: an opt-in `Idempotency-Key` request header on
|
|
10
|
+
* the non-idempotent create POSTs makes a network-blip retry replay the
|
|
11
|
+
* original response instead of double-creating. Claim-first: the row is
|
|
12
|
+
* inserted BEFORE the handler runs (the unique index is the mutex), so two
|
|
13
|
+
* concurrent requests with the same key can never both execute.
|
|
14
|
+
*
|
|
15
|
+
* Explicit target list, fail-closed style — only these consult it (the
|
|
16
|
+
* lines that say "the tool's" are the TOOL's, declared through `toolTargets`):
|
|
17
|
+
* POST /api/v1/api-keys
|
|
18
|
+
* POST /api/v1/invitations
|
|
19
|
+
* POST /api/v1/members/{id}/reset-link
|
|
20
|
+
* POST /api/v1/members/{id}/change-email-link (FUZZ-7, PRDCT-1354: the
|
|
21
|
+
* SECOND secret-minting member route, and the more dangerous one — its
|
|
22
|
+
* token is sign-in-equivalent. Its contract has always declared
|
|
23
|
+
* `Idempotency-Key` and a 409, but the claim never covered it, so a
|
|
24
|
+
* retried mint silently produced a SECOND live sign-in-equivalent JWT
|
|
25
|
+
* that cannot be revoked, on top of the first. The two mint routes must
|
|
26
|
+
* stay listed together.)
|
|
27
|
+
* the tool's token mint on one of its resources
|
|
28
|
+
* the tool's duplicate of a resource (PRDCT-2279: one click mints
|
|
29
|
+
* one copy; a network-blip retry must not mint a second copy)
|
|
30
|
+
* POST /api/v1/workspaces (PRDCT-2444/2443: one click mints one workspace;
|
|
31
|
+
* on cloud the retry would otherwise create a second organization at
|
|
32
|
+
* the hub. The claim is scoped to the caller's CURRENT workspace + user;
|
|
33
|
+
* the cloud zero-membership session has no principal and runs unclaimed)
|
|
34
|
+
* the tool's upload reserve (a retried reserve must not leak a
|
|
35
|
+
* second session + reserved resource id)
|
|
36
|
+
* POST /api/v1/projects (one click mints one project) and
|
|
37
|
+
* POST /api/v1/projects/{id}/members (a retried add answers the first
|
|
38
|
+
* add's 201, not 409 `already_member`)
|
|
39
|
+
* Deliberate NON-targets:
|
|
40
|
+
* POST /api/v1/files and the tool's asset upload — content-addressed
|
|
41
|
+
* dedupe already makes them idempotent, and upload bodies must never be
|
|
42
|
+
* buffered here;
|
|
43
|
+
* POST /api/v1/setup and /api/v1/invitations/accept — one-shot by
|
|
44
|
+
* construction (retries answer 410), and they run without a principal;
|
|
45
|
+
* the tool's version commits — one-shot (session consumed / version counter)
|
|
46
|
+
* by construction: a retry answers 409.
|
|
47
|
+
*
|
|
48
|
+
* The cached response body is stored AES-256-GCM ENCRYPTED: these responses
|
|
49
|
+
* carry one-shot secrets (the full API key, the invitation acceptUrl token,
|
|
50
|
+
* the reset link) whose plaintext is deliberately never persisted anywhere
|
|
51
|
+
* else, and this cache must not become the exception. Sealed payload format:
|
|
52
|
+
* `iv.ciphertext.tag`, each part base64url; key = sha256(authSecret +
|
|
53
|
+
* ':idempotency'). Rotating AUTH_SECRET inside the 24h window is the same
|
|
54
|
+
* hard cutover it is for API keys: `open()` fails closed (null) and the
|
|
55
|
+
* stale row is dropped and re-executed.
|
|
56
|
+
*
|
|
57
|
+
* Accepted edge: a crash between the handler's commit and the response
|
|
58
|
+
* persist leaves a claim without a response — same-key retries answer 409
|
|
59
|
+
* `idempotency_in_flight` until the 24h expiry. Safe (never double-creates),
|
|
60
|
+
* mildly annoying, self-healing.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Rows live 24h (the Stripe convention); the nightly purge deletes expired ones. */
|
|
64
|
+
const TTL_MS = 24 * 60 * 60 * 1000;
|
|
65
|
+
|
|
66
|
+
const KEY_MAX_LENGTH = 200;
|
|
67
|
+
|
|
68
|
+
const TARGET_PATHS = new Set([
|
|
69
|
+
'/api/v1/api-keys',
|
|
70
|
+
'/api/v1/invitations',
|
|
71
|
+
'/api/v1/workspaces',
|
|
72
|
+
'/api/v1/projects'
|
|
73
|
+
]);
|
|
74
|
+
// The two member routes that MINT a credential for another user. Both are
|
|
75
|
+
// covered (FUZZ-7): a replayed mint hands out a second live secret, and the
|
|
76
|
+
// change-email JWT is stateless, so it cannot even be revoked afterwards.
|
|
77
|
+
const RESET_LINK_RE = /^\/api\/v1\/members\/[^/]+\/reset-link$/;
|
|
78
|
+
const CHANGE_EMAIL_LINK_RE = /^\/api\/v1\/members\/[^/]+\/change-email-link$/;
|
|
79
|
+
const PROJECT_MEMBERS_RE = /^\/api\/v1\/projects\/[^/]+\/members$/;
|
|
80
|
+
|
|
81
|
+
function isTarget(
|
|
82
|
+
method: string,
|
|
83
|
+
path: string,
|
|
84
|
+
toolTargets: ((path: string) => boolean) | undefined
|
|
85
|
+
): boolean {
|
|
86
|
+
return (
|
|
87
|
+
method === 'POST' &&
|
|
88
|
+
(TARGET_PATHS.has(path) ||
|
|
89
|
+
RESET_LINK_RE.test(path) ||
|
|
90
|
+
CHANGE_EMAIL_LINK_RE.test(path) ||
|
|
91
|
+
PROJECT_MEMBERS_RE.test(path) ||
|
|
92
|
+
(toolTargets?.(path) ?? false))
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** AES-256-GCM key derived from the server auth secret (domain-separated). */
|
|
97
|
+
function keyOf(authSecret: string): Buffer {
|
|
98
|
+
return createHash('sha256')
|
|
99
|
+
.update(authSecret + ':idempotency')
|
|
100
|
+
.digest();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Encrypt a response body for storage at rest: `iv.ciphertext.tag` base64url. */
|
|
104
|
+
export function seal(plain: string, authSecret: string): string {
|
|
105
|
+
const iv = randomBytes(12);
|
|
106
|
+
const cipher = createCipheriv('aes-256-gcm', keyOf(authSecret), iv);
|
|
107
|
+
const ciphertext = Buffer.concat([cipher.update(plain, 'utf8'), cipher.final()]);
|
|
108
|
+
return `${iv.toString('base64url')}.${ciphertext.toString('base64url')}.${cipher.getAuthTag().toString('base64url')}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Decrypt a sealed body; null on tamper, malformed input, or a wrong/rotated key. */
|
|
112
|
+
export function open(sealed: string, authSecret: string): string | null {
|
|
113
|
+
const [iv, ciphertext, tag] = sealed.split('.');
|
|
114
|
+
if (!iv || !ciphertext || !tag) return null;
|
|
115
|
+
try {
|
|
116
|
+
const decipher = createDecipheriv('aes-256-gcm', keyOf(authSecret), Buffer.from(iv, 'base64url'));
|
|
117
|
+
decipher.setAuthTag(Buffer.from(tag, 'base64url'));
|
|
118
|
+
return Buffer.concat([decipher.update(Buffer.from(ciphertext, 'base64url')), decipher.final()]).toString(
|
|
119
|
+
'utf8'
|
|
120
|
+
);
|
|
121
|
+
} catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface IdempotencyDeps {
|
|
127
|
+
db: Db;
|
|
128
|
+
authSecret: string;
|
|
129
|
+
/** The tool's own create POSTs that take the claim (a pure predicate over the path; POST only). */
|
|
130
|
+
toolTargets?: (path: string) => boolean;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function idempotency({ db, authSecret, toolTargets }: IdempotencyDeps): MiddlewareHandler {
|
|
134
|
+
return async (c, next) => {
|
|
135
|
+
if (!isTarget(c.req.method, c.req.path, toolTargets)) return next();
|
|
136
|
+
const key = c.req.header('idempotency-key');
|
|
137
|
+
if (key === undefined) return next();
|
|
138
|
+
if (key.length === 0 || key.length > KEY_MAX_LENGTH) {
|
|
139
|
+
// This middleware runs before contract validation, so the header bound
|
|
140
|
+
// is enforced here (the contract mirrors it for the OpenAPI document).
|
|
141
|
+
return apiError(c, 400, 'invalid_idempotency_key', 'Idempotency-Key must be 1–200 characters');
|
|
142
|
+
}
|
|
143
|
+
const principal = c.get('principal');
|
|
144
|
+
if (!principal) return next(); // the route gates 401 downstream
|
|
145
|
+
|
|
146
|
+
// Hono caches the body: the zod validator's later c.req.json() re-reads
|
|
147
|
+
// from the same cache (verified on hono 4.12), so this text() is safe.
|
|
148
|
+
const bodyText = await c.req.text();
|
|
149
|
+
// Raw bytes, no canonicalization: a retry that re-serializes the same
|
|
150
|
+
// JSON differently hashes differently and 409s — by design.
|
|
151
|
+
const requestHash = createHash('sha256')
|
|
152
|
+
.update(`${c.req.method}\n${c.req.path}\n${bodyText}`)
|
|
153
|
+
.digest('hex');
|
|
154
|
+
|
|
155
|
+
const scope = and(
|
|
156
|
+
eq(idempotencyKeys.workspaceId, principal.workspaceId),
|
|
157
|
+
eq(idempotencyKeys.userId, principal.userId),
|
|
158
|
+
eq(idempotencyKeys.key, key)
|
|
159
|
+
);
|
|
160
|
+
const claim = async (): Promise<string | null> => {
|
|
161
|
+
const rows = await db
|
|
162
|
+
.insert(idempotencyKeys)
|
|
163
|
+
.values({
|
|
164
|
+
workspaceId: principal.workspaceId,
|
|
165
|
+
userId: principal.userId,
|
|
166
|
+
key,
|
|
167
|
+
requestHash,
|
|
168
|
+
expiresAt: new Date(Date.now() + TTL_MS)
|
|
169
|
+
})
|
|
170
|
+
.onConflictDoNothing({
|
|
171
|
+
target: [idempotencyKeys.workspaceId, idempotencyKeys.userId, idempotencyKeys.key]
|
|
172
|
+
})
|
|
173
|
+
.returning({ id: idempotencyKeys.id });
|
|
174
|
+
return rows[0]?.id ?? null;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
let claimId = await claim();
|
|
178
|
+
|
|
179
|
+
if (claimId === null) {
|
|
180
|
+
// Claim lost: someone (possibly an earlier attempt of this very
|
|
181
|
+
// client) holds the key. Inspect the row to replay or conflict.
|
|
182
|
+
const [existing] = await db.select().from(idempotencyKeys).where(scope).limit(1);
|
|
183
|
+
if (!existing) {
|
|
184
|
+
// The row vanished between insert and select (raced the nightly
|
|
185
|
+
// purge). Claim once more; losing again means a live concurrent racer.
|
|
186
|
+
claimId = await claim();
|
|
187
|
+
if (claimId === null) {
|
|
188
|
+
return apiError(
|
|
189
|
+
c,
|
|
190
|
+
409,
|
|
191
|
+
'idempotency_in_flight',
|
|
192
|
+
'A request with this Idempotency-Key is in flight — retry shortly'
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
} else if (existing.requestHash !== requestHash) {
|
|
196
|
+
return apiError(
|
|
197
|
+
c,
|
|
198
|
+
409,
|
|
199
|
+
'idempotency_key_reuse',
|
|
200
|
+
'This Idempotency-Key was already used with a different request'
|
|
201
|
+
);
|
|
202
|
+
} else if (existing.responseStatus === null || existing.responseBodyEnc === null) {
|
|
203
|
+
return apiError(
|
|
204
|
+
c,
|
|
205
|
+
409,
|
|
206
|
+
'idempotency_in_flight',
|
|
207
|
+
'The original request is still in flight — retry shortly'
|
|
208
|
+
);
|
|
209
|
+
} else {
|
|
210
|
+
const plain = open(existing.responseBodyEnc, authSecret);
|
|
211
|
+
if (plain === null) {
|
|
212
|
+
// Sealed under a rotated AUTH_SECRET (documented hard cutover):
|
|
213
|
+
// unrecoverable, so drop the stale row and execute afresh.
|
|
214
|
+
await db.delete(idempotencyKeys).where(eq(idempotencyKeys.id, existing.id));
|
|
215
|
+
claimId = await claim();
|
|
216
|
+
if (claimId === null) {
|
|
217
|
+
return apiError(
|
|
218
|
+
c,
|
|
219
|
+
409,
|
|
220
|
+
'idempotency_in_flight',
|
|
221
|
+
'A request with this Idempotency-Key is in flight — retry shortly'
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
c.header('idempotency-replayed', 'true');
|
|
226
|
+
return c.json(JSON.parse(plain), existing.responseStatus as ContentfulStatusCode);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Owner path: we hold the claim; the handler executes.
|
|
232
|
+
const ownedClaimId = claimId;
|
|
233
|
+
// Best-effort release: a failed request must stay retryable with the
|
|
234
|
+
// same key (release errors must not mask the real outcome).
|
|
235
|
+
const release = async () => {
|
|
236
|
+
await db
|
|
237
|
+
.delete(idempotencyKeys)
|
|
238
|
+
.where(eq(idempotencyKeys.id, ownedClaimId))
|
|
239
|
+
.catch(() => {});
|
|
240
|
+
};
|
|
241
|
+
try {
|
|
242
|
+
await next();
|
|
243
|
+
} catch (e) {
|
|
244
|
+
await release();
|
|
245
|
+
throw e;
|
|
246
|
+
}
|
|
247
|
+
if (c.res.status >= 200 && c.res.status < 300) {
|
|
248
|
+
// clone() tees the stream — the client still receives the original.
|
|
249
|
+
const body = await c.res.clone().text();
|
|
250
|
+
try {
|
|
251
|
+
await db
|
|
252
|
+
.update(idempotencyKeys)
|
|
253
|
+
.set({ responseStatus: c.res.status, responseBodyEnc: seal(body, authSecret) })
|
|
254
|
+
.where(eq(idempotencyKeys.id, ownedClaimId));
|
|
255
|
+
} catch {
|
|
256
|
+
// Best-effort, like audit: the handler's mutation has already
|
|
257
|
+
// committed, so a failed persist must never turn into a 500. The
|
|
258
|
+
// claim stays response-less; same-key retries 409 until expiry.
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
await release();
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type AdmitResult,
|
|
3
|
+
type PrincipalGate,
|
|
4
|
+
admitPrincipal,
|
|
5
|
+
authContext,
|
|
6
|
+
requireAuth,
|
|
7
|
+
requireNonGuest,
|
|
8
|
+
requireRole,
|
|
9
|
+
resolveSessionPrincipal
|
|
10
|
+
} from './auth-context.js';
|
|
11
|
+
export {
|
|
12
|
+
type BucketDeclaration,
|
|
13
|
+
type ClientIpFn,
|
|
14
|
+
type QuotaDecision,
|
|
15
|
+
type RateLimiters,
|
|
16
|
+
type RequestQuotaService,
|
|
17
|
+
createRateLimiters,
|
|
18
|
+
createRequestQuota,
|
|
19
|
+
emailKeyOf,
|
|
20
|
+
makeClientIp,
|
|
21
|
+
principalBucketKey,
|
|
22
|
+
quotaHeaderEntries,
|
|
23
|
+
rateLimit
|
|
24
|
+
} from './rate-limit.js';
|
|
25
|
+
export { requestId } from './request-id.js';
|
|
26
|
+
export { type ScopeAllowlistOptions, type ScopeRule, createScopeAllowlist, looksLikeJwt } from './scopes.js';
|
|
27
|
+
export { authBodyGuard } from './auth-body.js';
|
|
28
|
+
export { crossSiteGuard } from './cross-site.js';
|
|
29
|
+
export { idempotency, open, seal } from './idempotency.js';
|
|
30
|
+
export { MAX_JSON_DEPTH, exceedsJsonDepth, jsonDepthLimit } from './json-depth.js';
|
|
31
|
+
export { noStoreAuthenticated } from './no-store.js';
|
|
32
|
+
export { isPublicOauthPath, oauthPublicEndpoints } from './oauth-public.js';
|
|
33
|
+
export { buildCsp, hstsValue, inlineScriptHashes, securityHeaders } from './security-headers.js';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
import { apiError } from '../api/errors.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Nesting cap for request JSON. Deliberately far above anything a contract in
|
|
6
|
+
* `@antasphere/contract` describes (the deepest is three or four levels) and far
|
|
7
|
+
* below the depth at which V8 recursion breaks.
|
|
8
|
+
*
|
|
9
|
+
* Why a cap at all: `JSON.parse` is iterative and swallows any depth, but
|
|
10
|
+
* `JSON.stringify` is RECURSIVE and blows the stack with a `RangeError` past a
|
|
11
|
+
* few thousand levels — and the exact depth depends on the V8 build, so it
|
|
12
|
+
* reproduces inside the shipped `node:22-alpine` image and not on a newer host
|
|
13
|
+
* Node. Every path that echoes, audits, logs, or persists a validated body
|
|
14
|
+
* stringifies it, so an anonymous client could turn one small request body
|
|
15
|
+
* into a 500 plus an error-level stack trace. Rejecting at the edge — before
|
|
16
|
+
* anything parses, let alone stringifies — is the only place the fix is
|
|
17
|
+
* complete.
|
|
18
|
+
*/
|
|
19
|
+
export const MAX_JSON_DEPTH = 100;
|
|
20
|
+
|
|
21
|
+
/** Matches better-call's / Hono's JSON content-type test (same regex family). */
|
|
22
|
+
const JSON_CONTENT_TYPE = /^application\/([a-z0-9.+-]*\+)?json/i;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* True when `text` nests `{`/`[` deeper than `max`. A single string-aware
|
|
26
|
+
* scan, no parsing and no allocation: brackets inside JSON string literals
|
|
27
|
+
* (and escaped quotes inside them) do not count. Returns as soon as the limit
|
|
28
|
+
* is passed, so a hostile body costs O(prefix), not O(body).
|
|
29
|
+
*/
|
|
30
|
+
export function exceedsJsonDepth(text: string, max: number): boolean {
|
|
31
|
+
let depth = 0;
|
|
32
|
+
let inString = false;
|
|
33
|
+
let escaped = false;
|
|
34
|
+
for (let i = 0; i < text.length; i++) {
|
|
35
|
+
const ch = text[i];
|
|
36
|
+
if (inString) {
|
|
37
|
+
if (escaped) escaped = false;
|
|
38
|
+
else if (ch === '\\') escaped = true;
|
|
39
|
+
else if (ch === '"') inString = false;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (ch === '"') inString = true;
|
|
43
|
+
else if (ch === '{' || ch === '[') {
|
|
44
|
+
depth++;
|
|
45
|
+
if (depth > max) return true;
|
|
46
|
+
} else if (ch === '}' || ch === ']') depth--;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Rejects over-deep JSON bodies with a 400 before any handler, parser or
|
|
53
|
+
* serializer sees them. Non-JSON and bodyless requests pass untouched, so
|
|
54
|
+
* streamed uploads and form-encoded token calls are unaffected. Mount it
|
|
55
|
+
* AFTER the body-size limit so the scan is bounded by that cap.
|
|
56
|
+
*/
|
|
57
|
+
export function jsonDepthLimit(maxDepth: number = MAX_JSON_DEPTH): MiddlewareHandler {
|
|
58
|
+
return async (c, next) => {
|
|
59
|
+
const raw = c.req.raw;
|
|
60
|
+
if (!raw.body) return next();
|
|
61
|
+
if (!JSON_CONTENT_TYPE.test(raw.headers.get('content-type') ?? '')) return next();
|
|
62
|
+
let text: string;
|
|
63
|
+
try {
|
|
64
|
+
text = await raw.clone().text();
|
|
65
|
+
} catch {
|
|
66
|
+
// Unreadable body — let the normal parser produce the normal error.
|
|
67
|
+
return next();
|
|
68
|
+
}
|
|
69
|
+
if (exceedsJsonDepth(text, maxDepth)) {
|
|
70
|
+
return apiError(c, 400, 'payload_too_deep', `Request JSON nests deeper than ${maxDepth} levels`);
|
|
71
|
+
}
|
|
72
|
+
return next();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `Cache-Control: no-store` on authenticated JSON.
|
|
5
|
+
*
|
|
6
|
+
* `/me`, the member roster, the audit page, every product resource — all of
|
|
7
|
+
* them answer per-principal JSON with no cache directive at all, which leaves
|
|
8
|
+
* the decision to heuristic caching in whatever sits in front of the app (a
|
|
9
|
+
* shared corporate proxy, a CDN a self-hoster puts in the path, the browser's
|
|
10
|
+
* own bfcache/back-button restore). One user's roster served to the next is
|
|
11
|
+
* exactly the failure mode `no-store` exists to prevent.
|
|
12
|
+
*
|
|
13
|
+
* Scoped deliberately:
|
|
14
|
+
*
|
|
15
|
+
* - only when a principal resolved — anonymous discovery (`/instance`) and
|
|
16
|
+
* the OpenAPI document stay cacheable;
|
|
17
|
+
* - only JSON — file downloads and exports are streamed, sometimes ranged,
|
|
18
|
+
* and set their own headers (api/export.ts already sends `no-store`);
|
|
19
|
+
* - never clobbering a Cache-Control a route set for itself.
|
|
20
|
+
*/
|
|
21
|
+
export function noStoreAuthenticated(): MiddlewareHandler {
|
|
22
|
+
return async (c, next) => {
|
|
23
|
+
await next();
|
|
24
|
+
if (!c.get('principal')) return;
|
|
25
|
+
if (c.res.headers.has('cache-control')) return;
|
|
26
|
+
const contentType = c.res.headers.get('content-type') ?? '';
|
|
27
|
+
if (!contentType.includes('json')) return;
|
|
28
|
+
c.res.headers.set('Cache-Control', 'no-store');
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Public (cookie-less) OAuth endpoints that MCP clients call cross-origin.
|
|
5
|
+
* These authenticate via body credentials (code + PKCE, refresh token), never
|
|
6
|
+
* cookies, so a wildcard CORS origin is safe — and required for browser-based
|
|
7
|
+
* clients to read the responses. Cookie-bearing auth endpoints (sign-in,
|
|
8
|
+
* consent, authorize) are deliberately NOT in this list. Ported from the Neon
|
|
9
|
+
* template's hooks.server.ts PUBLIC_OAUTH_PATHS treatment, adapted to the
|
|
10
|
+
* /api/v1/auth base path.
|
|
11
|
+
*/
|
|
12
|
+
const PUBLIC_OAUTH_PATHS = new Set([
|
|
13
|
+
'/api/v1/auth/oauth2/token',
|
|
14
|
+
'/api/v1/auth/oauth2/register',
|
|
15
|
+
'/api/v1/auth/oauth2/introspect',
|
|
16
|
+
'/api/v1/auth/oauth2/revoke',
|
|
17
|
+
'/api/v1/auth/jwks'
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export const OAUTH_CORS_HEADERS = {
|
|
21
|
+
'Access-Control-Allow-Origin': '*',
|
|
22
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
23
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization, mcp-protocol-version',
|
|
24
|
+
'Access-Control-Max-Age': '86400'
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export function isPublicOauthPath(path: string): boolean {
|
|
28
|
+
return PUBLIC_OAUTH_PATHS.has(path) || path.startsWith('/api/v1/auth/.well-known/');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Wide-open CORS + preflight handling for the public OAuth endpoints, and
|
|
33
|
+
* RFC 6749 §5.1 cache suppression on the token endpoint (its responses carry
|
|
34
|
+
* credentials). Registered before the auth-surface rate limits so OPTIONS
|
|
35
|
+
* preflights never consume a bucket.
|
|
36
|
+
*/
|
|
37
|
+
export function oauthPublicEndpoints(): MiddlewareHandler {
|
|
38
|
+
return async (c, next) => {
|
|
39
|
+
if (!isPublicOauthPath(c.req.path)) {
|
|
40
|
+
return next();
|
|
41
|
+
}
|
|
42
|
+
if (c.req.method === 'OPTIONS') {
|
|
43
|
+
return c.body(null, 204, { ...OAUTH_CORS_HEADERS });
|
|
44
|
+
}
|
|
45
|
+
await next();
|
|
46
|
+
for (const [key, value] of Object.entries(OAUTH_CORS_HEADERS)) {
|
|
47
|
+
c.res.headers.set(key, value);
|
|
48
|
+
}
|
|
49
|
+
if (c.req.path === '/api/v1/auth/oauth2/token') {
|
|
50
|
+
c.res.headers.set('Cache-Control', 'no-store');
|
|
51
|
+
c.res.headers.set('Pragma', 'no-cache');
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|