@spacefast/common 0.0.11 → 0.0.13

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 (160) hide show
  1. package/dist/agents/connect-targets.d.ts +4 -4
  2. package/dist/agents/connect-targets.js +3 -3
  3. package/dist/agents/private-key-oauth.d.ts +37 -0
  4. package/dist/agents/private-key-oauth.js +158 -0
  5. package/dist/config/domains.js +1 -1
  6. package/dist/config/index.d.ts +1 -0
  7. package/dist/config/index.js +1 -0
  8. package/dist/config/postgres-budget.d.ts +126 -0
  9. package/dist/config/postgres-budget.js +135 -0
  10. package/dist/config/postgres-budget.json +50 -0
  11. package/dist/contracts/access.d.ts +386 -1183
  12. package/dist/contracts/access.js +240 -1018
  13. package/dist/contracts/activity.d.ts +1 -1
  14. package/dist/contracts/activity.js +11 -19
  15. package/dist/contracts/api-keys.d.ts +69 -45
  16. package/dist/contracts/api-keys.js +3 -0
  17. package/dist/contracts/archives.d.ts +9 -10
  18. package/dist/contracts/archives.js +4 -6
  19. package/dist/contracts/builds.d.ts +8 -8
  20. package/dist/contracts/builds.js +28 -48
  21. package/dist/contracts/channels.js +1 -2
  22. package/dist/contracts/comments.d.ts +102 -93
  23. package/dist/contracts/comments.js +121 -63
  24. package/dist/contracts/common.d.ts +4 -3
  25. package/dist/contracts/common.js +2 -0
  26. package/dist/contracts/countries.js +2 -7
  27. package/dist/contracts/data-source-routes.d.ts +20 -0
  28. package/dist/contracts/data-source-routes.js +15 -0
  29. package/dist/contracts/deployments.d.ts +3 -3
  30. package/dist/contracts/device-auth.d.ts +21 -15
  31. package/dist/contracts/docs.d.ts +5 -5
  32. package/dist/contracts/domains.d.ts +261 -1330
  33. package/dist/contracts/domains.js +39 -301
  34. package/dist/contracts/email-preferences.d.ts +50 -0
  35. package/dist/contracts/email-preferences.js +44 -0
  36. package/dist/contracts/enums.d.ts +3 -5
  37. package/dist/contracts/enums.js +3 -8
  38. package/dist/contracts/error-code-meta.d.ts +99 -33
  39. package/dist/contracts/error-code-meta.js +36 -9
  40. package/dist/contracts/error-codes.d.ts +1 -1
  41. package/dist/contracts/error-codes.js +28 -11
  42. package/dist/contracts/execution.d.ts +212 -0
  43. package/dist/contracts/execution.js +288 -0
  44. package/dist/contracts/feature-lifecycle.d.ts +498 -2
  45. package/dist/contracts/feature-lifecycle.js +539 -2
  46. package/dist/contracts/features.d.ts +184 -74
  47. package/dist/contracts/features.js +4 -303
  48. package/dist/contracts/functions.d.ts +729 -0
  49. package/dist/contracts/functions.js +485 -0
  50. package/dist/contracts/git.d.ts +1 -1
  51. package/dist/contracts/grants.d.ts +1158 -0
  52. package/dist/contracts/grants.js +696 -0
  53. package/dist/contracts/ids.d.ts +6 -5
  54. package/dist/contracts/ids.js +6 -5
  55. package/dist/contracts/internal.d.ts +3 -3
  56. package/dist/contracts/mcp.d.ts +12 -12
  57. package/dist/contracts/me.js +1 -1
  58. package/dist/contracts/mounts.d.ts +142 -0
  59. package/dist/contracts/mounts.js +56 -0
  60. package/dist/contracts/oauth-resources.d.ts +5 -5
  61. package/dist/contracts/oauth-resources.js +2 -0
  62. package/dist/contracts/operations.d.ts +4 -4
  63. package/dist/contracts/pages.d.ts +6 -14
  64. package/dist/contracts/pages.js +11 -23
  65. package/dist/contracts/plan-policy.d.ts +2 -9
  66. package/dist/contracts/plan-policy.js +1 -4
  67. package/dist/contracts/platform.d.ts +80 -32
  68. package/dist/contracts/platform.js +59 -12
  69. package/dist/contracts/push-new.d.ts +26 -2
  70. package/dist/contracts/push-new.js +8 -0
  71. package/dist/contracts/quotas.d.ts +0 -1
  72. package/dist/contracts/quotas.js +0 -5
  73. package/dist/contracts/repository-connections.d.ts +1 -1
  74. package/dist/contracts/resources.d.ts +21 -85
  75. package/dist/contracts/resources.js +17 -47
  76. package/dist/contracts/runtime-api.d.ts +799 -192
  77. package/dist/contracts/runtime-api.js +231 -100
  78. package/dist/contracts/runtime-app.d.ts +138 -0
  79. package/dist/contracts/runtime-app.js +21 -0
  80. package/dist/contracts/sf-config-v1.d.ts +5 -0
  81. package/dist/contracts/sf-config-v1.js +1 -1
  82. package/dist/contracts/sites.d.ts +17 -12
  83. package/dist/contracts/sites.js +30 -12
  84. package/dist/contracts/space-config.d.ts +46 -117
  85. package/dist/contracts/space-config.js +323 -25
  86. package/dist/contracts/spaces.d.ts +392 -256
  87. package/dist/contracts/spaces.js +163 -83
  88. package/dist/contracts/superadmin-emails.d.ts +27 -3
  89. package/dist/contracts/superadmin-emails.js +10 -15
  90. package/dist/contracts/superadmin-runtime.d.ts +2 -2
  91. package/dist/contracts/superadmin-spaces.d.ts +19 -142
  92. package/dist/contracts/superadmin-spaces.js +7 -0
  93. package/dist/contracts/tags.d.ts +66 -36
  94. package/dist/contracts/tags.js +195 -11
  95. package/dist/contracts/teams.d.ts +9 -9
  96. package/dist/contracts/transfers.d.ts +1 -2
  97. package/dist/contracts/variables.d.ts +4 -4
  98. package/dist/contracts/variables.js +4 -3
  99. package/dist/contracts/webhooks.d.ts +2 -2
  100. package/dist/contracts/zero.d.ts +437 -193
  101. package/dist/contracts/zero.js +149 -158
  102. package/dist/dashboard-paths/index.d.ts +3 -3
  103. package/dist/dashboard-paths/index.js +1 -0
  104. package/dist/docs/agent-prose.js +10 -8
  105. package/dist/docs/agent-setup.d.ts +6 -4
  106. package/dist/docs/agent-setup.js +26 -16
  107. package/dist/docs/agent-solutions.js +1 -1
  108. package/dist/docs/catalog.d.ts +35 -37
  109. package/dist/docs/catalog.js +36 -38
  110. package/dist/docs/error-docs.js +108 -44
  111. package/dist/utils/asset-fingerprint.d.ts +11 -0
  112. package/dist/utils/asset-fingerprint.js +46 -0
  113. package/dist/utils/auth-redirect.d.ts +1 -3
  114. package/dist/utils/auth-redirect.js +1 -21
  115. package/dist/utils/build-settings.d.ts +2 -0
  116. package/dist/utils/build-settings.js +61 -9
  117. package/dist/utils/credential-policy.d.ts +1 -1
  118. package/dist/utils/credential-policy.js +4 -0
  119. package/dist/utils/dns-instructions.d.ts +29 -0
  120. package/dist/utils/dns-instructions.js +78 -0
  121. package/dist/utils/domain-diagnostics.d.ts +29 -0
  122. package/dist/utils/domain-diagnostics.js +63 -0
  123. package/dist/utils/egress-policy.fixtures.json +51 -0
  124. package/dist/utils/grants.d.ts +53 -0
  125. package/dist/utils/grants.js +160 -0
  126. package/dist/utils/id-hints.d.ts +1 -0
  127. package/dist/utils/id-hints.js +55 -13
  128. package/dist/utils/local-space-state.js +1 -0
  129. package/dist/utils/page-colors.d.ts +50 -0
  130. package/dist/utils/page-colors.js +167 -0
  131. package/dist/utils/page-fonts.d.ts +2 -0
  132. package/dist/utils/page-fonts.js +4 -0
  133. package/dist/utils/pages.d.ts +19 -6
  134. package/dist/utils/pages.js +122 -49
  135. package/dist/utils/production-runtime.d.ts +18 -0
  136. package/dist/utils/production-runtime.js +28 -0
  137. package/dist/utils/publish-policy.d.ts +34 -4
  138. package/dist/utils/publish-policy.js +132 -61
  139. package/dist/utils/query-keys.d.ts +7 -13
  140. package/dist/utils/query-keys.js +12 -18
  141. package/dist/utils/source-archive-policy.d.ts +2 -0
  142. package/dist/utils/source-archive-policy.js +2 -0
  143. package/dist/utils/space-config.d.ts +5 -1
  144. package/dist/utils/space-config.js +35 -0
  145. package/dist/utils/static-runtime-policy.d.ts +5 -0
  146. package/dist/utils/static-runtime-policy.fixtures.json +57 -0
  147. package/dist/utils/static-runtime-policy.js +54 -10
  148. package/dist/utils/upload-session.d.ts +3 -0
  149. package/dist/utils/upload-session.js +31 -0
  150. package/package.json +6 -4
  151. package/dist/contracts/annotations.d.ts +0 -327
  152. package/dist/contracts/annotations.js +0 -235
  153. package/dist/contracts/generated-feature-launch-entries.d.ts +0 -2
  154. package/dist/contracts/generated-feature-launch-entries.js +0 -518
  155. package/dist/contracts/publishes.d.ts +0 -135
  156. package/dist/contracts/publishes.js +0 -162
  157. package/dist/utils/access-match.d.ts +0 -39
  158. package/dist/utils/access-match.js +0 -296
  159. package/dist/utils/sf-config-v1.d.ts +0 -2
  160. package/dist/utils/sf-config-v1.js +0 -542
