@spacefast/common 0.0.21 → 0.0.24

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 (182) hide show
  1. package/dist/agents/connect-targets.d.ts +9 -6
  2. package/dist/agents/connect-targets.js +9 -6
  3. package/dist/config/domains.d.ts +1 -1
  4. package/dist/config/domains.js +1 -0
  5. package/dist/config/index.d.ts +0 -1
  6. package/dist/config/index.js +0 -1
  7. package/dist/contracts/abuse.d.ts +2 -0
  8. package/dist/contracts/abuse.js +12 -0
  9. package/dist/contracts/access.d.ts +121 -9
  10. package/dist/contracts/access.js +73 -9
  11. package/dist/contracts/activity.d.ts +1 -1
  12. package/dist/contracts/activity.js +0 -9
  13. package/dist/contracts/api-keys.d.ts +21 -21
  14. package/dist/contracts/beta.js +1 -1
  15. package/dist/contracts/billing.d.ts +1 -34
  16. package/dist/contracts/billing.js +4 -53
  17. package/dist/contracts/builds.d.ts +8 -8
  18. package/dist/contracts/builds.js +10 -3
  19. package/dist/contracts/cli.d.ts +10 -0
  20. package/dist/contracts/cli.js +10 -0
  21. package/dist/contracts/collab-public.d.ts +63 -0
  22. package/dist/contracts/collab-public.js +46 -0
  23. package/dist/contracts/comments.d.ts +283 -54
  24. package/dist/contracts/comments.js +173 -52
  25. package/dist/contracts/common.d.ts +3 -3
  26. package/dist/contracts/device-auth.d.ts +6 -6
  27. package/dist/contracts/device-auth.js +1 -1
  28. package/dist/contracts/docs.d.ts +5 -5
  29. package/dist/contracts/domains.d.ts +36 -36
  30. package/dist/contracts/enums.d.ts +33 -30
  31. package/dist/contracts/enums.js +52 -38
  32. package/dist/contracts/error-code-meta.d.ts +37 -126
  33. package/dist/contracts/error-code-meta.js +12 -41
  34. package/dist/contracts/error-codes.d.ts +1 -1
  35. package/dist/contracts/error-codes.js +10 -32
  36. package/dist/contracts/execution.d.ts +35 -57
  37. package/dist/contracts/execution.js +41 -40
  38. package/dist/contracts/feature-lifecycle-core.d.ts +0 -6
  39. package/dist/contracts/feature-lifecycle-core.js +2 -31
  40. package/dist/contracts/feature-lifecycle.d.ts +8 -38
  41. package/dist/contracts/feature-lifecycle.js +16 -48
  42. package/dist/contracts/features.d.ts +15 -13
  43. package/dist/contracts/features.js +39 -38
  44. package/dist/contracts/functions.d.ts +97 -70
  45. package/dist/contracts/functions.js +101 -34
  46. package/dist/contracts/git.d.ts +1 -1
  47. package/dist/contracts/grants.d.ts +7 -3
  48. package/dist/contracts/grants.js +18 -9
  49. package/dist/contracts/internal.d.ts +14 -1
  50. package/dist/contracts/internal.js +17 -7
  51. package/dist/contracts/oauth-resources.d.ts +4 -3
  52. package/dist/contracts/oauth-resources.js +12 -3
  53. package/dist/contracts/operations.d.ts +90 -5
  54. package/dist/contracts/operations.js +75 -1
  55. package/dist/contracts/pages.d.ts +6 -1
  56. package/dist/contracts/pages.js +24 -1
  57. package/dist/contracts/plan-policy.d.ts +1 -3
  58. package/dist/contracts/plan-policy.js +1 -2
  59. package/dist/contracts/platform.d.ts +61 -148
  60. package/dist/contracts/platform.js +70 -126
  61. package/dist/contracts/publish-archive.d.ts +498 -0
  62. package/dist/contracts/publish-archive.js +25 -0
  63. package/dist/contracts/resources.d.ts +12 -24
  64. package/dist/contracts/resources.js +32 -12
  65. package/dist/contracts/runtime-api.d.ts +369 -175
  66. package/dist/contracts/runtime-api.js +372 -348
  67. package/dist/contracts/runtime-app.d.ts +127 -120
  68. package/dist/contracts/runtime-app.js +19 -10
  69. package/dist/contracts/runtime-db.d.ts +1 -1
  70. package/dist/contracts/runtime-services.d.ts +219 -0
  71. package/dist/contracts/runtime-services.js +437 -0
  72. package/dist/contracts/runtime-storage.d.ts +45 -32
  73. package/dist/contracts/runtime-storage.js +30 -8
  74. package/dist/contracts/space-config.d.ts +10 -16
  75. package/dist/contracts/space-config.js +14 -10
  76. package/dist/contracts/spaces.d.ts +241 -436
  77. package/dist/contracts/spaces.js +128 -145
  78. package/dist/contracts/superadmin-activity.d.ts +57 -4
  79. package/dist/contracts/superadmin-activity.js +48 -2
  80. package/dist/contracts/superadmin-search.d.ts +126 -0
  81. package/dist/contracts/superadmin-search.js +61 -0
  82. package/dist/contracts/superadmin-spaces.d.ts +358 -89
  83. package/dist/contracts/superadmin-spaces.js +97 -24
  84. package/dist/contracts/superadmin-teams.d.ts +28 -10
  85. package/dist/contracts/superadmin-teams.js +5 -8
  86. package/dist/contracts/superadmin.d.ts +0 -32
  87. package/dist/contracts/superadmin.js +3 -11
  88. package/dist/contracts/tags.d.ts +9 -9
  89. package/dist/contracts/teams.d.ts +44 -2
  90. package/dist/contracts/teams.js +43 -23
  91. package/dist/contracts/transfers.d.ts +0 -49
  92. package/dist/contracts/transfers.js +2 -6
  93. package/dist/contracts/usage.d.ts +61 -0
  94. package/dist/contracts/usage.js +64 -0
  95. package/dist/contracts/variables.d.ts +2 -7
  96. package/dist/contracts/variables.js +6 -5
  97. package/dist/contracts/webhooks.d.ts +2 -2
  98. package/dist/contracts/zero.d.ts +87 -56
  99. package/dist/contracts/zero.js +82 -20
  100. package/dist/dashboard-paths/index.d.ts +1 -1
  101. package/dist/dashboard-paths/index.js +1 -0
  102. package/dist/docs/agent-prose.d.ts +1 -1
  103. package/dist/docs/agent-prose.js +62 -66
  104. package/dist/docs/agent-setup.js +49 -23
  105. package/dist/docs/agent-solutions.d.ts +4 -4
  106. package/dist/docs/agent-solutions.js +8 -8
  107. package/dist/docs/catalog.d.ts +19 -19
  108. package/dist/docs/catalog.js +30 -19
  109. package/dist/docs/error-docs.js +63 -151
  110. package/dist/docs/skills.d.ts +3 -3
  111. package/dist/docs/skills.js +1 -1
  112. package/dist/test-helpers/fetch-stub.d.ts +16 -0
  113. package/dist/test-helpers/fetch-stub.js +24 -0
  114. package/dist/utils/build-settings.js +9 -3
  115. package/dist/utils/canonical-json.d.ts +10 -0
  116. package/dist/utils/canonical-json.js +21 -0
  117. package/dist/utils/cast-transport.d.ts +28 -0
  118. package/dist/utils/cast-transport.js +52 -0
  119. package/dist/utils/claim-token.d.ts +0 -8
  120. package/dist/utils/claim-token.js +3 -15
  121. package/dist/utils/credential-policy.d.ts +1 -1
  122. package/dist/utils/env-file.d.ts +17 -0
  123. package/dist/utils/env-file.js +96 -0
  124. package/dist/utils/error-code.d.ts +2 -0
  125. package/dist/utils/error-code.js +7 -0
  126. package/dist/utils/generate-space-name.d.ts +8 -10
  127. package/dist/utils/generate-space-name.js +206 -21
  128. package/dist/utils/grant-decision.fixtures.json +2938 -0
  129. package/dist/utils/grants.d.ts +2 -0
  130. package/dist/utils/grants.js +25 -2
  131. package/dist/utils/gravatar.d.ts +9 -0
  132. package/dist/utils/gravatar.js +31 -0
  133. package/dist/utils/idempotency.d.ts +6 -0
  134. package/dist/utils/idempotency.js +28 -0
  135. package/dist/utils/local-space-state.d.ts +1 -5
  136. package/dist/utils/local-space-state.js +7 -26
  137. package/dist/utils/page-fonts.d.ts +2 -2
  138. package/dist/utils/page-fonts.js +22 -4
  139. package/dist/utils/pages.d.ts +1 -2
  140. package/dist/utils/pages.js +21 -5
  141. package/dist/utils/publish-form-data.d.ts +12 -0
  142. package/dist/utils/publish-form-data.js +10 -0
  143. package/dist/utils/publish-policy.d.ts +20 -0
  144. package/dist/utils/publish-policy.fixtures.json +397 -0
  145. package/dist/utils/publish-policy.js +36 -19
  146. package/dist/utils/push-new.d.ts +7 -0
  147. package/dist/utils/push-new.js +7 -0
  148. package/dist/utils/query-keys.d.ts +0 -1
  149. package/dist/utils/query-keys.js +0 -1
  150. package/dist/utils/runtime-paths.d.ts +5 -0
  151. package/dist/utils/runtime-paths.js +5 -0
  152. package/dist/utils/runtime-upload-batch.d.ts +0 -5
  153. package/dist/utils/runtime-upload-batch.js +1 -27
  154. package/dist/utils/runtime-upload.d.ts +3 -13
  155. package/dist/utils/runtime-upload.js +4 -14
  156. package/dist/utils/space-config.d.ts +0 -33
  157. package/dist/utils/space-config.js +5 -326
  158. package/dist/utils/storage-policy.d.ts +1 -1
  159. package/dist/utils/storage-policy.js +3 -1
  160. package/dist/utils/structured-error.d.ts +14 -0
  161. package/dist/utils/structured-error.js +22 -0
  162. package/dist/utils/version-path.js +12 -3
  163. package/dist/vocabulary.d.ts +5 -3
  164. package/dist/vocabulary.js +13 -10
  165. package/package.json +10 -5
  166. package/dist/config/postgres-budget.d.ts +0 -129
  167. package/dist/config/postgres-budget.js +0 -140
  168. package/dist/config/postgres-budget.json +0 -51
  169. package/dist/contracts/archives.d.ts +0 -331
  170. package/dist/contracts/archives.js +0 -120
  171. package/dist/contracts/deployments.d.ts +0 -574
  172. package/dist/contracts/deployments.js +0 -97
  173. package/dist/contracts/sites.d.ts +0 -416
  174. package/dist/contracts/sites.js +0 -168
  175. package/dist/contracts/superadmin-queues.d.ts +0 -414
  176. package/dist/contracts/superadmin-queues.js +0 -202
  177. package/dist/contracts/superadmin-runtime.d.ts +0 -27
  178. package/dist/contracts/superadmin-runtime.js +0 -38
  179. package/dist/index.d.ts +0 -1
  180. package/dist/index.js +0 -1
  181. package/dist/utils/api.d.ts +0 -4
  182. package/dist/utils/api.js +0 -13
