@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
package/src/mcp/teams.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { mcpInputs } from './inputs.js';
|
|
4
|
+
import { jsonText, wrapToolErrors, type ErrorHints, type ToolTextResult } from './errors.js';
|
|
5
|
+
import {
|
|
6
|
+
callApi,
|
|
7
|
+
forWorkspace,
|
|
8
|
+
pageQuery,
|
|
9
|
+
type McpScopes,
|
|
10
|
+
type McpToolContext,
|
|
11
|
+
type ScopeCheck
|
|
12
|
+
} from './tool-kit.js';
|
|
13
|
+
import type { McpIdentity } from './server.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The two TEAM reads (PRDCT-2813), registered by the chassis right after the
|
|
17
|
+
* project tools: a team is a chassis concept (a named group of a workspace's
|
|
18
|
+
* own members, on both editions), so the tools over it are the chassis'. Thin
|
|
19
|
+
* shims over the instance's own /api/v1/teams called IN-PROCESS with the
|
|
20
|
+
* caller's bearer forwarded verbatim, like every other chassis tool.
|
|
21
|
+
*
|
|
22
|
+
* READS ONLY, by design: shaping a team (creating it, seating people) is a
|
|
23
|
+
* person's act on the People page, or on the Antasphere account site for a
|
|
24
|
+
* workspace it manages; an agent puts a team on a project through
|
|
25
|
+
* `<toolPrefix>add_project_member` with `teamId`. Nothing here names a tool,
|
|
26
|
+
* a brand or a domain.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** What a team IS, opening both descriptions. */
|
|
30
|
+
const WHAT_IS_A_TEAM =
|
|
31
|
+
'A team is a named group of the organization’s own members (for example "Design" or "Sales"). ' +
|
|
32
|
+
'A team can be put on a project with a role, and every member of the team then holds that role ' +
|
|
33
|
+
'on the project.';
|
|
34
|
+
|
|
35
|
+
/** Where teams come from and where they are shaped. */
|
|
36
|
+
const WHERE_TEAMS_LIVE =
|
|
37
|
+
'In an organization managed by the Antasphere account site, the teams come from there and are ' +
|
|
38
|
+
'read-only here. Creating a team or adding people to one is done by a person on the People page, ' +
|
|
39
|
+
'or on the Antasphere account site for an organization it manages, never through these tools.';
|
|
40
|
+
|
|
41
|
+
const teamIdInput = z.uuid().describe('The team id, from the teams list (never the team name or slug).');
|
|
42
|
+
|
|
43
|
+
/** Register the two team reads on a server, after the project tools. */
|
|
44
|
+
export function registerTeamTools(
|
|
45
|
+
server: McpServer,
|
|
46
|
+
ctx: McpToolContext,
|
|
47
|
+
identity: McpIdentity,
|
|
48
|
+
scopes: McpScopes,
|
|
49
|
+
checkScope: ScopeCheck<string>,
|
|
50
|
+
hints: ErrorHints
|
|
51
|
+
): void {
|
|
52
|
+
const { workspaceInput, cursorInput, limitInput } = mcpInputs(identity);
|
|
53
|
+
const prefix = identity.toolPrefix;
|
|
54
|
+
|
|
55
|
+
const read = (workspace: string | undefined, path: string): Promise<ToolTextResult> => {
|
|
56
|
+
const denied = checkScope(ctx.principal, scopes.read);
|
|
57
|
+
if (denied) return Promise.resolve(denied);
|
|
58
|
+
const c = forWorkspace(ctx, workspace);
|
|
59
|
+
return wrapToolErrors(async () => jsonText(await callApi(c, path)), hints);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
server.registerTool(
|
|
63
|
+
`${prefix}list_teams`,
|
|
64
|
+
{
|
|
65
|
+
description:
|
|
66
|
+
`List the teams of an organization, newest first. ${WHAT_IS_A_TEAM} ${WHERE_TEAMS_LIVE} ` +
|
|
67
|
+
'Returns { teams: [{ id, slug, name, membersCount, isMember, hubTeamId, createdAt, ' +
|
|
68
|
+
'updatedAt }], nextCursor } — `isMember` says whether YOU are in the team, and `hubTeamId` ' +
|
|
69
|
+
'is set when the team comes from the Antasphere account site. Pass a team `id` as `teamId` ' +
|
|
70
|
+
`to ${prefix}list_team_members or ${prefix}add_project_member. When nextCursor is non-null, ` +
|
|
71
|
+
'call again with cursor set to it.',
|
|
72
|
+
inputSchema: { workspace: workspaceInput, limit: limitInput, cursor: cursorInput },
|
|
73
|
+
annotations: { readOnlyHint: true }
|
|
74
|
+
},
|
|
75
|
+
async ({ workspace, limit, cursor }) => read(workspace, pageQuery('/api/v1/teams', { cursor, limit }))
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
server.registerTool(
|
|
79
|
+
`${prefix}list_team_members`,
|
|
80
|
+
{
|
|
81
|
+
description:
|
|
82
|
+
`List the members of one team. ${WHAT_IS_A_TEAM} ${WHERE_TEAMS_LIVE} Returns { members: ` +
|
|
83
|
+
'[{ userId, email, name, role, isActive, addedAt }], nextCursor } — `role` is the person’s ' +
|
|
84
|
+
'role in the ORGANIZATION (a team has no roles of its own). When nextCursor is non-null, call ' +
|
|
85
|
+
'again with cursor set to it.',
|
|
86
|
+
inputSchema: {
|
|
87
|
+
workspace: workspaceInput,
|
|
88
|
+
teamId: teamIdInput,
|
|
89
|
+
limit: limitInput,
|
|
90
|
+
cursor: cursorInput
|
|
91
|
+
},
|
|
92
|
+
annotations: { readOnlyHint: true }
|
|
93
|
+
},
|
|
94
|
+
async ({ workspace, teamId, limit, cursor }) =>
|
|
95
|
+
read(workspace, pageQuery(`/api/v1/teams/${teamId}/members`, { cursor, limit }))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { ACTIVE_WORKSPACE_HEADER, type Principal } from '@antasphere/chassis-contract';
|
|
2
|
+
import { ApiToolError, deny, type ToolTextResult } from './errors.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shared plumbing for MCP tools (used by the chassis examples in server.ts
|
|
6
|
+
* and the tool's own set). Every call goes through the
|
|
7
|
+
* instance's own /api/v1 IN-PROCESS with the caller's Authorization header
|
|
8
|
+
* forwarded verbatim — MCP is just another API client, no privileged path.
|
|
9
|
+
*/
|
|
10
|
+
export interface McpToolContext {
|
|
11
|
+
/** In-process fetch against the root app (path → Response). */
|
|
12
|
+
fetchApi: (path: string, init?: RequestInit) => Promise<Response>;
|
|
13
|
+
/** The verified caller (OAuth token or API key principal). */
|
|
14
|
+
principal: Principal;
|
|
15
|
+
/** Forwarded verbatim on every in-process API call. */
|
|
16
|
+
authorizationHeader: string;
|
|
17
|
+
/**
|
|
18
|
+
* The instance's public origin (`PUBLIC_BASE_URL`), for the one thing a
|
|
19
|
+
* tool composes for a human rather than for the API: the page of the tool's
|
|
20
|
+
* resource that a push answers with (PRDCT-2280). Never used to reach the API.
|
|
21
|
+
*/
|
|
22
|
+
publicBaseUrl: string;
|
|
23
|
+
/**
|
|
24
|
+
* Target workspace of THIS tool call (user-scoped credential model): set
|
|
25
|
+
* from the tool's optional `workspace` argument via {@link forWorkspace},
|
|
26
|
+
* it rides the in-process re-entry as the X-Workspace-Id header, where
|
|
27
|
+
* the API's own resolvers authorize it against the caller's live
|
|
28
|
+
* memberships — a tool argument can never grant what the credential's
|
|
29
|
+
* user does not hold. Absent = the caller's default workspace.
|
|
30
|
+
*/
|
|
31
|
+
workspaceId?: string | undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The per-call workspace seam: every workspace-scoped tool passes its
|
|
36
|
+
* optional `workspace` argument through here so the selection travels on
|
|
37
|
+
* the ONE header the whole platform authorizes.
|
|
38
|
+
*/
|
|
39
|
+
export function forWorkspace(ctx: McpToolContext, workspace: string | undefined): McpToolContext {
|
|
40
|
+
return workspace ? { ...ctx, workspaceId: workspace } : ctx;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The re-entry headers: caller's bearer + the per-call workspace selector. */
|
|
44
|
+
function apiHeaders(ctx: McpToolContext): Record<string, string> {
|
|
45
|
+
return {
|
|
46
|
+
authorization: ctx.authorizationHeader,
|
|
47
|
+
...(ctx.workspaceId ? { [ACTIVE_WORKSPACE_HEADER]: ctx.workspaceId } : {})
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Tool-level scope pre-check — UX only: the API's fail-closed allowlist
|
|
53
|
+
* (middleware/scopes.ts) is the enforcement point; this just gives the model
|
|
54
|
+
* a clean, actionable error instead of a raw 403.
|
|
55
|
+
*/
|
|
56
|
+
export type ScopeCheck<TScope extends string> = (
|
|
57
|
+
principal: Principal,
|
|
58
|
+
scope: TScope
|
|
59
|
+
) => ToolTextResult | null;
|
|
60
|
+
|
|
61
|
+
/** The tool's two MCP scope names: what a read tool and a write tool pre-check. */
|
|
62
|
+
export interface McpScopes<TRead extends string = string, TWrite extends string = string> {
|
|
63
|
+
read: TRead;
|
|
64
|
+
write: TWrite;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createScopeCheck<TRead extends string, TWrite extends string>(
|
|
68
|
+
scopes: McpScopes<TRead, TWrite>
|
|
69
|
+
): ScopeCheck<TRead | TWrite> {
|
|
70
|
+
return (principal, scope) => {
|
|
71
|
+
if (principal.scopes && !principal.scopes.has(scope)) {
|
|
72
|
+
return deny(
|
|
73
|
+
`Missing scope "${scope}": this connection was not granted ` +
|
|
74
|
+
(scope === scopes.write ? 'permission to create or edit data.' : 'permission to read data.') +
|
|
75
|
+
' Reconnect the MCP server and approve the permission on the consent screen.'
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* In-process API call returning the raw Response (asset downloads, multipart
|
|
84
|
+
* uploads). A non-2xx answer is parsed into an ApiToolError so wrapToolErrors
|
|
85
|
+
* renders the code + `Next:` hint.
|
|
86
|
+
*/
|
|
87
|
+
export async function fetchApiRaw(
|
|
88
|
+
ctx: McpToolContext,
|
|
89
|
+
path: string,
|
|
90
|
+
init: RequestInit = {}
|
|
91
|
+
): Promise<Response> {
|
|
92
|
+
const res = await ctx.fetchApi(path, {
|
|
93
|
+
...init,
|
|
94
|
+
headers: { ...(init.headers ?? {}), ...apiHeaders(ctx) }
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const body = (await res.json().catch(() => null)) as {
|
|
98
|
+
error?: { code?: string; message?: string; details?: unknown };
|
|
99
|
+
} | null;
|
|
100
|
+
throw new ApiToolError(
|
|
101
|
+
res.status,
|
|
102
|
+
body?.error?.code ?? null,
|
|
103
|
+
body?.error?.message ?? `unexpected response from ${path}`,
|
|
104
|
+
body?.error?.details
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return res;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** In-process JSON API call: parses the body, maps non-2xx to ApiToolError. */
|
|
111
|
+
export async function callApi(ctx: McpToolContext, path: string, init: RequestInit = {}): Promise<unknown> {
|
|
112
|
+
const res = await ctx.fetchApi(path, {
|
|
113
|
+
...init,
|
|
114
|
+
headers: { ...(init.headers ?? {}), ...apiHeaders(ctx) }
|
|
115
|
+
});
|
|
116
|
+
const body = (await res.json().catch(() => null)) as {
|
|
117
|
+
error?: { code?: string; message?: string; details?: unknown };
|
|
118
|
+
} | null;
|
|
119
|
+
if (!res.ok) {
|
|
120
|
+
throw new ApiToolError(
|
|
121
|
+
res.status,
|
|
122
|
+
body?.error?.code ?? null,
|
|
123
|
+
body?.error?.message ?? `unexpected response from ${path}`,
|
|
124
|
+
body?.error?.details
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return body;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Append cursor/limit list params to a path, after the route's own filters
|
|
132
|
+
* (`extra`, e.g. the `type` of the tool's resource list); an undefined filter is
|
|
133
|
+
* left out.
|
|
134
|
+
*/
|
|
135
|
+
export function pageQuery(
|
|
136
|
+
base: string,
|
|
137
|
+
params: { cursor?: string | undefined; limit?: number | undefined },
|
|
138
|
+
extra: Record<string, string | undefined> = {}
|
|
139
|
+
): string {
|
|
140
|
+
const query = new URLSearchParams();
|
|
141
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
142
|
+
if (value !== undefined) query.set(key, value);
|
|
143
|
+
}
|
|
144
|
+
if (params.cursor) query.set('cursor', params.cursor);
|
|
145
|
+
if (params.limit !== undefined) query.set('limit', String(params.limit));
|
|
146
|
+
const qs = query.toString();
|
|
147
|
+
return qs ? `${base}?${qs}` : base;
|
|
148
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { and, eq, inArray, isNull, or, sql } from 'drizzle-orm';
|
|
2
|
+
import {
|
|
3
|
+
demoPasses,
|
|
4
|
+
demoPassSessions,
|
|
5
|
+
invitations,
|
|
6
|
+
oauthAccessToken,
|
|
7
|
+
oauthRefreshToken,
|
|
8
|
+
projectMembers,
|
|
9
|
+
session as sessionTable,
|
|
10
|
+
user as userTable,
|
|
11
|
+
workspaceMembers,
|
|
12
|
+
workspaceTeamMembers,
|
|
13
|
+
type DbConn
|
|
14
|
+
} from '@antasphere/chassis-db';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The membership an ADD hangs a right on, re-read inside the add's own
|
|
18
|
+
* transaction and held FOR SHARE until it commits: true when the row is
|
|
19
|
+
* there, in that workspace, and active. Every add of something a removal
|
|
20
|
+
* takes (a project grant, a team seat, a demo pass) calls this before its
|
|
21
|
+
* insert, and refuses on false the way it refuses an inactive member.
|
|
22
|
+
*
|
|
23
|
+
* Why the lock (the end-to-end verification, finding 5): the add's first read
|
|
24
|
+
* is outside any transaction, and the insert's foreign key check takes only a
|
|
25
|
+
* KEY SHARE lock, which a removal's `UPDATE workspace_members` does not wait
|
|
26
|
+
* for. An add that read the row active, then waited on another lock (the
|
|
27
|
+
* project row, the team row), inserted after a removal had committed, on the
|
|
28
|
+
* now inactive row, and the right came back with the person at their
|
|
29
|
+
* re-invitation. Held FOR SHARE, the row makes the removal's update wait for
|
|
30
|
+
* the add to commit (the removal's second pass then takes what the add
|
|
31
|
+
* wrote, `deleteMembershipGrants`'s caller); an add that arrives after the
|
|
32
|
+
* update re-reads the row off and inserts nothing.
|
|
33
|
+
*/
|
|
34
|
+
export async function holdLiveMembership(
|
|
35
|
+
tx: DbConn,
|
|
36
|
+
workspaceId: string,
|
|
37
|
+
who: { memberId: string } | { userId: string }
|
|
38
|
+
): Promise<boolean> {
|
|
39
|
+
const [row] = await tx
|
|
40
|
+
.select({ id: workspaceMembers.id })
|
|
41
|
+
.from(workspaceMembers)
|
|
42
|
+
.where(
|
|
43
|
+
and(
|
|
44
|
+
'memberId' in who ? eq(workspaceMembers.id, who.memberId) : eq(workspaceMembers.userId, who.userId),
|
|
45
|
+
eq(workspaceMembers.workspaceId, workspaceId),
|
|
46
|
+
eq(workspaceMembers.isActive, true)
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
.for('share')
|
|
50
|
+
.limit(1);
|
|
51
|
+
return row !== undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** One membership a removal switched off. */
|
|
55
|
+
export interface RemovedMembership {
|
|
56
|
+
/** The `workspace_members` row. */
|
|
57
|
+
memberId: string;
|
|
58
|
+
workspaceId: string;
|
|
59
|
+
userId: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The tool's half of a removal (the `membershipRemoval` slot): what the TOOL
|
|
64
|
+
* hangs on a person in a workspace outside the chassis tables (an invite
|
|
65
|
+
* waiting for them, a grant on one of its resources). It runs in the
|
|
66
|
+
* removal's own transaction and answers what it ended, by name, for the
|
|
67
|
+
* audit record.
|
|
68
|
+
*/
|
|
69
|
+
export type MembershipRemovalHook = (
|
|
70
|
+
tx: DbConn,
|
|
71
|
+
removed: readonly RemovedMembership[]
|
|
72
|
+
) => Promise<Record<string, number>>;
|
|
73
|
+
|
|
74
|
+
export interface RemovalCounts {
|
|
75
|
+
projectGrants: number;
|
|
76
|
+
teamSeats: number;
|
|
77
|
+
/** Open workspace invitations revoked: the ones FOR the person and the ones they ISSUED. */
|
|
78
|
+
invitations: number;
|
|
79
|
+
/** Live demo passes revoked, their sessions ended: the ones opening the person and the ones they MINTED. */
|
|
80
|
+
demoPasses: number;
|
|
81
|
+
/** What the tool's hook ended, under the names it gave; empty without a hook. */
|
|
82
|
+
tool: Record<string, number>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* What a REMOVAL takes away beside the membership itself, stated once for
|
|
87
|
+
* both editions (PRDCT-2816): the person's project grants, their team seats
|
|
88
|
+
* (which is also every grant they held through a team), the open workspace
|
|
89
|
+
* invitations that name them or that they issued, and what the tool hangs
|
|
90
|
+
* on them in that workspace (`toolHook`).
|
|
91
|
+
*
|
|
92
|
+
* The demo passes are doors too (round 3, F1): a pass the person MINTED
|
|
93
|
+
* signs a demo person in, who could reactivate them; a pass minted FOR them
|
|
94
|
+
* works again the day they are re-invited, in whoever's hands it is. Both
|
|
95
|
+
* are revoked with the sessions they opened, the pass service's own way.
|
|
96
|
+
*
|
|
97
|
+
* ORDER (round 3, F2): the caller runs this BEFORE it switches the membership
|
|
98
|
+
* row off, inside the same transaction. An invitation's accept locks the
|
|
99
|
+
* invitation, then the membership row; a removal that locked the membership
|
|
100
|
+
* first and the invitation second met it head on and one of the two died
|
|
101
|
+
* of a deadlock. Same order on both sides, no deadlock.
|
|
102
|
+
*
|
|
103
|
+
* The invitations are doors, not rights (the verifier's round 2, N1 and N2).
|
|
104
|
+
* An invitation FOR the person that was open at the removal reactivates the
|
|
105
|
+
* row at the role it names: the person would come back alone, as admin if it
|
|
106
|
+
* says so. An invitation the person ISSUED is a way back in under another
|
|
107
|
+
* address. Both are revoked; an invitation made after the removal is the
|
|
108
|
+
* workspace's own act and brings the person back.
|
|
109
|
+
*
|
|
110
|
+
* A removal switches the membership row off and never deletes it (a re-add
|
|
111
|
+
* reactivates the very same row), so the foreign keys' cascade never fires:
|
|
112
|
+
* without these deletes, a person removed and added back later would find
|
|
113
|
+
* every old grant and seat waiting, and a door left open for them (a pending
|
|
114
|
+
* invite of the tool's) would let them switch the row back on themselves. A
|
|
115
|
+
* removal is a removal: only an act of the workspace brings the person back,
|
|
116
|
+
* and they come back with nothing. A PAUSE (`PATCH /members/{id}` with
|
|
117
|
+
* `isActive: false`) keeps everything, on purpose.
|
|
118
|
+
*
|
|
119
|
+
* The two callers: the hub reconcile's sweep (cloud, the hub removed the
|
|
120
|
+
* person) and `POST /members/{id}/remove` (a workspace managed here). Run it
|
|
121
|
+
* in the transaction that switches the rows off.
|
|
122
|
+
*
|
|
123
|
+
* Idempotent, so a caller may run it twice in one transaction: the deletes
|
|
124
|
+
* are by membership, the revokes filter on what is still open. The removal
|
|
125
|
+
* route does (a second pass after the row is off, `mergeRemovalCounts`).
|
|
126
|
+
*/
|
|
127
|
+
export async function deleteMembershipGrants(
|
|
128
|
+
tx: DbConn,
|
|
129
|
+
removed: readonly RemovedMembership[],
|
|
130
|
+
toolHook?: MembershipRemovalHook
|
|
131
|
+
): Promise<RemovalCounts> {
|
|
132
|
+
if (removed.length === 0) {
|
|
133
|
+
return { projectGrants: 0, teamSeats: 0, invitations: 0, demoPasses: 0, tool: {} };
|
|
134
|
+
}
|
|
135
|
+
const ids = removed.map((row) => row.memberId);
|
|
136
|
+
const grants = await tx
|
|
137
|
+
.delete(projectMembers)
|
|
138
|
+
.where(inArray(projectMembers.memberId, ids))
|
|
139
|
+
.returning({ id: projectMembers.id });
|
|
140
|
+
const seats = await tx
|
|
141
|
+
.delete(workspaceTeamMembers)
|
|
142
|
+
.where(inArray(workspaceTeamMembers.memberId, ids))
|
|
143
|
+
.returning({ id: workspaceTeamMembers.id });
|
|
144
|
+
let revokedInvitations = 0;
|
|
145
|
+
let revokedPasses = 0;
|
|
146
|
+
for (const { workspaceId, userId } of removed) {
|
|
147
|
+
const passes = await tx
|
|
148
|
+
.update(demoPasses)
|
|
149
|
+
.set({ revokedAt: sql`now()` })
|
|
150
|
+
.where(
|
|
151
|
+
and(
|
|
152
|
+
eq(demoPasses.workspaceId, workspaceId),
|
|
153
|
+
isNull(demoPasses.revokedAt),
|
|
154
|
+
or(eq(demoPasses.userId, userId), eq(demoPasses.createdBy, userId))
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
.returning({ id: demoPasses.id });
|
|
158
|
+
if (passes.length > 0) {
|
|
159
|
+
const passIds = passes.map((p) => p.id);
|
|
160
|
+
const sessions = (
|
|
161
|
+
await tx
|
|
162
|
+
.select({ sessionId: demoPassSessions.sessionId })
|
|
163
|
+
.from(demoPassSessions)
|
|
164
|
+
.where(inArray(demoPassSessions.passId, passIds))
|
|
165
|
+
).map((s) => s.sessionId);
|
|
166
|
+
if (sessions.length > 0) {
|
|
167
|
+
await tx.delete(oauthAccessToken).where(inArray(oauthAccessToken.sessionId, sessions));
|
|
168
|
+
await tx.delete(oauthRefreshToken).where(inArray(oauthRefreshToken.sessionId, sessions));
|
|
169
|
+
await tx.delete(demoPassSessions).where(inArray(demoPassSessions.sessionId, sessions));
|
|
170
|
+
await tx.delete(sessionTable).where(inArray(sessionTable.id, sessions));
|
|
171
|
+
}
|
|
172
|
+
revokedPasses += passes.length;
|
|
173
|
+
}
|
|
174
|
+
const [person] = await tx
|
|
175
|
+
.select({ email: userTable.email })
|
|
176
|
+
.from(userTable)
|
|
177
|
+
.where(eq(userTable.id, userId))
|
|
178
|
+
.limit(1);
|
|
179
|
+
const rows = await tx
|
|
180
|
+
.update(invitations)
|
|
181
|
+
.set({ revokedAt: sql`now()` })
|
|
182
|
+
.where(
|
|
183
|
+
and(
|
|
184
|
+
eq(invitations.workspaceId, workspaceId),
|
|
185
|
+
isNull(invitations.acceptedAt),
|
|
186
|
+
isNull(invitations.revokedAt),
|
|
187
|
+
person
|
|
188
|
+
? or(eq(invitations.invitedBy, userId), sql`lower(${invitations.email}) = lower(${person.email})`)
|
|
189
|
+
: eq(invitations.invitedBy, userId)
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
.returning({ id: invitations.id });
|
|
193
|
+
revokedInvitations += rows.length;
|
|
194
|
+
}
|
|
195
|
+
const tool = toolHook ? await toolHook(tx, removed) : {};
|
|
196
|
+
return {
|
|
197
|
+
projectGrants: grants.length,
|
|
198
|
+
teamSeats: seats.length,
|
|
199
|
+
invitations: revokedInvitations,
|
|
200
|
+
demoPasses: revokedPasses,
|
|
201
|
+
tool
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Two passes of `deleteMembershipGrants` as one record: every count summed, the tool's by name. */
|
|
206
|
+
export function mergeRemovalCounts(a: RemovalCounts, b: RemovalCounts): RemovalCounts {
|
|
207
|
+
const tool: Record<string, number> = { ...a.tool };
|
|
208
|
+
for (const [key, n] of Object.entries(b.tool)) tool[key] = (tool[key] ?? 0) + n;
|
|
209
|
+
return {
|
|
210
|
+
projectGrants: a.projectGrants + b.projectGrants,
|
|
211
|
+
teamSeats: a.teamSeats + b.teamSeats,
|
|
212
|
+
invitations: a.invitations + b.invitations,
|
|
213
|
+
demoPasses: a.demoPasses + b.demoPasses,
|
|
214
|
+
tool
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
import { hasNulDeep } from '@antasphere/chassis-contract';
|
|
3
|
+
import { apiError } from '../api/errors.js';
|
|
4
|
+
|
|
5
|
+
/** Matches better-call's / Hono's JSON content-type test (the json-depth regex). */
|
|
6
|
+
const JSON_CONTENT_TYPE = /^application\/([a-z0-9.+-]*\+)?json/i;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Pre-validates JSON bodies bound for the Better Auth mount (AF-1 + the
|
|
10
|
+
* update-user half of SL-B4, PRDCT-1358).
|
|
11
|
+
*
|
|
12
|
+
* The load-bearing half is NUL: Better Auth's free-text sinks (`/update-user`'s
|
|
13
|
+
* `name`) are outside the contract, so a NUL rode through to Postgres (SQLSTATE
|
|
14
|
+
* 22021) and surfaced as Better Auth's OWN 500 — a response `app.onError` never
|
|
15
|
+
* sees, so the app-level 22021 backstop cannot reach `/auth/*`. Refusing it
|
|
16
|
+
* here, before the mount, is the only complete place.
|
|
17
|
+
*
|
|
18
|
+
* The malformed/empty-JSON half is defence in depth and a wire-shape
|
|
19
|
+
* normalizer: on the pinned Better Auth (better-call ≥ 1.3.7) a JSON parse
|
|
20
|
+
* error already answers 400 (`BAD_REQUEST`), not a 500 — but with better-call's
|
|
21
|
+
* own error code, not this API's. Answering `invalid_json` here keeps the auth
|
|
22
|
+
* surface's parse errors in the same envelope as every other route, and guards
|
|
23
|
+
* a future dependency change that reverts to a 500.
|
|
24
|
+
*
|
|
25
|
+
* A body under a JSON content-type must parse and carry no NUL anywhere;
|
|
26
|
+
* non-JSON content types pass untouched (the OAuth token endpoint is
|
|
27
|
+
* form-encoded), as do bodyless requests. The body is read from a clone — the
|
|
28
|
+
* mount consumes the original.
|
|
29
|
+
*/
|
|
30
|
+
export function authBodyGuard(): MiddlewareHandler {
|
|
31
|
+
return async (c, next) => {
|
|
32
|
+
const raw = c.req.raw;
|
|
33
|
+
if (!raw.body) return next();
|
|
34
|
+
if (!JSON_CONTENT_TYPE.test(raw.headers.get('content-type') ?? '')) return next();
|
|
35
|
+
let text: string;
|
|
36
|
+
try {
|
|
37
|
+
text = await raw.clone().text();
|
|
38
|
+
} catch {
|
|
39
|
+
// Unreadable body — let the mount produce its own error.
|
|
40
|
+
return next();
|
|
41
|
+
}
|
|
42
|
+
let parsed: unknown;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(text);
|
|
45
|
+
} catch {
|
|
46
|
+
return apiError(c, 400, 'invalid_json', 'Request body is not valid JSON');
|
|
47
|
+
}
|
|
48
|
+
if (hasNulDeep(parsed)) {
|
|
49
|
+
return apiError(
|
|
50
|
+
c,
|
|
51
|
+
400,
|
|
52
|
+
'invalid_characters',
|
|
53
|
+
'Request contains characters that cannot be stored (e.g. a NUL byte)'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return next();
|
|
57
|
+
};
|
|
58
|
+
}
|