@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
@@ -4,6 +4,7 @@ import { functionsRuntimeConfigSchema } from "./functions.js";
4
4
  import { grantSchema } from "./grants.js";
5
5
  import { manifestFileSchema } from "./internal.js";
6
6
  import { runtimePagesSchema } from "./pages.js";
7
+ import { runtimePurgeStatusSchema } from "./runtime-purge.js";
7
8
  import { SPACE_CONFIG_CAPS } from "./space-config.js";
8
9
  import { zeroEndpointSchema, zeroRuntimeConfigSchema } from "./zero.js";
9
10
  const hostCanonicalRedirectSchema = z.object({
@@ -39,11 +40,11 @@ const previousVersionIdSchema = z
39
40
  .optional()
40
41
  .describe("The pointer target this activation replaces (diff baseline).");
41
42
  export const runtimePurgeReceiptSchema = z.object({
42
- status: z.enum(["ok", "failed", "pending"]),
43
+ status: runtimePurgeStatusSchema,
43
44
  mode: z.enum(["urls", "domain"]),
44
45
  urls: z.number().int().nonnegative().optional(),
45
46
  });
46
- const runtimeMutationPurgeShape = {
47
+ const runtimeMutationPurgeFields = {
47
48
  purge: runtimePurgeReceiptSchema.optional(),
48
49
  };
49
50
  export const runtimeSpacePurgeRequestSchema = z.object({
@@ -71,14 +72,22 @@ export const runtimeVersionFilesResponseSchema = z.object({
71
72
  })),
72
73
  next_cursor: z.string().min(1).nullable().optional(),
73
74
  });
75
+ export const runtimeRetentionModeSchema = z.enum(["all", "list", "none"]);
74
76
  export const runtimeVersionCreateRequestSchema = z.object({
75
77
  version_id: z.string().min(1).optional(),
76
78
  files: z.array(manifestFileSchema),
77
- // Retention is expressed as "everything from `reusable_version_id`": naming
78
- // the base and NO list is the retain-all signal, which the runtime
79
- // materializes from that version's own catalog at finalize (under the space
80
- // lock). An explicit list is the narrower form it retains exactly these
81
- // paths and is what a publish that prunes the base uses.
79
+ // Retention is stated, never inferred. `all` carries every path of
80
+ // `reusable_version_id` forward the runtime materializes that list from the
81
+ // base version's own catalog at finalize, under the space lock, which is what
82
+ // keeps the lazy publish path free of a pre-upload round trip. `list` retains
83
+ // exactly `retained_files`, and an EMPTY list is meaningful: it is a publish
84
+ // that drops every path the base held. `none` retains nothing.
85
+ //
86
+ // `all` and `list` both require `reusable_version_id`. Only `list` may carry
87
+ // `retained_files`. Inferring `all` from "base named + empty list" used to
88
+ // silently undo deletes — the runtime has no delete list, so deletion IS
89
+ // omission from the retained set.
90
+ retention: runtimeRetentionModeSchema,
82
91
  retained_files: z.array(manifestFileSchema).optional(),
83
92
  reusable_version_id: z.string().min(1).optional(),
84
93
  manifest_hash: z.string().optional(),
@@ -99,13 +108,27 @@ export const runtimeUploadSessionDescriptorSchema = z.object({
99
108
  manifest_hash: z.string().optional(),
100
109
  files: z.array(manifestFileSchema),
101
110
  // Retained files only travel in the authenticated finalize request: they are
102
- // unbounded and unused while accepting a PUT. Omitting them beside a
103
- // `reusable_version_id` is the retain-all signal (see the create request),
104
- // which is also what keeps a lazy session's descriptor inside its JWT budget.
111
+ // unbounded and unused while accepting a PUT, which is also what keeps a lazy
112
+ // session's descriptor inside its JWT budget. Retention itself is stated on
113
+ // the wire see the create request.
114
+ retention: runtimeRetentionModeSchema,
105
115
  retained_files: z.array(manifestFileSchema).optional(),
106
116
  reusable_version_id: z.string().min(1).optional(),
107
117
  metadata: z.record(z.string(), z.unknown()).default({}),
108
118
  });
119
+ /**
120
+ * The retention half of a create-version body or session descriptor, spelled
121
+ * once. `retained_files` is omitted when empty — with an explicit `retention`
122
+ * that omission is unambiguous: it means retain nothing beyond what `all`
123
+ * materializes.
124
+ */
125
+ export function runtimeRetentionFields(input) {
126
+ return {
127
+ retention: input.retention,
128
+ ...(input.retainedFiles.length > 0 ? { retained_files: [...input.retainedFiles] } : {}),
129
+ ...(input.reusableVersionId ? { reusable_version_id: input.reusableVersionId } : {}),
130
+ };
131
+ }
109
132
  export const RUNTIME_UPLOAD_SESSION_DESCRIPTOR_MAX_BYTES = 4096;
110
133
  // Hard wire budget for the complete `Authorization: Bearer <jwt>\r\n` line sent
111
134
  // on every PUT. Lazy-session selection measures the signed line and falls back
@@ -530,6 +553,31 @@ export const runtimeCompiledRoutingSchema = z.object({
530
553
  .max(1000)
531
554
  .default([]),
532
555
  });
556
+ // What one finalize RUN cost, stage by stage, straight off the native
557
+ // finalizer's envelope — which is why these keys are camelCase while the rest of
558
+ // this receipt is not: PHP passes the object through rather than restating it.
559
+ // Everything else here is read back from the version's immutable metadata;
560
+ // timings cannot be, because they differ on every run. `skippedFiles` is the
561
+ // incrementality gauge: it stays 0 while every finalize rebuilds everything.
562
+ export const runtimeFinalizeTelemetrySchema = z.object({
563
+ stagedFiles: z.number().int().nonnegative(),
564
+ generatedFiles: z.number().int().nonnegative(),
565
+ decoratedFiles: z.number().int().nonnegative(),
566
+ skippedFiles: z.number().int().nonnegative(),
567
+ stagingMs: z.number().int().nonnegative(),
568
+ templateSubstitutionMs: z.number().int().nonnegative(),
569
+ htmlPipelineMs: z.number().int().nonnegative(),
570
+ // The four stages below ship with the finalizer that splits them out; an
571
+ // engine predating the split reports the coarser stages only.
572
+ conventionsMs: z.number().int().nonnegative().optional(),
573
+ zeroCompileMs: z.number().int().nonnegative().optional(),
574
+ blobInstallMs: z.number().int().nonnegative(),
575
+ listingsMs: z.number().int().nonnegative().optional(),
576
+ responseTablesMs: z.number().int().nonnegative(),
577
+ catalogDeltaMs: z.number().int().nonnegative(),
578
+ artifactsWriteMs: z.number().int().nonnegative().optional(),
579
+ totalMs: z.number().int().nonnegative(),
580
+ });
533
581
  export const runtimeVersionFinalizeResponseSchema = z.object({
534
582
  space_id: z.string(),
535
583
  version_id: z.string(),
@@ -556,12 +604,15 @@ export const runtimeVersionFinalizeResponseSchema = z.object({
556
604
  // the catalog at finalize. Null when the version serves no image.
557
605
  preview_image_path: z.string().min(1).nullable().optional(),
558
606
  readiness_target: runtimeReadinessTargetSchema,
607
+ // Absent whenever the runtime answered without finalizing: a replayed or
608
+ // idempotent finalize re-runs no stage and reports no timings.
609
+ telemetry: runtimeFinalizeTelemetrySchema.optional(),
559
610
  activation_event_id: z
560
611
  .string()
561
612
  .min(1)
562
613
  .optional()
563
614
  .describe("Stable route_updated event id when finalize also activated a route."),
564
- ...runtimeMutationPurgeShape,
615
+ ...runtimeMutationPurgeFields,
565
616
  });
566
617
  export const runtimeZeroMigrationsApplyResponseSchema = z.object({
567
618
  space_id: z.string(),
@@ -602,12 +653,12 @@ export const runtimeRouteUpdateResponseSchema = z.object({
602
653
  .min(1)
603
654
  .optional()
604
655
  .describe("Stable route_updated event id for this exact route command, including retries."),
605
- ...runtimeMutationPurgeShape,
656
+ ...runtimeMutationPurgeFields,
606
657
  });
607
658
  export const runtimeHostnameIntentUpdateResponseSchema = z.object({
608
659
  space_id: z.string(),
609
660
  route_count: z.number().int().nonnegative(),
610
- ...runtimeMutationPurgeShape,
661
+ ...runtimeMutationPurgeFields,
611
662
  });
612
663
  export const runtimeTombstonesUpdateRequestSchema = z.object({
613
664
  hostnames: runtimeRouteIntentSchema.shape.production_hostnames,
@@ -620,7 +671,7 @@ export const runtimeTombstonesUpdateRequestSchema = z.object({
620
671
  export const runtimeTombstonesUpdateResponseSchema = z.object({
621
672
  space_id: z.string(),
622
673
  tombstone_count: z.number().int().nonnegative(),
623
- ...runtimeMutationPurgeShape,
674
+ ...runtimeMutationPurgeFields,
624
675
  });
625
676
  // The control plane computes prunable version ids; the engine stores the list
626
677
  // and its housekeeping tick prunes trees after re-checking live route pointers.
@@ -631,23 +682,13 @@ export const runtimeRetentionPolicyUpdateRequestSchema = z.object({
631
682
  export const runtimeRetentionPolicyUpdateResponseSchema = z.object({
632
683
  space_id: z.string(),
633
684
  prunable_count: z.number().int().nonnegative(),
634
- ...runtimeMutationPurgeShape,
635
- });
636
- export const runtimeSpaceDeleteResponseSchema = z.object({
637
- space_id: z.string(),
638
- status: z.literal("deleted"),
639
- ...runtimeMutationPurgeShape,
685
+ ...runtimeMutationPurgeFields,
640
686
  });
641
687
  export const runtimeVersionDeleteResponseSchema = z.object({
642
688
  space_id: z.string(),
643
689
  version_id: z.string(),
644
690
  status: z.literal("deleted"),
645
- ...runtimeMutationPurgeShape,
646
- });
647
- export const runtimeSpaceRepairResponseSchema = z.object({
648
- space_id: z.string(),
649
- status: z.literal("repaired"),
650
- ...runtimeMutationPurgeShape,
691
+ ...runtimeMutationPurgeFields,
651
692
  });
652
693
  // A pin freezes a set of blob SHAs against the collector for as long as it
653
694
  // lives. `snapshot` pins everything a set of versions plus space storage
@@ -23,8 +23,8 @@ export declare const runtimeAppSchema: z.ZodObject<{
23
23
  serverRuntime: z.ZodLiteral<"quickjs-rust">;
24
24
  inspect: z.ZodObject<{
25
25
  policy: z.ZodEnum<{
26
- public: "public";
27
26
  private: "private";
27
+ public: "public";
28
28
  }>;
29
29
  }, z.core.$strict>;
30
30
  install: z.ZodObject<{
@@ -36,7 +36,7 @@ export declare const runtimeAppSchema: z.ZodObject<{
36
36
  binary: z.ZodObject<{
37
37
  path: z.ZodLiteral<"__spacefast/zero/bin/stattic-runtime">;
38
38
  compatibilityTarget: z.ZodObject<{
39
- profile: z.ZodLiteral<"wpcloud-linux-x86_64-gnu-v1">;
39
+ profile: z.ZodLiteral<"linux-x86_64-gnu-v1">;
40
40
  os: z.ZodLiteral<"linux">;
41
41
  cpu: z.ZodLiteral<"x86_64">;
42
42
  libc: z.ZodLiteral<"glibc">;
@@ -17,7 +17,7 @@ import { z } from "zod";
17
17
  export declare const runtimeDbInspectResponseSchema: z.ZodObject<{
18
18
  versionId: z.ZodNullable<z.ZodString>;
19
19
  artifactId: z.ZodNullable<z.ZodString>;
20
- backend: z.ZodNullable<z.ZodLiteral<"wpcloud-mysql">>;
20
+ backend: z.ZodNullable<z.ZodLiteral<"mysql">>;
21
21
  migrationMode: z.ZodNullable<z.ZodEnum<{
22
22
  safe: "safe";
23
23
  drop: "drop";
@@ -97,7 +97,7 @@ export declare const runtimeDbInspectPublicResponseSchema: z.ZodObject<{
97
97
  data: z.ZodObject<{
98
98
  versionId: z.ZodNullable<z.ZodString>;
99
99
  artifactId: z.ZodNullable<z.ZodString>;
100
- backend: z.ZodNullable<z.ZodLiteral<"wpcloud-mysql">>;
100
+ backend: z.ZodNullable<z.ZodLiteral<"mysql">>;
101
101
  migrationMode: z.ZodNullable<z.ZodEnum<{
102
102
  safe: "safe";
103
103
  drop: "drop";
@@ -392,14 +392,14 @@ export declare const runtimeDbMigrateResponseSchema: z.ZodObject<{
392
392
  code: z.ZodString;
393
393
  severity: z.ZodEnum<{
394
394
  info: "info";
395
- warning: "warning";
396
395
  error: "error";
396
+ warning: "warning";
397
397
  }>;
398
398
  message: z.ZodString;
399
399
  path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
400
400
  provider: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
401
401
  registrar: "registrar";
402
- wpcloud: "wpcloud";
402
+ infra: "infra";
403
403
  dns: "dns";
404
404
  runtime: "runtime";
405
405
  }>>>;
@@ -412,13 +412,13 @@ export declare const runtimeDbMigrateResponseSchema: z.ZodObject<{
412
412
  }, z.core.$strip>>;
413
413
  }, z.core.$strip>;
414
414
  export declare const runtimeDbConsoleSchema: z.ZodObject<{
415
- provider: z.ZodLiteral<"wpcloud-phpmyadmin">;
415
+ provider: z.ZodLiteral<"phpmyadmin">;
416
416
  url: z.ZodString;
417
417
  }, z.core.$strict>;
418
418
  export type RuntimeDbConsole = z.infer<typeof runtimeDbConsoleSchema>;
419
419
  export declare const runtimeDbConsoleResponseSchema: z.ZodObject<{
420
420
  data: z.ZodObject<{
421
- provider: z.ZodLiteral<"wpcloud-phpmyadmin">;
421
+ provider: z.ZodLiteral<"phpmyadmin">;
422
422
  url: z.ZodString;
423
423
  }, z.core.$strict>;
424
424
  }, z.core.$strip>;
@@ -21,7 +21,7 @@ export const runtimeDbInspectResponseSchema = z
21
21
  .object({
22
22
  versionId: z.string().min(1).nullable(),
23
23
  artifactId: z.string().min(1).nullable(),
24
- backend: z.literal("wpcloud-mysql").nullable(),
24
+ backend: z.literal("mysql").nullable(),
25
25
  migrationMode: z.enum(["safe", "drop", "rename"]).nullable(),
26
26
  schemaHash: executionSha256Schema.nullable(),
27
27
  tables: z.array(zeroTableSchema).default([]),
@@ -98,7 +98,7 @@ export const runtimeDbMigrateResultSchema = z
98
98
  export const runtimeDbMigrateResponseSchema = mutationEnvelope(runtimeDbMigrateResultSchema);
99
99
  export const runtimeDbConsoleSchema = z
100
100
  .object({
101
- provider: z.literal("wpcloud-phpmyadmin"),
101
+ provider: z.literal("phpmyadmin"),
102
102
  url: z
103
103
  .string()
104
104
  .url()
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ export declare const runtimePurgeStatusSchema: z.ZodEnum<{
3
+ failed: "failed";
4
+ queued: "queued";
5
+ pending: "pending";
6
+ ok: "ok";
7
+ }>;
8
+ export type RuntimePurgeStatus = z.infer<typeof runtimePurgeStatusSchema>;
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ // One vocabulary for every runtime mutation that can invalidate edge state.
3
+ // `queued` is a successful durable handoff: production FPM flushes the
4
+ // management response once the purge journal owns the work, before the edge
5
+ // provider call runs. `pending` is narrower — the synchronous worker kick did
6
+ // not reach the purge entrypoint, so maintenance still owes the attempt.
7
+ export const runtimePurgeStatusSchema = z.enum(["queued", "ok", "failed", "pending"]);
@@ -90,14 +90,14 @@ export declare const runtimeStorageDeletePublicResponseSchema: z.ZodObject<{
90
90
  code: z.ZodString;
91
91
  severity: z.ZodEnum<{
92
92
  info: "info";
93
- warning: "warning";
94
93
  error: "error";
94
+ warning: "warning";
95
95
  }>;
96
96
  message: z.ZodString;
97
97
  path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
98
98
  provider: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
99
99
  registrar: "registrar";
100
- wpcloud: "wpcloud";
100
+ infra: "infra";
101
101
  dns: "dns";
102
102
  runtime: "runtime";
103
103
  }>>>;
@@ -119,6 +119,7 @@ export declare const runtimeStorageReadKeyRotateResponseSchema: z.ZodObject<{
119
119
  purge: z.ZodObject<{
120
120
  status: z.ZodEnum<{
121
121
  failed: "failed";
122
+ queued: "queued";
122
123
  pending: "pending";
123
124
  ok: "ok";
124
125
  }>;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { dataEnvelope, mutationEnvelope } from "./common.js";
3
+ import { runtimePurgeStatusSchema } from "./runtime-purge.js";
3
4
  /** Objects are addressed by a bare 128-bit random id — there is no key and no visibility. */
4
5
  export const runtimeStorageObjectIdSchema = z.string().regex(/^[a-f0-9]{32}$/);
5
6
  /** The runtime-scoped, revocable read key that makes a `/__stattic/u/<id>` URL readable. */
@@ -53,7 +54,7 @@ export const runtimeStorageReadKeyRotateResponseSchema = z
53
54
  // was nothing to purge.
54
55
  purge: z
55
56
  .object({
56
- status: z.enum(["ok", "failed", "pending"]),
57
+ status: runtimePurgeStatusSchema,
57
58
  mode: z.enum(["urls", "domain", "none"]),
58
59
  urls: z.number().int().nonnegative().optional(),
59
60
  })
@@ -4,10 +4,31 @@ export declare const SF_CONFIG_V1_FILES: readonly ["sf.jsonc", "spacefast.jsonc"
4
4
  /** Published JSON Schema URL for the strict `sf.jsonc` v1 contract. */
5
5
  export declare const SF_CONFIG_V1_SCHEMA_URL: `${string}/schemas/sf.v1.json`;
6
6
  /**
7
- * How a redirect answers. Omitting it means 302. There is no 200: a rule that
8
- * serves other content under the requested URL is a `rewrites` entry.
7
+ * How a redirect answers. Omitting it means 302. There is no 200 and no 404:
8
+ * a rule that serves other content under the requested URL is a `rewrites`
9
+ * entry — with `notFound: true` when it should answer 404.
9
10
  */
10
11
  export type SfConfigV1RedirectStatus = 301 | 302 | 303 | 307 | 308;
12
+ /**
13
+ * Query parameters a redirect or rewrite requires, as parameter name to
14
+ * capture name — `{ id: "id" }` is the `id=:id` token of a `_redirects` line,
15
+ * spelled the way the compiled rule (and the runtime matcher) carry it.
16
+ */
17
+ export type SfConfigV1QueryMatch = Record<string, string>;
18
+ /**
19
+ * One header operation: `{ key, value }` sets, `{ key, remove: true }` is the
20
+ * `!Name` line of a `_headers` block. The shape is what tells the two apart,
21
+ * so a remove entry carries no value.
22
+ */
23
+ export type SfConfigV1HeaderEntry = {
24
+ key: string;
25
+ value: string;
26
+ remove?: never;
27
+ } | {
28
+ key: string;
29
+ remove: true;
30
+ value?: never;
31
+ };
11
32
  export type SfConfigV1 = {
12
33
  $schema?: typeof SF_CONFIG_V1_SCHEMA_URL;
13
34
  version: 1;
@@ -32,29 +53,36 @@ export type SfConfigV1 = {
32
53
  source: string;
33
54
  destination: string;
34
55
  status?: SfConfigV1RedirectStatus;
56
+ /** Answer even when the request path resolves to a committed file — the `!` of a `_redirects` rule. */
57
+ force?: boolean;
58
+ query?: SfConfigV1QueryMatch;
35
59
  }[];
36
60
  /**
37
61
  * Rewrite and proxy rules: the URL stays, the content comes from the
38
62
  * destination. A path destination rewrites, an absolute URL proxies — the
39
63
  * same 200 rules `_redirects` writes as `/from /to 200`, which is why they
40
- * carry no status of their own.
64
+ * carry no status of their own. `notFound: true` answers 404 instead — the
65
+ * `/gone /404.html 404` rule, which is a rewrite in every way except the
66
+ * status; its destination must be a path.
41
67
  */
42
68
  rewrites?: {
43
69
  source: string;
44
70
  destination: string;
45
71
  /** Let shared caches store the proxy response. Absolute-URL destinations only. */
46
72
  cache?: "shared";
73
+ /** Rewrite even when the request path resolves to a committed file — the `!` of a `200!` / `404!` file rule. */
74
+ force?: boolean;
75
+ query?: SfConfigV1QueryMatch;
76
+ notFound?: boolean;
47
77
  }[];
48
78
  /**
49
- * Response headers to set on matching requests. Headers are a list, not a
50
- * map, so repeated names (Set-Cookie) survive.
79
+ * Response headers to set — or remove — on matching requests. Headers are a
80
+ * list, not a map, so repeated names (Set-Cookie) survive and operations
81
+ * keep their order.
51
82
  */
52
83
  headers?: {
53
84
  source: string;
54
- headers: {
55
- key: string;
56
- value: string;
57
- }[];
85
+ headers: SfConfigV1HeaderEntry[];
58
86
  }[];
59
87
  metadata?: {
60
88
  title?: string;
@@ -67,6 +95,15 @@ export type SfConfigV1 = {
67
95
  access?: {
68
96
  public: string[];
69
97
  };
98
+ /**
99
+ * Scheduled requests against this space's own paths. Declarations pass
100
+ * through verbatim — the compiled `__spacefast/crons.json` derives each
101
+ * entry's key from its path, and the schedule is never normalized here.
102
+ */
103
+ crons?: {
104
+ path: string;
105
+ schedule: string;
106
+ }[];
70
107
  };
71
108
  export type EffectiveConfigV1 = {
72
109
  version: 1;
@@ -88,6 +125,7 @@ export type EffectiveConfigV1 = {
88
125
  headers?: SfConfigV1["headers"];
89
126
  metadata?: SfConfigV1["metadata"];
90
127
  substitute?: SfConfigV1["substitute"];
128
+ crons?: SfConfigV1["crons"];
91
129
  grants?: Grant[];
92
130
  };
93
131
  /**
@@ -96,7 +134,7 @@ export type EffectiveConfigV1 = {
96
134
  * it is the same grammar and the same compiler.
97
135
  */
98
136
  export type SfConfigV1Issue = {
99
- code: "config_alias" | "config_conflict" | "config_identity_moved" | "config_invalid" | "config_key_removed" | "config_unknown_key" | "header_basic_auth_unsupported" | "header_cache_control_platform_managed" | "header_cdn_cache_unsupported" | "header_name_invalid" | "header_name_unsupported" | "header_path_invalid" | "header_pattern_invalid" | "header_port_unsupported" | "header_value_invalid" | "redirect_cache_directive_invalid" | "redirect_cache_not_proxy" | "redirect_destination_invalid" | "redirect_destination_missing" | "redirect_host_invalid" | "redirect_loop_invalid" | "redirect_pattern_invalid" | "redirect_rewrite_destination_invalid" | "redirect_source_invalid" | "redirect_status_unsupported" | "redirect_status_use_rewrites" | "serve_index_required" | "template_syntax_retired";
137
+ code: "config_alias" | "config_conflict" | "config_cron_duplicate_path" | "config_cron_invalid_path" | "config_cron_invalid_schedule" | "config_cron_too_many" | "config_identity_moved" | "config_invalid" | "config_key_removed" | "config_unknown_key" | "header_basic_auth_unsupported" | "header_cache_control_platform_managed" | "header_cdn_cache_unsupported" | "header_name_invalid" | "header_name_unsupported" | "header_path_invalid" | "header_pattern_invalid" | "header_port_unsupported" | "header_value_invalid" | "redirect_cache_directive_invalid" | "redirect_cache_not_proxy" | "redirect_destination_invalid" | "redirect_destination_missing" | "redirect_host_invalid" | "redirect_loop_invalid" | "redirect_pattern_invalid" | "redirect_query_match_invalid" | "redirect_rewrite_destination_invalid" | "redirect_source_invalid" | "redirect_status_unsupported" | "redirect_status_use_rewrites" | "serve_index_required" | "template_syntax_retired";
100
138
  severity: "error" | "warning";
101
139
  path: string;
102
140
  line: number;
@@ -4,7 +4,7 @@ export declare const SPACE_CONFIG_ALIAS_FILES: readonly ["spacefast.jsonc", "spa
4
4
  export declare const SPACE_CONFIG_ACCEPTED_FILES: readonly ["sf.jsonc", "spacefast.jsonc", "spacefast.json", "sf.json", ".sf/sf.json", ".sf/config.jsonc", ".sf/config.json"];
5
5
  /**
6
6
  * Accepted config filenames in read precedence order, highest first. Kept in
7
- * step with the finalizer's `CONFIG_PRECEDENCE` (crates/stattic-runtime-core
7
+ * step with the finalizer's `CONFIG_ACCEPTED_FILES` (crates/stattic-runtime-core
8
8
  * protocol.rs) — the runtime compile is the selection authority, and a local
9
9
  * read choosing a different file than the publish serves is a split brain.
10
10
  */
@@ -35,6 +35,10 @@ export declare const SPACE_CONFIG_CAPS: {
35
35
  readonly themeNameChars: 120;
36
36
  /** Max top-level `name` (space display name) length. Matches the stored column. */
37
37
  readonly nameChars: 255;
38
+ /** Max `crons` entries. One provider crontab slot each, so the cap is small and hard. */
39
+ readonly crons: 8;
40
+ /** Max `crons[].path` length. */
41
+ readonly cronPathChars: 512;
38
42
  };
39
43
  /** Published JSON Schema URL for `sf.jsonc` ($schema autocomplete). */
40
44
  export declare const SPACE_CONFIG_SCHEMA_URL: string;
@@ -71,7 +75,6 @@ export declare const wordpressDataSourceSchema: z.ZodObject<{
71
75
  kind: z.ZodLiteral<"wordpress">;
72
76
  url: z.ZodString;
73
77
  }, z.core.$strict>;
74
- export type WordPressDataSource = z.infer<typeof wordpressDataSourceSchema>;
75
78
  export declare const spaceDataSourcesSchema: z.ZodPipe<z.ZodUnknown, z.ZodRecord<z.ZodString, z.ZodObject<{
76
79
  kind: z.ZodLiteral<"wordpress">;
77
80
  url: z.ZodString;
@@ -166,7 +169,6 @@ export declare const spaceConfigFileAccessSchema: z.ZodUnion<readonly [z.ZodPipe
166
169
  }, "public">>, z.ZodObject<{
167
170
  public: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
168
171
  }, z.core.$strict>]>;
169
- export type SpaceConfigFileAccess = z.infer<typeof spaceConfigFileAccessSchema>;
170
172
  /**
171
173
  * Zero: a transactional app with its own database.
172
174
  *
@@ -193,6 +195,7 @@ export declare const spaceRuntimeFunctionsSchema: z.ZodObject<{
193
195
  kind: z.ZodLiteral<"functions">;
194
196
  entry: z.ZodOptional<z.ZodString>;
195
197
  database: z.ZodDefault<z.ZodBoolean>;
198
+ fetch: z.ZodOptional<z.ZodBoolean>;
196
199
  compatibilityDate: z.ZodOptional<z.ZodString>;
197
200
  }, z.core.$strip>;
198
201
  /**
@@ -211,11 +214,60 @@ export declare const spaceRuntimeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
211
214
  kind: z.ZodLiteral<"functions">;
212
215
  entry: z.ZodOptional<z.ZodString>;
213
216
  database: z.ZodDefault<z.ZodBoolean>;
217
+ fetch: z.ZodOptional<z.ZodBoolean>;
214
218
  compatibilityDate: z.ZodOptional<z.ZodString>;
215
219
  }, z.core.$strip>], "kind">;
216
220
  export type SpaceRuntimeZeroConfig = z.infer<typeof spaceRuntimeZeroSchema>;
217
221
  export type SpaceRuntimeFunctionsConfig = z.infer<typeof spaceRuntimeFunctionsSchema>;
218
222
  export type SpaceRuntimeConfig = z.infer<typeof spaceRuntimeSchema>;
223
+ /**
224
+ * Scheduled requests: the provider crontab asks this space for these paths on
225
+ * these schedules.
226
+ *
227
+ * File-only for the same reason `runtime` is: what runs on a schedule is a fact
228
+ * about the content of a version, so it rolls forward and back with the version
229
+ * instead of being set through the API config overlay.
230
+ *
231
+ * The Rust config compiler is the selection authority for both fields; this
232
+ * schema exists so an editor and an agent get the same answer before publish.
233
+ */
234
+ export declare const SPACE_CRON_NAMED_SCHEDULES: readonly ["hourly", "daily", "twicedaily", "weekly"];
235
+ /**
236
+ * The wp.cloud schedule grammar: a named interval, an `Nh`/`Nd`/`Nw` count, or
237
+ * a five-field crontab expression. No `@daily` macros and no month/day names —
238
+ * the provider does not accept them either.
239
+ */
240
+ export declare function isSpaceCronSchedule(schedule: string): boolean;
241
+ /**
242
+ * The artifact key for a cron path: lowercase, leading `/` stripped, every run
243
+ * of non-alphanumerics collapsed to one `-`, trimmed. Two paths that produce
244
+ * one key are rejected, so a key names exactly one schedule.
245
+ */
246
+ export declare function spaceCronKey(path: string): string;
247
+ /** Generated runtime file the serving engine reads, written only when a version declares a cron. */
248
+ export declare const SPACE_CRONS_ARTIFACT_PATH = "__spacefast/crons.json";
249
+ export declare const SPACE_CRONS_ARTIFACT_VERSION = 1;
250
+ /** One compiled cron, as the artifact carries it. */
251
+ export type SpaceCronEntry = {
252
+ /** Slug of `path`; unique within a version. */
253
+ key: string;
254
+ path: string;
255
+ /** Verbatim as declared — never normalized or expanded. */
256
+ schedule: string;
257
+ };
258
+ export type SpaceCronsArtifact = {
259
+ version: typeof SPACE_CRONS_ARTIFACT_VERSION;
260
+ crons: SpaceCronEntry[];
261
+ };
262
+ export declare const spaceCronSchema: z.ZodObject<{
263
+ path: z.ZodString;
264
+ schedule: z.ZodString;
265
+ }, z.core.$strip>;
266
+ export declare const spaceCronsSchema: z.ZodArray<z.ZodObject<{
267
+ path: z.ZodString;
268
+ schedule: z.ZodString;
269
+ }, z.core.$strip>>;
270
+ export type SpaceCronConfig = z.infer<typeof spaceCronSchema>;
219
271
  export declare const spaceConfigFileSchema: z.ZodObject<{
220
272
  index: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<false>]>>;
221
273
  fallback: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
@@ -307,8 +359,13 @@ export declare const spaceConfigFileSchema: z.ZodObject<{
307
359
  kind: z.ZodLiteral<"functions">;
308
360
  entry: z.ZodOptional<z.ZodString>;
309
361
  database: z.ZodDefault<z.ZodBoolean>;
362
+ fetch: z.ZodOptional<z.ZodBoolean>;
310
363
  compatibilityDate: z.ZodOptional<z.ZodString>;
311
364
  }, z.core.$strip>], "kind">>;
365
+ crons: z.ZodOptional<z.ZodArray<z.ZodObject<{
366
+ path: z.ZodString;
367
+ schedule: z.ZodString;
368
+ }, z.core.$strip>>>;
312
369
  }, z.core.$strip>;
313
370
  export type SpaceConfigFile = z.infer<typeof spaceConfigFileSchema>;
314
371
  /**