@spacefast/common 0.0.24 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/brand-assets/LICENSE-Haskoy.txt +93 -0
  2. package/brand-assets/haskoy-latin-variable.woff2 +0 -0
  3. package/brand-assets/spacefast-favicon.svg +4 -4
  4. package/brand-assets/spacefast-sf-full-bleed.svg +3 -3
  5. package/brand-assets/spacefast-wordmark.svg +2 -4
  6. package/dist/agents/connect-targets.js +1 -1
  7. package/dist/agents/private-key-oauth.d.ts +0 -1
  8. package/dist/agents/private-key-oauth.js +46 -63
  9. package/dist/brand-assets-build.js +4 -6
  10. package/dist/brand-assets.d.ts +5 -15
  11. package/dist/brand-assets.js +15 -14
  12. package/dist/config/domains.d.ts +47 -7
  13. package/dist/config/domains.js +65 -10
  14. package/dist/contracts/access.d.ts +3 -3
  15. package/dist/contracts/activity.d.ts +1 -1
  16. package/dist/contracts/activity.js +5 -3
  17. package/dist/contracts/api-keys.js +2 -2
  18. package/dist/contracts/billing.d.ts +2 -1
  19. package/dist/contracts/billing.js +30 -0
  20. package/dist/contracts/builds.d.ts +34 -22
  21. package/dist/contracts/builds.js +18 -6
  22. package/dist/contracts/channels.js +1 -1
  23. package/dist/contracts/comments.d.ts +1 -1
  24. package/dist/contracts/common.d.ts +6 -6
  25. package/dist/contracts/common.js +5 -5
  26. package/dist/contracts/crons.d.ts +35 -0
  27. package/dist/contracts/crons.js +42 -0
  28. package/dist/contracts/device-auth.js +1 -1
  29. package/dist/contracts/docs.d.ts +5 -5
  30. package/dist/contracts/docs.js +2 -2
  31. package/dist/contracts/domains.d.ts +74 -63
  32. package/dist/contracts/domains.js +29 -2
  33. package/dist/contracts/enums.d.ts +3 -2
  34. package/dist/contracts/enums.js +10 -10
  35. package/dist/contracts/error-code-meta.d.ts +14 -0
  36. package/dist/contracts/error-code-meta.js +17 -0
  37. package/dist/contracts/error-codes.d.ts +1 -1
  38. package/dist/contracts/error-codes.js +4 -1
  39. package/dist/contracts/execution.d.ts +15 -12
  40. package/dist/contracts/execution.js +15 -12
  41. package/dist/contracts/feature-lifecycle.d.ts +4 -14
  42. package/dist/contracts/feature-lifecycle.js +0 -11
  43. package/dist/contracts/features.d.ts +33 -47
  44. package/dist/contracts/features.js +27 -20
  45. package/dist/contracts/functions.d.ts +169 -2
  46. package/dist/contracts/functions.js +160 -4
  47. package/dist/contracts/git.d.ts +27 -33
  48. package/dist/contracts/git.js +10 -11
  49. package/dist/contracts/grants.d.ts +2 -2
  50. package/dist/contracts/ids.js +2 -2
  51. package/dist/contracts/internal.d.ts +5 -16
  52. package/dist/contracts/internal.js +2 -12
  53. package/dist/contracts/mcp.d.ts +11 -0
  54. package/dist/contracts/mcp.js +5 -0
  55. package/dist/contracts/me.js +1 -1
  56. package/dist/contracts/operations.d.ts +4 -4
  57. package/dist/contracts/operations.js +2 -2
  58. package/dist/contracts/pages.d.ts +6 -6
  59. package/dist/contracts/plan-policy.d.ts +1 -1
  60. package/dist/contracts/plan-policy.js +1 -1
  61. package/dist/contracts/platform.d.ts +4 -4
  62. package/dist/contracts/publish-archive.d.ts +170 -160
  63. package/dist/contracts/publish-archive.js +8 -1
  64. package/dist/contracts/push-new.d.ts +4 -4
  65. package/dist/contracts/quotas.js +2 -2
  66. package/dist/contracts/repository-connections.d.ts +43 -30
  67. package/dist/contracts/repository-connections.js +11 -3
  68. package/dist/contracts/resources.d.ts +8 -8
  69. package/dist/contracts/resources.js +6 -6
  70. package/dist/contracts/runtime-api.d.ts +103 -56
  71. package/dist/contracts/runtime-api.js +67 -26
  72. package/dist/contracts/runtime-app.d.ts +2 -2
  73. package/dist/contracts/runtime-db.d.ts +6 -6
  74. package/dist/contracts/runtime-db.js +2 -2
  75. package/dist/contracts/runtime-purge.d.ts +8 -0
  76. package/dist/contracts/runtime-purge.js +7 -0
  77. package/dist/contracts/runtime-storage.d.ts +3 -2
  78. package/dist/contracts/runtime-storage.js +2 -1
  79. package/dist/contracts/sf-config-v1.d.ts +48 -10
  80. package/dist/contracts/space-config.d.ts +60 -3
  81. package/dist/contracts/space-config.js +213 -18
  82. package/dist/contracts/spaces.d.ts +55 -74
  83. package/dist/contracts/spaces.js +11 -14
  84. package/dist/contracts/superadmin-spaces.d.ts +9 -9
  85. package/dist/contracts/superadmin-teams.d.ts +2 -2
  86. package/dist/contracts/superadmin-tenants.d.ts +0 -6
  87. package/dist/contracts/superadmin-tenants.js +1 -7
  88. package/dist/contracts/superadmin.d.ts +135 -22
  89. package/dist/contracts/superadmin.js +43 -12
  90. package/dist/contracts/tags.d.ts +21 -21
  91. package/dist/contracts/tags.js +3 -3
  92. package/dist/contracts/teams.d.ts +14 -17
  93. package/dist/contracts/teams.js +6 -6
  94. package/dist/contracts/transfers.js +2 -2
  95. package/dist/contracts/variables.d.ts +4 -4
  96. package/dist/contracts/variables.js +3 -3
  97. package/dist/contracts/webhooks.d.ts +4 -4
  98. package/dist/contracts/zero.d.ts +15 -17
  99. package/dist/contracts/zero.js +12 -12
  100. package/dist/docs/agent-prose.d.ts +1 -1
  101. package/dist/docs/agent-prose.js +11 -14
  102. package/dist/docs/agent-setup.js +5 -2
  103. package/dist/docs/catalog.d.ts +7 -7
  104. package/dist/docs/catalog.js +7 -7
  105. package/dist/docs/error-docs.js +145 -133
  106. package/dist/docs/skills.d.ts +12 -12
  107. package/dist/docs/skills.js +4 -4
  108. package/dist/test-helpers/fetch-stub.js +1 -0
  109. package/dist/utils/build-settings.d.ts +5 -1
  110. package/dist/utils/build-settings.js +82 -10
  111. package/dist/utils/canonical-json.js +1 -0
  112. package/dist/utils/concurrency.js +1 -0
  113. package/dist/utils/credential-policy.js +4 -3
  114. package/dist/utils/dns-instructions.js +9 -9
  115. package/dist/utils/error-code.js +1 -0
  116. package/dist/utils/grant-decision.fixtures.json +2 -2
  117. package/dist/utils/grants.js +3 -1
  118. package/dist/utils/local-space-state.d.ts +8 -11
  119. package/dist/utils/local-space-state.js +13 -24
  120. package/dist/utils/one-shot-replay.d.ts +4 -1
  121. package/dist/utils/page-colors.d.ts +14 -12
  122. package/dist/utils/page-colors.js +15 -13
  123. package/dist/utils/page-fonts.d.ts +1 -1
  124. package/dist/utils/page-fonts.js +11 -18
  125. package/dist/utils/pages.d.ts +20 -1
  126. package/dist/utils/pages.js +22 -9
  127. package/dist/utils/publish-policy.d.ts +7 -0
  128. package/dist/utils/publish-policy.fixtures.json +11 -5
  129. package/dist/utils/publish-policy.js +9 -1
  130. package/dist/utils/query-keys.d.ts +4 -4
  131. package/dist/utils/query-keys.js +2 -2
  132. package/dist/utils/runtime-upload.d.ts +5 -0
  133. package/dist/utils/runtime-upload.js +7 -0
  134. package/dist/utils/secure-local-file.js +5 -16
  135. package/dist/utils/space-config.d.ts +1 -1
  136. package/dist/utils/space-config.js +3 -0
  137. package/dist/utils/static-runtime-policy.d.ts +9 -3
  138. package/dist/utils/static-runtime-policy.fixtures.json +38 -41
  139. package/dist/utils/static-runtime-policy.js +22 -56
  140. package/dist/utils/upload-session.d.ts +4 -1
  141. package/dist/utils/upload-session.js +33 -5
  142. package/dist/utils/version-path.js +1 -1
  143. package/dist/vocabulary.d.ts +8 -8
  144. package/dist/vocabulary.js +31 -20
  145. package/package.json +2 -17
