@spacefast/common 0.0.26 → 0.2.1

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.
Files changed (302) hide show
  1. package/dist/agents/connect-targets.d.ts +6 -146
  2. package/dist/agents/connect-targets.js +63 -295
  3. package/dist/agents/private-key-oauth.d.ts +31 -1
  4. package/dist/agents/private-key-oauth.js +124 -33
  5. package/dist/agents/registry/core.d.ts +292 -0
  6. package/dist/agents/registry/core.js +1388 -0
  7. package/dist/agents/registry/deeplink-probes.d.ts +23 -0
  8. package/dist/agents/registry/deeplink-probes.js +18 -0
  9. package/dist/agents/registry/node.d.ts +56 -0
  10. package/dist/agents/registry/node.js +339 -0
  11. package/dist/brand-assets-build.js +1 -2
  12. package/dist/brand-assets.js +4 -7
  13. package/dist/brand.d.ts +17 -0
  14. package/dist/brand.js +24 -4
  15. package/dist/config/domains.d.ts +55 -28
  16. package/dist/config/domains.js +85 -41
  17. package/dist/config/index.js +1 -2
  18. package/dist/contracts/abuse.js +9 -24
  19. package/dist/contracts/access-profiles.d.ts +86 -0
  20. package/dist/contracts/access-profiles.js +89 -0
  21. package/dist/contracts/access.d.ts +21 -27
  22. package/dist/contracts/access.js +33 -64
  23. package/dist/contracts/activity.d.ts +18 -1
  24. package/dist/contracts/activity.js +70 -26
  25. package/dist/contracts/analytics.js +8 -10
  26. package/dist/contracts/api-keys.d.ts +77 -52
  27. package/dist/contracts/api-keys.js +44 -24
  28. package/dist/contracts/application-journal.d.ts +216 -0
  29. package/dist/contracts/application-journal.js +167 -0
  30. package/dist/contracts/auth.d.ts +90 -17
  31. package/dist/contracts/auth.js +86 -17
  32. package/dist/contracts/beta.d.ts +9 -4
  33. package/dist/contracts/beta.js +20 -16
  34. package/dist/contracts/billing.js +7 -11
  35. package/dist/contracts/bootstrap.d.ts +791 -0
  36. package/dist/contracts/bootstrap.js +51 -0
  37. package/dist/contracts/builds.d.ts +186 -7
  38. package/dist/contracts/builds.js +75 -21
  39. package/dist/contracts/channels.d.ts +43 -0
  40. package/dist/contracts/channels.js +25 -9
  41. package/dist/contracts/cli.d.ts +7 -0
  42. package/dist/contracts/cli.js +6 -0
  43. package/dist/contracts/collab-public.d.ts +1 -1
  44. package/dist/contracts/collab-public.js +5 -8
  45. package/dist/contracts/comments.d.ts +45 -35
  46. package/dist/contracts/comments.js +107 -77
  47. package/dist/contracts/commerce.d.ts +165 -0
  48. package/dist/contracts/commerce.js +146 -0
  49. package/dist/contracts/common.d.ts +3 -3
  50. package/dist/contracts/common.js +18 -29
  51. package/dist/contracts/content-contract-verification.d.ts +521 -0
  52. package/dist/contracts/content-contract-verification.js +320 -0
  53. package/dist/contracts/content-platform-fixture.d.ts +1278 -0
  54. package/dist/contracts/content-platform-fixture.js +44 -0
  55. package/dist/contracts/content-program.d.ts +994 -0
  56. package/dist/contracts/content-program.js +658 -0
  57. package/dist/contracts/content-sync.d.ts +290 -0
  58. package/dist/contracts/content-sync.js +167 -0
  59. package/dist/contracts/content.d.ts +432 -0
  60. package/dist/contracts/content.js +303 -0
  61. package/dist/contracts/continuation.d.ts +17 -1
  62. package/dist/contracts/continuation.js +23 -23
  63. package/dist/contracts/countries.js +3 -4
  64. package/dist/contracts/crons.d.ts +17 -0
  65. package/dist/contracts/crons.js +33 -15
  66. package/dist/contracts/dashboard-prefs.d.ts +56 -0
  67. package/dist/contracts/dashboard-prefs.js +51 -0
  68. package/dist/contracts/device-auth.d.ts +234 -37
  69. package/dist/contracts/device-auth.js +267 -53
  70. package/dist/contracts/docs.d.ts +6 -10
  71. package/dist/contracts/docs.js +5 -13
  72. package/dist/contracts/domains.d.ts +499 -102
  73. package/dist/contracts/domains.js +169 -58
  74. package/dist/contracts/email-preferences.d.ts +3 -3
  75. package/dist/contracts/email-preferences.js +6 -7
  76. package/dist/contracts/enums.d.ts +26 -26
  77. package/dist/contracts/enums.js +61 -54
  78. package/dist/contracts/error-code-meta.d.ts +269 -7
  79. package/dist/contracts/error-code-meta.js +80 -5
  80. package/dist/contracts/error-codes.d.ts +5 -5
  81. package/dist/contracts/error-codes.js +78 -16
  82. package/dist/contracts/events.d.ts +100 -20
  83. package/dist/contracts/events.js +107 -20
  84. package/dist/contracts/execution.d.ts +47 -66
  85. package/dist/contracts/execution.js +51 -64
  86. package/dist/contracts/feature-lifecycle.d.ts +70 -14
  87. package/dist/contracts/feature-lifecycle.js +86 -15
  88. package/dist/contracts/features.d.ts +100 -37
  89. package/dist/contracts/features.js +21 -27
  90. package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
  91. package/dist/contracts/frame-session.d.ts +192 -0
  92. package/dist/contracts/frame-session.js +164 -0
  93. package/dist/contracts/functions.d.ts +218 -211
  94. package/dist/contracts/functions.js +273 -260
  95. package/dist/contracts/grant-copy.d.ts +43 -0
  96. package/dist/contracts/grant-copy.js +44 -0
  97. package/dist/contracts/grants.d.ts +64 -56
  98. package/dist/contracts/grants.js +124 -23
  99. package/dist/contracts/ids.d.ts +4 -1
  100. package/dist/contracts/ids.js +4 -1
  101. package/dist/contracts/internal.d.ts +5 -4
  102. package/dist/contracts/internal.js +12 -3
  103. package/dist/contracts/mcp.d.ts +17 -0
  104. package/dist/contracts/mcp.js +23 -0
  105. package/dist/contracts/me.d.ts +6 -1
  106. package/dist/contracts/me.js +12 -6
  107. package/dist/contracts/notifications.d.ts +27 -29
  108. package/dist/contracts/notifications.js +9 -4
  109. package/dist/contracts/oauth-resources.d.ts +112 -10
  110. package/dist/contracts/oauth-resources.js +116 -11
  111. package/dist/contracts/oauth-scope-actions.d.ts +90 -0
  112. package/dist/contracts/oauth-scope-actions.js +126 -0
  113. package/dist/contracts/operations.d.ts +27 -4
  114. package/dist/contracts/operations.js +11 -5
  115. package/dist/contracts/pages.d.ts +29 -5
  116. package/dist/contracts/pages.js +22 -5
  117. package/dist/contracts/partner-notifications.d.ts +3 -0
  118. package/dist/contracts/partner-notifications.js +65 -0
  119. package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
  120. package/dist/contracts/{platform.js → partner.js} +27 -40
  121. package/dist/contracts/plan-policy.d.ts +1 -1
  122. package/dist/contracts/principal-assertion.d.ts +43 -0
  123. package/dist/contracts/principal-assertion.js +67 -0
  124. package/dist/contracts/principals.d.ts +73 -0
  125. package/dist/contracts/principals.js +59 -0
  126. package/dist/contracts/privacy.d.ts +11 -0
  127. package/dist/contracts/privacy.js +17 -0
  128. package/dist/contracts/problem-document.js +3 -4
  129. package/dist/contracts/publish-archive.d.ts +116 -18
  130. package/dist/contracts/publish-archive.js +6 -3
  131. package/dist/contracts/push-new.d.ts +4 -4
  132. package/dist/contracts/quotas.js +3 -3
  133. package/dist/contracts/realtime.d.ts +52 -0
  134. package/dist/contracts/realtime.js +54 -0
  135. package/dist/contracts/repository-connections.d.ts +1 -1
  136. package/dist/contracts/repository-connections.js +6 -2
  137. package/dist/contracts/resources.d.ts +105 -14
  138. package/dist/contracts/resources.js +145 -21
  139. package/dist/contracts/route-inventory.d.ts +358 -0
  140. package/dist/contracts/route-inventory.js +141 -0
  141. package/dist/contracts/runtime-api.d.ts +112 -35
  142. package/dist/contracts/runtime-api.js +86 -66
  143. package/dist/contracts/runtime-app.d.ts +11 -21
  144. package/dist/contracts/runtime-app.js +39 -24
  145. package/dist/contracts/runtime-components.d.ts +143 -0
  146. package/dist/contracts/runtime-components.js +199 -0
  147. package/dist/contracts/runtime-db.d.ts +45 -19
  148. package/dist/contracts/runtime-db.js +85 -20
  149. package/dist/contracts/runtime-purge.js +3 -5
  150. package/dist/contracts/runtime-services.d.ts +43 -75
  151. package/dist/contracts/runtime-services.js +29 -49
  152. package/dist/contracts/runtime-storage.d.ts +14 -14
  153. package/dist/contracts/runtime-storage.js +28 -13
  154. package/dist/contracts/sf-config-v1.d.ts +14 -18
  155. package/dist/contracts/slugs.js +13 -4
  156. package/dist/contracts/space-config.d.ts +235 -28
  157. package/dist/contracts/space-config.js +246 -91
  158. package/dist/contracts/spaces.d.ts +360 -255
  159. package/dist/contracts/spaces.js +190 -122
  160. package/dist/contracts/superadmin-activity.d.ts +3 -43
  161. package/dist/contracts/superadmin-activity.js +6 -30
  162. package/dist/contracts/superadmin-emails.d.ts +1 -0
  163. package/dist/contracts/superadmin-emails.js +17 -1
  164. package/dist/contracts/superadmin-runtime.d.ts +199 -0
  165. package/dist/contracts/superadmin-runtime.js +141 -0
  166. package/dist/contracts/superadmin-search.d.ts +22 -2
  167. package/dist/contracts/superadmin-search.js +14 -6
  168. package/dist/contracts/superadmin-spaces.d.ts +435 -186
  169. package/dist/contracts/superadmin-spaces.js +131 -25
  170. package/dist/contracts/superadmin-teams.d.ts +3 -0
  171. package/dist/contracts/superadmin-teams.js +1 -2
  172. package/dist/contracts/superadmin-tenants.d.ts +627 -6
  173. package/dist/contracts/superadmin-tenants.js +32 -7
  174. package/dist/contracts/superadmin.d.ts +98 -16
  175. package/dist/contracts/superadmin.js +63 -10
  176. package/dist/contracts/tags.d.ts +85 -58
  177. package/dist/contracts/tags.js +44 -34
  178. package/dist/contracts/teams.d.ts +72 -9
  179. package/dist/contracts/teams.js +84 -25
  180. package/dist/contracts/tenants.d.ts +135 -0
  181. package/dist/contracts/tenants.js +120 -0
  182. package/dist/contracts/test-triggers.d.ts +70 -0
  183. package/dist/contracts/test-triggers.js +116 -0
  184. package/dist/contracts/theme-json.js +3 -8
  185. package/dist/contracts/transfers.d.ts +1 -0
  186. package/dist/contracts/transfers.js +1 -0
  187. package/dist/contracts/usage.d.ts +209 -0
  188. package/dist/contracts/usage.js +124 -12
  189. package/dist/contracts/variables.d.ts +2 -2
  190. package/dist/contracts/variables.js +9 -13
  191. package/dist/contracts/webhooks.d.ts +13 -5
  192. package/dist/contracts/webhooks.js +3 -1
  193. package/dist/contracts/zero.d.ts +57 -64
  194. package/dist/contracts/zero.js +68 -66
  195. package/dist/dashboard-paths/index.d.ts +24 -21
  196. package/dist/dashboard-paths/index.js +35 -47
  197. package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
  198. package/dist/dashboard-paths/route-reservations.generated.js +36 -0
  199. package/dist/docs/agent-arrival.d.ts +92 -0
  200. package/dist/docs/agent-arrival.js +227 -0
  201. package/dist/docs/agent-output-policy.d.ts +6 -0
  202. package/dist/docs/agent-output-policy.js +22 -0
  203. package/dist/docs/agent-prose.d.ts +11 -17
  204. package/dist/docs/agent-prose.js +62 -37
  205. package/dist/docs/agent-setup.d.ts +72 -41
  206. package/dist/docs/agent-setup.js +336 -436
  207. package/dist/docs/catalog.d.ts +147 -89
  208. package/dist/docs/catalog.js +157 -42
  209. package/dist/docs/error-docs.d.ts +2098 -1
  210. package/dist/docs/error-docs.js +281 -16
  211. package/dist/docs/index-build.d.ts +0 -1
  212. package/dist/docs/index-build.js +2 -3
  213. package/dist/docs/page-context-prompt.d.ts +77 -0
  214. package/dist/docs/page-context-prompt.js +131 -0
  215. package/dist/docs/reference-urls.d.ts +46 -0
  216. package/dist/docs/reference-urls.js +79 -0
  217. package/dist/docs/search.d.ts +6 -8
  218. package/dist/docs/search.js +10 -13
  219. package/dist/docs/skill-distribution.d.ts +4 -1
  220. package/dist/docs/skill-distribution.js +10 -5
  221. package/dist/docs/skills.d.ts +117 -117
  222. package/dist/docs/skills.js +120 -72
  223. package/dist/docs/start-prompts.d.ts +45 -0
  224. package/dist/docs/start-prompts.js +62 -0
  225. package/dist/domain-exploration.js +9 -13
  226. package/dist/og-template.d.ts +56 -0
  227. package/dist/og-template.js +56 -0
  228. package/dist/slug-policy/index.js +5 -11
  229. package/dist/utils/browser-credential.d.ts +13 -6
  230. package/dist/utils/browser-credential.js +14 -7
  231. package/dist/utils/build-settings.d.ts +16 -0
  232. package/dist/utils/build-settings.js +63 -17
  233. package/dist/utils/canonical-json.d.ts +3 -5
  234. package/dist/utils/canonical-json.js +3 -5
  235. package/dist/utils/cast-transport.d.ts +5 -17
  236. package/dist/utils/cast-transport.js +6 -19
  237. package/dist/utils/claim-token.js +1 -2
  238. package/dist/utils/comment-avatars.js +4 -6
  239. package/dist/utils/concurrency.js +2 -3
  240. package/dist/utils/content-type.d.ts +7 -6
  241. package/dist/utils/content-type.js +73 -51
  242. package/dist/utils/credential-policy.d.ts +50 -6
  243. package/dist/utils/credential-policy.js +123 -57
  244. package/dist/utils/egress-policy.fixtures.json +1 -1
  245. package/dist/utils/generate-space-name.d.ts +3 -8
  246. package/dist/utils/generate-space-name.js +3 -8
  247. package/dist/utils/grants.d.ts +0 -1
  248. package/dist/utils/grants.js +4 -7
  249. package/dist/utils/gravatar.d.ts +2 -4
  250. package/dist/utils/gravatar.js +6 -12
  251. package/dist/utils/id-hints.js +14 -23
  252. package/dist/utils/idempotency.d.ts +3 -3
  253. package/dist/utils/idempotency.js +6 -7
  254. package/dist/utils/local-space-state.d.ts +15 -15
  255. package/dist/utils/local-space-state.js +34 -23
  256. package/dist/utils/oauth-signed-query.d.ts +3 -5
  257. package/dist/utils/oauth-signed-query.js +6 -9
  258. package/dist/utils/one-shot-replay.d.ts +3 -5
  259. package/dist/utils/one-shot-replay.js +3 -5
  260. package/dist/utils/page-colors.d.ts +4 -10
  261. package/dist/utils/page-colors.js +11 -35
  262. package/dist/utils/page-fonts.js +6 -11
  263. package/dist/utils/page-preview.d.ts +0 -1
  264. package/dist/utils/page-preview.js +0 -1
  265. package/dist/utils/pages.d.ts +22 -11
  266. package/dist/utils/pages.js +70 -30
  267. package/dist/utils/privacy-regions.d.ts +19 -0
  268. package/dist/utils/privacy-regions.js +91 -0
  269. package/dist/utils/publish-form-data.d.ts +4 -5
  270. package/dist/utils/publish-form-data.js +2 -3
  271. package/dist/utils/publish-policy.d.ts +10 -23
  272. package/dist/utils/publish-policy.js +63 -116
  273. package/dist/utils/query-client.d.ts +2 -0
  274. package/dist/utils/query-client.js +10 -1
  275. package/dist/utils/runtime-paths.d.ts +4 -4
  276. package/dist/utils/runtime-paths.js +6 -8
  277. package/dist/utils/runtime-upload.d.ts +4 -0
  278. package/dist/utils/runtime-upload.js +5 -0
  279. package/dist/utils/secure-local-file.d.ts +3 -3
  280. package/dist/utils/secure-local-file.js +18 -24
  281. package/dist/utils/space-config.d.ts +11 -14
  282. package/dist/utils/space-config.js +10 -16
  283. package/dist/utils/static-runtime-policy.d.ts +5 -8
  284. package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
  285. package/dist/utils/static-runtime-policy.generated.js +70 -0
  286. package/dist/utils/static-runtime-policy.js +17 -84
  287. package/dist/utils/storage-policy.js +1 -2
  288. package/dist/utils/upload-session.js +8 -14
  289. package/dist/utils/version-path.js +11 -19
  290. package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
  291. package/dist/utils/wpcom-auth-redirects.js +1 -4
  292. package/dist/vocabulary.d.ts +7 -7
  293. package/dist/vocabulary.js +30 -16
  294. package/package.json +14 -2
  295. package/dist/agents/client-registry.d.ts +0 -22
  296. package/dist/agents/client-registry.js +0 -41
  297. package/dist/docs/agent-handoff-document.d.ts +0 -15
  298. package/dist/docs/agent-handoff-document.js +0 -180
  299. package/dist/docs/agent-solutions.d.ts +0 -110
  300. package/dist/docs/agent-solutions.js +0 -183
  301. package/dist/utils/query-keys.d.ts +0 -84
  302. 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
