@spacefast/common 0.0.3 → 0.0.6

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 (159) hide show
  1. package/dist/agents/connect-targets.d.ts +133 -0
  2. package/dist/agents/connect-targets.js +224 -0
  3. package/dist/brand.d.ts +1 -0
  4. package/dist/brand.js +5 -0
  5. package/dist/config/domains.d.ts +12 -6
  6. package/dist/config/domains.js +30 -38
  7. package/dist/contracts/access.d.ts +829 -129
  8. package/dist/contracts/access.js +771 -148
  9. package/dist/contracts/activity.d.ts +5 -5
  10. package/dist/contracts/activity.js +28 -2
  11. package/dist/contracts/annotations.d.ts +3 -5
  12. package/dist/contracts/api-keys.d.ts +9 -10
  13. package/dist/contracts/api-keys.js +9 -6
  14. package/dist/contracts/archives.d.ts +22 -16
  15. package/dist/contracts/archives.js +11 -4
  16. package/dist/contracts/billing.d.ts +21 -30
  17. package/dist/contracts/builds.d.ts +21 -17
  18. package/dist/contracts/builds.js +12 -0
  19. package/dist/contracts/channels.d.ts +2 -2
  20. package/dist/contracts/common.d.ts +7 -5
  21. package/dist/contracts/common.js +4 -0
  22. package/dist/contracts/continuation.d.ts +63 -0
  23. package/dist/contracts/continuation.js +91 -0
  24. package/dist/contracts/countries.d.ts +2 -0
  25. package/dist/contracts/countries.js +261 -0
  26. package/dist/contracts/deployments.d.ts +34 -34
  27. package/dist/contracts/device-auth.d.ts +4 -11
  28. package/dist/contracts/device-auth.js +4 -0
  29. package/dist/contracts/docs.d.ts +119 -0
  30. package/dist/contracts/docs.js +51 -0
  31. package/dist/contracts/domains.d.ts +295 -253
  32. package/dist/contracts/domains.js +26 -4
  33. package/dist/contracts/enums.d.ts +17 -18
  34. package/dist/contracts/enums.js +25 -14
  35. package/dist/contracts/error-code-meta.d.ts +84 -0
  36. package/dist/contracts/error-code-meta.js +99 -10
  37. package/dist/contracts/error-codes.d.ts +1 -1
  38. package/dist/contracts/error-codes.js +17 -0
  39. package/dist/contracts/events.d.ts +13 -13
  40. package/dist/contracts/features.d.ts +93 -23
  41. package/dist/contracts/features.js +178 -13
  42. package/dist/contracts/git.d.ts +3 -9
  43. package/dist/contracts/ids.d.ts +5 -0
  44. package/dist/contracts/ids.js +5 -0
  45. package/dist/contracts/internal.d.ts +3 -3
  46. package/dist/contracts/mcp.d.ts +34 -36
  47. package/dist/contracts/me.d.ts +8 -8
  48. package/dist/contracts/me.js +1 -1
  49. package/dist/contracts/oauth-resources.d.ts +19 -8
  50. package/dist/contracts/oauth-resources.js +44 -13
  51. package/dist/contracts/operations.d.ts +2 -2
  52. package/dist/contracts/plan-policy.d.ts +4 -4
  53. package/dist/contracts/platform.d.ts +3 -105
  54. package/dist/contracts/platform.js +0 -50
  55. package/dist/contracts/push-new.d.ts +4 -4
  56. package/dist/contracts/quotas.d.ts +2 -0
  57. package/dist/contracts/quotas.js +8 -0
  58. package/dist/contracts/repository-connections.d.ts +1 -3
  59. package/dist/contracts/resources.d.ts +112 -28
  60. package/dist/contracts/resources.js +26 -2
  61. package/dist/contracts/routes.d.ts +0 -2
  62. package/dist/contracts/runtime-api.d.ts +365 -43
  63. package/dist/contracts/runtime-api.js +275 -6
  64. package/dist/contracts/sites.d.ts +45 -28
  65. package/dist/contracts/sites.js +21 -0
  66. package/dist/contracts/space-config.d.ts +201 -2
  67. package/dist/contracts/space-config.js +135 -5
  68. package/dist/contracts/spaces.d.ts +423 -162
  69. package/dist/contracts/spaces.js +94 -8
  70. package/dist/contracts/superadmin-emails.d.ts +7 -5
  71. package/dist/contracts/superadmin-emails.js +8 -0
  72. package/dist/contracts/superadmin-queues.d.ts +32 -32
  73. package/dist/contracts/superadmin-spaces.d.ts +418 -24
  74. package/dist/contracts/superadmin-spaces.js +24 -0
  75. package/dist/contracts/superadmin-tenants.d.ts +8 -8
  76. package/dist/contracts/superadmin.d.ts +17 -104
  77. package/dist/contracts/superadmin.js +6 -14
  78. package/dist/contracts/tags.d.ts +42 -41
  79. package/dist/contracts/tags.js +2 -1
  80. package/dist/contracts/teams.d.ts +40 -23
  81. package/dist/contracts/teams.js +20 -1
  82. package/dist/contracts/theme-json.d.ts +30 -0
  83. package/dist/contracts/theme-json.js +48 -0
  84. package/dist/contracts/transfers.d.ts +9 -9
  85. package/dist/contracts/variables.d.ts +14 -16
  86. package/dist/contracts/variables.js +0 -5
  87. package/dist/contracts/webhooks.d.ts +6 -4
  88. package/dist/contracts/webhooks.js +1 -1
  89. package/dist/contracts/zero.d.ts +13 -18
  90. package/dist/docs/agent-prose.d.ts +43 -3
  91. package/dist/docs/agent-prose.js +153 -10
  92. package/dist/docs/agent-setup.js +48 -15
  93. package/dist/docs/agent-solutions.d.ts +5 -5
  94. package/dist/docs/agent-solutions.js +2 -2
  95. package/dist/docs/catalog.d.ts +650 -0
  96. package/dist/docs/catalog.js +758 -0
  97. package/dist/docs/error-docs.d.ts +0 -2
  98. package/dist/docs/error-docs.js +89 -35
  99. package/dist/docs/index-build.d.ts +17 -0
  100. package/dist/docs/index-build.js +24 -0
  101. package/dist/docs/search.d.ts +54 -0
  102. package/dist/docs/search.js +96 -0
  103. package/dist/docs/skill-distribution.d.ts +5 -3
  104. package/dist/docs/skill-distribution.js +8 -8
  105. package/dist/utils/access-match.d.ts +39 -0
  106. package/dist/utils/access-match.js +296 -0
  107. package/dist/utils/auth-redirect.d.ts +3 -1
  108. package/dist/utils/auth-redirect.js +21 -1
  109. package/dist/utils/build-settings.d.ts +6 -0
  110. package/dist/utils/build-settings.js +429 -46
  111. package/dist/utils/claim-token.d.ts +8 -0
  112. package/dist/utils/claim-token.js +23 -2
  113. package/dist/utils/content-type.d.ts +1 -0
  114. package/dist/utils/content-type.js +1 -1
  115. package/dist/utils/credential-policy.d.ts +54 -0
  116. package/dist/utils/{access-policy.js → credential-policy.js} +28 -2
  117. package/dist/utils/gate-theme.d.ts +61 -0
  118. package/dist/utils/gate-theme.js +217 -0
  119. package/dist/utils/git-repository.d.ts +0 -1
  120. package/dist/utils/git-repository.js +0 -3
  121. package/dist/utils/id-hints.d.ts +8 -0
  122. package/dist/utils/id-hints.js +61 -0
  123. package/dist/utils/local-space-state.d.ts +91 -0
  124. package/dist/utils/local-space-state.js +251 -0
  125. package/dist/utils/oauth-signed-query.d.ts +8 -0
  126. package/dist/utils/oauth-signed-query.js +26 -0
  127. package/dist/utils/publish-detection.d.ts +0 -8
  128. package/dist/utils/publish-detection.js +0 -93
  129. package/dist/utils/publish-policy.d.ts +6 -5
  130. package/dist/utils/publish-policy.js +71 -7
  131. package/dist/utils/query-keys.d.ts +17 -6
  132. package/dist/utils/query-keys.js +27 -4
  133. package/dist/utils/runtime-paths.d.ts +0 -1
  134. package/dist/utils/runtime-paths.js +0 -1
  135. package/dist/utils/runtime-upload-batch.d.ts +18 -0
  136. package/dist/utils/runtime-upload-batch.js +90 -0
  137. package/dist/utils/runtime-upload.d.ts +2 -0
  138. package/dist/utils/runtime-upload.js +5 -0
  139. package/dist/utils/space-config.d.ts +4 -0
  140. package/dist/utils/space-config.js +10 -1
  141. package/dist/utils/space-theme.d.ts +2 -0
  142. package/dist/utils/space-theme.js +9 -0
  143. package/dist/utils/static-runtime-policy.d.ts +1 -1
  144. package/dist/utils/static-runtime-policy.js +47 -15
  145. package/dist/utils/upload-session.d.ts +1 -1
  146. package/dist/utils/wpcom-auth-redirects.d.ts +32 -2
  147. package/dist/utils/wpcom-auth-redirects.js +26 -10
  148. package/dist/vocabulary.d.ts +130 -30
  149. package/dist/vocabulary.js +77 -36
  150. package/package.json +16 -1
  151. package/dist/contracts/account.d.ts +0 -28
  152. package/dist/contracts/account.js +0 -54
  153. package/dist/contracts/intercom.d.ts +0 -6
  154. package/dist/contracts/intercom.js +0 -5
  155. package/dist/contracts/telemetry.d.ts +0 -2
  156. package/dist/contracts/telemetry.js +0 -1
  157. package/dist/utils/access-policy.d.ts +0 -39
  158. package/dist/utils/error-display.d.ts +0 -7
  159. package/dist/utils/error-display.js +0 -42