@@ -1,12 +1,13 @@
1
1
  import { defaultTreeAdapter, parse } from "parse5";
2
2
  import { SPACEFAST_WORDMARK_PATH } from "../brand-assets.js";
3
- import { CUSTOM_PAGE_IDS, PAGE_CATALOG, PAGE_ELEMENTS, PAGE_LAYOUT_FILE, PAGE_SOURCE_MAX_BYTES, SITE_PAGE_IDS, } from "../contracts/pages.js";
3
+ import { COLLAB_PAGE_ELEMENTS, COLLAB_PAGE_SOURCE, CUSTOM_PAGE_IDS, PAGE_CATALOG, PAGE_ELEMENTS, PAGE_LAYOUT_FILE, PAGE_SOURCE_MAX_BYTES, SITE_PAGE_IDS, } from "../contracts/pages.js";
4
4
  import { SPACE_CONFIG_ACCEPTED_FILES } from "../contracts/space-config.js";
5
5
  import { derivePageColors, PAGE_COLOR_DEFAULTS } from "./page-colors.js";
6
- import { PAGE_EMBEDDED_FONT_FACES, PAGE_FONT_FACES } from "./page-fonts.js";
6
+ import { PAGE_FONT_FACES, PAGE_FONT_PRELOAD_HTML } from "./page-fonts.js";
7
7
  export { PAGE_PREVIEW_QUERY, previewPageHref } from "./page-preview.js";
