@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.
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 +192 -7
  38. package/dist/contracts/builds.js +84 -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 +273 -7
  79. package/dist/contracts/error-code-meta.js +81 -5
  80. package/dist/contracts/error-codes.d.ts +5 -5
  81. package/dist/contracts/error-codes.js +79 -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 +121 -10
  110. package/dist/contracts/oauth-resources.js +130 -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 +2102 -1
  210. package/dist/docs/error-docs.js +285 -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
@@ -1,15 +1,19 @@
1
1
  import { z } from "zod";
2
2
  import { AGENT_HANDOFF_DECLINE_REASONS } from "../docs/agent-setup.js";
3
- import { ApiKeyPresetSchema, ApiKeySchema } from "./api-keys.js";
3
+ import { AccessProfileIdSchema, APPROVABLE_SCOPES, DEFAULT_ACCESS_PROFILE_ID, } from "./access-profiles.js";
4
+ import { ApiKeySchema } from "./api-keys.js";
4
5
  import { DeviceTeamScopeSchema } from "./device-team-scope.js";
5
6
  export { DeviceTeamScopeSchema } from "./device-team-scope.js";
6
- // Device authorization flow (the platform spec Credential Bootstrap):
7
- // `POST /v1/auth/device` starts the flow, `POST /v1/auth/device/poll` redeems
8
- // it. Device codes are bearer capabilities: they ride POST bodies only, are
9
- // never logged, and redeem exactly once. User codes are short display codes the
10
- // person types on the dashboard verification page; verification attempts are
11
- // rate-limited per caller and per code with lockout so user codes cannot be
12
- // brute-forced into approving an attacker's device.
7
+ // Device authorization flow (the platform spec Credential Bootstrap). Device
8
+ // codes are bearer capabilities: body-only, never logged, redeemed once. User
9
+ // code verification is rate-limited per caller and per code with lockout, so a
10
+ // user code cannot be brute-forced into approving an attacker's device.
11
+ // The one lifetime an interactive login grants a single tier sized to
12
+ // industry CLI/agent logins. The server (`grants.ts`) derives its TTL seconds
13
+ // from these, and the approval page renders the same numbers, so the consent
14
+ // screen can never state a lifetime the server won't honor.
15
+ export const INTERACTIVE_GRANT_TTL_DAYS = 30;
16
+ export const INTERACTIVE_GRANT_IDLE_DAYS = 7;
13
17
  export const DeviceAuthorizationStartRequestSchema = z
