@spacefast/common 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/agents/connect-targets.d.ts +4 -4
  2. package/dist/agents/connect-targets.js +3 -3
  3. package/dist/agents/private-key-oauth.d.ts +37 -0
  4. package/dist/agents/private-key-oauth.js +158 -0
  5. package/dist/config/domains.js +1 -1
  6. package/dist/config/index.d.ts +1 -0
  7. package/dist/config/index.js +1 -0
  8. package/dist/config/postgres-budget.d.ts +126 -0
  9. package/dist/config/postgres-budget.js +135 -0
  10. package/dist/config/postgres-budget.json +50 -0
  11. package/dist/contracts/access.d.ts +386 -1183
  12. package/dist/contracts/access.js +240 -1018
  13. package/dist/contracts/activity.d.ts +1 -1
  14. package/dist/contracts/activity.js +11 -19
  15. package/dist/contracts/api-keys.d.ts +69 -45
  16. package/dist/contracts/api-keys.js +3 -0
  17. package/dist/contracts/archives.d.ts +9 -10
  18. package/dist/contracts/archives.js +4 -6
  19. package/dist/contracts/builds.d.ts +8 -8
  20. package/dist/contracts/builds.js +28 -48
  21. package/dist/contracts/channels.js +1 -2
  22. package/dist/contracts/comments.d.ts +102 -93
  23. package/dist/contracts/comments.js +121 -63
  24. package/dist/contracts/common.d.ts +4 -3
  25. package/dist/contracts/common.js +2 -0
  26. package/dist/contracts/countries.js +2 -7
  27. package/dist/contracts/data-source-routes.d.ts +20 -0
  28. package/dist/contracts/data-source-routes.js +15 -0
  29. package/dist/contracts/deployments.d.ts +3 -3
  30. package/dist/contracts/device-auth.d.ts +21 -15
  31. package/dist/contracts/docs.d.ts +5 -5
  32. package/dist/contracts/domains.d.ts +261 -1330
  33. package/dist/contracts/domains.js +39 -301
  34. package/dist/contracts/email-preferences.d.ts +50 -0
  35. package/dist/contracts/email-preferences.js +44 -0
  36. package/dist/contracts/enums.d.ts +3 -5
  37. package/dist/contracts/enums.js +3 -8
  38. package/dist/contracts/error-code-meta.d.ts +99 -33
  39. package/dist/contracts/error-code-meta.js +36 -9
  40. package/dist/contracts/error-codes.d.ts +1 -1
  41. package/dist/contracts/error-codes.js +28 -11
  42. package/dist/contracts/execution.d.ts +212 -0
  43. package/dist/contracts/execution.js +288 -0
  44. package/dist/contracts/feature-lifecycle.d.ts +498 -2
  45. package/dist/contracts/feature-lifecycle.js +539 -2
  46. package/dist/contracts/features.d.ts +184 -74
  47. package/dist/contracts/features.js +4 -303
  48. package/dist/contracts/functions.d.ts +729 -0
  49. package/dist/contracts/functions.js +485 -0
  50. package/dist/contracts/git.d.ts +1 -1
  51. package/dist/contracts/grants.d.ts +1158 -0
  52. package/dist/contracts/grants.js +696 -0
  53. package/dist/contracts/ids.d.ts +6 -5
  54. package/dist/contracts/ids.js +6 -5
  55. package/dist/contracts/internal.d.ts +3 -3
  56. package/dist/contracts/mcp.d.ts +12 -12
  57. package/dist/contracts/me.js +1 -1
  58. package/dist/contracts/mounts.d.ts +142 -0
  59. package/dist/contracts/mounts.js +56 -0
  60. package/dist/contracts/oauth-resources.d.ts +5 -5
  61. package/dist/contracts/oauth-resources.js +2 -0
  62. package/dist/contracts/operations.d.ts +4 -4
  63. package/dist/contracts/pages.d.ts +6 -14
  64. package/dist/contracts/pages.js +11 -23
  65. package/dist/contracts/plan-policy.d.ts +2 -9
  66. package/dist/contracts/plan-policy.js +1 -4
  67. package/dist/contracts/platform.d.ts +80 -32
  68. package/dist/contracts/platform.js +59 -12
  69. package/dist/contracts/push-new.d.ts +26 -2
  70. package/dist/contracts/push-new.js +8 -0
  71. package/dist/contracts/quotas.d.ts +0 -1
  72. package/dist/contracts/quotas.js +0 -5
  73. package/dist/contracts/repository-connections.d.ts +1 -1
  74. package/dist/contracts/resources.d.ts +21 -85
  75. package/dist/contracts/resources.js +17 -47
  76. package/dist/contracts/runtime-api.d.ts +799 -192
  77. package/dist/contracts/runtime-api.js +231 -100
  78. package/dist/contracts/runtime-app.d.ts +138 -0
  79. package/dist/contracts/runtime-app.js +21 -0
  80. package/dist/contracts/sf-config-v1.d.ts +5 -0
  81. package/dist/contracts/sf-config-v1.js +1 -1
  82. package/dist/contracts/sites.d.ts +17 -12
  83. package/dist/contracts/sites.js +30 -12
  84. package/dist/contracts/space-config.d.ts +46 -117
  85. package/dist/contracts/space-config.js +323 -25
  86. package/dist/contracts/spaces.d.ts +392 -256
  87. package/dist/contracts/spaces.js +163 -83
  88. package/dist/contracts/superadmin-emails.d.ts +27 -3
  89. package/dist/contracts/superadmin-emails.js +10 -15
  90. package/dist/contracts/superadmin-runtime.d.ts +2 -2
  91. package/dist/contracts/superadmin-spaces.d.ts +19 -142
  92. package/dist/contracts/superadmin-spaces.js +7 -0
  93. package/dist/contracts/tags.d.ts +66 -36
  94. package/dist/contracts/tags.js +195 -11
  95. package/dist/contracts/teams.d.ts +9 -9
  96. package/dist/contracts/transfers.d.ts +1 -2
  97. package/dist/contracts/variables.d.ts +4 -4
  98. package/dist/contracts/variables.js +4 -3
  99. package/dist/contracts/webhooks.d.ts +2 -2
  100. package/dist/contracts/zero.d.ts +437 -193
  101. package/dist/contracts/zero.js +149 -158
  102. package/dist/dashboard-paths/index.d.ts +3 -3
  103. package/dist/dashboard-paths/index.js +1 -0
  104. package/dist/docs/agent-prose.js +10 -8
  105. package/dist/docs/agent-setup.d.ts +6 -4
  106. package/dist/docs/agent-setup.js +26 -16
  107. package/dist/docs/agent-solutions.js +1 -1
  108. package/dist/docs/catalog.d.ts +35 -37
  109. package/dist/docs/catalog.js +36 -38
  110. package/dist/docs/error-docs.js +108 -44
  111. package/dist/utils/asset-fingerprint.d.ts +11 -0
  112. package/dist/utils/asset-fingerprint.js +46 -0
  113. package/dist/utils/auth-redirect.d.ts +1 -3
  114. package/dist/utils/auth-redirect.js +1 -21
  115. package/dist/utils/build-settings.d.ts +2 -0
  116. package/dist/utils/build-settings.js +61 -9
  117. package/dist/utils/credential-policy.d.ts +1 -1
  118. package/dist/utils/credential-policy.js +4 -0
  119. package/dist/utils/dns-instructions.d.ts +29 -0
  120. package/dist/utils/dns-instructions.js +78 -0
  121. package/dist/utils/domain-diagnostics.d.ts +29 -0
  122. package/dist/utils/domain-diagnostics.js +63 -0
  123. package/dist/utils/egress-policy.fixtures.json +51 -0
  124. package/dist/utils/grants.d.ts +53 -0
  125. package/dist/utils/grants.js +160 -0
  126. package/dist/utils/id-hints.d.ts +1 -0
  127. package/dist/utils/id-hints.js +55 -13
  128. package/dist/utils/local-space-state.js +1 -0
  129. package/dist/utils/page-colors.d.ts +50 -0
  130. package/dist/utils/page-colors.js +167 -0
  131. package/dist/utils/page-fonts.d.ts +2 -0
  132. package/dist/utils/page-fonts.js +4 -0
  133. package/dist/utils/pages.d.ts +19 -6
  134. package/dist/utils/pages.js +122 -49
  135. package/dist/utils/production-runtime.d.ts +18 -0
  136. package/dist/utils/production-runtime.js +28 -0
  137. package/dist/utils/publish-policy.d.ts +34 -4
  138. package/dist/utils/publish-policy.js +132 -61
  139. package/dist/utils/query-keys.d.ts +7 -13
  140. package/dist/utils/query-keys.js +12 -18
  141. package/dist/utils/source-archive-policy.d.ts +2 -0
  142. package/dist/utils/source-archive-policy.js +2 -0
  143. package/dist/utils/space-config.d.ts +5 -1
  144. package/dist/utils/space-config.js +35 -0
  145. package/dist/utils/static-runtime-policy.d.ts +5 -0
  146. package/dist/utils/static-runtime-policy.fixtures.json +57 -0
  147. package/dist/utils/static-runtime-policy.js +54 -10
  148. package/dist/utils/upload-session.d.ts +3 -0
  149. package/dist/utils/upload-session.js +31 -0
  150. package/package.json +6 -4
  151. package/dist/contracts/annotations.d.ts +0 -327
  152. package/dist/contracts/annotations.js +0 -235
  153. package/dist/contracts/generated-feature-launch-entries.d.ts +0 -2
  154. package/dist/contracts/generated-feature-launch-entries.js +0 -518
  155. package/dist/contracts/publishes.d.ts +0 -135
  156. package/dist/contracts/publishes.js +0 -162
  157. package/dist/utils/access-match.d.ts +0 -39
  158. package/dist/utils/access-match.js +0 -296
  159. package/dist/utils/sf-config-v1.d.ts +0 -2
  160. package/dist/utils/sf-config-v1.js +0 -542