8
8
  const encoder = new TextEncoder();
9
9
  const knownElements = new Set(PAGE_ELEMENTS);
10
+ const collabElements = new Set(COLLAB_PAGE_ELEMENTS);
10
11
  const customPageIds = new Set(CUSTOM_PAGE_IDS);
11
12
  export function isPagePublicPath(path) {
12
13
  const lower = path.toLowerCase();
@@ -129,7 +130,14 @@ export function expandPageHtml(source, context) {
129
130
  const name = (paired ?? unary)?.toLowerCase();
130
131
  return name && knownElements.has(name) ? renderElement(name, context) : _match;
131
132
  });
132
- output = output.replaceAll("/*sf-default-fonts*/", context.embedPageFonts ? PAGE_EMBEDDED_FONT_FACES : PAGE_FONT_FACES);
133
+ if (output.includes("/*sf-default-fonts*/")) {
134
+ output = output.replaceAll("/*sf-default-fonts*/", PAGE_FONT_FACES);
135
+ // The faces point at shared font origins; preloading ahead of the inline
136
+ // stylesheet starts the cross-origin fetches with the parse.
137
+ output = /<\s*style\b/i.test(output)
138
+ ? output.replace(/<\s*style\b/i, (tag) => `${PAGE_FONT_PRELOAD_HTML}${tag}`)
139
+ : `${PAGE_FONT_PRELOAD_HTML}${output}`;
140
+ }
133
141
  const tokens = themeStyle(context.theme ?? {});
