@de-otio/trellis 0.6.1 → 0.7.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/env.d.ts +21 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +12 -0
- package/dist/env.js.map +1 -1
- package/dist/lambda/nightly-cron.d.ts.map +1 -1
- package/dist/lambda/nightly-cron.js +5 -2
- package/dist/lambda/nightly-cron.js.map +1 -1
- package/dist/lambda/post-confirmation.d.ts +30 -0
- package/dist/lambda/post-confirmation.d.ts.map +1 -1
- package/dist/lambda/post-confirmation.js +333 -29
- package/dist/lambda/post-confirmation.js.map +1 -1
- package/dist/lambda/pre-token-generation.d.ts +20 -0
- package/dist/lambda/pre-token-generation.d.ts.map +1 -1
- package/dist/lambda/pre-token-generation.js +233 -48
- package/dist/lambda/pre-token-generation.js.map +1 -1
- package/dist/lib/activitypub/activity-processor.d.ts.map +1 -1
- package/dist/lib/activitypub/activity-processor.js +2 -1
- package/dist/lib/activitypub/activity-processor.js.map +1 -1
- package/dist/lib/activitypub/group-service.d.ts +2 -2
- package/dist/lib/activitypub/group-service.d.ts.map +1 -1
- package/dist/lib/activitypub/group-service.js +5 -2
- package/dist/lib/activitypub/group-service.js.map +1 -1
- package/dist/lib/age-tier-transition.d.ts.map +1 -1
- package/dist/lib/age-tier-transition.js +19 -10
- package/dist/lib/age-tier-transition.js.map +1 -1
- package/dist/lib/audit/csv-export.d.ts +25 -0
- package/dist/lib/audit/csv-export.d.ts.map +1 -0
- package/dist/lib/audit/csv-export.js +54 -0
- package/dist/lib/audit/csv-export.js.map +1 -0
- package/dist/lib/audit/emit.d.ts +56 -0
- package/dist/lib/audit/emit.d.ts.map +1 -0
- package/dist/lib/audit/emit.js +124 -0
- package/dist/lib/audit/emit.js.map +1 -0
- package/dist/lib/audit/event-types.d.ts +36 -0
- package/dist/lib/audit/event-types.d.ts.map +1 -0
- package/dist/lib/audit/event-types.js +69 -0
- package/dist/lib/audit/event-types.js.map +1 -0
- package/dist/lib/audit/pii-filter.d.ts +22 -0
- package/dist/lib/audit/pii-filter.d.ts.map +1 -0
- package/dist/lib/audit/pii-filter.js +51 -0
- package/dist/lib/audit/pii-filter.js.map +1 -0
- package/dist/lib/audit-logger.js +1 -1
- package/dist/lib/audit-logger.js.map +1 -1
- package/dist/lib/auth/auth-context.d.ts +34 -0
- package/dist/lib/auth/auth-context.d.ts.map +1 -0
- package/dist/lib/auth/auth-context.js +10 -0
- package/dist/lib/auth/auth-context.js.map +1 -0
- package/dist/lib/auth/auth-middleware.d.ts +50 -0
- package/dist/lib/auth/auth-middleware.d.ts.map +1 -0
- package/dist/lib/auth/auth-middleware.js +153 -0
- package/dist/lib/auth/auth-middleware.js.map +1 -0
- package/dist/lib/auth/capabilities.d.ts +40 -0
- package/dist/lib/auth/capabilities.d.ts.map +1 -0
- package/dist/lib/auth/capabilities.js +44 -0
- package/dist/lib/auth/capabilities.js.map +1 -0
- package/dist/lib/auth/claims-cache.d.ts +70 -0
- package/dist/lib/auth/claims-cache.d.ts.map +1 -0
- package/dist/lib/auth/claims-cache.js +139 -0
- package/dist/lib/auth/claims-cache.js.map +1 -0
- package/dist/lib/auth/cognito-jwt.d.ts +6 -0
- package/dist/lib/auth/cognito-jwt.d.ts.map +1 -1
- package/dist/lib/auth/cognito-jwt.js.map +1 -1
- package/dist/lib/auth/idp-redirect-builder.d.ts +43 -0
- package/dist/lib/auth/idp-redirect-builder.d.ts.map +1 -0
- package/dist/lib/auth/idp-redirect-builder.js +48 -0
- package/dist/lib/auth/idp-redirect-builder.js.map +1 -0
- package/dist/lib/auth/require.d.ts +51 -0
- package/dist/lib/auth/require.d.ts.map +1 -0
- package/dist/lib/auth/require.js +99 -0
- package/dist/lib/auth/require.js.map +1 -0
- package/dist/lib/auth/role-grants.d.ts +18 -0
- package/dist/lib/auth/role-grants.d.ts.map +1 -0
- package/dist/lib/auth/role-grants.js +62 -0
- package/dist/lib/auth/role-grants.js.map +1 -0
- package/dist/lib/cognito/idp-sdk.d.ts +80 -0
- package/dist/lib/cognito/idp-sdk.d.ts.map +1 -0
- package/dist/lib/cognito/idp-sdk.js +186 -0
- package/dist/lib/cognito/idp-sdk.js.map +1 -0
- package/dist/lib/cognito/issuer-probe.d.ts +47 -0
- package/dist/lib/cognito/issuer-probe.d.ts.map +1 -0
- package/dist/lib/cognito/issuer-probe.js +319 -0
- package/dist/lib/cognito/issuer-probe.js.map +1 -0
- package/dist/lib/comment-handler.d.ts +7 -7
- package/dist/lib/comment-handler.d.ts.map +1 -1
- package/dist/lib/comment-handler.js +23 -20
- package/dist/lib/comment-handler.js.map +1 -1
- package/dist/lib/compliance/baseline.d.ts +15 -0
- package/dist/lib/compliance/baseline.d.ts.map +1 -0
- package/dist/lib/compliance/baseline.js +205 -0
- package/dist/lib/compliance/baseline.js.map +1 -0
- package/dist/lib/compliance/tenant-merge.d.ts +35 -0
- package/dist/lib/compliance/tenant-merge.d.ts.map +1 -0
- package/dist/lib/compliance/tenant-merge.js +80 -0
- package/dist/lib/compliance/tenant-merge.js.map +1 -0
- package/dist/lib/compliance/types.d.ts +135 -0
- package/dist/lib/compliance/types.d.ts.map +1 -0
- package/dist/lib/compliance/types.js +9 -0
- package/dist/lib/compliance/types.js.map +1 -0
- package/dist/lib/connection-code-handler.d.ts +4 -4
- package/dist/lib/connection-code-handler.d.ts.map +1 -1
- package/dist/lib/connection-code-handler.js +21 -11
- package/dist/lib/connection-code-handler.js.map +1 -1
- package/dist/lib/feed-handler.d.ts +2 -2
- package/dist/lib/feed-handler.d.ts.map +1 -1
- package/dist/lib/feed-handler.js +5 -9
- package/dist/lib/feed-handler.js.map +1 -1
- package/dist/lib/middleware/idempotency-store.d.ts +86 -0
- package/dist/lib/middleware/idempotency-store.d.ts.map +1 -0
- package/dist/lib/middleware/idempotency-store.js +109 -0
- package/dist/lib/middleware/idempotency-store.js.map +1 -0
- package/dist/lib/middleware/idempotency.d.ts +37 -0
- package/dist/lib/middleware/idempotency.d.ts.map +1 -0
- package/dist/lib/middleware/idempotency.js +358 -0
- package/dist/lib/middleware/idempotency.js.map +1 -0
- package/dist/lib/net/trusted-client-ip.d.ts +39 -0
- package/dist/lib/net/trusted-client-ip.d.ts.map +1 -0
- package/dist/lib/net/trusted-client-ip.js +100 -0
- package/dist/lib/net/trusted-client-ip.js.map +1 -0
- package/dist/lib/notification-handler.d.ts +5 -5
- package/dist/lib/notification-handler.d.ts.map +1 -1
- package/dist/lib/notification-handler.js +11 -9
- package/dist/lib/notification-handler.js.map +1 -1
- package/dist/lib/oauth/cognito-issuer.d.ts +34 -0
- package/dist/lib/oauth/cognito-issuer.d.ts.map +1 -0
- package/dist/lib/oauth/cognito-issuer.js +53 -0
- package/dist/lib/oauth/cognito-issuer.js.map +1 -0
- package/dist/lib/oauth/device-authorization.d.ts +145 -0
- package/dist/lib/oauth/device-authorization.d.ts.map +1 -0
- package/dist/lib/oauth/device-authorization.js +312 -0
- package/dist/lib/oauth/device-authorization.js.map +1 -0
- package/dist/lib/oauth/envelope-crypto.d.ts +101 -0
- package/dist/lib/oauth/envelope-crypto.d.ts.map +1 -0
- package/dist/lib/oauth/envelope-crypto.js +223 -0
- package/dist/lib/oauth/envelope-crypto.js.map +1 -0
- package/dist/lib/oauth/refresh-detection.d.ts +126 -0
- package/dist/lib/oauth/refresh-detection.d.ts.map +1 -0
- package/dist/lib/oauth/refresh-detection.js +248 -0
- package/dist/lib/oauth/refresh-detection.js.map +1 -0
- package/dist/lib/openapi/generator.d.ts +78 -0
- package/dist/lib/openapi/generator.d.ts.map +1 -0
- package/dist/lib/openapi/generator.js +201 -0
- package/dist/lib/openapi/generator.js.map +1 -0
- package/dist/lib/post-handler.d.ts +1 -1
- package/dist/lib/post-handler.d.ts.map +1 -1
- package/dist/lib/post-handler.js +4 -15
- package/dist/lib/post-handler.js.map +1 -1
- package/dist/lib/rate-limit.d.ts.map +1 -1
- package/dist/lib/rate-limit.js +11 -3
- package/dist/lib/rate-limit.js.map +1 -1
- package/dist/lib/routes/agent-authorize.d.ts +32 -0
- package/dist/lib/routes/agent-authorize.d.ts.map +1 -0
- package/dist/lib/routes/agent-authorize.js +479 -0
- package/dist/lib/routes/agent-authorize.js.map +1 -0
- package/dist/lib/routes/agent-sessions.d.ts +20 -0
- package/dist/lib/routes/agent-sessions.d.ts.map +1 -0
- package/dist/lib/routes/agent-sessions.js +124 -0
- package/dist/lib/routes/agent-sessions.js.map +1 -0
- package/dist/lib/routes/agent-surface.d.ts +37 -0
- package/dist/lib/routes/agent-surface.d.ts.map +1 -0
- package/dist/lib/routes/agent-surface.js +208 -0
- package/dist/lib/routes/agent-surface.js.map +1 -0
- package/dist/lib/routes/auth-discover.d.ts +18 -0
- package/dist/lib/routes/auth-discover.d.ts.map +1 -0
- package/dist/lib/routes/auth-discover.js +177 -0
- package/dist/lib/routes/auth-discover.js.map +1 -0
- package/dist/lib/routes/comments.d.ts.map +1 -1
- package/dist/lib/routes/comments.js +36 -7
- package/dist/lib/routes/comments.js.map +1 -1
- package/dist/lib/routes/connection-codes.d.ts.map +1 -1
- package/dist/lib/routes/connection-codes.js +21 -4
- package/dist/lib/routes/connection-codes.js.map +1 -1
- package/dist/lib/routes/content-discovery.d.ts.map +1 -1
- package/dist/lib/routes/content-discovery.js +18 -13
- package/dist/lib/routes/content-discovery.js.map +1 -1
- package/dist/lib/routes/dashboard.js +1 -1
- package/dist/lib/routes/dashboard.js.map +1 -1
- package/dist/lib/routes/employees.d.ts.map +1 -1
- package/dist/lib/routes/employees.js +57 -15
- package/dist/lib/routes/employees.js.map +1 -1
- package/dist/lib/routes/entities.d.ts.map +1 -1
- package/dist/lib/routes/entities.js +35 -19
- package/dist/lib/routes/entities.js.map +1 -1
- package/dist/lib/routes/errors.d.ts +34 -0
- package/dist/lib/routes/errors.d.ts.map +1 -0
- package/dist/lib/routes/errors.js +57 -0
- package/dist/lib/routes/errors.js.map +1 -0
- package/dist/lib/routes/feeds.d.ts.map +1 -1
- package/dist/lib/routes/feeds.js +12 -2
- package/dist/lib/routes/feeds.js.map +1 -1
- package/dist/lib/routes/index.d.ts.map +1 -1
- package/dist/lib/routes/index.js +50 -0
- package/dist/lib/routes/index.js.map +1 -1
- package/dist/lib/routes/mfa.d.ts.map +1 -1
- package/dist/lib/routes/mfa.js +1 -0
- package/dist/lib/routes/mfa.js.map +1 -1
- package/dist/lib/routes/notifications.d.ts.map +1 -1
- package/dist/lib/routes/notifications.js +21 -4
- package/dist/lib/routes/notifications.js.map +1 -1
- package/dist/lib/routes/oauth.d.ts +15 -0
- package/dist/lib/routes/oauth.d.ts.map +1 -0
- package/dist/lib/routes/oauth.js +139 -0
- package/dist/lib/routes/oauth.js.map +1 -0
- package/dist/lib/routes/posts.d.ts.map +1 -1
- package/dist/lib/routes/posts.js +30 -19
- package/dist/lib/routes/posts.js.map +1 -1
- package/dist/lib/routes/products.d.ts.map +1 -1
- package/dist/lib/routes/products.js +19 -22
- package/dist/lib/routes/products.js.map +1 -1
- package/dist/lib/routes/setup-status.d.ts +34 -0
- package/dist/lib/routes/setup-status.d.ts.map +1 -0
- package/dist/lib/routes/setup-status.js +87 -0
- package/dist/lib/routes/setup-status.js.map +1 -0
- package/dist/lib/routes/taxonomy-analytics.d.ts.map +1 -1
- package/dist/lib/routes/taxonomy-analytics.js +15 -14
- package/dist/lib/routes/taxonomy-analytics.js.map +1 -1
- package/dist/lib/routes/taxonomy.d.ts.map +1 -1
- package/dist/lib/routes/taxonomy.js +19 -16
- package/dist/lib/routes/taxonomy.js.map +1 -1
- package/dist/lib/routes/tenant-audit.d.ts +19 -0
- package/dist/lib/routes/tenant-audit.d.ts.map +1 -0
- package/dist/lib/routes/tenant-audit.js +244 -0
- package/dist/lib/routes/tenant-audit.js.map +1 -0
- package/dist/lib/routes/tenant-compliance.d.ts +21 -0
- package/dist/lib/routes/tenant-compliance.d.ts.map +1 -0
- package/dist/lib/routes/tenant-compliance.js +122 -0
- package/dist/lib/routes/tenant-compliance.js.map +1 -0
- package/dist/lib/routes/tenant-domains.d.ts +11 -0
- package/dist/lib/routes/tenant-domains.d.ts.map +1 -0
- package/dist/lib/routes/tenant-domains.js +95 -0
- package/dist/lib/routes/tenant-domains.js.map +1 -0
- package/dist/lib/routes/tenant-idp.d.ts +3 -0
- package/dist/lib/routes/tenant-idp.d.ts.map +1 -0
- package/dist/lib/routes/tenant-idp.js +89 -0
- package/dist/lib/routes/tenant-idp.js.map +1 -0
- package/dist/lib/routes/tenant-members.d.ts +13 -0
- package/dist/lib/routes/tenant-members.d.ts.map +1 -0
- package/dist/lib/routes/tenant-members.js +75 -0
- package/dist/lib/routes/tenant-members.js.map +1 -0
- package/dist/lib/routes/tenant-role-mappings.d.ts +11 -0
- package/dist/lib/routes/tenant-role-mappings.d.ts.map +1 -0
- package/dist/lib/routes/tenant-role-mappings.js +90 -0
- package/dist/lib/routes/tenant-role-mappings.js.map +1 -0
- package/dist/lib/routes/tenants.d.ts +13 -0
- package/dist/lib/routes/tenants.d.ts.map +1 -0
- package/dist/lib/routes/tenants.js +121 -0
- package/dist/lib/routes/tenants.js.map +1 -0
- package/dist/lib/routes/types.d.ts +9 -0
- package/dist/lib/routes/types.d.ts.map +1 -1
- package/dist/lib/schemas.d.ts +2 -2
- package/dist/lib/secrets/idp-secrets.d.ts +51 -0
- package/dist/lib/secrets/idp-secrets.d.ts.map +1 -0
- package/dist/lib/secrets/idp-secrets.js +111 -0
- package/dist/lib/secrets/idp-secrets.js.map +1 -0
- package/dist/lib/security-monitor.d.ts.map +1 -1
- package/dist/lib/security-monitor.js +6 -1
- package/dist/lib/security-monitor.js.map +1 -1
- package/dist/lib/session-manager.d.ts +1 -0
- package/dist/lib/session-manager.d.ts.map +1 -1
- package/dist/lib/session-manager.js.map +1 -1
- package/dist/lib/taxonomy-handler-factory.d.ts +4 -2
- package/dist/lib/taxonomy-handler-factory.d.ts.map +1 -1
- package/dist/lib/taxonomy-handler-factory.js +8 -7
- package/dist/lib/taxonomy-handler-factory.js.map +1 -1
- package/dist/lib/tenant/audit-emit.d.ts +18 -0
- package/dist/lib/tenant/audit-emit.d.ts.map +1 -0
- package/dist/lib/tenant/audit-emit.js +16 -0
- package/dist/lib/tenant/audit-emit.js.map +1 -0
- package/dist/lib/tenant/derive-domain.d.ts +19 -0
- package/dist/lib/tenant/derive-domain.d.ts.map +1 -0
- package/dist/lib/tenant/derive-domain.js +38 -0
- package/dist/lib/tenant/derive-domain.js.map +1 -0
- package/dist/lib/tenant/domain-handler.d.ts +42 -0
- package/dist/lib/tenant/domain-handler.d.ts.map +1 -0
- package/dist/lib/tenant/domain-handler.js +344 -0
- package/dist/lib/tenant/domain-handler.js.map +1 -0
- package/dist/lib/tenant/domain-validator.d.ts +28 -0
- package/dist/lib/tenant/domain-validator.d.ts.map +1 -0
- package/dist/lib/tenant/domain-validator.js +145 -0
- package/dist/lib/tenant/domain-validator.js.map +1 -0
- package/dist/lib/tenant/domain-verifier.d.ts +30 -0
- package/dist/lib/tenant/domain-verifier.d.ts.map +1 -0
- package/dist/lib/tenant/domain-verifier.js +53 -0
- package/dist/lib/tenant/domain-verifier.js.map +1 -0
- package/dist/lib/tenant/idp-handler.d.ts +29 -0
- package/dist/lib/tenant/idp-handler.d.ts.map +1 -0
- package/dist/lib/tenant/idp-handler.js +693 -0
- package/dist/lib/tenant/idp-handler.js.map +1 -0
- package/dist/lib/tenant/idp-name.d.ts +2 -0
- package/dist/lib/tenant/idp-name.d.ts.map +1 -0
- package/dist/lib/tenant/idp-name.js +20 -0
- package/dist/lib/tenant/idp-name.js.map +1 -0
- package/dist/lib/tenant/member-handler.d.ts +31 -0
- package/dist/lib/tenant/member-handler.d.ts.map +1 -0
- package/dist/lib/tenant/member-handler.js +343 -0
- package/dist/lib/tenant/member-handler.js.map +1 -0
- package/dist/lib/tenant/reserved-slugs.d.ts +37 -0
- package/dist/lib/tenant/reserved-slugs.d.ts.map +1 -0
- package/dist/lib/tenant/reserved-slugs.js +116 -0
- package/dist/lib/tenant/reserved-slugs.js.map +1 -0
- package/dist/lib/tenant/resolve-role.d.ts +39 -0
- package/dist/lib/tenant/resolve-role.d.ts.map +1 -0
- package/dist/lib/tenant/resolve-role.js +60 -0
- package/dist/lib/tenant/resolve-role.js.map +1 -0
- package/dist/lib/tenant/role-mapping-handler.d.ts +26 -0
- package/dist/lib/tenant/role-mapping-handler.d.ts.map +1 -0
- package/dist/lib/tenant/role-mapping-handler.js +260 -0
- package/dist/lib/tenant/role-mapping-handler.js.map +1 -0
- package/dist/lib/tenant/setup-status.d.ts +83 -0
- package/dist/lib/tenant/setup-status.d.ts.map +1 -0
- package/dist/lib/tenant/setup-status.js +201 -0
- package/dist/lib/tenant/setup-status.js.map +1 -0
- package/dist/lib/tenant/slug-validator.d.ts +31 -0
- package/dist/lib/tenant/slug-validator.d.ts.map +1 -0
- package/dist/lib/tenant/slug-validator.js +42 -0
- package/dist/lib/tenant/slug-validator.js.map +1 -0
- package/dist/lib/tenant/tenant-handler.d.ts +49 -0
- package/dist/lib/tenant/tenant-handler.d.ts.map +1 -0
- package/dist/lib/tenant/tenant-handler.js +377 -0
- package/dist/lib/tenant/tenant-handler.js.map +1 -0
- package/dist/lib/tenant/transfer-ownership.d.ts +39 -0
- package/dist/lib/tenant/transfer-ownership.d.ts.map +1 -0
- package/dist/lib/tenant/transfer-ownership.js +66 -0
- package/dist/lib/tenant/transfer-ownership.js.map +1 -0
- package/dist/lib/user/derive-handle.d.ts +29 -0
- package/dist/lib/user/derive-handle.d.ts.map +1 -0
- package/dist/lib/user/derive-handle.js +65 -0
- package/dist/lib/user/derive-handle.js.map +1 -0
- package/dist/lib/user-deprovisioning.d.ts +11 -1
- package/dist/lib/user-deprovisioning.d.ts.map +1 -1
- package/dist/lib/user-deprovisioning.js +46 -2
- package/dist/lib/user-deprovisioning.js.map +1 -1
- package/dist/lib/validation/feature-toggle-schemas.d.ts +10 -10
- package/package.json +5 -3
- package/prisma/migrations/20260502094501_add_tenancy_model/migration.sql +334 -0
- package/prisma/migrations/20260503000000_add_tenant_region/migration.sql +4 -0
- package/prisma/schema.prisma +324 -74
- package/src/lambda/nightly-cron.ts +4 -1
- package/src/lambda/post-confirmation.ts +405 -29
- package/src/lambda/pre-token-generation.ts +300 -59
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Refresh-token reuse detection (RFC 6819 §5.2.2.5, T9b-d).
|
|
4
|
+
*
|
|
5
|
+
* Each refresh-token JTI is recorded once. On refresh:
|
|
6
|
+
* - load the row by jti
|
|
7
|
+
* - if absent → unknown token; treat as suspect, deny
|
|
8
|
+
* - if `consumed` → REPLAY; revoke all sessions for that user via
|
|
9
|
+
* AdminUserGlobalSignOut and emit `auth.refresh_replay`
|
|
10
|
+
* - if `active` → mark consumed, issue new refresh with new jti
|
|
11
|
+
*
|
|
12
|
+
* Storage: AGENT_REFRESH_TABLE in DynamoDB. Same table also holds the
|
|
13
|
+
* agent-session metadata listed by `/api/users/me/agent-sessions`.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.recordAgentSession = recordAgentSession;
|
|
17
|
+
exports.consumeRefreshJti = consumeRefreshJti;
|
|
18
|
+
exports.handleRefreshReplay = handleRefreshReplay;
|
|
19
|
+
exports.rotateRefreshJti = rotateRefreshJti;
|
|
20
|
+
exports.listAgentSessions = listAgentSessions;
|
|
21
|
+
exports.revokeAgentSession = revokeAgentSession;
|
|
22
|
+
exports.getAgentSession = getAgentSession;
|
|
23
|
+
exports._deleteAgentSessionForTest = _deleteAgentSessionForTest;
|
|
24
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
25
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
26
|
+
const ddb = new client_dynamodb_1.DynamoDBClient({
|
|
27
|
+
region: process.env.AWS_REGION || "us-east-1",
|
|
28
|
+
...(process.env.DYNAMODB_ENDPOINT ? { endpoint: process.env.DYNAMODB_ENDPOINT } : {}),
|
|
29
|
+
});
|
|
30
|
+
function tableName() {
|
|
31
|
+
return (process.env.AGENT_REFRESH_TABLE ||
|
|
32
|
+
`${process.env.STAGE || "dev"}-trellis-agent-refresh`);
|
|
33
|
+
}
|
|
34
|
+
/** Initial record write at session creation (after approval). */
|
|
35
|
+
async function recordAgentSession(input) {
|
|
36
|
+
const now = Math.floor(Date.now() / 1000);
|
|
37
|
+
await ddb.send(new client_dynamodb_1.PutItemCommand({
|
|
38
|
+
TableName: tableName(),
|
|
39
|
+
Item: (0, util_dynamodb_1.marshall)({
|
|
40
|
+
pk: `s#${input.session.sessionId}`,
|
|
41
|
+
sk: "rec",
|
|
42
|
+
...input.session,
|
|
43
|
+
gsi1pk: `u#${input.session.userId}`,
|
|
44
|
+
gsi1sk: `s#${input.session.sessionId}`,
|
|
45
|
+
}, { removeUndefinedValues: true }),
|
|
46
|
+
ConditionExpression: "attribute_not_exists(pk)",
|
|
47
|
+
}));
|
|
48
|
+
await ddb.send(new client_dynamodb_1.PutItemCommand({
|
|
49
|
+
TableName: tableName(),
|
|
50
|
+
Item: (0, util_dynamodb_1.marshall)({
|
|
51
|
+
pk: `j#${input.initialJti}`,
|
|
52
|
+
sk: "rec",
|
|
53
|
+
jti: input.initialJti,
|
|
54
|
+
sessionId: input.session.sessionId,
|
|
55
|
+
userId: input.session.userId,
|
|
56
|
+
cognitoSub: input.session.cognitoSub,
|
|
57
|
+
status: "active",
|
|
58
|
+
issuedAt: now,
|
|
59
|
+
}),
|
|
60
|
+
ConditionExpression: "attribute_not_exists(pk)",
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate a refresh-token JTI. Three outcomes:
|
|
65
|
+
* - "ok" → the jti was active; row is now flipped to consumed.
|
|
66
|
+
* - "replay" → jti was already consumed → caller must revoke session globally.
|
|
67
|
+
* - "unknown" → jti not present (foreign or expired); deny.
|
|
68
|
+
*/
|
|
69
|
+
async function consumeRefreshJti(jti) {
|
|
70
|
+
try {
|
|
71
|
+
const out = await ddb.send(new client_dynamodb_1.UpdateItemCommand({
|
|
72
|
+
TableName: tableName(),
|
|
73
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `j#${jti}`, sk: "rec" }),
|
|
74
|
+
UpdateExpression: "SET #status = :consumed, consumedAt = :now",
|
|
75
|
+
ConditionExpression: "attribute_exists(pk) AND #status = :active",
|
|
76
|
+
ExpressionAttributeNames: { "#status": "status" },
|
|
77
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
|
|
78
|
+
":active": "active",
|
|
79
|
+
":consumed": "consumed",
|
|
80
|
+
":now": Math.floor(Date.now() / 1000),
|
|
81
|
+
}),
|
|
82
|
+
ReturnValues: "ALL_NEW",
|
|
83
|
+
}));
|
|
84
|
+
if (!out.Attributes)
|
|
85
|
+
return { outcome: "unknown" };
|
|
86
|
+
return { outcome: "ok", record: (0, util_dynamodb_1.unmarshall)(out.Attributes) };
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
if (err instanceof client_dynamodb_1.ConditionalCheckFailedException) {
|
|
90
|
+
// Row exists but wasn't `active` — load to distinguish unknown vs replay.
|
|
91
|
+
const out = await ddb.send(new client_dynamodb_1.GetItemCommand({
|
|
92
|
+
TableName: tableName(),
|
|
93
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `j#${jti}`, sk: "rec" }),
|
|
94
|
+
}));
|
|
95
|
+
if (!out.Item)
|
|
96
|
+
return { outcome: "unknown" };
|
|
97
|
+
const row = (0, util_dynamodb_1.unmarshall)(out.Item);
|
|
98
|
+
return { outcome: "replay", record: row };
|
|
99
|
+
}
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* On confirmed replay: revoke all sessions for the user, mark the session
|
|
105
|
+
* row revoked, emit `auth.refresh_replay`. The Cognito SDK call uses
|
|
106
|
+
* AdminUserGlobalSignOut to invalidate every refresh-derived token.
|
|
107
|
+
*
|
|
108
|
+
* Hardening (G4 CRITICAL-1, CRITICAL-2):
|
|
109
|
+
* - The Cognito username used for revocation is read directly from
|
|
110
|
+
* `jtiRecord.cognitoSub` (the value bound at session-creation time).
|
|
111
|
+
* Callers may not supply an alternate identity; this prevents the
|
|
112
|
+
* wrong account from being revoked if a caller forwards a request-
|
|
113
|
+
* scoped value here.
|
|
114
|
+
* - The audit event is emitted FIRST so a downstream Cognito or DDB
|
|
115
|
+
* failure cannot suppress the `auth.refresh_replay` signal. The
|
|
116
|
+
* mutation steps follow in order; each is wrapped so that audit
|
|
117
|
+
* emit completes even when a later step throws.
|
|
118
|
+
*/
|
|
119
|
+
async function handleRefreshReplay(input) {
|
|
120
|
+
// Source the Cognito username from the stored jti record only.
|
|
121
|
+
const cognitoUsername = input.jtiRecord.cognitoSub;
|
|
122
|
+
// Step 1: emit the audit event before any mutation. This is the
|
|
123
|
+
// observability anchor — a replay must always produce a record even if
|
|
124
|
+
// the downstream revocation path fails part-way through.
|
|
125
|
+
await input.audit.emit({
|
|
126
|
+
type: "auth.refresh_replay",
|
|
127
|
+
tenantId: input.tenantId,
|
|
128
|
+
actorUserId: input.jtiRecord.userId,
|
|
129
|
+
payload: {
|
|
130
|
+
refreshJti: input.jtiRecord.jti,
|
|
131
|
+
cognitoUserId: cognitoUsername,
|
|
132
|
+
},
|
|
133
|
+
sourceIp: input.sourceIp,
|
|
134
|
+
agentSessionId: input.jtiRecord.sessionId,
|
|
135
|
+
});
|
|
136
|
+
// Step 2: tombstone the session row in DDB. We do this before the
|
|
137
|
+
// Cognito call so a Cognito failure still leaves the local record
|
|
138
|
+
// marked revoked.
|
|
139
|
+
await ddb.send(new client_dynamodb_1.UpdateItemCommand({
|
|
140
|
+
TableName: tableName(),
|
|
141
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `s#${input.jtiRecord.sessionId}`, sk: "rec" }),
|
|
142
|
+
UpdateExpression: "SET #status = :revoked, currentJti = :null, lastUsedAt = :now",
|
|
143
|
+
ExpressionAttributeNames: { "#status": "status" },
|
|
144
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
|
|
145
|
+
":revoked": "revoked",
|
|
146
|
+
":null": null,
|
|
147
|
+
":now": Math.floor(Date.now() / 1000),
|
|
148
|
+
}),
|
|
149
|
+
}));
|
|
150
|
+
// Step 3: invalidate refresh-derived tokens at the IdP. If this throws
|
|
151
|
+
// the local state is already consistent (audit emitted, row revoked)
|
|
152
|
+
// and the caller can retry the global sign-out idempotently.
|
|
153
|
+
await input.cognito.globalSignOut({
|
|
154
|
+
userPoolId: input.userPoolId,
|
|
155
|
+
cognitoUsername,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Issue a new refresh JTI for a session. The old JTI must already be
|
|
160
|
+
* consumed (caller flips it before calling). Updates the session row.
|
|
161
|
+
*/
|
|
162
|
+
async function rotateRefreshJti(input) {
|
|
163
|
+
const now = Math.floor(Date.now() / 1000);
|
|
164
|
+
await ddb.send(new client_dynamodb_1.PutItemCommand({
|
|
165
|
+
TableName: tableName(),
|
|
166
|
+
Item: (0, util_dynamodb_1.marshall)({
|
|
167
|
+
pk: `j#${input.newJti}`,
|
|
168
|
+
sk: "rec",
|
|
169
|
+
jti: input.newJti,
|
|
170
|
+
sessionId: input.sessionId,
|
|
171
|
+
userId: input.userId,
|
|
172
|
+
cognitoSub: input.cognitoSub,
|
|
173
|
+
status: "active",
|
|
174
|
+
issuedAt: now,
|
|
175
|
+
}),
|
|
176
|
+
ConditionExpression: "attribute_not_exists(pk)",
|
|
177
|
+
}));
|
|
178
|
+
await ddb.send(new client_dynamodb_1.UpdateItemCommand({
|
|
179
|
+
TableName: tableName(),
|
|
180
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `s#${input.sessionId}`, sk: "rec" }),
|
|
181
|
+
UpdateExpression: "SET currentJti = :j, lastUsedAt = :n",
|
|
182
|
+
ConditionExpression: "attribute_exists(pk) AND #status = :active",
|
|
183
|
+
ExpressionAttributeNames: { "#status": "status" },
|
|
184
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
|
|
185
|
+
":j": input.newJti,
|
|
186
|
+
":n": now,
|
|
187
|
+
":active": "active",
|
|
188
|
+
}),
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
/** List all active sessions for a user. Used by `/api/users/me/agent-sessions`. */
|
|
192
|
+
async function listAgentSessions(userId) {
|
|
193
|
+
const out = await ddb.send(new client_dynamodb_1.QueryCommand({
|
|
194
|
+
TableName: tableName(),
|
|
195
|
+
IndexName: "gsi1",
|
|
196
|
+
KeyConditionExpression: "gsi1pk = :u",
|
|
197
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({ ":u": `u#${userId}` }),
|
|
198
|
+
}));
|
|
199
|
+
return (out.Items ?? [])
|
|
200
|
+
.map((it) => (0, util_dynamodb_1.unmarshall)(it))
|
|
201
|
+
.filter((r) => r.status === "active")
|
|
202
|
+
.map(({ ...rec }) => rec);
|
|
203
|
+
}
|
|
204
|
+
/** Revoke a session by id; caller must verify the session belongs to the user. */
|
|
205
|
+
async function revokeAgentSession(input) {
|
|
206
|
+
await input.cognito.globalSignOut({
|
|
207
|
+
userPoolId: input.userPoolId,
|
|
208
|
+
cognitoUsername: input.cognitoUsername,
|
|
209
|
+
});
|
|
210
|
+
await ddb.send(new client_dynamodb_1.UpdateItemCommand({
|
|
211
|
+
TableName: tableName(),
|
|
212
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `s#${input.sessionId}`, sk: "rec" }),
|
|
213
|
+
UpdateExpression: "SET #status = :revoked, currentJti = :null, lastUsedAt = :now",
|
|
214
|
+
ConditionExpression: "attribute_exists(pk)",
|
|
215
|
+
ExpressionAttributeNames: { "#status": "status" },
|
|
216
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
|
|
217
|
+
":revoked": "revoked",
|
|
218
|
+
":null": null,
|
|
219
|
+
":now": Math.floor(Date.now() / 1000),
|
|
220
|
+
}),
|
|
221
|
+
}));
|
|
222
|
+
await input.audit.emit({
|
|
223
|
+
type: "auth.agent_session.revoked",
|
|
224
|
+
tenantId: input.tenantId,
|
|
225
|
+
actorUserId: input.actorUserId,
|
|
226
|
+
payload: { cognitoUserId: input.cognitoUsername },
|
|
227
|
+
sourceIp: input.sourceIp,
|
|
228
|
+
agentSessionId: input.sessionId,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/** Look up a session by id (auth check helper). */
|
|
232
|
+
async function getAgentSession(sessionId) {
|
|
233
|
+
const out = await ddb.send(new client_dynamodb_1.GetItemCommand({
|
|
234
|
+
TableName: tableName(),
|
|
235
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `s#${sessionId}`, sk: "rec" }),
|
|
236
|
+
}));
|
|
237
|
+
if (!out.Item)
|
|
238
|
+
return null;
|
|
239
|
+
return (0, util_dynamodb_1.unmarshall)(out.Item);
|
|
240
|
+
}
|
|
241
|
+
/** Test-only: helper to clear a session row directly. */
|
|
242
|
+
async function _deleteAgentSessionForTest(sessionId) {
|
|
243
|
+
await ddb.send(new client_dynamodb_1.DeleteItemCommand({
|
|
244
|
+
TableName: tableName(),
|
|
245
|
+
Key: (0, util_dynamodb_1.marshall)({ pk: `s#${sessionId}`, sk: "rec" }),
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=refresh-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-detection.js","sourceRoot":"","sources":["../../../src/lib/oauth/refresh-detection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI 3.1 Document Generator
|
|
3
|
+
*
|
|
4
|
+
* Introspects the trellis route registry to emit a valid OpenAPI 3.1 document.
|
|
5
|
+
* Coverage priority: federation endpoints (T3–T8) plus the discovery surface.
|
|
6
|
+
* For routes whose Zod schemas aren't directly accessible, minimal `{}` schemas
|
|
7
|
+
* are emitted — validity over richness.
|
|
8
|
+
*/
|
|
9
|
+
import type { Route } from "../routes/types";
|
|
10
|
+
export interface OpenApiDocument {
|
|
11
|
+
openapi: "3.1.0";
|
|
12
|
+
info: {
|
|
13
|
+
title: string;
|
|
14
|
+
version: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
};
|
|
17
|
+
paths: Record<string, OpenApiPathItem>;
|
|
18
|
+
components?: {
|
|
19
|
+
schemas?: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
interface OpenApiPathItem {
|
|
23
|
+
[method: string]: OpenApiOperation;
|
|
24
|
+
}
|
|
25
|
+
interface OpenApiOperation {
|
|
26
|
+
summary?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
operationId?: string;
|
|
29
|
+
parameters?: OpenApiParameter[];
|
|
30
|
+
requestBody?: {
|
|
31
|
+
required?: boolean;
|
|
32
|
+
content: Record<string, {
|
|
33
|
+
schema: unknown;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
responses: Record<string, {
|
|
37
|
+
description: string;
|
|
38
|
+
content?: Record<string, {
|
|
39
|
+
schema: unknown;
|
|
40
|
+
}>;
|
|
41
|
+
}>;
|
|
42
|
+
tags?: string[];
|
|
43
|
+
}
|
|
44
|
+
interface OpenApiParameter {
|
|
45
|
+
name: string;
|
|
46
|
+
in: "path" | "query" | "header";
|
|
47
|
+
required: boolean;
|
|
48
|
+
schema: {
|
|
49
|
+
type: string;
|
|
50
|
+
};
|
|
51
|
+
description?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert a route pattern to an OpenAPI path string.
|
|
55
|
+
*
|
|
56
|
+
* Supports:
|
|
57
|
+
* - Exact strings: "/health" → "/health"
|
|
58
|
+
* - Express-style params: "/api/tenants/:id" → "/api/tenants/{id}"
|
|
59
|
+
* - Simple named-group regex: /^\/api\/tenants\/([^/]+)\/domains$/ →
|
|
60
|
+
* "/api/tenants/{param0}/domains"
|
|
61
|
+
* - Wildcards and complex regex are skipped (returns null)
|
|
62
|
+
*/
|
|
63
|
+
export declare function routePatternToPath(pattern: Route["path"]): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Generate an OpenAPI 3.1 document from the trellis route registry.
|
|
66
|
+
*
|
|
67
|
+
* Hardening (G4 MEDIUM-3): the generator emits ONLY routes flagged
|
|
68
|
+
* `publicSpec: true`. Routes without the flag (posts, comments, media,
|
|
69
|
+
* ActivityPub, extension-defined routes, etc.) are excluded so the
|
|
70
|
+
* public spec is a curated agent-integration surface rather than a
|
|
71
|
+
* reflection of every registered handler.
|
|
72
|
+
*
|
|
73
|
+
* Routes that cannot be represented as OpenAPI paths (wildcard handlers,
|
|
74
|
+
* complex regex) are silently skipped.
|
|
75
|
+
*/
|
|
76
|
+
export declare function generateOpenApiDoc(routes: Route[]): OpenApiDocument;
|
|
77
|
+
export {};
|
|
78
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../src/lib/openapi/generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAI7C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACH;AAED,UAAU,eAAe;IACvB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACpC;AAED,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC9C,CAAC;IACF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAClG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CA+DxE;AAwDD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAmCnE"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAPI 3.1 Document Generator
|
|
4
|
+
*
|
|
5
|
+
* Introspects the trellis route registry to emit a valid OpenAPI 3.1 document.
|
|
6
|
+
* Coverage priority: federation endpoints (T3–T8) plus the discovery surface.
|
|
7
|
+
* For routes whose Zod schemas aren't directly accessible, minimal `{}` schemas
|
|
8
|
+
* are emitted — validity over richness.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.routePatternToPath = routePatternToPath;
|
|
12
|
+
exports.generateOpenApiDoc = generateOpenApiDoc;
|
|
13
|
+
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
14
|
+
const API_TITLE = "Trellis API";
|
|
15
|
+
const API_VERSION = "0.7.0";
|
|
16
|
+
const API_DESCRIPTION = "Social-network core API. Discovery surfaces, federation management (T3–T8), and entity/social graph endpoints.";
|
|
17
|
+
/** Methods that support a request body */
|
|
18
|
+
const BODY_METHODS = new Set(["post", "put", "patch"]);
|
|
19
|
+
// Tags derived from path prefix for grouping
|
|
20
|
+
const FEDERATION_PREFIXES = [
|
|
21
|
+
[/^\/api\/tenants\/[^/]+\/domains/, "tenant-domains"],
|
|
22
|
+
[/^\/api\/tenants\/[^/]+\/identity-provider/, "tenant-idp"],
|
|
23
|
+
[/^\/api\/tenants\/[^/]+\/members/, "tenant-members"],
|
|
24
|
+
[/^\/api\/tenants\/[^/]+\/role-mappings/, "tenant-role-mappings"],
|
|
25
|
+
[/^\/api\/tenants\/[^/]+\/audit/, "tenant-audit"],
|
|
26
|
+
[/^\/api\/tenants/, "tenants"],
|
|
27
|
+
[/^\/api\/auth\/discover/, "auth-discover"],
|
|
28
|
+
[/^\/(llms\.txt|openapi\.json|security\.txt)/, "discovery"],
|
|
29
|
+
[/^\/health/, "health"],
|
|
30
|
+
];
|
|
31
|
+
function deriveTag(path) {
|
|
32
|
+
for (const [pattern, tag] of FEDERATION_PREFIXES) {
|
|
33
|
+
if (pattern.test(path))
|
|
34
|
+
return tag;
|
|
35
|
+
}
|
|
36
|
+
return "other";
|
|
37
|
+
}
|
|
38
|
+
// ── Path normalisation ─────────────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Convert a route pattern to an OpenAPI path string.
|
|
41
|
+
*
|
|
42
|
+
* Supports:
|
|
43
|
+
* - Exact strings: "/health" → "/health"
|
|
44
|
+
* - Express-style params: "/api/tenants/:id" → "/api/tenants/{id}"
|
|
45
|
+
* - Simple named-group regex: /^\/api\/tenants\/([^/]+)\/domains$/ →
|
|
46
|
+
* "/api/tenants/{param0}/domains"
|
|
47
|
+
* - Wildcards and complex regex are skipped (returns null)
|
|
48
|
+
*/
|
|
49
|
+
function routePatternToPath(pattern) {
|
|
50
|
+
if (typeof pattern === "string") {
|
|
51
|
+
if (pattern === "*")
|
|
52
|
+
return null;
|
|
53
|
+
// Convert express :param style
|
|
54
|
+
return pattern.replace(/:([^/]+)/g, "{$1}");
|
|
55
|
+
}
|
|
56
|
+
if (pattern instanceof RegExp) {
|
|
57
|
+
const src = pattern.source;
|
|
58
|
+
// Skip wildcard-only patterns
|
|
59
|
+
if (src === ".*" || src === "^.*$")
|
|
60
|
+
return null;
|
|
61
|
+
// Strip anchors
|
|
62
|
+
let s = src.replace(/^\^/, "").replace(/\$$/, "");
|
|
63
|
+
// Unescape forward slashes
|
|
64
|
+
s = s.replace(/\\\//g, "/");
|
|
65
|
+
// Replace capture groups with positional placeholders.
|
|
66
|
+
// We walk character-by-character to correctly handle character classes
|
|
67
|
+
// like `([^/]+)` which contain `]` that would fool a naive regex.
|
|
68
|
+
let paramIndex = 0;
|
|
69
|
+
let result = "";
|
|
70
|
+
let i = 0;
|
|
71
|
+
while (i < s.length) {
|
|
72
|
+
if (s[i] === "(") {
|
|
73
|
+
// Scan to the matching closing paren, skipping over [...] classes
|
|
74
|
+
let depth = 1;
|
|
75
|
+
i++;
|
|
76
|
+
while (i < s.length && depth > 0) {
|
|
77
|
+
if (s[i] === "[") {
|
|
78
|
+
// Skip character class entirely
|
|
79
|
+
i++;
|
|
80
|
+
while (i < s.length && s[i] !== "]")
|
|
81
|
+
i++;
|
|
82
|
+
i++; // skip ']'
|
|
83
|
+
}
|
|
84
|
+
else if (s[i] === "(") {
|
|
85
|
+
depth++;
|
|
86
|
+
i++;
|
|
87
|
+
}
|
|
88
|
+
else if (s[i] === ")") {
|
|
89
|
+
depth--;
|
|
90
|
+
i++;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
i++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
result += `{param${paramIndex++}}`;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
result += s[i];
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
s = result;
|
|
104
|
+
// Bail out if any remaining regex metacharacters.
|
|
105
|
+
// Note: {param0} placeholders are intentional OpenAPI path parameters, so
|
|
106
|
+
// we only reject metacharacters that appear outside of {...} placeholders.
|
|
107
|
+
const withoutPlaceholders = s.replace(/\{param\d+\}/g, "");
|
|
108
|
+
if (/[.*+?^${}()|[\]\\]/.test(withoutPlaceholders))
|
|
109
|
+
return null;
|
|
110
|
+
return s || null;
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
// ── Parameter extraction ───────────────────────────────────────────────────────
|
|
115
|
+
function extractPathParams(openApiPath) {
|
|
116
|
+
const params = [];
|
|
117
|
+
const re = /\{([^}]+)\}/g;
|
|
118
|
+
let m;
|
|
119
|
+
while ((m = re.exec(openApiPath)) !== null) {
|
|
120
|
+
params.push({
|
|
121
|
+
name: m[1],
|
|
122
|
+
in: "path",
|
|
123
|
+
required: true,
|
|
124
|
+
schema: { type: "string" },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return params;
|
|
128
|
+
}
|
|
129
|
+
// ── Operation builder ─────────────────────────────────────────────────────────
|
|
130
|
+
function buildOperation(route, method, openApiPath) {
|
|
131
|
+
const params = extractPathParams(openApiPath);
|
|
132
|
+
const tag = deriveTag(openApiPath);
|
|
133
|
+
const op = {
|
|
134
|
+
summary: route.description ?? `${method.toUpperCase()} ${openApiPath}`,
|
|
135
|
+
operationId: `${method}_${openApiPath.replace(/[^a-zA-Z0-9]/g, "_")}`,
|
|
136
|
+
tags: [tag],
|
|
137
|
+
parameters: params.length > 0 ? params : undefined,
|
|
138
|
+
responses: {
|
|
139
|
+
"200": { description: "Success" },
|
|
140
|
+
"400": { description: "Bad request" },
|
|
141
|
+
"401": { description: "Unauthorized" },
|
|
142
|
+
"500": { description: "Internal server error" },
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
if (BODY_METHODS.has(method)) {
|
|
146
|
+
op.requestBody = {
|
|
147
|
+
required: false,
|
|
148
|
+
content: {
|
|
149
|
+
"application/json": { schema: {} },
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return op;
|
|
154
|
+
}
|
|
155
|
+
// ── Main generator ─────────────────────────────────────────────────────────────
|
|
156
|
+
/**
|
|
157
|
+
* Generate an OpenAPI 3.1 document from the trellis route registry.
|
|
158
|
+
*
|
|
159
|
+
* Hardening (G4 MEDIUM-3): the generator emits ONLY routes flagged
|
|
160
|
+
* `publicSpec: true`. Routes without the flag (posts, comments, media,
|
|
161
|
+
* ActivityPub, extension-defined routes, etc.) are excluded so the
|
|
162
|
+
* public spec is a curated agent-integration surface rather than a
|
|
163
|
+
* reflection of every registered handler.
|
|
164
|
+
*
|
|
165
|
+
* Routes that cannot be represented as OpenAPI paths (wildcard handlers,
|
|
166
|
+
* complex regex) are silently skipped.
|
|
167
|
+
*/
|
|
168
|
+
function generateOpenApiDoc(routes) {
|
|
169
|
+
const paths = {};
|
|
170
|
+
for (const route of routes) {
|
|
171
|
+
if (route.publicSpec !== true)
|
|
172
|
+
continue;
|
|
173
|
+
const openApiPath = routePatternToPath(route.path);
|
|
174
|
+
if (!openApiPath)
|
|
175
|
+
continue;
|
|
176
|
+
const rawMethods = route.method ?? "GET";
|
|
177
|
+
const methods = Array.isArray(rawMethods) ? rawMethods : [rawMethods];
|
|
178
|
+
for (const rawMethod of methods) {
|
|
179
|
+
if (rawMethod === "*")
|
|
180
|
+
continue;
|
|
181
|
+
const method = rawMethod.toLowerCase();
|
|
182
|
+
if (!paths[openApiPath]) {
|
|
183
|
+
paths[openApiPath] = {};
|
|
184
|
+
}
|
|
185
|
+
paths[openApiPath][method] = buildOperation(route, method, openApiPath);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
openapi: "3.1.0",
|
|
190
|
+
info: {
|
|
191
|
+
title: API_TITLE,
|
|
192
|
+
version: API_VERSION,
|
|
193
|
+
description: API_DESCRIPTION,
|
|
194
|
+
},
|
|
195
|
+
paths,
|
|
196
|
+
components: {
|
|
197
|
+
schemas: {},
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../src/lib/openapi/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,7 +43,7 @@ export declare class PostHandler {
|
|
|
43
43
|
*
|
|
44
44
|
* PREPARATORY: Uses DataRouter for region-aware post creation.
|
|
45
45
|
*/
|
|
46
|
-
createPost(request: Request, session: Session, env: Env, requestContext: RequestContext): Promise<Response>;
|
|
46
|
+
createPost(request: Request, session: Session, env: Env, requestContext: RequestContext, activeTenantId: string): Promise<Response>;
|
|
47
47
|
/**
|
|
48
48
|
* Delete a post (soft delete)
|
|
49
49
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-handler.d.ts","sourceRoot":"","sources":["../../src/lib/post-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,4BAA4B,CAAC;AAWzF,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAErE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,GAAG;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,WAAW,CAAC;IAClC,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAChC,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,SAAS,CAAC;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,GAAG,CAAC,EAAE,SAAS;IAK3B;;;;OAIG;IACG,UAAU,CACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"post-handler.d.ts","sourceRoot":"","sources":["../../src/lib/post-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/post-handler.js
CHANGED
|
@@ -56,7 +56,7 @@ class PostHandler {
|
|
|
56
56
|
*
|
|
57
57
|
* PREPARATORY: Uses DataRouter for region-aware post creation.
|
|
58
58
|
*/
|
|
59
|
-
async createPost(request, session, env, requestContext) {
|
|
59
|
+
async createPost(request, session, env, requestContext, activeTenantId) {
|
|
60
60
|
try {
|
|
61
61
|
// PREPARATORY: Check if post creation is enabled for this region
|
|
62
62
|
// Note: Post creation is always enabled by default, but can be disabled via feature flags
|
|
@@ -367,16 +367,10 @@ class PostHandler {
|
|
|
367
367
|
if (taxonomyTags.length > 0) {
|
|
368
368
|
try {
|
|
369
369
|
const { TaxonomyHandler } = await Promise.resolve().then(() => __importStar(require("./taxonomy-handler")));
|
|
370
|
-
const { getRequestContext } = await Promise.resolve().then(() => __importStar(require("./tenant-context")));
|
|
371
|
-
const { createRequestContext } = await Promise.resolve().then(() => __importStar(require("./request-context")));
|
|
372
370
|
const { getWrappedDatabase } = await Promise.resolve().then(() => __importStar(require("./database-wrapper-helper")));
|
|
373
|
-
// Get tenant
|
|
374
|
-
const ctx = await createRequestContext(request, env);
|
|
375
|
-
const tenantCtx = await getRequestContext(request, ctx.session || null);
|
|
376
|
-
const tenantId = tenantCtx.tenant?.id || "trellis";
|
|
377
|
-
// Get database and taxonomy handler
|
|
371
|
+
// Get database and taxonomy handler scoped to caller's active tenant
|
|
378
372
|
const db = getWrappedDatabase(region, env, request);
|
|
379
|
-
const taxonomyHandler = new TaxonomyHandler(db,
|
|
373
|
+
const taxonomyHandler = new TaxonomyHandler(db, activeTenantId, env.TAXONOMY_CACHE_KV);
|
|
380
374
|
// Add taxonomy tags
|
|
381
375
|
await taxonomyHandler.addPostTaxonomyTags(post.id, taxonomyTags, session.userId);
|
|
382
376
|
}
|
|
@@ -624,14 +618,9 @@ class PostHandler {
|
|
|
624
618
|
if (taxonomyTags.length > 0) {
|
|
625
619
|
try {
|
|
626
620
|
const { TaxonomyHandler } = await Promise.resolve().then(() => __importStar(require("./taxonomy-handler")));
|
|
627
|
-
const { getRequestContext } = await Promise.resolve().then(() => __importStar(require("./tenant-context")));
|
|
628
|
-
const { createRequestContext } = await Promise.resolve().then(() => __importStar(require("./request-context")));
|
|
629
621
|
const { getWrappedDatabase } = await Promise.resolve().then(() => __importStar(require("./database-wrapper-helper")));
|
|
630
|
-
const ctx = await createRequestContext(request, env);
|
|
631
|
-
const tenantCtx = await getRequestContext(request, ctx.session || null);
|
|
632
|
-
const tenantId = tenantCtx.tenant?.id || "trellis";
|
|
633
622
|
const db = getWrappedDatabase(region, env, request);
|
|
634
|
-
const taxonomyHandler = new TaxonomyHandler(db,
|
|
623
|
+
const taxonomyHandler = new TaxonomyHandler(db, activeTenantId, env.TAXONOMY_CACHE_KV);
|
|
635
624
|
const tags = await taxonomyHandler.getPostTaxonomyTags(post.id);
|
|
636
625
|
taxonomyTagsResponse = tags.map((t) => ({
|
|
637
626
|
taxonId: t.taxonId,
|