14
18
  .object({
15
19
  clientId: z
@@ -19,13 +23,7 @@ export const DeviceAuthorizationStartRequestSchema = z
19
23
  .max(255)
20
24
  .default("spacefast-cli")
21
25
  .describe("Requesting client identifier shown on the verification page."),
22
- scope: z
23
- .string()
24
- .trim()
25
- .min(1)
26
- .max(4096)
27
- .optional()
28
- .describe("Requested access preset name. The approver chooses the final preset; this only seeds the verification page default."),
26
+ access: AccessProfileIdSchema.default(DEFAULT_ACCESS_PROFILE_ID).describe("Access profile the device requests. One word with a server-owned meaning; the approver can narrow the resulting scopes on the verification page but never widen them."),
29
27
  claim: z
30
28
  .object({
31
29
  spaceId: z
@@ -78,9 +76,20 @@ export const DeviceAuthorizationPollRequestSchema = z.object({
78
76
  export const DeviceAuthorizationStatusSchema = z
79
77
  .enum(["pending", "approved", "denied", "expired", "consumed"])
80
78
  .describe("Device authorization state. `approved` carries the one-time API key exactly once, then the record is `consumed`.");
79
+ export const DeviceGrantedAccessSchema = z
80
+ .object({
81
+ profile: AccessProfileIdSchema.nullable().describe("Access profile the granted scopes exactly match, or null for a customized grant."),
82
+ scopes: z
83
+ .array(z.enum(APPROVABLE_SCOPES))
84
+ .min(1)
85
+ .describe("Exact scopes the approver granted. The one authoritative description."),
86
+ teams: DeviceTeamScopeSchema.describe("Team access the approver granted."),
87
+ })
88
+ .strict();
81
89
  export const DeviceAuthorizationPollResponseSchema = z.object({
82
90
  status: DeviceAuthorizationStatusSchema,
83
91
  apiKey: ApiKeySchema.optional().describe("The minted API key including its one-time `secret`. Present only on the first poll after approval."),
92
+ access: DeviceGrantedAccessSchema.optional().describe("What was granted, in the words the approval page used. Present alongside `apiKey`."),
84
93
  claimedSpaceId: z
85
94
  .string()
86
95
  .nullable()
@@ -88,7 +97,7 @@ export const DeviceAuthorizationPollResponseSchema = z.object({
88
97
  .describe("Space claimed during approval, when the device flow was started by `sf spaces claim`."),
89
98
  });
90
99
  // Verification-page surface (`GET /v1/auth/device?user_code=…`). Returns
91
- // requester context only never the device code (it is the bearer capability).
100
+ // requester context only, never the device code.
92
101
  export const DeviceAuthorizationVerifyQuerySchema = z.object({
93
102
  user_code: z
94
103
  .string()
@@ -103,7 +112,15 @@ export const DeviceAuthorizationVerifyResponseSchema = z.object({
103
112
  .string()
104
113
  .nullable()
105
114
  .describe("Requesting client identifier recorded at device start."),
106
- scope: z.string().nullable().describe("Access preset the device requested at start, if any."),
115
+ requestedAccess: z
116
+ .object({
117
+ profile: AccessProfileIdSchema.nullable().describe("Access profile the requested scopes exactly match, if any."),
118
+ scopes: z
119
+ .array(z.enum(APPROVABLE_SCOPES))
120
+ .describe("Scopes the device requested. The approval page renders exactly these."),
121
+ })
122
+ .strict()
123
+ .describe("Server-resolved access request. Ids only; copy is derived client-side."),
107
124
  origin: z
108
125
  .string()
109
126
  .nullable()
@@ -122,12 +139,18 @@ export const DeviceAuthorizationVerifyResponseSchema = z.object({
122
139
  .nullable()
123
140
  .describe("Explicit claim handoff attached to this device authorization, if any."),
124
141
  });
125
- // Approval intent (`POST /v1/auth/device/approve`): the approver chooses the
126
- // team scope and preset. If the device start request carried a claim handoff,
127
- // approval also claims that anonymous space into the explicit destination team after the approval CAS
128
- // wins. The intent persists server-side and the poll mints from it; the chosen
129
- // preset's compiled policy must be a subset of the approver's effective
130
- // team-role policy.
142
+ // Approval intent (`POST /v1/auth/device/approve`). The intent persists
143
+ // server-side and the poll mints from it.
144
+ //
145
+ // SCOPES are the wire vocabulary of the grant: the approver confirms (or
146
+ // narrows) the same human-readable list that OAuth consent, the elevation
147
+ // diff, and the ledger render. Access profiles are request intent only and are
148
+ // never submitted here. Approved scopes must be a subset of the requested
149
+ // scopes; authority is the granted scopes' actions bounded per team by the
150
+ // holder's LIVE role at request time, so approval itself never fails on role.
151
+ // A claim handoff is claimed into `claimTeamId` only after the approval CAS
152
+ // wins.
153
+ export const DeviceAuthorizationApprovalScopeSchema = z.enum(APPROVABLE_SCOPES);
131
154
  export const DeviceAuthorizationApproveRequestSchema = z
132
155
  .object({
133
156
  userCode: z
@@ -142,11 +165,14 @@ export const DeviceAuthorizationApproveRequestSchema = z
142
165
  .min(1)
143
166
  .optional()
144
167
  .describe("Explicit destination team for a claim handoff. Required when the flow carries a claim."),
145
- preset: ApiKeyPresetSchema.describe("Policy preset for the minted key. Its compiled policy must be a subset of the approver's team-role policy."),
168
+ scopes: z
169
+ .array(DeviceAuthorizationApprovalScopeSchema)
170
+ .min(1)
171
+ .describe("OAuth scopes the approver granted — a subset of the scopes the device requested. Authority is these scopes' actions, bounded per team by the holder's live role on every request."),
146
172
  agentContinuation: z
147
173
  .boolean()
148
174
  .optional()
149
- .describe("Applies when the device flow carries an anonymous-space claim: keep the publishing agent authorized after the claim (default false unless explicitly granted) via the one-time claim-token exchange."),
175
+ .describe("Applies when the device flow carries an anonymous-space claim. Keeps the publishing agent authorized after the claim through the one-time claim-token exchange. Defaults to false."),
150
176
  })
151
177
  .strict();
152
178
  export const DeviceAuthorizationApproveResponseSchema = z
@@ -170,31 +196,187 @@ export const DeviceAuthorizationDenyResponseSchema = z.object({
170
196
  status: z.literal("denied").describe("The device authorization is denied."),
171
197
  });
172
198
  export const AGENT_HANDOFF_CLIENT_TARGETS = ["claude-code", "codex", "cursor", "vscode"];
199
+ export const PAGE_CONTEXT_HANDOFF_TARGETS = [
200
+ "any",
201
+ "v0",
202
+ "chatgpt",
203
+ "claude",
204
+ "t3",
205
+ "scira",
206
+ "cursor",
207
+ ];
208
+ export const AGENT_HANDOFF_TARGETS = [
209
+ "claude-code",
210
+ "codex",
211
+ "cursor",
212
+ "vscode",
213
+ "any",
214
+ "v0",
215
+ "chatgpt",
216
+ "claude",
217
+ "t3",
218
+ "scira",
219
+ ];
220
+ export function isAgentHandoffClientTarget(value) {
221
+ return AGENT_HANDOFF_CLIENT_TARGETS.some((target) => target === value);
222
+ }
223
+ export function isPageContextHandoffTarget(value) {
224
+ return PAGE_CONTEXT_HANDOFF_TARGETS.some((target) => target === value);
225
+ }
226
+ export const AGENT_HANDOFF_CLIENT_TARGET_LABELS = {
227
+ "claude-code": "Claude Code",
228
+ codex: "Codex",
229
+ cursor: "Cursor",
230
+ vscode: "VS Code",
231
+ // The target for a handoff copied without choosing an agent; the label reads
232
+ // naturally in the prompt's "Connect your agent privately" heading.
233
+ any: "your agent",
234
+ v0: "v0",
235
+ chatgpt: "ChatGPT",
236
+ claude: "Claude",
237
+ t3: "T3 Chat",
238
+ scira: "Scira",
239
+ };
240
+ /**
241
+ * Handoff purposes that name a subject: a Space to publish to, or the dashboard
242
+ * page the agent was launched from. Both are minted by a signed-in dashboard
243
+ * session, both appear in the team ledger, and both redeem for a credential.
244
+ */
245
+ export const AGENT_HANDOFF_SUBJECT_KINDS = ["space", "page_context"];
246
+ /**
247
+ * Every handoff purpose, including `anonymous` — the signed-out /start handoff.
248
+ * It has no team, no Space, and no subject: its document is the public setup
249
+ * guide and it can never be redeemed. It exists so a visitor who has not signed
250
+ * up yet still gets told when their agent picked the prompt up, which is exactly
251
+ * the capability the retired connect beacon provided. Being subject-less is what
252
+ * keeps it out of team ledgers and out of the revoke-all sweep.
253
+ */
254
+ export const AGENT_HANDOFF_KINDS = [...AGENT_HANDOFF_SUBJECT_KINDS, "anonymous"];
255
+ /** Wire-visible ceiling on how long an anonymous handoff stays fetchable. */
256
+ export const ANONYMOUS_AGENT_HANDOFF_TTL_MS = 30 * 60_000;
257
+ export const AnonymousAgentHandoffSchema = z
258
+ .object({
259
+ kind: z.literal("anonymous").describe("Handoff purpose."),
260
+ id: z.string().min(1).describe("Non-secret handoff ledger identifier."),
261
+ url: z
262
+ .string()
263
+ .url()
264
+ .describe("Sensitive one-time handoff URL. The only response field carrying the bearer."),
265
+ expiresAt: z
266
+ .string()
267
+ .datetime()
268
+ .describe("Instant after which the handoff stops serving its document."),
269
+ })
270
+ .strict();
271
+ export const AnonymousAgentHandoffStatusSchema = z
272
+ .object({
273
+ id: z.string().min(1).describe("Non-secret handoff ledger identifier."),
274
+ expiresAt: z
275
+ .string()
276
+ .datetime()
277
+ .describe("Instant after which the handoff stops serving its document."),
278
+ firstFetchedAt: z
279
+ .string()
280
+ .datetime()
281
+ .nullable()
282
+ .describe("Instant the document was first fetched, or null while nothing has fetched it."),
283
+ lastFetchedAt: z
284
+ .string()
285
+ .datetime()
286
+ .nullable()
287
+ .describe("Instant the document was most recently fetched, if it was."),
288
+ fetchCount: z.number().int().nonnegative().describe("Number of document fetches recorded."),
289
+ })
290
+ .strict();
173
291
  export const AgentHandoffCreateRequestSchema = z
174
292
  .object({
175
- teamId: z.string().min(1).describe("Team that owns the selected space."),
176
- spaceId: z.string().min(1).describe("Finite space scope granted to the agent."),
293
+ kind: z
294
+ .enum(AGENT_HANDOFF_SUBJECT_KINDS)
295
+ .optional()
296
+ .describe("Handoff purpose. If absent, the purpose is `space`."),
297
+ teamId: z.string().min(1).describe("Team that owns the handoff."),
298
+ spaceId: z
299
+ .string()
300
+ .min(1)
301
+ .optional()
302
+ .describe("Space that the agent can manage. Use this field only for a `space` handoff."),
303
+ pagePath: z
304
+ .string()
305
+ .trim()
306
+ .startsWith("/")
307
+ .max(1024)
308
+ .optional()
309
+ .describe("Dashboard path that supplied the agent context. Use this field only for a `page_context` handoff."),
177
310
  clientTargetId: z
178
- .enum(AGENT_HANDOFF_CLIENT_TARGETS)
179
- .describe("CLI-redeemable client family the handoff is bound to."),
311
+ .enum(AGENT_HANDOFF_TARGETS)
312
+ .describe("Agent destination that receives the handoff prompt."),
180
313
  })
181
- .strict();
314
+ .strict()
315
+ .superRefine((value, context) => {
316
+ const kind = value.kind ?? "space";
317
+ if (kind === "space" && !isAgentHandoffClientTarget(value.clientTargetId)) {
318
+ context.addIssue({
319
+ code: "custom",
320
+ path: ["clientTargetId"],
321
+ message: "A space handoff requires a local agent client.",
322
+ });
323
+ }
324
+ if (kind === "space" && !value.spaceId) {
325
+ context.addIssue({
326
+ code: "custom",
327
+ path: ["spaceId"],
328
+ message: "A space handoff requires spaceId.",
329
+ });
330
+ }
331
+ if (kind === "space" && value.pagePath) {
332
+ context.addIssue({
333
+ code: "custom",
334
+ path: ["pagePath"],
335
+ message: "A space handoff cannot include pagePath.",
336
+ });
337
+ }
338
+ if (kind === "page_context" && !value.pagePath) {
339
+ context.addIssue({
340
+ code: "custom",
341
+ path: ["pagePath"],
342
+ message: "A page-context handoff requires pagePath.",
343
+ });
344
+ }
345
+ if (kind === "page_context" && value.spaceId) {
346
+ context.addIssue({
347
+ code: "custom",
348
+ path: ["spaceId"],
349
+ message: "A page-context handoff cannot include spaceId.",
350
+ });
351
+ }
352
+ });
182
353
  export const AgentHandoffCreateResponseSchema = z
183
354
  .object({
184
- id: z.string().min(1).describe("Opaque app-private handoff document identifier."),
355
+ kind: z.enum(AGENT_HANDOFF_SUBJECT_KINDS).describe("Handoff purpose."),
356
+ id: z.string().min(1).describe("Non-secret handoff ledger identifier."),
185
357
  url: z
186
358
  .string()
187
359
  .url()
188
- .describe("Sensitive one-time handoff URL. This is the only response field containing the browser credential."),
360
+ .describe("Sensitive one-time handoff URL. The only response field carrying the browser credential."),
189
361
  expiresAt: z
190
362
  .string()
191
363
  .datetime()
192
364
  .describe("Instant after which the handoff cannot be redeemed."),
193
- teamId: z.string().min(1).describe("Team that owns the selected space."),
194
- spaceId: z.string().min(1).describe("Finite space scope granted to the agent."),
365
+ teamId: z.string().min(1).describe("Team that owns the handoff."),
366
+ spaceId: z
367
+ .string()
368
+ .min(1)
369
+ .nullable()
370
+ .describe("Space that the agent can manage. A page-context handoff returns null."),
371
+ pagePath: z
372
+ .string()
373
+ .startsWith("/")
374
+ .max(1024)
375
+ .nullable()
376
+ .describe("Dashboard path that supplied the agent context. A space handoff returns null."),
195
377
  clientTargetId: z
196
- .enum(AGENT_HANDOFF_CLIENT_TARGETS)
197
- .describe("CLI-redeemable client family the handoff is bound to."),
378
+ .enum(AGENT_HANDOFF_TARGETS)
379
+ .describe("Agent destination that receives the handoff prompt."),
198
380
  })
199
381
  .strict();
200
382
  export const AgentHandoffRedeemRequestSchema = z
@@ -204,20 +386,31 @@ export const AgentHandoffRedeemRequestSchema = z
204
386
  .min(1)
205
387
  .describe("Full sensitive handoff link, supplied only in the request body."),
206
388
  clientTargetId: z
207
- .enum(AGENT_HANDOFF_CLIENT_TARGETS)
389
+ .enum(AGENT_HANDOFF_TARGETS)
208
390
  .optional()
209
- .describe("Declared redeeming client family, when the client can identify itself."),
391
+ .describe("Agent destination declared by the client, if the client knows it."),
210
392
  })
211
393
  .strict();
212
394
  export const AgentHandoffRedeemResponseSchema = z
213
395
  .object({
214
396
  status: z.literal("redeemed").describe("The handoff was redeemed exactly once."),
215
- apiKey: ApiKeySchema.describe("Finite space-scoped API key including its one-time secret."),
216
- teamId: z.string().min(1).describe("Team that owns the selected space."),
217
- spaceId: z.string().min(1).describe("Finite space scope granted to the agent."),
397
+ kind: z.enum(AGENT_HANDOFF_SUBJECT_KINDS).describe("Handoff purpose."),
398
+ apiKey: ApiKeySchema.describe("API key that includes its one-time secret."),
399
+ teamId: z.string().min(1).describe("Team that owns the handoff."),
400
+ spaceId: z
401
+ .string()
402
+ .min(1)
403
+ .nullable()
404
+ .describe("Space that the agent can manage. A page-context handoff returns null."),
405
+ pagePath: z
406
+ .string()
407
+ .startsWith("/")
408
+ .max(1024)
409
+ .nullable()
410
+ .describe("Dashboard path that supplied the agent context. A space handoff returns null."),
218
411
  clientTargetId: z
219
- .enum(AGENT_HANDOFF_CLIENT_TARGETS)
220
- .describe("CLI-redeemable client family the handoff is bound to."),
412
+ .enum(AGENT_HANDOFF_TARGETS)
413
+ .describe("Agent destination that received the handoff prompt."),
221
414
  })
222
415
  .strict();
223
416
  export const AgentHandoffRevokeResponseSchema = z
@@ -225,11 +418,10 @@ export const AgentHandoffRevokeResponseSchema = z
225
418
  status: z.literal("revoked").describe("The unused handoff is revoked."),
226
419
  })
227
420
  .strict();
228
- // List (`GET /v1/auth/agent-handoffs?teamId=…`): the human handoff ledger. Session-only,
229
- // scoped to one team, bounded to the newest rows (active handoffs are few and short-lived,
230
- // so the bound can never hide a revocable link); rows are the truthful lifecycle record,
231
- // never the secret (the browser credential exists only in the one create response and is
232
- // never listed or replayed).
421
+ // List (`GET /v1/auth/agent-handoffs?teamId=…`). Session-only, one team,
422
+ // bounded to the newest rows; handoffs are few and short-lived, so the bound
423
+ // cannot hide a revocable link. The browser credential exists only in the
424
+ // create response and is never listed.
233
425
  export const AgentHandoffListQuerySchema = z.object({
234
426
  teamId: z.string().min(1).describe("Team whose issued agent handoffs to list."),
235
427
  });
@@ -238,12 +430,23 @@ export const AgentHandoffStatusSchema = z
238
430
  .describe("Stored lifecycle status. `expired` is not a stored status. The caller derives it from `expiresAt`.");
239
431
  export const AgentHandoffSummarySchema = z
240
432
  .object({
241
- id: z.string().min(1).describe("Opaque app-private handoff document identifier."),
242
- teamId: z.string().min(1).describe("Team that owns the selected space."),
243
- spaceId: z.string().min(1).describe("Finite space scope granted to the agent."),
433
+ kind: z.enum(AGENT_HANDOFF_SUBJECT_KINDS).describe("Handoff purpose."),
434
+ id: z.string().min(1).describe("Non-secret handoff ledger identifier."),
435
+ teamId: z.string().min(1).describe("Team that owns the handoff."),
436
+ spaceId: z
437
+ .string()
438
+ .min(1)
439
+ .nullable()
440
+ .describe("Space that the agent can manage. A page-context handoff returns null."),
441
+ pagePath: z
442
+ .string()
443
+ .startsWith("/")
444
+ .max(1024)
445
+ .nullable()
446
+ .describe("Dashboard path that supplied the agent context. A space handoff returns null."),
244
447
  clientTargetId: z
245
- .enum(AGENT_HANDOFF_CLIENT_TARGETS)
246
- .describe("CLI-redeemable client family the handoff is bound to."),
448
+ .enum(AGENT_HANDOFF_TARGETS)
449
+ .describe("Agent destination that received the handoff prompt."),
247
450
  status: AgentHandoffStatusSchema,
248
451
  createdAt: z.string().datetime().describe("Instant the handoff was minted."),
249
452
  expiresAt: z
@@ -260,6 +463,17 @@ export const AgentHandoffSummarySchema = z
260
463
  .datetime()
261
464
  .nullable()
262
465
  .describe("Instant the handoff was revoked, if it was."),
466
+ firstFetchedAt: z
467
+ .string()
468
+ .datetime()
469
+ .nullable()
470
+ .describe("Instant the handoff document was first fetched, if it was."),
471
+ lastFetchedAt: z
472
+ .string()
473
+ .datetime()
474
+ .nullable()
475
+ .describe("Instant the handoff document was most recently fetched, if it was."),
476
+ fetchCount: z.number().int().nonnegative().describe("Number of document fetches recorded."),
263
477
  })
264
478
  .strict();
265
479
  export const AgentHandoffListResponseSchema = z.array(AgentHandoffSummarySchema);
@@ -1,5 +1,4 @@
1
1
  import { z } from "zod";
2
- /** Disclosure tiers an entry can carry, default `essential` for listings. */
3
2
  export declare const DOC_TIERS: readonly ["essential", "full", "reference"];
4
3
  export declare const docsIndexQuerySchema: z.ZodObject<{
5
4
  q: z.ZodOptional<z.ZodString>;
@@ -11,18 +10,16 @@ export declare const docsIndexQuerySchema: z.ZodObject<{
11
10
  category: z.ZodOptional<z.ZodEnum<{
12
11
  guide: "guide";
13
12
  api: "api";
14
- error: "error";
15
13
  cli: "cli";
14
+ error: "error";
16
15
  workflow: "workflow";
17
16
  recipe: "recipe";
18
17
  }>>;
19
18
  }, z.core.$strip>;
20
- /** Links carried by every docs entry. */
21
19
  export declare const DocsLinksSchema: z.ZodObject<{
22
20
  doc: z.ZodString;
23
21
  self: z.ZodString;
24
22
  }, z.core.$strip>;
25
- /** One entry in the docs index. */
26
23
  export declare const DocsEntrySchema: z.ZodObject<{
27
24
  slug: z.ZodString;
28
25
  title: z.ZodString;
@@ -30,8 +27,8 @@ export declare const DocsEntrySchema: z.ZodObject<{
30
27
  category: z.ZodEnum<{
31
28
  guide: "guide";
32
29
  api: "api";
33
- error: "error";
34
30
  cli: "cli";
31
+ error: "error";
35
32
  workflow: "workflow";
36
33
  recipe: "recipe";
37
34
  }>;
@@ -48,7 +45,6 @@ export declare const DocsEntrySchema: z.ZodObject<{
48
45
  }, z.core.$strip>;
49
46
  }, z.core.$strip>;
50
47
  export type DocsEntry = z.infer<typeof DocsEntrySchema>;
51
- /** A single doc, which additionally carries its printable body. */
52
48
  export declare const DocsDocSchema: z.ZodObject<{
53
49
  slug: z.ZodString;
54
50
  title: z.ZodString;
@@ -56,8 +52,8 @@ export declare const DocsDocSchema: z.ZodObject<{
56
52
  category: z.ZodEnum<{
57
53
  guide: "guide";
58
54
  api: "api";
59
- error: "error";
60
55
  cli: "cli";
56
+ error: "error";
61
57
  workflow: "workflow";
62
58
  recipe: "recipe";
63
59
  }>;
@@ -75,7 +71,7 @@ export declare const DocsDocSchema: z.ZodObject<{
75
71
  body: z.ZodString;
76
72
  }, z.core.$strip>;
77
73
  export type DocsDoc = z.infer<typeof DocsDocSchema>;
78
- /** The GET /v1/docs index payload (inside the `{ data }` envelope). */
74
+ /** GET /v1/docs payload, inside the `{ data }` envelope. */
79
75
  export declare const DocsIndexResponseSchema: z.ZodObject<{
80
76
  tier: z.ZodEnum<{
81
77
  essential: "essential";
@@ -86,8 +82,8 @@ export declare const DocsIndexResponseSchema: z.ZodObject<{
86
82
  category: z.ZodNullable<z.ZodEnum<{
87
83
  guide: "guide";
88
84
  api: "api";
89
- error: "error";
90
85
  cli: "cli";
86
+ error: "error";
91
87
  workflow: "workflow";
92
88
  recipe: "recipe";
93
89
  }>>;
@@ -99,8 +95,8 @@ export declare const DocsIndexResponseSchema: z.ZodObject<{
99
95
  category: z.ZodEnum<{
100
96
  guide: "guide";
101
97
  api: "api";
102
- error: "error";
103
98
  cli: "cli";
99
+ error: "error";
104
100
  workflow: "workflow";
105
101
  recipe: "recipe";
106
102
  }>;
@@ -1,17 +1,12 @@
1
- // Public contract for the machine-readable docs index API (GET /v1/docs and
2
- // GET /v1/docs/:slug). Tier values come from the shared CLI disclosure tiers and
3
- // categories from the shared docs catalog, so the API can never describe a tier
4
- // or category the catalog does not produce.
1
+ // Public contract for the docs index API (GET /v1/docs, GET /v1/docs/pages/:slug).
2
+ // Tiers and categories are reused from the shared CLI vocabulary and docs
3
+ // catalog, so the API can never name one they do not produce.
5
4
  import { z } from "zod";
6
5
  import { DOC_KINDS } from "../docs/catalog.js";
7
6
  import { CLI_DISCLOSURE_TIER_ORDER } from "../vocabulary.js";
8
- /** Disclosure tiers an entry can carry, default `essential` for listings. */
9
7
  export const DOC_TIERS = CLI_DISCLOSURE_TIER_ORDER;
10
8
  const docTierEnum = z.enum([...DOC_TIERS]);
11
9
  const docCategoryEnum = z.enum([...DOC_KINDS]);
12
- // Query for GET /v1/docs. Tier-aware: defaults to `essential`; pass
13
- // `tier=reference` to get EVERYTHING (tiers are cumulative). Optional `q`
14
- // free-text search and `category` filter compose with the tier.
15
10
  export const docsIndexQuerySchema = z.object({
16
11
  q: z.string().optional().describe("Free-text search across slug, title, summary, and keywords."),
17
12
  tier: docTierEnum
@@ -21,12 +16,10 @@ export const docsIndexQuerySchema = z.object({
21
16
  .optional()
22
17
  .describe("Restrict to one docs area: `guide`, `cli`, `api`, `recipe`, `workflow`, or `error`."),
23
18
  });
24
- /** Links carried by every docs entry. */
25
19
  export const DocsLinksSchema = z.object({
26
20
  doc: z.string().url().describe("Canonical human-readable docs URL."),
27
- self: z.string().describe("API-relative link to this entry's JSON (`/v1/docs/{slug}`)."),
21
+ self: z.string().describe("API-relative link to this entry's JSON (`/v1/docs/pages/{slug}`)."),
28
22
  });
29
- /** One entry in the docs index. */
30
23
  export const DocsEntrySchema = z.object({
31
24
  slug: z.string().describe("Stable topic id, for example `publishing` or `api/spaces`."),
32
25
  title: z.string(),
@@ -37,11 +30,10 @@ export const DocsEntrySchema = z.object({
37
30
  url: z.string().url().describe("Canonical human-readable docs URL."),
38
31
  links: DocsLinksSchema,
39
32
  });
40
- /** A single doc, which additionally carries its printable body. */
41
33
  export const DocsDocSchema = DocsEntrySchema.extend({
42
34
  body: z.string().describe("Short printable explanation of the topic."),
43
35
  });
44
- /** The GET /v1/docs index payload (inside the `{ data }` envelope). */
36
+ /** GET /v1/docs payload, inside the `{ data }` envelope. */
45
37
  export const DocsIndexResponseSchema = z.object({
46
38
  tier: docTierEnum.describe("The tier the listing ran at."),
47
39
  query: z.string().nullable().describe("The trimmed `q` query, or null when listing."),