@noodleseed/one 0.110.0 → 0.111.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/dist/commands/analytics-ops.d.ts.map +1 -1
- package/dist/commands/analytics-ops.js +36 -57
- package/dist/commands/analytics-ops.js.map +1 -1
- package/dist/commands/apps-ops.d.ts.map +1 -1
- package/dist/commands/apps-ops.js +12 -32
- package/dist/commands/apps-ops.js.map +1 -1
- package/dist/commands/archive-ops.d.ts.map +1 -1
- package/dist/commands/archive-ops.js +30 -48
- package/dist/commands/archive-ops.js.map +1 -1
- package/dist/commands/audit-ops.js +17 -40
- package/dist/commands/audit-ops.js.map +1 -1
- package/dist/commands/author-loop.d.ts.map +1 -1
- package/dist/commands/author-loop.js +27 -51
- package/dist/commands/author-loop.js.map +1 -1
- package/dist/commands/catalog-data-tenant-admin.d.ts.map +1 -1
- package/dist/commands/catalog-data-tenant-admin.js +35 -0
- package/dist/commands/catalog-data-tenant-admin.js.map +1 -1
- package/dist/commands/config-values.d.ts.map +1 -1
- package/dist/commands/config-values.js +24 -59
- package/dist/commands/config-values.js.map +1 -1
- package/dist/commands/deployments-ops.d.ts.map +1 -1
- package/dist/commands/deployments-ops.js +11 -39
- package/dist/commands/deployments-ops.js.map +1 -1
- package/dist/commands/devtools.d.ts.map +1 -1
- package/dist/commands/devtools.js +19 -35
- package/dist/commands/devtools.js.map +1 -1
- package/dist/commands/envs-ops.d.ts.map +1 -1
- package/dist/commands/envs-ops.js +10 -35
- package/dist/commands/envs-ops.js.map +1 -1
- package/dist/commands/github-shared.d.ts +1 -1
- package/dist/commands/github-shared.d.ts.map +1 -1
- package/dist/commands/github-shared.js +11 -33
- package/dist/commands/github-shared.js.map +1 -1
- package/dist/commands/logs-ops.d.ts.map +1 -1
- package/dist/commands/logs-ops.js +18 -30
- package/dist/commands/logs-ops.js.map +1 -1
- package/dist/commands/org-admin.d.ts.map +1 -1
- package/dist/commands/org-admin.js +13 -47
- package/dist/commands/org-admin.js.map +1 -1
- package/dist/commands/org-domains.js +5 -36
- package/dist/commands/org-domains.js.map +1 -1
- package/dist/commands/org-mcp-subdomain.d.ts +9 -0
- package/dist/commands/org-mcp-subdomain.d.ts.map +1 -0
- package/dist/commands/org-mcp-subdomain.js +144 -0
- package/dist/commands/org-mcp-subdomain.js.map +1 -0
- package/dist/commands/org-member-args.d.ts.map +1 -1
- package/dist/commands/org-member-args.js +22 -57
- package/dist/commands/org-member-args.js.map +1 -1
- package/dist/commands/org-openai-challenge.js +9 -40
- package/dist/commands/org-openai-challenge.js.map +1 -1
- package/dist/commands/resource-shared.d.ts +1 -1
- package/dist/commands/resource-shared.d.ts.map +1 -1
- package/dist/commands/resource-shared.js +6 -31
- package/dist/commands/resource-shared.js.map +1 -1
- package/dist/commands/service-ops.js +21 -40
- package/dist/commands/service-ops.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +21 -52
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/shared.d.ts +16 -0
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +45 -33
- package/dist/commands/shared.js.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/contracts.d.ts +39 -0
- package/node_modules/@noodle-borg/control-plane/dist/contracts.d.ts.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.d.ts +116 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.js +302 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/index.d.ts +6 -2
- package/node_modules/@noodle-borg/control-plane/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/index.js +5 -1
- package/node_modules/@noodle-borg/control-plane/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.d.ts +42 -0
- package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.js +181 -0
- package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/organization-helpers.d.ts +13 -0
- package/node_modules/@noodle-borg/control-plane/dist/organization-helpers.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/organization-helpers.js +41 -0
- package/node_modules/@noodle-borg/control-plane/dist/organization-helpers.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-claims.d.ts +18 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-claims.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-claims.js +173 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-claims.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-schema.d.ts +4 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-schema.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-schema.js +134 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-mcp-subdomain-schema.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.d.ts.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.js +2 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.js.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/validation.d.ts +2 -0
- package/node_modules/@noodle-borg/control-plane/dist/validation.d.ts.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/validation.js +4 -0
- package/node_modules/@noodle-borg/control-plane/dist/validation.js.map +1 -1
- package/node_modules/@noodle-borg/module/dist/contract.d.ts +11 -3
- package/node_modules/@noodle-borg/module/dist/contract.d.ts.map +1 -1
- package/node_modules/@noodle-borg/module/dist/contract.js +61 -12
- package/node_modules/@noodle-borg/module/dist/contract.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/developer-mcp/control-plane-adapter.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/developer-mcp/control-plane-adapter.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/developer-mcp/control-plane-adapter.js +6 -4
- package/node_modules/@noodle-borg/service/dist/developer-mcp/control-plane-adapter.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/developer-mcp/inspection.d.ts +3 -6
- package/node_modules/@noodle-borg/service/dist/developer-mcp/inspection.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/developer-mcp/inspection.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/main.js +1 -1
- package/node_modules/@noodle-borg/service/dist/main.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.d.ts +15 -28
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.js +15 -51
- package/node_modules/@noodle-borg/service/dist/mcp-public-routing.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.js +7 -3
- package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-principal-resource.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-principal-resource.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-principal-resource.js +7 -35
- package/node_modules/@noodle-borg/service/dist/oauth/service-principal-resource.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/operations/rollback-deployment.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/operations/rollback-deployment.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/operations/rollback-deployment.js +1 -1
- package/node_modules/@noodle-borg/service/dist/operations/rollback-deployment.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/options.d.ts +3 -3
- package/node_modules/@noodle-borg/service/dist/personal-workspace.d.ts +1 -3
- package/node_modules/@noodle-borg/service/dist/personal-workspace.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/personal-workspace.js +2 -17
- package/node_modules/@noodle-borg/service/dist/personal-workspace.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-helpers.d.ts +4 -2
- package/node_modules/@noodle-borg/service/dist/registry-helpers.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-helpers.js +8 -3
- package/node_modules/@noodle-borg/service/dist/registry-helpers.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-status.d.ts +2 -3
- package/node_modules/@noodle-borg/service/dist/registry-status.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-status.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry.d.ts +2 -4
- package/node_modules/@noodle-borg/service/dist/registry.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/apps.d.ts +3 -3
- package/node_modules/@noodle-borg/service/dist/routes/apps.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/apps.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/apps.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-dispatch.d.ts +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-dispatch.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-dispatch.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-dispatch.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.d.ts +2 -3
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.js +2 -1
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/contracts.d.ts +29 -0
- package/node_modules/@noodle-borg/service/dist/routes/contracts.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/contracts.js +39 -0
- package/node_modules/@noodle-borg/service/dist/routes/contracts.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +4 -6
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/credential-auth-dispatch.d.ts +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/credential-auth-dispatch.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/credential-auth-dispatch.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/deployments.d.ts +3 -3
- package/node_modules/@noodle-borg/service/dist/routes/deployments.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/deployments.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/deployments.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/diagnostics.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/diagnostics.js +5 -6
- package/node_modules/@noodle-borg/service/dist/routes/diagnostics.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/endpoint-enrichment.d.ts +2 -3
- package/node_modules/@noodle-borg/service/dist/routes/endpoint-enrichment.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/endpoint-enrichment.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/envs.d.ts +3 -3
- package/node_modules/@noodle-borg/service/dist/routes/envs.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/envs.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/envs.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/openai-apps-challenge.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/openai-apps-challenge.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/openai-apps-challenge.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/org-admin-dispatch.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/org-admin-dispatch.js +13 -1
- package/node_modules/@noodle-borg/service/dist/routes/org-admin-dispatch.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/org-admin.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/org-admin.js +10 -7
- package/node_modules/@noodle-borg/service/dist/routes/org-admin.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/org-mcp-subdomain.d.ts +8 -0
- package/node_modules/@noodle-borg/service/dist/routes/org-mcp-subdomain.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/org-mcp-subdomain.js +175 -0
- package/node_modules/@noodle-borg/service/dist/routes/org-mcp-subdomain.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/paths.d.ts +3 -0
- package/node_modules/@noodle-borg/service/dist/routes/paths.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/paths.js +11 -0
- package/node_modules/@noodle-borg/service/dist/routes/paths.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/protected-resource-metadata.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/routes/protected-resource-metadata.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/protected-resource-metadata.js +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/protected-resource-metadata.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/resource-read-dispatch.d.ts +3 -2
- package/node_modules/@noodle-borg/service/dist/routes/resource-read-dispatch.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/resource-read-dispatch.js +6 -6
- package/node_modules/@noodle-borg/service/dist/routes/resource-read-dispatch.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/rollback.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/rollback.js +3 -3
- package/node_modules/@noodle-borg/service/dist/routes/rollback.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve-resource-auth.d.ts +3 -5
- package/node_modules/@noodle-borg/service/dist/serve-resource-auth.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/serve-resource-auth.js +18 -15
- package/node_modules/@noodle-borg/service/dist/serve-resource-auth.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/service.js +24 -35
- package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts +4 -94
- package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/control-plane.js +25 -265
- package/node_modules/@noodle-borg/service/dist/store/control-plane.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-mcp-subdomain.d.ts +13 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres-mcp-subdomain.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres-mcp-subdomain.js +40 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres-mcp-subdomain.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts +2 -2
- package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.js +2 -2
- package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.d.ts +2 -2
- package/node_modules/@noodle-borg/service/dist/store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts +2 -0
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.js +14 -8
- package/node_modules/@noodle-borg/transport-http/dist/handler.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/identity-authorization.d.ts +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/identity-authorization.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts +2 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.js +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.d.ts +42 -0
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.js +49 -0
- package/node_modules/@noodle-borg/transport-http/dist/public-routing.js.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/routing.d.ts +3 -2
- package/node_modules/@noodle-borg/transport-http/dist/routing.d.ts.map +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/routing.js +6 -3
- package/node_modules/@noodle-borg/transport-http/dist/routing.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { isSystemOwnedOrgSlug, validateMcpSubdomain, validateSlug } from './validation.js';
|
|
3
|
+
const MCP_SUBDOMAIN_COOLDOWN_MS = 30 * 24 * 60 * 60 * 1000;
|
|
4
|
+
export class McpSubdomainOwnerRequiredError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super('organization owner required');
|
|
7
|
+
this.name = 'McpSubdomainOwnerRequiredError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class McpSubdomainUnavailableError extends Error {
|
|
11
|
+
constructor() {
|
|
12
|
+
super('MCP subdomain is unavailable');
|
|
13
|
+
this.name = 'McpSubdomainUnavailableError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class McpSubdomainIdempotencyConflictError extends Error {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('idempotency key was already used for another MCP subdomain request');
|
|
19
|
+
this.name = 'McpSubdomainIdempotencyConflictError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class McpSubdomainCooldownError extends Error {
|
|
23
|
+
changeAllowedAt;
|
|
24
|
+
constructor(changeAllowedAt) {
|
|
25
|
+
super('MCP subdomain change is in cooldown');
|
|
26
|
+
this.name = 'McpSubdomainCooldownError';
|
|
27
|
+
this.changeAllowedAt = changeAllowedAt;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** In-memory parity for active claim reads and organization-creation defaults. */
|
|
31
|
+
export class InMemoryMcpSubdomainClaimStore {
|
|
32
|
+
#activeByOrg = new Map();
|
|
33
|
+
#activeBySubdomain = new Map();
|
|
34
|
+
#claimedSubdomains = new Set();
|
|
35
|
+
#lastChangedAtByOrg = new Map();
|
|
36
|
+
#mutations = new Map();
|
|
37
|
+
#now;
|
|
38
|
+
#mutationTail = Promise.resolve();
|
|
39
|
+
constructor(now = () => new Date()) {
|
|
40
|
+
this.#now = now;
|
|
41
|
+
}
|
|
42
|
+
ensureDefaultMcpSubdomain(org) {
|
|
43
|
+
const orgSlug = validateSlug('org', org);
|
|
44
|
+
if (isSystemOwnedOrgSlug(orgSlug))
|
|
45
|
+
return undefined;
|
|
46
|
+
const existing = this.#activeByOrg.get(orgSlug);
|
|
47
|
+
if (existing !== undefined)
|
|
48
|
+
return existing;
|
|
49
|
+
const mcpSubdomain = validateMcpSubdomain(orgSlug);
|
|
50
|
+
if (this.#claimedSubdomains.has(mcpSubdomain)) {
|
|
51
|
+
throw new McpSubdomainUnavailableError();
|
|
52
|
+
}
|
|
53
|
+
const record = {
|
|
54
|
+
mcpSubdomain,
|
|
55
|
+
orgSlug,
|
|
56
|
+
claimedAt: this.#now().toISOString(),
|
|
57
|
+
};
|
|
58
|
+
this.#activeByOrg.set(orgSlug, record);
|
|
59
|
+
this.#activeBySubdomain.set(mcpSubdomain, record);
|
|
60
|
+
this.#claimedSubdomains.add(mcpSubdomain);
|
|
61
|
+
return record;
|
|
62
|
+
}
|
|
63
|
+
getActiveMcpSubdomain(org) {
|
|
64
|
+
return Promise.resolve(this.#activeByOrg.get(validateSlug('org', org)));
|
|
65
|
+
}
|
|
66
|
+
resolveActiveMcpSubdomain(mcpSubdomain) {
|
|
67
|
+
return Promise.resolve(this.#activeBySubdomain.get(validateMcpSubdomain(mcpSubdomain)));
|
|
68
|
+
}
|
|
69
|
+
async getMcpSubdomainSetting(org) {
|
|
70
|
+
const claim = this.#activeByOrg.get(validateSlug('org', org));
|
|
71
|
+
if (claim === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
const changeAllowedAt = this.#changeAllowedAt(claim.orgSlug);
|
|
74
|
+
return { ...claim, ...(changeAllowedAt === undefined ? {} : { changeAllowedAt }) };
|
|
75
|
+
}
|
|
76
|
+
changeMcpSubdomain(input, isExactOwner) {
|
|
77
|
+
return this.#serialize(async () => {
|
|
78
|
+
const org = validateSlug('org', input.org);
|
|
79
|
+
if (!(await isExactOwner()))
|
|
80
|
+
throw new McpSubdomainOwnerRequiredError();
|
|
81
|
+
if (input.idempotencyKey.length === 0) {
|
|
82
|
+
throw new Error('idempotency key must not be empty');
|
|
83
|
+
}
|
|
84
|
+
const keyHash = digest(input.idempotencyKey);
|
|
85
|
+
const fingerprint = `v1:${digest(input.mcpSubdomain)}`;
|
|
86
|
+
const recordKey = `${org}\u0000${keyHash}`;
|
|
87
|
+
const replay = this.#mutations.get(recordKey);
|
|
88
|
+
if (replay !== undefined) {
|
|
89
|
+
if (replay.fingerprint !== fingerprint) {
|
|
90
|
+
throw new McpSubdomainIdempotencyConflictError();
|
|
91
|
+
}
|
|
92
|
+
return { ...replay.result, replayed: true };
|
|
93
|
+
}
|
|
94
|
+
const mcpSubdomain = validateMcpSubdomain(input.mcpSubdomain);
|
|
95
|
+
const current = this.#activeByOrg.get(org);
|
|
96
|
+
if (current === undefined) {
|
|
97
|
+
throw new Error(`active MCP subdomain claim missing for organization "${org}"`);
|
|
98
|
+
}
|
|
99
|
+
const changeAllowedAt = this.#changeAllowedAt(org);
|
|
100
|
+
if (mcpSubdomain === current.mcpSubdomain) {
|
|
101
|
+
const result = {
|
|
102
|
+
orgSlug: org,
|
|
103
|
+
previousMcpSubdomain: current.mcpSubdomain,
|
|
104
|
+
mcpSubdomain,
|
|
105
|
+
changed: false,
|
|
106
|
+
replayed: false,
|
|
107
|
+
...(changeAllowedAt === undefined ? {} : { changeAllowedAt }),
|
|
108
|
+
auditCommitted: false,
|
|
109
|
+
};
|
|
110
|
+
this.#mutations.set(recordKey, { fingerprint, result });
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
const now = this.#now();
|
|
114
|
+
if (changeAllowedAt !== undefined && now.getTime() < Date.parse(changeAllowedAt)) {
|
|
115
|
+
throw new McpSubdomainCooldownError(changeAllowedAt);
|
|
116
|
+
}
|
|
117
|
+
if (this.#claimedSubdomains.has(mcpSubdomain)) {
|
|
118
|
+
throw new McpSubdomainUnavailableError();
|
|
119
|
+
}
|
|
120
|
+
const changedAt = now.toISOString();
|
|
121
|
+
const nextChangeAllowedAt = new Date(now.getTime() + MCP_SUBDOMAIN_COOLDOWN_MS).toISOString();
|
|
122
|
+
const next = {
|
|
123
|
+
orgSlug: org,
|
|
124
|
+
mcpSubdomain,
|
|
125
|
+
claimedAt: changedAt,
|
|
126
|
+
};
|
|
127
|
+
this.#activeBySubdomain.delete(current.mcpSubdomain);
|
|
128
|
+
this.#activeByOrg.set(org, next);
|
|
129
|
+
this.#activeBySubdomain.set(mcpSubdomain, next);
|
|
130
|
+
this.#claimedSubdomains.add(mcpSubdomain);
|
|
131
|
+
this.#lastChangedAtByOrg.set(org, changedAt);
|
|
132
|
+
const result = {
|
|
133
|
+
orgSlug: org,
|
|
134
|
+
previousMcpSubdomain: current.mcpSubdomain,
|
|
135
|
+
mcpSubdomain,
|
|
136
|
+
changed: true,
|
|
137
|
+
replayed: false,
|
|
138
|
+
changedAt,
|
|
139
|
+
changeAllowedAt: nextChangeAllowedAt,
|
|
140
|
+
auditCommitted: false,
|
|
141
|
+
};
|
|
142
|
+
this.#mutations.set(recordKey, { fingerprint, result });
|
|
143
|
+
return result;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
#changeAllowedAt(org) {
|
|
147
|
+
const changedAt = this.#lastChangedAtByOrg.get(org);
|
|
148
|
+
return changedAt === undefined
|
|
149
|
+
? undefined
|
|
150
|
+
: new Date(Date.parse(changedAt) + MCP_SUBDOMAIN_COOLDOWN_MS).toISOString();
|
|
151
|
+
}
|
|
152
|
+
#serialize(operation) {
|
|
153
|
+
const result = this.#mutationTail.then(operation, operation);
|
|
154
|
+
this.#mutationTail = result.then(() => undefined, () => undefined);
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function digest(value) {
|
|
159
|
+
return createHash('sha256').update(value).digest('hex');
|
|
160
|
+
}
|
|
161
|
+
export async function resolveMcpSubdomainTenant(store, ref) {
|
|
162
|
+
const claim = await store.resolveActiveMcpSubdomain(ref.mcpSubdomain);
|
|
163
|
+
if (claim === undefined)
|
|
164
|
+
return undefined;
|
|
165
|
+
return {
|
|
166
|
+
org: claim.orgSlug,
|
|
167
|
+
app: ref.app,
|
|
168
|
+
env: ref.env,
|
|
169
|
+
...(ref.serverVersion === undefined ? {} : { serverVersion: ref.serverVersion }),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export async function mcpSubdomainEndpointOptions(store, org, publicBaseDomain) {
|
|
173
|
+
if (publicBaseDomain === undefined)
|
|
174
|
+
return {};
|
|
175
|
+
const claim = await store.getActiveMcpSubdomain(org);
|
|
176
|
+
if (claim === undefined) {
|
|
177
|
+
throw new Error(`active MCP subdomain claim missing for organization "${org}"`);
|
|
178
|
+
}
|
|
179
|
+
return { publicBaseDomain, mcpSubdomain: claim.mcpSubdomain };
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=mcp-subdomain-claims.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-subdomain-claims.js","sourceRoot":"","sources":["../src/mcp-subdomain-claims.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SignupAllowlistKind } from './contracts.js';
|
|
2
|
+
export declare function memberKey(org: string, subject: string): string;
|
|
3
|
+
export declare function domainKey(org: string, domain: string): string;
|
|
4
|
+
export declare function domainFromEmail(email: string): string | undefined;
|
|
5
|
+
export declare function normalizeSignupAllowlistValue(kind: SignupAllowlistKind, value: string): string;
|
|
6
|
+
export declare function signupKey(kind: SignupAllowlistKind, value: string): string;
|
|
7
|
+
export declare function personalOrgSlug(identity: {
|
|
8
|
+
readonly subject: string;
|
|
9
|
+
readonly email: string;
|
|
10
|
+
}): string;
|
|
11
|
+
/** Immutable suffix used to discover and bind legacy email-derived personal organization slugs. */
|
|
12
|
+
export declare function personalOrgSlugSuffix(subject: string): string;
|
|
13
|
+
//# sourceMappingURL=organization-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-helpers.d.ts","sourceRoot":"","sources":["../src/organization-helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQjE;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GAAG,MAAM,CAIT;AAED,mGAAmG;AACnG,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { validateDomain, validateSlug } from './validation.js';
|
|
3
|
+
export function memberKey(org, subject) {
|
|
4
|
+
return `${org}/${subject}`;
|
|
5
|
+
}
|
|
6
|
+
export function domainKey(org, domain) {
|
|
7
|
+
return `${org}/${domain}`;
|
|
8
|
+
}
|
|
9
|
+
export function domainFromEmail(email) {
|
|
10
|
+
const at = email.lastIndexOf('@');
|
|
11
|
+
if (at < 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
try {
|
|
14
|
+
return validateDomain(email.slice(at + 1));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function normalizeSignupAllowlistValue(kind, value) {
|
|
21
|
+
return kind === 'domain' ? validateDomain(value) : value.trim().toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
export function signupKey(kind, value) {
|
|
24
|
+
return `${kind}/${value}`;
|
|
25
|
+
}
|
|
26
|
+
export function personalOrgSlug(identity) {
|
|
27
|
+
const localPart = identity.email.split('@')[0] ?? 'user';
|
|
28
|
+
const base = slugPart(localPart).slice(0, 52) || 'user';
|
|
29
|
+
return validateSlug('org', `u-${base}${personalOrgSlugSuffix(identity.subject)}`);
|
|
30
|
+
}
|
|
31
|
+
/** Immutable suffix used to discover and bind legacy email-derived personal organization slugs. */
|
|
32
|
+
export function personalOrgSlugSuffix(subject) {
|
|
33
|
+
return `-${createHash('sha256').update(subject).digest('hex').slice(0, 8)}`;
|
|
34
|
+
}
|
|
35
|
+
function slugPart(value) {
|
|
36
|
+
return value
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
39
|
+
.replace(/^-+|-+$/g, '');
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=organization-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-helpers.js","sourceRoot":"","sources":["../src/organization-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,OAAe;IACpD,OAAO,GAAG,GAAG,IAAI,OAAO,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,MAAc;IACnD,OAAO,GAAG,GAAG,IAAI,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,IAAyB,EAAE,KAAa;IACpF,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAyB,EAAE,KAAa;IAChE,OAAO,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAG/B;IACC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC;IACxD,OAAO,YAAY,CAAC,KAAK,EAAE,KAAK,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACpF,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Pool, PoolClient } from 'pg';
|
|
2
|
+
import type { ActiveMcpSubdomainClaim, ChangeMcpSubdomainInput, McpSubdomainMutationResult, McpSubdomainSetting } from './contracts.js';
|
|
3
|
+
type ChangedMcpSubdomainResult = Omit<McpSubdomainMutationResult, 'changed' | 'changedAt'> & {
|
|
4
|
+
readonly changed: true;
|
|
5
|
+
readonly changedAt: string;
|
|
6
|
+
};
|
|
7
|
+
export interface PostgresMcpSubdomainMutationOptions {
|
|
8
|
+
readonly now?: () => Date;
|
|
9
|
+
/** Called after state and mutation rows are staged but before commit. */
|
|
10
|
+
readonly recordAudit?: (client: Pick<PoolClient, 'query'>, result: ChangedMcpSubdomainResult, input: ChangeMcpSubdomainInput) => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare function getActiveMcpSubdomainRow(pool: Pool, org: string): Promise<ActiveMcpSubdomainClaim | undefined>;
|
|
13
|
+
export declare function resolveActiveMcpSubdomainRow(pool: Pool, mcpSubdomain: string): Promise<ActiveMcpSubdomainClaim | undefined>;
|
|
14
|
+
export declare function getMcpSubdomainSettingRow(pool: Pool, org: string): Promise<McpSubdomainSetting | undefined>;
|
|
15
|
+
/** Exact-owner, globally unique, permanently retiring mutation in one PostgreSQL transaction. */
|
|
16
|
+
export declare function changeMcpSubdomainRow(pool: Pool, input: ChangeMcpSubdomainInput, options?: PostgresMcpSubdomainMutationOptions): Promise<McpSubdomainMutationResult>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=postgres-mcp-subdomain-claims.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-mcp-subdomain-claims.d.ts","sourceRoot":"","sources":["../src/postgres-mcp-subdomain-claims.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAWxB,KAAK,yBAAyB,GAAG,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,WAAW,CAAC,GAAG;IAC3F,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAqBF,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,CACrB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EACjC,MAAM,EAAE,yBAAyB,EACjC,KAAK,EAAE,uBAAuB,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC,CAQ9C;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC,CAQ9C;AAED,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAe1C;AAED,iGAAiG;AACjG,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,uBAAuB,EAC9B,OAAO,GAAE,mCAAwC,GAChD,OAAO,CAAC,0BAA0B,CAAC,CAqHrC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { McpSubdomainCooldownError, McpSubdomainIdempotencyConflictError, McpSubdomainOwnerRequiredError, McpSubdomainUnavailableError, } from './mcp-subdomain-claims.js';
|
|
3
|
+
import { validateMcpSubdomain, validateSlug } from './validation.js';
|
|
4
|
+
const MCP_SUBDOMAIN_COOLDOWN_MS = 30 * 24 * 60 * 60 * 1000;
|
|
5
|
+
export async function getActiveMcpSubdomainRow(pool, org) {
|
|
6
|
+
const { rows } = await pool.query(`SELECT subdomain, org_slug, claimed_at
|
|
7
|
+
FROM org_mcp_subdomain_claims
|
|
8
|
+
WHERE org_slug = $1 AND state = 'active'`, [validateSlug('org', org)]);
|
|
9
|
+
return rows[0] === undefined ? undefined : claimRowToRecord(rows[0]);
|
|
10
|
+
}
|
|
11
|
+
export async function resolveActiveMcpSubdomainRow(pool, mcpSubdomain) {
|
|
12
|
+
const { rows } = await pool.query(`SELECT subdomain, org_slug, claimed_at
|
|
13
|
+
FROM org_mcp_subdomain_claims
|
|
14
|
+
WHERE subdomain = $1 AND state = 'active'`, [validateMcpSubdomain(mcpSubdomain)]);
|
|
15
|
+
return rows[0] === undefined ? undefined : claimRowToRecord(rows[0]);
|
|
16
|
+
}
|
|
17
|
+
export async function getMcpSubdomainSettingRow(pool, org) {
|
|
18
|
+
const { rows } = await pool.query(`SELECT claims.subdomain, claims.org_slug, claims.claimed_at,
|
|
19
|
+
(SELECT max(changed_at)
|
|
20
|
+
FROM org_mcp_subdomain_mutations
|
|
21
|
+
WHERE org_slug = claims.org_slug AND outcome = 'changed') AS last_changed_at
|
|
22
|
+
FROM org_mcp_subdomain_claims AS claims
|
|
23
|
+
WHERE claims.org_slug = $1 AND claims.state = 'active'`, [validateSlug('org', org)]);
|
|
24
|
+
const row = rows[0];
|
|
25
|
+
if (row === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
const claim = claimRowToRecord(row);
|
|
28
|
+
const changeAllowedAt = cooldownBoundary(row.last_changed_at);
|
|
29
|
+
return { ...claim, ...(changeAllowedAt === undefined ? {} : { changeAllowedAt }) };
|
|
30
|
+
}
|
|
31
|
+
/** Exact-owner, globally unique, permanently retiring mutation in one PostgreSQL transaction. */
|
|
32
|
+
export async function changeMcpSubdomainRow(pool, input, options = {}) {
|
|
33
|
+
const org = validateSlug('org', input.org);
|
|
34
|
+
if (input.idempotencyKey.length === 0)
|
|
35
|
+
throw new Error('idempotency key must not be empty');
|
|
36
|
+
const keyHash = `sha256:${digest(input.idempotencyKey)}`;
|
|
37
|
+
const fingerprint = `v1:${digest(input.mcpSubdomain)}`;
|
|
38
|
+
const now = (options.now ?? (() => new Date()))();
|
|
39
|
+
const client = await pool.connect();
|
|
40
|
+
try {
|
|
41
|
+
await client.query('BEGIN');
|
|
42
|
+
const { rowCount: orgCount } = await client.query('SELECT slug FROM orgs WHERE slug = $1 FOR UPDATE', [org]);
|
|
43
|
+
if (orgCount !== 1)
|
|
44
|
+
throw new McpSubdomainOwnerRequiredError();
|
|
45
|
+
const { rows: memberRows } = await client.query(`SELECT role FROM org_members
|
|
46
|
+
WHERE org_slug = $1 AND subject = $2
|
|
47
|
+
FOR UPDATE`, [org, input.actor.subject]);
|
|
48
|
+
if (memberRows[0]?.role !== 'owner')
|
|
49
|
+
throw new McpSubdomainOwnerRequiredError();
|
|
50
|
+
const { rows: replayRows } = await client.query(`SELECT request_fingerprint, outcome, previous_subdomain, current_subdomain,
|
|
51
|
+
recorded_at, changed_at
|
|
52
|
+
FROM org_mcp_subdomain_mutations
|
|
53
|
+
WHERE org_slug = $1 AND idempotency_key_hash = $2
|
|
54
|
+
FOR UPDATE`, [org, keyHash]);
|
|
55
|
+
const replay = replayRows[0];
|
|
56
|
+
if (replay !== undefined) {
|
|
57
|
+
if (replay.request_fingerprint !== fingerprint) {
|
|
58
|
+
throw new McpSubdomainIdempotencyConflictError();
|
|
59
|
+
}
|
|
60
|
+
const result = await replayResult(client, org, replay);
|
|
61
|
+
await client.query('COMMIT');
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
const mcpSubdomain = validateMcpSubdomain(input.mcpSubdomain);
|
|
65
|
+
const { rows: claimRows } = await client.query(`SELECT subdomain, org_slug, claimed_at
|
|
66
|
+
FROM org_mcp_subdomain_claims
|
|
67
|
+
WHERE org_slug = $1 AND state = 'active'
|
|
68
|
+
FOR UPDATE`, [org]);
|
|
69
|
+
const current = claimRows[0];
|
|
70
|
+
if (current === undefined) {
|
|
71
|
+
throw new Error(`active MCP subdomain claim missing for organization "${org}"`);
|
|
72
|
+
}
|
|
73
|
+
const lastChangedAt = await latestChangedAt(client, org);
|
|
74
|
+
const changeAllowedAt = cooldownBoundary(lastChangedAt);
|
|
75
|
+
if (mcpSubdomain === current.subdomain) {
|
|
76
|
+
await client.query(`INSERT INTO org_mcp_subdomain_mutations
|
|
77
|
+
(org_slug, idempotency_key_hash, request_fingerprint, outcome,
|
|
78
|
+
previous_subdomain, current_subdomain, actor_principal_id, recorded_at, changed_at)
|
|
79
|
+
VALUES ($1, $2, $3, 'noop', $4, $4, $5, $6, NULL)`, [org, keyHash, fingerprint, current.subdomain, input.actor.subject, now]);
|
|
80
|
+
const result = {
|
|
81
|
+
orgSlug: org,
|
|
82
|
+
previousMcpSubdomain: current.subdomain,
|
|
83
|
+
mcpSubdomain,
|
|
84
|
+
changed: false,
|
|
85
|
+
replayed: false,
|
|
86
|
+
...(changeAllowedAt === undefined ? {} : { changeAllowedAt }),
|
|
87
|
+
auditCommitted: false,
|
|
88
|
+
};
|
|
89
|
+
await client.query('COMMIT');
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
if (changeAllowedAt !== undefined && now.getTime() < Date.parse(changeAllowedAt)) {
|
|
93
|
+
throw new McpSubdomainCooldownError(changeAllowedAt);
|
|
94
|
+
}
|
|
95
|
+
await client.query(`UPDATE org_mcp_subdomain_claims
|
|
96
|
+
SET state = 'retired', retired_at = $2, retired_by_principal = $3
|
|
97
|
+
WHERE org_slug = $1 AND state = 'active'`, [org, now, input.actor.subject]);
|
|
98
|
+
await client.query(`INSERT INTO org_mcp_subdomain_claims (subdomain, org_slug, state, claimed_at)
|
|
99
|
+
VALUES ($1, $2, 'active', $3)`, [mcpSubdomain, org, now]);
|
|
100
|
+
await client.query(`INSERT INTO org_mcp_subdomain_mutations
|
|
101
|
+
(org_slug, idempotency_key_hash, request_fingerprint, outcome,
|
|
102
|
+
previous_subdomain, current_subdomain, actor_principal_id, recorded_at, changed_at)
|
|
103
|
+
VALUES ($1, $2, $3, 'changed', $4, $5, $6, $7, $7)`, [org, keyHash, fingerprint, current.subdomain, mcpSubdomain, input.actor.subject, now]);
|
|
104
|
+
const changedAt = now.toISOString();
|
|
105
|
+
const result = {
|
|
106
|
+
orgSlug: org,
|
|
107
|
+
previousMcpSubdomain: current.subdomain,
|
|
108
|
+
mcpSubdomain,
|
|
109
|
+
changed: true,
|
|
110
|
+
replayed: false,
|
|
111
|
+
changedAt,
|
|
112
|
+
changeAllowedAt: new Date(now.getTime() + MCP_SUBDOMAIN_COOLDOWN_MS).toISOString(),
|
|
113
|
+
auditCommitted: options.recordAudit !== undefined,
|
|
114
|
+
};
|
|
115
|
+
if (options.recordAudit !== undefined)
|
|
116
|
+
await options.recordAudit(client, result, input);
|
|
117
|
+
await client.query('COMMIT');
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
await client.query('ROLLBACK').catch(() => undefined);
|
|
122
|
+
if (isUniqueViolation(error))
|
|
123
|
+
throw new McpSubdomainUnavailableError();
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
client.release();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function replayResult(client, org, row) {
|
|
131
|
+
const changed = row.outcome === 'changed';
|
|
132
|
+
const changedAt = row.changed_at === null ? undefined : new Date(row.changed_at).toISOString();
|
|
133
|
+
const priorChangedAt = changed
|
|
134
|
+
? row.changed_at
|
|
135
|
+
: await latestChangedAt(client, org, new Date(row.recorded_at));
|
|
136
|
+
const changeAllowedAt = cooldownBoundary(priorChangedAt);
|
|
137
|
+
return {
|
|
138
|
+
orgSlug: org,
|
|
139
|
+
previousMcpSubdomain: row.previous_subdomain,
|
|
140
|
+
mcpSubdomain: row.current_subdomain,
|
|
141
|
+
changed,
|
|
142
|
+
replayed: true,
|
|
143
|
+
...(changedAt === undefined ? {} : { changedAt }),
|
|
144
|
+
...(changeAllowedAt === undefined ? {} : { changeAllowedAt }),
|
|
145
|
+
auditCommitted: changed,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async function latestChangedAt(queryable, org, atOrBefore) {
|
|
149
|
+
const { rows } = await queryable.query(`SELECT max(changed_at) AS changed_at
|
|
150
|
+
FROM org_mcp_subdomain_mutations
|
|
151
|
+
WHERE org_slug = $1 AND outcome = 'changed'
|
|
152
|
+
AND ($2::timestamptz IS NULL OR changed_at <= $2)`, [org, atOrBefore ?? null]);
|
|
153
|
+
return rows[0]?.changed_at ?? null;
|
|
154
|
+
}
|
|
155
|
+
function cooldownBoundary(value) {
|
|
156
|
+
return value === null
|
|
157
|
+
? undefined
|
|
158
|
+
: new Date(new Date(value).getTime() + MCP_SUBDOMAIN_COOLDOWN_MS).toISOString();
|
|
159
|
+
}
|
|
160
|
+
function digest(value) {
|
|
161
|
+
return createHash('sha256').update(value).digest('hex');
|
|
162
|
+
}
|
|
163
|
+
function isUniqueViolation(error) {
|
|
164
|
+
return typeof error === 'object' && error !== null && 'code' in error && error.code === '23505';
|
|
165
|
+
}
|
|
166
|
+
function claimRowToRecord(row) {
|
|
167
|
+
return {
|
|
168
|
+
mcpSubdomain: row.subdomain,
|
|
169
|
+
orgSlug: row.org_slug,
|
|
170
|
+
claimedAt: new Date(row.claimed_at).toISOString(),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=postgres-mcp-subdomain-claims.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-mcp-subdomain-claims.js","sourceRoot":"","sources":["../src/postgres-mcp-subdomain-claims.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Pool } from 'pg';
|
|
2
|
+
/** Install and reconcile the append-only MCP-subdomain claim ledger in one organization-locked migration. */
|
|
3
|
+
export declare function ensureMcpSubdomainClaimSchema(pool: Pool): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=postgres-mcp-subdomain-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-mcp-subdomain-schema.d.ts","sourceRoot":"","sources":["../src/postgres-mcp-subdomain-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE/B,6GAA6G;AAC7G,wBAAsB,6BAA6B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAiI7E"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/** Install and reconcile the append-only MCP-subdomain claim ledger in one organization-locked migration. */
|
|
2
|
+
export async function ensureMcpSubdomainClaimSchema(pool) {
|
|
3
|
+
const client = await pool.connect();
|
|
4
|
+
try {
|
|
5
|
+
await client.query('BEGIN');
|
|
6
|
+
await client.query('LOCK TABLE orgs IN SHARE ROW EXCLUSIVE MODE');
|
|
7
|
+
await client.query(`
|
|
8
|
+
CREATE TABLE IF NOT EXISTS org_mcp_subdomain_claims (
|
|
9
|
+
subdomain text PRIMARY KEY,
|
|
10
|
+
org_slug text NOT NULL REFERENCES orgs(slug) ON DELETE RESTRICT,
|
|
11
|
+
state text NOT NULL CHECK (state IN ('active', 'retired')),
|
|
12
|
+
claimed_at timestamptz NOT NULL DEFAULT now(),
|
|
13
|
+
retired_at timestamptz,
|
|
14
|
+
retired_by_principal text,
|
|
15
|
+
CONSTRAINT org_mcp_subdomain_claim_label_valid CHECK (
|
|
16
|
+
subdomain ~ '^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$'
|
|
17
|
+
AND subdomain NOT IN ('deploy', 'healthz', 'readyz', 'v1', 'o', 'mcp', 'local')
|
|
18
|
+
),
|
|
19
|
+
CONSTRAINT org_mcp_subdomain_claim_retirement_valid CHECK (
|
|
20
|
+
(state = 'active' AND retired_at IS NULL AND retired_by_principal IS NULL)
|
|
21
|
+
OR
|
|
22
|
+
(state = 'retired' AND retired_at IS NOT NULL AND retired_by_principal IS NOT NULL)
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
`);
|
|
26
|
+
await client.query(`
|
|
27
|
+
CREATE UNIQUE INDEX IF NOT EXISTS org_mcp_subdomain_claims_one_active_org_idx
|
|
28
|
+
ON org_mcp_subdomain_claims (org_slug)
|
|
29
|
+
WHERE state = 'active'
|
|
30
|
+
`);
|
|
31
|
+
await client.query(`
|
|
32
|
+
CREATE TABLE IF NOT EXISTS org_mcp_subdomain_mutations (
|
|
33
|
+
org_slug text NOT NULL REFERENCES orgs(slug) ON DELETE RESTRICT,
|
|
34
|
+
idempotency_key_hash text NOT NULL,
|
|
35
|
+
request_fingerprint text NOT NULL,
|
|
36
|
+
outcome text NOT NULL CHECK (outcome IN ('changed', 'noop')),
|
|
37
|
+
previous_subdomain text NOT NULL,
|
|
38
|
+
current_subdomain text NOT NULL,
|
|
39
|
+
actor_principal_id text NOT NULL,
|
|
40
|
+
recorded_at timestamptz NOT NULL,
|
|
41
|
+
changed_at timestamptz,
|
|
42
|
+
PRIMARY KEY (org_slug, idempotency_key_hash),
|
|
43
|
+
CONSTRAINT org_mcp_subdomain_mutation_change_valid CHECK (
|
|
44
|
+
(outcome = 'changed' AND changed_at IS NOT NULL)
|
|
45
|
+
OR (outcome = 'noop' AND changed_at IS NULL)
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
`);
|
|
49
|
+
await client.query(`
|
|
50
|
+
CREATE OR REPLACE FUNCTION guard_org_mcp_subdomain_claim_mutation()
|
|
51
|
+
RETURNS trigger
|
|
52
|
+
LANGUAGE plpgsql
|
|
53
|
+
AS $function$
|
|
54
|
+
BEGIN
|
|
55
|
+
IF TG_OP = 'DELETE' THEN
|
|
56
|
+
RAISE EXCEPTION 'MCP subdomain claims are append-only' USING ERRCODE = '23514';
|
|
57
|
+
END IF;
|
|
58
|
+
IF OLD.subdomain IS DISTINCT FROM NEW.subdomain
|
|
59
|
+
OR OLD.org_slug IS DISTINCT FROM NEW.org_slug
|
|
60
|
+
OR OLD.claimed_at IS DISTINCT FROM NEW.claimed_at
|
|
61
|
+
OR OLD.state <> 'active'
|
|
62
|
+
OR NEW.state <> 'retired'
|
|
63
|
+
OR OLD.retired_at IS NOT NULL
|
|
64
|
+
OR OLD.retired_by_principal IS NOT NULL
|
|
65
|
+
OR NEW.retired_at IS NULL
|
|
66
|
+
OR NEW.retired_by_principal IS NULL THEN
|
|
67
|
+
RAISE EXCEPTION 'invalid MCP subdomain claim transition' USING ERRCODE = '23514';
|
|
68
|
+
END IF;
|
|
69
|
+
RETURN NEW;
|
|
70
|
+
END
|
|
71
|
+
$function$
|
|
72
|
+
`);
|
|
73
|
+
await client.query(`
|
|
74
|
+
DROP TRIGGER IF EXISTS guard_org_mcp_subdomain_claim_mutation
|
|
75
|
+
ON org_mcp_subdomain_claims
|
|
76
|
+
`);
|
|
77
|
+
await client.query(`
|
|
78
|
+
CREATE TRIGGER guard_org_mcp_subdomain_claim_mutation
|
|
79
|
+
BEFORE UPDATE OR DELETE ON org_mcp_subdomain_claims
|
|
80
|
+
FOR EACH ROW EXECUTE FUNCTION guard_org_mcp_subdomain_claim_mutation()
|
|
81
|
+
`);
|
|
82
|
+
await client.query(`
|
|
83
|
+
INSERT INTO org_mcp_subdomain_claims (subdomain, org_slug, state, claimed_at)
|
|
84
|
+
SELECT slug, slug, 'active', created_at
|
|
85
|
+
FROM orgs
|
|
86
|
+
WHERE slug <> 'local'
|
|
87
|
+
ON CONFLICT (subdomain) DO NOTHING
|
|
88
|
+
`);
|
|
89
|
+
const { rows } = await client.query(`
|
|
90
|
+
SELECT count(*)::text AS invalid_count
|
|
91
|
+
FROM (
|
|
92
|
+
SELECT orgs.slug
|
|
93
|
+
FROM orgs
|
|
94
|
+
LEFT JOIN org_mcp_subdomain_claims AS claims
|
|
95
|
+
ON claims.org_slug = orgs.slug AND claims.state = 'active'
|
|
96
|
+
WHERE orgs.slug <> 'local'
|
|
97
|
+
GROUP BY orgs.slug
|
|
98
|
+
HAVING count(claims.subdomain) <> 1
|
|
99
|
+
) AS invalid_orgs
|
|
100
|
+
`);
|
|
101
|
+
if (rows[0]?.invalid_count !== '0') {
|
|
102
|
+
throw new Error('MCP subdomain backfill did not establish one active claim per hosted org');
|
|
103
|
+
}
|
|
104
|
+
await client.query(`
|
|
105
|
+
CREATE OR REPLACE FUNCTION claim_default_org_mcp_subdomain()
|
|
106
|
+
RETURNS trigger
|
|
107
|
+
LANGUAGE plpgsql
|
|
108
|
+
AS $function$
|
|
109
|
+
BEGIN
|
|
110
|
+
IF NEW.slug <> 'local' THEN
|
|
111
|
+
INSERT INTO org_mcp_subdomain_claims (subdomain, org_slug, state, claimed_at)
|
|
112
|
+
VALUES (NEW.slug, NEW.slug, 'active', NEW.created_at);
|
|
113
|
+
END IF;
|
|
114
|
+
RETURN NEW;
|
|
115
|
+
END
|
|
116
|
+
$function$
|
|
117
|
+
`);
|
|
118
|
+
await client.query('DROP TRIGGER IF EXISTS claim_default_org_mcp_subdomain ON orgs');
|
|
119
|
+
await client.query(`
|
|
120
|
+
CREATE TRIGGER claim_default_org_mcp_subdomain
|
|
121
|
+
AFTER INSERT ON orgs
|
|
122
|
+
FOR EACH ROW EXECUTE FUNCTION claim_default_org_mcp_subdomain()
|
|
123
|
+
`);
|
|
124
|
+
await client.query('COMMIT');
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
await client.query('ROLLBACK').catch(() => undefined);
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
client.release();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=postgres-mcp-subdomain-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-mcp-subdomain-schema.js","sourceRoot":"","sources":["../src/postgres-mcp-subdomain-schema.ts"],"names":[],"mappings":"AAEA,6GAA6G;AAC7G,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,IAAU;IAC5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAClE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;KAkBlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;KAIlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;KAiBlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;KAuBlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC;;;KAGlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;KAIlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;KAMlB,CAAC,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAA4B;;;;;;;;;;;KAW9D,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,aAAa,KAAK,GAAG,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;KAalB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACrF,MAAM,MAAM,CAAC,KAAK,CAAC;;;;KAIlB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-schema.d.ts","sourceRoot":"","sources":["../src/postgres-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"postgres-schema.d.ts","sourceRoot":"","sources":["../src/postgres-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAG/B,sFAAsF;AACtF,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFxE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ensureMcpSubdomainClaimSchema } from './postgres-mcp-subdomain-schema.js';
|
|
1
2
|
/** Idempotent organization, membership, signup, and onboarding persistence schema. */
|
|
2
3
|
export async function ensureOrganizationSchema(pool) {
|
|
3
4
|
await pool.query(`
|
|
@@ -84,5 +85,6 @@ export async function ensureOrganizationSchema(pool) {
|
|
|
84
85
|
CREATE INDEX IF NOT EXISTS org_invitations_org_email_idx
|
|
85
86
|
ON org_invitations (org_slug, email, expires_at)
|
|
86
87
|
`);
|
|
88
|
+
await ensureMcpSubdomainClaimSchema(pool);
|
|
87
89
|
}
|
|
88
90
|
//# sourceMappingURL=postgres-schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-schema.js","sourceRoot":"","sources":["../src/postgres-schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"postgres-schema.js","sourceRoot":"","sources":["../src/postgres-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AAEnF,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,IAAU;IACvD,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;KAMd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;KASd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;KAcd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC9F,MAAM,IAAI,CAAC,KAAK,CAAC;;;;KAId,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;KAUd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;KAQd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;KAQd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;KAYd,CAAC,CAAC;IACL,MAAM,IAAI,CAAC,KAAK,CAAC;;;KAGd,CAAC,CAAC;IACL,MAAM,6BAA6B,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC"}
|