@spacefast/common 0.0.26 → 0.2.1
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/dist/agents/connect-targets.d.ts +6 -146
- package/dist/agents/connect-targets.js +63 -295
- package/dist/agents/private-key-oauth.d.ts +31 -1
- package/dist/agents/private-key-oauth.js +124 -33
- package/dist/agents/registry/core.d.ts +292 -0
- package/dist/agents/registry/core.js +1388 -0
- package/dist/agents/registry/deeplink-probes.d.ts +23 -0
- package/dist/agents/registry/deeplink-probes.js +18 -0
- package/dist/agents/registry/node.d.ts +56 -0
- package/dist/agents/registry/node.js +339 -0
- package/dist/brand-assets-build.js +1 -2
- package/dist/brand-assets.js +4 -7
- package/dist/brand.d.ts +17 -0
- package/dist/brand.js +24 -4
- package/dist/config/domains.d.ts +55 -28
- package/dist/config/domains.js +85 -41
- package/dist/config/index.js +1 -2
- package/dist/contracts/abuse.js +9 -24
- package/dist/contracts/access-profiles.d.ts +86 -0
- package/dist/contracts/access-profiles.js +89 -0
- package/dist/contracts/access.d.ts +21 -27
- package/dist/contracts/access.js +33 -64
- package/dist/contracts/activity.d.ts +18 -1
- package/dist/contracts/activity.js +70 -26
- package/dist/contracts/analytics.js +8 -10
- package/dist/contracts/api-keys.d.ts +77 -52
- package/dist/contracts/api-keys.js +44 -24
- package/dist/contracts/application-journal.d.ts +216 -0
- package/dist/contracts/application-journal.js +167 -0
- package/dist/contracts/auth.d.ts +90 -17
- package/dist/contracts/auth.js +86 -17
- package/dist/contracts/beta.d.ts +9 -4
- package/dist/contracts/beta.js +20 -16
- package/dist/contracts/billing.js +7 -11
- package/dist/contracts/bootstrap.d.ts +791 -0
- package/dist/contracts/bootstrap.js +51 -0
- package/dist/contracts/builds.d.ts +186 -7
- package/dist/contracts/builds.js +75 -21
- package/dist/contracts/channels.d.ts +43 -0
- package/dist/contracts/channels.js +25 -9
- package/dist/contracts/cli.d.ts +7 -0
- package/dist/contracts/cli.js +6 -0
- package/dist/contracts/collab-public.d.ts +1 -1
- package/dist/contracts/collab-public.js +5 -8
- package/dist/contracts/comments.d.ts +45 -35
- package/dist/contracts/comments.js +107 -77
- package/dist/contracts/commerce.d.ts +165 -0
- package/dist/contracts/commerce.js +146 -0
- package/dist/contracts/common.d.ts +3 -3
- package/dist/contracts/common.js +18 -29
- package/dist/contracts/content-contract-verification.d.ts +521 -0
- package/dist/contracts/content-contract-verification.js +320 -0
- package/dist/contracts/content-platform-fixture.d.ts +1278 -0
- package/dist/contracts/content-platform-fixture.js +44 -0
- package/dist/contracts/content-program.d.ts +994 -0
- package/dist/contracts/content-program.js +658 -0
- package/dist/contracts/content-sync.d.ts +290 -0
- package/dist/contracts/content-sync.js +167 -0
- package/dist/contracts/content.d.ts +432 -0
- package/dist/contracts/content.js +303 -0
- package/dist/contracts/continuation.d.ts +17 -1
- package/dist/contracts/continuation.js +23 -23
- package/dist/contracts/countries.js +3 -4
- package/dist/contracts/crons.d.ts +17 -0
- package/dist/contracts/crons.js +33 -15
- package/dist/contracts/dashboard-prefs.d.ts +56 -0
- package/dist/contracts/dashboard-prefs.js +51 -0
- package/dist/contracts/device-auth.d.ts +234 -37
- package/dist/contracts/device-auth.js +267 -53
- package/dist/contracts/docs.d.ts +6 -10
- package/dist/contracts/docs.js +5 -13
- package/dist/contracts/domains.d.ts +499 -102
- package/dist/contracts/domains.js +169 -58
- package/dist/contracts/email-preferences.d.ts +3 -3
- package/dist/contracts/email-preferences.js +6 -7
- package/dist/contracts/enums.d.ts +26 -26
- package/dist/contracts/enums.js +61 -54
- package/dist/contracts/error-code-meta.d.ts +269 -7
- package/dist/contracts/error-code-meta.js +80 -5
- package/dist/contracts/error-codes.d.ts +5 -5
- package/dist/contracts/error-codes.js +78 -16
- package/dist/contracts/events.d.ts +100 -20
- package/dist/contracts/events.js +107 -20
- package/dist/contracts/execution.d.ts +47 -66
- package/dist/contracts/execution.js +51 -64
- package/dist/contracts/feature-lifecycle.d.ts +70 -14
- package/dist/contracts/feature-lifecycle.js +86 -15
- package/dist/contracts/features.d.ts +100 -37
- package/dist/contracts/features.js +21 -27
- package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
- package/dist/contracts/frame-session.d.ts +192 -0
- package/dist/contracts/frame-session.js +164 -0
- package/dist/contracts/functions.d.ts +218 -211
- package/dist/contracts/functions.js +273 -260
- package/dist/contracts/grant-copy.d.ts +43 -0
- package/dist/contracts/grant-copy.js +44 -0
- package/dist/contracts/grants.d.ts +64 -56
- package/dist/contracts/grants.js +124 -23
- package/dist/contracts/ids.d.ts +4 -1
- package/dist/contracts/ids.js +4 -1
- package/dist/contracts/internal.d.ts +5 -4
- package/dist/contracts/internal.js +12 -3
- package/dist/contracts/mcp.d.ts +17 -0
- package/dist/contracts/mcp.js +23 -0
- package/dist/contracts/me.d.ts +6 -1
- package/dist/contracts/me.js +12 -6
- package/dist/contracts/notifications.d.ts +27 -29
- package/dist/contracts/notifications.js +9 -4
- package/dist/contracts/oauth-resources.d.ts +112 -10
- package/dist/contracts/oauth-resources.js +116 -11
- package/dist/contracts/oauth-scope-actions.d.ts +90 -0
- package/dist/contracts/oauth-scope-actions.js +126 -0
- package/dist/contracts/operations.d.ts +27 -4
- package/dist/contracts/operations.js +11 -5
- package/dist/contracts/pages.d.ts +29 -5
- package/dist/contracts/pages.js +22 -5
- package/dist/contracts/partner-notifications.d.ts +3 -0
- package/dist/contracts/partner-notifications.js +65 -0
- package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
- package/dist/contracts/{platform.js → partner.js} +27 -40
- package/dist/contracts/plan-policy.d.ts +1 -1
- package/dist/contracts/principal-assertion.d.ts +43 -0
- package/dist/contracts/principal-assertion.js +67 -0
- package/dist/contracts/principals.d.ts +73 -0
- package/dist/contracts/principals.js +59 -0
- package/dist/contracts/privacy.d.ts +11 -0
- package/dist/contracts/privacy.js +17 -0
- package/dist/contracts/problem-document.js +3 -4
- package/dist/contracts/publish-archive.d.ts +116 -18
- package/dist/contracts/publish-archive.js +6 -3
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.js +3 -3
- package/dist/contracts/realtime.d.ts +52 -0
- package/dist/contracts/realtime.js +54 -0
- package/dist/contracts/repository-connections.d.ts +1 -1
- package/dist/contracts/repository-connections.js +6 -2
- package/dist/contracts/resources.d.ts +105 -14
- package/dist/contracts/resources.js +145 -21
- package/dist/contracts/route-inventory.d.ts +358 -0
- package/dist/contracts/route-inventory.js +141 -0
- package/dist/contracts/runtime-api.d.ts +112 -35
- package/dist/contracts/runtime-api.js +86 -66
- package/dist/contracts/runtime-app.d.ts +11 -21
- package/dist/contracts/runtime-app.js +39 -24
- package/dist/contracts/runtime-components.d.ts +143 -0
- package/dist/contracts/runtime-components.js +199 -0
- package/dist/contracts/runtime-db.d.ts +45 -19
- package/dist/contracts/runtime-db.js +85 -20
- package/dist/contracts/runtime-purge.js +3 -5
- package/dist/contracts/runtime-services.d.ts +43 -75
- package/dist/contracts/runtime-services.js +29 -49
- package/dist/contracts/runtime-storage.d.ts +14 -14
- package/dist/contracts/runtime-storage.js +28 -13
- package/dist/contracts/sf-config-v1.d.ts +14 -18
- package/dist/contracts/slugs.js +13 -4
- package/dist/contracts/space-config.d.ts +235 -28
- package/dist/contracts/space-config.js +246 -91
- package/dist/contracts/spaces.d.ts +360 -255
- package/dist/contracts/spaces.js +190 -122
- package/dist/contracts/superadmin-activity.d.ts +3 -43
- package/dist/contracts/superadmin-activity.js +6 -30
- package/dist/contracts/superadmin-emails.d.ts +1 -0
- package/dist/contracts/superadmin-emails.js +17 -1
- package/dist/contracts/superadmin-runtime.d.ts +199 -0
- package/dist/contracts/superadmin-runtime.js +141 -0
- package/dist/contracts/superadmin-search.d.ts +22 -2
- package/dist/contracts/superadmin-search.js +14 -6
- package/dist/contracts/superadmin-spaces.d.ts +435 -186
- package/dist/contracts/superadmin-spaces.js +131 -25
- package/dist/contracts/superadmin-teams.d.ts +3 -0
- package/dist/contracts/superadmin-teams.js +1 -2
- package/dist/contracts/superadmin-tenants.d.ts +627 -6
- package/dist/contracts/superadmin-tenants.js +32 -7
- package/dist/contracts/superadmin.d.ts +98 -16
- package/dist/contracts/superadmin.js +63 -10
- package/dist/contracts/tags.d.ts +85 -58
- package/dist/contracts/tags.js +44 -34
- package/dist/contracts/teams.d.ts +72 -9
- package/dist/contracts/teams.js +84 -25
- package/dist/contracts/tenants.d.ts +135 -0
- package/dist/contracts/tenants.js +120 -0
- package/dist/contracts/test-triggers.d.ts +70 -0
- package/dist/contracts/test-triggers.js +116 -0
- package/dist/contracts/theme-json.js +3 -8
- package/dist/contracts/transfers.d.ts +1 -0
- package/dist/contracts/transfers.js +1 -0
- package/dist/contracts/usage.d.ts +209 -0
- package/dist/contracts/usage.js +124 -12
- package/dist/contracts/variables.d.ts +2 -2
- package/dist/contracts/variables.js +9 -13
- package/dist/contracts/webhooks.d.ts +13 -5
- package/dist/contracts/webhooks.js +3 -1
- package/dist/contracts/zero.d.ts +57 -64
- package/dist/contracts/zero.js +68 -66
- package/dist/dashboard-paths/index.d.ts +24 -21
- package/dist/dashboard-paths/index.js +35 -47
- package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
- package/dist/dashboard-paths/route-reservations.generated.js +36 -0
- package/dist/docs/agent-arrival.d.ts +92 -0
- package/dist/docs/agent-arrival.js +227 -0
- package/dist/docs/agent-output-policy.d.ts +6 -0
- package/dist/docs/agent-output-policy.js +22 -0
- package/dist/docs/agent-prose.d.ts +11 -17
- package/dist/docs/agent-prose.js +62 -37
- package/dist/docs/agent-setup.d.ts +72 -41
- package/dist/docs/agent-setup.js +336 -436
- package/dist/docs/catalog.d.ts +147 -89
- package/dist/docs/catalog.js +157 -42
- package/dist/docs/error-docs.d.ts +2098 -1
- package/dist/docs/error-docs.js +281 -16
- package/dist/docs/index-build.d.ts +0 -1
- package/dist/docs/index-build.js +2 -3
- package/dist/docs/page-context-prompt.d.ts +77 -0
- package/dist/docs/page-context-prompt.js +131 -0
- package/dist/docs/reference-urls.d.ts +46 -0
- package/dist/docs/reference-urls.js +79 -0
- package/dist/docs/search.d.ts +6 -8
- package/dist/docs/search.js +10 -13
- package/dist/docs/skill-distribution.d.ts +4 -1
- package/dist/docs/skill-distribution.js +10 -5
- package/dist/docs/skills.d.ts +117 -117
- package/dist/docs/skills.js +120 -72
- package/dist/docs/start-prompts.d.ts +45 -0
- package/dist/docs/start-prompts.js +62 -0
- package/dist/domain-exploration.js +9 -13
- package/dist/og-template.d.ts +56 -0
- package/dist/og-template.js +56 -0
- package/dist/slug-policy/index.js +5 -11
- package/dist/utils/browser-credential.d.ts +13 -6
- package/dist/utils/browser-credential.js +14 -7
- package/dist/utils/build-settings.d.ts +16 -0
- package/dist/utils/build-settings.js +63 -17
- package/dist/utils/canonical-json.d.ts +3 -5
- package/dist/utils/canonical-json.js +3 -5
- package/dist/utils/cast-transport.d.ts +5 -17
- package/dist/utils/cast-transport.js +6 -19
- package/dist/utils/claim-token.js +1 -2
- package/dist/utils/comment-avatars.js +4 -6
- package/dist/utils/concurrency.js +2 -3
- package/dist/utils/content-type.d.ts +7 -6
- package/dist/utils/content-type.js +73 -51
- package/dist/utils/credential-policy.d.ts +50 -6
- package/dist/utils/credential-policy.js +123 -57
- package/dist/utils/egress-policy.fixtures.json +1 -1
- package/dist/utils/generate-space-name.d.ts +3 -8
- package/dist/utils/generate-space-name.js +3 -8
- package/dist/utils/grants.d.ts +0 -1
- package/dist/utils/grants.js +4 -7
- package/dist/utils/gravatar.d.ts +2 -4
- package/dist/utils/gravatar.js +6 -12
- package/dist/utils/id-hints.js +14 -23
- package/dist/utils/idempotency.d.ts +3 -3
- package/dist/utils/idempotency.js +6 -7
- package/dist/utils/local-space-state.d.ts +15 -15
- package/dist/utils/local-space-state.js +34 -23
- package/dist/utils/oauth-signed-query.d.ts +3 -5
- package/dist/utils/oauth-signed-query.js +6 -9
- package/dist/utils/one-shot-replay.d.ts +3 -5
- package/dist/utils/one-shot-replay.js +3 -5
- package/dist/utils/page-colors.d.ts +4 -10
- package/dist/utils/page-colors.js +11 -35
- package/dist/utils/page-fonts.js +6 -11
- package/dist/utils/page-preview.d.ts +0 -1
- package/dist/utils/page-preview.js +0 -1
- package/dist/utils/pages.d.ts +22 -11
- package/dist/utils/pages.js +70 -30
- package/dist/utils/privacy-regions.d.ts +19 -0
- package/dist/utils/privacy-regions.js +91 -0
- package/dist/utils/publish-form-data.d.ts +4 -5
- package/dist/utils/publish-form-data.js +2 -3
- package/dist/utils/publish-policy.d.ts +10 -23
- package/dist/utils/publish-policy.js +63 -116
- package/dist/utils/query-client.d.ts +2 -0
- package/dist/utils/query-client.js +10 -1
- package/dist/utils/runtime-paths.d.ts +4 -4
- package/dist/utils/runtime-paths.js +6 -8
- package/dist/utils/runtime-upload.d.ts +4 -0
- package/dist/utils/runtime-upload.js +5 -0
- package/dist/utils/secure-local-file.d.ts +3 -3
- package/dist/utils/secure-local-file.js +18 -24
- package/dist/utils/space-config.d.ts +11 -14
- package/dist/utils/space-config.js +10 -16
- package/dist/utils/static-runtime-policy.d.ts +5 -8
- package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
- package/dist/utils/static-runtime-policy.generated.js +70 -0
- package/dist/utils/static-runtime-policy.js +17 -84
- package/dist/utils/storage-policy.js +1 -2
- package/dist/utils/upload-session.js +8 -14
- package/dist/utils/version-path.js +11 -19
- package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
- package/dist/utils/wpcom-auth-redirects.js +1 -4
- package/dist/vocabulary.d.ts +7 -7
- package/dist/vocabulary.js +30 -16
- package/package.json +14 -2
- package/dist/agents/client-registry.d.ts +0 -22
- package/dist/agents/client-registry.js +0 -41
- package/dist/docs/agent-handoff-document.d.ts +0 -15
- package/dist/docs/agent-handoff-document.js +0 -180
- package/dist/docs/agent-solutions.d.ts +0 -110
- package/dist/docs/agent-solutions.js +0 -183
- package/dist/utils/query-keys.d.ts +0 -84
- package/dist/utils/query-keys.js +0 -108
|
@@ -2,21 +2,17 @@ import { BRAND } from "../brand.js";
|
|
|
2
2
|
import { WORST_CASE_QUOTAS } from "../contracts/quotas.js";
|
|
3
3
|
import { SPACE_CONFIG_PRIVATE_FILES } from "../contracts/space-config.js";
|
|
4
4
|
import { ZERO_RUNTIME_DEPLOY_PATH } from "../contracts/zero.js";
|
|
5
|
-
// The ONE static publish policy (
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// local preflight, inline archive extraction, and the runtime parity fixtures
|
|
9
|
-
// (the PHP twin is runtime/engine/admin/upload-policy.php).
|
|
5
|
+
// The ONE static publish policy (spec "Upload Contract"), shared by API
|
|
6
|
+
// manifest validation, CLI preflight and archive extraction. The PHP twin is
|
|
7
|
+
// runtime/engine/admin/upload-policy.php.
|
|
10
8
|
import { canonicalizeVersionPath, normalizeVersionPath } from "./version-path.js";
|
|
11
|
-
// Manifest scale caps (spec "Upload Contract")
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// 16 MB, enforced fail-early before any upload session exists.
|
|
9
|
+
// Manifest scale caps (spec "Upload Contract"). Plan policy may LOWER the
|
|
10
|
+
// file-count ceiling (Free 20,000), never raise it. All are enforced before
|
|
11
|
+
// any upload session exists.
|
|
15
12
|
export const MANIFEST_MAX_FILES_CEILING = 100_000;
|
|
16
13
|
export const MANIFEST_MAX_PATH_BYTES = 1024;
|
|
17
14
|
export const MANIFEST_MAX_BODY_BYTES = 16 * 1024 * 1024;
|
|
18
15
|
export const MAX_VERSION_FILE_SIZE_BYTES = 64 * 1024 * 1024;
|
|
19
|
-
// Worst-case artifact ceiling lives in the named raise-only quota table.
|
|
20
16
|
export const MAX_VERSION_TOTAL_BYTES = WORST_CASE_QUOTAS.maxArtifactBytes;
|
|
21
17
|
const IGNORED_EXACT_PATHS = new Set([
|
|
22
18
|
".DS_Store",
|
|
@@ -28,8 +24,7 @@ const IGNORED_EXACT_PATHS = new Set([
|
|
|
28
24
|
".env.test",
|
|
29
25
|
".npmrc",
|
|
30
26
|
".netrc",
|
|
31
|
-
// CLI checkout state
|
|
32
|
-
// user archives may contain either; both stay out of every publish).
|
|
27
|
+
// CLI checkout state. Both spellings appear in user archives.
|
|
33
28
|
".spacefast/state.json",
|
|
34
29
|
".stattic/state.json",
|
|
35
30
|
"_routes.json",
|
|
@@ -57,33 +52,22 @@ const SENSITIVE_FILE_PATTERNS = [
|
|
|
57
52
|
// Denied runtime private/control paths (spec "Static path policy").
|
|
58
53
|
// Every list below is generated verbatim into runtime/engine/admin/upload-policy.php
|
|
59
54
|
// by apps/control-plane/src/scripts/codegen-php-policy.ts, so the two enforcers
|
|
60
|
-
// cannot hold different literals. Lowercase only
|
|
55
|
+
// cannot hold different literals. Lowercase only; both sides fold the path first.
|
|
61
56
|
export const STATIC_EXECUTION_CONTROL_FILES = [".htaccess", ".user.ini"];
|
|
62
|
-
//
|
|
63
|
-
// `/__spacefast
|
|
64
|
-
// (`/__stattic_probe` today, more `/__stattic/*` routes planned) stays
|
|
65
|
-
// reserved the same way. Mid-segment occurrences are ordinary content.
|
|
57
|
+
// Matched by PREFIX, so the runtime owns `__spacefast_generated/` as well as
|
|
58
|
+
// `/__spacefast/*`. Mid-segment occurrences are ordinary content.
|
|
66
59
|
export const STATIC_RUNTIME_CONTROL_SEGMENT_PREFIXES = ["__spacefast", "__stattic"];
|
|
67
|
-
// Reserved as WHOLE root segments
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
// starts_with('/__sf/')`, so `/__sfx/...` and `/__spanish/page` are ordinary
|
|
71
|
-
// tenant paths. Reserving more than the front door claims would refuse a publish
|
|
72
|
-
// of content the front door then happily serves as tenant content.
|
|
60
|
+
// Reserved as WHOLE root segments, so `/__sfx/...` and `/__spanish/page` are
|
|
61
|
+
// ordinary tenant paths. Reserving more than the front door claims would refuse
|
|
62
|
+
// a publish of content the front door then serves anyway.
|
|
73
63
|
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
// time, where serve.php refuses to let either a published file or a routing rule
|
|
79
|
-
// answer a reserved route, and that refusal is what runtime/tests/collab-frame.test.ts
|
|
80
|
-
// exercises by publishing a file at `__/collab` on purpose. The control table is
|
|
81
|
-
// the authority; this list is a publish-time convenience, so keep it a subset
|
|
82
|
-
// and never let it contradict the table.
|
|
64
|
+
// A SUBSET of what the control table in runtime/engine/shared/context.php
|
|
65
|
+
// reserves, never a mirror: the table also reserves `/__/collab`, enforced at
|
|
66
|
+
// request time by serve.php. The table is the authority; keep this list a
|
|
67
|
+
// subset of it.
|
|
83
68
|
export const STATIC_RUNTIME_ROOT_SEGMENTS = ["__sf", "__span"];
|
|
84
|
-
// Both
|
|
85
|
-
//
|
|
86
|
-
// legacy on-disk layout, and user archives may carry either name.
|
|
69
|
+
// Both spellings stay denied: spaces published before the `.stattic` →
|
|
70
|
+
// `.spacefast` rename still serve from the legacy on-disk layout.
|
|
87
71
|
export const STATIC_RUNTIME_CONTROL_PATHS = [
|
|
88
72
|
".well-known/spacefast-runtime",
|
|
89
73
|
".well-known/stattic-runtime",
|
|
@@ -98,39 +82,23 @@ export function normalizePublishPath(relativePath) {
|
|
|
98
82
|
return relativePath.replace(/\\/g, "/").replace(/^\/+/g, "");
|
|
99
83
|
}
|
|
100
84
|
/**
|
|
101
|
-
* The one subtree inside the runtime control prefix
|
|
85
|
+
* The one subtree inside the runtime control prefix a publish may write, so a
|
|
86
|
+
* compiled worker bundle travels the ordinary manifest and upload path while
|
|
87
|
+
* staying unservable as static content.
|
|
102
88
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* needing a parallel one. Keeping it under the control prefix is what makes it
|
|
106
|
-
* unservable as static content by default — the runtime answers it only behind a
|
|
107
|
-
* signature.
|
|
108
|
-
*
|
|
109
|
-
* Scoped to `bundles/` rather than the whole `__spacefast/functions/` directory
|
|
110
|
-
* on purpose: the sibling `config.json` holds the key those signatures are
|
|
111
|
-
* minted with, and a publish that could overwrite it would be a publish that
|
|
112
|
-
* could mint its own tokens.
|
|
89
|
+
* Scoped to `bundles/`, not the whole `__spacefast/functions/` directory: the
|
|
90
|
+
* sibling `config.json` holds the key its signatures are minted with.
|
|
113
91
|
*/
|
|
114
92
|
export const PUBLISHABLE_BUILD_ARTIFACT_PREFIX = "__spacefast/functions/bundles/";
|
|
115
|
-
/**
|
|
116
|
-
* The bundle carve-out's sibling for the Next-cache seed document: the same
|
|
117
|
-
* reasoning (travel through the ordinary manifest and upload path, stay
|
|
118
|
-
* unservable by default), the same deliberate narrowness (a prefix of its
|
|
119
|
-
* own, never the whole `functions/` directory — see the bundle comment).
|
|
120
|
-
*/
|
|
93
|
+
/** The same carve-out for the Next-cache seed document. */
|
|
121
94
|
export const PUBLISHABLE_SEED_ARTIFACT_PREFIX = "__spacefast/functions/seeds/";
|
|
122
95
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* the Functions bundle above, same channel.
|
|
130
|
-
*
|
|
131
|
-
* One exact path, not a prefix: its siblings under `__spacefast/zero/` are the
|
|
132
|
-
* runtime's own artifact, config and binary, and a publish that could overwrite
|
|
133
|
-
* those would be a publish that could replace the runtime.
|
|
96
|
+
* ZERO_RUNTIME_DEPLOY_PATH is the one FILE a publish may write inside the
|
|
97
|
+
* control prefix. A Zero capsule's server travels as version metadata, so a
|
|
98
|
+
* server-only change would otherwise ship a byte-identical shell that the
|
|
99
|
+
* manifest comparison reads as "no changes"; the deploy digest moves it. One
|
|
100
|
+
* exact path, not a prefix: its siblings under `__spacefast/zero/` are the
|
|
101
|
+
* runtime's own artifact, config and binary.
|
|
134
102
|
*/
|
|
135
103
|
function isPublishableBuildArtifactPath(normalizedPath, lowerPath) {
|
|
136
104
|
return (lowerPath.startsWith(PUBLISHABLE_BUILD_ARTIFACT_PREFIX) ||
|
|
@@ -139,10 +107,9 @@ function isPublishableBuildArtifactPath(normalizedPath, lowerPath) {
|
|
|
139
107
|
}
|
|
140
108
|
export function publishPathIgnored(relativePath) {
|
|
141
109
|
const path = normalizePublishPath(relativePath);
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
// content in the same dirs (e.g. the legacy .stattic/routes.json convention).
|
|
110
|
+
// Drop these files at any depth so a checkout archived one level too high
|
|
111
|
+
// never ships a claim token, while other content in the same dirs still
|
|
112
|
+
// publishes (e.g. the legacy .stattic/routes.json convention).
|
|
146
113
|
if (/(?:^|\/)\.(?:spacefast|stattic)\/(?:state|space)\.json$/.test(path) ||
|
|
147
114
|
/(?:^|\/)\.spacefast-(?:[0-9a-f-]{36}\.(?:tmp|rollback|retired)|[0-9a-f]{24}\.lock)$/.test(path)) {
|
|
148
115
|
return true;
|
|
@@ -159,11 +126,9 @@ export function publishPathIgnored(relativePath) {
|
|
|
159
126
|
export function publishPathIsConvention(relativePath) {
|
|
160
127
|
return RESERVED_CONVENTION_PATHS.has(normalizePublishPath(relativePath));
|
|
161
128
|
}
|
|
162
|
-
// Provider runtime features
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
// with a warning so migrations are never silent. A root `functions/` directory
|
|
166
|
-
// is Spacefast's own file-router convention and must never reach this warning.
|
|
129
|
+
// Provider runtime features with no Spacefast equivalent publish as inert
|
|
130
|
+
// content with a warning, so migrations are never silent. A root `functions/`
|
|
131
|
+
// directory is Spacefast's own convention and must never reach this warning.
|
|
167
132
|
function providerRuntimeFeatureForPath(path) {
|
|
168
133
|
if (path === "_worker.js") {
|
|
169
134
|
return "Cloudflare Pages _worker.js";
|
|
@@ -218,9 +183,8 @@ export function staticUploadPathViolation(path, options = {}) {
|
|
|
218
183
|
return pathViolation("invalid_file_path", "File path is invalid.", rawPath);
|
|
219
184
|
}
|
|
220
185
|
if (normalizedPath !== rawPath) {
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
// this policy used to report a different string than the runtime's copy.
|
|
186
|
+
// Echo the path the caller sent; a rewritten one would suggest the
|
|
187
|
+
// rewrite was accepted.
|
|
224
188
|
return pathViolation("invalid_file_path", "File path is invalid.", rawPath);
|
|
225
189
|
}
|
|
226
190
|
if (new TextEncoder().encode(normalizedPath).length > MANIFEST_MAX_PATH_BYTES) {
|
|
@@ -288,12 +252,10 @@ export function canonicalizePublishRequestedRoute(route) {
|
|
|
288
252
|
return segments.length === 0 ? "/" : `/${segments.join("/")}`;
|
|
289
253
|
}
|
|
290
254
|
/**
|
|
291
|
-
* Expands artifact paths into the request routes they can serve
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* expansion in canonical access-route form so authorization and diagnostics
|
|
296
|
-
* never have to infer a route from an artifact path.
|
|
255
|
+
* Expands artifact paths into the request routes they can serve: literal
|
|
256
|
+
* files, directory indexes and clean `.html` aliases. Two artifacts owning one
|
|
257
|
+
* route is rejected at publish rather than left to lookup order.
|
|
258
|
+
* `routeOwnership` restates the expansion in canonical access-route form.
|
|
297
259
|
*/
|
|
298
260
|
export function analyzePublishRoutes(paths, options = {}) {
|
|
299
261
|
const index = options.index === undefined ? "index.html" : options.index;
|
|
@@ -362,12 +324,10 @@ export function analyzePublishRoutes(paths, options = {}) {
|
|
|
362
324
|
export function resolveManifestFileCap(maxFiles) {
|
|
363
325
|
return Math.min(MANIFEST_MAX_FILES_CEILING, maxFiles && maxFiles > 0 ? maxFiles : MANIFEST_MAX_FILES_CEILING);
|
|
364
326
|
}
|
|
365
|
-
// The shared manifest validator (spec "Upload Contract")
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
// extraction routes through the same checks. Returns the manifest with
|
|
370
|
-
// canonical paths — callers use the returned files, never the input.
|
|
327
|
+
// The shared manifest validator (spec "Upload Contract"). Runs BEFORE any
|
|
328
|
+
// upload session is created; archive extraction routes through the same
|
|
329
|
+
// checks. Returns canonical paths, so callers use the returned files, never
|
|
330
|
+
// the input.
|
|
371
331
|
export function validatePublishManifest(files, caps = {}) {
|
|
372
332
|
const maxFiles = resolveManifestFileCap(caps.maxFiles);
|
|
373
333
|
if (files.length > maxFiles) {
|
|
@@ -424,15 +384,13 @@ export function validatePublishManifest(files, caps = {}) {
|
|
|
424
384
|
warnings: [],
|
|
425
385
|
};
|
|
426
386
|
}
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
// high must never publish a claim token to the live site, and failing the
|
|
430
|
-
// whole manifest for it would punish the common accident.
|
|
387
|
+
// Dropped rather than rejected: failing a whole manifest over a stray
|
|
388
|
+
// .env or .spacefast/ would punish the common accident.
|
|
431
389
|
if (publishPathIgnored(canonicalPath)) {
|
|
432
390
|
continue;
|
|
433
391
|
}
|
|
434
|
-
//
|
|
435
|
-
//
|
|
392
|
+
// Distinct paths here, but they cannot round-trip a case-insensitive
|
|
393
|
+
// filesystem.
|
|
436
394
|
const lowercase = canonicalPath.toLowerCase();
|
|
437
395
|
const caseSibling = lowercasePaths.get(lowercase);
|
|
438
396
|
if (caseSibling !== undefined && caseSibling !== canonicalPath) {
|
|
@@ -494,8 +452,7 @@ const FREE_PLAN_ALLOWED_UPLOAD_EXTENSIONS = new Set([
|
|
|
494
452
|
".txt",
|
|
495
453
|
".md",
|
|
496
454
|
".csv",
|
|
497
|
-
//
|
|
498
|
-
// application/octet-stream by the runtime.
|
|
455
|
+
// Migration fixtures, served as application/octet-stream.
|
|
499
456
|
".customtype",
|
|
500
457
|
".xml",
|
|
501
458
|
".svg",
|
|
@@ -511,13 +468,10 @@ const FREE_PLAN_ALLOWED_UPLOAD_EXTENSIONS = new Set([
|
|
|
511
468
|
".ttf",
|
|
512
469
|
".otf",
|
|
513
470
|
]);
|
|
514
|
-
// THE anonymous content enforcement
|
|
515
|
-
//
|
|
516
|
-
//
|
|
517
|
-
//
|
|
518
|
-
// enforces the list without knowing it means "anonymous"). Web-page content
|
|
519
|
-
// only — no opaque octet-streams, archives (except scanned gzip, which
|
|
520
|
-
// pagefind search indexes depend on), documents, or media containers.
|
|
471
|
+
// THE anonymous content enforcement: uploads are accepted like any free
|
|
472
|
+
// publish, but until the space is claimed the runtime serves only these types,
|
|
473
|
+
// pushed as the route-config `content_types` allowlist. Web-page content only.
|
|
474
|
+
// Gzip is the one archive, because pagefind search indexes need it.
|
|
521
475
|
export const ANONYMOUS_SERVE_CONTENT_TYPES = [
|
|
522
476
|
"text/*",
|
|
523
477
|
"image/*",
|
|
@@ -542,20 +496,14 @@ function freePlanDeniedExecutablePath(filePath) {
|
|
|
542
496
|
.split("/")
|
|
543
497
|
.some((segment) => segment === "bin");
|
|
544
498
|
}
|
|
545
|
-
// Acceptance is deliberately identical for claimed-free and unclaimed
|
|
546
|
-
//
|
|
547
|
-
//
|
|
548
|
-
//
|
|
549
|
-
// SERVE-time content-type allowlist (ANONYMOUS_SERVE_CONTENT_TYPES via the
|
|
550
|
-
// route-config `content_types` policy) is what keeps opaque binaries dark
|
|
551
|
-
// until the space is claimed.
|
|
499
|
+
// Acceptance is deliberately identical for claimed-free and unclaimed spaces:
|
|
500
|
+
// rejecting types at upload adds no safety, since the bytes reach us before
|
|
501
|
+
// any scan either way. ANONYMOUS_SERVE_CONTENT_TYPES is what keeps opaque
|
|
502
|
+
// binaries dark until the space is claimed.
|
|
552
503
|
export function freePlanCanUploadPath(filePath, options) {
|
|
553
504
|
const path = normalizePublishPath(filePath);
|
|
554
|
-
//
|
|
555
|
-
//
|
|
556
|
-
// `_redirects`/`_headers`) — the plan's content-extension gate must never
|
|
557
|
-
// eat it (e2e checkpoint 4: it was silently dropped on free publishes,
|
|
558
|
-
// disabling fallback/meta/templates/theme for every free space).
|
|
505
|
+
// Platform machinery, not user content: same lifecycle as
|
|
506
|
+
// `_redirects`/`_headers`, so the content-extension gate must never eat them.
|
|
559
507
|
if (SPACE_CONFIG_PRIVATE_FILES.includes(path)) {
|
|
560
508
|
return true;
|
|
561
509
|
}
|
|
@@ -579,8 +527,7 @@ export function freePlanCanUploadContentType(contentType) {
|
|
|
579
527
|
normalized === "application/javascript" ||
|
|
580
528
|
normalized === "application/json" ||
|
|
581
529
|
normalized === "application/manifest+json" ||
|
|
582
|
-
//
|
|
583
|
-
// ship as gzip fragments, and ClamAV decompresses gzip when scanning.
|
|
530
|
+
// pagefind ships gzip fragments, and ClamAV decompresses gzip when scanning.
|
|
584
531
|
normalized === "application/gzip" ||
|
|
585
532
|
normalized === "image/svg+xml" ||
|
|
586
533
|
normalized === "application/xml" ||
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
/**
|
|
3
|
+
* Freshness for a caller that has not adopted a tiered caching policy.
|
|
4
|
+
*
|
|
5
|
+
* The tiers themselves (`STALE_TIME_MS`) live in `@spacefast/sdk/query`, which
|
|
6
|
+
* depends on this package — so they cannot be imported here and arrive as an
|
|
7
|
+
* argument instead. The dashboard passes `STALE_TIME_MS.normal`; superadmin
|
|
8
|
+
* still runs on this default.
|
|
9
|
+
*/
|
|
10
|
+
const UNTIERED_STALE_TIME_MS = 60_000;
|
|
2
11
|
export function createSpacefastQueryClient(options) {
|
|
3
12
|
return new QueryClient({
|
|
4
13
|
defaultOptions: {
|
|
@@ -12,7 +21,7 @@ export function createSpacefastQueryClient(options) {
|
|
|
12
21
|
}
|
|
13
22
|
return failureCount < 2;
|
|
14
23
|
},
|
|
15
|
-
staleTime:
|
|
24
|
+
staleTime: options?.staleTime ?? UNTIERED_STALE_TIME_MS,
|
|
16
25
|
refetchOnWindowFocus: true,
|
|
17
26
|
refetchOnReconnect: true,
|
|
18
27
|
},
|
|
@@ -2,13 +2,13 @@ export declare const SPACEFAST_RUNTIME_NAMESPACE: "/__spacefast";
|
|
|
2
2
|
export declare const RUNTIME_MANAGEMENT_API_PATH: "/__spacefast/api.php";
|
|
3
3
|
export declare const RUNTIME_UPLOAD_API_PATH: "/__spacefast/upload.php";
|
|
4
4
|
export declare const RUNTIME_HEALTH_PATH: "/__spacefast/health.php";
|
|
5
|
+
export declare const RUNTIME_CONTENT_API_PATH: "/__spacefast/content.php";
|
|
5
6
|
export declare const RUNTIME_COMMENTS_CONFIG_PATH: "/__spacefast/comments/config";
|
|
6
7
|
export declare const RUNTIME_COMMENTS_TICKET_PATH: "/__spacefast/comments/ticket";
|
|
7
8
|
export declare const RUNTIME_COMMENTS_VERSION_URLS_PATH: "/__spacefast/comments/version-urls";
|
|
8
|
-
/** The review workspace the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* The PHP mirror is SPACEFAST_COLLAB_FRAME_PATH in runtime/engine/shared/context.php. */
|
|
9
|
+
/** The review workspace, on the Space's own origin and outside the
|
|
10
|
+
* `/__spacefast` exchange namespace because people paste it into Slack.
|
|
11
|
+
* The PHP mirror is SPACEFAST_COLLAB_FRAME_PATH in shared/context.php. */
|
|
12
12
|
export declare const RUNTIME_COLLAB_FRAME_PATH: "/__/collab";
|
|
13
13
|
export declare function runtimeManagementPath(suffix: string): string;
|
|
14
14
|
export declare function runtimeUploadPath(params: URLSearchParams | Record<string, string>): string;
|
|
@@ -2,17 +2,15 @@ export const SPACEFAST_RUNTIME_NAMESPACE = "/__spacefast";
|
|
|
2
2
|
export const RUNTIME_MANAGEMENT_API_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/api.php`;
|
|
3
3
|
export const RUNTIME_UPLOAD_API_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/upload.php`;
|
|
4
4
|
export const RUNTIME_HEALTH_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/health.php`;
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
// runtime/
|
|
8
|
-
// packages/collab-sdk/test/entry.test.ts pins the SDK side to these literals.
|
|
5
|
+
export const RUNTIME_CONTENT_API_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/content.php`;
|
|
6
|
+
// Same-origin Comments exchange paths. The PHP mirror is
|
|
7
|
+
// SPACEFAST_COMMENTS_*_PATH in runtime/engine/shared/context.php.
|
|
9
8
|
export const RUNTIME_COMMENTS_CONFIG_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/comments/config`;
|
|
10
9
|
export const RUNTIME_COMMENTS_TICKET_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/comments/ticket`;
|
|
11
10
|
export const RUNTIME_COMMENTS_VERSION_URLS_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/comments/version-urls`;
|
|
12
|
-
/** The review workspace the
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* The PHP mirror is SPACEFAST_COLLAB_FRAME_PATH in runtime/engine/shared/context.php. */
|
|
11
|
+
/** The review workspace, on the Space's own origin and outside the
|
|
12
|
+
* `/__spacefast` exchange namespace because people paste it into Slack.
|
|
13
|
+
* The PHP mirror is SPACEFAST_COLLAB_FRAME_PATH in shared/context.php. */
|
|
16
14
|
export const RUNTIME_COLLAB_FRAME_PATH = "/__/collab";
|
|
17
15
|
export function runtimeManagementPath(suffix) {
|
|
18
16
|
const route = normalizeRuntimeRoute(suffix);
|
|
@@ -9,6 +9,10 @@ export declare function runtimeUploadFileUrl(input: {
|
|
|
9
9
|
uploadId: string;
|
|
10
10
|
path: string;
|
|
11
11
|
}): string;
|
|
12
|
+
export declare function runtimeUploadBlobsHaveUrl(input: {
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
spaceId: string;
|
|
15
|
+
}): string;
|
|
12
16
|
export declare function runtimeUploadBlobUrl(input: {
|
|
13
17
|
baseUrl: string;
|
|
14
18
|
spaceId: string;
|
|
@@ -22,6 +22,11 @@ export function runtimeUploadFileUrl(input) {
|
|
|
22
22
|
path: runtimeUploadCanonicalPath(input.path),
|
|
23
23
|
}), input.baseUrl).toString();
|
|
24
24
|
}
|
|
25
|
+
export function runtimeUploadBlobsHaveUrl(input) {
|
|
26
|
+
return new URL(runtimeUploadPath({
|
|
27
|
+
route: `/spaces/${encodeURIComponent(input.spaceId)}/blobs/have`,
|
|
28
|
+
}), input.baseUrl).toString();
|
|
29
|
+
}
|
|
25
30
|
export function runtimeUploadBlobUrl(input) {
|
|
26
31
|
return new URL(runtimeUploadPath({
|
|
27
32
|
route: `/spaces/${encodeURIComponent(input.spaceId)}/blobs/${encodeURIComponent(input.sha256)}`,
|
|
@@ -51,9 +51,9 @@ export declare function secureOutputLocation(trustedPath: string, outputPath: st
|
|
|
51
51
|
};
|
|
52
52
|
/**
|
|
53
53
|
* Writes beneath an explicitly trusted root without following output-tree
|
|
54
|
-
* symlinks. Linux uses descriptor-relative operations; other
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
* symlinks. Linux uses descriptor-relative operations; other platforms use
|
|
55
|
+
* exclusive staging plus before-and-after ancestor identity validation, and
|
|
56
|
+
* fail closed if any binding changes.
|
|
57
57
|
*/
|
|
58
58
|
export declare function secureWriteFile(options: SecureWriteOptions): Promise<void>;
|
|
59
59
|
export declare function secureReadFile(options: SecureReadOptions & {
|
|
@@ -236,10 +236,9 @@ async function canonicalPortableWriteRoot(rootInput) {
|
|
|
236
236
|
async function openPortableChildDirectory(identities, visibleParent, component, create) {
|
|
237
237
|
assertSafeComponent(component);
|
|
238
238
|
const childPath = path.join(visibleParent, component);
|
|
239
|
-
// A missing directory is the normal "file not found"
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
// fails closed because an observed ancestor binding changed mid-read.
|
|
239
|
+
// A missing directory is the normal "file not found" for secure reads, so
|
|
240
|
+
// probe before identity capture. A later disappearance still fails closed in
|
|
241
|
+
// visibleDirectoryIdentity.
|
|
243
242
|
if (!create) {
|
|
244
243
|
await lstat(childPath);
|
|
245
244
|
}
|
|
@@ -465,8 +464,7 @@ async function unlinkOwnedLeafLockArtifact(lockPath, artifactPath, nonce) {
|
|
|
465
464
|
return;
|
|
466
465
|
}
|
|
467
466
|
// The pathname changed after its owner was inspected. Restore the exact inode
|
|
468
|
-
// when the name is
|
|
469
|
-
// one displaced so contenders detect it instead of deleting a fresh owner.
|
|
467
|
+
// when the name is free; otherwise keep it displaced so contenders detect it.
|
|
470
468
|
let restored = false;
|
|
471
469
|
try {
|
|
472
470
|
await link(retiredPath, artifactPath);
|
|
@@ -544,14 +542,12 @@ async function acquireLeafLock(lockPath, temporaryPath) {
|
|
|
544
542
|
if (released)
|
|
545
543
|
return;
|
|
546
544
|
released = true;
|
|
547
|
-
// Move the canonical name into unique
|
|
548
|
-
//
|
|
549
|
-
// publish, but cleanup only ever unlinks the retired name it inspected.
|
|
545
|
+
// Move the canonical name into unique custody while its inode is still
|
|
546
|
+
// active; cleanup only ever unlinks the retired name it inspected.
|
|
550
547
|
await unlinkOwnedLeafLockArtifact(lockPath, lockPath, owner.nonce).catch(() => undefined);
|
|
551
548
|
try {
|
|
552
|
-
// A delayed stale reclaimer may
|
|
553
|
-
//
|
|
554
|
-
// reclaimed even though this process remains alive.
|
|
549
|
+
// A delayed stale reclaimer may hold this inode at a displaced name.
|
|
550
|
+
// Mark it complete through the handle so it can still be reclaimed.
|
|
555
551
|
const releasedWrite = await acquiredHandle.write(Buffer.from("R"), 0, 1, 0);
|
|
556
552
|
if (releasedWrite.bytesWritten === 1)
|
|
557
553
|
await acquiredHandle.sync();
|
|
@@ -598,16 +594,15 @@ async function acquireLeafLock(lockPath, temporaryPath) {
|
|
|
598
594
|
}
|
|
599
595
|
const displaced = await readLeafLockRecord(displacedPath);
|
|
600
596
|
if (!(await leafLockRecordIsStale(displaced))) {
|
|
601
|
-
// A fresh owner won between our stale read and rename. Put its exact
|
|
602
|
-
// back
|
|
603
|
-
//
|
|
597
|
+
// A fresh owner won between our stale read and rename. Put its exact
|
|
598
|
+
// inode back; contenders scan displaced names before entering, so a live
|
|
599
|
+
// writer is never silently unlocked.
|
|
604
600
|
try {
|
|
605
601
|
await link(displacedPath, lockPath);
|
|
606
602
|
}
|
|
607
603
|
catch (error) {
|
|
608
604
|
if (isMissing(error)) {
|
|
609
|
-
// Its owner
|
|
610
|
-
// Nothing remains to restore; compete again for the now-current name.
|
|
605
|
+
// Its owner finished cleanup; compete again for the current name.
|
|
611
606
|
await delay(LEAF_LOCK_RETRY_DELAY_MS);
|
|
612
607
|
continue;
|
|
613
608
|
}
|
|
@@ -857,10 +852,9 @@ async function commitPortableStagedFile(input) {
|
|
|
857
852
|
}
|
|
858
853
|
}
|
|
859
854
|
async function secureWriteFilePortable(options) {
|
|
860
|
-
//
|
|
861
|
-
//
|
|
862
|
-
//
|
|
863
|
-
// component-by-component without following symlinks.
|
|
855
|
+
// Canonicalize the trusted root once so system aliases like macOS
|
|
856
|
+
// `/var -> /private/var` don't look like attacker-controlled children.
|
|
857
|
+
// Everything below it is still walked without following symlinks.
|
|
864
858
|
const root = await canonicalPortableWriteRoot(options.root);
|
|
865
859
|
const relativePath = validateRelativePath(options.relativePath, "write");
|
|
866
860
|
const components = relativePath.split(path.sep);
|
|
@@ -923,9 +917,9 @@ async function secureWriteFilePortable(options) {
|
|
|
923
917
|
}
|
|
924
918
|
/**
|
|
925
919
|
* Writes beneath an explicitly trusted root without following output-tree
|
|
926
|
-
* symlinks. Linux uses descriptor-relative operations; other
|
|
927
|
-
*
|
|
928
|
-
*
|
|
920
|
+
* symlinks. Linux uses descriptor-relative operations; other platforms use
|
|
921
|
+
* exclusive staging plus before-and-after ancestor identity validation, and
|
|
922
|
+
* fail closed if any binding changes.
|
|
929
923
|
*/
|
|
930
924
|
export async function secureWriteFile(options) {
|
|
931
925
|
if ((options.data === undefined) === (options.write === undefined)) {
|
|
@@ -16,18 +16,15 @@ type SpaceConfigBlockingIssue = SpaceConfigIssue & {
|
|
|
16
16
|
code: SpaceConfigBlockingIssueCode;
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
|
-
* Keys a committed `sf.jsonc` owns outright
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* overlay. API intake refuses them rather than storing or dropping them.
|
|
19
|
+
* Keys a committed `sf.jsonc` owns outright. They are facts about a version's
|
|
20
|
+
* content, so they roll forward and back with it instead of living in the
|
|
21
|
+
* space's mutable overlay. API intake refuses them.
|
|
23
22
|
*/
|
|
24
|
-
export declare const SPACE_CONFIG_FILE_ONLY_KEYS: readonly ["access", "name", "runtime"];
|
|
23
|
+
export declare const SPACE_CONFIG_FILE_ONLY_KEYS: readonly ["access", "name", "runtime", "system"];
|
|
25
24
|
/**
|
|
26
|
-
* Validates a space `config` overlay at API intake
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* acceptable. Takes the raw request value, because the overlay schema strips
|
|
30
|
-
* file-only keys and this is what has to see them.
|
|
25
|
+
* Validates a space `config` overlay at API intake, returning the first
|
|
26
|
+
* blocking issue or null. Takes the RAW request value: the overlay schema
|
|
27
|
+
* strips file-only keys, and this is what has to see them.
|
|
31
28
|
*/
|
|
32
29
|
export declare function spaceConfigOverlayIssue(config: unknown): SpaceConfigBlockingIssue | null;
|
|
33
30
|
export declare function stripJsonComments(raw: string): string;
|
|
@@ -37,16 +34,16 @@ export type ResolvedServingConfig = {
|
|
|
37
34
|
path: string;
|
|
38
35
|
status: 200 | 404;
|
|
39
36
|
} | null;
|
|
40
|
-
/**
|
|
37
|
+
/** Serve flat `<name>.html` at its extensionless URL. */
|
|
41
38
|
cleanUrls: boolean;
|
|
42
39
|
listing: boolean;
|
|
43
40
|
viewer: boolean;
|
|
44
41
|
meta: NonNullable<SpaceConfig["meta"]> | null;
|
|
45
|
-
/** Theme tokens for every Spacefast-authored page
|
|
42
|
+
/** Theme tokens for every Spacefast-authored page. */
|
|
46
43
|
pageTheme: NonNullable<SpaceConfig["theme"]> | null;
|
|
47
|
-
/** Hidden experimental build-pipeline flag
|
|
44
|
+
/** Hidden experimental build-pipeline flag. */
|
|
48
45
|
experimentalGutenberg: boolean;
|
|
49
|
-
/**
|
|
46
|
+
/** Only honored when experimentalGutenberg is true. */
|
|
50
47
|
inject: NonNullable<SpaceConfig["inject"]> | null;
|
|
51
48
|
};
|
|
52
49
|
export type SpaceSettingsPatch = {
|
|
@@ -42,9 +42,7 @@ function capIssues(candidate) {
|
|
|
42
42
|
details: { count: templates.length, limit: SPACE_CONFIG_CAPS.templates },
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
// inject
|
|
46
|
-
// shape and byte caps fail with the stable codes here, before zod, so intake
|
|
47
|
-
// reports inject_invalid / inject_snippet_too_large instead of shape errors.
|
|
45
|
+
// inject is a hidden feature, honored only with experimental_gutenberg.
|
|
48
46
|
const inject = candidate.inject;
|
|
49
47
|
if (inject !== undefined) {
|
|
50
48
|
if (typeof inject !== "object" || inject === null || Array.isArray(inject)) {
|
|
@@ -126,18 +124,15 @@ function capIssues(candidate) {
|
|
|
126
124
|
return issues;
|
|
127
125
|
}
|
|
128
126
|
/**
|
|
129
|
-
* Keys a committed `sf.jsonc` owns outright
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* overlay. API intake refuses them rather than storing or dropping them.
|
|
127
|
+
* Keys a committed `sf.jsonc` owns outright. They are facts about a version's
|
|
128
|
+
* content, so they roll forward and back with it instead of living in the
|
|
129
|
+
* space's mutable overlay. API intake refuses them.
|
|
133
130
|
*/
|
|
134
|
-
export const SPACE_CONFIG_FILE_ONLY_KEYS = ["access", "name", "runtime"];
|
|
131
|
+
export const SPACE_CONFIG_FILE_ONLY_KEYS = ["access", "name", "runtime", "system"];
|
|
135
132
|
/**
|
|
136
|
-
* Validates a space `config` overlay at API intake
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* acceptable. Takes the raw request value, because the overlay schema strips
|
|
140
|
-
* file-only keys and this is what has to see them.
|
|
133
|
+
* Validates a space `config` overlay at API intake, returning the first
|
|
134
|
+
* blocking issue or null. Takes the RAW request value: the overlay schema
|
|
135
|
+
* strips file-only keys, and this is what has to see them.
|
|
141
136
|
*/
|
|
142
137
|
export function spaceConfigOverlayIssue(config) {
|
|
143
138
|
if (config === null || config === undefined || typeof config !== "object") {
|
|
@@ -166,9 +161,8 @@ export function spaceConfigOverlayIssue(config) {
|
|
|
166
161
|
}
|
|
167
162
|
return capIssues(config)[0] ?? null;
|
|
168
163
|
}
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
// files the CLI reads (agent configs, exported platform env).
|
|
164
|
+
// The config file itself is parsed by the crate; this stays for the OTHER
|
|
165
|
+
// JSONC files the CLI reads (agent configs, exported platform env).
|
|
172
166
|
export function stripJsonComments(raw) {
|
|
173
167
|
let output = "";
|
|
174
168
|
let inString = false;
|