@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.
- package/brand-assets/LICENSE-Haskoy.txt +93 -0
- package/brand-assets/haskoy-latin-variable.woff2 +0 -0
- package/brand-assets/spacefast-favicon.svg +4 -4
- package/brand-assets/spacefast-sf-full-bleed.svg +3 -3
- package/brand-assets/spacefast-wordmark.svg +2 -4
- package/dist/agents/connect-targets.js +1 -1
- package/dist/agents/private-key-oauth.d.ts +0 -1
- package/dist/agents/private-key-oauth.js +46 -63
- package/dist/brand-assets-build.js +4 -6
- package/dist/brand-assets.d.ts +5 -15
- package/dist/brand-assets.js +15 -14
- package/dist/config/domains.d.ts +47 -7
- package/dist/config/domains.js +65 -10
- package/dist/contracts/access.d.ts +3 -3
- package/dist/contracts/activity.d.ts +1 -1
- package/dist/contracts/activity.js +5 -3
- package/dist/contracts/api-keys.js +2 -2
- package/dist/contracts/billing.d.ts +2 -1
- package/dist/contracts/billing.js +30 -0
- package/dist/contracts/builds.d.ts +34 -22
- package/dist/contracts/builds.js +18 -6
- package/dist/contracts/channels.js +1 -1
- package/dist/contracts/comments.d.ts +1 -1
- package/dist/contracts/common.d.ts +6 -6
- package/dist/contracts/common.js +5 -5
- package/dist/contracts/crons.d.ts +35 -0
- package/dist/contracts/crons.js +42 -0
- package/dist/contracts/device-auth.js +1 -1
- package/dist/contracts/docs.d.ts +5 -5
- package/dist/contracts/docs.js +2 -2
- package/dist/contracts/domains.d.ts +74 -63
- package/dist/contracts/domains.js +29 -2
- package/dist/contracts/enums.d.ts +3 -2
- package/dist/contracts/enums.js +10 -10
- package/dist/contracts/error-code-meta.d.ts +14 -0
- package/dist/contracts/error-code-meta.js +17 -0
- package/dist/contracts/error-codes.d.ts +1 -1
- package/dist/contracts/error-codes.js +4 -1
- package/dist/contracts/execution.d.ts +15 -12
- package/dist/contracts/execution.js +15 -12
- package/dist/contracts/feature-lifecycle.d.ts +4 -14
- package/dist/contracts/feature-lifecycle.js +0 -11
- package/dist/contracts/features.d.ts +33 -47
- package/dist/contracts/features.js +27 -20
- package/dist/contracts/functions.d.ts +169 -2
- package/dist/contracts/functions.js +160 -4
- package/dist/contracts/git.d.ts +27 -33
- package/dist/contracts/git.js +10 -11
- package/dist/contracts/grants.d.ts +2 -2
- package/dist/contracts/ids.js +2 -2
- package/dist/contracts/internal.d.ts +5 -16
- package/dist/contracts/internal.js +2 -12
- package/dist/contracts/mcp.d.ts +11 -0
- package/dist/contracts/mcp.js +5 -0
- package/dist/contracts/me.js +1 -1
- package/dist/contracts/operations.d.ts +4 -4
- package/dist/contracts/operations.js +2 -2
- package/dist/contracts/pages.d.ts +6 -6
- package/dist/contracts/plan-policy.d.ts +1 -1
- package/dist/contracts/plan-policy.js +1 -1
- package/dist/contracts/platform.d.ts +4 -4
- package/dist/contracts/publish-archive.d.ts +170 -160
- package/dist/contracts/publish-archive.js +8 -1
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.js +2 -2
- package/dist/contracts/repository-connections.d.ts +43 -30
- package/dist/contracts/repository-connections.js +11 -3
- package/dist/contracts/resources.d.ts +8 -8
- package/dist/contracts/resources.js +6 -6
- package/dist/contracts/runtime-api.d.ts +103 -56
- package/dist/contracts/runtime-api.js +67 -26
- package/dist/contracts/runtime-app.d.ts +2 -2
- package/dist/contracts/runtime-db.d.ts +6 -6
- package/dist/contracts/runtime-db.js +2 -2
- package/dist/contracts/runtime-purge.d.ts +8 -0
- package/dist/contracts/runtime-purge.js +7 -0
- package/dist/contracts/runtime-storage.d.ts +3 -2
- package/dist/contracts/runtime-storage.js +2 -1
- package/dist/contracts/sf-config-v1.d.ts +48 -10
- package/dist/contracts/space-config.d.ts +60 -3
- package/dist/contracts/space-config.js +213 -18
- package/dist/contracts/spaces.d.ts +55 -74
- package/dist/contracts/spaces.js +11 -14
- package/dist/contracts/superadmin-spaces.d.ts +9 -9
- package/dist/contracts/superadmin-teams.d.ts +2 -2
- package/dist/contracts/superadmin-tenants.d.ts +0 -6
- package/dist/contracts/superadmin-tenants.js +1 -7
- package/dist/contracts/superadmin.d.ts +135 -22
- package/dist/contracts/superadmin.js +43 -12
- package/dist/contracts/tags.d.ts +21 -21
- package/dist/contracts/tags.js +3 -3
- package/dist/contracts/teams.d.ts +14 -17
- package/dist/contracts/teams.js +6 -6
- package/dist/contracts/transfers.js +2 -2
- package/dist/contracts/variables.d.ts +4 -4
- package/dist/contracts/variables.js +3 -3
- package/dist/contracts/webhooks.d.ts +4 -4
- package/dist/contracts/zero.d.ts +15 -17
- package/dist/contracts/zero.js +12 -12
- package/dist/docs/agent-prose.d.ts +1 -1
- package/dist/docs/agent-prose.js +11 -14
- package/dist/docs/agent-setup.js +5 -2
- package/dist/docs/catalog.d.ts +7 -7
- package/dist/docs/catalog.js +7 -7
- package/dist/docs/error-docs.js +145 -133
- package/dist/docs/skills.d.ts +12 -12
- package/dist/docs/skills.js +4 -4
- package/dist/test-helpers/fetch-stub.js +1 -0
- package/dist/utils/build-settings.d.ts +5 -1
- package/dist/utils/build-settings.js +82 -10
- package/dist/utils/canonical-json.js +1 -0
- package/dist/utils/concurrency.js +1 -0
- package/dist/utils/credential-policy.js +4 -3
- package/dist/utils/dns-instructions.js +9 -9
- package/dist/utils/error-code.js +1 -0
- package/dist/utils/grant-decision.fixtures.json +2 -2
- package/dist/utils/grants.js +3 -1
- package/dist/utils/local-space-state.d.ts +8 -11
- package/dist/utils/local-space-state.js +13 -24
- package/dist/utils/one-shot-replay.d.ts +4 -1
- package/dist/utils/page-colors.d.ts +14 -12
- package/dist/utils/page-colors.js +15 -13
- package/dist/utils/page-fonts.d.ts +1 -1
- package/dist/utils/page-fonts.js +11 -18
- package/dist/utils/pages.d.ts +20 -1
- package/dist/utils/pages.js +22 -9
- package/dist/utils/publish-policy.d.ts +7 -0
- package/dist/utils/publish-policy.fixtures.json +11 -5
- package/dist/utils/publish-policy.js +9 -1
- package/dist/utils/query-keys.d.ts +4 -4
- package/dist/utils/query-keys.js +2 -2
- package/dist/utils/runtime-upload.d.ts +5 -0
- package/dist/utils/runtime-upload.js +7 -0
- package/dist/utils/secure-local-file.js +5 -16
- package/dist/utils/space-config.d.ts +1 -1
- package/dist/utils/space-config.js +3 -0
- package/dist/utils/static-runtime-policy.d.ts +9 -3
- package/dist/utils/static-runtime-policy.fixtures.json +38 -41
- package/dist/utils/static-runtime-policy.js +22 -56
- package/dist/utils/upload-session.d.ts +4 -1
- package/dist/utils/upload-session.js +33 -5
- package/dist/utils/version-path.js +1 -1
- package/dist/vocabulary.d.ts +8 -8
- package/dist/vocabulary.js +31 -20
- package/package.json +2 -17
|
@@ -16,13 +16,13 @@ export const SPACE_CONFIG_ACCEPTED_FILES = [
|
|
|
16
16
|
];
|
|
17
17
|
/**
|
|
18
18
|
* Accepted config filenames in read precedence order, highest first. Kept in
|
|
19
|
-
* step with the finalizer's `
|
|
19
|
+
* step with the finalizer's `CONFIG_ACCEPTED_FILES` (crates/stattic-runtime-core
|
|
20
20
|
* protocol.rs) — the runtime compile is the selection authority, and a local
|
|
21
21
|
* read choosing a different file than the publish serves is a split brain.
|
|
22
22
|
*/
|
|
23
23
|
export const SPACE_CONFIG_PRECEDENCE = SPACE_CONFIG_ACCEPTED_FILES;
|
|
24
24
|
export const SPACE_CONFIG_PRIVATE_FILES = [...SPACE_CONFIG_ACCEPTED_FILES];
|
|
25
|
-
// Config compiler parser-safety caps (
|
|
25
|
+
// Config compiler parser-safety caps (the platform spec "Config
|
|
26
26
|
// compiler scale targets"): hard from launch, enforced by ONE shared validator
|
|
27
27
|
// at every intake seam — finalize for the `sf.jsonc` file, request
|
|
28
28
|
// validation for the API `config` overlay. Plan policy may LOWER these caps,
|
|
@@ -52,6 +52,10 @@ export const SPACE_CONFIG_CAPS = {
|
|
|
52
52
|
themeNameChars: 120,
|
|
53
53
|
/** Max top-level `name` (space display name) length. Matches the stored column. */
|
|
54
54
|
nameChars: 255,
|
|
55
|
+
/** Max `crons` entries. One provider crontab slot each, so the cap is small and hard. */
|
|
56
|
+
crons: 8,
|
|
57
|
+
/** Max `crons[].path` length. */
|
|
58
|
+
cronPathChars: 512,
|
|
55
59
|
};
|
|
56
60
|
/** Published JSON Schema URL for `sf.jsonc` ($schema autocomplete). */
|
|
57
61
|
export const SPACE_CONFIG_SCHEMA_URL = `${serviceOrigin("www", "prod")}/schemas/sf.json`;
|
|
@@ -350,7 +354,7 @@ function refineDefaultDataSource(config, ctx) {
|
|
|
350
354
|
});
|
|
351
355
|
}
|
|
352
356
|
}
|
|
353
|
-
// Shared SpaceConfig fields (
|
|
357
|
+
// Shared SpaceConfig fields (the platform spec "SpaceConfig"): the
|
|
354
358
|
// declarative serving config also accepted by `sf.jsonc`. Cloud-only overlay
|
|
355
359
|
// fields such as pre-build data sources are added to `spaceConfigSchema` below.
|
|
356
360
|
// Meta caps are the spec parser-safety numbers (title 300, description 1000,
|
|
@@ -453,7 +457,7 @@ const spaceConfigBaseSchema = z.object({
|
|
|
453
457
|
.optional()
|
|
454
458
|
.describe("Accepted serving flag; runtime enforcement ships separately."),
|
|
455
459
|
// Intentionally undescribed (hidden, experimental): enables the finalize-time
|
|
456
|
-
// build pipeline (
|
|
460
|
+
// build pipeline (the build-pipeline plan). Accepted without
|
|
457
461
|
// diagnostics; absent/false keeps today's behavior byte-for-byte.
|
|
458
462
|
experimental_gutenberg: z.boolean().optional(),
|
|
459
463
|
// Intentionally minimally described (hidden, experimental): static HTML
|
|
@@ -493,7 +497,7 @@ export function spaceSuperpowersEnabled(config) {
|
|
|
493
497
|
const superpowers = config?.superpowers;
|
|
494
498
|
return superpowers?.enabled !== false && superpowers?.disable_all_injection !== true;
|
|
495
499
|
}
|
|
496
|
-
// The `sf.jsonc` FILE shape (
|
|
500
|
+
// The `sf.jsonc` FILE shape (the platform spec "Space
|
|
497
501
|
// Configuration Files"): SpaceConfig plus the editor `$schema` pointer and the
|
|
498
502
|
// optional `space` link (slug or `spc_` id) resolved by CLI/publish flows.
|
|
499
503
|
// Routing rules (`redirects`/`rewrites`/`headers`) are sf.jsonc keys too, but they belong
|
|
@@ -596,12 +600,17 @@ export const spaceRuntimeFunctionsSchema = z
|
|
|
596
600
|
.string()
|
|
597
601
|
.optional()
|
|
598
602
|
.describe("Path to the worker entry module, relative to the published directory. " +
|
|
599
|
-
"When absent, the server detects it automatically. Naming an entry that does not exist is an error, not a silent
|
|
603
|
+
"When absent, the server detects it automatically. Naming an entry that does not exist is an error, not a silent file-only publish."),
|
|
600
604
|
database: z
|
|
601
605
|
.boolean()
|
|
602
606
|
.default(false)
|
|
603
607
|
.describe("Give the worker `env.DB`, a D1-shaped binding to this space's database. " +
|
|
604
608
|
"This capability is declared, not detected. A capability an author did not request is authority they cannot see. Reading it from minified build output is a guess. Defaults to off, so a worker reaches nothing until it says so."),
|
|
609
|
+
fetch: z
|
|
610
|
+
.boolean()
|
|
611
|
+
.optional()
|
|
612
|
+
.describe("Give the worker `ctx.fetch`, brokered outbound HTTP through the relay. " +
|
|
613
|
+
"Declared, not detected, for the same reason as `database`. No schema default, because the right one depends on what was published: a Next build gets egress unless this says false — SSR fetches while rendering, so denying it breaks the build rather than narrowing it — while a hand-written worker reaches nothing until it says so."),
|
|
605
614
|
compatibilityDate: z
|
|
606
615
|
.string()
|
|
607
616
|
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
@@ -619,7 +628,154 @@ export const spaceRuntimeFunctionsSchema = z
|
|
|
619
628
|
*/
|
|
620
629
|
export const spaceRuntimeSchema = z
|
|
621
630
|
.discriminatedUnion("kind", [spaceRuntimeZeroSchema, spaceRuntimeFunctionsSchema])
|
|
622
|
-
.describe("Runtime this version's code runs on. Omit it
|
|
631
|
+
.describe("Runtime this version's code runs on. Omit it when the space does not run code. Functions is also detected from the published directory when it is not stated.");
|
|
632
|
+
/**
|
|
633
|
+
* Scheduled requests: the provider crontab asks this space for these paths on
|
|
634
|
+
* these schedules.
|
|
635
|
+
*
|
|
636
|
+
* File-only for the same reason `runtime` is: what runs on a schedule is a fact
|
|
637
|
+
* about the content of a version, so it rolls forward and back with the version
|
|
638
|
+
* instead of being set through the API config overlay.
|
|
639
|
+
*
|
|
640
|
+
* The Rust config compiler is the selection authority for both fields; this
|
|
641
|
+
* schema exists so an editor and an agent get the same answer before publish.
|
|
642
|
+
*/
|
|
643
|
+
export const SPACE_CRON_NAMED_SCHEDULES = ["hourly", "daily", "twicedaily", "weekly"];
|
|
644
|
+
/** Field bounds, in crontab order: minute, hour, day of month, month, weekday. */
|
|
645
|
+
const CRON_FIELD_BOUNDS = [
|
|
646
|
+
[0, 59],
|
|
647
|
+
[0, 23],
|
|
648
|
+
[1, 31],
|
|
649
|
+
[1, 12],
|
|
650
|
+
[0, 7],
|
|
651
|
+
];
|
|
652
|
+
/** How many times per hour, day or week the `Nh`/`Nd`/`Nw` shorthand may ask. */
|
|
653
|
+
const CRON_SHORTHAND_LIMITS = new Map([
|
|
654
|
+
["h", 12],
|
|
655
|
+
["d", 23],
|
|
656
|
+
["w", 6],
|
|
657
|
+
]);
|
|
658
|
+
const CRON_STEP_MAX = 0xffff_ffff;
|
|
659
|
+
function cronNumberInBounds(value, min, max) {
|
|
660
|
+
if (!/^\d+$/.test(value))
|
|
661
|
+
return false;
|
|
662
|
+
const parsed = Number(value);
|
|
663
|
+
return parsed >= min && parsed <= max;
|
|
664
|
+
}
|
|
665
|
+
function cronFieldIsValid(field, [min, max]) {
|
|
666
|
+
if (field.length === 0)
|
|
667
|
+
return false;
|
|
668
|
+
return field.split(",").every((item) => {
|
|
669
|
+
const slash = item.indexOf("/");
|
|
670
|
+
const range = slash === -1 ? item : item.slice(0, slash);
|
|
671
|
+
const step = slash === -1 ? undefined : item.slice(slash + 1);
|
|
672
|
+
// A step only makes sense over a span, which is what `*` and `a-b` are;
|
|
673
|
+
// `5/2` names one value and then asks to skip within it.
|
|
674
|
+
let span;
|
|
675
|
+
if (range === "*") {
|
|
676
|
+
span = true;
|
|
677
|
+
}
|
|
678
|
+
else if (range.includes("-")) {
|
|
679
|
+
const [start, end, ...rest] = range.split("-");
|
|
680
|
+
if (rest.length > 0 ||
|
|
681
|
+
start === undefined ||
|
|
682
|
+
end === undefined ||
|
|
683
|
+
!cronNumberInBounds(start, min, max) ||
|
|
684
|
+
!cronNumberInBounds(end, min, max) ||
|
|
685
|
+
Number(start) > Number(end)) {
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
688
|
+
span = true;
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
if (!cronNumberInBounds(range, min, max))
|
|
692
|
+
return false;
|
|
693
|
+
span = false;
|
|
694
|
+
}
|
|
695
|
+
if (step === undefined)
|
|
696
|
+
return true;
|
|
697
|
+
const parsedStep = Number(step);
|
|
698
|
+
return (span &&
|
|
699
|
+
/^\d+$/.test(step) &&
|
|
700
|
+
Number.isInteger(parsedStep) &&
|
|
701
|
+
parsedStep >= 1 &&
|
|
702
|
+
parsedStep <= CRON_STEP_MAX);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* The wp.cloud schedule grammar: a named interval, an `Nh`/`Nd`/`Nw` count, or
|
|
707
|
+
* a five-field crontab expression. No `@daily` macros and no month/day names —
|
|
708
|
+
* the provider does not accept them either.
|
|
709
|
+
*/
|
|
710
|
+
export function isSpaceCronSchedule(schedule) {
|
|
711
|
+
if (SPACE_CRON_NAMED_SCHEDULES.some((named) => named === schedule))
|
|
712
|
+
return true;
|
|
713
|
+
const shorthand = /^(\d+)([hdw])$/.exec(schedule);
|
|
714
|
+
const limit = CRON_SHORTHAND_LIMITS.get(shorthand?.[2] ?? "");
|
|
715
|
+
if (shorthand?.[1] !== undefined && limit !== undefined) {
|
|
716
|
+
const count = Number(shorthand[1]);
|
|
717
|
+
return count >= 1 && count <= limit;
|
|
718
|
+
}
|
|
719
|
+
const fields = schedule.split(" ");
|
|
720
|
+
return (fields.length === CRON_FIELD_BOUNDS.length &&
|
|
721
|
+
fields.every((field, index) => {
|
|
722
|
+
const bounds = CRON_FIELD_BOUNDS[index];
|
|
723
|
+
return bounds !== undefined && cronFieldIsValid(field, bounds);
|
|
724
|
+
}));
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* The artifact key for a cron path: lowercase, leading `/` stripped, every run
|
|
728
|
+
* of non-alphanumerics collapsed to one `-`, trimmed. Two paths that produce
|
|
729
|
+
* one key are rejected, so a key names exactly one schedule.
|
|
730
|
+
*/
|
|
731
|
+
export function spaceCronKey(path) {
|
|
732
|
+
return path
|
|
733
|
+
.replace(/^\/+/, "")
|
|
734
|
+
.toLowerCase()
|
|
735
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
736
|
+
.replace(/^-+|-+$/g, "");
|
|
737
|
+
}
|
|
738
|
+
/** Generated runtime file the serving engine reads, written only when a version declares a cron. */
|
|
739
|
+
export const SPACE_CRONS_ARTIFACT_PATH = "__spacefast/crons.json";
|
|
740
|
+
export const SPACE_CRONS_ARTIFACT_VERSION = 1;
|
|
741
|
+
export const spaceCronSchema = z.object({
|
|
742
|
+
path: z
|
|
743
|
+
.string()
|
|
744
|
+
.max(SPACE_CONFIG_CAPS.cronPathChars)
|
|
745
|
+
.regex(/^\/[^*:?#\s\\]*$/, "must be a literal path starting with / (no * splats, :placeholders, query or fragment)")
|
|
746
|
+
.refine((path) => spaceCronKey(path).length > 0, "must contain at least one letter or digit")
|
|
747
|
+
.describe("Path this space is asked for on the schedule."),
|
|
748
|
+
schedule: z
|
|
749
|
+
.string()
|
|
750
|
+
.refine(isSpaceCronSchedule, "must be hourly, daily, twicedaily, weekly, an Nh/Nd/Nw interval, or a five-field crontab expression")
|
|
751
|
+
.describe("hourly, daily, twicedaily, weekly, an Nh/Nd/Nw interval, or a five-field crontab expression."),
|
|
752
|
+
});
|
|
753
|
+
export const spaceCronsSchema = z
|
|
754
|
+
.array(spaceCronSchema)
|
|
755
|
+
.max(SPACE_CONFIG_CAPS.crons)
|
|
756
|
+
.superRefine((entries, context) => {
|
|
757
|
+
// Identical paths always slug to one key, so keying on the key alone
|
|
758
|
+
// catches both defects: a path written twice, and two paths that slug to
|
|
759
|
+
// one key — which would give two schedules one identity downstream.
|
|
760
|
+
const seenByKey = new Map();
|
|
761
|
+
entries.forEach((entry, index) => {
|
|
762
|
+
const key = spaceCronKey(entry.path);
|
|
763
|
+
const at = seenByKey.get(key);
|
|
764
|
+
if (at !== undefined) {
|
|
765
|
+
// Name the exact duplicate the author wrote: the path when it repeats
|
|
766
|
+
// verbatim, the shared key when two distinct paths collide on it.
|
|
767
|
+
const collided = entries[at];
|
|
768
|
+
context.addIssue({
|
|
769
|
+
code: "custom",
|
|
770
|
+
path: [index, "path"],
|
|
771
|
+
message: `crons entry ${at} already declares ${collided?.path === entry.path ? entry.path : key}.`,
|
|
772
|
+
});
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
seenByKey.set(key, index);
|
|
776
|
+
});
|
|
777
|
+
})
|
|
778
|
+
.describe(`Scheduled requests Spacefast issues against this space's own paths; at most ${SPACE_CONFIG_CAPS.crons} entries.`);
|
|
623
779
|
export const spaceConfigFileSchema = spaceConfigBaseSchema.extend({
|
|
624
780
|
$schema: z
|
|
625
781
|
.string()
|
|
@@ -641,6 +797,7 @@ export const spaceConfigFileSchema = spaceConfigBaseSchema.extend({
|
|
|
641
797
|
.describe("Display name for this space. While set, the API refuses to rename the space."),
|
|
642
798
|
access: spaceConfigFileAccessSchema.optional(),
|
|
643
799
|
runtime: spaceRuntimeSchema.optional(),
|
|
800
|
+
crons: spaceCronsSchema.optional(),
|
|
644
801
|
});
|
|
645
802
|
/**
|
|
646
803
|
* The published JSON Schema artifact for `sf.jsonc`, generated from the
|
|
@@ -666,6 +823,19 @@ export function spaceConfigJsonSchema() {
|
|
|
666
823
|
},
|
|
667
824
|
};
|
|
668
825
|
}
|
|
826
|
+
// The `!` and `name=:capture` of a `_redirects` line, shared by both rule
|
|
827
|
+
// sections — the same shapes `config::strict::public_json_schema` publishes.
|
|
828
|
+
const SPACE_CONFIG_ROUTING_FORCE_SCHEMA = {
|
|
829
|
+
type: "boolean",
|
|
830
|
+
default: false,
|
|
831
|
+
description: "Answer even when the request path resolves to a committed file — the ! of a _redirects rule.",
|
|
832
|
+
};
|
|
833
|
+
const SPACE_CONFIG_ROUTING_QUERY_SCHEMA = {
|
|
834
|
+
type: "object",
|
|
835
|
+
description: 'Query parameters the request must carry, as parameter name to capture name: { "id": "id" } is the name=:capture token id=:id.',
|
|
836
|
+
propertyNames: { pattern: "^[A-Za-z][A-Za-z0-9_-]*$" },
|
|
837
|
+
additionalProperties: { type: "string", pattern: "^[A-Za-z][A-Za-z0-9_]*$" },
|
|
838
|
+
};
|
|
669
839
|
const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
|
|
670
840
|
redirects: {
|
|
671
841
|
type: "array",
|
|
@@ -688,6 +858,8 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
|
|
|
688
858
|
default: 302,
|
|
689
859
|
description: "Redirect status. To serve other content under this URL, use rewrites.",
|
|
690
860
|
},
|
|
861
|
+
force: SPACE_CONFIG_ROUTING_FORCE_SCHEMA,
|
|
862
|
+
query: SPACE_CONFIG_ROUTING_QUERY_SCHEMA,
|
|
691
863
|
},
|
|
692
864
|
required: ["source", "destination"],
|
|
693
865
|
additionalProperties: false,
|
|
@@ -713,6 +885,13 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
|
|
|
713
885
|
const: "shared",
|
|
714
886
|
description: "Let shared caches store the proxy response. Absolute-URL destinations only.",
|
|
715
887
|
},
|
|
888
|
+
force: SPACE_CONFIG_ROUTING_FORCE_SCHEMA,
|
|
889
|
+
query: SPACE_CONFIG_ROUTING_QUERY_SCHEMA,
|
|
890
|
+
notFound: {
|
|
891
|
+
type: "boolean",
|
|
892
|
+
default: false,
|
|
893
|
+
description: "Serve the destination with status 404 — the 404 of a _redirects rule. The destination must be a path.",
|
|
894
|
+
},
|
|
716
895
|
},
|
|
717
896
|
required: ["source", "destination"],
|
|
718
897
|
additionalProperties: false,
|
|
@@ -720,7 +899,7 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
|
|
|
720
899
|
},
|
|
721
900
|
headers: {
|
|
722
901
|
type: "array",
|
|
723
|
-
description: "Response headers to set on matching requests. A _headers rule wins on the same header name.",
|
|
902
|
+
description: "Response headers to set or remove on matching requests. A _headers rule wins on the same header name.",
|
|
724
903
|
items: {
|
|
725
904
|
type: "object",
|
|
726
905
|
properties: {
|
|
@@ -729,13 +908,29 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
|
|
|
729
908
|
type: "array",
|
|
730
909
|
minItems: 1,
|
|
731
910
|
items: {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
911
|
+
oneOf: [
|
|
912
|
+
{
|
|
913
|
+
type: "object",
|
|
914
|
+
properties: {
|
|
915
|
+
key: { type: "string", minLength: 1 },
|
|
916
|
+
value: { type: "string" },
|
|
917
|
+
},
|
|
918
|
+
required: ["key", "value"],
|
|
919
|
+
additionalProperties: false,
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
type: "object",
|
|
923
|
+
properties: {
|
|
924
|
+
key: { type: "string", minLength: 1 },
|
|
925
|
+
remove: {
|
|
926
|
+
const: true,
|
|
927
|
+
description: "Remove this header instead of setting it — the !Name line of a _headers block.",
|
|
928
|
+
},
|
|
929
|
+
},
|
|
930
|
+
required: ["key", "remove"],
|
|
931
|
+
additionalProperties: false,
|
|
932
|
+
},
|
|
933
|
+
],
|
|
739
934
|
},
|
|
740
935
|
},
|
|
741
936
|
},
|
|
@@ -745,7 +940,7 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
|
|
|
745
940
|
},
|
|
746
941
|
};
|
|
747
942
|
/*
|
|
748
|
-
* Hidden-feature discipline (
|
|
943
|
+
* Hidden-feature discipline (the build-pipeline plan): the
|
|
749
944
|
* `experimental_gutenberg` flag and its `inject` companion are ACCEPTED by the
|
|
750
945
|
* parser but never published — the bare key names alone would document the
|
|
751
946
|
* feature to every editor/agent reading a schema artifact. Every generator
|
|
@@ -769,14 +964,14 @@ export function stripHiddenSpaceConfigKeys(schema) {
|
|
|
769
964
|
if (name === "experimental_gutenberg") {
|
|
770
965
|
return false;
|
|
771
966
|
}
|
|
772
|
-
return !(name === "inject" &&
|
|
967
|
+
return !(name === "inject" && isHiddenInjectSchema(value));
|
|
773
968
|
}));
|
|
774
969
|
return [key, stripHiddenSpaceConfigKeys(kept)];
|
|
775
970
|
}
|
|
776
971
|
return [key, stripHiddenSpaceConfigKeys(entry)];
|
|
777
972
|
}));
|
|
778
973
|
}
|
|
779
|
-
function
|
|
974
|
+
function isHiddenInjectSchema(value) {
|
|
780
975
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
781
976
|
return false;
|
|
782
977
|
}
|