@spacefast/common 0.0.23 → 0.0.26
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.
- package/brand-assets/LICENSE-Haskoy.txt +93 -0
- package/brand-assets/haskoy-latin-variable.woff2 +0 -0
- package/brand-assets/spacefast-favicon.svg +4 -4
- package/brand-assets/spacefast-sf-full-bleed.svg +3 -3
- package/brand-assets/spacefast-wordmark.svg +2 -4
- package/dist/agents/connect-targets.js +1 -1
- package/dist/agents/private-key-oauth.d.ts +0 -1
- package/dist/agents/private-key-oauth.js +46 -63
- package/dist/brand-assets-build.js +4 -6
- package/dist/brand-assets.d.ts +5 -15
- package/dist/brand-assets.js +15 -14
- package/dist/config/domains.d.ts +47 -7
- package/dist/config/domains.js +66 -10
- package/dist/config/index.d.ts +0 -1
- package/dist/config/index.js +0 -1
- package/dist/contracts/abuse.d.ts +2 -0
- package/dist/contracts/abuse.js +12 -0
- package/dist/contracts/access.d.ts +124 -12
- package/dist/contracts/access.js +73 -9
- package/dist/contracts/activity.d.ts +1 -1
- package/dist/contracts/activity.js +5 -12
- package/dist/contracts/api-keys.d.ts +21 -21
- package/dist/contracts/api-keys.js +2 -2
- package/dist/contracts/beta.js +1 -1
- package/dist/contracts/billing.d.ts +3 -35
- package/dist/contracts/billing.js +33 -52
- package/dist/contracts/builds.d.ts +30 -18
- package/dist/contracts/builds.js +28 -9
- package/dist/contracts/channels.js +1 -1
- package/dist/contracts/cli.d.ts +10 -0
- package/dist/contracts/cli.js +10 -0
- package/dist/contracts/collab-public.d.ts +63 -0
- package/dist/contracts/collab-public.js +46 -0
- package/dist/contracts/comments.d.ts +282 -53
- package/dist/contracts/comments.js +173 -52
- package/dist/contracts/common.d.ts +3 -3
- package/dist/contracts/common.js +5 -5
- package/dist/contracts/crons.d.ts +35 -0
- package/dist/contracts/crons.js +42 -0
- package/dist/contracts/device-auth.d.ts +6 -6
- package/dist/contracts/device-auth.js +2 -2
- package/dist/contracts/docs.js +2 -2
- package/dist/contracts/domains.d.ts +38 -27
- package/dist/contracts/domains.js +29 -2
- package/dist/contracts/enums.d.ts +34 -30
- package/dist/contracts/enums.js +62 -48
- package/dist/contracts/error-code-meta.d.ts +50 -125
- package/dist/contracts/error-code-meta.js +29 -41
- package/dist/contracts/error-codes.d.ts +1 -1
- package/dist/contracts/error-codes.js +14 -33
- package/dist/contracts/execution.d.ts +47 -66
- package/dist/contracts/execution.js +53 -49
- package/dist/contracts/feature-lifecycle-core.d.ts +0 -6
- package/dist/contracts/feature-lifecycle-core.js +2 -31
- package/dist/contracts/feature-lifecycle.d.ts +12 -52
- package/dist/contracts/feature-lifecycle.js +16 -59
- package/dist/contracts/features.d.ts +48 -60
- package/dist/contracts/features.js +59 -51
- package/dist/contracts/functions.d.ts +266 -72
- package/dist/contracts/functions.js +260 -37
- package/dist/contracts/git.d.ts +28 -34
- package/dist/contracts/git.js +10 -11
- package/dist/contracts/grants.d.ts +9 -5
- package/dist/contracts/grants.js +18 -9
- package/dist/contracts/ids.js +2 -2
- package/dist/contracts/internal.d.ts +8 -6
- package/dist/contracts/internal.js +12 -12
- package/dist/contracts/mcp.d.ts +11 -0
- package/dist/contracts/mcp.js +5 -0
- package/dist/contracts/me.js +1 -1
- package/dist/contracts/oauth-resources.d.ts +4 -3
- package/dist/contracts/oauth-resources.js +12 -3
- package/dist/contracts/operations.d.ts +90 -5
- package/dist/contracts/operations.js +77 -3
- package/dist/contracts/pages.d.ts +12 -7
- package/dist/contracts/pages.js +24 -1
- package/dist/contracts/plan-policy.d.ts +0 -2
- package/dist/contracts/plan-policy.js +2 -3
- package/dist/contracts/platform.d.ts +61 -148
- package/dist/contracts/platform.js +70 -126
- package/dist/contracts/publish-archive.d.ts +508 -0
- package/dist/contracts/publish-archive.js +32 -0
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.js +2 -2
- package/dist/contracts/repository-connections.d.ts +43 -30
- package/dist/contracts/repository-connections.js +11 -3
- package/dist/contracts/resources.d.ts +12 -24
- package/dist/contracts/resources.js +36 -16
- package/dist/contracts/runtime-api.d.ts +433 -192
- package/dist/contracts/runtime-api.js +421 -356
- package/dist/contracts/runtime-app.d.ts +127 -120
- package/dist/contracts/runtime-app.js +19 -10
- package/dist/contracts/runtime-db.d.ts +5 -5
- package/dist/contracts/runtime-db.js +2 -2
- package/dist/contracts/runtime-purge.d.ts +8 -0
- package/dist/contracts/runtime-purge.js +7 -0
- package/dist/contracts/runtime-services.d.ts +219 -0
- package/dist/contracts/runtime-services.js +437 -0
- package/dist/contracts/runtime-storage.d.ts +46 -32
- package/dist/contracts/runtime-storage.js +31 -8
- package/dist/contracts/sf-config-v1.d.ts +48 -10
- package/dist/contracts/space-config.d.ts +69 -18
- package/dist/contracts/space-config.js +226 -27
- package/dist/contracts/spaces.d.ts +236 -450
- package/dist/contracts/spaces.js +131 -151
- package/dist/contracts/superadmin-activity.d.ts +57 -4
- package/dist/contracts/superadmin-activity.js +48 -2
- package/dist/contracts/superadmin-search.d.ts +126 -0
- package/dist/contracts/superadmin-search.js +61 -0
- package/dist/contracts/superadmin-spaces.d.ts +361 -92
- package/dist/contracts/superadmin-spaces.js +97 -24
- package/dist/contracts/superadmin-teams.d.ts +28 -10
- package/dist/contracts/superadmin-teams.js +5 -8
- package/dist/contracts/superadmin-tenants.d.ts +0 -6
- package/dist/contracts/superadmin-tenants.js +1 -7
- package/dist/contracts/superadmin.d.ts +135 -54
- package/dist/contracts/superadmin.js +46 -23
- package/dist/contracts/tags.d.ts +12 -12
- package/dist/contracts/tags.js +3 -3
- package/dist/contracts/teams.d.ts +49 -14
- package/dist/contracts/teams.js +40 -22
- package/dist/contracts/transfers.d.ts +0 -49
- package/dist/contracts/transfers.js +4 -8
- package/dist/contracts/usage.d.ts +61 -0
- package/dist/contracts/usage.js +64 -0
- package/dist/contracts/variables.d.ts +2 -7
- package/dist/contracts/variables.js +9 -8
- package/dist/contracts/webhooks.d.ts +2 -2
- package/dist/contracts/zero.d.ts +102 -73
- package/dist/contracts/zero.js +94 -32
- package/dist/dashboard-paths/index.d.ts +1 -1
- package/dist/dashboard-paths/index.js +1 -0
- package/dist/docs/agent-prose.d.ts +2 -2
- package/dist/docs/agent-prose.js +63 -70
- package/dist/docs/agent-setup.js +45 -15
- package/dist/docs/catalog.d.ts +24 -24
- package/dist/docs/catalog.js +35 -24
- package/dist/docs/error-docs.js +194 -270
- package/dist/docs/skills.d.ts +12 -12
- package/dist/docs/skills.js +4 -4
- package/dist/test-helpers/fetch-stub.d.ts +16 -0
- package/dist/test-helpers/fetch-stub.js +25 -0
- package/dist/utils/build-settings.d.ts +5 -1
- package/dist/utils/build-settings.js +91 -13
- package/dist/utils/canonical-json.d.ts +10 -0
- package/dist/utils/canonical-json.js +22 -0
- package/dist/utils/cast-transport.d.ts +28 -0
- package/dist/utils/cast-transport.js +52 -0
- package/dist/utils/claim-token.d.ts +0 -8
- package/dist/utils/claim-token.js +3 -15
- package/dist/utils/concurrency.js +1 -0
- package/dist/utils/credential-policy.d.ts +1 -1
- package/dist/utils/credential-policy.js +4 -3
- package/dist/utils/dns-instructions.js +9 -9
- package/dist/utils/env-file.d.ts +17 -0
- package/dist/utils/env-file.js +96 -0
- package/dist/utils/error-code.d.ts +2 -0
- package/dist/utils/error-code.js +8 -0
- package/dist/utils/generate-space-name.d.ts +8 -10
- package/dist/utils/generate-space-name.js +206 -21
- package/dist/utils/grant-decision.fixtures.json +2938 -0
- package/dist/utils/grants.d.ts +2 -0
- package/dist/utils/grants.js +26 -1
- package/dist/utils/gravatar.d.ts +9 -0
- package/dist/utils/gravatar.js +31 -0
- package/dist/utils/idempotency.d.ts +6 -0
- package/dist/utils/idempotency.js +28 -0
- package/dist/utils/local-space-state.d.ts +9 -16
- package/dist/utils/local-space-state.js +20 -50
- package/dist/utils/one-shot-replay.d.ts +4 -1
- package/dist/utils/page-colors.d.ts +14 -12
- package/dist/utils/page-colors.js +15 -13
- package/dist/utils/page-fonts.d.ts +2 -2
- package/dist/utils/page-fonts.js +15 -4
- package/dist/utils/pages.d.ts +21 -3
- package/dist/utils/pages.js +42 -13
- package/dist/utils/publish-form-data.d.ts +12 -0
- package/dist/utils/publish-form-data.js +10 -0
- package/dist/utils/publish-policy.d.ts +27 -0
- package/dist/utils/publish-policy.fixtures.json +403 -0
- package/dist/utils/publish-policy.js +45 -20
- package/dist/utils/push-new.d.ts +7 -0
- package/dist/utils/push-new.js +7 -0
- package/dist/utils/query-keys.d.ts +4 -5
- package/dist/utils/query-keys.js +2 -3
- package/dist/utils/runtime-paths.d.ts +5 -0
- package/dist/utils/runtime-paths.js +5 -0
- package/dist/utils/runtime-upload-batch.d.ts +0 -5
- package/dist/utils/runtime-upload-batch.js +1 -27
- package/dist/utils/runtime-upload.d.ts +6 -11
- package/dist/utils/runtime-upload.js +10 -13
- package/dist/utils/secure-local-file.js +5 -16
- package/dist/utils/space-config.d.ts +1 -34
- package/dist/utils/space-config.js +8 -326
- package/dist/utils/static-runtime-policy.d.ts +9 -3
- package/dist/utils/static-runtime-policy.fixtures.json +38 -41
- package/dist/utils/static-runtime-policy.js +22 -56
- package/dist/utils/storage-policy.d.ts +1 -1
- package/dist/utils/storage-policy.js +3 -1
- package/dist/utils/structured-error.d.ts +14 -0
- package/dist/utils/structured-error.js +22 -0
- package/dist/utils/upload-session.d.ts +4 -1
- package/dist/utils/upload-session.js +33 -5
- package/dist/utils/version-path.js +13 -4
- package/dist/vocabulary.d.ts +13 -11
- package/dist/vocabulary.js +42 -28
- package/package.json +7 -17
- package/dist/config/postgres-budget.d.ts +0 -129
- package/dist/config/postgres-budget.js +0 -140
- package/dist/config/postgres-budget.json +0 -51
- package/dist/contracts/archives.d.ts +0 -331
- package/dist/contracts/archives.js +0 -120
- package/dist/contracts/deployments.d.ts +0 -574
- package/dist/contracts/deployments.js +0 -97
- package/dist/contracts/sites.d.ts +0 -416
- package/dist/contracts/sites.js +0 -168
- package/dist/contracts/superadmin-queues.d.ts +0 -414
- package/dist/contracts/superadmin-queues.js +0 -202
- package/dist/contracts/superadmin-runtime.d.ts +0 -27
- package/dist/contracts/superadmin-runtime.js +0 -38
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/utils/api.d.ts +0 -4
- package/dist/utils/api.js +0 -13
package/dist/utils/pages.js
CHANGED
|
@@ -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 {
|
|
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();
|
|
@@ -32,15 +33,21 @@ export function escapePageHtml(value) {
|
|
|
32
33
|
.replaceAll('"', """)
|
|
33
34
|
.replaceAll("'", "'");
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The custom properties a theme paints with. Pushed colors are intent; the
|
|
38
|
+
* readability engine (page-colors.ts) derives what the templates actually use.
|
|
39
|
+
* A custom background pins a complete scheme for both OS modes — emitting
|
|
40
|
+
* `--sf-bg` alone used to leave dark-mode visitors with the dark foreground on
|
|
41
|
+
* the user's light background.
|
|
42
|
+
*
|
|
43
|
+
* Exported because the dashboard's live preview paints the same tokens from an
|
|
44
|
+
* unsaved draft: it passes the colors it has already derived, and gets exactly
|
|
45
|
+
* what the published page would carry.
|
|
46
|
+
*/
|
|
47
|
+
export function pageThemeCss(theme, derived = derivePageColors(theme)) {
|
|
40
48
|
const root = [];
|
|
41
49
|
const dark = [];
|
|
42
50
|
if (theme.accent || theme.background) {
|
|
43
|
-
const derived = derivePageColors(theme);
|
|
44
51
|
// `derived.accent` is the parse-validated input (or the default), never
|
|
45
52
|
// an arbitrary string straight from the theme.
|
|
46
53
|
if (theme.accent)
|
|
@@ -58,7 +65,11 @@ function themeStyle(theme) {
|
|
|
58
65
|
if (root.length === 0)
|
|
59
66
|
return "";
|
|
60
67
|
const darkBlock = dark.length > 0 ? `@media(prefers-color-scheme:dark){:root{${dark.join(";")}}}` : "";
|
|
61
|
-
return
|
|
68
|
+
return `:root{${root.join(";")}}${darkBlock}`;
|
|
69
|
+
}
|
|
70
|
+
function themeStyle(theme) {
|
|
71
|
+
const css = pageThemeCss(theme);
|
|
72
|
+
return css ? `<style>${css}</style>` : "";
|
|
62
73
|
}
|
|
63
74
|
const runtimeSlot = (name, fallback) => `<!--sf-runtime:${name}:start-->${fallback}<!--sf-runtime:${name}:end-->`;
|
|
64
75
|
function renderFiles(files) {
|
|
@@ -83,7 +94,7 @@ function renderFile(file) {
|
|
|
83
94
|
function renderSpacefastBranding(hidden) {
|
|
84
95
|
const wordmark = hidden
|
|
85
96
|
? ""
|
|
86
|
-
: `<span class="sf-powered" tabindex="0"><svg class="sf-wordmark" viewBox="0 0
|
|
97
|
+
: `<span class="sf-powered" tabindex="0"><svg class="sf-wordmark" viewBox="0 0 152 28.9062" role="img" aria-label="Spacefast"><path fill="currentColor" d="${SPACEFAST_WORDMARK_PATH}"></path></svg><span class="sf-powered-line"><a href="https://spacefast.com">Best way to share what your agent made</a></span></span>`;
|
|
87
98
|
return `<footer class="sf-colophon"><div class="sf-colophon-row">${wordmark}<a class="sf-help" href="https://spacefast.com/help">Need help?</a></div></footer>`;
|
|
88
99
|
}
|
|
89
100
|
function renderElement(element, context) {
|
|
@@ -127,9 +138,17 @@ const ELEMENT_PATTERN = /<\s*(sf-[a-z0-9-]+)\b[^>]*>(?:\s*<\s*\/\s*\1\s*>)?|<\s*
|
|
|
127
138
|
export function expandPageHtml(source, context) {
|
|
128
139
|
let output = source.replace(ELEMENT_PATTERN, (_match, paired, unary) => {
|
|
129
140
|
const name = (paired ?? unary)?.toLowerCase();
|
|
141
|
+
// SAFETY: The set membership check admits only names from the PageElement literal set.
|
|
130
142
|
return name && knownElements.has(name) ? renderElement(name, context) : _match;
|
|
131
143
|
});
|
|
132
|
-
|
|
144
|
+
if (output.includes("/*sf-default-fonts*/")) {
|
|
145
|
+
output = output.replaceAll("/*sf-default-fonts*/", PAGE_FONT_FACES);
|
|
146
|
+
// The faces point at shared font origins; preloading ahead of the inline
|
|
147
|
+
// stylesheet starts the cross-origin fetches with the parse.
|
|
148
|
+
output = /<\s*style\b/i.test(output)
|
|
149
|
+
? output.replace(/<\s*style\b/i, (tag) => `${PAGE_FONT_PRELOAD_HTML}${tag}`)
|
|
150
|
+
: `${PAGE_FONT_PRELOAD_HTML}${output}`;
|
|
151
|
+
}
|
|
133
152
|
const tokens = themeStyle(context.theme ?? {});
|
|
134
153
|
if (tokens) {
|
|
135
154
|
output = /<\s*\/\s*head\s*>/i.test(output)
|
|
@@ -179,7 +198,11 @@ export function validatePageSources(input) {
|
|
|
179
198
|
const path = sourcePath.includes("_pages/") ? sourcePath : `_pages/${sourcePath}`;
|
|
180
199
|
const filename = path.slice(path.lastIndexOf("_pages/") + 7);
|
|
181
200
|
const id = filename.replace(/\.html$/i, "");
|
|
182
|
-
|
|
201
|
+
// A collab layout is Space-level — one review room, one URL — so unlike the
|
|
202
|
+
// gate and listing pages it has no per-directory form.
|
|
203
|
+
if (!customPageIds.has(id) ||
|
|
204
|
+
filename !== `${id}.html` ||
|
|
205
|
+
(id === "collab" && path !== COLLAB_PAGE_SOURCE)) {
|
|
183
206
|
diagnostics.push({
|
|
184
207
|
severity: "error",
|
|
185
208
|
code: "unknown_page_template",
|
|
@@ -204,6 +227,10 @@ export function validatePageSources(input) {
|
|
|
204
227
|
path,
|
|
205
228
|
});
|
|
206
229
|
for (const element of foundElements(source)) {
|
|
230
|
+
// Collab elements are the browser SDK's, not the compiler's: legal in the
|
|
231
|
+
// review room, meaningless anywhere the SDK is not the point.
|
|
232
|
+
if (id === "collab" && collabElements.has(element))
|
|
233
|
+
continue;
|
|
207
234
|
if (!knownElements.has(element))
|
|
208
235
|
diagnostics.push({
|
|
209
236
|
severity: "error",
|
|
@@ -361,7 +388,7 @@ export function defaultPageBody(id) {
|
|
|
361
388
|
// The built-in palette runs through the same readability engine as pushed
|
|
362
389
|
// themes, so buttons and links remain readable for every accepted accent.
|
|
363
390
|
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
|
|
391
|
+
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:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","Segoe UI",system-ui,Roboto,"Helvetica Neue",Arial,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:14px;color:var(--sf-fg)}@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
392
|
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
393
|
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
394
|
const pageFooter = "<sf-spacefast-branding></sf-spacefast-branding>";
|
|
@@ -384,8 +411,10 @@ export function defaultPageTemplate(id) {
|
|
|
384
411
|
}
|
|
385
412
|
export function pageIdFromFilename(filename) {
|
|
386
413
|
const id = filename.replace(/\.html$/, "");
|
|
414
|
+
// SAFETY: The set membership check admits only ids from the CustomPageId literal set.
|
|
387
415
|
return customPageIds.has(id) ? id : null;
|
|
388
416
|
}
|
|
389
417
|
export function allDefaultPageTemplates() {
|
|
418
|
+
// SAFETY: SITE_PAGE_IDS maps every SitePageId to its corresponding default template entry.
|
|
390
419
|
return Object.fromEntries(SITE_PAGE_IDS.map((id) => [id, DEFAULT_PAGE_TEMPLATES[id]]));
|
|
391
420
|
}
|
|
@@ -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,34 @@ 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/";
|
|
28
|
+
/**
|
|
29
|
+
* The bundle carve-out's sibling for the Next-cache seed document: the same
|
|
30
|
+
* reasoning (travel through the ordinary manifest and upload path, stay
|
|
31
|
+
* unservable by default), the same deliberate narrowness (a prefix of its
|
|
32
|
+
* own, never the whole `functions/` directory — see the bundle comment).
|
|
33
|
+
*/
|
|
34
|
+
export declare const PUBLISHABLE_SEED_ARTIFACT_PREFIX = "__spacefast/functions/seeds/";
|
|
8
35
|
export declare function publishPathIgnored(relativePath: string): boolean;
|
|
9
36
|
export declare function publishPathIsConvention(relativePath: string): boolean;
|
|
10
37
|
export declare function providerRuntimeFeatureWarnings(paths: readonly string[]): PublishManifestWarning[];
|
|
@@ -0,0 +1,403 @@
|
|
|
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/functions/seeds/abc123/seed.json",
|
|
151
|
+
"expected": null,
|
|
152
|
+
"why": "the Next-cache seed document, the bundle carve-out's sibling"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"path": "__spacefast/functions/seeds.json",
|
|
156
|
+
"expected": "static_runtime_control_path_not_supported",
|
|
157
|
+
"why": "the carve-out is the seeds/ prefix, not anything starting with seeds"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"path": "__spacefast/zero/deploy.json",
|
|
161
|
+
"expected": null,
|
|
162
|
+
"why": "the Zero deploy record"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"path": "__spacefast/zero/DEPLOY.JSON",
|
|
166
|
+
"expected": "static_runtime_control_path_not_supported",
|
|
167
|
+
"why": "the deploy record is one exact path, not folded"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"path": "__Spacefast/zero/deploy.json",
|
|
171
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"path": "__spacefast/zero/deploy.json/evil",
|
|
175
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"path": "__spacefast/anything",
|
|
179
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"path": ".htaccess",
|
|
183
|
+
"expected": "static_control_file_not_supported"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"path": "a/.htaccess",
|
|
187
|
+
"expected": "static_control_file_not_supported"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"path": "nested/.HTACCESS",
|
|
191
|
+
"expected": "static_control_file_not_supported"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"path": ".user.ini",
|
|
195
|
+
"expected": "static_control_file_not_supported"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"path": "nested/.User.INI",
|
|
199
|
+
"expected": "static_control_file_not_supported"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"path": "custom-redirects.php",
|
|
203
|
+
"expected": "static_runtime_control_path_not_supported",
|
|
204
|
+
"why": "engine-manifest.json aliases it into the docroot root"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"path": "CUSTOM-REDIRECTS.PHP",
|
|
208
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"path": "engine-manifest.json",
|
|
212
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"path": "nested/custom-redirects.php",
|
|
216
|
+
"expected": null,
|
|
217
|
+
"why": "only the docroot root collides"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"path": "init.php",
|
|
221
|
+
"expected": null,
|
|
222
|
+
"why": "engine/init.php installs inside an immutable release, not the docroot"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"path": ".spacefast/storage/routes/current.php",
|
|
226
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"path": ".spacefast/engine/init.php",
|
|
230
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"path": ".stattic/storage/routes/current.php",
|
|
234
|
+
"expected": "static_runtime_control_path_not_supported",
|
|
235
|
+
"why": "legacy layout still serves"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"path": ".stattic/engine/init.php",
|
|
239
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"path": ".spacefast/config.json",
|
|
243
|
+
"expected": null,
|
|
244
|
+
"why": "state dirs also carry publishable configuration"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"path": ".spacefast/routes.json",
|
|
248
|
+
"expected": null
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"path": "nested/.SPACEFAST/routes.json",
|
|
252
|
+
"expected": null
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"path": ".spacefast/agents/settings.json",
|
|
256
|
+
"expected": null
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"path": ".stattic/routes.json",
|
|
260
|
+
"expected": null,
|
|
261
|
+
"why": "the legacy state dir carries the same publishable configuration"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"path": ".well-known/spacefast-runtime",
|
|
265
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"path": ".well-known/stattic-runtime",
|
|
269
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"path": ".WELL-KNOWN/SPACEFAST-RUNTIME",
|
|
273
|
+
"expected": "static_runtime_control_path_not_supported"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"path": "../escape.txt",
|
|
277
|
+
"expected": "invalid_file_path"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"path": "a/../b.txt",
|
|
281
|
+
"expected": "invalid_file_path"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"path": "a//b.txt",
|
|
285
|
+
"expected": "invalid_file_path"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"path": "a/./b.txt",
|
|
289
|
+
"expected": "invalid_file_path"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"path": "./a.txt",
|
|
293
|
+
"expected": "invalid_file_path"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"path": "/absolute.txt",
|
|
297
|
+
"expected": "invalid_file_path"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"path": "a\\b.txt",
|
|
301
|
+
"expected": "invalid_file_path",
|
|
302
|
+
"why": "backslash is never a separator at intake"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"path": " leading.txt",
|
|
306
|
+
"expected": "invalid_file_path"
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"path": "trailing.txt ",
|
|
310
|
+
"expected": "invalid_file_path"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"path": "trailing./x",
|
|
314
|
+
"expected": "invalid_file_path"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"path": "trailing /x",
|
|
318
|
+
"expected": "invalid_file_path"
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"path": "dir./file.txt",
|
|
322
|
+
"expected": "invalid_file_path"
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"path": "",
|
|
326
|
+
"expected": "invalid_file_path"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"path": ".",
|
|
330
|
+
"expected": "invalid_file_path"
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"path": "..",
|
|
334
|
+
"expected": "invalid_file_path"
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"path": "a/",
|
|
338
|
+
"expected": "invalid_file_path"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"path": "/",
|
|
342
|
+
"expected": "invalid_file_path"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"path": "caf\u00e9.txt",
|
|
346
|
+
"expected": null,
|
|
347
|
+
"why": "already NFC"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"path": "cafe\u0301.txt",
|
|
351
|
+
"expected": "invalid_file_path",
|
|
352
|
+
"why": "NFD: the canonical form is NFC, and intake never rewrites"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"path": "\u4e2d.txt",
|
|
356
|
+
"expected": null
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"path": "\u00fcber/stra\u00dfe.html",
|
|
360
|
+
"expected": null
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"path": "emoji-\ud83d\ude80.txt",
|
|
364
|
+
"expected": null
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"path": "a%20b.txt",
|
|
368
|
+
"expected": null,
|
|
369
|
+
"why": "percent escapes are decoded once BEFORE this policy, never here"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"path": "a%2Fb.txt",
|
|
373
|
+
"expected": null
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"path": "100%.txt",
|
|
377
|
+
"expected": null
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"path": "nul\u0000.txt",
|
|
381
|
+
"expected": "invalid_file_path",
|
|
382
|
+
"why": "a control character can never be part of a servable path"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"path": "bell\u0007.txt",
|
|
386
|
+
"expected": "invalid_file_path"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"path": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt",
|
|
390
|
+
"expected": null,
|
|
391
|
+
"why": "exactly 1024 bytes"
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"path": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt",
|
|
395
|
+
"expected": "path_too_long",
|
|
396
|
+
"why": "1025 bytes"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"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",
|
|
400
|
+
"expected": "path_too_long",
|
|
401
|
+
"why": "1025 bytes: the cap counts bytes, not code points"
|
|
402
|
+
}
|
|
403
|
+
]
|