@@ -6,8 +6,9 @@
6
6
  // `ErrorCode`, so emitting a code that is not in the table is a typecheck (CI) failure;
7
7
  // the remaining untyped string paths (low-level serializer, superadmin Better Auth
8
8
  // passthrough) fold into the typed envelope in the F2 envelope chunk.
9
- // Growth is additive-only: codes are never renamed or removed. Diagnostic codes share
10
- // this table so every diagnostic also carries a resolvable docs link.
9
+ // A code's meaning stays stable while it can be emitted. Retiring an API surface removes
10
+ // its dead codes and generated references together. Diagnostic codes share this table so
11
+ // every current diagnostic also carries a resolvable docs link.
11
12
  import { ERROR_DOCS_BASE_URL } from "../brand.js";
12
13
  export { ERROR_DOCS_BASE_URL };
13
14
  /** `docsUrl` derivation rule: docs origin + `/{code}`. Asserted by the conformance suite. */
@@ -19,9 +20,11 @@ export const ERROR_CODES = [
19
20
  "abuse_report_rate_limited",
20
21
  "abuse_takedown",
21
22
  "access_denied",
23
+ "access_scope_suggestion",
22
24
  "account_suspended",
23
25
  "agent_handoff_declined",
24
26
  "agent_handoff_limit_reached",
27
+ "agent_handoff_origin_unsupported",
25
28
  "ambiguous_space_slug",
26
29
  "anonymous_expired",
27
30
  "anonymous_pool_unavailable",
@@ -68,8 +71,8 @@ export const ERROR_CODES = [
68
71
  "credential_revoked",
69
72
  "csam_blocked",
70
73
  "csam_policy_floor",
74
+ "custom_certificates_require_dedicated_site",
71
75
  "data_location_immutable",
72
- "datacenters_unavailable",
73
76
  "device_authorization_failed",
74
77
  "device_verification_rate_limited",
75
78
  "dns_export_required",
@@ -133,10 +136,9 @@ export const ERROR_CODES = [
133
136
  "files_mode_does_not_support_spa",
134
137
  "forbidden",
135
138
  "free_external_proxy_disabled",
136
- "free_headers_basic_auth_disabled",
139
+ "google_play_webhook_identity_not_configured",
137
140
  "idempotency_conflict_in_progress",
138
141
  "idempotency_key_reused",
139
- "immutable_version_requires_login",
140
142
  "import_archive_not_uploaded",
141
143
  "import_not_cancelable",
142
144
  "import_not_waiting_for_archive",
@@ -151,6 +153,7 @@ export const ERROR_CODES = [
151
153
  "invalid_domain",
152
154
  "invalid_domain_name",
153
155
  "invalid_file_path",
156
+ "invalid_google_play_webhook_identity",
154
157
  "invalid_grant",
155
158
  "invalid_idempotency_key",
156
159
  "invalid_publish_archive",
@@ -180,6 +183,7 @@ export const ERROR_CODES = [
180
183
  "last_owner",
181
184
  "log_retention_clamped",
182
185
  "lost_domain_control",
186
+ "maintenance_in_progress",
183
187
  "malware_detected",
184
188
  "managed_domain_protected",
185
189
  "manifest_body_too_large",
@@ -224,6 +228,7 @@ export const ERROR_CODES = [
224
228
  "publish_not_cancelable",
225
229
  "publish_path_collision",
226
230
  "publish_path_invalid",
231
+ "publish_reference_missing",
227
232
  "publish_setup_failed",
228
233
  "publish_snapshot_empty",
229
234
  "publish_upload_failed",
@@ -242,7 +247,6 @@ export const ERROR_CODES = [
242
247
  "runtime_jti_missing",
243
248
  "runtime_jti_replayed",
244
249
  "runtime_jwks_key_missing",
245
- "runtime_logs_unavailable",
246
250
  "runtime_management_unavailable",
247
251
  "runtime_not_provisioned",
248
252
  "runtime_operation_missing",
@@ -255,8 +259,8 @@ export const ERROR_CODES = [
255
259
  "runtime_upload_required",
256
260
  "scan_pending",
257
261
  "secret_variable_in_template",
262
+ "service_signature_invalid",
258
263
  "site_already_deleted",
259
- "site_capacity_exceeded",
260
264
  "site_has_live_spaces",
261
265
  "site_not_static",
262
266
  "site_required",
@@ -265,7 +269,11 @@ export const ERROR_CODES = [
265
269
  "slug_invalid",
266
270
  "slug_reserved",
267
271
  "slug_unavailable",
272
+ "source_archive_decompression_timeout",
273
+ "source_archive_expansion_ratio_exceeded",
274
+ "source_archive_validation_busy",
268
275
  "space_already_claimed",
276
+ "space_capacity_warming",
269
277
  "space_claim_unavailable",
270
278
  "space_claimed_credential_available",
271
279
  "space_disabled",
@@ -277,6 +285,7 @@ export const ERROR_CODES = [
277
285
  "space_import_archive_too_large",
278
286
  "space_import_config_only_archive",
279
287
  "space_import_runtime_schema_unsupported",
288
+ "space_move_would_strand_zero_data",
280
289
  "space_moving",
281
290
  "space_no_live_version",
282
291
  "space_not_disabled",
@@ -287,6 +296,13 @@ export const ERROR_CODES = [
287
296
  "space_unclaimed",
288
297
  "ssl_renewal_blocked",
289
298
  "static_control_file_not_supported",
299
+ "static_mount_path_conflict",
300
+ "static_mount_source_not_ready",
301
+ "static_mount_target_forbidden",
302
+ "static_mount_target_in_use",
303
+ "static_mount_target_not_live",
304
+ "static_mount_target_not_ready",
305
+ "static_mount_target_not_static",
290
306
  "static_runtime_control_path_not_supported",
291
307
  "static_runtime_required",
292
308
  "storage_bucket_unavailable",
@@ -321,7 +337,6 @@ export const ERROR_CODES = [
321
337
  "upload_hash_mismatch",
322
338
  "upload_path_not_canonical",
323
339
  "upload_path_not_declared",
324
- "upload_session_cap_exceeded",
325
340
  "upload_size_mismatch",
326
341
  "user_banned",
327
342
  "validation_error",
@@ -364,10 +379,8 @@ export const ERROR_CODES = [
364
379
  "zero_artifact_abi_mismatch",
365
380
  "zero_artifact_invalid",
366
381
  "zero_artifact_malformed",
367
- "zero_artifact_missing",
368
382
  "zero_artifact_path_invalid",
369
383
  "zero_artifact_unreadable",
370
- "zero_artifact_untrusted",
371
384
  "zero_auth_unavailable",
372
385
  "zero_blob_key_invalid",
373
386
  "zero_blob_store_full",
@@ -390,8 +403,11 @@ export const ERROR_CODES = [
390
403
  "zero_db_row_invalid",
391
404
  "zero_db_sql_invalid",
392
405
  "zero_db_too_many_params",
406
+ "zero_db_transaction_active",
393
407
  "zero_db_transaction_commit_failed",
394
408
  "zero_db_transaction_invalid",
409
+ "zero_db_transaction_missing",
410
+ "zero_db_transaction_rollback_failed",
395
411
  "zero_db_transaction_start_failed",
396
412
  "zero_db_url_invalid",
397
413
  "zero_db_url_missing",
@@ -418,7 +434,6 @@ export const ERROR_CODES = [
418
434
  "zero_js_response_malformed",
419
435
  "zero_js_runtime_init_failed",
420
436
  "zero_log_query_invalid",
421
- "zero_lookup_invalid",
422
437
  "zero_method_not_allowed",
423
438
  "zero_migration_failed",
424
439
  "zero_query_name_missing",
@@ -434,6 +449,8 @@ export const ERROR_CODES = [
434
449
  "zero_replay_unavailable",
435
450
  "zero_request_body_too_large",
436
451
  "zero_requires_dedicated_plan",
452
+ "zero_response_header_forbidden",
453
+ "zero_response_header_invalid",
437
454
  "zero_response_too_large",
438
455
  "zero_routes_invalid",
439
456
  "zero_run_compile_failed",
@@ -0,0 +1,212 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The platform execution layer: everything true of running tenant code on
4
+ * Spacefast regardless of which product is running it.
5
+ *
6
+ * Two products sit on top of this file, and they are genuinely different
7
+ * things rather than two configurations of one thing:
8
+ *
9
+ * - **Zero** (`./zero.js`) runs capsules — schema, queries, mutations and
10
+ * endpoints that share one parent-owned transaction — in the native runner
11
+ * on a dedicated wp.cloud site, next to that site's MySQL.
12
+ * - **Functions** (`./functions.js`) runs workers on Cloudflare Workers for
13
+ * Platforms, carrying npm and framework output that we could never sandbox
14
+ * as well ourselves.
15
+ *
16
+ * The only surface both can host is an endpoint that touches neither the
17
+ * database nor the caller's identity — see `endpointIsPortable`. That is the
18
+ * portable seam, and it is deliberately narrow: a capsule handler's semantics
19
+ * depend on the transaction wrapped around it, which does not exist on an
20
+ * isolate a continent away from the database.
21
+ */
22
+ /**
23
+ * What a live version runs. `static` is bytes on disk with no execution at
24
+ * all, and remains the overwhelming majority of traffic; the other two each
25
+ * name a product.
26
+ */
27
+ export declare const runtimeKindSchema: z.ZodEnum<{
28
+ zero: "zero";
29
+ functions: "functions";
30
+ static: "static";
31
+ }>;
32
+ export type RuntimeKind = z.infer<typeof runtimeKindSchema>;
33
+ export declare const EXECUTION_ENV_MAX_KEYS = 64;
34
+ export declare const EXECUTION_ENV_NAME_MAX_BYTES = 128;
35
+ export declare const EXECUTION_ENV_VALUE_MAX_BYTES: number;
36
+ export declare const EXECUTION_ENV_TOTAL_VALUE_MAX_BYTES: number;
37
+ /**
38
+ * Names the platform reserves for itself in the tenant environment. Tenant
39
+ * code cannot set these, so it cannot spoof the values the broker trusts.
40
+ */
41
+ export declare const EXECUTION_ENV_RESERVED_PREFIXES: readonly ["SPACEFAST_", "ZERO_"];
42
+ /** Paths the platform owns on every space, whatever the product. */
43
+ export declare const PLATFORM_ROUTE_PREFIX = "/__spacefast";
44
+ /**
45
+ * First path segments the platform claims. Matched as segment prefixes rather
46
+ * than whole segments because the runtime already reserves the whole family —
47
+ * `/__stattic_probe` is a live serving path, and `upload-policy.php` refuses
48
+ * any first segment starting with either of these. Encoding it the same way
49
+ * here keeps a capsule or worker from declaring a route the origin would
50
+ * intercept before it ever reached them.
51
+ */
52
+ export declare const PLATFORM_RESERVED_ROUTE_SEGMENT_PREFIXES: readonly ["__spacefast", "__stattic", "__span"];
53
+ export declare const executionSha256Schema: z.ZodString;
54
+ export declare const executionBase64Schema: z.ZodString;
55
+ export declare const executionIdentifierSchema: z.ZodString;
56
+ export declare const executionEnvNameSchema: z.ZodString;
57
+ /**
58
+ * Builds the route-path schema for a product. Structural rules — normalization,
59
+ * traversal, wildcards, the platform's own prefixes — are identical everywhere
60
+ * and live here. Each product passes the extra paths and prefixes its own app
61
+ * shell claims, because those differ: Zero's client router owns `/auth/*`,
62
+ * a Functions worker owns nothing beyond what the platform reserves.
63
+ */
64
+ export declare function appRoutePathSchema(options: {
65
+ subject: string;
66
+ reservedPaths?: readonly string[];
67
+ reservedPrefixes?: readonly string[];
68
+ }): z.ZodString;
69
+ export declare const httpMethodSchema: z.ZodEnum<{
70
+ POST: "POST";
71
+ PUT: "PUT";
72
+ GET: "GET";
73
+ HEAD: "HEAD";
74
+ PATCH: "PATCH";
75
+ DELETE: "DELETE";
76
+ OPTIONS: "OPTIONS";
77
+ }>;
78
+ export type HttpMethod = z.infer<typeof httpMethodSchema>;
79
+ /**
80
+ * What a handler is allowed to reach. Declared at build time from what the
81
+ * source actually imports, not from what the author claims, and printed in the
82
+ * publish receipt so placement is never a surprise.
83
+ */
84
+ export declare const executionCapabilitiesSchema: z.ZodDefault<z.ZodObject<{
85
+ db: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
86
+ fetch: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
87
+ auth: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
88
+ env: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
89
+ realtime: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
90
+ logging: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
91
+ }, z.core.$strip>>;
92
+ export type ExecutionCapabilities = z.infer<typeof executionCapabilitiesSchema>;
93
+ /**
94
+ * The portable seam, stated as one predicate.
95
+ *
96
+ * `db` and `auth` are the two capabilities that bind a handler to the local
97
+ * tier. `db` because Zero's store guarantees every handler runs inside one
98
+ * parent-owned transaction, which an isolate reaching the database over a
99
+ * relay cannot offer. `auth` because capsule identity is resolved against that
100
+ * same transaction's view. Everything else — fetch, env, realtime, logging —
101
+ * is brokered identically on both tiers and does not constrain placement.
102
+ *
103
+ * Nothing here decides placement automatically: the product a version deploys
104
+ * to is a property of what its author wrote, and this predicate only reports
105
+ * whether the code could also have run on the other tier.
106
+ */
107
+ export declare function endpointIsPortable(capabilities: ExecutionCapabilities): boolean;
108
+ /**
109
+ * A source-carrying handler, before it is compiled to whichever tier will run
110
+ * it. Both products publish these; only the capability set decides which of
111
+ * them could accept a given one.
112
+ */
113
+ export declare function executionEndpointSourceSchema(routePathSchema: z.ZodType<string>): z.ZodObject<{
114
+ method: z.ZodEnum<{
115
+ POST: "POST";
116
+ PUT: "PUT";
117
+ GET: "GET";
118
+ HEAD: "HEAD";
119
+ PATCH: "PATCH";
120
+ DELETE: "DELETE";
121
+ OPTIONS: "OPTIONS";
122
+ }>;
123
+ path: z.ZodType<string, unknown, z.core.$ZodTypeInternals<string, unknown>>;
124
+ endpointId: z.ZodString;
125
+ source: z.ZodString;
126
+ capabilities: z.ZodDefault<z.ZodObject<{
127
+ db: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
128
+ fetch: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
129
+ auth: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
130
+ env: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
131
+ realtime: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
132
+ logging: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
133
+ }, z.core.$strip>>;
134
+ }, z.core.$strict>;
135
+ /**
136
+ * Byte-carrying artifacts travel inline in the finalize payload rather than as
137
+ * a separate upload, so a version's code lands in the same atomic write as the
138
+ * rest of it. The storage root and ceiling differ per product, hence a factory.
139
+ */
140
+ export declare function executionBundleSchema(options: {
141
+ bundleRoot: string;
142
+ maxBytes: number;
143
+ }): z.ZodObject<{
144
+ path: z.ZodString;
145
+ sha256: z.ZodString;
146
+ size: z.ZodNumber;
147
+ contentBase64: z.ZodString;
148
+ }, z.core.$strict>;
149
+ export declare function executionStaticFileSchema(options: {
150
+ storageRoot: string;
151
+ maxBytes: number;
152
+ }): z.ZodObject<{
153
+ path: z.ZodString;
154
+ contentType: z.ZodString;
155
+ sha256: z.ZodString;
156
+ size: z.ZodNumber;
157
+ contentBase64: z.ZodString;
158
+ }, z.core.$strict>;
159
+ /**
160
+ * Whether a version's execution surface may be read by anyone or only by the
161
+ * space's own members. Both products expose an inspect route; the policy is
162
+ * the same question on each.
163
+ */
164
+ export declare const executionInspectPolicySchema: z.ZodEnum<{
165
+ public: "public";
166
+ private: "private";
167
+ }>;
168
+ export type ExecutionInspectPolicy = z.infer<typeof executionInspectPolicySchema>;
169
+ export declare const executionLogEntrySchema: z.ZodObject<{
170
+ id: z.ZodString;
171
+ timestamp: z.ZodString;
172
+ level: z.ZodEnum<{
173
+ info: "info";
174
+ error: "error";
175
+ debug: "debug";
176
+ warn: "warn";
177
+ }>;
178
+ requestId: z.ZodNullable<z.ZodString>;
179
+ versionId: z.ZodNullable<z.ZodString>;
180
+ handlerName: z.ZodNullable<z.ZodString>;
181
+ message: z.ZodString;
182
+ metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
183
+ }, z.core.$strict>;
184
+ export type ExecutionLogEntry = z.infer<typeof executionLogEntrySchema>;
185
+ export declare const executionLogListQuerySchema: z.ZodObject<{
186
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
187
+ cursor: z.ZodOptional<z.ZodString>;
188
+ requestId: z.ZodOptional<z.ZodString>;
189
+ handlerName: z.ZodOptional<z.ZodString>;
190
+ }, z.core.$strict>;
191
+ export type ExecutionLogListQuery = z.infer<typeof executionLogListQuerySchema>;
192
+ export declare const executionLogListResponseSchema: z.ZodObject<{
193
+ data: z.ZodArray<z.ZodObject<{
194
+ id: z.ZodString;
195
+ timestamp: z.ZodString;
196
+ level: z.ZodEnum<{
197
+ info: "info";
198
+ error: "error";
199
+ debug: "debug";
200
+ warn: "warn";
201
+ }>;
202
+ requestId: z.ZodNullable<z.ZodString>;
203
+ versionId: z.ZodNullable<z.ZodString>;
204
+ handlerName: z.ZodNullable<z.ZodString>;
205
+ message: z.ZodString;
206
+ metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
207
+ }, z.core.$strict>>;
208
+ pagination: z.ZodObject<{
209
+ nextCursor: z.ZodNullable<z.ZodString>;
210
+ }, z.core.$strict>;
211
+ }, z.core.$strict>;
212
+ export type ExecutionLogListResponse = z.infer<typeof executionLogListResponseSchema>;
@@ -0,0 +1,288 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The platform execution layer: everything true of running tenant code on
4
+ * Spacefast regardless of which product is running it.
5
+ *
6
+ * Two products sit on top of this file, and they are genuinely different
7
+ * things rather than two configurations of one thing:
8
+ *
9
+ * - **Zero** (`./zero.js`) runs capsules — schema, queries, mutations and
10
+ * endpoints that share one parent-owned transaction — in the native runner
11
+ * on a dedicated wp.cloud site, next to that site's MySQL.
12
+ * - **Functions** (`./functions.js`) runs workers on Cloudflare Workers for
13
+ * Platforms, carrying npm and framework output that we could never sandbox
14
+ * as well ourselves.
15
+ *
16
+ * The only surface both can host is an endpoint that touches neither the
17
+ * database nor the caller's identity — see `endpointIsPortable`. That is the
18
+ * portable seam, and it is deliberately narrow: a capsule handler's semantics
19
+ * depend on the transaction wrapped around it, which does not exist on an
20
+ * isolate a continent away from the database.
21
+ */
22
+ /**
23
+ * What a live version runs. `static` is bytes on disk with no execution at
24
+ * all, and remains the overwhelming majority of traffic; the other two each
25
+ * name a product.
26
+ */
27
+ export const runtimeKindSchema = z.enum(["static", "zero", "functions"]);
28
+ export const EXECUTION_ENV_MAX_KEYS = 64;
29
+ export const EXECUTION_ENV_NAME_MAX_BYTES = 128;
30
+ export const EXECUTION_ENV_VALUE_MAX_BYTES = 16 * 1024;
31
+ export const EXECUTION_ENV_TOTAL_VALUE_MAX_BYTES = 64 * 1024;
32
+ /**
33
+ * Names the platform reserves for itself in the tenant environment. Tenant
34
+ * code cannot set these, so it cannot spoof the values the broker trusts.
35
+ */
36
+ export const EXECUTION_ENV_RESERVED_PREFIXES = ["SPACEFAST_", "ZERO_"];
37
+ /** Paths the platform owns on every space, whatever the product. */
38
+ export const PLATFORM_ROUTE_PREFIX = "/__spacefast";
39
+ /**
40
+ * First path segments the platform claims. Matched as segment prefixes rather
41
+ * than whole segments because the runtime already reserves the whole family —
42
+ * `/__stattic_probe` is a live serving path, and `upload-policy.php` refuses
43
+ * any first segment starting with either of these. Encoding it the same way
44
+ * here keeps a capsule or worker from declaring a route the origin would
45
+ * intercept before it ever reached them.
46
+ */
47
+ export const PLATFORM_RESERVED_ROUTE_SEGMENT_PREFIXES = [
48
+ "__spacefast",
49
+ "__stattic",
50
+ "__span",
51
+ ];
52
+ export const executionSha256Schema = z.string().regex(/^sha256:[a-f0-9]{64}$/);
53
+ export const executionBase64Schema = z
54
+ .string()
55
+ .regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/);
56
+ export const executionIdentifierSchema = z
57
+ .string()
58
+ .min(1)
59
+ .max(128)
60
+ .regex(/^[A-Za-z_][A-Za-z0-9_]*$/);
61
+ export const executionEnvNameSchema = z
62
+ .string()
63
+ .min(1)
64
+ .max(EXECUTION_ENV_NAME_MAX_BYTES)
65
+ .regex(/^[A-Za-z_][A-Za-z0-9_]*$/)
66
+ .refine((name) => !EXECUTION_ENV_RESERVED_PREFIXES.some((prefix) => name.toUpperCase().startsWith(prefix)), { message: "Environment variable name uses a reserved prefix." });
67
+ /**
68
+ * Rejects lone surrogates. A path that survives JSON but not UTF-8 encoding
69
+ * round-trips differently through PHP, Rust and Cloudflare's router, so it is
70
+ * refused at the contract rather than resolved differently on each tier.
71
+ */
72
+ function hasWellFormedUnicode(value) {
73
+ for (let index = 0; index < value.length; index++) {
74
+ const codeUnit = value.charCodeAt(index);
75
+ if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {
76
+ if (index + 1 >= value.length)
77
+ return false;
78
+ const next = value.charCodeAt(index + 1);
79
+ if (next < 0xdc00 || next > 0xdfff)
80
+ return false;
81
+ index++;
82
+ }
83
+ else if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) {
84
+ return false;
85
+ }
86
+ }
87
+ return true;
88
+ }
89
+ function hasNoAsciiControlCharacters(value) {
90
+ for (let index = 0; index < value.length; index++) {
91
+ const codeUnit = value.charCodeAt(index);
92
+ if (codeUnit <= 0x1f || codeUnit === 0x7f)
93
+ return false;
94
+ }
95
+ return true;
96
+ }
97
+ /**
98
+ * Builds the route-path schema for a product. Structural rules — normalization,
99
+ * traversal, wildcards, the platform's own prefixes — are identical everywhere
100
+ * and live here. Each product passes the extra paths and prefixes its own app
101
+ * shell claims, because those differ: Zero's client router owns `/auth/*`,
102
+ * a Functions worker owns nothing beyond what the platform reserves.
103
+ */
104
+ export function appRoutePathSchema(options) {
105
+ const reservedPaths = options.reservedPaths ?? [];
106
+ const reservedPrefixes = options.reservedPrefixes ?? [];
107
+ return z
108
+ .string()
109
+ .min(1)
110
+ .max(2048)
111
+ .startsWith("/")
112
+ .refine(hasWellFormedUnicode, {
113
+ message: `${options.subject} must contain well-formed Unicode.`,
114
+ })
115
+ .refine((path) => path.normalize("NFC") === path, {
116
+ message: `${options.subject} must use NFC-normalized Unicode.`,
117
+ })
118
+ .refine(hasNoAsciiControlCharacters, {
119
+ message: `${options.subject} must not contain ASCII control characters.`,
120
+ })
121
+ .refine((path) => !path.includes("//") &&
122
+ !path.includes("\\") &&
123
+ !path.includes("*") &&
124
+ !path.includes("?") &&
125
+ !path.includes("#") &&
126
+ !path.includes("%") &&
127
+ // The root is the one path allowed to end in a slash. Zero reserves it
128
+ // for its app shell anyway, but a Functions worker serving a framework
129
+ // app needs to claim "/" as its index route.
130
+ (path === "/" || !path.endsWith("/")) &&
131
+ path
132
+ .split("/")
133
+ .every((segment, index, segments) => segment !== "." &&
134
+ segment !== ".." &&
135
+ segment !== ":" &&
136
+ (segment !== ":splat" || index === segments.length - 1)), {
137
+ message: `${options.subject} must be absolute app paths without encoded, empty, traversal, unnamed parameter, * wildcard, non-terminal splat, \\, ?, or # segments.`,
138
+ })
139
+ .refine((path) => !PLATFORM_RESERVED_ROUTE_SEGMENT_PREFIXES.some((segmentPrefix) => (path.split("/")[1] ?? "").startsWith(segmentPrefix)), { message: `${options.subject} cannot use a path the platform reserves.` })
140
+ .refine((path) => !reservedPaths.some((reservedPath) => path === reservedPath), {
141
+ message: `${options.subject} cannot use a reserved path.`,
142
+ })
143
+ .refine((path) => !reservedPrefixes.some((prefix) => path.startsWith(prefix)), {
144
+ message: `${options.subject} cannot use a reserved path prefix.`,
145
+ });
146
+ }
147
+ export const httpMethodSchema = z.enum([
148
+ "GET",
149
+ "HEAD",
150
+ "POST",
151
+ "PUT",
152
+ "PATCH",
153
+ "DELETE",
154
+ "OPTIONS",
155
+ ]);
156
+ /**
157
+ * What a handler is allowed to reach. Declared at build time from what the
158
+ * source actually imports, not from what the author claims, and printed in the
159
+ * publish receipt so placement is never a surprise.
160
+ */
161
+ export const executionCapabilitiesSchema = z
162
+ .object({
163
+ db: z.boolean().default(false),
164
+ fetch: z.boolean().default(false),
165
+ auth: z.boolean().default(false),
166
+ env: z.boolean().default(false),
167
+ realtime: z.boolean().default(false),
168
+ logging: z.boolean().default(false),
169
+ })
170
+ .partial()
171
+ .default({});
172
+ /**
173
+ * The portable seam, stated as one predicate.
174
+ *
175
+ * `db` and `auth` are the two capabilities that bind a handler to the local
176
+ * tier. `db` because Zero's store guarantees every handler runs inside one
177
+ * parent-owned transaction, which an isolate reaching the database over a
178
+ * relay cannot offer. `auth` because capsule identity is resolved against that
179
+ * same transaction's view. Everything else — fetch, env, realtime, logging —
180
+ * is brokered identically on both tiers and does not constrain placement.
181
+ *
182
+ * Nothing here decides placement automatically: the product a version deploys
183
+ * to is a property of what its author wrote, and this predicate only reports
184
+ * whether the code could also have run on the other tier.
185
+ */
186
+ export function endpointIsPortable(capabilities) {
187
+ return capabilities.db !== true && capabilities.auth !== true;
188
+ }
189
+ /**
190
+ * A source-carrying handler, before it is compiled to whichever tier will run
191
+ * it. Both products publish these; only the capability set decides which of
192
+ * them could accept a given one.
193
+ */
194
+ export function executionEndpointSourceSchema(routePathSchema) {
195
+ return z
196
+ .object({
197
+ method: httpMethodSchema,
198
+ path: routePathSchema,
199
+ endpointId: z.string().min(1).max(256),
200
+ source: z
201
+ .string()
202
+ .min(1)
203
+ .max(2 * 1024 * 1024),
204
+ capabilities: executionCapabilitiesSchema,
205
+ })
206
+ .strict();
207
+ }
208
+ /**
209
+ * Byte-carrying artifacts travel inline in the finalize payload rather than as
210
+ * a separate upload, so a version's code lands in the same atomic write as the
211
+ * rest of it. The storage root and ceiling differ per product, hence a factory.
212
+ */
213
+ export function executionBundleSchema(options) {
214
+ return z
215
+ .object({
216
+ path: z
217
+ .string()
218
+ .min(1)
219
+ .startsWith(`${options.bundleRoot}/`)
220
+ .refine((bundlePath) => !bundlePath.split("/").includes(".."), {
221
+ message: "Bundle paths cannot traverse outside the runtime bundle root.",
222
+ }),
223
+ sha256: executionSha256Schema,
224
+ size: z.number().int().nonnegative().max(options.maxBytes),
225
+ contentBase64: executionBase64Schema,
226
+ })
227
+ .strict();
228
+ }
229
+ export function executionStaticFileSchema(options) {
230
+ return z
231
+ .object({
232
+ path: z
233
+ .string()
234
+ .min(1)
235
+ .max(2048)
236
+ .refine((path) => !path.startsWith("/") && !path.split("/").includes(".."), {
237
+ message: "Static file paths must be relative and cannot traverse.",
238
+ })
239
+ .refine((path) => !path.startsWith(`${options.storageRoot}/`), {
240
+ message: `Static files cannot use ${options.storageRoot}.`,
241
+ })
242
+ .refine((path) => !path.startsWith("_") && !path.startsWith("."), {
243
+ message: "Static file paths cannot use private root prefixes.",
244
+ }),
245
+ contentType: z.string().min(1).max(255),
246
+ sha256: executionSha256Schema,
247
+ size: z.number().int().nonnegative().max(options.maxBytes),
248
+ contentBase64: executionBase64Schema,
249
+ })
250
+ .strict();
251
+ }
252
+ /**
253
+ * Whether a version's execution surface may be read by anyone or only by the
254
+ * space's own members. Both products expose an inspect route; the policy is
255
+ * the same question on each.
256
+ */
257
+ export const executionInspectPolicySchema = z.enum(["private", "public"]);
258
+ export const executionLogEntrySchema = z
259
+ .object({
260
+ id: z.string().min(1),
261
+ timestamp: z.string().datetime(),
262
+ level: z.enum(["debug", "info", "warn", "error"]),
263
+ requestId: z.string().min(1).nullable(),
264
+ versionId: z.string().min(1).nullable(),
265
+ /** Zero names the mutation; Functions names the handler. */
266
+ handlerName: z.string().min(1).nullable(),
267
+ message: z.string(),
268
+ metadata: z.record(z.string(), z.unknown()).default({}),
269
+ })
270
+ .strict();
271
+ export const executionLogListQuerySchema = z
272
+ .object({
273
+ limit: z.coerce.number().int().min(1).max(100).default(50),
274
+ cursor: z.string().min(1).optional(),
275
+ requestId: z.string().min(1).optional(),
276
+ handlerName: z.string().min(1).optional(),
277
+ })
278
+ .strict();
279
+ export const executionLogListResponseSchema = z
280
+ .object({
281
+ data: z.array(executionLogEntrySchema),
282
+ pagination: z
283
+ .object({
284
+ nextCursor: z.string().nullable(),
285
+ })
286
+ .strict(),
287
+ })
288
+ .strict();