@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
@@ -21,7 +21,6 @@ export declare const qk: {
21
21
  teamSpaces: (id: string) => readonly ["teams", string, "spaces"];
22
22
  teamDomains: (id: string) => readonly ["teams", string, "domains"];
23
23
  teamManagedDomains: (id: string) => readonly ["teams", string, "managed-domains"];
24
- domainBindings: () => readonly ["domain-bindings"];
25
24
  slugAvailability: (kind: "team" | "space", slug: string, teamId?: string, currentSlug?: string) => readonly ["slugs", "availability", "space" | "team", string, string, string];
26
25
  teamVariables: (id: string) => readonly ["teams", string, "variables"];
27
26
  teamActivity: (id: string, limit: number) => readonly ["teams", string, "activity", number];
@@ -30,8 +29,8 @@ export declare const qk: {
30
29
  spaceVersions: (id: string) => readonly ["spaces", string, "versions"];
31
30
  spaceVersionsHistory: (id: string) => readonly ["spaces", string, "versions", "history"];
32
31
  spaceCollaboration: (id: string) => readonly ["spaces", string, "collaboration"];
33
- spaceCollaborationEmbedConfig: (id: string) => readonly ["spaces", string, "collaboration", "embed-config"];
34
- spaceAnnotations: (id: string) => readonly ["spaces", string, "annotations"];
32
+ spaceComments: (id: string) => readonly ["spaces", string, "comments"];
33
+ spaceCommentThread: (id: string, threadId: string) => readonly ["spaces", string, "comments", string];
35
34
  spaceActivity: (id: string, limit: number) => readonly ["spaces", string, "activity", number];
36
35
  spaceDeployments: (id: string) => readonly ["spaces", string, "deployments"];
37
36
  spaceTags: (id: string) => readonly ["spaces", string, "tags"];
@@ -39,11 +38,11 @@ export declare const qk: {
39
38
  spaceTagDiff: (id: string, versionId: string) => readonly ["spaces", string, "tags", string, "diff"];
40
39
  spaceTagReleases: (id: string) => readonly ["spaces", string, "tags", "releases"];
41
40
  spaceTagsEffective: (id: string) => readonly ["spaces", string, "tags", "effective"];
42
- build: (id: string) => readonly ["builds", string];
43
- buildLogs: (id: string, limit?: number) => readonly ["builds", string, "logs"] | readonly ["builds", string, "logs", number];
41
+ build: (spaceId: string, id: string) => readonly ["spaces", string, "builds", string];
42
+ buildLogs: (spaceId: string, id: string, limit?: number) => readonly ["spaces", string, "builds", string, "logs"] | readonly ["spaces", string, "builds", string, "logs", number];
44
43
  spaceBuilds: (id: string) => readonly ["spaces", string, "builds"];
45
44
  spaceRepositoryConnection: (id: string, connectionType?: string) => readonly ["spaces", string, "repository-connection", string];
46
- repositoryInstallations: (spaceId: string) => readonly ["repository-connections", "installations", string];
45
+ repositoryInstallations: (spaceId: string) => readonly ["spaces", string, "repository-installations"];
47
46
  repositoryInstallationRepositories: (installationId: string) => readonly ["repository-connections", "installations", string, "repositories"];
48
47
  spaceRepositoryAnalyze: (id: string, connectionType?: string, ref?: string, root?: string) => readonly ["spaces", string, "repository-connection", string, "analyze", string, string];
49
48
  spaceRepositoryWebhookDeliveries: (id: string, connectionType?: string) => readonly ["spaces", string, "repository-webhook-deliveries", string];
@@ -51,7 +50,7 @@ export declare const qk: {
51
50
  webhook: (webhookId: string) => readonly ["webhooks", string];
52
51
  webhookDeliveries: (webhookId: string) => readonly ["webhooks", string, "deliveries"];
53
52
  spaceVersion: (id: string, versionId: string) => readonly ["spaces", string, "versions", string];
54
- spaceVersionAnnotations: (id: string, versionId: string, status?: string) => readonly ["spaces", string, "versions", string, "annotations"] | readonly ["spaces", string, "versions", string, "annotations", string];
53
+ spaceVersionComments: (id: string, versionId: string, status?: string) => readonly ["spaces", string, "versions", string, "comments"] | readonly ["spaces", string, "versions", string, "comments", string];
55
54
  spaceVersionFiles: (id: string, versionId: string) => readonly ["spaces", string, "versions", string, "files"];
56
55
  spaceVersionFile: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string];
57
56
  spaceVersionFileDirectUrl: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string, "direct-url"];
@@ -64,20 +63,15 @@ export declare const qk: {
64
63
  spaceDomains: (id: string) => readonly ["spaces", string, "domains"];
65
64
  spaceRuntimeStatus: (id: string) => readonly ["spaces", string, "runtime"];
66
65
  spaceApplyState: (id: string) => readonly ["spaces", string, "apply-state"];
67
- spaceZero: (id: string) => readonly ["spaces", string, "zero"];
68
66
  spaceZeroDb: (id: string) => readonly ["spaces", string, "zero", "db"];
69
- spaceZeroLogs: (id: string, limit: number) => readonly ["spaces", string, "zero", "logs", number];
67
+ spaceRuntimeLogs: (id: string, limit: number) => readonly ["spaces", string, "logs", "runtime", number];
70
68
  spaceZeroRealtimeEvents: (id: string, limit: number) => readonly ["spaces", string, "zero", "realtime", "events", number];
71
69
  spaceVariables: (id: string) => readonly ["spaces", string, "variables"];
72
70
  spaceCertificates: (id: string) => readonly ["spaces", string, "runtime", "certificates"];
73
71
  spaceLogs: (id: string, kind: "build" | "access" | "runtime") => readonly ["spaces", string, "logs", "build" | "runtime" | "access"];
74
72
  spaceAnalytics: (id: string, window: string) => readonly ["spaces", string, "analytics", string];
75
- spaceFirewall: (id: string) => readonly ["spaces", string, "access", "firewall"];
76
- spaceAccessViews: (id: string, since?: string) => readonly ["spaces", string, "access", "views", string];
77
- teamServiceTokens: (teamId: string) => readonly ["teams", string, "access", "service-tokens"];
78
73
  teamAgentHandoffs: (teamId: string) => readonly ["teams", string, "agent-handoffs"];
79
74
  teamAccessDefaults: (teamId: string) => readonly ["teams", string, "access", "defaults"];
80
- teamAccessConnections: (teamId: string) => readonly ["teams", string, "access", "connections"];
81
75
  domain: (teamId: string, ref: string) => readonly ["teams", string, "domains", string];
82
76
  domainDiagnostics: (teamId: string, domainId: string) => readonly ["teams", string, "domains", string, "diagnostics"];
83
77
  domainDnsCapabilities: (domainId: string) => readonly ["domains", string, "dns", "capabilities"];
@@ -26,7 +26,6 @@ export const qk = {
26
26
  teamSpaces: (id) => ["teams", id, "spaces"],
27
27
  teamDomains: (id) => ["teams", id, "domains"],
28
28
  teamManagedDomains: (id) => ["teams", id, "managed-domains"],
29
- domainBindings: () => ["domain-bindings"],
30
29
  slugAvailability: (kind, slug, teamId, currentSlug) => ["slugs", "availability", kind, slug, teamId ?? "", currentSlug ?? ""],
31
30
  teamVariables: (id) => ["teams", id, "variables"],
32
31
  teamActivity: (id, limit) => ["teams", id, "activity", limit],
@@ -38,8 +37,8 @@ export const qk = {
38
37
  // `invalidateQueries({ queryKey: qk.spaceVersions(id) })` still reaches it.
39
38
  spaceVersionsHistory: (id) => [...qk.spaceVersions(id), "history"],
40
39
  spaceCollaboration: (id) => ["spaces", id, "collaboration"],
41
- spaceCollaborationEmbedConfig: (id) => ["spaces", id, "collaboration", "embed-config"],
42
- spaceAnnotations: (id) => ["spaces", id, "annotations"],
40
+ spaceComments: (id) => ["spaces", id, "comments"],
41
+ spaceCommentThread: (id, threadId) => [...qk.spaceComments(id), threadId],
43
42
  spaceActivity: (id, limit) => ["spaces", id, "activity", limit],
44
43
  spaceDeployments: (id) => ["spaces", id, "deployments"],
45
44
  spaceTags: (id) => ["spaces", id, "tags"],
@@ -49,15 +48,15 @@ export const qk = {
49
48
  // The merged (system+team+space) read-only view; never a write base — see
50
49
  // `fetchSpaceReleasedGraph` in apps/my/src/lib/space-queries.ts.
51
50
  spaceTagsEffective: (id) => ["spaces", id, "tags", "effective"],
52
- build: (id) => ["builds", id],
51
+ build: (spaceId, id) => [...qk.spaceBuilds(spaceId), id],
53
52
  // Observers with different limits must not share a cache entry; calling with
54
53
  // no limit yields the bare prefix for invalidating every limit at once.
55
- buildLogs: (id, limit) => limit === undefined
56
- ? ["builds", id, "logs"]
57
- : ["builds", id, "logs", limit],
54
+ buildLogs: (spaceId, id, limit) => limit === undefined
55
+ ? [...qk.build(spaceId, id), "logs"]
56
+ : [...qk.build(spaceId, id), "logs", limit],
58
57
  spaceBuilds: (id) => ["spaces", id, "builds"],
59
58
  spaceRepositoryConnection: (id, connectionType = "connected") => ["spaces", id, "repository-connection", connectionType],
60
- repositoryInstallations: (spaceId) => ["repository-connections", "installations", spaceId],
59
+ repositoryInstallations: (spaceId) => [...qk.space(spaceId), "repository-installations"],
61
60
  repositoryInstallationRepositories: (installationId) => ["repository-connections", "installations", installationId, "repositories"],
62
61
  spaceRepositoryAnalyze: (id, connectionType = "connected", ref = "", root = "") => ["spaces", id, "repository-connection", connectionType, "analyze", ref, root],
63
62
  spaceRepositoryWebhookDeliveries: (id, connectionType = "connected") => ["spaces", id, "repository-webhook-deliveries", connectionType],
@@ -66,10 +65,10 @@ export const qk = {
66
65
  webhookDeliveries: (webhookId) => ["webhooks", webhookId, "deliveries"],
67
66
  spaceVersion: (id, versionId) => ["spaces", id, "versions", versionId],
68
67
  // Calling with no status yields the bare prefix, for invalidating every
69
- // status-scoped annotations list at once.
70
- spaceVersionAnnotations: (id, versionId, status) => status === undefined
71
- ? ["spaces", id, "versions", versionId, "annotations"]
72
- : ["spaces", id, "versions", versionId, "annotations", status],
68
+ // status-scoped version comment list at once.
69
+ spaceVersionComments: (id, versionId, status) => status === undefined
70
+ ? ["spaces", id, "versions", versionId, "comments"]
71
+ : ["spaces", id, "versions", versionId, "comments", status],
73
72
  spaceVersionFiles: (id, versionId) => ["spaces", id, "versions", versionId, "files"],
74
73
  spaceVersionFile: (id, versionId, path) => ["spaces", id, "versions", versionId, "files", path],
75
74
  spaceVersionFileDirectUrl: (id, versionId, path) => ["spaces", id, "versions", versionId, "files", path, "direct-url"],
@@ -82,20 +81,15 @@ export const qk = {
82
81
  spaceDomains: (id) => ["spaces", id, "domains"],
83
82
  spaceRuntimeStatus: (id) => ["spaces", id, "runtime"],
84
83
  spaceApplyState: (id) => ["spaces", id, "apply-state"],
85
- spaceZero: (id) => ["spaces", id, "zero"],
86
84
  spaceZeroDb: (id) => ["spaces", id, "zero", "db"],
87
- spaceZeroLogs: (id, limit) => ["spaces", id, "zero", "logs", limit],
85
+ spaceRuntimeLogs: (id, limit) => ["spaces", id, "logs", "runtime", limit],
88
86
  spaceZeroRealtimeEvents: (id, limit) => ["spaces", id, "zero", "realtime", "events", limit],
89
87
  spaceVariables: (id) => ["spaces", id, "variables"],
90
88
  spaceCertificates: (id) => ["spaces", id, "runtime", "certificates"],
91
89
  spaceLogs: (id, kind) => ["spaces", id, "logs", kind],
92
90
  spaceAnalytics: (id, window) => ["spaces", id, "analytics", window],
93
- spaceFirewall: (id) => ["spaces", id, "access", "firewall"],
94
- spaceAccessViews: (id, since) => ["spaces", id, "access", "views", since ?? ""],
95
- teamServiceTokens: (teamId) => ["teams", teamId, "access", "service-tokens"],
96
91
  teamAgentHandoffs: (teamId) => ["teams", teamId, "agent-handoffs"],
97
92
  teamAccessDefaults: (teamId) => ["teams", teamId, "access", "defaults"],
98
- teamAccessConnections: (teamId) => ["teams", teamId, "access", "connections"],
99
93
  domain: (teamId, ref) => ["teams", teamId, "domains", ref],
100
94
  domainDiagnostics: (teamId, domainId) => ["teams", teamId, "domains", domainId, "diagnostics"],
101
95
  domainDnsCapabilities: (domainId) => ["domains", domainId, "dns", "capabilities"],
@@ -0,0 +1,2 @@
1
+ export declare const SOURCE_ARCHIVE_MAX_EXPANSION_RATIO = 200;
2
+ export declare const SOURCE_ARCHIVE_EXPANSION_RATIO_FLOOR_BYTES: number;
@@ -0,0 +1,2 @@
1
+ export const SOURCE_ARCHIVE_MAX_EXPANSION_RATIO = 200;
2
+ export const SOURCE_ARCHIVE_EXPANSION_RATIO_FLOOR_BYTES = 8 * 1024 * 1024;
@@ -1,3 +1,4 @@
1
+ import { type Grant } from "../contracts/grants.js";
1
2
  import { type SpaceConfig, type SpaceConfigFile } from "../contracts/space-config.js";
2
3
  export type SpaceConfigBlockingIssueCode = "config_file_too_large" | "config_templates_over_limit" | "config_meta_too_long" | "config_invalid" | "inject_snippet_too_large" | "inject_invalid";
3
4
  export type SpaceConfigIssue = {
@@ -8,6 +9,9 @@ export type SpaceConfigIssue = {
8
9
  path?: string;
9
10
  details?: Record<string, unknown>;
10
11
  };
12
+ export declare const CONFIG_PUBLIC_GRANT_COMPILED_ID = "config:access.public";
13
+ /** Compiles the file-only access declaration; activation decides which Version is live. */
14
+ export declare function compileSpaceConfigPublicGrant(fileConfig: Pick<SpaceConfigFile, "access"> | null | undefined): Grant | null;
11
15
  type SpaceConfigBlockingIssue = SpaceConfigIssue & {
12
16
  code: SpaceConfigBlockingIssueCode;
13
17
  };
@@ -16,7 +20,7 @@ type SpaceConfigBlockingIssue = SpaceConfigIssue & {
16
20
  * `config`): the 16 KB compiled-overlay cap plus the shared shape caps.
17
21
  * Returns the first blocking issue, or null when the overlay is acceptable.
18
22
  */
19
- export declare function spaceConfigOverlayIssue(config: SpaceConfig): SpaceConfigBlockingIssue | null;
23
+ export declare function spaceConfigOverlayIssue(config: SpaceConfig | Record<string, unknown>): SpaceConfigBlockingIssue | null;
20
24
  export declare function stripJsonComments(raw: string): string;
21
25
  export type ParsedSpaceConfigFile = {
22
26
  /** Parsed config (cap- and shape-valid keys only); null when unusable. */
@@ -1,8 +1,35 @@
1
+ import { CONFIG_PUBLIC_GRANT_SOURCE_REFERENCE, grantSchema, } from "../contracts/grants.js";
1
2
  import { SPACE_CONFIG_CAPS, SPACE_CONFIG_CANONICAL_FILE, SPACE_CONFIG_PRIVATE_FILES, spaceConfigFileSchema, spaceConfigSchema, } from "../contracts/space-config.js";
2
3
  const TEXT_BYTES = new TextEncoder();
4
+ export const CONFIG_PUBLIC_GRANT_COMPILED_ID = "config:access.public";
3
5
  function byteLength(value) {
4
6
  return TEXT_BYTES.encode(value).length;
5
7
  }
8
+ /** Compiles the file-only access declaration; activation decides which Version is live. */
9
+ export function compileSpaceConfigPublicGrant(fileConfig) {
10
+ const patterns = fileConfig?.access?.public ?? [];
11
+ const include = patterns.filter((pattern) => !pattern.startsWith("!"));
12
+ if (include.length === 0)
13
+ return null;
14
+ return grantSchema.parse({
15
+ id: CONFIG_PUBLIC_GRANT_COMPILED_ID,
16
+ name: "Public paths from sf.jsonc",
17
+ audience: { kind: "public" },
18
+ resources: {
19
+ include,
20
+ exclude: patterns
21
+ .filter((pattern) => pattern.startsWith("!"))
22
+ .map((pattern) => pattern.slice(1)),
23
+ },
24
+ capabilities: ["page.view"],
25
+ constraints: {},
26
+ target: { kind: "live" },
27
+ source: {
28
+ kind: "config",
29
+ reference: CONFIG_PUBLIC_GRANT_SOURCE_REFERENCE,
30
+ },
31
+ });
32
+ }
6
33
  function capIssues(candidate) {
7
34
  const issues = [];
8
35
  const templates = candidate.templates;
@@ -102,6 +129,14 @@ function capIssues(candidate) {
102
129
  * Returns the first blocking issue, or null when the overlay is acceptable.
103
130
  */
104
131
  export function spaceConfigOverlayIssue(config) {
132
+ if (Object.prototype.hasOwnProperty.call(config, "access")) {
133
+ return {
134
+ severity: "error",
135
+ code: "config_invalid",
136
+ message: "access is only valid in the committed sf.jsonc file.",
137
+ path: "access",
138
+ };
139
+ }
105
140
  const encoded = JSON.stringify(config);
106
141
  if (byteLength(encoded) > SPACE_CONFIG_CAPS.overlayBytes) {
107
142
  return {
@@ -1,5 +1,10 @@
1
1
  export declare const PHP_LIKE_EXTENSIONS: string[];
2
+ export declare const INTERNAL_REDIRECT_RESPONSE_HEADERS: string[];
2
3
  export declare const PLATFORM_MANAGED_RESPONSE_HEADERS: string[];
4
+ /** Reserved response-header namespaces owned by the platform's own serving signature. */
5
+ export declare const PLATFORM_MANAGED_RESPONSE_HEADER_PREFIXES: string[];
6
+ /** True when user rules may neither set nor remove this response header. */
7
+ export declare function isPlatformManagedResponseHeader(name: string): boolean;
3
8
  export declare const NON_IMMUTABLE_EXTENSIONS: string[];
4
9
  export declare const GUARANTEED_IMMUTABLE_PREFIXES: string[];
5
10
  /** Lowercased extension without the leading dot, posix semantics. Dotfiles have no extension. */
@@ -0,0 +1,57 @@
1
+ {
2
+ "phpLike": [
3
+ { "path": "index.php", "expected": true },
4
+ { "path": "nested/app.phtml", "expected": true },
5
+ { "path": "lib.phar", "expected": true },
6
+ { "path": "legacy.php5", "expected": true },
7
+ { "path": "index.html", "expected": false },
8
+ { "path": "assets/main.js", "expected": false },
9
+ { "path": ".env", "expected": false }
10
+ ],
11
+ "immutable": [
12
+ { "path": "_next/static/chunks/main-app-4A_iFExJ.js", "expected": true },
13
+ { "path": "_next/static/chunks/framework-2c1d4f8a.js", "expected": true },
14
+ { "path": "_next/static/chunks/pages/index-a1b2c3d4e5f6.js", "expected": true },
15
+ { "path": "_next/static/chunks/oton0Guf.js", "expected": true },
16
+ { "path": "_next/static/css/app.plainname.css", "expected": true },
17
+ { "path": "/_next/static/chunks/oton0Guf.js", "expected": true },
18
+ { "path": "_app/immutable/entry/start.DYyuCeEr.js", "expected": true },
19
+ { "path": "_nuxt/index.oton0Guf.js", "expected": true },
20
+ { "path": "_astro/about.DYyuCeEr.css", "expected": true },
21
+ { "path": "_next/static/index.html", "expected": false },
22
+ { "path": "_next/static/sitemap.xml", "expected": false },
23
+ { "path": "_app/immutable/manifest.txt", "expected": false },
24
+ { "path": "_nextish/chunks/oton0Guf.js", "expected": false },
25
+ { "path": "nested/_next/static/chunks/oton0Guf.js", "expected": false },
26
+ { "path": "assets/index-BzeDGMM3.js", "expected": false },
27
+ { "path": "assets/auth-client-P1Tx-Cyu.js", "expected": false },
28
+ { "path": "assets/index-DYyuCeEr.js", "expected": false },
29
+ { "path": "assets/index-9f8e7d6c.js", "expected": false },
30
+ { "path": "assets/D3GeoMap.js", "expected": false },
31
+ { "path": "assets/index.js", "expected": false },
32
+ { "path": "assets/client-widget.js", "expected": false },
33
+ { "path": "app.1a2b3c4d.css", "expected": false },
34
+ { "path": "vendor.3f9a2b7e.js", "expected": false },
35
+ { "path": "static/js/main.d41d8cd98f00b204e9800998.js", "expected": false },
36
+ { "path": "index.html", "expected": false },
37
+ { "path": "robots.txt", "expected": false },
38
+ { "path": "config.xml", "expected": false },
39
+ { "path": "page.php", "expected": false },
40
+ { "path": "MyComponent.js", "expected": false },
41
+ { "path": "image01.png", "expected": false }
42
+ ],
43
+ "safeContentType": [
44
+ {
45
+ "path": "index.php",
46
+ "mime": "application/x-httpd-php",
47
+ "expected": "text/plain; charset=utf-8"
48
+ },
49
+ { "path": "lib.phar", "mime": "application/zip", "expected": "application/octet-stream" },
50
+ {
51
+ "path": "assets/main.js",
52
+ "mime": "text/javascript; charset=utf-8",
53
+ "expected": "text/javascript; charset=utf-8"
54
+ },
55
+ { "path": "logo.svg", "mime": "image/svg+xml", "expected": "image/svg+xml" }
56
+ ]
57
+ }
@@ -7,13 +7,47 @@
7
7
  // (static-runtime-policy.fixtures.json). Do not add platform/filesystem
8
8
  // behavior here.
9
9
  export const PHP_LIKE_EXTENSIONS = ["php", "php3", "php4", "php5", "php7", "php8", "phtml", "phar"];
10
+ // The internal-redirect/sendfile family: headers that do not describe a response, they
11
+ // instruct the web server to produce a different one. Under nginx+php-fpm
12
+ // X-Accel-Redirect (and every vendor spelling of it) turns a response into a server-side
13
+ // read of an arbitrary internal path — a private-path disclosure primitive — while
14
+ // X-Accel-Limit-Rate pins the serving worker for the length of the transfer.
15
+ //
16
+ // These are dangerous from ANY origin we do not control, so this family is factored out
17
+ // of the platform-managed list below: a relay lane (runtime/engine/runtime/proxy.php)
18
+ // must drop exactly this set from an untrusted upstream while still relaying the
19
+ // ordinary response headers (location, content-encoding, content-range, allow) that the
20
+ // rest of the managed list contains.
21
+ export const INTERNAL_REDIRECT_RESPONSE_HEADERS = [
22
+ "x-accel-buffering",
23
+ "x-accel-charset",
24
+ "x-accel-expires",
25
+ "x-accel-limit-rate",
26
+ "x-accel-redirect",
27
+ "x-lighttpd-send-file",
28
+ "x-lighttpd-sendfile",
29
+ "x-lighttpd-sendfile2",
30
+ "x-reproxy-url",
31
+ "x-sendfile",
32
+ ];
10
33
  // Rejected/platform-managed response headers (internal-docs/platform.md "Routing And
11
- // Headers"): user `_headers` rules can never set or remove these. The list includes the
12
- // internal-redirect/sendfile family (X-Accel-Redirect, X-Sendfile, X-LIGHTTPD-send-file,
13
- // X-Accel-Buffering) because under nginx+php-fpm those headers turn a response into a
14
- // server-side file read a private-path disclosure primitive. The routing compiler
15
- // rejects them at publish; the PHP runtime refuses them again at apply time so a compiler
16
- // gap can never emit one.
34
+ // Headers"): user `_headers` rules can never set or remove these. The
35
+ // internal-redirect/sendfile family above is spread in, so it stays a strict subset —
36
+ // anything the proxy lane refuses to relay is also refused from `_headers`. The rest is
37
+ // the connection and transport surface: hop-by-hop names (Connection, Keep-Alive, TE,
38
+ // Trailer, Transfer-Encoding, Upgrade, Proxy-*), framing, and the edge-cache trio.
39
+ //
40
+ // `isPlatformManagedResponseHeader` — not this list alone — is the policy: the reserved
41
+ // `x-spacefast-*` / `x-stattic-*` namespaces below carry the platform's own response
42
+ // signature (X-Spacefast-Runtime, X-Spacefast-Version, X-Spacefast-Reason, …), so user
43
+ // rules can never forge or clobber them.
44
+ //
45
+ // Every enforcement point derives from here: the `_headers` compiler in
46
+ // @spacefast/routing imports it directly, the PHP runtime maps and prefixes are
47
+ // generated from it into runtime/engine/shared/safety.php, and the Rust authorities
48
+ // (crates/stattic-runtime-core policy.rs, crates/stattic-zero-runner
49
+ // response_headers.rs) are drift-guarded against it by
50
+ // apps/control-plane/src/runtime/php-policy-parity.test.ts.
17
51
  export const PLATFORM_MANAGED_RESPONSE_HEADERS = [
18
52
  "accept-ranges",
19
53
  "age",
@@ -28,21 +62,31 @@ export const PLATFORM_MANAGED_RESPONSE_HEADERS = [
28
62
  "cookie",
29
63
  "date",
30
64
  "host",
65
+ "keep-alive",
31
66
  "location",
32
67
  "netlify-cdn-cache-control",
68
+ "proxy-authenticate",
69
+ "proxy-authorization",
33
70
  "server",
34
71
  "set-cookie",
35
72
  "strict-transport-security",
36
73
  "surrogate-control",
74
+ "te",
37
75
  "trailer",
38
76
  "transfer-encoding",
39
77
  "upgrade",
40
78
  "vary",
41
- "x-accel-buffering",
42
- "x-accel-redirect",
43
- "x-lighttpd-send-file",
44
- "x-sendfile",
79
+ ...INTERNAL_REDIRECT_RESPONSE_HEADERS,
45
80
  ];
81
+ /** Reserved response-header namespaces owned by the platform's own serving signature. */
82
+ export const PLATFORM_MANAGED_RESPONSE_HEADER_PREFIXES = ["x-spacefast-", "x-stattic-"];
83
+ const PLATFORM_MANAGED_RESPONSE_HEADER_SET = new Set(PLATFORM_MANAGED_RESPONSE_HEADERS);
84
+ /** True when user rules may neither set nor remove this response header. */
85
+ export function isPlatformManagedResponseHeader(name) {
86
+ const lower = name.trim().toLowerCase();
87
+ return (PLATFORM_MANAGED_RESPONSE_HEADER_SET.has(lower) ||
88
+ PLATFORM_MANAGED_RESPONSE_HEADER_PREFIXES.some((prefix) => lower.startsWith(prefix)));
89
+ }
46
90
  export const NON_IMMUTABLE_EXTENSIONS = ["html", "htm", "php", "txt", "xml"];
47
91
  const PHP_LIKE_EXTENSION_SET = new Set(PHP_LIKE_EXTENSIONS);
48
92
  const NON_IMMUTABLE_EXTENSION_SET = new Set(NON_IMMUTABLE_EXTENSIONS);
@@ -24,6 +24,9 @@ export declare class UploadTargetError extends Error {
24
24
  readonly status: number;
25
25
  constructor(target: UploadTarget, status: number, message: string);
26
26
  }
27
+ export declare function uploadPageHasRemainder(page: UploadSession): boolean;
28
+ export declare const UPLOAD_STALLED_RESUME_MAX_ATTEMPTS = 3;
29
+ export declare function uploadQueueAdvanced(before: UploadSession, after: UploadSession | null): boolean;
27
30
  export declare function executeUploadSession(input: {
28
31
  session: UploadSession;
29
32
  targets?: readonly UploadTarget[] | undefined;
@@ -8,6 +8,37 @@ export class UploadTargetError extends Error {
8
8
  this.name = "UploadTargetError";
9
9
  }
10
10
  }
11
+ // Manifest paging policy — ONE definition, shared by every uploader (the CLI
12
+ // and the control plane's inline uploader).
13
+ //
14
+ // `targets` is a single instruction page, bounded by the instruction payload
15
+ // budget; `summary.upload` counts the whole declared manifest. A short page
16
+ // therefore means a remainder that only `resume` hands out, and an uploader
17
+ // that stops at the first page finalizes a version the runtime rejects with
18
+ // `version_upload_incomplete`. A complete page means there is nothing left to
19
+ // ask for — don't re-resume to double-check the uploads, since the runtime
20
+ // verifies size and sha256 on every PUT and finalize independently enumerates
21
+ // anything still missing.
22
+ export function uploadPageHasRemainder(page) {
23
+ return page.summary.upload > page.targets.length;
24
+ }
25
+ // Resume mints the next page from runtime session truth, so a converging
26
+ // session always hands back different work. A page that repeats the previous
27
+ // one is a session that is not draining; retry it a bounded number of times,
28
+ // then fail loudly rather than page forever.
29
+ export const UPLOAD_STALLED_RESUME_MAX_ATTEMPTS = 3;
30
+ export function uploadQueueAdvanced(before, after) {
31
+ if (!after || after.targets.length === 0) {
32
+ return true;
33
+ }
34
+ if (after.targets.length < before.targets.length) {
35
+ return true;
36
+ }
37
+ if (after.targets.length > before.targets.length) {
38
+ return false;
39
+ }
40
+ return after.targets.some((target, index) => target.path !== before.targets[index]?.path);
41
+ }
11
42
  async function runConcurrent(items, concurrency, fn) {
12
43
  let nextIndex = 0;
13
44
  const runWorker = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spacefast/common",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "license": "MIT",
5
5
  "description": "Shared TypeScript contracts and utilities for Spacefast packages.",
6
6
  "repository": {
@@ -91,8 +91,10 @@
91
91
  }
92
92
  },
93
93
  "dependencies": {
94
- "@tanstack/react-query": "^5.101.1",
95
- "smol-toml": "^1.6.1",
96
- "zod": "^4.3.6"
94
+ "@tanstack/react-query": "^5.101.4",
95
+ "culori": "^4.0.2",
96
+ "js-yaml": "^4.1.1",
97
+ "smol-toml": "^1.7.0",
98
+ "zod": "^4.4.3"
97
99
  }
98
100
  }