@spacefast/common 0.0.2
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/README.md +42 -0
- package/dist/brand.d.ts +15 -0
- package/dist/brand.js +24 -0
- package/dist/config/domains.d.ts +30 -0
- package/dist/config/domains.js +75 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +3 -0
- package/dist/contracts/abuse.d.ts +93 -0
- package/dist/contracts/abuse.js +50 -0
- package/dist/contracts/access.d.ts +409 -0
- package/dist/contracts/access.js +396 -0
- package/dist/contracts/account.d.ts +28 -0
- package/dist/contracts/account.js +54 -0
- package/dist/contracts/activity.d.ts +118 -0
- package/dist/contracts/activity.js +180 -0
- package/dist/contracts/analytics.d.ts +56 -0
- package/dist/contracts/analytics.js +91 -0
- package/dist/contracts/annotations.d.ts +327 -0
- package/dist/contracts/annotations.js +234 -0
- package/dist/contracts/api-keys.d.ts +517 -0
- package/dist/contracts/api-keys.js +235 -0
- package/dist/contracts/archives.d.ts +332 -0
- package/dist/contracts/archives.js +120 -0
- package/dist/contracts/auth.d.ts +86 -0
- package/dist/contracts/auth.js +82 -0
- package/dist/contracts/beta.d.ts +106 -0
- package/dist/contracts/beta.js +104 -0
- package/dist/contracts/billing.d.ts +328 -0
- package/dist/contracts/billing.js +203 -0
- package/dist/contracts/builds.d.ts +504 -0
- package/dist/contracts/builds.js +248 -0
- package/dist/contracts/channels.d.ts +49 -0
- package/dist/contracts/channels.js +51 -0
- package/dist/contracts/common.d.ts +238 -0
- package/dist/contracts/common.js +175 -0
- package/dist/contracts/deployments.d.ts +574 -0
- package/dist/contracts/deployments.js +97 -0
- package/dist/contracts/device-auth.d.ts +194 -0
- package/dist/contracts/device-auth.js +162 -0
- package/dist/contracts/domains.d.ts +6115 -0
- package/dist/contracts/domains.js +1435 -0
- package/dist/contracts/enums.d.ts +196 -0
- package/dist/contracts/enums.js +211 -0
- package/dist/contracts/error-code-meta.d.ts +1560 -0
- package/dist/contracts/error-code-meta.js +400 -0
- package/dist/contracts/error-codes.d.ts +13 -0
- package/dist/contracts/error-codes.js +416 -0
- package/dist/contracts/events.d.ts +398 -0
- package/dist/contracts/events.js +320 -0
- package/dist/contracts/fast-domain-search.d.ts +19 -0
- package/dist/contracts/fast-domain-search.js +22 -0
- package/dist/contracts/features.d.ts +240 -0
- package/dist/contracts/features.js +406 -0
- package/dist/contracts/git.d.ts +288 -0
- package/dist/contracts/git.js +116 -0
- package/dist/contracts/ids.d.ts +35 -0
- package/dist/contracts/ids.js +45 -0
- package/dist/contracts/intercom.d.ts +6 -0
- package/dist/contracts/intercom.js +5 -0
- package/dist/contracts/internal.d.ts +103 -0
- package/dist/contracts/internal.js +92 -0
- package/dist/contracts/mcp.d.ts +788 -0
- package/dist/contracts/mcp.js +161 -0
- package/dist/contracts/me.d.ts +81 -0
- package/dist/contracts/me.js +104 -0
- package/dist/contracts/oauth-resources.d.ts +30 -0
- package/dist/contracts/oauth-resources.js +61 -0
- package/dist/contracts/operations.d.ts +54 -0
- package/dist/contracts/operations.js +14 -0
- package/dist/contracts/plan-policy.d.ts +85 -0
- package/dist/contracts/plan-policy.js +75 -0
- package/dist/contracts/platform.d.ts +359 -0
- package/dist/contracts/platform.js +216 -0
- package/dist/contracts/push-new.d.ts +156 -0
- package/dist/contracts/push-new.js +52 -0
- package/dist/contracts/quotas.d.ts +16 -0
- package/dist/contracts/quotas.js +36 -0
- package/dist/contracts/repository-connections.d.ts +231 -0
- package/dist/contracts/repository-connections.js +106 -0
- package/dist/contracts/resources.d.ts +529 -0
- package/dist/contracts/resources.js +209 -0
- package/dist/contracts/routes.d.ts +45 -0
- package/dist/contracts/routes.js +31 -0
- package/dist/contracts/runtime-api.d.ts +449 -0
- package/dist/contracts/runtime-api.js +513 -0
- package/dist/contracts/sites.d.ts +393 -0
- package/dist/contracts/sites.js +121 -0
- package/dist/contracts/slugs.d.ts +31 -0
- package/dist/contracts/slugs.js +47 -0
- package/dist/contracts/space-config.d.ts +216 -0
- package/dist/contracts/space-config.js +237 -0
- package/dist/contracts/space-theme.d.ts +25 -0
- package/dist/contracts/space-theme.js +49 -0
- package/dist/contracts/spaces.d.ts +2760 -0
- package/dist/contracts/spaces.js +589 -0
- package/dist/contracts/superadmin-activity.d.ts +205 -0
- package/dist/contracts/superadmin-activity.js +107 -0
- package/dist/contracts/superadmin-emails.d.ts +212 -0
- package/dist/contracts/superadmin-emails.js +112 -0
- package/dist/contracts/superadmin-queues.d.ts +414 -0
- package/dist/contracts/superadmin-queues.js +202 -0
- package/dist/contracts/superadmin-runtime.d.ts +27 -0
- package/dist/contracts/superadmin-runtime.js +38 -0
- package/dist/contracts/superadmin-spaces.d.ts +429 -0
- package/dist/contracts/superadmin-spaces.js +82 -0
- package/dist/contracts/superadmin-tenants.d.ts +180 -0
- package/dist/contracts/superadmin-tenants.js +117 -0
- package/dist/contracts/superadmin.d.ts +654 -0
- package/dist/contracts/superadmin.js +309 -0
- package/dist/contracts/tags.d.ts +1140 -0
- package/dist/contracts/tags.js +1050 -0
- package/dist/contracts/teams.d.ts +233 -0
- package/dist/contracts/teams.js +174 -0
- package/dist/contracts/telemetry.d.ts +2 -0
- package/dist/contracts/telemetry.js +1 -0
- package/dist/contracts/transfers.d.ts +105 -0
- package/dist/contracts/transfers.js +48 -0
- package/dist/contracts/variables.d.ts +189 -0
- package/dist/contracts/variables.js +82 -0
- package/dist/contracts/webhooks.d.ts +159 -0
- package/dist/contracts/webhooks.js +59 -0
- package/dist/contracts/zero.d.ts +1538 -0
- package/dist/contracts/zero.js +755 -0
- package/dist/docs/agent-prose.d.ts +35 -0
- package/dist/docs/agent-prose.js +153 -0
- package/dist/docs/agent-setup.d.ts +6 -0
- package/dist/docs/agent-setup.js +164 -0
- package/dist/docs/agent-solutions.d.ts +110 -0
- package/dist/docs/agent-solutions.js +181 -0
- package/dist/docs/error-docs.d.ts +12 -0
- package/dist/docs/error-docs.js +1601 -0
- package/dist/docs/skill-distribution.d.ts +12 -0
- package/dist/docs/skill-distribution.js +18 -0
- package/dist/domain-exploration.d.ts +108 -0
- package/dist/domain-exploration.js +488 -0
- package/dist/domain-normalize.d.ts +1 -0
- package/dist/domain-normalize.js +14 -0
- package/dist/domain-zones.d.ts +1 -0
- package/dist/domain-zones.js +5272 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/access-policy.d.ts +39 -0
- package/dist/utils/access-policy.js +232 -0
- package/dist/utils/api.d.ts +4 -0
- package/dist/utils/api.js +13 -0
- package/dist/utils/auth-redirect.d.ts +1 -0
- package/dist/utils/auth-redirect.js +48 -0
- package/dist/utils/auth.d.ts +5 -0
- package/dist/utils/auth.js +13 -0
- package/dist/utils/build-settings.d.ts +49 -0
- package/dist/utils/build-settings.js +366 -0
- package/dist/utils/claim-token.d.ts +1 -0
- package/dist/utils/claim-token.js +9 -0
- package/dist/utils/collections.d.ts +1 -0
- package/dist/utils/collections.js +5 -0
- package/dist/utils/concurrency.d.ts +1 -0
- package/dist/utils/concurrency.js +18 -0
- package/dist/utils/content-type.d.ts +10 -0
- package/dist/utils/content-type.js +145 -0
- package/dist/utils/error-display.d.ts +7 -0
- package/dist/utils/error-display.js +42 -0
- package/dist/utils/error.d.ts +1 -0
- package/dist/utils/error.js +3 -0
- package/dist/utils/generate-space-name.d.ts +14 -0
- package/dist/utils/generate-space-name.js +95 -0
- package/dist/utils/git-repository.d.ts +5 -0
- package/dist/utils/git-repository.js +99 -0
- package/dist/utils/guards.d.ts +1 -0
- package/dist/utils/guards.js +3 -0
- package/dist/utils/publish-detection.d.ts +10 -0
- package/dist/utils/publish-detection.js +118 -0
- package/dist/utils/publish-policy.d.ts +69 -0
- package/dist/utils/publish-policy.js +429 -0
- package/dist/utils/query-client.d.ts +7 -0
- package/dist/utils/query-client.js +21 -0
- package/dist/utils/query-keys.d.ts +75 -0
- package/dist/utils/query-keys.js +78 -0
- package/dist/utils/runtime-paths.d.ts +7 -0
- package/dist/utils/runtime-paths.js +28 -0
- package/dist/utils/runtime-upload.d.ts +19 -0
- package/dist/utils/runtime-upload.js +27 -0
- package/dist/utils/slug.d.ts +5 -0
- package/dist/utils/slug.js +13 -0
- package/dist/utils/space-config.d.ts +75 -0
- package/dist/utils/space-config.js +415 -0
- package/dist/utils/space-theme.d.ts +16 -0
- package/dist/utils/space-theme.js +89 -0
- package/dist/utils/static-runtime-policy.d.ts +17 -0
- package/dist/utils/static-runtime-policy.js +103 -0
- package/dist/utils/upload-session.d.ts +34 -0
- package/dist/utils/upload-session.js +69 -0
- package/dist/utils/urls.d.ts +2 -0
- package/dist/utils/urls.js +7 -0
- package/dist/utils/version-path.d.ts +6 -0
- package/dist/utils/version-path.js +51 -0
- package/dist/utils/wpcom-auth-redirects.d.ts +14 -0
- package/dist/utils/wpcom-auth-redirects.js +49 -0
- package/dist/utils/zero-realtime-signature.d.ts +12 -0
- package/dist/utils/zero-realtime-signature.js +45 -0
- package/dist/vocabulary.d.ts +230 -0
- package/dist/vocabulary.js +218 -0
- package/package.json +58 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import { BRAND } from "../brand.js";
|
|
2
|
+
import { WORST_CASE_QUOTAS } from "../contracts/quotas.js";
|
|
3
|
+
import { SPACE_CONFIG_PRIVATE_FILES } from "../contracts/space-config.js";
|
|
4
|
+
// The ONE static publish policy (internal-docs/platform.md "Upload Contract"):
|
|
5
|
+
// path denials, manifest scale caps, plan caps, duplicate detection, and the
|
|
6
|
+
// free-plan content rules live here. Consumed by API manifest validation, CLI
|
|
7
|
+
// local preflight, inline archive extraction, and the runtime parity fixtures
|
|
8
|
+
// (the PHP twin is runtime/engine/admin/upload-policy.php).
|
|
9
|
+
import { canonicalizeVersionPath, normalizeVersionPath } from "./version-path.js";
|
|
10
|
+
// Manifest scale caps (spec "Upload Contract"): the hard contract ceiling is
|
|
11
|
+
// 100,000 files per version; plan policy may LOWER it (Free 20,000), never
|
|
12
|
+
// raise it. Canonical paths cap at 1,024 bytes; manifest request bodies at
|
|
13
|
+
// 16 MB, enforced fail-early before any upload session exists.
|
|
14
|
+
export const MANIFEST_MAX_FILES_CEILING = 100_000;
|
|
15
|
+
export const MANIFEST_MAX_PATH_BYTES = 1024;
|
|
16
|
+
export const MANIFEST_MAX_BODY_BYTES = 16 * 1024 * 1024;
|
|
17
|
+
export const MAX_VERSION_FILE_SIZE_BYTES = 64 * 1024 * 1024;
|
|
18
|
+
// Worst-case artifact ceiling lives in the named raise-only quota table.
|
|
19
|
+
export const MAX_VERSION_TOTAL_BYTES = WORST_CASE_QUOTAS.maxArtifactBytes;
|
|
20
|
+
const IGNORED_EXACT_PATHS = new Set([
|
|
21
|
+
".DS_Store",
|
|
22
|
+
".gitignore",
|
|
23
|
+
".env",
|
|
24
|
+
".env.local",
|
|
25
|
+
".env.production",
|
|
26
|
+
".env.development",
|
|
27
|
+
".env.test",
|
|
28
|
+
".npmrc",
|
|
29
|
+
".netrc",
|
|
30
|
+
".stattic/state.json",
|
|
31
|
+
"_routes.json",
|
|
32
|
+
]);
|
|
33
|
+
const IGNORED_SEGMENTS = new Set([
|
|
34
|
+
".aws",
|
|
35
|
+
".git",
|
|
36
|
+
".hg",
|
|
37
|
+
".ssh",
|
|
38
|
+
".svn",
|
|
39
|
+
".wrangler",
|
|
40
|
+
".vercel",
|
|
41
|
+
".netlify",
|
|
42
|
+
".turbo",
|
|
43
|
+
".cache",
|
|
44
|
+
"node_modules",
|
|
45
|
+
]);
|
|
46
|
+
const RESERVED_CONVENTION_PATHS = new Set(["_headers", "_redirects"]);
|
|
47
|
+
const SENSITIVE_FILE_PATTERNS = [
|
|
48
|
+
/^\.env\./,
|
|
49
|
+
/^id_(rsa|dsa|ecdsa|ed25519)(\.pub)?$/,
|
|
50
|
+
/(^|[.-])private[.-]?key$/i,
|
|
51
|
+
/\.(pem|key|p12|pfx)$/i,
|
|
52
|
+
];
|
|
53
|
+
// Denied runtime private/control paths (spec "Static path policy").
|
|
54
|
+
const STATIC_EXECUTION_CONTROL_FILES = new Set([".htaccess", ".user.ini"]);
|
|
55
|
+
const STATIC_RUNTIME_CONTROL_SEGMENTS = new Set(["__spacefast", "__stattic"]);
|
|
56
|
+
const STATIC_RUNTIME_CONTROL_PATHS = new Set([".well-known/stattic-runtime"]);
|
|
57
|
+
const STATIC_RUNTIME_CONTROL_PREFIXES = [".stattic/storage", ".stattic/engine"];
|
|
58
|
+
export function normalizePublishPath(relativePath) {
|
|
59
|
+
return relativePath.replace(/\\/g, "/").replace(/^\/+/g, "");
|
|
60
|
+
}
|
|
61
|
+
export function publishPathIgnored(relativePath) {
|
|
62
|
+
const path = normalizePublishPath(relativePath);
|
|
63
|
+
if (IGNORED_EXACT_PATHS.has(path) || /(?:^|\/)\.next\/cache(?:\/|$)/.test(path)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return path
|
|
67
|
+
.split("/")
|
|
68
|
+
.some((segment) => IGNORED_SEGMENTS.has(segment) ||
|
|
69
|
+
IGNORED_EXACT_PATHS.has(segment) ||
|
|
70
|
+
SENSITIVE_FILE_PATTERNS.some((pattern) => pattern.test(segment)));
|
|
71
|
+
}
|
|
72
|
+
export function publishPathIsConvention(relativePath) {
|
|
73
|
+
return RESERVED_CONVENTION_PATHS.has(normalizePublishPath(relativePath));
|
|
74
|
+
}
|
|
75
|
+
// Provider runtime features that have no Spacefast equivalent (spec "Routing And
|
|
76
|
+
// Headers", migration diagnostics): Cloudflare Pages `_worker.js`/`_routes.json`
|
|
77
|
+
// and Pages/Netlify function directories publish as inert content with a
|
|
78
|
+
// warning so migrations are never silent.
|
|
79
|
+
export function providerRuntimeFeatureWarnings(paths) {
|
|
80
|
+
const warnings = [];
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
const featureForPath = (path) => {
|
|
83
|
+
if (path === "_worker.js") {
|
|
84
|
+
return "Cloudflare Pages _worker.js";
|
|
85
|
+
}
|
|
86
|
+
if (path === "_routes.json") {
|
|
87
|
+
return "Cloudflare Pages _routes.json";
|
|
88
|
+
}
|
|
89
|
+
if (path.startsWith("functions/")) {
|
|
90
|
+
return "Pages Functions (functions/)";
|
|
91
|
+
}
|
|
92
|
+
if (path.startsWith("netlify/functions/")) {
|
|
93
|
+
return "Netlify Functions (netlify/functions/)";
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
};
|
|
97
|
+
for (const rawPath of paths) {
|
|
98
|
+
const path = normalizePublishPath(rawPath);
|
|
99
|
+
const feature = featureForPath(path);
|
|
100
|
+
if (!feature || seen.has(feature)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
seen.add(feature);
|
|
104
|
+
warnings.push({
|
|
105
|
+
severity: "warning",
|
|
106
|
+
code: "provider_runtime_feature_unsupported",
|
|
107
|
+
message: `${feature} is a provider runtime feature ${BRAND.productName} does not execute; it publishes as inert static content.`,
|
|
108
|
+
path,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return warnings;
|
|
112
|
+
}
|
|
113
|
+
function pathViolation(code, message, path) {
|
|
114
|
+
return { code, message, path };
|
|
115
|
+
}
|
|
116
|
+
function basename(path) {
|
|
117
|
+
const index = path.lastIndexOf("/");
|
|
118
|
+
return index >= 0 ? path.slice(index + 1) : path;
|
|
119
|
+
}
|
|
120
|
+
export function staticUploadPathViolation(path, options = {}) {
|
|
121
|
+
const rawPath = path;
|
|
122
|
+
if (rawPath !== rawPath.trim() ||
|
|
123
|
+
rawPath.startsWith("/") ||
|
|
124
|
+
rawPath.includes("\\") ||
|
|
125
|
+
rawPath.includes("//")) {
|
|
126
|
+
return pathViolation("invalid_file_path", "File path is invalid.", rawPath);
|
|
127
|
+
}
|
|
128
|
+
let normalizedPath;
|
|
129
|
+
try {
|
|
130
|
+
normalizedPath = normalizeVersionPath(path);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return pathViolation("invalid_file_path", "File path is invalid.", rawPath);
|
|
134
|
+
}
|
|
135
|
+
if (normalizedPath !== rawPath) {
|
|
136
|
+
return pathViolation("invalid_file_path", "File path is invalid.", normalizedPath);
|
|
137
|
+
}
|
|
138
|
+
if (new TextEncoder().encode(normalizedPath).length > MANIFEST_MAX_PATH_BYTES) {
|
|
139
|
+
return pathViolation("path_too_long", `File paths support up to ${MANIFEST_MAX_PATH_BYTES} bytes in canonical form.`, normalizedPath);
|
|
140
|
+
}
|
|
141
|
+
const lowerName = basename(normalizedPath).toLowerCase();
|
|
142
|
+
const lowerPath = normalizedPath.toLowerCase();
|
|
143
|
+
const segments = normalizedPath.split("/");
|
|
144
|
+
const invalidSegment = segments.find((segment) => segment.endsWith(".") || segment.endsWith(" "));
|
|
145
|
+
if (invalidSegment) {
|
|
146
|
+
return pathViolation("invalid_file_path", "File path is invalid.", normalizedPath);
|
|
147
|
+
}
|
|
148
|
+
if (STATIC_EXECUTION_CONTROL_FILES.has(lowerName)) {
|
|
149
|
+
return pathViolation("static_control_file_not_supported", "Static deploys cannot upload execution-control files.", normalizedPath);
|
|
150
|
+
}
|
|
151
|
+
const reservedRuntimeControlFiles = options.reservedRuntimeControlFiles
|
|
152
|
+
? new Set(Array.from(options.reservedRuntimeControlFiles, (name) => name.toLowerCase()))
|
|
153
|
+
: null;
|
|
154
|
+
if (reservedRuntimeControlFiles?.has(lowerName) && lowerPath === lowerName) {
|
|
155
|
+
return pathViolation("static_runtime_control_path_not_supported", "Static deploys cannot upload runtime control paths.", normalizedPath);
|
|
156
|
+
}
|
|
157
|
+
const controlSegment = segments.find((segment) => STATIC_RUNTIME_CONTROL_SEGMENTS.has(segment.toLowerCase()));
|
|
158
|
+
if (controlSegment) {
|
|
159
|
+
return pathViolation("static_runtime_control_path_not_supported", "Static deploys cannot upload runtime control paths.", normalizedPath);
|
|
160
|
+
}
|
|
161
|
+
if (STATIC_RUNTIME_CONTROL_PREFIXES.some((prefix) => lowerPath === prefix || lowerPath.startsWith(`${prefix}/`))) {
|
|
162
|
+
return pathViolation("static_runtime_control_path_not_supported", "Static deploys cannot upload runtime control paths.", normalizedPath);
|
|
163
|
+
}
|
|
164
|
+
if (STATIC_RUNTIME_CONTROL_PATHS.has(lowerPath)) {
|
|
165
|
+
return pathViolation("static_runtime_control_path_not_supported", "Static deploys cannot upload runtime control paths.", normalizedPath);
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
export function firstStaticUploadPathViolation(paths, options = {}) {
|
|
170
|
+
for (const path of paths) {
|
|
171
|
+
const violation = staticUploadPathViolation(path, options);
|
|
172
|
+
if (violation) {
|
|
173
|
+
return violation;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
export function resolveManifestFileCap(maxFiles) {
|
|
179
|
+
return Math.min(MANIFEST_MAX_FILES_CEILING, maxFiles && maxFiles > 0 ? maxFiles : MANIFEST_MAX_FILES_CEILING);
|
|
180
|
+
}
|
|
181
|
+
// The shared manifest validator (spec "Upload Contract"): canonicalizes every
|
|
182
|
+
// path (decode-once + NFC), enforces the static path policy, the scale caps,
|
|
183
|
+
// and plan caps, rejects post-canonicalization duplicates, and emits the
|
|
184
|
+
// case-collision warning. Runs BEFORE any upload session is created; archive
|
|
185
|
+
// extraction routes through the same checks. Returns the manifest with
|
|
186
|
+
// canonical paths — callers use the returned files, never the input.
|
|
187
|
+
export function validatePublishManifest(files, caps = {}) {
|
|
188
|
+
const maxFiles = resolveManifestFileCap(caps.maxFiles);
|
|
189
|
+
if (files.length > maxFiles) {
|
|
190
|
+
return {
|
|
191
|
+
error: {
|
|
192
|
+
code: "manifest_too_many_files",
|
|
193
|
+
message: `Versions support up to ${maxFiles.toLocaleString()} files on this plan.`,
|
|
194
|
+
details: { fileCount: files.length, limit: maxFiles },
|
|
195
|
+
},
|
|
196
|
+
files: null,
|
|
197
|
+
warnings: [],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const canonicalFiles = [];
|
|
201
|
+
const canonicalPaths = new Set();
|
|
202
|
+
const lowercasePaths = new Map();
|
|
203
|
+
const warnings = [];
|
|
204
|
+
for (const file of files) {
|
|
205
|
+
let canonicalPath;
|
|
206
|
+
try {
|
|
207
|
+
canonicalPath = canonicalizeVersionPath(file.path);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return {
|
|
211
|
+
error: {
|
|
212
|
+
code: "invalid_file_path",
|
|
213
|
+
message: `Invalid file path "${file.path}".`,
|
|
214
|
+
details: { path: file.path },
|
|
215
|
+
},
|
|
216
|
+
files: null,
|
|
217
|
+
warnings: [],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (canonicalPaths.has(canonicalPath)) {
|
|
221
|
+
return {
|
|
222
|
+
error: {
|
|
223
|
+
code: "manifest_duplicate_path",
|
|
224
|
+
message: `Manifest contains duplicate path "${canonicalPath}" after canonicalization.`,
|
|
225
|
+
details: { path: canonicalPath },
|
|
226
|
+
},
|
|
227
|
+
files: null,
|
|
228
|
+
warnings: [],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const violation = staticUploadPathViolation(canonicalPath);
|
|
232
|
+
if (violation) {
|
|
233
|
+
return {
|
|
234
|
+
error: {
|
|
235
|
+
code: violation.code,
|
|
236
|
+
message: violation.message,
|
|
237
|
+
details: { path: violation.path },
|
|
238
|
+
},
|
|
239
|
+
files: null,
|
|
240
|
+
warnings: [],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// Case-only-differing paths are distinct (paths are byte-exact and
|
|
244
|
+
// case-sensitive) but cannot round-trip case-insensitive filesystems.
|
|
245
|
+
const lowercase = canonicalPath.toLowerCase();
|
|
246
|
+
const caseSibling = lowercasePaths.get(lowercase);
|
|
247
|
+
if (caseSibling !== undefined && caseSibling !== canonicalPath) {
|
|
248
|
+
warnings.push({
|
|
249
|
+
severity: "warning",
|
|
250
|
+
code: "path_case_collision",
|
|
251
|
+
message: `"${canonicalPath}" and "${caseSibling}" differ only by letter case and cannot coexist on case-insensitive filesystems.`,
|
|
252
|
+
path: canonicalPath,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
lowercasePaths.set(lowercase, canonicalPath);
|
|
257
|
+
}
|
|
258
|
+
canonicalPaths.add(canonicalPath);
|
|
259
|
+
canonicalFiles.push(canonicalPath === file.path ? file : { ...file, path: canonicalPath });
|
|
260
|
+
}
|
|
261
|
+
const maxFileBytes = caps.maxFileBytes && caps.maxFileBytes > 0 ? caps.maxFileBytes : MAX_VERSION_FILE_SIZE_BYTES;
|
|
262
|
+
const oversized = canonicalFiles.find((file) => file.size > maxFileBytes);
|
|
263
|
+
if (oversized) {
|
|
264
|
+
return {
|
|
265
|
+
error: {
|
|
266
|
+
code: "version_file_too_large",
|
|
267
|
+
message: `File ${oversized.path} exceeds the ${maxFileBytes} byte per-file limit for this plan.`,
|
|
268
|
+
details: { path: oversized.path, size: oversized.size, limit: maxFileBytes },
|
|
269
|
+
},
|
|
270
|
+
files: null,
|
|
271
|
+
warnings: [],
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const totalBytes = canonicalFiles.reduce((sum, file) => sum + file.size, 0);
|
|
275
|
+
if (totalBytes > MAX_VERSION_TOTAL_BYTES) {
|
|
276
|
+
return {
|
|
277
|
+
error: {
|
|
278
|
+
code: "version_total_bytes_exceeded",
|
|
279
|
+
message: `Version exceeds the ${MAX_VERSION_TOTAL_BYTES} byte total size limit.`,
|
|
280
|
+
details: { totalBytes, limit: MAX_VERSION_TOTAL_BYTES },
|
|
281
|
+
},
|
|
282
|
+
files: null,
|
|
283
|
+
warnings: [],
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
warnings.push(...providerRuntimeFeatureWarnings(canonicalFiles.map((file) => file.path)));
|
|
287
|
+
return { error: null, files: canonicalFiles, warnings };
|
|
288
|
+
}
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
// Free-plan publish content policy (spec "Plans And Limits"). Free spaces
|
|
291
|
+
// publish web content; other file types are ignored with a diagnostic.
|
|
292
|
+
const FREE_PLAN_ALLOWED_UPLOAD_EXTENSIONS = new Set([
|
|
293
|
+
".html",
|
|
294
|
+
".htm",
|
|
295
|
+
".css",
|
|
296
|
+
".js",
|
|
297
|
+
".mjs",
|
|
298
|
+
".cjs",
|
|
299
|
+
".json",
|
|
300
|
+
".map",
|
|
301
|
+
".webmanifest",
|
|
302
|
+
".txt",
|
|
303
|
+
".md",
|
|
304
|
+
".csv",
|
|
305
|
+
// Opaque static payloads used by migration fixtures and served as
|
|
306
|
+
// application/octet-stream by the runtime.
|
|
307
|
+
".customtype",
|
|
308
|
+
".xml",
|
|
309
|
+
".svg",
|
|
310
|
+
".png",
|
|
311
|
+
".jpg",
|
|
312
|
+
".jpeg",
|
|
313
|
+
".gif",
|
|
314
|
+
".webp",
|
|
315
|
+
".avif",
|
|
316
|
+
".ico",
|
|
317
|
+
".woff",
|
|
318
|
+
".woff2",
|
|
319
|
+
".ttf",
|
|
320
|
+
".otf",
|
|
321
|
+
]);
|
|
322
|
+
const LINE_SPLIT_PATTERN = /\r?\n/;
|
|
323
|
+
const BASIC_AUTH_HEADER_PATTERN = /^basic-auth\s*:/i;
|
|
324
|
+
function extensionForPath(filePath) {
|
|
325
|
+
const normalized = normalizePublishPath(filePath).toLowerCase();
|
|
326
|
+
const fileName = normalized.split("/").at(-1) ?? normalized;
|
|
327
|
+
const extensionIndex = fileName.lastIndexOf(".");
|
|
328
|
+
return extensionIndex > 0 ? fileName.slice(extensionIndex) : "";
|
|
329
|
+
}
|
|
330
|
+
function freePlanDeniedExecutablePath(filePath) {
|
|
331
|
+
return normalizePublishPath(filePath)
|
|
332
|
+
.toLowerCase()
|
|
333
|
+
.split("/")
|
|
334
|
+
.some((segment) => segment === "bin");
|
|
335
|
+
}
|
|
336
|
+
export function freePlanCanUploadPath(filePath, options) {
|
|
337
|
+
const path = normalizePublishPath(filePath);
|
|
338
|
+
// Root Spacefast config files are platform machinery, not user content (spec "Space
|
|
339
|
+
// Configuration Files": ships in the manifest, same lifecycle as
|
|
340
|
+
// `_redirects`/`_headers`) — the plan's content-extension gate must never
|
|
341
|
+
// eat it (e2e checkpoint 4: it was silently dropped on free publishes,
|
|
342
|
+
// disabling fallback/meta/templates/theme for every free space).
|
|
343
|
+
if (SPACE_CONFIG_PRIVATE_FILES.includes(path)) {
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
if (freePlanDeniedExecutablePath(path)) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
const extension = extensionForPath(path);
|
|
350
|
+
return (publishPathIsConvention(path) ||
|
|
351
|
+
extension === "" ||
|
|
352
|
+
FREE_PLAN_ALLOWED_UPLOAD_EXTENSIONS.has(extension) ||
|
|
353
|
+
(options?.claimedSpace === true && extension === ".sh"));
|
|
354
|
+
}
|
|
355
|
+
export function freePlanCanUploadContentType(contentType) {
|
|
356
|
+
const normalized = contentType?.split(";")[0]?.trim().toLowerCase();
|
|
357
|
+
return (normalized === "text/html" ||
|
|
358
|
+
normalized === "text/plain" ||
|
|
359
|
+
normalized === "text/css" ||
|
|
360
|
+
normalized === "text/csv" ||
|
|
361
|
+
normalized === "text/markdown" ||
|
|
362
|
+
normalized === "text/javascript" ||
|
|
363
|
+
normalized === "application/javascript" ||
|
|
364
|
+
normalized === "application/json" ||
|
|
365
|
+
normalized === "application/manifest+json" ||
|
|
366
|
+
normalized === "application/gzip" ||
|
|
367
|
+
normalized === "image/svg+xml" ||
|
|
368
|
+
normalized === "application/xml" ||
|
|
369
|
+
normalized === "text/xml" ||
|
|
370
|
+
normalized?.startsWith("image/") ||
|
|
371
|
+
normalized?.startsWith("font/") ||
|
|
372
|
+
false);
|
|
373
|
+
}
|
|
374
|
+
export function filterFreePlanManifest(files, options) {
|
|
375
|
+
const allowed = [];
|
|
376
|
+
const ignored = [];
|
|
377
|
+
for (const file of files) {
|
|
378
|
+
if (freePlanCanUploadPath(file.path, options) ||
|
|
379
|
+
freePlanCanUploadContentType(file.contentType)) {
|
|
380
|
+
allowed.push(file);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
ignored.push(file.path);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return { allowed, ignored };
|
|
387
|
+
}
|
|
388
|
+
// Free-plan `_headers` compile policy (spec "Plans And Limits", amended
|
|
389
|
+
// 2026-06-10): custom response headers stay FREE; the Basic-Auth header
|
|
390
|
+
// MECHANISM is the paid feature. Basic-Auth operations are dropped from free
|
|
391
|
+
// compiles with a `free_headers_basic_auth_disabled` warning; every other
|
|
392
|
+
// header operation passes through untouched.
|
|
393
|
+
export function filterFreePlanHeaders(content) {
|
|
394
|
+
const output = [];
|
|
395
|
+
let droppedBasicAuthCount = 0;
|
|
396
|
+
let pendingMatcher = null;
|
|
397
|
+
let matcherEmitted = false;
|
|
398
|
+
const emitOperation = (rawLine) => {
|
|
399
|
+
if (pendingMatcher !== null && !matcherEmitted) {
|
|
400
|
+
output.push(pendingMatcher);
|
|
401
|
+
matcherEmitted = true;
|
|
402
|
+
}
|
|
403
|
+
output.push(rawLine);
|
|
404
|
+
};
|
|
405
|
+
for (const rawLine of content.split(LINE_SPLIT_PATTERN)) {
|
|
406
|
+
const trimmed = rawLine.trim();
|
|
407
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (!rawLine.startsWith(" ") && !rawLine.startsWith("\t")) {
|
|
411
|
+
pendingMatcher = trimmed;
|
|
412
|
+
matcherEmitted = false;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
if (pendingMatcher === null) {
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (BASIC_AUTH_HEADER_PATTERN.test(trimmed)) {
|
|
419
|
+
droppedBasicAuthCount += 1;
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
emitOperation(rawLine);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
headers: output.length > 0 ? `${output.join("\n")}\n` : undefined,
|
|
427
|
+
droppedBasicAuthCount,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
export function createSpacefastQueryClient(options) {
|
|
3
|
+
return new QueryClient({
|
|
4
|
+
defaultOptions: {
|
|
5
|
+
queries: {
|
|
6
|
+
retry: (failureCount, error) => {
|
|
7
|
+
if (options?.isClientError?.(error)) {
|
|
8
|
+
const { status } = error;
|
|
9
|
+
if (status >= 400 && status < 500 && status !== 408 && status !== 429) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return failureCount < 2;
|
|
14
|
+
},
|
|
15
|
+
staleTime: 60_000,
|
|
16
|
+
refetchOnWindowFocus: true,
|
|
17
|
+
refetchOnReconnect: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export declare const qk: {
|
|
2
|
+
session: () => readonly ["session"];
|
|
3
|
+
authCapabilities: () => readonly ["auth", "capabilities"];
|
|
4
|
+
accountSessions: () => readonly ["account", "sessions"];
|
|
5
|
+
accountConnections: () => readonly ["account", "connections"];
|
|
6
|
+
accountInvitations: () => readonly ["account", "invitations"];
|
|
7
|
+
apiTokens: () => readonly ["api-tokens"];
|
|
8
|
+
agentAccounts: () => readonly ["agent-accounts"];
|
|
9
|
+
mcpDashboard: () => readonly ["mcp", "dashboard"];
|
|
10
|
+
mcpApproval: (id: string) => readonly ["mcp", "approval", string];
|
|
11
|
+
teams: () => readonly ["teams", "list"];
|
|
12
|
+
team: (ref: string) => readonly ["teams", "by-ref", string];
|
|
13
|
+
teamMembers: (id: string) => readonly ["teams", string, "members"];
|
|
14
|
+
teamInvites: (id: string) => readonly ["teams", string, "invites"];
|
|
15
|
+
teamBilling: (id: string) => readonly ["teams", string, "billing"];
|
|
16
|
+
teamUsage: (id: string) => readonly ["teams", string, "usage"];
|
|
17
|
+
teamEntitlements: (id: string) => readonly ["teams", string, "entitlements"];
|
|
18
|
+
teamFeatures: (id: string) => readonly ["teams", string, "features"];
|
|
19
|
+
teamSettings: (id: string) => readonly ["teams", string, "settings"];
|
|
20
|
+
teamSpaces: (id: string) => readonly ["teams", string, "spaces"];
|
|
21
|
+
teamDomains: (id: string) => readonly ["teams", string, "domains"];
|
|
22
|
+
teamManagedDomains: (id: string) => readonly ["teams", string, "managed-domains"];
|
|
23
|
+
domainBindings: () => readonly ["domain-bindings"];
|
|
24
|
+
slugAvailability: (kind: "team" | "space", slug: string, teamId?: string, currentSlug?: string) => readonly ["slugs", "availability", "team" | "space", string, string, string];
|
|
25
|
+
teamVariables: (id: string) => readonly ["teams", string, "variables"];
|
|
26
|
+
teamActivity: (id: string, limit: number) => readonly ["teams", string, "activity", number];
|
|
27
|
+
space: (id: string) => readonly ["spaces", string];
|
|
28
|
+
spaceByRef: (teamRef: string, spaceRef: string) => readonly ["spaces", "by-ref", string, string];
|
|
29
|
+
spaceVersions: (id: string) => readonly ["spaces", string, "versions"];
|
|
30
|
+
spaceCollaboration: (id: string) => readonly ["spaces", string, "collaboration"];
|
|
31
|
+
spaceAnnotations: (id: string) => readonly ["spaces", string, "annotations"];
|
|
32
|
+
spaceActivity: (id: string, limit: number) => readonly ["spaces", string, "activity", number];
|
|
33
|
+
spaceDeployments: (id: string) => readonly ["spaces", string, "deployments"];
|
|
34
|
+
spaceTags: (id: string) => readonly ["spaces", string, "tags"];
|
|
35
|
+
spaceTagVersion: (id: string, versionId: string) => readonly ["spaces", string, "tags", "versions", string];
|
|
36
|
+
build: (id: string) => readonly ["builds", string];
|
|
37
|
+
buildLogs: (id: string) => readonly ["builds", string, "logs"];
|
|
38
|
+
spaceRepositoryConnection: (id: string, connectionType?: string) => readonly ["spaces", string, "repository-connection", string];
|
|
39
|
+
repositoryInstallations: (spaceId: string) => readonly ["repository-connections", "installations", string];
|
|
40
|
+
repositoryInstallationRepositories: (installationId: string) => readonly ["repository-connections", "installations", string, "repositories"];
|
|
41
|
+
spaceRepositoryAnalyze: (id: string, connectionType?: string, ref?: string, root?: string) => readonly ["spaces", string, "repository-connection", string, "analyze", string, string];
|
|
42
|
+
spaceRepositoryWebhookDeliveries: (id: string, connectionType?: string) => readonly ["spaces", string, "repository-webhook-deliveries", string];
|
|
43
|
+
teamWebhooks: (teamId: string) => readonly ["teams", string, "webhooks"];
|
|
44
|
+
webhook: (webhookId: string) => readonly ["webhooks", string];
|
|
45
|
+
webhookDeliveries: (webhookId: string) => readonly ["webhooks", string, "deliveries"];
|
|
46
|
+
spaceVersion: (id: string, versionId: string) => readonly ["spaces", string, "versions", string];
|
|
47
|
+
spaceVersionAnnotations: (id: string, versionId: string, status?: string) => readonly ["spaces", string, "versions", string, "annotations", string];
|
|
48
|
+
spaceVersionFiles: (id: string, versionId: string) => readonly ["spaces", string, "versions", string, "files"];
|
|
49
|
+
spaceVersionFile: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string];
|
|
50
|
+
spaceVersionFileDirectUrl: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string, "direct-url"];
|
|
51
|
+
spaceVersionFileUrlPreview: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string, "url-preview"];
|
|
52
|
+
spaceVersionFileDiff: (id: string, versionId: string, baseVersionId?: string) => readonly ["spaces", string, "versions", string, "files", "diff", string];
|
|
53
|
+
spaceVersionConventionArtifacts: (id: string, versionId: string) => readonly ["spaces", string, "versions", string, "convention-artifacts"];
|
|
54
|
+
spaceVersionConventionArtifact: (id: string, versionId: string, kind: "redirects" | "headers") => readonly ["spaces", string, "versions", string, "convention-artifacts", "redirects" | "headers"];
|
|
55
|
+
spaceVersionRoutingSummary: (id: string, versionId: string) => readonly ["spaces", string, "versions", string, "routing-summary"];
|
|
56
|
+
spaceDiagnostics: (id: string) => readonly ["spaces", string, "diagnostics"];
|
|
57
|
+
spaceDomains: (id: string) => readonly ["spaces", string, "domains"];
|
|
58
|
+
spaceRuntimeStatus: (id: string) => readonly ["spaces", string, "runtime"];
|
|
59
|
+
spaceApplyState: (id: string) => readonly ["spaces", string, "apply-state"];
|
|
60
|
+
spaceZero: (id: string) => readonly ["spaces", string, "zero"];
|
|
61
|
+
spaceZeroDb: (id: string) => readonly ["spaces", string, "zero", "db"];
|
|
62
|
+
spaceZeroLogs: (id: string, limit: number) => readonly ["spaces", string, "zero", "logs", number];
|
|
63
|
+
spaceZeroRealtimeEvents: (id: string, limit: number) => readonly ["spaces", string, "zero", "realtime", "events", number];
|
|
64
|
+
spaceVariables: (id: string) => readonly ["spaces", string, "variables"];
|
|
65
|
+
spaceCertificates: (id: string) => readonly ["spaces", string, "runtime", "certificates"];
|
|
66
|
+
spaceLogs: (id: string, kind: "build" | "access" | "runtime") => readonly ["spaces", string, "logs", "build" | "access" | "runtime"];
|
|
67
|
+
spaceAnalytics: (id: string, window: string) => readonly ["spaces", string, "analytics", string];
|
|
68
|
+
domain: (teamId: string, ref: string) => readonly ["teams", string, "domains", string];
|
|
69
|
+
domainDiagnostics: (teamId: string, domainId: string) => readonly ["teams", string, "domains", string, "diagnostics"];
|
|
70
|
+
domainDnsCapabilities: (domainId: string) => readonly ["domains", string, "dns", "capabilities"];
|
|
71
|
+
domainDnsRecords: (domainId: string) => readonly ["domains", string, "dns", "records"];
|
|
72
|
+
domainDnsOperations: (domainId: string) => readonly ["domains", string, "dns", "operations"];
|
|
73
|
+
domainActions: (domainId: string) => readonly ["domains", string, "actions"];
|
|
74
|
+
domainProviderConnections: (teamId: string) => readonly ["domains", "provider-connections", string];
|
|
75
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const qk = {
|
|
2
|
+
session: () => ["session"],
|
|
3
|
+
authCapabilities: () => ["auth", "capabilities"],
|
|
4
|
+
accountSessions: () => ["account", "sessions"],
|
|
5
|
+
accountConnections: () => ["account", "connections"],
|
|
6
|
+
accountInvitations: () => ["account", "invitations"],
|
|
7
|
+
apiTokens: () => ["api-tokens"],
|
|
8
|
+
agentAccounts: () => ["agent-accounts"],
|
|
9
|
+
mcpDashboard: () => ["mcp", "dashboard"],
|
|
10
|
+
mcpApproval: (id) => ["mcp", "approval", id],
|
|
11
|
+
// The teams LIST gets its own leaf so invalidating it never cascades into
|
|
12
|
+
// ["teams", id, ...] resource queries (members, spaces, domains, ...).
|
|
13
|
+
teams: () => ["teams", "list"],
|
|
14
|
+
// Keyed by slug (the URL ref), so it lives outside the id namespace.
|
|
15
|
+
team: (ref) => ["teams", "by-ref", ref],
|
|
16
|
+
teamMembers: (id) => ["teams", id, "members"],
|
|
17
|
+
teamInvites: (id) => ["teams", id, "invites"],
|
|
18
|
+
teamBilling: (id) => ["teams", id, "billing"],
|
|
19
|
+
teamUsage: (id) => ["teams", id, "usage"],
|
|
20
|
+
teamEntitlements: (id) => ["teams", id, "entitlements"],
|
|
21
|
+
teamFeatures: (id) => ["teams", id, "features"],
|
|
22
|
+
teamSettings: (id) => ["teams", id, "settings"],
|
|
23
|
+
teamSpaces: (id) => ["teams", id, "spaces"],
|
|
24
|
+
teamDomains: (id) => ["teams", id, "domains"],
|
|
25
|
+
teamManagedDomains: (id) => ["teams", id, "managed-domains"],
|
|
26
|
+
domainBindings: () => ["domain-bindings"],
|
|
27
|
+
slugAvailability: (kind, slug, teamId, currentSlug) => ["slugs", "availability", kind, slug, teamId ?? "", currentSlug ?? ""],
|
|
28
|
+
teamVariables: (id) => ["teams", id, "variables"],
|
|
29
|
+
teamActivity: (id, limit) => ["teams", id, "activity", limit],
|
|
30
|
+
space: (id) => ["spaces", id],
|
|
31
|
+
spaceByRef: (teamRef, spaceRef) => ["spaces", "by-ref", teamRef, spaceRef],
|
|
32
|
+
spaceVersions: (id) => ["spaces", id, "versions"],
|
|
33
|
+
spaceCollaboration: (id) => ["spaces", id, "collaboration"],
|
|
34
|
+
spaceAnnotations: (id) => ["spaces", id, "annotations"],
|
|
35
|
+
spaceActivity: (id, limit) => ["spaces", id, "activity", limit],
|
|
36
|
+
spaceDeployments: (id) => ["spaces", id, "deployments"],
|
|
37
|
+
spaceTags: (id) => ["spaces", id, "tags"],
|
|
38
|
+
spaceTagVersion: (id, versionId) => ["spaces", id, "tags", "versions", versionId],
|
|
39
|
+
build: (id) => ["builds", id],
|
|
40
|
+
buildLogs: (id) => ["builds", id, "logs"],
|
|
41
|
+
spaceRepositoryConnection: (id, connectionType = "connected") => ["spaces", id, "repository-connection", connectionType],
|
|
42
|
+
repositoryInstallations: (spaceId) => ["repository-connections", "installations", spaceId],
|
|
43
|
+
repositoryInstallationRepositories: (installationId) => ["repository-connections", "installations", installationId, "repositories"],
|
|
44
|
+
spaceRepositoryAnalyze: (id, connectionType = "connected", ref = "", root = "") => ["spaces", id, "repository-connection", connectionType, "analyze", ref, root],
|
|
45
|
+
spaceRepositoryWebhookDeliveries: (id, connectionType = "connected") => ["spaces", id, "repository-webhook-deliveries", connectionType],
|
|
46
|
+
teamWebhooks: (teamId) => ["teams", teamId, "webhooks"],
|
|
47
|
+
webhook: (webhookId) => ["webhooks", webhookId],
|
|
48
|
+
webhookDeliveries: (webhookId) => ["webhooks", webhookId, "deliveries"],
|
|
49
|
+
spaceVersion: (id, versionId) => ["spaces", id, "versions", versionId],
|
|
50
|
+
spaceVersionAnnotations: (id, versionId, status = "open") => ["spaces", id, "versions", versionId, "annotations", status],
|
|
51
|
+
spaceVersionFiles: (id, versionId) => ["spaces", id, "versions", versionId, "files"],
|
|
52
|
+
spaceVersionFile: (id, versionId, path) => ["spaces", id, "versions", versionId, "files", path],
|
|
53
|
+
spaceVersionFileDirectUrl: (id, versionId, path) => ["spaces", id, "versions", versionId, "files", path, "direct-url"],
|
|
54
|
+
spaceVersionFileUrlPreview: (id, versionId, path) => ["spaces", id, "versions", versionId, "files", path, "url-preview"],
|
|
55
|
+
spaceVersionFileDiff: (id, versionId, baseVersionId) => ["spaces", id, "versions", versionId, "files", "diff", baseVersionId ?? ""],
|
|
56
|
+
spaceVersionConventionArtifacts: (id, versionId) => ["spaces", id, "versions", versionId, "convention-artifacts"],
|
|
57
|
+
spaceVersionConventionArtifact: (id, versionId, kind) => ["spaces", id, "versions", versionId, "convention-artifacts", kind],
|
|
58
|
+
spaceVersionRoutingSummary: (id, versionId) => ["spaces", id, "versions", versionId, "routing-summary"],
|
|
59
|
+
spaceDiagnostics: (id) => ["spaces", id, "diagnostics"],
|
|
60
|
+
spaceDomains: (id) => ["spaces", id, "domains"],
|
|
61
|
+
spaceRuntimeStatus: (id) => ["spaces", id, "runtime"],
|
|
62
|
+
spaceApplyState: (id) => ["spaces", id, "apply-state"],
|
|
63
|
+
spaceZero: (id) => ["spaces", id, "zero"],
|
|
64
|
+
spaceZeroDb: (id) => ["spaces", id, "zero", "db"],
|
|
65
|
+
spaceZeroLogs: (id, limit) => ["spaces", id, "zero", "logs", limit],
|
|
66
|
+
spaceZeroRealtimeEvents: (id, limit) => ["spaces", id, "zero", "realtime", "events", limit],
|
|
67
|
+
spaceVariables: (id) => ["spaces", id, "variables"],
|
|
68
|
+
spaceCertificates: (id) => ["spaces", id, "runtime", "certificates"],
|
|
69
|
+
spaceLogs: (id, kind) => ["spaces", id, "logs", kind],
|
|
70
|
+
spaceAnalytics: (id, window) => ["spaces", id, "analytics", window],
|
|
71
|
+
domain: (teamId, ref) => ["teams", teamId, "domains", ref],
|
|
72
|
+
domainDiagnostics: (teamId, domainId) => ["teams", teamId, "domains", domainId, "diagnostics"],
|
|
73
|
+
domainDnsCapabilities: (domainId) => ["domains", domainId, "dns", "capabilities"],
|
|
74
|
+
domainDnsRecords: (domainId) => ["domains", domainId, "dns", "records"],
|
|
75
|
+
domainDnsOperations: (domainId) => ["domains", domainId, "dns", "operations"],
|
|
76
|
+
domainActions: (domainId) => ["domains", domainId, "actions"],
|
|
77
|
+
domainProviderConnections: (teamId) => ["domains", "provider-connections", teamId],
|
|
78
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const SPACEFAST_RUNTIME_NAMESPACE: "/__spacefast";
|
|
2
|
+
export declare const RUNTIME_MANAGEMENT_API_PATH: "/__spacefast/api.php";
|
|
3
|
+
export declare const RUNTIME_UPLOAD_API_PATH: "/__spacefast/upload.php";
|
|
4
|
+
export declare const RUNTIME_HEALTH_PATH: "/__spacefast/health.php";
|
|
5
|
+
export declare const RUNTIME_ACCESS_CALLBACK_PATH: "/__spacefast/access-callback.php";
|
|
6
|
+
export declare function runtimeManagementPath(suffix: string): string;
|
|
7
|
+
export declare function runtimeUploadPath(params: URLSearchParams | Record<string, string>): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const SPACEFAST_RUNTIME_NAMESPACE = "/__spacefast";
|
|
2
|
+
export const RUNTIME_MANAGEMENT_API_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/api.php`;
|
|
3
|
+
export const RUNTIME_UPLOAD_API_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/upload.php`;
|
|
4
|
+
export const RUNTIME_HEALTH_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/health.php`;
|
|
5
|
+
export const RUNTIME_ACCESS_CALLBACK_PATH = `${SPACEFAST_RUNTIME_NAMESPACE}/access-callback.php`;
|
|
6
|
+
export function runtimeManagementPath(suffix) {
|
|
7
|
+
const route = normalizeRuntimeRoute(suffix);
|
|
8
|
+
if (route === "/") {
|
|
9
|
+
return RUNTIME_MANAGEMENT_API_PATH;
|
|
10
|
+
}
|
|
11
|
+
const [pathname = "/", query = ""] = route.split("?", 2);
|
|
12
|
+
const params = new URLSearchParams({ route: pathname });
|
|
13
|
+
for (const [key, value] of new URLSearchParams(query)) {
|
|
14
|
+
params.append(key, value);
|
|
15
|
+
}
|
|
16
|
+
return `${RUNTIME_MANAGEMENT_API_PATH}?${params.toString()}`;
|
|
17
|
+
}
|
|
18
|
+
export function runtimeUploadPath(params) {
|
|
19
|
+
const query = params instanceof URLSearchParams ? params : new URLSearchParams(params);
|
|
20
|
+
return `${RUNTIME_UPLOAD_API_PATH}?${query.toString()}`;
|
|
21
|
+
}
|
|
22
|
+
function normalizeRuntimeRoute(suffix) {
|
|
23
|
+
if (suffix === "") {
|
|
24
|
+
return "/";
|
|
25
|
+
}
|
|
26
|
+
const route = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
27
|
+
return route;
|
|
28
|
+
}
|