@@ -8,5 +8,3 @@ export type ErrorDoc = {
8
8
  export declare const ERROR_DOCS: Record<ErrorCode, ErrorDoc>;
9
9
  /** One generated reference page per error code; the `.md` twin is this exact text. */
10
10
  export declare function errorDocMarkdown(code: ErrorCode): string;
11
- /** The generated `/docs/errors` index page; the `.md` twin is this exact text. */
12
- export declare function errorDocsIndexMarkdown(): string;
@@ -5,7 +5,8 @@
5
5
  // and pages never go missing. apps/www renders the HTML pages and writes the
6
6
  // `.md` twins from the same entries.
7
7
  import { BRAND } from "../brand.js";
8
- import { ERROR_CODES, errorDocsUrl } from "../contracts/error-codes.js";
8
+ import { ERROR_CODES, errorDocsUrl, } from "../contracts/error-codes.js";
9
+ // Restore upgrade-oriented recovery copy here when paid plan checkout is live.
9
10
  export const ERROR_DOCS = {
10
11
  abuse_report_invalid_transition: {
11
12
  summary: "The abuse report cannot move to the requested status from its current status.",
@@ -33,7 +34,7 @@ export const ERROR_DOCS = {
33
34
  },
34
35
  anonymous_expired: {
35
36
  summary: "This anonymous space expired before it was claimed.",
36
- fix: "Publish again to get a fresh space, or claim spaces before their expiry next time.",
37
+ fix: "Publish a fresh space and share its claim link right away this time. If you meant to update a space that is still live, check .spacefast/ (or your saved receipt) for its spaceId and publish to that with its credential instead of creating a new space.",
37
38
  },
38
39
  anonymous_pool_unavailable: {
39
40
  summary: "No pooled capacity is available for anonymous publishes right now.",
@@ -43,6 +44,10 @@ export const ERROR_DOCS = {
43
44
  summary: "Too many anonymous publishes came from this network in a short window.",
44
45
  fix: "Wait for the window to pass, or sign in with an API key for higher limits.",
45
46
  },
47
+ anonymous_space_limit_reached: {
48
+ summary: "Too many unclaimed anonymous spaces are already active for this client.",
49
+ fix: "Log in to publish into an authenticated space, or claim/delete an existing anonymous space before creating another.",
50
+ },
46
51
  archive_body_required: {
47
52
  summary: "This request must carry an archive body but none was provided.",
48
53
  fix: "Send the zip bytes as the request body with the matching content-type header.",
@@ -145,7 +150,7 @@ export const ERROR_DOCS = {
145
150
  },
146
151
  claimed_space_quota_exceeded: {
147
152
  summary: "Claiming this space would exceed the target team's space quota.",
148
- fix: "Delete unused spaces or upgrade the plan, then claim again.",
153
+ fix: "Delete unused spaces, then claim again. Still stuck? POST /v1/feedback with the error code and request id.",
149
154
  },
150
155
  cli_upgrade_required: {
151
156
  summary: "This CLI version is too old to talk to the API safely.",
@@ -165,7 +170,15 @@ export const ERROR_DOCS = {
165
170
  },
166
171
  config_templates_over_limit: {
167
172
  summary: "The configuration declares more template files than the plan allows.",
168
- fix: "Reduce the number of template entries in sf.jsonc.",
173
+ fix: "Reduce the number of template entries in sf.jsonc. Still stuck? POST /v1/feedback with the error code and request id.",
174
+ },
175
+ continuation_unavailable: {
176
+ summary: "This claim token can no longer be exchanged for an access token.",
177
+ fix: "If the space is claimed, ask its owner for an access token (dashboard: Account → Access tokens). If it is still unclaimed, keep using the claim token as bearer auth instead of exchanging it. Still stuck? POST /v1/feedback with the error code and request id.",
178
+ },
179
+ continuation_used: {
180
+ summary: "This claim token was already exchanged for a durable access token.",
181
+ fix: "Authenticate with the exchanged access token (check .spacefast/state.json or wherever it was saved). If it was lost, ask the space owner to mint a new access token.",
169
182
  },
170
183
  credential_expired: {
171
184
  summary: "The credential used for this request has expired.",
@@ -191,9 +204,13 @@ export const ERROR_DOCS = {
191
204
  summary: "CSAM enforcement policy cannot be set below the mandatory account-suspend floor.",
192
205
  fix: "Set the CSAM category enforcement tier to account suspension.",
193
206
  },
207
+ datacenters_unavailable: {
208
+ summary: "Placement regions are temporarily unavailable.",
209
+ fix: "Retry after the datacenter list has synced.",
210
+ },
194
211
  data_location_immutable: {
195
- summary: "A space's data location cannot be changed after placement.",
196
- fix: "Create a new space in the desired region and transfer content into it.",
212
+ summary: "This request tried to change data location through an immutable path.",
213
+ fix: "Use PATCH /v1/spaces/{id} to queue a region move when region changes are supported for this space.",
197
214
  },
198
215
  device_authorization_failed: {
199
216
  summary: "The device login request failed and cannot be completed.",
@@ -373,7 +390,7 @@ export const ERROR_DOCS = {
373
390
  },
374
391
  domain_quota_exceeded: {
375
392
  summary: "Adding this domain would exceed the plan's external domain allowance.",
376
- fix: "Remove unused domains or upgrade the plan.",
393
+ fix: "Remove unused domains. Still stuck? POST /v1/feedback with the error code and request id.",
377
394
  },
378
395
  domain_registration_active: {
379
396
  summary: "The domain has an active registration, which blocks this operation.",
@@ -421,7 +438,7 @@ export const ERROR_DOCS = {
421
438
  },
422
439
  feature_unavailable: {
423
440
  summary: "This feature is not available on this deployment or plan.",
424
- fix: "Check the feature's availability, or upgrade if it is plan-gated.",
441
+ fix: "Check the feature's availability and try again when it is enabled for your team.",
425
442
  },
426
443
  files_mode_does_not_support_spa: {
427
444
  summary: "SPA fallback cannot be combined with files-listing mode.",
@@ -433,11 +450,11 @@ export const ERROR_DOCS = {
433
450
  },
434
451
  free_external_proxy_disabled: {
435
452
  summary: "Proxy routes to external upstreams are not available on the Free plan.",
436
- fix: "Remove the proxy rules or upgrade the plan to enable external proxying.",
453
+ fix: "Remove the proxy rules before publishing. Still stuck? POST /v1/feedback with the error code and request id.",
437
454
  },
438
455
  free_headers_basic_auth_disabled: {
439
456
  summary: "Basic-Auth via _headers is not available on the Free plan.",
440
- fix: "Use space password protection, or upgrade the plan for _headers Basic Auth.",
457
+ fix: "Use space password protection instead. Still stuck? POST /v1/feedback with the error code and request id.",
441
458
  },
442
459
  idempotency_conflict_in_progress: {
443
460
  summary: "Another request with the same Idempotency-Key is still in flight.",
@@ -483,6 +500,10 @@ export const ERROR_DOCS = {
483
500
  summary: "The claim token is invalid or does not match this space.",
484
501
  fix: "Use the exact claim URL returned by the publish that created the space.",
485
502
  },
503
+ invalid_continuation_token: {
504
+ summary: "The continuation token is invalid, expired, or already finished.",
505
+ fix: "Restart the originating flow to obtain a fresh requiresAction envelope and continuation token.",
506
+ },
486
507
  invalid_data_location: {
487
508
  summary: "The requested data location is not a supported region.",
488
509
  fix: "Pick a region from the documented data locations, or use auto.",
@@ -571,6 +592,14 @@ export const ERROR_DOCS = {
571
592
  summary: "An invitation for this email already exists on the team.",
572
593
  fix: "Resend the existing invitation instead of creating a new one.",
573
594
  },
595
+ invitation_email_mismatch: {
596
+ summary: "This invitation was addressed to a different email than the accepting user.",
597
+ fix: "Sign in as the invited email, or ask an admin to invite your current address.",
598
+ },
599
+ invitation_expired: {
600
+ summary: "The invitation has expired and can no longer be accepted.",
601
+ fix: "Ask a team admin to send a fresh invitation, then accept the new one.",
602
+ },
574
603
  invitation_not_pending: {
575
604
  summary: "The invitation is no longer pending.",
576
605
  fix: "Create a new invitation if the member still needs to join.",
@@ -601,7 +630,7 @@ export const ERROR_DOCS = {
601
630
  },
602
631
  log_retention_clamped: {
603
632
  summary: "The requested log range exceeds the plan's retention and was clamped.",
604
- fix: "Narrow the range, or upgrade the plan for longer retention.",
633
+ fix: "Narrow the range.",
605
634
  },
606
635
  lost_domain_control: {
607
636
  summary: `${BRAND.productName} no longer observes DNS control for this domain.`,
@@ -635,6 +664,10 @@ export const ERROR_DOCS = {
635
664
  summary: "A required route parameter is missing from the request path.",
636
665
  fix: "Check the endpoint path in the API reference and include every parameter.",
637
666
  },
667
+ move_target_capacity_lost: {
668
+ summary: "The selected move target no longer has capacity for the space.",
669
+ fix: "Retry the move with a different target or after capacity is freed.",
670
+ },
638
671
  nameserver_delegation_required: {
639
672
  summary: `This operation requires the domain to be delegated to ${BRAND.productName} nameservers.`,
640
673
  fix: "Update the domain's nameservers at the registrar, then retry once delegation propagates.",
@@ -671,6 +704,14 @@ export const ERROR_DOCS = {
671
704
  summary: "This plan grant was already revoked.",
672
705
  fix: "Nothing to do; create a new grant if the team should regain the plan.",
673
706
  },
707
+ placement_invalid_burstable: {
708
+ summary: "The placement burstable option was used with an unsupported placement mode.",
709
+ fix: 'Set placement.mode to "dedicated" before setting placement.burstable, or remove the burstable option.',
710
+ },
711
+ placement_mode_requires_plan: {
712
+ summary: "The requested placement mode requires a plan entitlement.",
713
+ fix: "Upgrade the team plan or choose shared placement.",
714
+ },
674
715
  platform_tenant_immutable_client: {
675
716
  summary: "The tenant's provider client cannot be changed.",
676
717
  fix: "Create a new tenant with the desired provider client instead.",
@@ -717,7 +758,7 @@ export const ERROR_DOCS = {
717
758
  },
718
759
  publish_archive_expanded_size_exceeded: {
719
760
  summary: "The archive expands beyond the maximum allowed total size.",
720
- fix: "Reduce the content size or upgrade the plan for higher limits.",
761
+ fix: "Reduce the content size.",
721
762
  },
722
763
  publish_archive_file_count_exceeded: {
723
764
  summary: "The archive contains more files than the allowed ceiling.",
@@ -769,7 +810,7 @@ export const ERROR_DOCS = {
769
810
  },
770
811
  routing_rules_over_plan: {
771
812
  summary: "The published _redirects and _headers exceed the plan's routing-rule allowance.",
772
- fix: "Reduce the rule count or upgrade the plan.",
813
+ fix: "Reduce the rule count. Still stuck? POST /v1/feedback with the error code and request id.",
773
814
  },
774
815
  runtime_action_forbidden: {
775
816
  summary: "The runtime credential does not allow this action.",
@@ -777,7 +818,7 @@ export const ERROR_DOCS = {
777
818
  },
778
819
  runtime_api_not_found: {
779
820
  summary: "The runtime management endpoint was not found.",
780
- fix: "Check the runtime API path against the runtime contract.",
821
+ fix: "Send the request with the management hostname as the Host header; management routes are not served on public hostnames.",
781
822
  },
782
823
  runtime_callback_forbidden: {
783
824
  summary: "The runtime callback could not be authenticated.",
@@ -888,13 +929,17 @@ export const ERROR_DOCS = {
888
929
  fix: "Increase the polling interval; aggressive polling invalidates the flow.",
889
930
  },
890
931
  space_already_claimed: {
891
- summary: "The space was already claimed by someone else.",
892
- fix: "Publish a new space; a claim can only succeed once.",
932
+ summary: "The space was already claimed; a claim can only succeed once.",
933
+ fix: "If you are the agent that published this space, exchange your claim token once at POST /v1/anonymous-claim/exchange for a durable access token and keep publishing to the same spaceId. Otherwise ask the owner for access — do not publish a duplicate space.",
893
934
  },
894
935
  space_claim_unavailable: {
895
936
  summary: "This space cannot be claimed.",
896
937
  fix: "Only anonymous, unexpired spaces with a valid claim token can be claimed.",
897
938
  },
939
+ space_claimed_credential_available: {
940
+ summary: "The space was claimed and its owner kept agent publishing enabled; this claim token now works exactly once as an exchange voucher.",
941
+ fix: "POST /v1/anonymous-claim/exchange with this claim token as bearer auth. Save the returned access token (e.g. .spacefast/state.json), then retry the request with it as Authorization: Bearer. Do not publish a new space.",
942
+ },
898
943
  space_disabled: {
899
944
  summary: "The space is disabled and cannot be served or modified.",
900
945
  fix: "Check the disabled reason on the space; it explains the path to restore it.",
@@ -971,9 +1016,13 @@ export const ERROR_DOCS = {
971
1016
  summary: "This operation only applies to static-runtime spaces.",
972
1017
  fix: "Target a static-runtime space.",
973
1018
  },
1019
+ storage_bucket_unavailable: {
1020
+ summary: "No usable internal storage bucket is configured for this operation.",
1021
+ fix: "Check the storage bucket registry and credential environment references, then retry.",
1022
+ },
974
1023
  storage_quota_exceeded: {
975
1024
  summary: "The publish would exceed the plan's storage allowance.",
976
- fix: "Delete old versions or upgrade the plan.",
1025
+ fix: "Delete old versions. Still stuck? POST /v1/feedback with the error code and request id.",
977
1026
  },
978
1027
  storage_usage_unavailable: {
979
1028
  summary: "Storage usage could not be computed right now.",
@@ -991,6 +1040,10 @@ export const ERROR_DOCS = {
991
1040
  summary: "The hostname was recently bound elsewhere; a takeover notice window applies.",
992
1041
  fix: "Retry after the notice window, or have the current holder release the binding.",
993
1042
  },
1043
+ team_member_quota_exceeded: {
1044
+ summary: "Inviting this person would exceed the team's seat limit.",
1045
+ fix: "Remove a team member or cancel a pending invitation to free a seat; pending invitations count toward the limit.",
1046
+ },
994
1047
  team_ref_required: {
995
1048
  summary: "A team reference is required for this operation.",
996
1049
  fix: "Pass the team id or slug.",
@@ -1063,6 +1116,10 @@ export const ERROR_DOCS = {
1063
1116
  summary: "The transfer has progressed past the point where it can be canceled.",
1064
1117
  fix: "Wait for the transfer to finish.",
1065
1118
  },
1119
+ transfer_push_failed: {
1120
+ summary: "The source runtime could not push the space blobs into the transfer bucket.",
1121
+ fix: "Retry the move; if it persists, check the source runtime and bucket configuration.",
1122
+ },
1066
1123
  transfer_source_changed: {
1067
1124
  summary: "The space changed since the transfer was created, so it must be re-confirmed.",
1068
1125
  fix: "Review the space's current state and confirm the transfer again.",
@@ -1071,6 +1128,10 @@ export const ERROR_DOCS = {
1071
1128
  summary: "The transfer target is the same principal that already owns the space.",
1072
1129
  fix: "Pick a different target team or account.",
1073
1130
  },
1131
+ transfer_verify_failed: {
1132
+ summary: "The target runtime could not verify transferred blob content.",
1133
+ fix: "Retry the move; if it persists, check the target runtime and bucket integrity.",
1134
+ },
1074
1135
  unauthorized: {
1075
1136
  summary: "The request carried no valid credential.",
1076
1137
  fix: "Send a bearer access token, use an agent OAuth client, or sign in.",
@@ -1153,7 +1214,7 @@ export const ERROR_DOCS = {
1153
1214
  },
1154
1215
  version_file_too_large: {
1155
1216
  summary: "A file exceeds the plan's maximum file size.",
1156
- fix: "Reduce the file size or upgrade the plan.",
1217
+ fix: "Reduce the file size.",
1157
1218
  },
1158
1219
  version_files_missing: {
1159
1220
  summary: "Declared files were never uploaded, so the version cannot finalize.",
@@ -1193,11 +1254,11 @@ export const ERROR_DOCS = {
1193
1254
  },
1194
1255
  version_quota_exceeded: {
1195
1256
  summary: "The space has reached its version quota.",
1196
- fix: "Delete old versions or upgrade the plan.",
1257
+ fix: "Delete old versions. Still stuck? POST /v1/feedback with the error code and request id.",
1197
1258
  },
1198
1259
  version_total_bytes_exceeded: {
1199
1260
  summary: "The version exceeds the maximum total size.",
1200
- fix: "Reduce the content size or upgrade the plan.",
1261
+ fix: "Reduce the content size.",
1201
1262
  },
1202
1263
  webhook_delivery_budget_exceeded: {
1203
1264
  summary: "The webhook exhausted its delivery budget and was paused.",
@@ -1207,6 +1268,10 @@ export const ERROR_DOCS = {
1207
1268
  summary: "WHOIS data is unavailable for this domain right now.",
1208
1269
  fix: "Retry later.",
1209
1270
  },
1271
+ zero_activating: {
1272
+ summary: "Zero endpoints are activating.",
1273
+ fix: "Wait for the dedicated runtime move to complete, then retry the request.",
1274
+ },
1210
1275
  zero_artifact_abi_mismatch: {
1211
1276
  summary: "The Zero endpoint artifact was built for a different runner ABI.",
1212
1277
  fix: `Rebuild and republish the Zero project with the current ${BRAND.productName} CLI and runtime.`,
@@ -1363,6 +1428,10 @@ export const ERROR_DOCS = {
1363
1428
  summary: "No Zero endpoint artifact exists for this endpoint id.",
1364
1429
  fix: "Check the route path and rebuild the Zero endpoint index.",
1365
1430
  },
1431
+ zero_requires_dedicated_plan: {
1432
+ summary: "Zero endpoints require a plan with dedicated runtime isolation.",
1433
+ fix: "Upgrade the team to a plan that includes Zero and dedicated runtime, then publish again.",
1434
+ },
1366
1435
  zero_envelope_encode_failed: {
1367
1436
  summary: "The PHP bridge could not encode the Zero runner request envelope.",
1368
1437
  fix: "Retry with valid request data; report the issue if it persists.",
@@ -1584,18 +1653,3 @@ export function errorDocMarkdown(code) {
1584
1653
  "",
1585
1654
  ].join("\n");
1586
1655
  }
1587
- /** The generated `/docs/errors` index page; the `.md` twin is this exact text. */
1588
- export function errorDocsIndexMarkdown() {
1589
- return [
1590
- "# Error reference",
1591
- "",
1592
- `Every ${PRODUCT} API error response carries a stable \`code\` and a \`docsUrl\` that`,
1593
- "links to one of the pages below. Codes are never renamed or removed. Match on",
1594
- "`code` in clients; `message` text may improve over time.",
1595
- "",
1596
- "| Code | Meaning |",
1597
- "| --- | --- |",
1598
- ...ERROR_CODES.map((code) => `| [\`${code}\`](/docs/errors/${code}) | ${ERROR_DOCS[code].summary} |`),
1599
- "",
1600
- ].join("\n");
1601
- }
@@ -0,0 +1,17 @@
1
+ import { type DocEntry } from "./catalog.js";
2
+ /** Current on-disk index schema version; bump when the shape changes. */
3
+ export declare const DOCS_INDEX_VERSION: 1;
4
+ /** A catalog entry plus its precomputed search blob. */
5
+ export interface DocIndexEntry extends DocEntry {
6
+ /** Lowercased haystack (slug + title + summary + kind + keywords) for offline search. */
7
+ readonly haystack: string;
8
+ }
9
+ /** The bundled, generated docs index. */
10
+ export interface DocsIndex {
11
+ readonly version: typeof DOCS_INDEX_VERSION;
12
+ /** Provenance marker so a reader knows the artifact is generated. */
13
+ readonly generatedFrom: string;
14
+ readonly entries: readonly DocIndexEntry[];
15
+ }
16
+ /** Build the derived search index from a catalog (defaults to the bundled one). */
17
+ export declare function buildDocsIndex(catalog?: readonly DocEntry[]): DocsIndex;
@@ -0,0 +1,24 @@
1
+ // Pure transform from the curated docs catalog (catalog.ts) to a search index.
2
+ // Both the CLI's generator script and its drift-guard test call buildDocsIndex,
3
+ // and the control-plane builds the same index in memory for GET /v1/docs, so the
4
+ // served index, the bundled artifact, and the source can never silently diverge.
5
+ import { DOCS_CATALOG } from "./catalog.js";
6
+ /** Current on-disk index schema version; bump when the shape changes. */
7
+ export const DOCS_INDEX_VERSION = 1;
8
+ /** Build the derived search index from a catalog (defaults to the bundled one). */
9
+ export function buildDocsIndex(catalog = DOCS_CATALOG) {
10
+ const entries = catalog.map((entry) => ({
11
+ ...entry,
12
+ keywords: [...entry.keywords],
13
+ haystack: [entry.slug, entry.title, entry.summary, entry.kind, ...entry.keywords]
14
+ .join(" ")
15
+ .toLowerCase(),
16
+ }));
17
+ return {
18
+ version: DOCS_INDEX_VERSION,
19
+ // Provenance points at the CLI's re-export path, which the committed
20
+ // docs-index.generated.json artifact (and its drift-guard test) pin.
21
+ generatedFrom: "src/docs-catalog.ts",
22
+ entries,
23
+ };
24
+ }
@@ -0,0 +1,54 @@
1
+ import { type CliDisclosureTier } from "../vocabulary.js";
2
+ import type { DocIndexEntry, DocsIndex } from "./index-build.js";
3
+ /** The public, machine-readable shape of a single matched doc. */
4
+ export interface DocResult {
5
+ readonly slug: string;
6
+ readonly title: string;
7
+ readonly kind: DocIndexEntry["kind"];
8
+ readonly tier: CliDisclosureTier;
9
+ readonly summary: string;
10
+ readonly url: string;
11
+ }
12
+ /** A topic result additionally carries the printable body. */
13
+ export interface DocTopic extends DocResult {
14
+ readonly body: string;
15
+ }
16
+ /** The exact `data` payload `sf docs` emits (drives both human + `--json` output). */
17
+ export interface DocsCommandResult {
18
+ /** The trimmed query, or null when listing. */
19
+ readonly query: string | null;
20
+ /** The tier the listing/search ran at. */
21
+ readonly tier: CliDisclosureTier;
22
+ /** Present when the query resolved to an exact topic. */
23
+ readonly topic: DocTopic | null;
24
+ /** Matched docs (or the full tier listing when no query). */
25
+ readonly results: readonly DocResult[];
26
+ }
27
+ /** Entries visible at `viewTier`, in catalog order. */
28
+ export declare function visibleEntries(index: DocsIndex, viewTier: CliDisclosureTier): DocIndexEntry[];
29
+ /** Exact topic lookup by slug (case-insensitive). Ignores tier — explicit intent wins. */
30
+ export declare function findTopic(index: DocsIndex, slug: string): DocIndexEntry | undefined;
31
+ /**
32
+ * Ranked query results are capped so a broad term (e.g. one that hits a chunk
33
+ * of the ~390 generated error-reference entries) can never return the whole
34
+ * catalog in one response. Listing a tier with no query is unaffected — that's
35
+ * an intentional "show me everything at this tier" request, not a search.
36
+ */
37
+ export declare const SEARCH_DOCS_RESULT_LIMIT = 25;
38
+ /**
39
+ * Rank docs matching `query` within the tier. Empty query returns the full tier
40
+ * listing (catalog order), uncapped. A non-empty query ranks matches and caps
41
+ * the result count at {@link SEARCH_DOCS_RESULT_LIMIT}.
42
+ */
43
+ export declare function searchDocs(index: DocsIndex, options: {
44
+ query?: string;
45
+ tier: CliDisclosureTier;
46
+ }): DocIndexEntry[];
47
+ /**
48
+ * Resolve the `sf docs [query]` request: an exact-slug query prints that topic;
49
+ * any other query searches; an empty query lists the tier. Pure + offline.
50
+ */
51
+ export declare function resolveDocsCommand(index: DocsIndex, options: {
52
+ query?: string;
53
+ tier: CliDisclosureTier;
54
+ }): DocsCommandResult;
@@ -0,0 +1,96 @@
1
+ // Pure, offline search + tier filtering over a docs index. Shared by the CLI's
2
+ // `sf docs` (offline, against the bundled JSON) and the control-plane's
3
+ // GET /v1/docs (in memory, against the catalog-derived index) so both rank and
4
+ // gate identically. Tier-aware — ESSENTIAL by default, widening to FULL
5
+ // (`--full`) and REFERENCE (`--all`).
6
+ import { tierVisibleAt } from "../vocabulary.js";
7
+ function toResult(entry) {
8
+ return {
9
+ slug: entry.slug,
10
+ title: entry.title,
11
+ kind: entry.kind,
12
+ tier: entry.tier,
13
+ summary: entry.summary,
14
+ url: entry.url,
15
+ };
16
+ }
17
+ function toTopic(entry) {
18
+ return { ...toResult(entry), body: entry.body };
19
+ }
20
+ /** Entries visible at `viewTier`, in catalog order. */
21
+ export function visibleEntries(index, viewTier) {
22
+ return index.entries.filter((entry) => tierVisibleAt(viewTier, entry.tier));
23
+ }
24
+ /** Exact topic lookup by slug (case-insensitive). Ignores tier — explicit intent wins. */
25
+ export function findTopic(index, slug) {
26
+ const needle = slug.trim().toLowerCase();
27
+ if (!needle)
28
+ return undefined;
29
+ return index.entries.find((entry) => entry.slug.toLowerCase() === needle);
30
+ }
31
+ function scoreEntry(entry, tokens) {
32
+ const slug = entry.slug.toLowerCase();
33
+ const title = entry.title.toLowerCase();
34
+ const keywords = entry.keywords.map((keyword) => keyword.toLowerCase());
35
+ let total = 0;
36
+ for (const token of tokens) {
37
+ let tokenScore = 0;
38
+ if (slug === token)
39
+ tokenScore = Math.max(tokenScore, 5);
40
+ else if (slug.includes(token))
41
+ tokenScore = Math.max(tokenScore, 3);
42
+ if (title.includes(token))
43
+ tokenScore = Math.max(tokenScore, 3);
44
+ if (keywords.some((keyword) => keyword.includes(token)))
45
+ tokenScore = Math.max(tokenScore, 2);
46
+ if (tokenScore === 0 && entry.haystack.includes(token))
47
+ tokenScore = 1;
48
+ // AND semantics: every query token must match somewhere.
49
+ if (tokenScore === 0)
50
+ return 0;
51
+ total += tokenScore;
52
+ }
53
+ return total;
54
+ }
55
+ /**
56
+ * Ranked query results are capped so a broad term (e.g. one that hits a chunk
57
+ * of the ~390 generated error-reference entries) can never return the whole
58
+ * catalog in one response. Listing a tier with no query is unaffected — that's
59
+ * an intentional "show me everything at this tier" request, not a search.
60
+ */
61
+ export const SEARCH_DOCS_RESULT_LIMIT = 25;
62
+ /**
63
+ * Rank docs matching `query` within the tier. Empty query returns the full tier
64
+ * listing (catalog order), uncapped. A non-empty query ranks matches and caps
65
+ * the result count at {@link SEARCH_DOCS_RESULT_LIMIT}.
66
+ */
67
+ export function searchDocs(index, options) {
68
+ const pool = visibleEntries(index, options.tier);
69
+ const tokens = (options.query ?? "").toLowerCase().split(/\s+/).filter(Boolean);
70
+ if (tokens.length === 0)
71
+ return pool;
72
+ return pool
73
+ .map((entry) => ({ entry, score: scoreEntry(entry, tokens) }))
74
+ .filter((scored) => scored.score > 0)
75
+ .toSorted((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug))
76
+ .slice(0, SEARCH_DOCS_RESULT_LIMIT)
77
+ .map((scored) => scored.entry);
78
+ }
79
+ /**
80
+ * Resolve the `sf docs [query]` request: an exact-slug query prints that topic;
81
+ * any other query searches; an empty query lists the tier. Pure + offline.
82
+ */
83
+ export function resolveDocsCommand(index, options) {
84
+ const trimmed = (options.query ?? "").trim();
85
+ const exact = trimmed ? findTopic(index, trimmed) : undefined;
86
+ if (exact) {
87
+ return {
88
+ query: trimmed || null,
89
+ tier: options.tier,
90
+ topic: toTopic(exact),
91
+ results: [toResult(exact)],
92
+ };
93
+ }
94
+ const results = searchDocs(index, { query: trimmed, tier: options.tier }).map(toResult);
95
+ return { query: trimmed || null, tier: options.tier, topic: null, results };
96
+ }
@@ -3,10 +3,12 @@ export declare const spacefastSkillRepoOwner = "spacefast";
3
3
  export declare const spacefastSkillRepoName = "plugins";
4
4
  export declare const spacefastSkillRepoRef = "spacefast/plugins";
5
5
  export declare const spacefastSkillUrl: string;
6
- export declare const spacefastSkillInstallCommand: string;
6
+ export declare const spacefastSkillFetchCommand: string;
7
+ export declare const spacefastSkillInstallCommand = "npx -y skills add spacefast/plugins --skill spacefast -g -y";
7
8
  export declare const spacefastInstallCurlCommand: string;
8
9
  export declare const spacefastInstallPowerShellCommand: string;
9
10
  export declare const spacefastClaudePluginAddCommand = "claude plugin marketplace add spacefast/plugins";
10
11
  export declare const spacefastClaudePluginInstallCommand = "claude plugin install spacefast@spacefast";
11
- export declare const spacefastCodexSkillInstallCommand = "npx skills add spacefast/plugins --skill spacefast -g";
12
- export declare const spacefastAgentSetupPrompt: string;
12
+ export declare const spacefastCodexPluginAddCommand = "codex plugin marketplace add spacefast/plugins";
13
+ export declare const spacefastCodexPluginInstallCommand = "codex plugin add spacefast@spacefast";
14
+ export declare const spacefastCodexSkillInstallCommand = "npx -y skills add spacefast/plugins --skill spacefast -g -a codex -y";
@@ -4,15 +4,15 @@ export const spacefastSkillRepoOwner = "spacefast";
4
4
  export const spacefastSkillRepoName = "plugins";
5
5
  export const spacefastSkillRepoRef = `${spacefastSkillRepoOwner}/${spacefastSkillRepoName}`;
6
6
  export const spacefastSkillUrl = `${BRAND.apiOrigin}/skill`;
7
- export const spacefastSkillInstallCommand = `curl -fsSL ${spacefastSkillUrl}`;
7
+ export const spacefastSkillFetchCommand = `curl -fsSL ${spacefastSkillUrl}`;
8
+ export const spacefastSkillInstallCommand = `npx -y skills add ${spacefastSkillRepoRef} --skill ${spacefastSkillName} -g -y`;
8
9
  export const spacefastInstallCurlCommand = `curl -fsSL ${BRAND.websiteOrigin}/install.sh | bash`;
9
10
  export const spacefastInstallPowerShellCommand = `irm ${BRAND.websiteOrigin}/install.ps1 | iex`;
10
11
  export const spacefastClaudePluginAddCommand = `claude plugin marketplace add ${spacefastSkillRepoRef}`;
11
12
  export const spacefastClaudePluginInstallCommand = `claude plugin install ${spacefastSkillName}@${spacefastSkillName}`;
12
- export const spacefastCodexSkillInstallCommand = `npx skills add ${spacefastSkillRepoRef} --skill ${spacefastSkillName} -g`;
13
- export const spacefastAgentSetupPrompt = `I'd like you to set up ${BRAND.websiteOrigin}, the static host for AI agents.
14
-
15
- Install the ${BRAND.productName} CLI with: ${spacefastInstallCurlCommand}
16
- On Windows PowerShell, use: ${spacefastInstallPowerShellCommand}
17
-
18
- If your environment supports manual skill import, fetch the official ${BRAND.productName} skill from: ${spacefastSkillUrl}`;
13
+ // Codex mirrors the Claude plugin commands (same marketplace repo, same
14
+ // plugin name); the release workflow validates both installs against the
15
+ // assembled dist/plugins tree.
16
+ export const spacefastCodexPluginAddCommand = `codex plugin marketplace add ${spacefastSkillRepoRef}`;
17
+ export const spacefastCodexPluginInstallCommand = `codex plugin add ${spacefastSkillName}@${spacefastSkillName}`;
18
+ export const spacefastCodexSkillInstallCommand = `npx -y skills add ${spacefastSkillRepoRef} --skill ${spacefastSkillName} -g -a codex -y`;
@@ -0,0 +1,39 @@
1
+ export declare function filterGrantsByNamespace(grants: string[], namespaces: string[]): string[];
2
+ export declare function grantGlobMatches(pattern: string, grant: string): boolean;
3
+ export declare function grantsIntersect(grants: string[], requiredGrants: string[]): boolean;
4
+ export declare function grantsSatisfyRule(input: {
5
+ grants: string[];
6
+ requiredGrants: string[];
7
+ grantNamespaces: string[];
8
+ }): boolean;
9
+ export declare function canonicalizeHost(host: string): string;
10
+ export declare function hostGlobMatches(pattern: string, host: string): boolean;
11
+ export declare function hostTemplateMatches(template: string, host: string): boolean;
12
+ export declare function pathGlobMatches(pattern: string, path: string): boolean;
13
+ export declare function agentMatches(needle: string, agent: string): boolean;
14
+ export declare function ipInCidr(ip: string, cidr: string): boolean;
15
+ export declare function ipInAnyCidr(ip: string, cidrs: string[]): boolean;
16
+ export type RuleMatchContext = {
17
+ host: string;
18
+ path: string;
19
+ channel?: string | undefined;
20
+ ip?: string | undefined;
21
+ agent?: string | undefined;
22
+ country?: string | undefined;
23
+ headers?: Record<string, string> | undefined;
24
+ };
25
+ export type RuleMatchInput = {
26
+ host?: string | undefined;
27
+ hostPattern?: string | undefined;
28
+ hostTemplate?: string | undefined;
29
+ pathPattern?: string | undefined;
30
+ channel?: string | undefined;
31
+ ipCidrs?: string[] | undefined;
32
+ agent?: string | undefined;
33
+ country?: string | undefined;
34
+ header?: {
35
+ name: string;
36
+ value: string;
37
+ } | undefined;
38
+ };
39
+ export declare function ruleMatchApplies(match: RuleMatchInput, context: RuleMatchContext): boolean;