134
142
  if (tokens) {
135
143
  output = /<\s*\/\s*head\s*>/i.test(output)
@@ -179,7 +187,11 @@ export function validatePageSources(input) {
179
187
  const path = sourcePath.includes("_pages/") ? sourcePath : `_pages/${sourcePath}`;
180
188
  const filename = path.slice(path.lastIndexOf("_pages/") + 7);
181
189
  const id = filename.replace(/\.html$/i, "");
182
- if (!customPageIds.has(id) || filename !== `${id}.html`) {
190
+ // A collab layout is Space-level — one review room, one URL — so unlike the
191
+ // gate and listing pages it has no per-directory form.
192
+ if (!customPageIds.has(id) ||
193
+ filename !== `${id}.html` ||
194
+ (id === "collab" && path !== COLLAB_PAGE_SOURCE)) {
183
195
  diagnostics.push({
184
196
  severity: "error",
185
197
  code: "unknown_page_template",
@@ -204,6 +216,10 @@ export function validatePageSources(input) {
204
216
  path,
205
217
  });
206
218
  for (const element of foundElements(source)) {
219
+ // Collab elements are the browser SDK's, not the compiler's: legal in the
220
+ // review room, meaningless anywhere the SDK is not the point.
221
+ if (id === "collab" && collabElements.has(element))
222
+ continue;
207
223
  if (!knownElements.has(element))
208
224
  diagnostics.push({
209
225
  severity: "error",
@@ -361,7 +377,7 @@ export function defaultPageBody(id) {
361
377
  // The built-in palette runs through the same readability engine as pushed
362
378
  // themes, so buttons and links remain readable for every accepted accent.
363
379
  const defaultPageColors = derivePageColors({});
364
- const sharedCss = `/*sf-default-fonts*/:root{color-scheme:light dark;--sf-accent:${PAGE_COLOR_DEFAULTS.accent};--sf-bg:${PAGE_COLOR_DEFAULTS.bg};--sf-fg:${PAGE_COLOR_DEFAULTS.fg};--sf-muted:${PAGE_COLOR_DEFAULTS.muted};--sf-card:${PAGE_COLOR_DEFAULTS.card};--sf-border:${PAGE_COLOR_DEFAULTS.border};--sf-link:${defaultPageColors.link};--sf-on-accent:${defaultPageColors.onAccent};--sf-error:#a82d1a;--sf-font:"Haskoy",-apple-system,BlinkMacSystemFont,ui-sans-serif,"Segoe UI",sans-serif;--sf-display-font:"Merriweather",Georgia,serif;--sf-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace}*{box-sizing:border-box}html{min-width:320px;background:var(--sf-bg);-webkit-font-smoothing:antialiased}body{margin:0;min-height:100vh;background:var(--sf-bg);color:var(--sf-fg);font:14px/1.65 var(--sf-font)}a{color:inherit}.sf-page{min-height:100vh;display:flex;flex-direction:column;padding:clamp(22px,4vw,44px)}.sf-header{display:flex;align-items:center;min-height:32px}.sf-page-center .sf-header{justify-content:center}.sf-brand{display:inline-flex;min-width:0;align-items:center;gap:10px;color:var(--sf-fg);text-decoration:none}.sf-brand-mark{width:7px;height:7px;flex:none;background:var(--sf-accent)}.sf-logo{width:28px;height:28px;flex:none;object-fit:contain}.sf-brand strong{min-width:0;overflow-wrap:anywhere;font-size:13px;font-weight:600}.sf-main{flex:1;width:100%;padding:clamp(34px,9vh,84px) 0}.sf-page-plain .sf-main{max-width:680px}.sf-page-center .sf-main{max-width:620px;margin:auto;display:flex;flex-direction:column;align-items:center;text-align:center}.sf-eyebrow{margin:0 0 14px;color:var(--sf-muted);font:500 11px/1.5 var(--sf-mono);letter-spacing:.12em;text-transform:uppercase;overflow-wrap:anywhere}.sf-page-center .sf-eyebrow{margin-bottom:16px}h1{max-width:20ch;margin:0 0 12px;color:var(--sf-fg);font:430 clamp(1.9rem,5vw,2.8rem)/1.22 var(--sf-display-font);letter-spacing:-.012em;text-wrap:balance}.sf-copy,.sf-sub{max-width:52ch;margin:0;color:var(--sf-muted);text-wrap:pretty}.sf-inline-path{font-family:var(--sf-mono);font-size:.9em;color:var(--sf-fg);overflow-wrap:anywhere}.sf-actions{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin-top:22px}.sf-page-center .sf-actions{justify-content:center}.sf-button{display:inline-flex;min-height:44px;align-items:center;justify-content:center;border:0;background:var(--sf-accent);color:var(--sf-on-accent);padding:10px 16px;font:600 13px/1.4 var(--sf-font);text-decoration:none;cursor:pointer}.sf-ghost{color:var(--sf-muted);text-underline-offset:3px}.sf-button:hover{filter:brightness(1.06)}a:focus-visible,button:focus-visible{outline:2px solid var(--sf-link);outline-offset:2px}.sf-copy+.sf-copy{margin-top:12px}.sf-files{width:100%;margin:24px 0 0;padding:0;list-style:none}.sf-files li{display:flex;min-width:0;align-items:baseline;gap:18px;border-bottom:1px solid var(--sf-border)}.sf-files a{min-width:0;flex:1;padding:10px 2px;color:var(--sf-fg);font-weight:500;text-decoration:none}.sf-files a:hover{color:var(--sf-link)}.sf-file-name{overflow-wrap:anywhere}.sf-file-size{flex:none;padding:10px 2px;color:var(--sf-muted);font:12px/1.5 var(--sf-mono);white-space:nowrap}.sf-empty{max-width:420px;margin:24px 0 0;border:1px dashed var(--sf-border);padding:18px 20px;color:var(--sf-muted)}.sf-preview-wrap{width:min(100%,560px);aspect-ratio:16/9;margin:10px 0 18px;overflow:hidden;background:#fff;outline:1px solid color-mix(in srgb,var(--sf-fg) 10%,transparent);outline-offset:-1px}.sf-preview{display:block;width:100%;height:100%;border:0;object-fit:contain}.sf-file-meta{width:min(100%,560px);margin:0}.sf-file-meta div{display:flex;min-width:0;justify-content:space-between;gap:20px;border-bottom:1px solid var(--sf-border);padding:9px 2px}.sf-file-meta dt{color:var(--sf-fg);font-weight:600}.sf-file-meta dd{min-width:0;margin:0;color:var(--sf-muted);font-family:var(--sf-mono);overflow-wrap:anywhere;text-align:right}.sf-colophon{display:flex;flex-direction:column;align-items:center;gap:10px;padding:44px 0 26px;margin-top:auto;color:var(--sf-muted)}.sf-page-plain .sf-colophon{align-items:flex-start}.sf-colophon-row{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.sf-powered{display:inline-flex;align-items:center;gap:10px;cursor:pointer;outline:none}.sf-powered-line{display:none;font-size:12px;color:var(--sf-muted)}.sf-powered:hover .sf-powered-line,.sf-powered:focus .sf-powered-line,.sf-powered:focus-within .sf-powered-line{display:inline}.sf-powered-line a{color:var(--sf-link);text-decoration:underline;text-underline-offset:3px}.sf-help{font-size:12px;color:var(--sf-muted);text-decoration:underline;text-underline-offset:3px}.sf-help:hover{color:var(--sf-fg)}.sf-wordmark{display:block;flex:none;width:auto;height:11px}.sf-wordmark-shadow{fill:var(--sf-accent)}.sf-wordmark-plate{fill:#141419}.sf-wordmark-paper{fill:#fbf8f1}@media(max-width:520px){.sf-page{padding:20px}.sf-button{min-height:48px}.sf-file-meta div{flex-direction:column;gap:2px}.sf-file-meta dd{text-align:left}.sf-colophon{padding-top:32px}}@media(prefers-color-scheme:dark){:root{--sf-bg:${PAGE_COLOR_DEFAULTS.darkBg};--sf-fg:${PAGE_COLOR_DEFAULTS.darkFg};--sf-muted:${PAGE_COLOR_DEFAULTS.darkMuted};--sf-card:${PAGE_COLOR_DEFAULTS.darkCard};--sf-border:${PAGE_COLOR_DEFAULTS.darkBorder};--sf-link:${defaultPageColors.linkDark};--sf-error:#ff8a7a}.sf-preview-wrap{outline-color:#ffffff1a}}@media(forced-colors:active){.sf-brand-mark{background:CanvasText}.sf-button{border:1px solid ButtonText}.sf-powered:focus{outline:1px solid CanvasText;outline-offset:3px}}`;
380
+ const sharedCss = `/*sf-default-fonts*/:root{color-scheme:light dark;--sf-accent:${PAGE_COLOR_DEFAULTS.accent};--sf-bg:${PAGE_COLOR_DEFAULTS.bg};--sf-fg:${PAGE_COLOR_DEFAULTS.fg};--sf-muted:${PAGE_COLOR_DEFAULTS.muted};--sf-card:${PAGE_COLOR_DEFAULTS.card};--sf-border:${PAGE_COLOR_DEFAULTS.border};--sf-link:${defaultPageColors.link};--sf-on-accent:${defaultPageColors.onAccent};--sf-error:#a82d1a;--sf-font:"Haskoy",-apple-system,BlinkMacSystemFont,ui-sans-serif,"Segoe UI",sans-serif;--sf-display-font:"Recoleta",Georgia,serif;--sf-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace}*{box-sizing:border-box}html{min-width:320px;background:var(--sf-bg);-webkit-font-smoothing:antialiased}body{margin:0;min-height:100vh;background:var(--sf-bg);color:var(--sf-fg);font:14px/1.65 var(--sf-font)}a{color:inherit}.sf-page{min-height:100vh;display:flex;flex-direction:column;padding:clamp(22px,4vw,44px)}.sf-header{display:flex;align-items:center;min-height:32px}.sf-page-center .sf-header{justify-content:center}.sf-brand{display:inline-flex;min-width:0;align-items:center;gap:10px;color:var(--sf-fg);text-decoration:none}.sf-brand-mark{width:7px;height:7px;flex:none;background:var(--sf-accent)}.sf-logo{width:28px;height:28px;flex:none;object-fit:contain}.sf-brand strong{min-width:0;overflow-wrap:anywhere;font-size:13px;font-weight:600}.sf-main{flex:1;width:100%;padding:clamp(34px,9vh,84px) 0}.sf-page-plain .sf-main{max-width:680px}.sf-page-center .sf-main{max-width:620px;margin:auto;display:flex;flex-direction:column;align-items:center;text-align:center}.sf-eyebrow{margin:0 0 14px;color:var(--sf-muted);font:500 11px/1.5 var(--sf-mono);letter-spacing:.12em;text-transform:uppercase;overflow-wrap:anywhere}.sf-page-center .sf-eyebrow{margin-bottom:16px}h1{max-width:20ch;margin:0 0 12px;color:var(--sf-fg);font:400 clamp(1.9rem,5vw,2.8rem)/1.22 var(--sf-display-font);letter-spacing:-.012em;text-wrap:balance}.sf-copy,.sf-sub{max-width:52ch;margin:0;color:var(--sf-muted);text-wrap:pretty}.sf-inline-path{font-family:var(--sf-mono);font-size:.9em;color:var(--sf-fg);overflow-wrap:anywhere}.sf-actions{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin-top:22px}.sf-page-center .sf-actions{justify-content:center}.sf-button{display:inline-flex;min-height:44px;align-items:center;justify-content:center;border:0;background:var(--sf-accent);color:var(--sf-on-accent);padding:10px 16px;font:600 13px/1.4 var(--sf-font);text-decoration:none;cursor:pointer}.sf-ghost{color:var(--sf-muted);text-underline-offset:3px}.sf-button:hover{filter:brightness(1.06)}a:focus-visible,button:focus-visible{outline:2px solid var(--sf-link);outline-offset:2px}.sf-copy+.sf-copy{margin-top:12px}.sf-files{width:100%;margin:24px 0 0;padding:0;list-style:none}.sf-files li{display:flex;min-width:0;align-items:baseline;gap:18px;border-bottom:1px solid var(--sf-border)}.sf-files a{min-width:0;flex:1;padding:10px 2px;color:var(--sf-fg);font-weight:500;text-decoration:none}.sf-files a:hover{color:var(--sf-link)}.sf-file-name{overflow-wrap:anywhere}.sf-file-size{flex:none;padding:10px 2px;color:var(--sf-muted);font:12px/1.5 var(--sf-mono);white-space:nowrap}.sf-empty{max-width:420px;margin:24px 0 0;border:1px dashed var(--sf-border);padding:18px 20px;color:var(--sf-muted)}.sf-preview-wrap{width:min(100%,560px);aspect-ratio:16/9;margin:10px 0 18px;overflow:hidden;background:#fff;outline:1px solid color-mix(in srgb,var(--sf-fg) 10%,transparent);outline-offset:-1px}.sf-preview{display:block;width:100%;height:100%;border:0;object-fit:contain}.sf-file-meta{width:min(100%,560px);margin:0}.sf-file-meta div{display:flex;min-width:0;justify-content:space-between;gap:20px;border-bottom:1px solid var(--sf-border);padding:9px 2px}.sf-file-meta dt{color:var(--sf-fg);font-weight:600}.sf-file-meta dd{min-width:0;margin:0;color:var(--sf-muted);font-family:var(--sf-mono);overflow-wrap:anywhere;text-align:right}.sf-colophon{display:flex;flex-direction:column;align-items:center;gap:10px;padding:44px 0 26px;margin-top:auto;color:var(--sf-muted)}.sf-page-plain .sf-colophon{align-items:flex-start}.sf-colophon-row{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.sf-powered{display:inline-flex;align-items:center;gap:10px;cursor:pointer;outline:none}.sf-powered-line{display:none;font-size:12px;color:var(--sf-muted)}.sf-powered:hover .sf-powered-line,.sf-powered:focus .sf-powered-line,.sf-powered:focus-within .sf-powered-line{display:inline}.sf-powered-line a{color:var(--sf-link);text-decoration:underline;text-underline-offset:3px}.sf-help{font-size:12px;color:var(--sf-muted);text-decoration:underline;text-underline-offset:3px}.sf-help:hover{color:var(--sf-fg)}.sf-wordmark{display:block;flex:none;width:auto;height:11px}.sf-wordmark-shadow{fill:var(--sf-accent)}.sf-wordmark-plate{fill:#141419}.sf-wordmark-paper{fill:#fbf8f1}@media(max-width:520px){.sf-page{padding:20px}.sf-button{min-height:48px}.sf-file-meta div{flex-direction:column;gap:2px}.sf-file-meta dd{text-align:left}.sf-colophon{padding-top:32px}}@media(prefers-color-scheme:dark){:root{--sf-bg:${PAGE_COLOR_DEFAULTS.darkBg};--sf-fg:${PAGE_COLOR_DEFAULTS.darkFg};--sf-muted:${PAGE_COLOR_DEFAULTS.darkMuted};--sf-card:${PAGE_COLOR_DEFAULTS.darkCard};--sf-border:${PAGE_COLOR_DEFAULTS.darkBorder};--sf-link:${defaultPageColors.linkDark};--sf-error:#ff8a7a}.sf-preview-wrap{outline-color:#ffffff1a}}@media(forced-colors:active){.sf-brand-mark{background:CanvasText}.sf-button{border:1px solid ButtonText}.sf-powered:focus{outline:1px solid CanvasText;outline-offset:3px}}`;
365
381
  const accessCss = `.sf-page.access .sf-main{max-width:26rem;padding:clamp(42px,8vh,72px) 0}.sf-page.access h1{max-width:18ch;margin-bottom:14px;font:600 clamp(2rem,7vw,2.65rem)/1.12 var(--sf-font);letter-spacing:-.035em}.sf-page.access .sf-copy{font-size:15px;line-height:1.6}.sf-access-default{display:flex;width:100%;flex-direction:column;align-items:center}.sf-access-status{padding:10px 12px;border:1px solid color-mix(in srgb,var(--sf-fg) 10%,transparent);border-radius:8px;background:color-mix(in srgb,var(--sf-fg) 4%,transparent);color:var(--sf-fg)}.sf-access-lanes{display:flex;flex-direction:column;gap:16px;width:min(23rem,100%);margin-top:30px;text-align:left}.sf-access-lanes form{display:flex;flex-direction:column;gap:14px;margin:0}.sf-input{box-sizing:border-box;width:100%;min-height:46px;padding:11px 12px;border:1px solid color-mix(in srgb,var(--sf-fg) 18%,transparent);border-radius:8px;outline:2px solid transparent;outline-offset:-1px;background:color-mix(in srgb,var(--sf-bg) 92%,var(--sf-fg));color:var(--sf-fg);font:500 15px/1.45 var(--sf-font);appearance:none}.sf-input::placeholder{color:color-mix(in srgb,var(--sf-muted) 82%,transparent);font:inherit}.sf-input:hover{border-color:color-mix(in srgb,var(--sf-fg) 34%,transparent)}.sf-input:focus-visible{border-color:var(--sf-accent);outline-color:var(--sf-accent)}textarea.sf-input{min-height:92px;resize:vertical}.sf-label{color:var(--sf-fg);font:600 13px/1.4 var(--sf-font)}.sf-access-lanes .sf-button{width:100%;min-height:46px;border-radius:8px}.sf-access-or{display:flex;align-items:center;gap:12px;color:var(--sf-muted);font-size:13px}.sf-access-or:before,.sf-access-or:after{content:"";flex:1;border-top:1px solid color-mix(in srgb,var(--sf-fg) 12%,transparent)}.sf-error{margin:0;color:var(--sf-error);font-size:14px}.sf-access-password-row{display:flex;gap:8px}.sf-access-password-row .sf-input{min-width:0;flex:1}.sf-access-password-row .sf-button{width:auto;flex:none}.sf-access-request{padding-top:2px}.sf-access-request summary{padding:4px 0;cursor:pointer;color:var(--sf-muted);font:550 14px/1.5 var(--sf-font)}.sf-access-request summary:hover{color:var(--sf-fg)}.sf-access-request[open] summary{color:var(--sf-fg)}.sf-access-request form{margin-top:16px}@media(max-width:520px){.sf-page.access .sf-main{padding:38px 0}.sf-page.access h1{font-size:2rem}.sf-page.access .sf-copy{font-size:16px}.sf-input{min-height:48px;font-size:16px}.sf-access-lanes .sf-button{min-height:48px}.sf-access-password-row{flex-direction:column}.sf-access-password-row .sf-button{width:100%}}@media(prefers-color-scheme:dark){.sf-access-status{background:color-mix(in srgb,var(--sf-fg) 5%,transparent)}}`;
366
382
  const pageHeader = '<header class="sf-header"><a class="sf-brand" href="/" aria-label="Homepage"><span class="sf-brand-mark" aria-hidden="true"></span><sf-logo></sf-logo><strong><sf-name></sf-name></strong></a></header>';
367
383
  const pageFooter = "<sf-spacefast-branding></sf-spacefast-branding>";
@@ -19,4 +19,16 @@ export declare function createPublishFormData(input: {
19
19
  slug?: string | undefined;
20
20
  title?: string | undefined;
21
21
  description?: string | undefined;
22
+ /** Live promotion intent for archive builds; null produces an unpromoted ready version. */
23
+ channel?: "live" | null | undefined;
24
+ /**
25
+ * Control-plane-only provenance for the version's build/deploy read models —
26
+ * a compiled runtime (Zero capsule, Functions worker) declares its artifact
27
+ * here under its own key (e.g. `statticZero`). Same shape the CLI sends on the
28
+ * declared-session path; the multipart intake reads it from the `metadata`
29
+ * JSON field and folds it into `publishRequestSchema.sourceMetadata`.
30
+ */
31
+ sourceMetadata?: Record<string, unknown> | undefined;
32
+ /** Bounded build transcript recorded on the version when a build ran. */
33
+ buildLog?: string | undefined;
22
34
  }): FormData;
@@ -5,6 +5,16 @@ export function createPublishFormData(input) {
5
5
  form.append("spaceId", input.spaceId);
6
6
  if (input.description)
7
7
  form.append("description", input.description);
8
+ // The multipart intake merges this JSON field into the parsed publish body
9
+ // (it reads `payload`/`publish`/`metadata`), so build provenance rides the
10
+ // one-shot form exactly as it rides the CLI's declared-session JSON body.
11
+ if (input.sourceMetadata || input.buildLog || input.channel !== undefined) {
12
+ form.append("metadata", JSON.stringify({
13
+ ...(input.sourceMetadata ? { sourceMetadata: input.sourceMetadata } : {}),
14
+ ...(input.buildLog ? { buildLog: input.buildLog } : {}),
15
+ ...(input.channel !== undefined ? { channel: input.channel } : {}),
16
+ }));
17
+ }
8
18
  if (input.slug || input.title) {
9
19
  form.append("space", JSON.stringify({
10
20
  ...(input.slug ? { slug: input.slug } : {}),
@@ -4,7 +4,27 @@ export declare const MANIFEST_MAX_PATH_BYTES = 1024;
4
4
  export declare const MANIFEST_MAX_BODY_BYTES: number;
5
5
  export declare const MAX_VERSION_FILE_SIZE_BYTES: number;
6
6
  export declare const MAX_VERSION_TOTAL_BYTES: number;
7
+ export declare const STATIC_EXECUTION_CONTROL_FILES: string[];
8
+ export declare const STATIC_RUNTIME_CONTROL_SEGMENT_PREFIXES: string[];
9
+ export declare const STATIC_RUNTIME_ROOT_SEGMENTS: string[];
10
+ export declare const STATIC_RUNTIME_CONTROL_PATHS: string[];
11
+ export declare const STATIC_RUNTIME_CONTROL_PREFIXES: string[];
7
12
  export declare function normalizePublishPath(relativePath: string): string;
13
+ /**
14
+ * The one subtree inside the runtime control prefix that a publish may write.
15
+ *
16
+ * `sf publish` compiles a version's worker into `__spacefast/functions/bundles/`
17
+ * so the bundle travels through the ordinary manifest and upload path instead of
18
+ * needing a parallel one. Keeping it under the control prefix is what makes it
19
+ * unservable as static content by default — the runtime answers it only behind a
20
+ * signature.
21
+ *
22
+ * Scoped to `bundles/` rather than the whole `__spacefast/functions/` directory
23
+ * on purpose: the sibling `config.json` holds the key those signatures are
24
+ * minted with, and a publish that could overwrite it would be a publish that
25
+ * could mint its own tokens.
26
+ */
27
+ export declare const PUBLISHABLE_BUILD_ARTIFACT_PREFIX = "__spacefast/functions/bundles/";
8
28
  export declare function publishPathIgnored(relativePath: string): boolean;
9
29
  export declare function publishPathIsConvention(relativePath: string): boolean;
10
30
  export declare function providerRuntimeFeatureWarnings(paths: readonly string[]): PublishManifestWarning[];
@@ -0,0 +1,397 @@
1
+ [
2
+ {
3
+ "path": "index.html",
4
+ "expected": null
5
+ },
6
+ {
7
+ "path": "index.php",
8
+ "expected": null,
9
+ "why": "never lands in the docroot, so it serves as inert bytes"
10
+ },
11
+ {
12
+ "path": "nested/deep/file.txt",
13
+ "expected": null
14
+ },
15
+ {
16
+ "path": "_redirects",
17
+ "expected": null
18
+ },
19
+ {
20
+ "path": ".well-known/security.txt",
21
+ "expected": null
22
+ },
23
+ {
24
+ "path": ".env.example",
25
+ "expected": null
26
+ },
27
+ {
28
+ "path": "docs/installer.php",
29
+ "expected": null
30
+ },
31
+ {
32
+ "path": "my__stattic_thing.txt",
33
+ "expected": null,
34
+ "why": "reserved names match a segment start, not mid-string"
35
+ },
36
+ {
37
+ "path": "assets/app__spacefast.js",
38
+ "expected": null
39
+ },
40
+ {
41
+ "path": "__sf",
42
+ "expected": "static_runtime_control_path_not_supported",
43
+ "why": "the '/__sf' namespace row matches the bare segment"
44
+ },
45
+ {
46
+ "path": "__sf/redeem",
47
+ "expected": "static_runtime_control_path_not_supported"
48
+ },
49
+ {
50
+ "path": "__SF/redeem",
51
+ "expected": "static_runtime_control_path_not_supported",
52
+ "why": "the row folds case"
53
+ },
54
+ {
55
+ "path": "__sf/access/open",
56
+ "expected": "static_runtime_control_path_not_supported"
57
+ },
58
+ {
59
+ "path": "__sfx/endpoint.json",
60
+ "expected": null,
61
+ "why": "'namespace' is whole-segment: /__sfx is not /__sf"
62
+ },
63
+ {
64
+ "path": "__SF_future/endpoint.json",
65
+ "expected": null
66
+ },
67
+ {
68
+ "path": "__sfoo.html",
69
+ "expected": null
70
+ },
71
+ {
72
+ "path": "nested/__sf/content.json",
73
+ "expected": null,
74
+ "why": "the table is only consulted for paths starting /__"
75
+ },
76
+ {
77
+ "path": "a/b/__sf/c.txt",
78
+ "expected": null
79
+ },
80
+ {
81
+ "path": "my__sf_thing.txt",
82
+ "expected": null
83
+ },
84
+ {
85
+ "path": "__span/index.html",
86
+ "expected": "static_runtime_control_path_not_supported"
87
+ },
88
+ {
89
+ "path": "__SPAN/collision.json",
90
+ "expected": "static_runtime_control_path_not_supported"
91
+ },
92
+ {
93
+ "path": "__spanish/page.html",
94
+ "expected": null,
95
+ "why": "the control table's own example of a tenant path"
96
+ },
97
+ {
98
+ "path": "nested/__span/x.json",
99
+ "expected": null
100
+ },
101
+ {
102
+ "path": "__spacefast/x.txt",
103
+ "expected": "static_runtime_control_path_not_supported"
104
+ },
105
+ {
106
+ "path": "__spacefast/api.php/state",
107
+ "expected": "static_runtime_control_path_not_supported"
108
+ },
109
+ {
110
+ "path": "__spacefast_generated/theme.css",
111
+ "expected": "static_runtime_control_path_not_supported",
112
+ "why": "the runtime writes generated assets here"
113
+ },
114
+ {
115
+ "path": "nested/__SPACEFAST/upl/files/index.html",
116
+ "expected": "static_runtime_control_path_not_supported"
117
+ },
118
+ {
119
+ "path": "__stattic/x.txt",
120
+ "expected": "static_runtime_control_path_not_supported"
121
+ },
122
+ {
123
+ "path": "__stattic_probe",
124
+ "expected": "static_runtime_control_path_not_supported"
125
+ },
126
+ {
127
+ "path": "a/__STATTIC_probe/x.txt",
128
+ "expected": "static_runtime_control_path_not_supported"
129
+ },
130
+ {
131
+ "path": "__stattic/functions/bundles/abc/bundle.json",
132
+ "expected": "static_runtime_control_path_not_supported",
133
+ "why": "the carve-out is __spacefast only"
134
+ },
135
+ {
136
+ "path": "__spacefast/functions/bundles/abc123/bundle.json",
137
+ "expected": null,
138
+ "why": "compiled Functions bundle"
139
+ },
140
+ {
141
+ "path": "__spacefast/functions/config.json",
142
+ "expected": "static_runtime_control_path_not_supported",
143
+ "why": "holds the key that signs bundle URLs"
144
+ },
145
+ {
146
+ "path": "__spacefast/functions/bundlesX/evil.json",
147
+ "expected": "static_runtime_control_path_not_supported"
148
+ },
149
+ {
150
+ "path": "__spacefast/zero/deploy.json",
151
+ "expected": null,
152
+ "why": "the Zero deploy record"
153
+ },
154
+ {
155
+ "path": "__spacefast/zero/DEPLOY.JSON",
156
+ "expected": "static_runtime_control_path_not_supported",
157
+ "why": "the deploy record is one exact path, not folded"
158
+ },
159
+ {
160
+ "path": "__Spacefast/zero/deploy.json",
161
+ "expected": "static_runtime_control_path_not_supported"
162
+ },
163
+ {
164
+ "path": "__spacefast/zero/deploy.json/evil",
165
+ "expected": "static_runtime_control_path_not_supported"
166
+ },
167
+ {
168
+ "path": "__spacefast/anything",
169
+ "expected": "static_runtime_control_path_not_supported"
170
+ },
171
+ {
172
+ "path": ".htaccess",
173
+ "expected": "static_control_file_not_supported"
174
+ },
175
+ {
176
+ "path": "a/.htaccess",
177
+ "expected": "static_control_file_not_supported"
178
+ },
179
+ {
180
+ "path": "nested/.HTACCESS",
181
+ "expected": "static_control_file_not_supported"
182
+ },
183
+ {
184
+ "path": ".user.ini",
185
+ "expected": "static_control_file_not_supported"
186
+ },
187
+ {
188
+ "path": "nested/.User.INI",
189
+ "expected": "static_control_file_not_supported"
190
+ },
191
+ {
192
+ "path": "custom-redirects.php",
193
+ "expected": "static_runtime_control_path_not_supported",
194
+ "why": "engine-manifest.json aliases it into the docroot root"
195
+ },
196
+ {
197
+ "path": "CUSTOM-REDIRECTS.PHP",
198
+ "expected": "static_runtime_control_path_not_supported"
199
+ },
200
+ {
201
+ "path": "engine-manifest.json",
202
+ "expected": "static_runtime_control_path_not_supported"
203
+ },
204
+ {
205
+ "path": "entrypoint-shim.php",
206
+ "expected": "static_runtime_control_path_not_supported"
207
+ },
208
+ {
209
+ "path": "nested/custom-redirects.php",
210
+ "expected": null,
211
+ "why": "only the docroot root collides"
212
+ },
213
+ {
214
+ "path": "init.php",
215
+ "expected": null,
216
+ "why": "engine/init.php installs under .stattic/engine/, not the docroot"
217
+ },
218
+ {
219
+ "path": ".spacefast/storage/routes/current.php",
220
+ "expected": "static_runtime_control_path_not_supported"
221
+ },
222
+ {
223
+ "path": ".spacefast/engine/init.php",
224
+ "expected": "static_runtime_control_path_not_supported"
225
+ },
226
+ {
227
+ "path": ".stattic/storage/routes/current.php",
228
+ "expected": "static_runtime_control_path_not_supported",
229
+ "why": "legacy layout still serves"
230
+ },
231
+ {
232
+ "path": ".stattic/engine/init.php",
233
+ "expected": "static_runtime_control_path_not_supported"
234
+ },
235
+ {
236
+ "path": ".spacefast/config.json",
237
+ "expected": null,
238
+ "why": "state dirs also carry publishable configuration"
239
+ },
240
+ {
241
+ "path": ".spacefast/routes.json",
242
+ "expected": null
243
+ },
244
+ {
245
+ "path": "nested/.SPACEFAST/routes.json",
246
+ "expected": null
247
+ },
248
+ {
249
+ "path": ".spacefast/agents/settings.json",
250
+ "expected": null
251
+ },
252
+ {
253
+ "path": ".stattic/routes.json",
254
+ "expected": null,
255
+ "why": "the legacy state dir carries the same publishable configuration"
256
+ },
257
+ {
258
+ "path": ".well-known/spacefast-runtime",
259
+ "expected": "static_runtime_control_path_not_supported"
260
+ },
261
+ {
262
+ "path": ".well-known/stattic-runtime",
263
+ "expected": "static_runtime_control_path_not_supported"
264
+ },
265
+ {
266
+ "path": ".WELL-KNOWN/SPACEFAST-RUNTIME",
267
+ "expected": "static_runtime_control_path_not_supported"
268
+ },
269
+ {
270
+ "path": "../escape.txt",
271
+ "expected": "invalid_file_path"
272
+ },
273
+ {
274
+ "path": "a/../b.txt",
275
+ "expected": "invalid_file_path"
276
+ },
277
+ {
278
+ "path": "a//b.txt",
279
+ "expected": "invalid_file_path"
280
+ },
281
+ {
282
+ "path": "a/./b.txt",
283
+ "expected": "invalid_file_path"
284
+ },
285
+ {
286
+ "path": "./a.txt",
287
+ "expected": "invalid_file_path"
288
+ },
289
+ {
290
+ "path": "/absolute.txt",
291
+ "expected": "invalid_file_path"
292
+ },
293
+ {
294
+ "path": "a\\b.txt",
295
+ "expected": "invalid_file_path",
296
+ "why": "backslash is never a separator at intake"
297
+ },
298
+ {
299
+ "path": " leading.txt",
300
+ "expected": "invalid_file_path"
301
+ },
302
+ {
303
+ "path": "trailing.txt ",
304
+ "expected": "invalid_file_path"
305
+ },
306
+ {
307
+ "path": "trailing./x",
308
+ "expected": "invalid_file_path"
309
+ },
310
+ {
311
+ "path": "trailing /x",
312
+ "expected": "invalid_file_path"
313
+ },
314
+ {
315
+ "path": "dir./file.txt",
316
+ "expected": "invalid_file_path"
317
+ },
318
+ {
319
+ "path": "",
320
+ "expected": "invalid_file_path"
321
+ },
322
+ {
323
+ "path": ".",
324
+ "expected": "invalid_file_path"
325
+ },
326
+ {
327
+ "path": "..",
328
+ "expected": "invalid_file_path"
329
+ },
330
+ {
331
+ "path": "a/",
332
+ "expected": "invalid_file_path"
333
+ },
334
+ {
335
+ "path": "/",
336
+ "expected": "invalid_file_path"
337
+ },
338
+ {
339
+ "path": "caf\u00e9.txt",
340
+ "expected": null,
341
+ "why": "already NFC"
342
+ },
343
+ {
344
+ "path": "cafe\u0301.txt",
345
+ "expected": "invalid_file_path",
346
+ "why": "NFD: the canonical form is NFC, and intake never rewrites"
347
+ },
348
+ {
349
+ "path": "\u4e2d.txt",
350
+ "expected": null
351
+ },
352
+ {
353
+ "path": "\u00fcber/stra\u00dfe.html",
354
+ "expected": null
355
+ },
356
+ {
357
+ "path": "emoji-\ud83d\ude80.txt",
358
+ "expected": null
359
+ },
360
+ {
361
+ "path": "a%20b.txt",
362
+ "expected": null,
363
+ "why": "percent escapes are decoded once BEFORE this policy, never here"
364
+ },
365
+ {
366
+ "path": "a%2Fb.txt",
367
+ "expected": null
368
+ },
369
+ {
370
+ "path": "100%.txt",
371
+ "expected": null
372
+ },
373
+ {
374
+ "path": "nul\u0000.txt",
375
+ "expected": "invalid_file_path",
376
+ "why": "a control character can never be part of a servable path"
377
+ },
378
+ {
379
+ "path": "bell\u0007.txt",
380
+ "expected": "invalid_file_path"
381
+ },
382
+ {
383
+ "path": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt",
384
+ "expected": null,
385
+ "why": "exactly 1024 bytes"
386
+ },
387
+ {
388
+ "path": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt",
389
+ "expected": "path_too_long",
390
+ "why": "1025 bytes"
391
+ },
392
+ {
393
+ "path": "\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9.test",
394
+ "expected": "path_too_long",
395
+ "why": "1025 bytes: the cap counts bytes, not code points"
396
+ }
397
+ ]