@@ -28,6 +28,10 @@ export const ERROR_DOCS = {
28
28
  summary: "The authorization request was denied by the user.",
29
29
  fix: "Restart the login flow and approve the request to continue.",
30
30
  },
31
+ access_scope_suggestion: {
32
+ summary: "Published dependencies cluster under paths that may be useful as explicit public scopes.",
33
+ fix: "If those files are safe for anyone to read, make only the suggested scopes Public. Otherwise leave access unchanged.",
34
+ },
31
35
  agent_handoff_declined: {
32
36
  summary: "The app-private agent handoff cannot be redeemed.",
33
37
  fix: "Ask the user to create a fresh handoff for this Space and client, then redeem that new link once.",
@@ -36,6 +40,10 @@ export const ERROR_DOCS = {
36
40
  summary: "This user already has the maximum number of pending handoffs for the Space.",
37
41
  fix: "Redeem or revoke an existing pending handoff for the Space before creating another.",
38
42
  },
43
+ agent_handoff_origin_unsupported: {
44
+ summary: "The dashboard origin this deployment is configured with cannot mint canonical agent handoff links.",
45
+ fix: "Point SPACEFAST_DASHBOARD_URL at a valid HTTP(S) origin; if you cannot change it, contact support.",
46
+ },
39
47
  ambiguous_space_slug: {
40
48
  summary: "The slug matches spaces in more than one of your teams, so it cannot be resolved.",
41
49
  fix: "Pass a teamRef alongside the slug, or reference the space by its spc_ id.",
@@ -169,7 +177,7 @@ export const ERROR_DOCS = {
169
177
  fix: "Upgrade the CLI to the latest release and retry.",
170
178
  },
171
179
  comment_screenshot_rate_limited: {
172
- summary: "Too many anonymous comment screenshot uploads were attempted.",
180
+ summary: "Too many comment screenshot uploads were attempted.",
173
181
  fix: "Wait for the one-minute window to reset, then retry the screenshot upload.",
174
182
  },
175
183
  config_file_too_large: {
@@ -190,11 +198,11 @@ export const ERROR_DOCS = {
190
198
  },
191
199
  continuation_unavailable: {
192
200
  summary: "This claim token can no longer be exchanged for an access token.",
193
- 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.",
201
+ fix: "If the space is claimed, ask its owner for an API key (dashboard: Account → API keys). 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.",
194
202
  },
195
203
  continuation_used: {
196
204
  summary: "This claim token was already exchanged for a durable access token.",
197
- 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.",
205
+ 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 create a new API key.",
198
206
  },
199
207
  credential_expired: {
200
208
  summary: "The credential used for this request has expired.",
@@ -220,13 +228,13 @@ export const ERROR_DOCS = {
220
228
  summary: "CSAM enforcement policy cannot be set below the mandatory account-suspend floor.",
221
229
  fix: "Set the CSAM category enforcement tier to account suspension.",
222
230
  },
223
- datacenters_unavailable: {
224
- summary: "Placement regions are temporarily unavailable.",
225
- fix: "Retry after the datacenter list has synced.",
231
+ custom_certificates_require_dedicated_site: {
232
+ summary: "Custom certificates are unavailable while this space uses shared placement.",
233
+ fix: "Move the space to dedicated placement before managing custom certificates.",
226
234
  },
227
235
  data_location_immutable: {
228
236
  summary: "This request tried to change data location through an immutable path.",
229
- fix: "Use PATCH /v1/spaces/{id} to queue a region move when region changes are supported for this space.",
237
+ fix: "Data location is fixed when the space is created and cannot be changed afterwards. Create a new space in the region you want.",
230
238
  },
231
239
  device_authorization_failed: {
232
240
  summary: "The device login request failed and cannot be completed.",
@@ -472,9 +480,9 @@ export const ERROR_DOCS = {
472
480
  summary: "Proxy routes to external upstreams are not available on the Free plan.",
473
481
  fix: "Remove the proxy rules before publishing. Still stuck? POST /v1/feedback with the error code and request id.",
474
482
  },
475
- free_headers_basic_auth_disabled: {
476
- summary: "Basic-Auth via _headers is not available on the Free plan.",
477
- fix: "Use space password protection instead. Still stuck? POST /v1/feedback with the error code and request id.",
483
+ google_play_webhook_identity_not_configured: {
484
+ summary: "Google Play Pub/Sub push authentication is not configured on this deployment.",
485
+ fix: "Configure the exact push audience and dedicated Pub/Sub service-account email before enabling RTDN delivery.",
478
486
  },
479
487
  idempotency_conflict_in_progress: {
480
488
  summary: "Another request with the same Idempotency-Key is still in flight.",
@@ -484,10 +492,6 @@ export const ERROR_DOCS = {
484
492
  summary: "The Idempotency-Key was reused with a different request body.",
485
493
  fix: "Use a fresh key for new requests; keys bind to one exact request body.",
486
494
  },
487
- immutable_version_requires_login: {
488
- summary: "This immutable version URL is past its public window and now requires login.",
489
- fix: "Sign in to view it, or promote the version to a channel for public serving.",
490
- },
491
495
  import_archive_not_uploaded: {
492
496
  summary: "The import has no uploaded archive yet.",
493
497
  fix: "Upload the archive to the import's upload target, then finalize.",
@@ -544,6 +548,10 @@ export const ERROR_DOCS = {
544
548
  summary: "A file path in the request is not a valid space path.",
545
549
  fix: "Use forward-slash relative paths without traversal segments.",
546
550
  },
551
+ invalid_google_play_webhook_identity: {
552
+ summary: "The Google Play notification did not carry a valid Pub/Sub push identity.",
553
+ fix: "Send the notification through the configured authenticated Pub/Sub push subscription.",
554
+ },
547
555
  invalid_grant: {
548
556
  summary: "The authorization grant is invalid or was already used.",
549
557
  fix: "Restart the login flow to obtain a new grant.",
@@ -660,6 +668,10 @@ export const ERROR_DOCS = {
660
668
  summary: `${BRAND.productName} no longer observes DNS control for this domain.`,
661
669
  fix: "Restore the documented DNS records, then re-run domain verification.",
662
670
  },
671
+ maintenance_in_progress: {
672
+ summary: "This change is temporarily unavailable while maintenance finishes.",
673
+ fix: "Wait for the Retry-After window, then send the same request again.",
674
+ },
663
675
  malware_detected: {
664
676
  summary: "Malware was detected in the uploaded content.",
665
677
  fix: "Remove the flagged files; contact support if you believe this is a false positive.",
@@ -829,13 +841,17 @@ export const ERROR_DOCS = {
829
841
  fix: "Wait for the publish to finish, then roll back by promoting a previous version if needed.",
830
842
  },
831
843
  publish_path_collision: {
832
- summary: "Two entries in the publish payload normalize to the same path.",
833
- fix: "Remove the duplicate; each path may appear once across files and deletes.",
844
+ summary: "Two different artifacts would serve the same URL after directory-index or clean-URL resolution.",
845
+ fix: "Rename or remove one artifact so every request route has one owner.",
834
846
  },
835
847
  publish_path_invalid: {
836
848
  summary: "A publish path is not a relative, normalized POSIX path.",
837
849
  fix: "Use forward-slash relative paths without traversal segments or control characters.",
838
850
  },
851
+ publish_reference_missing: {
852
+ summary: "Published HTML, CSS, or JavaScript references an internal path that is not in the version.",
853
+ fix: "Publish the missing artifact, or correct the reference to a route that this version serves.",
854
+ },
839
855
  publish_setup_failed: {
840
856
  summary: "Provisioning for this publish failed.",
841
857
  fix: "Retry the publish; if it persists, contact support with the requestId.",
@@ -908,17 +924,13 @@ export const ERROR_DOCS = {
908
924
  summary: "No signing key matching the token's key id was found.",
909
925
  fix: "Refresh the runtime JWKS; the signing keys may have rotated.",
910
926
  },
911
- runtime_logs_unavailable: {
912
- summary: "Server logs are not available because Spacefast serves your space as static files.",
913
- fix: "There is no running server process to log. Use the request logs in your dashboard to inspect recent traffic.",
914
- },
915
927
  runtime_management_unavailable: {
916
928
  summary: "The runtime management surface is unavailable for this site.",
917
929
  fix: "Retry shortly; if the site stays unreachable, contact support.",
918
930
  },
919
931
  runtime_not_provisioned: {
920
- summary: "The space has no provisioned runtime yet.",
921
- fix: "Wait for provisioning to finish; the operation receipt reports progress.",
932
+ summary: "The space has not served a published version yet, so it has no runtime data to read.",
933
+ fix: "Publish a version first. If a publish is already running, wait for it the operation receipt reports progress.",
922
934
  },
923
935
  runtime_operation_missing: {
924
936
  summary: "The runtime operation referenced by this request was not found.",
@@ -960,14 +972,14 @@ export const ERROR_DOCS = {
960
972
  summary: "A secret variable was referenced in a template, which is blocked.",
961
973
  fix: "Templates may only substitute non-secret variables; remove the secret reference.",
962
974
  },
975
+ service_signature_invalid: {
976
+ summary: "The service request signature could not be verified.",
977
+ fix: "Sign the exact request method, path, body digest, timestamp, and a fresh nonce.",
978
+ },
963
979
  site_already_deleted: {
964
980
  summary: "The site was already deleted.",
965
981
  fix: "No action needed; the site is gone.",
966
982
  },
967
- site_capacity_exceeded: {
968
- summary: "The site has reached its capacity and cannot take more content.",
969
- fix: "Retry shortly; the platform rebalances spaces onto new sites automatically.",
970
- },
971
983
  site_has_live_spaces: {
972
984
  summary: "The site still has live spaces assigned to it, so it cannot be deleted.",
973
985
  fix: "Delete the live spaces or move them to another site before deleting this site.",
@@ -1000,10 +1012,26 @@ export const ERROR_DOCS = {
1000
1012
  summary: "The slug is already in use within the relevant ownership scope.",
1001
1013
  fix: "Choose another slug or use the available suggestion returned by the API.",
1002
1014
  },
1015
+ source_archive_decompression_timeout: {
1016
+ summary: "The uploaded source archive did not finish decompressing within the validation limit.",
1017
+ fix: "Reduce the archive's compressed complexity or split it into a smaller source upload, then retry.",
1018
+ },
1019
+ source_archive_expansion_ratio_exceeded: {
1020
+ summary: "The uploaded source archive expands too much relative to its compressed size.",
1021
+ fix: "Rebuild the archive without highly compressible filler or generated content, then upload it again.",
1022
+ },
1023
+ source_archive_validation_busy: {
1024
+ summary: "The service is already validating its maximum number of source archives.",
1025
+ fix: "Wait briefly and retry the upload.",
1026
+ },
1003
1027
  space_already_claimed: {
1004
1028
  summary: "The space was already claimed; a claim can only succeed once.",
1005
1029
  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.",
1006
1030
  },
1031
+ space_capacity_warming: {
1032
+ summary: "This space is waiting on serving capacity that is being provisioned in the background.",
1033
+ fix: "Wait for the Retry-After window, then send the same publish again. No version was created and no files were uploaded.",
1034
+ },
1007
1035
  space_claim_unavailable: {
1008
1036
  summary: "This space cannot be claimed.",
1009
1037
  fix: "Only anonymous, unexpired spaces with a valid claim token can be claimed.",
@@ -1048,6 +1076,10 @@ export const ERROR_DOCS = {
1048
1076
  summary: "The export was produced by an unsupported runtime schema version.",
1049
1077
  fix: "Re-export from a current runtime, or upgrade before exporting.",
1050
1078
  },
1079
+ space_move_would_strand_zero_data: {
1080
+ summary: "The Space runs Zero, whose database lives on the site the Space is placed on. Relocating it would create an empty database on the new site and leave every row behind, so the move is refused.",
1081
+ fix: "Nothing was moved and no data was lost. Migrating Zero data between sites is not implemented; contact support if the Space genuinely has to be relocated.",
1082
+ },
1051
1083
  space_moving: {
1052
1084
  summary: "The space is moving between sites, which blocks this operation.",
1053
1085
  fix: "Wait for the move to finish, then retry.",
@@ -1088,6 +1120,34 @@ export const ERROR_DOCS = {
1088
1120
  summary: "This control file is not supported by the static runtime.",
1089
1121
  fix: "Remove the file; see the routing docs for supported convention files.",
1090
1122
  },
1123
+ static_mount_path_conflict: {
1124
+ summary: "The requested mount path overlaps another static mount on this space.",
1125
+ fix: "Choose a path that is not equal to, above, or below an existing mount path.",
1126
+ },
1127
+ static_mount_source_not_ready: {
1128
+ summary: "The website version that owns this mount is not ready.",
1129
+ fix: "Wait for the website version to finish finalizing, then retry.",
1130
+ },
1131
+ static_mount_target_forbidden: {
1132
+ summary: "The target space is not an authorized space in the same team.",
1133
+ fix: "Choose another space in the source space's team and authenticate with read access to its versions.",
1134
+ },
1135
+ static_mount_target_in_use: {
1136
+ summary: "A static mount dependency blocks changing or deleting this space.",
1137
+ fix: "Remove the reported static mount before retrying the operation.",
1138
+ },
1139
+ static_mount_target_not_live: {
1140
+ summary: "The target space does not have a production version to mount.",
1141
+ fix: "Publish or promote a ready version on the target space, then retry.",
1142
+ },
1143
+ static_mount_target_not_ready: {
1144
+ summary: "The target production version is not ready for static delivery.",
1145
+ fix: "Wait for the target version to finish finalizing, then retry.",
1146
+ },
1147
+ static_mount_target_not_static: {
1148
+ summary: "The target production version contains runtime functions.",
1149
+ fix: "Promote a fully static target version or serve the dynamic application without a static mount.",
1150
+ },
1091
1151
  static_runtime_control_path_not_supported: {
1092
1152
  summary: "This control path is not supported by the static runtime.",
1093
1153
  fix: "Remove the path from the upload.",
@@ -1230,11 +1290,7 @@ export const ERROR_DOCS = {
1230
1290
  },
1231
1291
  upload_path_not_declared: {
1232
1292
  summary: "An uploaded path was not declared in the version's manifest.",
1233
- fix: "Declare every path up front, or use an open session for incremental uploads.",
1234
- },
1235
- upload_session_cap_exceeded: {
1236
- summary: "The open upload session exceeded its file or byte cap.",
1237
- fix: "Stay within the session caps, or declare a manifest for large publishes.",
1293
+ fix: "Declare every path up front.",
1238
1294
  },
1239
1295
  upload_size_mismatch: {
1240
1296
  summary: "An uploaded file's size does not match the declared size.",
@@ -1368,10 +1424,6 @@ export const ERROR_DOCS = {
1368
1424
  summary: "The Zero endpoint artifact could not be parsed.",
1369
1425
  fix: "Rebuild the Zero project; do not edit generated artifact JSON by hand.",
1370
1426
  },
1371
- zero_artifact_missing: {
1372
- summary: "A Zero route points to an endpoint artifact that is missing.",
1373
- fix: "Declare the endpoint in zero_endpoints, then rebuild and publish again.",
1374
- },
1375
1427
  zero_artifact_path_invalid: {
1376
1428
  summary: "The Zero endpoint artifact path is invalid.",
1377
1429
  fix: "Rebuild the Zero routes so all artifact paths stay inside the version bundle.",
@@ -1380,10 +1432,6 @@ export const ERROR_DOCS = {
1380
1432
  summary: "The Zero endpoint artifact could not be read by the runtime.",
1381
1433
  fix: "Verify the version finalized with all generated Zero files present.",
1382
1434
  },
1383
- zero_artifact_untrusted: {
1384
- summary: "A Zero route points to an uploaded artifact that the runtime did not compile.",
1385
- fix: "Declare the endpoint in zero_endpoints so finalize generates trusted bytecode.",
1386
- },
1387
1435
  zero_auth_unavailable: {
1388
1436
  summary: "Hosted Zero auth is not configured for this deployment.",
1389
1437
  fix: "Finalize the Zero version with hosted auth URLs or use guest/local auth.",
@@ -1472,6 +1520,10 @@ export const ERROR_DOCS = {
1472
1520
  summary: "The Zero database operation has too many parameters.",
1473
1521
  fix: "Reduce the number of bound parameters or split the operation.",
1474
1522
  },
1523
+ zero_db_transaction_active: {
1524
+ summary: "The Zero runner tried to start a database transaction while one was already active.",
1525
+ fix: "Rebuild with the current Zero runner and report the failure if it repeats.",
1526
+ },
1475
1527
  zero_db_transaction_commit_failed: {
1476
1528
  summary: "The Zero database transaction could not be committed.",
1477
1529
  fix: "Retry after checking database connectivity and transaction conflicts.",
@@ -1480,6 +1532,14 @@ export const ERROR_DOCS = {
1480
1532
  summary: "The Zero database transaction mode is invalid.",
1481
1533
  fix: "Use a supported generated transaction mode.",
1482
1534
  },
1535
+ zero_db_transaction_missing: {
1536
+ summary: "The Zero runner tried to finish a database transaction that was not active.",
1537
+ fix: "Rebuild with the current Zero runner and report the failure if it repeats.",
1538
+ },
1539
+ zero_db_transaction_rollback_failed: {
1540
+ summary: "The Zero database transaction could not be rolled back cleanly.",
1541
+ fix: "Inspect the affected database state before retrying, then report the failure.",
1542
+ },
1483
1543
  zero_db_transaction_start_failed: {
1484
1544
  summary: "The Zero database transaction could not be started.",
1485
1545
  fix: "Check database connectivity and retry the mutation.",
@@ -1586,11 +1646,7 @@ export const ERROR_DOCS = {
1586
1646
  },
1587
1647
  zero_log_query_invalid: {
1588
1648
  summary: "The Zero log query parameters are invalid.",
1589
- fix: "Use valid cursor, limit, mutationName, and requestId parameters.",
1590
- },
1591
- zero_lookup_invalid: {
1592
- summary: "The Zero lookup map contains an invalid path or action.",
1593
- fix: "Use normalized relative paths and valid finalized Zero actions.",
1649
+ fix: "Use valid cursor, limit, handlerName, and requestId parameters.",
1594
1650
  },
1595
1651
  zero_method_not_allowed: {
1596
1652
  summary: "The request method is not allowed for this Zero endpoint.",
@@ -1648,6 +1704,14 @@ export const ERROR_DOCS = {
1648
1704
  summary: "The Zero request body exceeds the runtime size limit.",
1649
1705
  fix: "Send a smaller request body or move large payloads to blob/object storage.",
1650
1706
  },
1707
+ zero_response_header_forbidden: {
1708
+ summary: "A Zero endpoint attempted to set a platform-managed response header.",
1709
+ fix: "Remove the reserved response header from the endpoint response.",
1710
+ },
1711
+ zero_response_header_invalid: {
1712
+ summary: "A Zero endpoint response header is invalid or exceeds the header limits.",
1713
+ fix: "Use ASCII header names, keep values under the size limits, and avoid duplicate names.",
1714
+ },
1651
1715
  zero_response_too_large: {
1652
1716
  summary: "The Zero endpoint response exceeds the runtime size limit.",
1653
1717
  fix: "Return a smaller response body or paginate the data.",
@@ -31,6 +31,17 @@ export type FingerprintPlan = {
31
31
  reason: FingerprintSkipReason;
32
32
  }>;
33
33
  };
34
+ export type StaticDocumentDependency = {
35
+ sourcePath: string;
36
+ targetPath: string;
37
+ };
38
+ /**
39
+ * Advisory-only dependency discovery used by finalize diagnostics. It shares
40
+ * the exact HTML/CSS tokenizer and URL resolver with asset fingerprinting, then
41
+ * adds conservative static JS imports and page links. It never rewrites bytes
42
+ * and never changes access automatically.
43
+ */
44
+ export declare function scanStaticDocumentDependencies(sourcePath: string, text: string): StaticDocumentDependency[];
34
45
  export declare function planAssetFingerprints(input: {
35
46
  files: readonly FingerprintCandidateFile[];
36
47
  /** sha256 as lowercase hex over UTF-8 bytes of `text`. */
@@ -48,6 +48,52 @@ const FINGERPRINT_ASSET_EXTENSIONS = new Set([
48
48
  // no whitespace. Anything else stays on the default lane.
49
49
  const SAFE_PATH_PATTERN = /^[A-Za-z0-9/_.-]+$/;
50
50
  const SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
51
+ const HTML_ANCHOR_HREF_PATTERN = /<a\b[^>]*\bhref\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/giu;
52
+ const JS_STATIC_REFERENCE_PATTERN = /(?:\b(?:import|export)\s+(?:[^"'()]*?\s+from\s+)?|\bimport\s*\(|\bnew\s+URL\s*\()\s*["']([^"']+)["']/gu;
53
+ const SOURCE_MAP_REFERENCE_PATTERN = /[#@]\s*sourceMappingURL=([^\s*]+)/gu;
54
+ /**
55
+ * Advisory-only dependency discovery used by finalize diagnostics. It shares
56
+ * the exact HTML/CSS tokenizer and URL resolver with asset fingerprinting, then
57
+ * adds conservative static JS imports and page links. It never rewrites bytes
58
+ * and never changes access automatically.
59
+ */
60
+ export function scanStaticDocumentDependencies(sourcePath, text) {
61
+ const extension = pathExtensionOf(sourcePath);
62
+ const rawUrls = [];
63
+ if (extension === "html" || extension === "htm") {
64
+ const html = scanHtml(text);
65
+ rawUrls.push(...html.refs.map((ref) => ref.url));
66
+ for (const range of html.cssRanges) {
67
+ rawUrls.push(...scanCssRefs(range.css, range.offset).map((ref) => ref.url));
68
+ }
69
+ for (const match of text.matchAll(HTML_ANCHOR_HREF_PATTERN)) {
70
+ const url = match[1] ?? match[2] ?? match[3];
71
+ if (url)
72
+ rawUrls.push(url);
73
+ }
74
+ }
75
+ else if (extension === "css") {
76
+ rawUrls.push(...scanCssRefs(text, 0).map((ref) => ref.url));
77
+ }
78
+ else if (extension === "js" || extension === "mjs" || extension === "cjs") {
79
+ for (const match of text.matchAll(JS_STATIC_REFERENCE_PATTERN)) {
80
+ if (match[1])
81
+ rawUrls.push(match[1]);
82
+ }
83
+ for (const match of text.matchAll(SOURCE_MAP_REFERENCE_PATTERN)) {
84
+ if (match[1])
85
+ rawUrls.push(match[1]);
86
+ }
87
+ }
88
+ const baseDir = parentDir(sourcePath);
89
+ return [
90
+ ...new Set(rawUrls
91
+ .map((url) => resolveReference(baseDir, url))
92
+ .filter((targetPath) => targetPath !== null)),
93
+ ]
94
+ .toSorted()
95
+ .map((targetPath) => ({ sourcePath, targetPath }));
96
+ }
51
97
  export function planAssetFingerprints(input) {
52
98
  const covered = input.pathCoveredByUserCacheControl ?? (() => false);
53
99
  const excluded = input.excludePath ?? (() => false);
@@ -1,3 +1 @@
1
- export declare function sanitizeDashboardReturnTo(returnTo: string | null | undefined, options?: {
2
- apiOrigin?: string | null;
3
- }): string | undefined;
1
+ export declare function sanitizeDashboardReturnTo(returnTo: string | null | undefined): string | undefined;
@@ -17,29 +17,9 @@ function hasUnsafeReturnToChars(value) {
17
17
  }
18
18
  return false;
19
19
  }
20
- // The ONE absolute-URL exception to the same-origin returnTo policy
21
- // (access-plan X-41): the api-origin GET /v1/access/authorize URL exactly —
22
- // the sign-in leg of the visitor redirect chain. Everything else absolute is
23
- // an open-redirect surface and stays rejected.
24
- const API_AUTHORIZE_PATH = "/v1/access/authorize";
25
- export function sanitizeDashboardReturnTo(returnTo, options) {
20
+ export function sanitizeDashboardReturnTo(returnTo) {
26
21
  const normalized = returnTo?.trim();
27
22
  const decoded = normalized ? decodedReturnTo(normalized) : null;
28
- if (normalized && decoded && options?.apiOrigin) {
29
- try {
30
- const candidate = new URL(normalized);
31
- const apiOrigin = new URL(options.apiOrigin).origin;
32
- if (candidate.origin === apiOrigin &&
33
- candidate.pathname === API_AUTHORIZE_PATH &&
34
- !hasUnsafeReturnToChars(normalized) &&
35
- !hasUnsafeReturnToChars(decoded)) {
36
- return candidate.toString();
37
- }
38
- }
39
- catch {
40
- // Not an absolute URL — fall through to the same-origin path rules.
41
- }
42
- }
43
23
  if (!normalized ||
44
24
  !decoded ||
45
25
  !normalized.startsWith("/") ||
@@ -1,6 +1,8 @@
1
1
  export type BuildSettingsInput = {
2
2
  fileNames: Iterable<string>;
3
3
  packageJson?: string | null | undefined;
4
+ jekyllYaml?: string | null | undefined;
5
+ jekyllToml?: string | null | undefined;
4
6
  vercelJson?: string | null | undefined;
5
7
  netlifyToml?: string | null | undefined;
6
8
  wranglerToml?: string | null | undefined;
@@ -1,3 +1,4 @@
1
+ import { load as parseYaml } from "js-yaml";
1
2
  import { parse as parseToml } from "smol-toml";
2
3
  export const BUILD_ANALYZER_CANDIDATE_ROOTS = ["apps", "packages", "sites", "docs"];
3
4
  const PACKAGE_MANAGER_ONLY_FILES = new Set([
@@ -7,6 +8,8 @@ const PACKAGE_MANAGER_ONLY_FILES = new Set([
7
8
  "pnpm-lock.yaml",
8
9
  "yarn.lock",
9
10
  "package-lock.json",
11
+ "Gemfile",
12
+ "Gemfile.lock",
10
13
  ]);
11
14
  export function hasWorkspaceSignal(fileNames, packageJsonText) {
12
15
  const names = new Set(fileNames);
@@ -102,6 +105,20 @@ function parseTomlObject(value) {
102
105
  return null;
103
106
  }
104
107
  }
108
+ function parseYamlObject(value) {
109
+ if (!value) {
110
+ return null;
111
+ }
112
+ try {
113
+ const parsed = parseYaml(value);
114
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
115
+ ? parsed
116
+ : null;
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
105
122
  export function stringField(value, key) {
106
123
  const field = value?.[key];
107
124
  return typeof field === "string" && field.trim() ? field.trim() : null;
@@ -628,9 +645,8 @@ const FRAMEWORKS = [
628
645
  },
629
646
  {
630
647
  preset: "jekyll",
631
- configFiles: ["_config.yml", "_config.yaml"],
648
+ configFiles: ["_config.yml", "_config.yaml", "_config.toml"],
632
649
  outputDirectory: "_site",
633
- defaultBuildCommand: "bundle exec jekyll build",
634
650
  },
635
651
  {
636
652
  preset: "mkdocs",
@@ -675,6 +691,26 @@ function outputDirectoryForFramework(frameworkPreset, files) {
675
691
  return framework.outputDirectory;
676
692
  return files.has("dist") ? "dist" : null;
677
693
  }
694
+ const JEKYLL_BUNDLE_PATH = ".spacefast/cache/jekyll-bundle";
695
+ const JEKYLL_GEM_HOME = ".spacefast/cache/jekyll-gems";
696
+ function jekyllInstallCommand(files) {
697
+ return files.has("Gemfile")
698
+ ? `BUNDLE_PATH=${JEKYLL_BUNDLE_PATH} bundle install`
699
+ : `GEM_HOME=${JEKYLL_GEM_HOME} gem install jekyll --no-document`;
700
+ }
701
+ function jekyllConfigFile(files) {
702
+ return ["_config.yml", "_config.yaml", "_config.toml"].find((file) => files.has(file));
703
+ }
704
+ function jekyllBuildCommand(files) {
705
+ const command = files.has("Gemfile")
706
+ ? `JEKYLL_ENV=production BUNDLE_PATH=${JEKYLL_BUNDLE_PATH} bundle exec jekyll build`
707
+ : `JEKYLL_ENV=production GEM_HOME=${JEKYLL_GEM_HOME} ${JEKYLL_GEM_HOME}/bin/jekyll build`;
708
+ const configFile = jekyllConfigFile(files);
709
+ return configFile ? `${command} --config ${configFile}` : command;
710
+ }
711
+ function frameworkInstallCommand(frameworkPreset, files) {
712
+ return frameworkPreset === "jekyll" ? jekyllInstallCommand(files) : null;
713
+ }
678
714
  function installCommandForManager(packageManager, packageJson) {
679
715
  switch (packageManager) {
680
716
  case "bun":
@@ -687,13 +723,15 @@ function installCommandForManager(packageManager, packageJson) {
687
723
  return packageJson ? "npm ci" : null;
688
724
  }
689
725
  }
690
- function buildCommandForDefaults(packageJson, run, frameworkPreset) {
726
+ function buildCommandForDefaults(packageJson, run, frameworkPreset, files) {
691
727
  if (packageJson?.scripts?.build)
692
728
  return `${run} build`;
729
+ if (frameworkPreset === "jekyll")
730
+ return jekyllBuildCommand(files);
693
731
  return frameworkForPreset(frameworkPreset)?.defaultBuildCommand ?? null;
694
732
  }
695
- function packageDefaults(files, packageJsonText) {
696
- const packageJson = parsePackageJson(packageJsonText);
733
+ function packageDefaults(input, files) {
734
+ const packageJson = parsePackageJson(input.packageJson);
697
735
  const dependencies = {
698
736
  ...packageJson?.dependencies,
699
737
  ...packageJson?.devDependencies,
@@ -701,17 +739,26 @@ function packageDefaults(files, packageJsonText) {
701
739
  const packageManager = packageManagerForFiles(files);
702
740
  const run = packageManager === "npm" ? "npm run" : packageManager === "bun" ? "bun run" : packageManager;
703
741
  const frameworkPreset = detectFrameworkPreset(files, dependencies);
742
+ const installCommands = [
743
+ installCommandForManager(packageManager, packageJson),
744
+ frameworkInstallCommand(frameworkPreset, files),
745
+ ].filter((command) => Boolean(command));
746
+ const jekyllConfig = input.jekyllYaml
747
+ ? parseYamlObject(input.jekyllYaml)
748
+ : parseTomlObject(input.jekyllToml);
704
749
  return {
705
750
  frameworkPreset,
706
- installCommand: installCommandForManager(packageManager, packageJson),
707
- buildCommand: buildCommandForDefaults(packageJson, run, frameworkPreset),
708
- outputDirectory: outputDirectoryForFramework(frameworkPreset, files),
751
+ installCommand: installCommands.length > 0 ? installCommands.join(" && ") : null,
752
+ buildCommand: buildCommandForDefaults(packageJson, run, frameworkPreset, files),
753
+ outputDirectory: frameworkPreset === "jekyll"
754
+ ? (stringField(jekyllConfig, "destination") ?? "_site")
755
+ : outputDirectoryForFramework(frameworkPreset, files),
709
756
  };
710
757
  }
711
758
  export function detectBuildSettings(input) {
712
759
  const files = new Set(input.fileNames);
713
760
  const defaults = {
714
- ...packageDefaults(files, input.packageJson),
761
+ ...packageDefaults(input, files),
715
762
  rootDirectory: input.rootDirectory ?? null,
716
763
  platformPreset: null,
717
764
  detectedFiles: [
@@ -721,6 +768,11 @@ export function detectBuildSettings(input) {
721
768
  files.has("pnpm-lock.yaml") ? "pnpm-lock.yaml" : null,
722
769
  files.has("yarn.lock") ? "yarn.lock" : null,
723
770
  files.has("package-lock.json") ? "package-lock.json" : null,
771
+ files.has("Gemfile") ? "Gemfile" : null,
772
+ files.has("Gemfile.lock") ? "Gemfile.lock" : null,
773
+ files.has("_config.yml") ? "_config.yml" : null,
774
+ files.has("_config.yaml") ? "_config.yaml" : null,
775
+ files.has("_config.toml") ? "_config.toml" : null,
724
776
  ].filter((file) => Boolean(file)),
725
777
  };
726
778
  const vercelFramework = input.vercelJson
@@ -16,7 +16,7 @@ export type PolicyAuthorizeInput = {
16
16
  resource: string | readonly string[];
17
17
  conditions?: RequestCondition;
18
18
  };
19
- export declare const publishActions: ("spaces:read" | "spaces:create" | "spaces:write" | "spaces:publish" | "versions:read" | "versions:promote" | "versions:download" | "builds:read" | "builds:create")[];
19
+ export declare const publishActions: ("spaces:read" | "spaces:write" | "spaces:create" | "spaces:publish" | "versions:read" | "versions:promote" | "versions:download" | "builds:read" | "builds:trigger" | "builds:create")[];
20
20
  export declare function compileApiKeyPreset(preset: ApiKeyPreset, input: PolicyCompileInput): ApiCredentialPolicy;
21
21
  /** Expand a named API-key preset into the finite permissions sent on the public wire contract. */
22
22
  export declare function apiKeyPresetPermissions(preset: ApiKeyPreset): StatticAction[];
@@ -8,10 +8,12 @@ export const publishActions = [
8
8
  "versions:promote",
9
9
  "versions:download",
10
10
  "builds:read",
11
+ "builds:trigger",
11
12
  "builds:create",
12
13
  ];
13
14
  const spaceAdminActions = [
14
15
  ...publishActions,
16
+ "spaces:rename",
15
17
  "spaces:delete",
16
18
  "spaces:transfer",
17
19
  "spaces:export",
@@ -81,12 +83,14 @@ export function compileTeamRolePolicy(input) {
81
83
  "spaces:read",
82
84
  "spaces:create",
83
85
  "spaces:write",
86
+ "spaces:rename",
84
87
  "spaces:publish",
85
88
  "versions:read",
86
89
  "versions:promote",
87
90
  "versions:download",
88
91
  "domains:read",
89
92
  "builds:read",
93
+ "builds:trigger",
90
94
  "builds:create",
91
95
  "teams:read",
92
96
  "billing:read",
@@ -0,0 +1,29 @@
1
+ import { type DnsInstruction } from "../contracts/common.js";
2
+ export type AddressDnsInstruction = DnsInstruction & {
3
+ type: "A" | "AAAA";
4
+ };
5
+ export type UnsupportedAddressDnsRecord = {
6
+ type: "A" | "AAAA";
7
+ name: string;
8
+ value: string;
9
+ };
10
+ export declare function addressDnsInstructionsForHostname(input: {
11
+ hostname: string;
12
+ dnsInstructions: unknown[];
13
+ }): AddressDnsInstruction[];
14
+ export declare function isWpCloudInboundIpv4(value: string): boolean;
15
+ export declare function addressDnsInstructionIsObserved(input: {
16
+ instruction: Pick<AddressDnsInstruction, "type" | "value">;
17
+ records: {
18
+ a: string[];
19
+ aaaa: string[];
20
+ };
21
+ }): boolean;
22
+ export declare function unsupportedAddressDnsRecordsForHostname(input: {
23
+ hostname: string;
24
+ dnsInstructions: unknown[];
25
+ records: {
26
+ a: string[];
27
+ aaaa: string[];
28
+ };
29
+ }): UnsupportedAddressDnsRecord[];