@@ -23,13 +23,13 @@ export interface SpacefastSkillDefinition {
23
23
  export declare const SPACEFAST_SKILLS: readonly [{
24
24
  readonly name: "create-and-publish-site";
25
25
  readonly title: "Create and publish a polished website";
26
- readonly description: "Turn a brief into a responsive static website, review the result, publish it to Spacefast, and verify the live version.";
26
+ readonly description: "Turn a brief into a responsive website, review the result, publish it to Spacefast, and verify the live version.";
27
27
  readonly whenToUse: "Use when the user wants an agent to design, build, improve, or launch a new website rather than only upload an existing build.";
28
28
  readonly keywords: readonly ["create", "website", "design", "build", "responsive", "launch", "publish"];
29
29
  readonly runtimes: readonly ["local", "hosted"];
30
30
  readonly tools: readonly ["publish", "execute"];
31
31
  readonly docs: readonly ["quickstart", "publishing"];
32
- readonly instructions: readonly ["Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.", "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.", "Build a focused, accessible static experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.", "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.", "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.", "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions."];
32
+ readonly instructions: readonly ["Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.", "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.", "Build a focused, accessible experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.", "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.", "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.", "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions."];
33
33
  readonly verification: readonly ["Call `status` after publishing and confirm the intended version is live; use `diagnose` if serving is stalled or failed.", "Open the live URL and verify the primary page, navigation, assets, responsive layout, and main call to action before claiming success."];
34
34
  readonly runtimeNotes: {
35
35
  readonly local: "On-Device can work directly inside the configured local workspace root and publish a local build path.";
@@ -44,13 +44,13 @@ export declare const SPACEFAST_SKILLS: readonly [{
44
44
  }, {
45
45
  readonly name: "publish-and-verify";
46
46
  readonly title: "Publish and verify";
47
- readonly description: "Publish an existing static build, confirm the new version is actually live, and return the useful URLs without leaking credentials.";
47
+ readonly description: "Publish an existing build, confirm the new version is actually live, and return the useful URLs without leaking credentials.";
48
48
  readonly whenToUse: "Use when the artifact already exists and the user wants it published or updated.";
49
49
  readonly keywords: readonly ["publish", "deploy", "live", "verify", "version", "claim"];
50
50
  readonly runtimes: readonly ["local", "hosted"];
51
51
  readonly tools: readonly ["publish", "status", "diagnose"];
52
52
  readonly docs: readonly ["publishing", "workflow/publish-receipt", "workflow/secret-handling"];
53
- readonly instructions: readonly ["Identify the actual publish root or build output. Run the real build first when the source tree is not itself the static artifact.", "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.", "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics."];
53
+ readonly instructions: readonly ["Identify the actual publish root or build output. Run the real build first when the source tree is not itself the artifact to publish.", "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.", "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics."];
54
54
  readonly verification: readonly ["Call `status` and confirm the intended version is live. Use `diagnose` for a failed or stalled publish.", "Open the live URL and verify representative content and assets rather than treating a successful upload or health check as serving proof."];
55
55
  readonly runtimeNotes: {
56
56
  readonly local: "Publish a bounded local path; locally custodied claim credentials are reused automatically.";
@@ -196,13 +196,13 @@ export declare const SPACEFAST_SKILLS: readonly [{
196
196
  export declare const SPACEFAST_PROMPT_SKILLS: ({
197
197
  readonly name: "create-and-publish-site";
198
198
  readonly title: "Create and publish a polished website";
199
- readonly description: "Turn a brief into a responsive static website, review the result, publish it to Spacefast, and verify the live version.";
199
+ readonly description: "Turn a brief into a responsive website, review the result, publish it to Spacefast, and verify the live version.";
200
200
  readonly whenToUse: "Use when the user wants an agent to design, build, improve, or launch a new website rather than only upload an existing build.";
201
201
  readonly keywords: readonly ["create", "website", "design", "build", "responsive", "launch", "publish"];
202
202
  readonly runtimes: readonly ["local", "hosted"];
203
203
  readonly tools: readonly ["publish", "execute"];
204
204
  readonly docs: readonly ["quickstart", "publishing"];
205
- readonly instructions: readonly ["Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.", "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.", "Build a focused, accessible static experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.", "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.", "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.", "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions."];
205
+ readonly instructions: readonly ["Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.", "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.", "Build a focused, accessible experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.", "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.", "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.", "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions."];
206
206
  readonly verification: readonly ["Call `status` after publishing and confirm the intended version is live; use `diagnose` if serving is stalled or failed.", "Open the live URL and verify the primary page, navigation, assets, responsive layout, and main call to action before claiming success."];
207
207
  readonly runtimeNotes: {
208
208
  readonly local: "On-Device can work directly inside the configured local workspace root and publish a local build path.";
@@ -217,13 +217,13 @@ export declare const SPACEFAST_PROMPT_SKILLS: ({
217
217
  } | {
218
218
  readonly name: "publish-and-verify";
219
219
  readonly title: "Publish and verify";
220
- readonly description: "Publish an existing static build, confirm the new version is actually live, and return the useful URLs without leaking credentials.";
220
+ readonly description: "Publish an existing build, confirm the new version is actually live, and return the useful URLs without leaking credentials.";
221
221
  readonly whenToUse: "Use when the artifact already exists and the user wants it published or updated.";
222
222
  readonly keywords: readonly ["publish", "deploy", "live", "verify", "version", "claim"];
223
223
  readonly runtimes: readonly ["local", "hosted"];
224
224
  readonly tools: readonly ["publish", "status", "diagnose"];
225
225
  readonly docs: readonly ["publishing", "workflow/publish-receipt", "workflow/secret-handling"];
226
- readonly instructions: readonly ["Identify the actual publish root or build output. Run the real build first when the source tree is not itself the static artifact.", "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.", "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics."];
226
+ readonly instructions: readonly ["Identify the actual publish root or build output. Run the real build first when the source tree is not itself the artifact to publish.", "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.", "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics."];
227
227
  readonly verification: readonly ["Call `status` and confirm the intended version is live. Use `diagnose` for a failed or stalled publish.", "Open the live URL and verify representative content and assets rather than treating a successful upload or health check as serving proof."];
228
228
  readonly runtimeNotes: {
229
229
  readonly local: "Publish a bounded local path; locally custodied claim credentials are reused automatically.";
@@ -369,13 +369,13 @@ export declare const SPACEFAST_PROMPT_SKILLS: ({
369
369
  export declare const SPACEFAST_RECIPE_SKILLS: (({
370
370
  readonly name: "create-and-publish-site";
371
371
  readonly title: "Create and publish a polished website";
372
- readonly description: "Turn a brief into a responsive static website, review the result, publish it to Spacefast, and verify the live version.";
372
+ readonly description: "Turn a brief into a responsive website, review the result, publish it to Spacefast, and verify the live version.";
373
373
  readonly whenToUse: "Use when the user wants an agent to design, build, improve, or launch a new website rather than only upload an existing build.";
374
374
  readonly keywords: readonly ["create", "website", "design", "build", "responsive", "launch", "publish"];
375
375
  readonly runtimes: readonly ["local", "hosted"];
376
376
  readonly tools: readonly ["publish", "execute"];
377
377
  readonly docs: readonly ["quickstart", "publishing"];
378
- readonly instructions: readonly ["Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.", "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.", "Build a focused, accessible static experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.", "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.", "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.", "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions."];
378
+ readonly instructions: readonly ["Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.", "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.", "Build a focused, accessible experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.", "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.", "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.", "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions."];
379
379
  readonly verification: readonly ["Call `status` after publishing and confirm the intended version is live; use `diagnose` if serving is stalled or failed.", "Open the live URL and verify the primary page, navigation, assets, responsive layout, and main call to action before claiming success."];
380
380
  readonly runtimeNotes: {
381
381
  readonly local: "On-Device can work directly inside the configured local workspace root and publish a local build path.";
@@ -390,13 +390,13 @@ export declare const SPACEFAST_RECIPE_SKILLS: (({
390
390
  } | {
391
391
  readonly name: "publish-and-verify";
392
392
  readonly title: "Publish and verify";
393
- readonly description: "Publish an existing static build, confirm the new version is actually live, and return the useful URLs without leaking credentials.";
393
+ readonly description: "Publish an existing build, confirm the new version is actually live, and return the useful URLs without leaking credentials.";
394
394
  readonly whenToUse: "Use when the artifact already exists and the user wants it published or updated.";
395
395
  readonly keywords: readonly ["publish", "deploy", "live", "verify", "version", "claim"];
396
396
  readonly runtimes: readonly ["local", "hosted"];
397
397
  readonly tools: readonly ["publish", "status", "diagnose"];
398
398
  readonly docs: readonly ["publishing", "workflow/publish-receipt", "workflow/secret-handling"];
399
- readonly instructions: readonly ["Identify the actual publish root or build output. Run the real build first when the source tree is not itself the static artifact.", "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.", "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics."];
399
+ readonly instructions: readonly ["Identify the actual publish root or build output. Run the real build first when the source tree is not itself the artifact to publish.", "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.", "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics."];
400
400
  readonly verification: readonly ["Call `status` and confirm the intended version is live. Use `diagnose` for a failed or stalled publish.", "Open the live URL and verify representative content and assets rather than treating a successful upload or health check as serving proof."];
401
401
  readonly runtimeNotes: {
402
402
  readonly local: "Publish a bounded local path; locally custodied claim credentials are reused automatically.";
@@ -5,7 +5,7 @@ export const SPACEFAST_SKILLS = [
5
5
  {
6
6
  name: "create-and-publish-site",
7
7
  title: "Create and publish a polished website",
8
- description: "Turn a brief into a responsive static website, review the result, publish it to Spacefast, and verify the live version.",
8
+ description: "Turn a brief into a responsive website, review the result, publish it to Spacefast, and verify the live version.",
9
9
  whenToUse: "Use when the user wants an agent to design, build, improve, or launch a new website rather than only upload an existing build.",
10
10
  keywords: ["create", "website", "design", "build", "responsive", "launch", "publish"],
11
11
  runtimes: BOTH_RUNTIMES,
@@ -14,7 +14,7 @@ export const SPACEFAST_SKILLS = [
14
14
  instructions: [
15
15
  "Clarify the audience, goal, required content, brand constraints, and desired call to action. If the visual direction is open, propose two or three distinct directions and choose one with the user.",
16
16
  "Inspect the existing workspace before editing. Reuse its framework, package manager, components, assets, and build conventions when they are sound.",
17
- "Build a focused, accessible static experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.",
17
+ "Build a focused, accessible experience with a clear hierarchy, real content, responsive layouts, useful interaction states, and no placeholder copy. Keep the main path simple and put secondary detail behind progressive disclosure.",
18
18
  "Run the real build and inspect the result at mobile and desktop widths. Fix overflow, illegible contrast, broken links, missing assets, keyboard traps, and avoidable layout shift.",
19
19
  "Review the workspace diff and summarize material design or content judgments before publishing. Never include API keys, claim credentials, upload credentials, or local auth state in the artifact.",
20
20
  "Publish the built output with `publish`. Present Open as the reusable access link and Claim as the one-time ownership link. Treat live and immutable-version URLs as receipt metadata, not extra actions.",
@@ -37,14 +37,14 @@ export const SPACEFAST_SKILLS = [
37
37
  {
38
38
  name: "publish-and-verify",
39
39
  title: "Publish and verify",
40
- description: "Publish an existing static build, confirm the new version is actually live, and return the useful URLs without leaking credentials.",
40
+ description: "Publish an existing build, confirm the new version is actually live, and return the useful URLs without leaking credentials.",
41
41
  whenToUse: "Use when the artifact already exists and the user wants it published or updated.",
42
42
  keywords: ["publish", "deploy", "live", "verify", "version", "claim"],
43
43
  runtimes: BOTH_RUNTIMES,
44
44
  tools: ["publish", "status", "diagnose"],
45
45
  docs: ["publishing", "workflow/publish-receipt", "workflow/secret-handling"],
46
46
  instructions: [
47
- "Identify the actual publish root or build output. Run the real build first when the source tree is not itself the static artifact.",
47
+ "Identify the actual publish root or build output. Run the real build first when the source tree is not itself the artifact to publish.",
48
48
  "Publish with `publish`. For an anonymous On-Device publish, keep the claim credential in local custody and return only the claim URL and expiry; never expose or ask the user to paste the raw token.",
49
49
  "Report the bare Live URL, private Access URL when present, immutable Version URL when present, anonymous Claim URL and expiry when present, plus actionable diagnostics.",
50
50
  ],
@@ -2,6 +2,7 @@ import { errorDocsUrl, errorTitle, PROBLEM_CONTENT_TYPE } from "../contracts/err
2
2
  /** The original fetch implementation captured before a test installs a stub. */
3
3
  export const realFetch = globalThis.fetch;
4
4
  export function stubFetch(handler) {
5
+ // SAFETY: The wrapper accepts fetch's parameter types and always resolves to the handler's Response.
5
6
  globalThis.fetch = (async (input, init) => handler(input instanceof Request && init === undefined ? input : new Request(input, init)));
6
7
  }
7
8
  export function restoreFetch() {
@@ -1,3 +1,4 @@
1
+ import { type SpaceCronConfig } from "../contracts/space-config.js";
1
2
  export type BuildSettingsInput = {
2
3
  fileNames: Iterable<string>;
3
4
  packageJson?: string | null | undefined;
@@ -24,7 +25,7 @@ export type BuildAnalyzerCandidateRankInput = {
24
25
  rootDirectory: string | null;
25
26
  fileNames: Iterable<string>;
26
27
  };
27
- export declare function hasWorkspaceSignal(fileNames: Iterable<string>, packageJsonText?: string | null): unknown;
28
+ export declare function hasWorkspaceSignal(fileNames: Iterable<string>, packageJsonText?: string | null): boolean;
28
29
  export declare function rankBuildAnalyzerCandidate(input: BuildAnalyzerCandidateRankInput): {
29
30
  confidence: number;
30
31
  reasons: string[];
@@ -43,6 +44,7 @@ export type PlatformConfig = {
43
44
  redirects: Array<Record<string, unknown>>;
44
45
  rewrites: Array<Record<string, unknown>>;
45
46
  headers: Array<Record<string, unknown>>;
47
+ crons: Array<Record<string, unknown>>;
46
48
  unsupportedFeatures: string[];
47
49
  };
48
50
  export declare function stringField(value: Record<string, unknown> | null, key: string): string | null;
@@ -51,7 +53,9 @@ export declare function detectPlatformConfigs(input: Omit<BuildSettingsInput, "f
51
53
  export type PlatformRoutingConversion = {
52
54
  redirectLines: string[];
53
55
  headerBlocks: string[];
56
+ crons: SpaceCronConfig[];
54
57
  notes: string[];
55
58
  };
56
59
  export declare function convertPlatformRouting(configs: PlatformConfig[]): PlatformRoutingConversion;
60
+ export declare const BUILD_MARKER_FILE_NAMES: Set<string>;
57
61
  export declare function detectBuildSettings(input: BuildSettingsInput): DetectedBuildSettings;
@@ -1,5 +1,6 @@
1
1
  import { load as parseYaml } from "js-yaml";
2
2
  import { parse as parseToml } from "smol-toml";
3
+ import { SPACE_CONFIG_CAPS, spaceCronKey, spaceCronSchema, } from "../contracts/space-config.js";
3
4
  export const BUILD_ANALYZER_CANDIDATE_ROOTS = ["apps", "packages", "sites", "docs"];
4
5
  const PACKAGE_MANAGER_ONLY_FILES = new Set([
5
6
  "package.json",
@@ -12,12 +13,15 @@ const PACKAGE_MANAGER_ONLY_FILES = new Set([
12
13
  "Gemfile",
13
14
  "Gemfile.lock",
14
15
  ]);
16
+ const WORKSPACE_ROOT_FILES = new Set([
17
+ "pnpm-workspace.yaml",
18
+ "turbo.json",
19
+ "nx.json",
20
+ "lerna.json",
21
+ ]);
15
22
  export function hasWorkspaceSignal(fileNames, packageJsonText) {
16
23
  const names = new Set(fileNames);
17
- if (names.has("pnpm-workspace.yaml") ||
18
- names.has("turbo.json") ||
19
- names.has("nx.json") ||
20
- names.has("lerna.json")) {
24
+ if ([...WORKSPACE_ROOT_FILES].some((file) => names.has(file))) {
21
25
  return true;
22
26
  }
23
27
  if (!packageJsonText) {
@@ -25,10 +29,14 @@ export function hasWorkspaceSignal(fileNames, packageJsonText) {
25
29
  }
26
30
  try {
27
31
  const parsed = JSON.parse(packageJsonText);
28
- return (Array.isArray(parsed.workspaces) ||
29
- (parsed.workspaces &&
30
- typeof parsed.workspaces === "object" &&
31
- Array.isArray(parsed.workspaces.packages)));
32
+ if (Array.isArray(parsed.workspaces)) {
33
+ return true;
34
+ }
35
+ if (!parsed.workspaces || typeof parsed.workspaces !== "object") {
36
+ return false;
37
+ }
38
+ // SAFETY: The preceding non-null object check proves workspaces can carry an optional packages property.
39
+ return Array.isArray(parsed.workspaces.packages);
32
40
  }
33
41
  catch {
34
42
  return false;
@@ -78,6 +86,7 @@ function parseJsonObject(value) {
78
86
  }
79
87
  try {
80
88
  const parsed = JSON.parse(value);
89
+ // SAFETY: The conditional establishes parsed is a non-null, non-array object before returning it as a dictionary.
81
90
  return parsed && typeof parsed === "object" && !Array.isArray(parsed)
82
91
  ? parsed
83
92
  : null;
@@ -98,6 +107,7 @@ function parseTomlObject(value) {
98
107
  }
99
108
  try {
100
109
  const parsed = parseToml(value);
110
+ // SAFETY: The conditional establishes parsed is a non-null, non-array object before returning it as a dictionary.
101
111
  return parsed && typeof parsed === "object" && !Array.isArray(parsed)
102
112
  ? parsed
103
113
  : null;
@@ -112,6 +122,7 @@ function parseYamlObject(value) {
112
122
  }
113
123
  try {
114
124
  const parsed = parseYaml(value);
125
+ // SAFETY: The conditional establishes parsed is a non-null, non-array object before returning it as a dictionary.
115
126
  return parsed && typeof parsed === "object" && !Array.isArray(parsed)
116
127
  ? parsed
117
128
  : null;
@@ -130,6 +141,7 @@ export function numberField(value, key) {
130
141
  }
131
142
  function objectField(value, key) {
132
143
  const field = value?.[key];
144
+ // SAFETY: The conditional establishes field is a non-null, non-array object before returning it as a dictionary.
133
145
  return field && typeof field === "object" && !Array.isArray(field)
134
146
  ? field
135
147
  : null;
@@ -155,11 +167,11 @@ function vercelConfig(value) {
155
167
  redirects: arrayField(config, "redirects"),
156
168
  rewrites: arrayField(config, "rewrites"),
157
169
  headers: arrayField(config, "headers"),
170
+ crons: arrayField(config, "crons"),
158
171
  unsupportedFeatures: [
159
172
  ...("functions" in config ? ["Vercel functions are not converted."] : []),
160
173
  ...("middleware" in config ? ["Vercel middleware is not converted."] : []),
161
174
  ...("images" in config ? ["Vercel image optimization config is not converted."] : []),
162
- ...("crons" in config ? ["Vercel cron jobs are not converted."] : []),
163
175
  ],
164
176
  };
165
177
  }
@@ -179,6 +191,9 @@ function netlifyConfig(value) {
179
191
  redirects: arrayField(config, "redirects"),
180
192
  rewrites: [],
181
193
  headers: arrayField(config, "headers"),
194
+ // Netlify has no scheduled-request config: its scheduled functions are
195
+ // declared in function code, which this importer does not read.
196
+ crons: [],
182
197
  unsupportedFeatures: [
183
198
  ...("functions" in config ? ["Netlify functions are not converted."] : []),
184
199
  ...("edge_functions" in config ? ["Netlify edge functions are not converted."] : []),
@@ -224,6 +239,7 @@ function cloudflarePagesConfig(input) {
224
239
  redirects: [],
225
240
  rewrites: [],
226
241
  headers: [],
242
+ crons: [],
227
243
  unsupportedFeatures,
228
244
  };
229
245
  }
@@ -387,6 +403,7 @@ function convertVercelHeaderRule(rule, out) {
387
403
  const entries = rule.headers;
388
404
  const headers = (Array.isArray(entries) ? entries : [])
389
405
  .map((entry) => {
406
+ // SAFETY: The conditional establishes entry is a non-null object before reading dictionary properties.
390
407
  const header = entry && typeof entry === "object" ? entry : null;
391
408
  const key = stringField(header, "key");
392
409
  const value = header && typeof header.value === "string" ? header.value : null;
@@ -425,8 +442,47 @@ function convertNetlifyHeaderRule(rule, out) {
425
442
  }
426
443
  out.headerBlocks.push(headerBlock(matcher, headers));
427
444
  }
445
+ /**
446
+ * One `vercel.json` cron entry into an `sf.jsonc` `crons` entry.
447
+ *
448
+ * Both sides are `{ path, schedule }` over a literal path and a five-field
449
+ * crontab expression, so a valid Vercel cron converts verbatim — there is no
450
+ * translation to get wrong. What this guards is the tail: Vercel accepts paths
451
+ * and schedules our grammar does not, and it has no per-project cap the way we
452
+ * do. Every rejection names the entry, because a scheduled job that silently
453
+ * stops existing is the one migration failure nobody notices until the work
454
+ * has not run for a week.
455
+ */
456
+ function convertVercelCron(rule, out) {
457
+ const path = stringField(rule, "path");
458
+ const schedule = stringField(rule, "schedule");
459
+ const label = `vercel.json cron ${path ?? "(missing path)"}`;
460
+ if (!path || !schedule) {
461
+ out.notes.push(`${label}: skipped — missing path or schedule.`);
462
+ return;
463
+ }
464
+ const parsed = spaceCronSchema.safeParse({ path, schedule });
465
+ if (!parsed.success) {
466
+ out.notes.push(`${label}: skipped — ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
467
+ return;
468
+ }
469
+ if (out.crons.some((entry) => spaceCronKey(entry.path) === spaceCronKey(path))) {
470
+ out.notes.push(`${label}: skipped — another cron already schedules this path.`);
471
+ return;
472
+ }
473
+ if (out.crons.length >= SPACE_CONFIG_CAPS.crons) {
474
+ out.notes.push(`${label}: skipped — at most ${SPACE_CONFIG_CAPS.crons} crons are supported.`);
475
+ return;
476
+ }
477
+ out.crons.push(parsed.data);
478
+ }
428
479
  export function convertPlatformRouting(configs) {
429
- const out = { redirectLines: [], headerBlocks: [], notes: [] };
480
+ const out = {
481
+ redirectLines: [],
482
+ headerBlocks: [],
483
+ crons: [],
484
+ notes: [],
485
+ };
430
486
  for (const config of configs) {
431
487
  if (config.platform === "vercel") {
432
488
  for (const rule of config.redirects) {
@@ -438,6 +494,9 @@ export function convertPlatformRouting(configs) {
438
494
  for (const rule of config.headers) {
439
495
  convertVercelHeaderRule(rule, out);
440
496
  }
497
+ for (const rule of config.crons) {
498
+ convertVercelCron(rule, out);
499
+ }
441
500
  }
442
501
  if (config.platform === "netlify") {
443
502
  // Netlify expresses rewrites as 200-status redirects; both arrive in
@@ -671,6 +730,19 @@ const FRAMEWORKS = [
671
730
  defaultBuildCommand: "bundle exec middleman build",
672
731
  },
673
732
  ];
733
+ // Every file name the build analyzer keys on: package manifests, lockfiles,
734
+ // workspace roots, and the platform and framework configs it detects a build
735
+ // from. An archive carrying any of them is a project to build, not a website.
736
+ export const BUILD_MARKER_FILE_NAMES = new Set([
737
+ ...PACKAGE_MANAGER_ONLY_FILES,
738
+ ...WORKSPACE_ROOT_FILES,
739
+ "vercel.json",
740
+ "netlify.toml",
741
+ "wrangler.toml",
742
+ "wrangler.json",
743
+ "wrangler.jsonc",
744
+ ...FRAMEWORKS.flatMap((framework) => framework.configFiles ?? []),
745
+ ]);
674
746
  function frameworkForPreset(frameworkPreset) {
675
747
  return FRAMEWORKS.find((framework) => framework.preset === frameworkPreset) ?? null;
676
748
  }
@@ -12,6 +12,7 @@ export function canonicalJson(value) {
12
12
  return `[${value.map(canonicalJson).join(",")}]`;
13
13
  }
14
14
  if (value && typeof value === "object") {
15
+ // SAFETY: This branch establishes value is a non-null object before enumerating its entries.
15
16
  return `{${Object.entries(value)
16
17
  .toSorted(([left], [right]) => left.localeCompare(right))
17
18
  .map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`)
@@ -10,6 +10,7 @@ export async function mapConcurrent(items, limit, mapper) {
10
10
  if (index >= items.length) {
11
11
  return;
12
12
  }
13
+ // SAFETY: the bounds check above proves this index addresses an item in the input array.
13
14
  results[index] = await mapper(items[index], index);
14
15
  await worker();
15
16
  }
@@ -141,7 +141,7 @@ export function policyIsSubsetOfGrantor(requested, grantor) {
141
141
  return statement.actions.every((action) => statement.resources.every((resource) => grantorAllows(grantor, action, resource, statement.conditions)));
142
142
  }) && grantorDeniesArePreserved(requested, grantor));
143
143
  }
144
- // Request-time evaluation (internal-docs/platform.md IAM-lite): explicit deny wins,
144
+ // Request-time evaluation (the platform spec IAM-lite): explicit deny wins,
145
145
  // explicit allow permits, otherwise implicit deny. Condition keys are ANDed and an
146
146
  // unresolvable condition attribute fails closed (see `conditionsMatch`).
147
147
  export function policyAllows(input) {
@@ -152,7 +152,7 @@ export function policyAllows(input) {
152
152
  return resources.some((resource) => matchesEffect(input.policy, "allow", input.action, resource, input.conditions, "request"));
153
153
  }
154
154
  // The tenants a credential's policy grants any access to. Drives tenant
155
- // selection (internal-docs/platform.md Tenant): `X-Spacefast-Tenant-Id` may pick
155
+ // selection (the platform spec Tenant): `X-Spacefast-Tenant-Id` may pick
156
156
  // one granted tenant but is never an authority by itself, and a token spanning
157
157
  // multiple tenants must fail ambiguous requests with `tenant_selection_required`.
158
158
  export function grantedTenantsFromPolicy(policy) {
@@ -259,7 +259,7 @@ function resourceMatches(pattern, resource) {
259
259
  if (pattern.endsWith("/*")) {
260
260
  return resource === pattern.slice(0, -2) || resource.startsWith(pattern.slice(0, -1));
261
261
  }
262
- // A tenant-rooted resource is scope-wide (internal-docs/platform.md L617/L879:
262
+ // A tenant-rooted resource is scope-wide (the platform spec:
263
263
  // `stt://tenant/{t}` is a grantable StatticResource and resource grants cover
264
264
  // their subtree): it covers every resource inside that tenant. This is the
265
265
  // tenant-scoped (partner/agency) credential shape.
@@ -273,6 +273,7 @@ function conditionsMatch(statementConditions, contextConditions, effect, mode) {
273
273
  return true;
274
274
  }
275
275
  return Object.entries(statementConditions).every(([key, value]) => {
276
+ // SAFETY: Object.entries obtains key from the named RequestCondition object immediately above.
276
277
  const resolved = contextConditions?.[key];
277
278
  if (resolved === undefined && mode === "request") {
278
279
  // Fail closed on unresolvable condition attributes: the condition never
@@ -15,15 +15,15 @@ export function addressDnsInstructionsForHostname(input) {
15
15
  normalizeDnsName(instruction.name) !== hostname) {
16
16
  return [];
17
17
  }
18
- return [
19
- {
20
- type: instruction.type,
21
- name: instruction.name,
22
- value: instruction.value,
23
- purpose: instruction.purpose,
24
- ...(instruction.ttl === undefined ? {} : { ttl: instruction.ttl }),
25
- },
26
- ];
18
+ const result = {
19
+ type: instruction.type,
20
+ name: instruction.name,
21
+ value: instruction.value,
22
+ purpose: instruction.purpose,
23
+ };
24
+ if (instruction.ttl !== undefined)
25
+ result.ttl = instruction.ttl;
26
+ return [result];
27
27
  });
28
28
  }
29
29
  function normalizeAddress(value) {
@@ -3,5 +3,6 @@ export function hasErrorCode(error, code) {
3
3
  return (error !== null &&
4
4
  typeof error === "object" &&
5
5
  "code" in error &&
6
+ // SAFETY: The preceding checks prove error is a non-null object with a code property.
6
7
  error.code === code);
7
8
  }
@@ -1438,8 +1438,8 @@
1438
1438
  "principal": {}
1439
1439
  },
1440
1440
  "expected": {
1441
- "capabilities": ["page.view"],
1442
- "matchedGrantIds": ["grt_all_versions"]
1441
+ "capabilities": [],
1442
+ "matchedGrantIds": []
1443
1443
  },
1444
1444
  "phpProjectionCompiles": true
1445
1445
  },
@@ -27,8 +27,10 @@ function targetMatches(selector, target) {
27
27
  return target.kind === "version" && target.versionId === selector.versionId;
28
28
  case "branch":
29
29
  return target.kind === "branch" && target.branch === selector.branch;
30
+ // Immutable Version hosts only. The live host is its own target: sharing
31
+ // "every Version" does not thereby publish the live site.
30
32
  case "all_versions":
31
- return target.kind === "live" || target.kind === "version";
33
+ return target.kind === "version";
32
34
  }
33
35
  throw new Error("Unsupported Grant target.");
34
36
  }
@@ -22,6 +22,12 @@ export declare const localSpaceLinkSchema: z.ZodObject<{
22
22
  apiBaseUrl: z.ZodOptional<z.ZodString>;
23
23
  }, z.core.$loose>;
24
24
  export declare const LOCAL_SPACE_STATE_SCHEMA_VERSION = 1;
25
+ export declare const creationAttemptSchema: z.ZodObject<{
26
+ key: z.ZodString;
27
+ principal: z.ZodString;
28
+ kind: z.ZodLiteral<"authenticated">;
29
+ createdAt: z.ZodString;
30
+ }, z.core.$strict>;
25
31
  export declare const localSpaceStateSchema: z.ZodObject<{
26
32
  schemaVersion: z.ZodLiteral<1>;
27
33
  spaceId: z.ZodOptional<z.ZodString>;
@@ -41,22 +47,14 @@ export declare const localSpaceStateSchema: z.ZodObject<{
41
47
  pendingPublish: z.ZodOptional<z.ZodObject<{
42
48
  key: z.ZodString;
43
49
  principal: z.ZodString;
44
- kind: z.ZodEnum<{
45
- anonymous: "anonymous";
46
- authenticated: "authenticated";
47
- }>;
48
- intent: z.ZodOptional<z.ZodString>;
50
+ kind: z.ZodLiteral<"authenticated">;
49
51
  createdAt: z.ZodString;
50
52
  }, z.core.$strict>>;
51
53
  /** Settled creation receipt identity retained for invocations that began before its commit. */
52
54
  creationReplay: z.ZodOptional<z.ZodObject<{
53
55
  key: z.ZodString;
54
56
  principal: z.ZodString;
55
- kind: z.ZodEnum<{
56
- anonymous: "anonymous";
57
- authenticated: "authenticated";
58
- }>;
59
- intent: z.ZodOptional<z.ZodString>;
57
+ kind: z.ZodLiteral<"authenticated">;
60
58
  createdAt: z.ZodString;
61
59
  }, z.core.$strict>>;
62
60
  /** Random replay capability reserved before consuming a claim credential. */
@@ -147,7 +145,6 @@ export declare function mutateLocalSpaceState(root: string, mutate: (current: Lo
147
145
  /** Fault-injection observer used to synchronize concurrency tests. */
148
146
  onConflict?: (() => void | Promise<void>) | undefined;
149
147
  }): Promise<LocalSpaceStateFile>;
150
- export declare function writeLocalSpaceState(root: string, state: LocalSpaceStateWrite): Promise<string>;
151
148
  /** Reserve random replay custody before a claim token can be consumed. */
152
149
  export declare function reserveLocalCredentialReplay(root: string, input: {
153
150
  operation: LocalCredentialReplayOperation;
@@ -29,6 +29,17 @@ export const localSpaceLinkSchema = z
29
29
  })
30
30
  .loose();
31
31
  export const LOCAL_SPACE_STATE_SCHEMA_VERSION = 1;
32
+ // One reservation, two slots: it is written as `pendingPublish` and moved to
33
+ // `creationReplay` once its receipt commits. Space creation is the only
34
+ // mutation that reserves one — credential-free publishes are not idempotent.
35
+ export const creationAttemptSchema = z
36
+ .object({
37
+ key: z.string().min(1),
38
+ principal: z.string().regex(/^[0-9a-f]{64}$/),
39
+ kind: z.literal("authenticated"),
40
+ createdAt: z.string().datetime(),
41
+ })
42
+ .strict();
32
43
  export const localSpaceStateSchema = z.strictObject({
33
44
  schemaVersion: z.literal(LOCAL_SPACE_STATE_SCHEMA_VERSION),
34
45
  spaceId: z.string().min(1).optional(),
@@ -45,27 +56,9 @@ export const localSpaceStateSchema = z.strictObject({
45
56
  /** Secret per-checkout entropy used only to namespace replay-safe first publishes. */
46
57
  anonymousPublishNonce: z.string().min(32).optional(),
47
58
  /** Unsettled first-publish mutation. Retries must reuse this exact key. */
48
- pendingPublish: z
49
- .object({
50
- key: z.string().min(1),
51
- principal: z.string().regex(/^[0-9a-f]{64}$/),
52
- kind: z.enum(["anonymous", "authenticated"]),
53
- intent: z.string().min(1).optional(),
54
- createdAt: z.string().datetime(),
55
- })
56
- .strict()
57
- .optional(),
59
+ pendingPublish: creationAttemptSchema.optional(),
58
60
  /** Settled creation receipt identity retained for invocations that began before its commit. */
59
- creationReplay: z
60
- .object({
61
- key: z.string().min(1),
62
- principal: z.string().regex(/^[0-9a-f]{64}$/),
63
- kind: z.enum(["anonymous", "authenticated"]),
64
- intent: z.string().min(1).optional(),
65
- createdAt: z.string().datetime(),
66
- })
67
- .strict()
68
- .optional(),
61
+ creationReplay: creationAttemptSchema.optional(),
69
62
  /** Random replay capability reserved before consuming a claim credential. */
70
63
  pendingCredentialReplay: z
71
64
  .object({
@@ -360,10 +353,6 @@ export async function mutateLocalSpaceState(root, mutate, options = {}) {
360
353
  /* eslint-enable no-await-in-loop */
361
354
  throw new LocalSpaceStateConflictError("Local Spacefast state stayed busy for too long.");
362
355
  }
363
- export async function writeLocalSpaceState(root, state) {
364
- await mutateLocalSpaceState(root, () => state);
365
- return localSpaceStatePath(root);
366
- }
367
356
  function credentialFingerprint(credential) {
368
357
  return createHash("sha256").update(credential).digest("hex");
369
358
  }
@@ -11,4 +11,7 @@ export type OneShotReplayIdentity = {
11
11
  */
12
12
  export declare function createOneShotReplayIdentity(prefix: string): OneShotReplayIdentity;
13
13
  /** Production headers for one one-shot attempt (or one device-poll sequence). */
14
- export declare function oneShotReplayHeaders(identity: OneShotReplayIdentity, sequence?: number): Record<"idempotency-key" | "x-spacefast-idempotency-principal", string>;
14
+ export declare function oneShotReplayHeaders(identity: OneShotReplayIdentity, sequence?: number): {
15
+ "idempotency-key": string;
16
+ "x-spacefast-idempotency-principal": string;
17
+ };