- notifications: z.ZodArray<z.ZodObject<{
43
- id: z.ZodString;
44
- kind: z.ZodEnum<{
45
- "comment.created": "comment.created";
46
- "comment.replied": "comment.replied";
47
- "thread.archived": "thread.archived";
48
- "thread.unarchived": "thread.unarchived";
49
- mention: "mention";
50
- }>;
51
- teamId: z.ZodNullable<z.ZodString>;
52
- spaceId: z.ZodNullable<z.ZodString>;
53
- threadId: z.ZodNullable<z.ZodString>;
54
- title: z.ZodString;
55
- body: z.ZodNullable<z.ZodString>;
56
- actor: z.ZodObject<{
57
- name: z.ZodNullable<z.ZodString>;
58
- avatarUrl: z.ZodNullable<z.ZodString>;
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.stringbool().optional().default(false),
31
+ unread: z
32
+ .stringbool()
33
+ .optional()
34
+ .default(false)
35
+ .describe("Return only notifications that have not been read yet."),
32
36
  });
33
- export const notificationListResponseSchema = dataEnvelope(z.object({
34
- notifications: z.array(notificationSchema),
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 ["mcp:tools", "teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write"];
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 so a resource
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 agent account.
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 ["mcp:tools", "teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "offline_access"];
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,110 @@ 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 ["mcp:tools", "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", "mcp:tools"];
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
+ export declare const OAUTH_SCOPE_RISK_TINTS: readonly ["neutral", "warning", "critical"];
45
+ export type OAuthScopeRiskTint = (typeof OAUTH_SCOPE_RISK_TINTS)[number];
46
+ export type OAuthScopeId = keyof typeof OAUTH_SCOPE_DESCRIPTIONS;
47
+ export type OAuthScopeCopy = {
48
+ label: string;
49
+ description: string;
50
+ riskTint: OAuthScopeRiskTint;
51
+ };
52
+ /**
53
+ * Human-facing permission copy shared by every authorization surface. Keep raw
54
+ * OAuth scope ids in developer views only; consent, approvals, ledgers, CLI
55
+ * prompts, and email should all render this vocabulary.
56
+ */
57
+ export declare const OAUTH_SCOPE_COPY: {
58
+ readonly openid: {
59
+ readonly label: "Identify your account";
60
+ readonly description: "Identify the signed-in account.";
61
+ readonly riskTint: "neutral";
62
+ };
63
+ readonly profile: {
64
+ readonly label: "Read your profile";
65
+ readonly description: "Read the signed-in account's basic profile.";
66
+ readonly riskTint: "neutral";
67
+ };
68
+ readonly email: {
69
+ readonly label: "Read your email address";
70
+ readonly description: "Read the signed-in account's email address.";
71
+ readonly riskTint: "neutral";
72
+ };
73
+ readonly offline_access: {
74
+ readonly label: "Stay connected";
75
+ readonly description: "Refresh access without another interactive sign-in.";
76
+ readonly riskTint: "warning";
77
+ };
78
+ readonly "teams:read": {
79
+ readonly label: "Read your teams";
80
+ readonly description: "Read the teams the account belongs to.";
81
+ readonly riskTint: "neutral";
82
+ };
83
+ readonly "teams:create": {
84
+ readonly label: "Create teams";
85
+ readonly description: "Create teams.";
86
+ readonly riskTint: "warning";
87
+ };
88
+ readonly "spaces:read": {
89
+ readonly label: "Read your sites";
90
+ readonly description: "Read spaces, versions, and build status.";
91
+ readonly riskTint: "neutral";
92
+ };
93
+ readonly "spaces:write": {
94
+ readonly label: "Create and update your sites";
95
+ readonly description: "Create and update spaces and their settings.";
96
+ readonly riskTint: "warning";
97
+ };
98
+ readonly "spaces:rename": {
99
+ readonly label: "Rename your sites";
100
+ readonly description: "Rename space slugs and managed addresses.";
101
+ readonly riskTint: "warning";
102
+ };
103
+ readonly "publish:write": {
104
+ readonly label: "Publish and manage versions";
105
+ readonly description: "Publish new immutable versions.";
106
+ readonly riskTint: "warning";
107
+ };
108
+ readonly "spaces:publish": {
109
+ readonly label: "Publish new versions of your sites";
110
+ readonly description: "Publish a version to an existing space.";
111
+ readonly riskTint: "warning";
112
+ };
113
+ readonly "builds:trigger": {
114
+ readonly label: "Start builds";
115
+ readonly description: "Start a build for an existing version.";
116
+ readonly riskTint: "warning";
117
+ };
118
+ readonly "domains:read": {
119
+ readonly label: "Read your domains";
120
+ readonly description: "Read domain inventory and DNS diagnostics.";
121
+ readonly riskTint: "neutral";
122
+ };
123
+ readonly "domains:write": {
124
+ readonly label: "Manage domains and DNS";
125
+ readonly description: "Attach, verify, and mutate domains and DNS records.";
126
+ readonly riskTint: "critical";
127
+ };
128
+ };
129
+ export declare function oauthScopeCopy(scope: string): OAuthScopeCopy;
28
130
  export declare const OAUTH_RESOURCE_DEFINITIONS: {
29
131
  readonly api: {
30
132
  readonly key: "api";
@@ -36,14 +138,14 @@ export declare const OAUTH_RESOURCE_DEFINITIONS: {
36
138
  readonly key: "mcp";
37
139
  readonly name: "Spacefast MCP";
38
140
  readonly accessTokenTtlSeconds: number;
39
- readonly allowedScopes: readonly ["mcp:tools", "teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "offline_access"];
141
+ readonly allowedScopes: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write", "offline_access"];
40
142
  };
41
143
  };
42
144
  /** Resource identifier for the public API: `https://api.<domain>/v1`. */
43
145
  export declare function oauthApiResourceUrl(apiOrigin: string | URL): string;
44
146
  /**
45
147
  * Resource identifier for hosted MCP: the mcp origin itself, in RFC 8707
46
- * canonical form (lowercase scheme/host, no trailing slash) this is the
148
+ * canonical form (lowercase scheme/host, no trailing slash). This is the
47
149
  * exact string MCP clients send as the `resource` parameter.
48
150
  */
49
151
  export declare function oauthMcpResourceUrl(mcpOrigin: string | URL): string;
@@ -51,7 +153,7 @@ export declare function normalizeOAuthResourceIdentifier(resource: string): stri
51
153
  /**
52
154
  * Derive the mcp origin from a configured api origin (`api.X` → `mcp.X`).
53
155
  * Returns null when the api host doesn't follow the `api.` convention
54
- * (loopback dev, docker test hosts) callers fall back to the api origin.
156
+ * (loopback dev, docker test hosts). Callers fall back to the api origin.
55
157
  */
56
158
  export declare function oauthMcpOriginFromApiOrigin(apiOrigin: string | URL): string | null;
57
159
  /**
@@ -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
- const OAUTH_SHARED_API_RESOURCE_SCOPES = [
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
- export const OAUTH_MCP_RESOURCE_SCOPES = [
23
- OAUTH_MCP_TOOL_SCOPE,
24
- ...OAUTH_SHARED_API_RESOURCE_SCOPES,
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 so a resource
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 agent account.
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,109 @@ 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
+ export const OAUTH_SCOPE_RISK_TINTS = ["neutral", "warning", "critical"];
77
+ /**
78
+ * Human-facing permission copy shared by every authorization surface. Keep raw
79
+ * OAuth scope ids in developer views only; consent, approvals, ledgers, CLI
80
+ * prompts, and email should all render this vocabulary.
81
+ */
82
+ export const OAUTH_SCOPE_COPY = {
83
+ openid: {
84
+ label: "Identify your account",
85
+ description: OAUTH_SCOPE_DESCRIPTIONS.openid,
86
+ riskTint: "neutral",
87
+ },
88
+ profile: {
89
+ label: "Read your profile",
90
+ description: OAUTH_SCOPE_DESCRIPTIONS.profile,
91
+ riskTint: "neutral",
92
+ },
93
+ email: {
94
+ label: "Read your email address",
95
+ description: OAUTH_SCOPE_DESCRIPTIONS.email,
96
+ riskTint: "neutral",
97
+ },
98
+ offline_access: {
99
+ label: "Stay connected",
100
+ description: OAUTH_SCOPE_DESCRIPTIONS.offline_access,
101
+ riskTint: "warning",
102
+ },
103
+ "teams:read": {
104
+ label: "Read your teams",
105
+ description: OAUTH_SCOPE_DESCRIPTIONS["teams:read"],
106
+ riskTint: "neutral",
107
+ },
108
+ "teams:create": {
109
+ label: "Create teams",
110
+ description: OAUTH_SCOPE_DESCRIPTIONS["teams:create"],
111
+ riskTint: "warning",
112
+ },
113
+ "spaces:read": {
114
+ label: "Read your sites",
115
+ description: OAUTH_SCOPE_DESCRIPTIONS["spaces:read"],
116
+ riskTint: "neutral",
117
+ },
118
+ "spaces:write": {
119
+ label: "Create and update your sites",
120
+ description: OAUTH_SCOPE_DESCRIPTIONS["spaces:write"],
121
+ riskTint: "warning",
122
+ },
123
+ "spaces:rename": {
124
+ label: "Rename your sites",
125
+ description: OAUTH_SCOPE_DESCRIPTIONS["spaces:rename"],
126
+ riskTint: "warning",
127
+ },
128
+ "publish:write": {
129
+ label: "Publish and manage versions",
130
+ description: OAUTH_SCOPE_DESCRIPTIONS["publish:write"],
131
+ riskTint: "warning",
132
+ },
133
+ "spaces:publish": {
134
+ label: "Publish new versions of your sites",
135
+ description: OAUTH_SCOPE_DESCRIPTIONS["spaces:publish"],
136
+ riskTint: "warning",
137
+ },
138
+ "builds:trigger": {
139
+ label: "Start builds",
140
+ description: OAUTH_SCOPE_DESCRIPTIONS["builds:trigger"],
141
+ riskTint: "warning",
142
+ },
143
+ "domains:read": {
144
+ label: "Read your domains",
145
+ description: OAUTH_SCOPE_DESCRIPTIONS["domains:read"],
146
+ riskTint: "neutral",
147
+ },
148
+ "domains:write": {
149
+ label: "Manage domains and DNS",
150
+ description: OAUTH_SCOPE_DESCRIPTIONS["domains:write"],
151
+ riskTint: "critical",
152
+ },
153
+ };
154
+ export function oauthScopeCopy(scope) {
155
+ const match = Object.entries(OAUTH_SCOPE_COPY).find(([knownScope]) => knownScope === scope);
156
+ return (match?.[1] ?? {
157
+ label: "Additional Spacefast access",
158
+ description: "Review this permission in Spacefast before you approve it.",
159
+ riskTint: "critical",
160
+ });
161
+ }
57
162
  export const OAUTH_RESOURCE_DEFINITIONS = {
58
163
  api: {
59
164
  key: "api",
@@ -74,7 +179,7 @@ export function oauthApiResourceUrl(apiOrigin) {
74
179
  }
75
180
  /**
76
181
  * Resource identifier for hosted MCP: the mcp origin itself, in RFC 8707
77
- * canonical form (lowercase scheme/host, no trailing slash) this is the
182
+ * canonical form (lowercase scheme/host, no trailing slash). This is the
78
183
  * exact string MCP clients send as the `resource` parameter.
79
184
  */
80
185
  export function oauthMcpResourceUrl(mcpOrigin) {
@@ -98,7 +203,7 @@ export function normalizeOAuthResourceIdentifier(resource) {
98
203
  /**
99
204
  * Derive the mcp origin from a configured api origin (`api.X` → `mcp.X`).
100
205
  * Returns null when the api host doesn't follow the `api.` convention
101
- * (loopback dev, docker test hosts) callers fall back to the api origin.
206
+ * (loopback dev, docker test hosts). Callers fall back to the api origin.
102
207
  */
103
208
  export function oauthMcpOriginFromApiOrigin(apiOrigin) {
104
209
  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
+ }