@spacefast/common 0.0.26 → 0.2.2
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/agents/connect-targets.d.ts +6 -146
- package/dist/agents/connect-targets.js +63 -295
- package/dist/agents/private-key-oauth.d.ts +31 -1
- package/dist/agents/private-key-oauth.js +124 -33
- package/dist/agents/registry/core.d.ts +292 -0
- package/dist/agents/registry/core.js +1388 -0
- package/dist/agents/registry/deeplink-probes.d.ts +23 -0
- package/dist/agents/registry/deeplink-probes.js +18 -0
- package/dist/agents/registry/node.d.ts +56 -0
- package/dist/agents/registry/node.js +339 -0
- package/dist/brand-assets-build.js +1 -2
- package/dist/brand-assets.js +4 -7
- package/dist/brand.d.ts +17 -0
- package/dist/brand.js +24 -4
- package/dist/config/domains.d.ts +55 -28
- package/dist/config/domains.js +85 -41
- package/dist/config/index.js +1 -2
- package/dist/contracts/abuse.js +9 -24
- package/dist/contracts/access-profiles.d.ts +86 -0
- package/dist/contracts/access-profiles.js +89 -0
- package/dist/contracts/access.d.ts +21 -27
- package/dist/contracts/access.js +33 -64
- package/dist/contracts/activity.d.ts +18 -1
- package/dist/contracts/activity.js +70 -26
- package/dist/contracts/analytics.js +8 -10
- package/dist/contracts/api-keys.d.ts +77 -52
- package/dist/contracts/api-keys.js +44 -24
- package/dist/contracts/application-journal.d.ts +216 -0
- package/dist/contracts/application-journal.js +167 -0
- package/dist/contracts/auth.d.ts +90 -17
- package/dist/contracts/auth.js +86 -17
- package/dist/contracts/beta.d.ts +9 -4
- package/dist/contracts/beta.js +20 -16
- package/dist/contracts/billing.js +7 -11
- package/dist/contracts/bootstrap.d.ts +791 -0
- package/dist/contracts/bootstrap.js +51 -0
- package/dist/contracts/builds.d.ts +192 -7
- package/dist/contracts/builds.js +84 -21
- package/dist/contracts/channels.d.ts +43 -0
- package/dist/contracts/channels.js +25 -9
- package/dist/contracts/cli.d.ts +7 -0
- package/dist/contracts/cli.js +6 -0
- package/dist/contracts/collab-public.d.ts +1 -1
- package/dist/contracts/collab-public.js +5 -8
- package/dist/contracts/comments.d.ts +45 -35
- package/dist/contracts/comments.js +107 -77
- package/dist/contracts/commerce.d.ts +165 -0
- package/dist/contracts/commerce.js +146 -0
- package/dist/contracts/common.d.ts +3 -3
- package/dist/contracts/common.js +18 -29
- package/dist/contracts/content-contract-verification.d.ts +521 -0
- package/dist/contracts/content-contract-verification.js +320 -0
- package/dist/contracts/content-platform-fixture.d.ts +1278 -0
- package/dist/contracts/content-platform-fixture.js +44 -0
- package/dist/contracts/content-program.d.ts +994 -0
- package/dist/contracts/content-program.js +658 -0
- package/dist/contracts/content-sync.d.ts +290 -0
- package/dist/contracts/content-sync.js +167 -0
- package/dist/contracts/content.d.ts +432 -0
- package/dist/contracts/content.js +303 -0
- package/dist/contracts/continuation.d.ts +17 -1
- package/dist/contracts/continuation.js +23 -23
- package/dist/contracts/countries.js +3 -4
- package/dist/contracts/crons.d.ts +17 -0
- package/dist/contracts/crons.js +33 -15
- package/dist/contracts/dashboard-prefs.d.ts +56 -0
- package/dist/contracts/dashboard-prefs.js +51 -0
- package/dist/contracts/device-auth.d.ts +234 -37
- package/dist/contracts/device-auth.js +267 -53
- package/dist/contracts/docs.d.ts +6 -10
- package/dist/contracts/docs.js +5 -13
- package/dist/contracts/domains.d.ts +499 -102
- package/dist/contracts/domains.js +169 -58
- package/dist/contracts/email-preferences.d.ts +3 -3
- package/dist/contracts/email-preferences.js +6 -7
- package/dist/contracts/enums.d.ts +26 -26
- package/dist/contracts/enums.js +61 -54
- package/dist/contracts/error-code-meta.d.ts +273 -7
- package/dist/contracts/error-code-meta.js +81 -5
- package/dist/contracts/error-codes.d.ts +5 -5
- package/dist/contracts/error-codes.js +79 -16
- package/dist/contracts/events.d.ts +100 -20
- package/dist/contracts/events.js +107 -20
- package/dist/contracts/execution.d.ts +47 -66
- package/dist/contracts/execution.js +51 -64
- package/dist/contracts/feature-lifecycle.d.ts +70 -14
- package/dist/contracts/feature-lifecycle.js +86 -15
- package/dist/contracts/features.d.ts +100 -37
- package/dist/contracts/features.js +21 -27
- package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
- package/dist/contracts/frame-session.d.ts +192 -0
- package/dist/contracts/frame-session.js +164 -0
- package/dist/contracts/functions.d.ts +218 -211
- package/dist/contracts/functions.js +273 -260
- package/dist/contracts/grant-copy.d.ts +43 -0
- package/dist/contracts/grant-copy.js +44 -0
- package/dist/contracts/grants.d.ts +64 -56
- package/dist/contracts/grants.js +124 -23
- package/dist/contracts/ids.d.ts +4 -1
- package/dist/contracts/ids.js +4 -1
- package/dist/contracts/internal.d.ts +5 -4
- package/dist/contracts/internal.js +12 -3
- package/dist/contracts/mcp.d.ts +17 -0
- package/dist/contracts/mcp.js +23 -0
- package/dist/contracts/me.d.ts +6 -1
- package/dist/contracts/me.js +12 -6
- package/dist/contracts/notifications.d.ts +27 -29
- package/dist/contracts/notifications.js +9 -4
- package/dist/contracts/oauth-resources.d.ts +121 -10
- package/dist/contracts/oauth-resources.js +130 -11
- package/dist/contracts/oauth-scope-actions.d.ts +90 -0
- package/dist/contracts/oauth-scope-actions.js +126 -0
- package/dist/contracts/operations.d.ts +27 -4
- package/dist/contracts/operations.js +11 -5
- package/dist/contracts/pages.d.ts +29 -5
- package/dist/contracts/pages.js +22 -5
- package/dist/contracts/partner-notifications.d.ts +3 -0
- package/dist/contracts/partner-notifications.js +65 -0
- package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
- package/dist/contracts/{platform.js → partner.js} +27 -40
- package/dist/contracts/plan-policy.d.ts +1 -1
- package/dist/contracts/principal-assertion.d.ts +43 -0
- package/dist/contracts/principal-assertion.js +67 -0
- package/dist/contracts/principals.d.ts +73 -0
- package/dist/contracts/principals.js +59 -0
- package/dist/contracts/privacy.d.ts +11 -0
- package/dist/contracts/privacy.js +17 -0
- package/dist/contracts/problem-document.js +3 -4
- package/dist/contracts/publish-archive.d.ts +116 -18
- package/dist/contracts/publish-archive.js +6 -3
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.js +3 -3
- package/dist/contracts/realtime.d.ts +52 -0
- package/dist/contracts/realtime.js +54 -0
- package/dist/contracts/repository-connections.d.ts +1 -1
- package/dist/contracts/repository-connections.js +6 -2
- package/dist/contracts/resources.d.ts +105 -14
- package/dist/contracts/resources.js +145 -21
- package/dist/contracts/route-inventory.d.ts +358 -0
- package/dist/contracts/route-inventory.js +141 -0
- package/dist/contracts/runtime-api.d.ts +112 -35
- package/dist/contracts/runtime-api.js +86 -66
- package/dist/contracts/runtime-app.d.ts +11 -21
- package/dist/contracts/runtime-app.js +39 -24
- package/dist/contracts/runtime-components.d.ts +143 -0
- package/dist/contracts/runtime-components.js +199 -0
- package/dist/contracts/runtime-db.d.ts +45 -19
- package/dist/contracts/runtime-db.js +85 -20
- package/dist/contracts/runtime-purge.js +3 -5
- package/dist/contracts/runtime-services.d.ts +43 -75
- package/dist/contracts/runtime-services.js +29 -49
- package/dist/contracts/runtime-storage.d.ts +14 -14
- package/dist/contracts/runtime-storage.js +28 -13
- package/dist/contracts/sf-config-v1.d.ts +14 -18
- package/dist/contracts/slugs.js +13 -4
- package/dist/contracts/space-config.d.ts +235 -28
- package/dist/contracts/space-config.js +246 -91
- package/dist/contracts/spaces.d.ts +360 -255
- package/dist/contracts/spaces.js +190 -122
- package/dist/contracts/superadmin-activity.d.ts +3 -43
- package/dist/contracts/superadmin-activity.js +6 -30
- package/dist/contracts/superadmin-emails.d.ts +1 -0
- package/dist/contracts/superadmin-emails.js +17 -1
- package/dist/contracts/superadmin-runtime.d.ts +199 -0
- package/dist/contracts/superadmin-runtime.js +141 -0
- package/dist/contracts/superadmin-search.d.ts +22 -2
- package/dist/contracts/superadmin-search.js +14 -6
- package/dist/contracts/superadmin-spaces.d.ts +435 -186
- package/dist/contracts/superadmin-spaces.js +131 -25
- package/dist/contracts/superadmin-teams.d.ts +3 -0
- package/dist/contracts/superadmin-teams.js +1 -2
- package/dist/contracts/superadmin-tenants.d.ts +627 -6
- package/dist/contracts/superadmin-tenants.js +32 -7
- package/dist/contracts/superadmin.d.ts +98 -16
- package/dist/contracts/superadmin.js +63 -10
- package/dist/contracts/tags.d.ts +85 -58
- package/dist/contracts/tags.js +44 -34
- package/dist/contracts/teams.d.ts +72 -9
- package/dist/contracts/teams.js +84 -25
- package/dist/contracts/tenants.d.ts +135 -0
- package/dist/contracts/tenants.js +120 -0
- package/dist/contracts/test-triggers.d.ts +70 -0
- package/dist/contracts/test-triggers.js +116 -0
- package/dist/contracts/theme-json.js +3 -8
- package/dist/contracts/transfers.d.ts +1 -0
- package/dist/contracts/transfers.js +1 -0
- package/dist/contracts/usage.d.ts +209 -0
- package/dist/contracts/usage.js +124 -12
- package/dist/contracts/variables.d.ts +2 -2
- package/dist/contracts/variables.js +9 -13
- package/dist/contracts/webhooks.d.ts +13 -5
- package/dist/contracts/webhooks.js +3 -1
- package/dist/contracts/zero.d.ts +57 -64
- package/dist/contracts/zero.js +68 -66
- package/dist/dashboard-paths/index.d.ts +24 -21
- package/dist/dashboard-paths/index.js +35 -47
- package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
- package/dist/dashboard-paths/route-reservations.generated.js +36 -0
- package/dist/docs/agent-arrival.d.ts +92 -0
- package/dist/docs/agent-arrival.js +227 -0
- package/dist/docs/agent-output-policy.d.ts +6 -0
- package/dist/docs/agent-output-policy.js +22 -0
- package/dist/docs/agent-prose.d.ts +11 -17
- package/dist/docs/agent-prose.js +62 -37
- package/dist/docs/agent-setup.d.ts +72 -41
- package/dist/docs/agent-setup.js +336 -436
- package/dist/docs/catalog.d.ts +147 -89
- package/dist/docs/catalog.js +157 -42
- package/dist/docs/error-docs.d.ts +2102 -1
- package/dist/docs/error-docs.js +285 -16
- package/dist/docs/index-build.d.ts +0 -1
- package/dist/docs/index-build.js +2 -3
- package/dist/docs/page-context-prompt.d.ts +77 -0
- package/dist/docs/page-context-prompt.js +131 -0
- package/dist/docs/reference-urls.d.ts +46 -0
- package/dist/docs/reference-urls.js +79 -0
- package/dist/docs/search.d.ts +6 -8
- package/dist/docs/search.js +10 -13
- package/dist/docs/skill-distribution.d.ts +4 -1
- package/dist/docs/skill-distribution.js +10 -5
- package/dist/docs/skills.d.ts +117 -117
- package/dist/docs/skills.js +120 -72
- package/dist/docs/start-prompts.d.ts +45 -0
- package/dist/docs/start-prompts.js +62 -0
- package/dist/domain-exploration.js +9 -13
- package/dist/og-template.d.ts +56 -0
- package/dist/og-template.js +56 -0
- package/dist/slug-policy/index.js +5 -11
- package/dist/utils/browser-credential.d.ts +13 -6
- package/dist/utils/browser-credential.js +14 -7
- package/dist/utils/build-settings.d.ts +16 -0
- package/dist/utils/build-settings.js +63 -17
- package/dist/utils/canonical-json.d.ts +3 -5
- package/dist/utils/canonical-json.js +3 -5
- package/dist/utils/cast-transport.d.ts +5 -17
- package/dist/utils/cast-transport.js +6 -19
- package/dist/utils/claim-token.js +1 -2
- package/dist/utils/comment-avatars.js +4 -6
- package/dist/utils/concurrency.js +2 -3
- package/dist/utils/content-type.d.ts +7 -6
- package/dist/utils/content-type.js +73 -51
- package/dist/utils/credential-policy.d.ts +50 -6
- package/dist/utils/credential-policy.js +123 -57
- package/dist/utils/egress-policy.fixtures.json +1 -1
- package/dist/utils/generate-space-name.d.ts +3 -8
- package/dist/utils/generate-space-name.js +3 -8
- package/dist/utils/grants.d.ts +0 -1
- package/dist/utils/grants.js +4 -7
- package/dist/utils/gravatar.d.ts +2 -4
- package/dist/utils/gravatar.js +6 -12
- package/dist/utils/id-hints.js +14 -23
- package/dist/utils/idempotency.d.ts +3 -3
- package/dist/utils/idempotency.js +6 -7
- package/dist/utils/local-space-state.d.ts +15 -15
- package/dist/utils/local-space-state.js +34 -23
- package/dist/utils/oauth-signed-query.d.ts +3 -5
- package/dist/utils/oauth-signed-query.js +6 -9
- package/dist/utils/one-shot-replay.d.ts +3 -5
- package/dist/utils/one-shot-replay.js +3 -5
- package/dist/utils/page-colors.d.ts +4 -10
- package/dist/utils/page-colors.js +11 -35
- package/dist/utils/page-fonts.js +6 -11
- package/dist/utils/page-preview.d.ts +0 -1
- package/dist/utils/page-preview.js +0 -1
- package/dist/utils/pages.d.ts +22 -11
- package/dist/utils/pages.js +70 -30
- package/dist/utils/privacy-regions.d.ts +19 -0
- package/dist/utils/privacy-regions.js +91 -0
- package/dist/utils/publish-form-data.d.ts +4 -5
- package/dist/utils/publish-form-data.js +2 -3
- package/dist/utils/publish-policy.d.ts +10 -23
- package/dist/utils/publish-policy.js +63 -116
- package/dist/utils/query-client.d.ts +2 -0
- package/dist/utils/query-client.js +10 -1
- package/dist/utils/runtime-paths.d.ts +4 -4
- package/dist/utils/runtime-paths.js +6 -8
- package/dist/utils/runtime-upload.d.ts +4 -0
- package/dist/utils/runtime-upload.js +5 -0
- package/dist/utils/secure-local-file.d.ts +3 -3
- package/dist/utils/secure-local-file.js +18 -24
- package/dist/utils/space-config.d.ts +11 -14
- package/dist/utils/space-config.js +10 -16
- package/dist/utils/static-runtime-policy.d.ts +5 -8
- package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
- package/dist/utils/static-runtime-policy.generated.js +70 -0
- package/dist/utils/static-runtime-policy.js +17 -84
- package/dist/utils/storage-policy.js +1 -2
- package/dist/utils/upload-session.js +8 -14
- package/dist/utils/version-path.js +11 -19
- package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
- package/dist/utils/wpcom-auth-redirects.js +1 -4
- package/dist/vocabulary.d.ts +7 -7
- package/dist/vocabulary.js +30 -16
- package/package.json +14 -2
- package/dist/agents/client-registry.d.ts +0 -22
- package/dist/agents/client-registry.js +0 -41
- package/dist/docs/agent-handoff-document.d.ts +0 -15
- package/dist/docs/agent-handoff-document.js +0 -180
- package/dist/docs/agent-solutions.d.ts +0 -110
- package/dist/docs/agent-solutions.js +0 -183
- package/dist/utils/query-keys.d.ts +0 -84
- package/dist/utils/query-keys.js +0 -108
|
@@ -38,36 +38,34 @@ export declare const notificationListQuerySchema: z.ZodObject<{
|
|
|
38
38
|
unread: z.ZodDefault<z.ZodOptional<z.ZodCodec<z.ZodString, z.ZodBoolean>>>;
|
|
39
39
|
}, z.core.$strip>;
|
|
40
40
|
export declare const notificationListResponseSchema: z.ZodObject<{
|
|
41
|
-
data: z.ZodObject<{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
color: z.ZodNullable<z.ZodString>;
|
|
60
|
-
}, z.core.$strip>;
|
|
61
|
-
path: z.ZodNullable<z.ZodString>;
|
|
62
|
-
versionId: z.ZodNullable<z.ZodString>;
|
|
63
|
-
link: z.ZodNullable<z.ZodString>;
|
|
64
|
-
readAt: z.ZodNullable<z.ZodString>;
|
|
65
|
-
createdAt: z.ZodString;
|
|
66
|
-
}, z.core.$strip>>;
|
|
67
|
-
pagination: z.ZodObject<{
|
|
68
|
-
nextCursor: z.ZodNullable<z.ZodString>;
|
|
69
|
-
hasMore: z.ZodBoolean;
|
|
41
|
+
data: z.ZodArray<z.ZodObject<{
|
|
42
|
+
id: z.ZodString;
|
|
43
|
+
kind: z.ZodEnum<{
|
|
44
|
+
"comment.created": "comment.created";
|
|
45
|
+
"comment.replied": "comment.replied";
|
|
46
|
+
"thread.archived": "thread.archived";
|
|
47
|
+
"thread.unarchived": "thread.unarchived";
|
|
48
|
+
mention: "mention";
|
|
49
|
+
}>;
|
|
50
|
+
teamId: z.ZodNullable<z.ZodString>;
|
|
51
|
+
spaceId: z.ZodNullable<z.ZodString>;
|
|
52
|
+
threadId: z.ZodNullable<z.ZodString>;
|
|
53
|
+
title: z.ZodString;
|
|
54
|
+
body: z.ZodNullable<z.ZodString>;
|
|
55
|
+
actor: z.ZodObject<{
|
|
56
|
+
name: z.ZodNullable<z.ZodString>;
|
|
57
|
+
avatarUrl: z.ZodNullable<z.ZodString>;
|
|
58
|
+
color: z.ZodNullable<z.ZodString>;
|
|
70
59
|
}, z.core.$strip>;
|
|
60
|
+
path: z.ZodNullable<z.ZodString>;
|
|
61
|
+
versionId: z.ZodNullable<z.ZodString>;
|
|
62
|
+
link: z.ZodNullable<z.ZodString>;
|
|
63
|
+
readAt: z.ZodNullable<z.ZodString>;
|
|
64
|
+
createdAt: z.ZodString;
|
|
65
|
+
}, z.core.$strip>>;
|
|
66
|
+
pagination: z.ZodObject<{
|
|
67
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
68
|
+
hasMore: z.ZodBoolean;
|
|
71
69
|
}, z.core.$strip>;
|
|
72
70
|
}, z.core.$strip>;
|
|
73
71
|
export declare const notificationUnreadCountResponseSchema: z.ZodObject<{
|
|
@@ -28,12 +28,17 @@ export const notificationSchema = z.object({
|
|
|
28
28
|
createdAt: z.string().datetime(),
|
|
29
29
|
});
|
|
30
30
|
export const notificationListQuerySchema = cursorListQuerySchema.extend({
|
|
31
|
-
unread: z
|
|
31
|
+
unread: z
|
|
32
|
+
.stringbool()
|
|
33
|
+
.optional()
|
|
34
|
+
.default(false)
|
|
35
|
+
.describe("Return only notifications that have not been read yet."),
|
|
32
36
|
});
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
// The one platform list envelope: items in `data[]`, page state beside it.
|
|
38
|
+
export const notificationListResponseSchema = z.object({
|
|
39
|
+
data: z.array(notificationSchema),
|
|
35
40
|
pagination: CursorPaginationSchema,
|
|
36
|
-
})
|
|
41
|
+
});
|
|
37
42
|
export const notificationUnreadCountResponseSchema = dataEnvelope(z.object({ count: z.number().int().nonnegative() }));
|
|
38
43
|
export const notificationReadRequestSchema = z.object({
|
|
39
44
|
ids: z.array(z.string().min(1)).max(100).optional(),
|
|
@@ -3,19 +3,19 @@ export declare const OAUTH_AUTHORIZATION_SERVER_PATH: "/v1/auth";
|
|
|
3
3
|
* mcp origin (`https://mcp.<domain>`), so it has no path entry here. */
|
|
4
4
|
export declare const OAUTH_API_RESOURCE_PATH: "/v1";
|
|
5
5
|
export type OAuthResourceKey = "api" | "mcp";
|
|
6
|
+
export declare const OAUTH_SHARED_API_RESOURCE_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write"];
|
|
6
7
|
export declare const OAUTH_API_RESOURCE_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "spaces:publish", "builds:trigger"];
|
|
7
|
-
export declare const OAUTH_MCP_TOOL_SCOPE: "mcp:tools";
|
|
8
8
|
export declare const OAUTH_OFFLINE_ACCESS_SCOPE: "offline_access";
|
|
9
|
-
export declare const OAUTH_MCP_RESOURCE_SCOPES: readonly ["
|
|
9
|
+
export declare const OAUTH_MCP_RESOURCE_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write"];
|
|
10
10
|
/**
|
|
11
11
|
* A resource's `allowedScopes` is intersected with the requested scopes on every
|
|
12
|
-
* token request, and the refresh token stores that intersection
|
|
12
|
+
* token request, and the refresh token stores that intersection, so a resource
|
|
13
13
|
* that omits `offline_access` cannot mint a refresh token that survives
|
|
14
14
|
* rotation, and its clients must re-consent in a browser every
|
|
15
15
|
* `accessTokenTtlSeconds`. Kept separate from OAUTH_MCP_RESOURCE_SCOPES, which
|
|
16
|
-
* is the list of capabilities the dashboard and CLI offer per
|
|
16
|
+
* is the list of capabilities the dashboard and CLI offer per machine OAuth client.
|
|
17
17
|
*/
|
|
18
|
-
export declare const OAUTH_MCP_RESOURCE_ALLOWED_SCOPES: readonly ["
|
|
18
|
+
export declare const OAUTH_MCP_RESOURCE_ALLOWED_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "offline_access"];
|
|
19
19
|
export declare const OAUTH_API_RESOURCE_ALLOWED_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "spaces:publish", "builds:trigger", "offline_access"];
|
|
20
20
|
/**
|
|
21
21
|
* Interactive MCP clients should be useful after one consent. Authorization is
|
|
@@ -23,8 +23,119 @@ export declare const OAUTH_API_RESOURCE_ALLOWED_SCOPES: readonly ["teams:read",
|
|
|
23
23
|
* sensitive execution; these scopes only let the MCP resource represent those
|
|
24
24
|
* capabilities. Machine clients may continue to request a narrower set.
|
|
25
25
|
*/
|
|
26
|
-
export declare const OAUTH_MCP_DEFAULT_SCOPES: readonly ["
|
|
27
|
-
export declare const OAUTH_PROVIDER_SCOPES: readonly ["openid", "profile", "email", "offline_access", "teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "spaces:publish", "builds:trigger"
|
|
26
|
+
export declare const OAUTH_MCP_DEFAULT_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "offline_access"];
|
|
27
|
+
export declare const OAUTH_PROVIDER_SCOPES: readonly ["openid", "profile", "email", "offline_access", "teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "spaces:publish", "builds:trigger"];
|
|
28
|
+
export declare const OAUTH_SCOPE_DESCRIPTIONS: {
|
|
29
|
+
readonly openid: "Identify the signed-in account.";
|
|
30
|
+
readonly profile: "Read the signed-in account's basic profile.";
|
|
31
|
+
readonly email: "Read the signed-in account's email address.";
|
|
32
|
+
readonly offline_access: "Refresh access without another interactive sign-in.";
|
|
33
|
+
readonly "teams:read": "Read the teams the account belongs to.";
|
|
34
|
+
readonly "teams:create": "Create teams.";
|
|
35
|
+
readonly "spaces:read": "Read spaces, versions, and build status.";
|
|
36
|
+
readonly "spaces:write": "Create and update spaces and their settings.";
|
|
37
|
+
readonly "spaces:rename": "Rename space slugs and managed addresses.";
|
|
38
|
+
readonly "publish:write": "Publish new immutable versions.";
|
|
39
|
+
readonly "spaces:publish": "Publish a version to an existing space.";
|
|
40
|
+
readonly "builds:trigger": "Start a build for an existing version.";
|
|
41
|
+
readonly "domains:read": "Read domain inventory and DNS diagnostics.";
|
|
42
|
+
readonly "domains:write": "Attach, verify, and mutate domains and DNS records.";
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Drop scope ids the vocabulary no longer knows (e.g. a removed scope that
|
|
46
|
+
* older grants still store). Safe and non-widening, same as the api-key
|
|
47
|
+
* action normalizer: a retired scope gates nothing anywhere, so the surviving
|
|
48
|
+
* scopes are the real grant — serving the retired id would present a
|
|
49
|
+
* permission that does not exist, and strict consumers of the provider
|
|
50
|
+
* vocabulary would reject the whole payload over it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function knownOAuthScopes(scopes: readonly string[]): OAuthScopeId[];
|
|
53
|
+
export declare const OAUTH_SCOPE_RISK_TINTS: readonly ["neutral", "warning", "critical"];
|
|
54
|
+
export type OAuthScopeRiskTint = (typeof OAUTH_SCOPE_RISK_TINTS)[number];
|
|
55
|
+
export type OAuthScopeId = keyof typeof OAUTH_SCOPE_DESCRIPTIONS;
|
|
56
|
+
export type OAuthScopeCopy = {
|
|
57
|
+
label: string;
|
|
58
|
+
description: string;
|
|
59
|
+
riskTint: OAuthScopeRiskTint;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Human-facing permission copy shared by every authorization surface. Keep raw
|
|
63
|
+
* OAuth scope ids in developer views only; consent, approvals, ledgers, CLI
|
|
64
|
+
* prompts, and email should all render this vocabulary.
|
|
65
|
+
*/
|
|
66
|
+
export declare const OAUTH_SCOPE_COPY: {
|
|
67
|
+
readonly openid: {
|
|
68
|
+
readonly label: "Identify your account";
|
|
69
|
+
readonly description: "Identify the signed-in account.";
|
|
70
|
+
readonly riskTint: "neutral";
|
|
71
|
+
};
|
|
72
|
+
readonly profile: {
|
|
73
|
+
readonly label: "Read your profile";
|
|
74
|
+
readonly description: "Read the signed-in account's basic profile.";
|
|
75
|
+
readonly riskTint: "neutral";
|
|
76
|
+
};
|
|
77
|
+
readonly email: {
|
|
78
|
+
readonly label: "Read your email address";
|
|
79
|
+
readonly description: "Read the signed-in account's email address.";
|
|
80
|
+
readonly riskTint: "neutral";
|
|
81
|
+
};
|
|
82
|
+
readonly offline_access: {
|
|
83
|
+
readonly label: "Stay connected";
|
|
84
|
+
readonly description: "Refresh access without another interactive sign-in.";
|
|
85
|
+
readonly riskTint: "warning";
|
|
86
|
+
};
|
|
87
|
+
readonly "teams:read": {
|
|
88
|
+
readonly label: "Read your teams";
|
|
89
|
+
readonly description: "Read the teams the account belongs to.";
|
|
90
|
+
readonly riskTint: "neutral";
|
|
91
|
+
};
|
|
92
|
+
readonly "teams:create": {
|
|
93
|
+
readonly label: "Create teams";
|
|
94
|
+
readonly description: "Create teams.";
|
|
95
|
+
readonly riskTint: "warning";
|
|
96
|
+
};
|
|
97
|
+
readonly "spaces:read": {
|
|
98
|
+
readonly label: "Read your sites";
|
|
99
|
+
readonly description: "Read spaces, versions, and build status.";
|
|
100
|
+
readonly riskTint: "neutral";
|
|
101
|
+
};
|
|
102
|
+
readonly "spaces:write": {
|
|
103
|
+
readonly label: "Create and update your sites";
|
|
104
|
+
readonly description: "Create and update spaces and their settings.";
|
|
105
|
+
readonly riskTint: "warning";
|
|
106
|
+
};
|
|
107
|
+
readonly "spaces:rename": {
|
|
108
|
+
readonly label: "Rename your sites";
|
|
109
|
+
readonly description: "Rename space slugs and managed addresses.";
|
|
110
|
+
readonly riskTint: "warning";
|
|
111
|
+
};
|
|
112
|
+
readonly "publish:write": {
|
|
113
|
+
readonly label: "Publish and manage versions";
|
|
114
|
+
readonly description: "Publish new immutable versions.";
|
|
115
|
+
readonly riskTint: "warning";
|
|
116
|
+
};
|
|
117
|
+
readonly "spaces:publish": {
|
|
118
|
+
readonly label: "Publish new versions of your sites";
|
|
119
|
+
readonly description: "Publish a version to an existing space.";
|
|
120
|
+
readonly riskTint: "warning";
|
|
121
|
+
};
|
|
122
|
+
readonly "builds:trigger": {
|
|
123
|
+
readonly label: "Start builds";
|
|
124
|
+
readonly description: "Start a build for an existing version.";
|
|
125
|
+
readonly riskTint: "warning";
|
|
126
|
+
};
|
|
127
|
+
readonly "domains:read": {
|
|
128
|
+
readonly label: "Read your domains";
|
|
129
|
+
readonly description: "Read domain inventory and DNS diagnostics.";
|
|
130
|
+
readonly riskTint: "neutral";
|
|
131
|
+
};
|
|
132
|
+
readonly "domains:write": {
|
|
133
|
+
readonly label: "Manage domains and DNS";
|
|
134
|
+
readonly description: "Attach, verify, and mutate domains and DNS records.";
|
|
135
|
+
readonly riskTint: "critical";
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
export declare function oauthScopeCopy(scope: string): OAuthScopeCopy;
|
|
28
139
|
export declare const OAUTH_RESOURCE_DEFINITIONS: {
|
|
29
140
|
readonly api: {
|
|
30
141
|
readonly key: "api";
|
|
@@ -36,14 +147,14 @@ export declare const OAUTH_RESOURCE_DEFINITIONS: {
|
|
|
36
147
|
readonly key: "mcp";
|
|
37
148
|
readonly name: "Spacefast MCP";
|
|
38
149
|
readonly accessTokenTtlSeconds: number;
|
|
39
|
-
readonly allowedScopes: readonly ["
|
|
150
|
+
readonly allowedScopes: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "offline_access"];
|
|
40
151
|
};
|
|
41
152
|
};
|
|
42
153
|
/** Resource identifier for the public API: `https://api.<domain>/v1`. */
|
|
43
154
|
export declare function oauthApiResourceUrl(apiOrigin: string | URL): string;
|
|
44
155
|
/**
|
|
45
156
|
* Resource identifier for hosted MCP: the mcp origin itself, in RFC 8707
|
|
46
|
-
* canonical form (lowercase scheme/host, no trailing slash)
|
|
157
|
+
* canonical form (lowercase scheme/host, no trailing slash). This is the
|
|
47
158
|
* exact string MCP clients send as the `resource` parameter.
|
|
48
159
|
*/
|
|
49
160
|
export declare function oauthMcpResourceUrl(mcpOrigin: string | URL): string;
|
|
@@ -51,7 +162,7 @@ export declare function normalizeOAuthResourceIdentifier(resource: string): stri
|
|
|
51
162
|
/**
|
|
52
163
|
* Derive the mcp origin from a configured api origin (`api.X` → `mcp.X`).
|
|
53
164
|
* Returns null when the api host doesn't follow the `api.` convention
|
|
54
|
-
* (loopback dev, docker test hosts)
|
|
165
|
+
* (loopback dev, docker test hosts). Callers fall back to the api origin.
|
|
55
166
|
*/
|
|
56
167
|
export declare function oauthMcpOriginFromApiOrigin(apiOrigin: string | URL): string | null;
|
|
57
168
|
/**
|
|
@@ -2,7 +2,12 @@ export const OAUTH_AUTHORIZATION_SERVER_PATH = "/v1/auth";
|
|
|
2
2
|
/** The API resource is a path on the api origin; the MCP resource is the whole
|
|
3
3
|
* mcp origin (`https://mcp.<domain>`), so it has no path entry here. */
|
|
4
4
|
export const OAUTH_API_RESOURCE_PATH = "/v1";
|
|
5
|
-
|
|
5
|
+
// The scopes shared by the API resource, the MCP resource, and the interactive
|
|
6
|
+
// approval surface. `spaces:publish` and `builds:trigger` are deliberately NOT
|
|
7
|
+
// here: their actions are already covered by `publish:write`, so they exist
|
|
8
|
+
// only as granular API-resource scopes for clients (e.g. the WordPress plugin)
|
|
9
|
+
// that want to name them. Interactive approval and MCP speak this shared set.
|
|
10
|
+
export const OAUTH_SHARED_API_RESOURCE_SCOPES = [
|
|
6
11
|
"teams:read",
|
|
7
12
|
"teams:create",
|
|
8
13
|
"spaces:read",
|
|
@@ -17,19 +22,18 @@ export const OAUTH_API_RESOURCE_SCOPES = [
|
|
|
17
22
|
"spaces:publish",
|
|
18
23
|
"builds:trigger",
|
|
19
24
|
];
|
|
20
|
-
export const OAUTH_MCP_TOOL_SCOPE = "mcp:tools";
|
|
21
25
|
export const OAUTH_OFFLINE_ACCESS_SCOPE = "offline_access";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
];
|
|
26
|
+
// Hosted MCP is pure transport over the API: a session represents exactly the
|
|
27
|
+
// shared API scopes, and each tool call is gated only by the underlying API
|
|
28
|
+
// scope it exercises. So the MCP resource's scopes are the shared API set.
|
|
29
|
+
export const OAUTH_MCP_RESOURCE_SCOPES = [...OAUTH_SHARED_API_RESOURCE_SCOPES];
|
|
26
30
|
/**
|
|
27
31
|
* A resource's `allowedScopes` is intersected with the requested scopes on every
|
|
28
|
-
* token request, and the refresh token stores that intersection
|
|
32
|
+
* token request, and the refresh token stores that intersection, so a resource
|
|
29
33
|
* that omits `offline_access` cannot mint a refresh token that survives
|
|
30
34
|
* rotation, and its clients must re-consent in a browser every
|
|
31
35
|
* `accessTokenTtlSeconds`. Kept separate from OAUTH_MCP_RESOURCE_SCOPES, which
|
|
32
|
-
* is the list of capabilities the dashboard and CLI offer per
|
|
36
|
+
* is the list of capabilities the dashboard and CLI offer per machine OAuth client.
|
|
33
37
|
*/
|
|
34
38
|
export const OAUTH_MCP_RESOURCE_ALLOWED_SCOPES = [
|
|
35
39
|
...OAUTH_MCP_RESOURCE_SCOPES,
|
|
@@ -52,8 +56,123 @@ export const OAUTH_PROVIDER_SCOPES = [
|
|
|
52
56
|
"email",
|
|
53
57
|
OAUTH_OFFLINE_ACCESS_SCOPE,
|
|
54
58
|
...OAUTH_API_RESOURCE_SCOPES,
|
|
55
|
-
OAUTH_MCP_TOOL_SCOPE,
|
|
56
59
|
];
|
|
60
|
+
export const OAUTH_SCOPE_DESCRIPTIONS = {
|
|
61
|
+
openid: "Identify the signed-in account.",
|
|
62
|
+
profile: "Read the signed-in account's basic profile.",
|
|
63
|
+
email: "Read the signed-in account's email address.",
|
|
64
|
+
offline_access: "Refresh access without another interactive sign-in.",
|
|
65
|
+
"teams:read": "Read the teams the account belongs to.",
|
|
66
|
+
"teams:create": "Create teams.",
|
|
67
|
+
"spaces:read": "Read spaces, versions, and build status.",
|
|
68
|
+
"spaces:write": "Create and update spaces and their settings.",
|
|
69
|
+
"spaces:rename": "Rename space slugs and managed addresses.",
|
|
70
|
+
"publish:write": "Publish new immutable versions.",
|
|
71
|
+
"spaces:publish": "Publish a version to an existing space.",
|
|
72
|
+
"builds:trigger": "Start a build for an existing version.",
|
|
73
|
+
"domains:read": "Read domain inventory and DNS diagnostics.",
|
|
74
|
+
"domains:write": "Attach, verify, and mutate domains and DNS records.",
|
|
75
|
+
};
|
|
76
|
+
const OAUTH_PROVIDER_SCOPE_SET = new Set(OAUTH_PROVIDER_SCOPES);
|
|
77
|
+
/**
|
|
78
|
+
* Drop scope ids the vocabulary no longer knows (e.g. a removed scope that
|
|
79
|
+
* older grants still store). Safe and non-widening, same as the api-key
|
|
80
|
+
* action normalizer: a retired scope gates nothing anywhere, so the surviving
|
|
81
|
+
* scopes are the real grant — serving the retired id would present a
|
|
82
|
+
* permission that does not exist, and strict consumers of the provider
|
|
83
|
+
* vocabulary would reject the whole payload over it.
|
|
84
|
+
*/
|
|
85
|
+
export function knownOAuthScopes(scopes) {
|
|
86
|
+
return [
|
|
87
|
+
...new Set(scopes.filter((scope) => OAUTH_PROVIDER_SCOPE_SET.has(scope))),
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
export const OAUTH_SCOPE_RISK_TINTS = ["neutral", "warning", "critical"];
|
|
91
|
+
/**
|
|
92
|
+
* Human-facing permission copy shared by every authorization surface. Keep raw
|
|
93
|
+
* OAuth scope ids in developer views only; consent, approvals, ledgers, CLI
|
|
94
|
+
* prompts, and email should all render this vocabulary.
|
|
95
|
+
*/
|
|
96
|
+
export const OAUTH_SCOPE_COPY = {
|
|
97
|
+
openid: {
|
|
98
|
+
label: "Identify your account",
|
|
99
|
+
description: OAUTH_SCOPE_DESCRIPTIONS.openid,
|
|
100
|
+
riskTint: "neutral",
|
|
101
|
+
},
|
|
102
|
+
profile: {
|
|
103
|
+
label: "Read your profile",
|
|
104
|
+
description: OAUTH_SCOPE_DESCRIPTIONS.profile,
|
|
105
|
+
riskTint: "neutral",
|
|
106
|
+
},
|
|
107
|
+
email: {
|
|
108
|
+
label: "Read your email address",
|
|
109
|
+
description: OAUTH_SCOPE_DESCRIPTIONS.email,
|
|
110
|
+
riskTint: "neutral",
|
|
111
|
+
},
|
|
112
|
+
offline_access: {
|
|
113
|
+
label: "Stay connected",
|
|
114
|
+
description: OAUTH_SCOPE_DESCRIPTIONS.offline_access,
|
|
115
|
+
riskTint: "warning",
|
|
116
|
+
},
|
|
117
|
+
"teams:read": {
|
|
118
|
+
label: "Read your teams",
|
|
119
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["teams:read"],
|
|
120
|
+
riskTint: "neutral",
|
|
121
|
+
},
|
|
122
|
+
"teams:create": {
|
|
123
|
+
label: "Create teams",
|
|
124
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["teams:create"],
|
|
125
|
+
riskTint: "warning",
|
|
126
|
+
},
|
|
127
|
+
"spaces:read": {
|
|
128
|
+
label: "Read your sites",
|
|
129
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["spaces:read"],
|
|
130
|
+
riskTint: "neutral",
|
|
131
|
+
},
|
|
132
|
+
"spaces:write": {
|
|
133
|
+
label: "Create and update your sites",
|
|
134
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["spaces:write"],
|
|
135
|
+
riskTint: "warning",
|
|
136
|
+
},
|
|
137
|
+
"spaces:rename": {
|
|
138
|
+
label: "Rename your sites",
|
|
139
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["spaces:rename"],
|
|
140
|
+
riskTint: "warning",
|
|
141
|
+
},
|
|
142
|
+
"publish:write": {
|
|
143
|
+
label: "Publish and manage versions",
|
|
144
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["publish:write"],
|
|
145
|
+
riskTint: "warning",
|
|
146
|
+
},
|
|
147
|
+
"spaces:publish": {
|
|
148
|
+
label: "Publish new versions of your sites",
|
|
149
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["spaces:publish"],
|
|
150
|
+
riskTint: "warning",
|
|
151
|
+
},
|
|
152
|
+
"builds:trigger": {
|
|
153
|
+
label: "Start builds",
|
|
154
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["builds:trigger"],
|
|
155
|
+
riskTint: "warning",
|
|
156
|
+
},
|
|
157
|
+
"domains:read": {
|
|
158
|
+
label: "Read your domains",
|
|
159
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["domains:read"],
|
|
160
|
+
riskTint: "neutral",
|
|
161
|
+
},
|
|
162
|
+
"domains:write": {
|
|
163
|
+
label: "Manage domains and DNS",
|
|
164
|
+
description: OAUTH_SCOPE_DESCRIPTIONS["domains:write"],
|
|
165
|
+
riskTint: "critical",
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
export function oauthScopeCopy(scope) {
|
|
169
|
+
const match = Object.entries(OAUTH_SCOPE_COPY).find(([knownScope]) => knownScope === scope);
|
|
170
|
+
return (match?.[1] ?? {
|
|
171
|
+
label: "Additional Spacefast access",
|
|
172
|
+
description: "Review this permission in Spacefast before you approve it.",
|
|
173
|
+
riskTint: "critical",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
57
176
|
export const OAUTH_RESOURCE_DEFINITIONS = {
|
|
58
177
|
api: {
|
|
59
178
|
key: "api",
|
|
@@ -74,7 +193,7 @@ export function oauthApiResourceUrl(apiOrigin) {
|
|
|
74
193
|
}
|
|
75
194
|
/**
|
|
76
195
|
* Resource identifier for hosted MCP: the mcp origin itself, in RFC 8707
|
|
77
|
-
* canonical form (lowercase scheme/host, no trailing slash)
|
|
196
|
+
* canonical form (lowercase scheme/host, no trailing slash). This is the
|
|
78
197
|
* exact string MCP clients send as the `resource` parameter.
|
|
79
198
|
*/
|
|
80
199
|
export function oauthMcpResourceUrl(mcpOrigin) {
|
|
@@ -98,7 +217,7 @@ export function normalizeOAuthResourceIdentifier(resource) {
|
|
|
98
217
|
/**
|
|
99
218
|
* Derive the mcp origin from a configured api origin (`api.X` → `mcp.X`).
|
|
100
219
|
* Returns null when the api host doesn't follow the `api.` convention
|
|
101
|
-
* (loopback dev, docker test hosts)
|
|
220
|
+
* (loopback dev, docker test hosts). Callers fall back to the api origin.
|
|
102
221
|
*/
|
|
103
222
|
export function oauthMcpOriginFromApiOrigin(apiOrigin) {
|
|
104
223
|
const url = new URL(apiOrigin);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type StatticAction } from "./api-keys.js";
|
|
2
|
+
/**
|
|
3
|
+
* Tenant-admission actions — the ONE declaration the credential compiler and
|
|
4
|
+
* scope-grantability both read, so they cannot drift. These are account-level:
|
|
5
|
+
* compiled onto the tenant root and checked ONLY there (creating a
|
|
6
|
+
* not-yet-existing team has no team to hang on), so their reach across the
|
|
7
|
+
* shared tenant grants no team authority. Every other action is team-role:
|
|
8
|
+
* compiled per team and intersected with the holder's LIVE role there.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TENANT_ADMISSION_ACTIONS: readonly ["teams:create"];
|
|
11
|
+
export declare function isTenantAdmissionAction(action: StatticAction): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The one table binding OAuth scopes to IAM-lite actions, in both directions.
|
|
14
|
+
*
|
|
15
|
+
* Each scope declares only the actions it adds, plus the narrower scopes it
|
|
16
|
+
* subsumes. Everything else is derived:
|
|
17
|
+
*
|
|
18
|
+
* - forward (`oauthScopeActions`): a scope grants its own actions plus every
|
|
19
|
+
* action of the scopes it covers, transitively. That is also what an API-key
|
|
20
|
+
* preset with the same name is allowed to do, so `credential-policy.ts`
|
|
21
|
+
* compiles presets from here rather than from a second list.
|
|
22
|
+
* - inverse (`oauthScopesForActions`): a policy's actions name the scopes whose
|
|
23
|
+
* *own* actions they reach. Covered actions are deliberately not signals —
|
|
24
|
+
* otherwise a read-only policy would label itself `publish:write` just for
|
|
25
|
+
* holding `spaces:read`.
|
|
26
|
+
*
|
|
27
|
+
* Keep both halves honest by editing one entry: adding an action to a scope
|
|
28
|
+
* widens the grant and the label together, and `oauth-resources.test.ts` pins
|
|
29
|
+
* the derivation's invariants.
|
|
30
|
+
*/
|
|
31
|
+
declare const OAUTH_SCOPE_GRAPH: {
|
|
32
|
+
readonly "teams:read": {
|
|
33
|
+
readonly covers: readonly [];
|
|
34
|
+
readonly actions: readonly ["teams:read"];
|
|
35
|
+
};
|
|
36
|
+
readonly "teams:create": {
|
|
37
|
+
readonly covers: readonly [];
|
|
38
|
+
readonly actions: readonly ["teams:create"];
|
|
39
|
+
};
|
|
40
|
+
readonly "spaces:read": {
|
|
41
|
+
readonly covers: readonly [];
|
|
42
|
+
readonly actions: readonly ["spaces:read", "versions:read", "builds:read"];
|
|
43
|
+
};
|
|
44
|
+
readonly "spaces:write": {
|
|
45
|
+
readonly covers: readonly [];
|
|
46
|
+
readonly actions: readonly ["spaces:create", "spaces:write"];
|
|
47
|
+
};
|
|
48
|
+
readonly "spaces:rename": {
|
|
49
|
+
readonly covers: readonly [];
|
|
50
|
+
readonly actions: readonly ["spaces:rename"];
|
|
51
|
+
};
|
|
52
|
+
readonly "publish:write": {
|
|
53
|
+
readonly covers: readonly ["spaces:read", "spaces:write"];
|
|
54
|
+
readonly actions: readonly ["spaces:publish", "versions:promote", "versions:download", "builds:trigger", "builds:create"];
|
|
55
|
+
};
|
|
56
|
+
readonly "domains:read": {
|
|
57
|
+
readonly covers: readonly [];
|
|
58
|
+
readonly actions: readonly ["domains:read"];
|
|
59
|
+
};
|
|
60
|
+
readonly "domains:write": {
|
|
61
|
+
readonly covers: readonly ["domains:read"];
|
|
62
|
+
readonly actions: readonly ["domains:create", "domains:verify", "domains:assign", "domains:bind", "domains:delete", "domains:dns.write", "domains:purchase"];
|
|
63
|
+
};
|
|
64
|
+
readonly "spaces:publish": {
|
|
65
|
+
readonly covers: readonly [];
|
|
66
|
+
readonly actions: readonly ["spaces:publish"];
|
|
67
|
+
};
|
|
68
|
+
readonly "builds:trigger": {
|
|
69
|
+
readonly covers: readonly [];
|
|
70
|
+
readonly actions: readonly ["builds:trigger"];
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export type OAuthScopeWithActions = keyof typeof OAUTH_SCOPE_GRAPH;
|
|
74
|
+
export declare function oauthScopeHasActions(scope: string): scope is OAuthScopeWithActions;
|
|
75
|
+
/**
|
|
76
|
+
* The scopes a credential policy can be *labelled* with: the capability set the
|
|
77
|
+
* dashboard and CLI offer per machine OAuth client. Derived from the graph's
|
|
78
|
+
* own order so the label list reads the way the consent screen does.
|
|
79
|
+
*/
|
|
80
|
+
export declare const OAUTH_PRIMARY_SCOPES: ("teams:read" | "teams:create" | "spaces:read" | "spaces:write" | "spaces:rename" | "publish:write" | "domains:read" | "domains:write" | "spaces:publish" | "builds:trigger")[];
|
|
81
|
+
/** Every action a scope grants, including the scopes it subsumes. */
|
|
82
|
+
export declare function oauthScopeActionsFor(scope: OAuthScopeWithActions): StatticAction[];
|
|
83
|
+
/** Every action a set of scopes grants together. Unknown scopes grant nothing. */
|
|
84
|
+
export declare function oauthScopeActions(scopes: readonly string[] | null | undefined): StatticAction[];
|
|
85
|
+
/**
|
|
86
|
+
* The primary scopes a set of allowed actions amounts to. `*` is every primary
|
|
87
|
+
* scope; anything else matches on a scope's own actions only.
|
|
88
|
+
*/
|
|
89
|
+
export declare function oauthScopesForActions(actions: Iterable<string>): OAuthScopeWithActions[];
|
|
90
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { StatticActionSchema } from "./api-keys.js";
|
|
2
|
+
import { OAUTH_MCP_RESOURCE_SCOPES } from "./oauth-resources.js";
|
|
3
|
+
/**
|
|
4
|
+
* Tenant-admission actions — the ONE declaration the credential compiler and
|
|
5
|
+
* scope-grantability both read, so they cannot drift. These are account-level:
|
|
6
|
+
* compiled onto the tenant root and checked ONLY there (creating a
|
|
7
|
+
* not-yet-existing team has no team to hang on), so their reach across the
|
|
8
|
+
* shared tenant grants no team authority. Every other action is team-role:
|
|
9
|
+
* compiled per team and intersected with the holder's LIVE role there.
|
|
10
|
+
*/
|
|
11
|
+
export const TENANT_ADMISSION_ACTIONS = [
|
|
12
|
+
"teams:create",
|
|
13
|
+
];
|
|
14
|
+
const TENANT_ADMISSION_ACTION_SET = new Set(TENANT_ADMISSION_ACTIONS);
|
|
15
|
+
export function isTenantAdmissionAction(action) {
|
|
16
|
+
return TENANT_ADMISSION_ACTION_SET.has(action);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The one table binding OAuth scopes to IAM-lite actions, in both directions.
|
|
20
|
+
*
|
|
21
|
+
* Each scope declares only the actions it adds, plus the narrower scopes it
|
|
22
|
+
* subsumes. Everything else is derived:
|
|
23
|
+
*
|
|
24
|
+
* - forward (`oauthScopeActions`): a scope grants its own actions plus every
|
|
25
|
+
* action of the scopes it covers, transitively. That is also what an API-key
|
|
26
|
+
* preset with the same name is allowed to do, so `credential-policy.ts`
|
|
27
|
+
* compiles presets from here rather than from a second list.
|
|
28
|
+
* - inverse (`oauthScopesForActions`): a policy's actions name the scopes whose
|
|
29
|
+
* *own* actions they reach. Covered actions are deliberately not signals —
|
|
30
|
+
* otherwise a read-only policy would label itself `publish:write` just for
|
|
31
|
+
* holding `spaces:read`.
|
|
32
|
+
*
|
|
33
|
+
* Keep both halves honest by editing one entry: adding an action to a scope
|
|
34
|
+
* widens the grant and the label together, and `oauth-resources.test.ts` pins
|
|
35
|
+
* the derivation's invariants.
|
|
36
|
+
*/
|
|
37
|
+
const OAUTH_SCOPE_GRAPH = {
|
|
38
|
+
"teams:read": { covers: [], actions: ["teams:read"] },
|
|
39
|
+
"teams:create": { covers: [], actions: ["teams:create"] },
|
|
40
|
+
"spaces:read": {
|
|
41
|
+
covers: [],
|
|
42
|
+
actions: ["spaces:read", "versions:read", "builds:read"],
|
|
43
|
+
},
|
|
44
|
+
"spaces:write": { covers: [], actions: ["spaces:create", "spaces:write"] },
|
|
45
|
+
"spaces:rename": { covers: [], actions: ["spaces:rename"] },
|
|
46
|
+
// The publish tier is read + write plus the version and build verbs a
|
|
47
|
+
// publish flow needs. `spaces:publish` and `builds:trigger` are also offered
|
|
48
|
+
// on their own as granular API-resource scopes; they stay listed here as
|
|
49
|
+
// publish's own actions so a policy holding nothing but them still labels as
|
|
50
|
+
// a publisher.
|
|
51
|
+
"publish:write": {
|
|
52
|
+
covers: ["spaces:read", "spaces:write"],
|
|
53
|
+
actions: [
|
|
54
|
+
"spaces:publish",
|
|
55
|
+
"versions:promote",
|
|
56
|
+
"versions:download",
|
|
57
|
+
"builds:trigger",
|
|
58
|
+
"builds:create",
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
"domains:read": { covers: [], actions: ["domains:read"] },
|
|
62
|
+
"domains:write": {
|
|
63
|
+
covers: ["domains:read"],
|
|
64
|
+
actions: [
|
|
65
|
+
"domains:create",
|
|
66
|
+
"domains:verify",
|
|
67
|
+
"domains:assign",
|
|
68
|
+
"domains:bind",
|
|
69
|
+
"domains:delete",
|
|
70
|
+
"domains:dns.write",
|
|
71
|
+
"domains:purchase",
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
// Granular API-resource scopes. They never label a policy on their own — the
|
|
75
|
+
// inverse only ranges over the primary scopes below.
|
|
76
|
+
"spaces:publish": { covers: [], actions: ["spaces:publish"] },
|
|
77
|
+
"builds:trigger": { covers: [], actions: ["builds:trigger"] },
|
|
78
|
+
};
|
|
79
|
+
export function oauthScopeHasActions(scope) {
|
|
80
|
+
return scope in OAUTH_SCOPE_GRAPH;
|
|
81
|
+
}
|
|
82
|
+
const primaryScopeSet = new Set(OAUTH_MCP_RESOURCE_SCOPES);
|
|
83
|
+
/**
|
|
84
|
+
* The scopes a credential policy can be *labelled* with: the capability set the
|
|
85
|
+
* dashboard and CLI offer per machine OAuth client. Derived from the graph's
|
|
86
|
+
* own order so the label list reads the way the consent screen does.
|
|
87
|
+
*/
|
|
88
|
+
export const OAUTH_PRIMARY_SCOPES = Object.keys(OAUTH_SCOPE_GRAPH)
|
|
89
|
+
.filter(oauthScopeHasActions)
|
|
90
|
+
.filter((scope) => primaryScopeSet.has(scope));
|
|
91
|
+
// Derived action lists are emitted in `StatticActionSchema` order, so a
|
|
92
|
+
// credential's permissions read the same however the graph is authored and a
|
|
93
|
+
// reordered entry never churns the wire contract.
|
|
94
|
+
const ACTION_ORDER = new Map(StatticActionSchema.options.map((action, index) => [action, index]));
|
|
95
|
+
function actionsForScope(scope, seen) {
|
|
96
|
+
if (seen.has(scope))
|
|
97
|
+
return [];
|
|
98
|
+
seen.add(scope);
|
|
99
|
+
const entry = OAUTH_SCOPE_GRAPH[scope];
|
|
100
|
+
return [
|
|
101
|
+
...entry.actions,
|
|
102
|
+
...entry.covers
|
|
103
|
+
.filter(oauthScopeHasActions)
|
|
104
|
+
.flatMap((covered) => actionsForScope(covered, seen)),
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
/** Every action a scope grants, including the scopes it subsumes. */
|
|
108
|
+
export function oauthScopeActionsFor(scope) {
|
|
109
|
+
return [...new Set(actionsForScope(scope, new Set()))].toSorted((left, right) => (ACTION_ORDER.get(left) ?? 0) - (ACTION_ORDER.get(right) ?? 0));
|
|
110
|
+
}
|
|
111
|
+
/** Every action a set of scopes grants together. Unknown scopes grant nothing. */
|
|
112
|
+
export function oauthScopeActions(scopes) {
|
|
113
|
+
return [
|
|
114
|
+
...new Set((scopes ?? []).filter(oauthScopeHasActions).flatMap((scope) => oauthScopeActionsFor(scope))),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The primary scopes a set of allowed actions amounts to. `*` is every primary
|
|
119
|
+
* scope; anything else matches on a scope's own actions only.
|
|
120
|
+
*/
|
|
121
|
+
export function oauthScopesForActions(actions) {
|
|
122
|
+
const allowed = new Set(actions);
|
|
123
|
+
if (allowed.has("*"))
|
|
124
|
+
return [...OAUTH_PRIMARY_SCOPES];
|
|
125
|
+
return OAUTH_PRIMARY_SCOPES.filter((scope) => OAUTH_SCOPE_GRAPH[scope].actions.some((action) => allowed.has(action)));
|
|
126
|
+
}
|