@caelo-cms/provisioning 0.10.48 → 0.10.50
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/caddy/Caddyfile.production +5 -1
- package/caddy/Caddyfile.staging +5 -1
- package/dist/agent-db.js +102 -58
- package/dist/caddy-redirects.d.ts +15 -0
- package/dist/caddy-redirects.d.ts.map +1 -0
- package/dist/caddy-redirects.js +65 -0
- package/dist/caddy-redirects.js.map +1 -0
- package/dist/caddy.d.ts +22 -2
- package/dist/caddy.d.ts.map +1 -1
- package/dist/caddy.js +66 -17
- package/dist/caddy.js.map +1 -1
- package/dist/cli-routing.d.ts.map +1 -1
- package/dist/cli-routing.js +7 -0
- package/dist/cli-routing.js.map +1 -1
- package/dist/cli.js +248 -254
- package/dist/cli.js.map +1 -1
- package/dist/compose.d.ts +54 -2
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +86 -32
- package/dist/compose.js.map +1 -1
- package/dist/gcp-names.d.ts +12 -0
- package/dist/gcp-names.d.ts.map +1 -1
- package/dist/gcp-names.js +21 -0
- package/dist/gcp-names.js.map +1 -1
- package/dist/gcp-url-map.d.ts +27 -0
- package/dist/gcp-url-map.d.ts.map +1 -0
- package/dist/gcp-url-map.js +62 -0
- package/dist/gcp-url-map.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/infra-contract.d.ts +20 -1
- package/dist/infra-contract.d.ts.map +1 -1
- package/dist/infra-contract.js +39 -1
- package/dist/infra-contract.js.map +1 -1
- package/dist/public-role-isolation.d.ts +19 -0
- package/dist/public-role-isolation.d.ts.map +1 -0
- package/dist/public-role-isolation.js +69 -0
- package/dist/public-role-isolation.js.map +1 -0
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +3 -0
- package/dist/release-contract.js.map +1 -1
- package/dist/release-manifest.d.ts +2 -41
- package/dist/release-manifest.d.ts.map +1 -1
- package/dist/release-manifest.js +20 -122
- package/dist/release-manifest.js.map +1 -1
- package/dist/self-hosted-backup.d.ts +86 -0
- package/dist/self-hosted-backup.d.ts.map +1 -0
- package/dist/self-hosted-backup.js +350 -0
- package/dist/self-hosted-backup.js.map +1 -0
- package/dist/self-hosted-release.d.ts +12 -3
- package/dist/self-hosted-release.d.ts.map +1 -1
- package/dist/self-hosted-release.js +6 -4
- package/dist/self-hosted-release.js.map +1 -1
- package/dist/self-hosted-start.d.ts +50 -0
- package/dist/self-hosted-start.d.ts.map +1 -0
- package/dist/self-hosted-start.js +59 -0
- package/dist/self-hosted-start.js.map +1 -0
- package/dist/self-hosted-upgrade.d.ts +30 -0
- package/dist/self-hosted-upgrade.d.ts.map +1 -1
- package/dist/self-hosted-upgrade.js +29 -7
- package/dist/self-hosted-upgrade.js.map +1 -1
- package/dist/tar-entries.d.ts +14 -0
- package/dist/tar-entries.d.ts.map +1 -0
- package/dist/tar-entries.js +104 -0
- package/dist/tar-entries.js.map +1 -0
- package/dist/upgrade/converge.d.ts +2 -2
- package/dist/upgrade/converge.d.ts.map +1 -1
- package/dist/upgrade/converge.js +44 -2
- package/dist/upgrade/converge.js.map +1 -1
- package/dist/upgrade/release-images.d.ts +14 -2
- package/dist/upgrade/release-images.d.ts.map +1 -1
- package/dist/upgrade/release-images.js +4 -2
- package/dist/upgrade/release-images.js.map +1 -1
- package/dist/upgrader-assess.d.ts +4 -1
- package/dist/upgrader-assess.d.ts.map +1 -1
- package/dist/upgrader-assess.js +8 -1
- package/dist/upgrader-assess.js.map +1 -1
- package/dist/upgrader-job.d.ts +3 -1
- package/dist/upgrader-job.d.ts.map +1 -1
- package/dist/upgrader-job.js.map +1 -1
- package/dist/url-map-redirects-access.d.ts +15 -0
- package/dist/url-map-redirects-access.d.ts.map +1 -0
- package/dist/url-map-redirects-access.js +81 -0
- package/dist/url-map-redirects-access.js.map +1 -0
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +3 -1
- package/dist/wizard.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +45 -0
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +2 -2
- package/src/admin-memory.test.ts +2 -2
- package/src/agent/run.test.ts +55 -0
- package/src/caddy-redirects.docker.test.ts +255 -0
- package/src/caddy-redirects.test.ts +115 -0
- package/src/caddy-redirects.ts +68 -0
- package/src/caddy-validate.test.ts +119 -0
- package/src/caddy.test.ts +108 -0
- package/src/caddy.ts +89 -20
- package/src/cli-routing.test.ts +12 -0
- package/src/cli-routing.ts +7 -0
- package/src/cli.ts +299 -287
- package/src/compose.ts +106 -34
- package/src/gcp-names.ts +23 -0
- package/src/gcp-url-map.test.ts +150 -0
- package/src/gcp-url-map.ts +81 -0
- package/src/index.test.ts +18 -146
- package/src/index.ts +0 -9
- package/src/infra-contract.test.ts +39 -0
- package/src/infra-contract.ts +42 -1
- package/src/public-role-isolation.test.ts +89 -0
- package/src/public-role-isolation.ts +83 -0
- package/src/release-contract.ts +3 -0
- package/src/release-manifest.test.ts +20 -1
- package/src/release-manifest.ts +39 -158
- package/src/self-hosted-backup.test.ts +344 -0
- package/src/self-hosted-backup.ts +480 -0
- package/src/self-hosted-compose.test.ts +88 -4
- package/src/self-hosted-release.ts +22 -7
- package/src/self-hosted-start.test.ts +68 -0
- package/src/self-hosted-start.ts +123 -0
- package/src/self-hosted-upgrade.ts +35 -8
- package/src/stack-contract.test.ts +2 -2
- package/src/tar-entries.test.ts +52 -0
- package/src/tar-entries.ts +116 -0
- package/src/upgrade/converge.ts +51 -4
- package/src/upgrade/release-images.ts +4 -2
- package/src/upgrade/upgrade.test.ts +78 -1
- package/src/upgrader-assess.test.ts +64 -1
- package/src/upgrader-assess.ts +20 -2
- package/src/upgrader-job.test.ts +3 -0
- package/src/upgrader-job.ts +3 -0
- package/src/url-map-redirects-access.test.ts +88 -0
- package/src/url-map-redirects-access.ts +89 -0
- package/src/wizard.ts +3 -1
- package/src/wizards/gcp.ts +48 -0
- package/stacks/aws/index.ts +34 -2
- package/stacks/azure/index.ts +13 -0
- package/stacks/gcp/index.ts +24 -17
- package/stacks/gcp-firebase/index.ts +7 -0
- package/stacks/self-hosted/Pulumi.yaml +2 -2
- package/stacks/self-hosted/README.md +3 -3
- package/stacks/self-hosted/index.ts +45 -22
- package/dist/redirects-emit.d.ts +0 -52
- package/dist/redirects-emit.d.ts.map +0 -1
- package/dist/redirects-emit.js +0 -111
- package/dist/redirects-emit.js.map +0 -1
- package/src/redirects-emit.ts +0 -175
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
:80 {
|
|
12
12
|
root * /srv/current
|
|
13
|
+
# #587 — the redirects table of the build served here (the generator
|
|
14
|
+
# writes it; `*` so a fresh checkout without a build still starts).
|
|
15
|
+
# docker-compose.yml reloads Caddy when it changes (caddy-redirects.ts).
|
|
16
|
+
import /srv/current/_redirects.caddy*
|
|
13
17
|
# Content-hashed build outputs (fonts, plugin bundles, media) never
|
|
14
18
|
# change under the same URL — cache them for a year. Keep this pattern in
|
|
15
19
|
# sync with CONTENT_HASHED_PATH_PATTERN in @caelo-cms/shared
|
|
@@ -18,7 +22,7 @@
|
|
|
18
22
|
# `file` gates the header on the file existing: a 404 for a hashed
|
|
19
23
|
# URL (old page after a deploy switch) must not be cached for a year.
|
|
20
24
|
@content_hashed {
|
|
21
|
-
path_regexp content_hashed ^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16
|
|
25
|
+
path_regexp content_hashed ^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16}\.woff2|_assets/fonts/pinned/[0-9a-f]{64}\.[a-z]+(?:-[a-z]+)?\.[0-9a-f]{12}\.woff2|_assets/[a-z0-9][a-z0-9-]*(?:/[a-z][a-z0-9-]*)?\.[0-9a-f]{16}\.[a-z0-9]{2,5}|_caelo/plugin/[^/]+/[^/]+\.[0-9a-f]{12}\.(?:js|css))$
|
|
22
26
|
file
|
|
23
27
|
}
|
|
24
28
|
header @content_hashed Cache-Control "public, max-age=31536000, immutable"
|
package/caddy/Caddyfile.staging
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
:80 {
|
|
16
16
|
root * /srv/current
|
|
17
|
+
# #587 — the redirects table of the build served here (the generator
|
|
18
|
+
# writes it; `*` so a fresh checkout without a build still starts).
|
|
19
|
+
# docker-compose.yml reloads Caddy when it changes (caddy-redirects.ts).
|
|
20
|
+
import /srv/current/_redirects.caddy*
|
|
17
21
|
# Content-hashed build outputs (fonts, plugin bundles, media) never
|
|
18
22
|
# change under the same URL — cache them for a year. Keep this pattern in
|
|
19
23
|
# sync with CONTENT_HASHED_PATH_PATTERN in @caelo-cms/shared
|
|
@@ -22,7 +26,7 @@
|
|
|
22
26
|
# `file` gates the header on the file existing: a 404 for a hashed
|
|
23
27
|
# URL (old page after a deploy switch) must not be cached for a year.
|
|
24
28
|
@content_hashed {
|
|
25
|
-
path_regexp content_hashed ^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16
|
|
29
|
+
path_regexp content_hashed ^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16}\.woff2|_assets/fonts/pinned/[0-9a-f]{64}\.[a-z]+(?:-[a-z]+)?\.[0-9a-f]{12}\.woff2|_assets/[a-z0-9][a-z0-9-]*(?:/[a-z][a-z0-9-]*)?\.[0-9a-f]{16}\.[a-z0-9]{2,5}|_caelo/plugin/[^/]+/[^/]+\.[0-9a-f]{12}\.(?:js|css))$
|
|
26
30
|
file
|
|
27
31
|
}
|
|
28
32
|
header @content_hashed Cache-Control "public, max-age=31536000, immutable"
|
package/dist/agent-db.js
CHANGED
|
@@ -6808,7 +6808,7 @@ var setPageSeoToolInput = object({
|
|
|
6808
6808
|
}).strict();
|
|
6809
6809
|
var autofillPageSeoToolInput = object({
|
|
6810
6810
|
pageId: string2().uuid(),
|
|
6811
|
-
metaDescription: string2().min(1).max(320),
|
|
6811
|
+
metaDescription: string2().trim().min(1).max(320),
|
|
6812
6812
|
ogImageAssetId: string2().uuid().nullable().optional()
|
|
6813
6813
|
}).strict();
|
|
6814
6814
|
var optimizePageSeoToolInput = object({
|
|
@@ -6897,6 +6897,61 @@ var loginFormSchema = object({
|
|
|
6897
6897
|
email: string2().email("must be a valid email").max(254),
|
|
6898
6898
|
password: string2().min(1, "required").max(256)
|
|
6899
6899
|
}).strict();
|
|
6900
|
+
// ../shared/src/platform-updates.ts
|
|
6901
|
+
var PLATFORM_UPDATE_PHASES = [
|
|
6902
|
+
"queued",
|
|
6903
|
+
"start",
|
|
6904
|
+
"verify",
|
|
6905
|
+
"assess",
|
|
6906
|
+
"backup",
|
|
6907
|
+
"health-baseline",
|
|
6908
|
+
"migrations",
|
|
6909
|
+
"roll",
|
|
6910
|
+
"health",
|
|
6911
|
+
"rollback",
|
|
6912
|
+
"record",
|
|
6913
|
+
"self-update",
|
|
6914
|
+
"finish"
|
|
6915
|
+
];
|
|
6916
|
+
var PLATFORM_UPDATE_EVENT_LEVELS = ["info", "success", "warn", "error"];
|
|
6917
|
+
var PLATFORM_UPDATE_TRIGGERS = ["manual", "auto"];
|
|
6918
|
+
var PLATFORM_UPDATE_STALE_MINUTES = 90;
|
|
6919
|
+
var PLATFORM_UPDATE_STALE_REASON = "The upgrader stopped before it finished (its run timed out or crashed). The previous release may still serve, or the new one may be partly rolled out: open the site, and if it misbehaves run the upgrade by hand once \u2014 Settings \u2192 Updates shows how for this install.";
|
|
6920
|
+
var PLATFORM_UPDATE_EVENT_MAX = 4000;
|
|
6921
|
+
var SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;
|
|
6922
|
+
var releaseVersionSchema = string2().regex(SEMVER, "expected a release version like 0.11.0 (no leading v)");
|
|
6923
|
+
var UPDATE_POLICY_MODES = ["off", "notify", "auto"];
|
|
6924
|
+
var UPDATE_POLICY_CHANNELS = ["stable", "rc", "beta", "alpha"];
|
|
6925
|
+
var WALL_CLOCK = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
6926
|
+
function isKnownTimeZone(tz) {
|
|
6927
|
+
try {
|
|
6928
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
6929
|
+
return true;
|
|
6930
|
+
} catch {
|
|
6931
|
+
return false;
|
|
6932
|
+
}
|
|
6933
|
+
}
|
|
6934
|
+
var updatePolicySchema = object({
|
|
6935
|
+
mode: _enum(UPDATE_POLICY_MODES),
|
|
6936
|
+
autoSecurity: boolean2(),
|
|
6937
|
+
autoPatch: boolean2(),
|
|
6938
|
+
autoMinor: boolean2(),
|
|
6939
|
+
channel: _enum(UPDATE_POLICY_CHANNELS),
|
|
6940
|
+
windowStart: string2().regex(WALL_CLOCK, "expected HH:MM").nullable(),
|
|
6941
|
+
windowEnd: string2().regex(WALL_CLOCK, "expected HH:MM").nullable(),
|
|
6942
|
+
windowTimezone: string2().min(1).max(64).refine(isKnownTimeZone, "unknown time zone"),
|
|
6943
|
+
soakHours: number2().int().min(0).max(720),
|
|
6944
|
+
securitySoakHours: number2().int().min(0).max(720)
|
|
6945
|
+
}).strict().refine((p) => p.windowStart === null === (p.windowEnd === null), {
|
|
6946
|
+
message: "set both ends of the maintenance window, or neither"
|
|
6947
|
+
}).refine((p) => p.mode !== "auto" || p.channel === "stable", {
|
|
6948
|
+
message: "automatic installs follow the stable channel only"
|
|
6949
|
+
}).refine((p) => p.securitySoakHours <= p.soakHours, {
|
|
6950
|
+
message: "security fixes cannot wait longer than other releases"
|
|
6951
|
+
});
|
|
6952
|
+
|
|
6953
|
+
// ../shared/src/auto-update.ts
|
|
6954
|
+
var AUTO_UPDATE_BASES = ["security", "patch", "minor"];
|
|
6900
6955
|
// ../shared/src/base-css.ts
|
|
6901
6956
|
var BASE_TECHNICAL_CSS = "*,*::before,*::after{box-sizing:border-box}" + "body{margin:0}" + "img,picture,video,canvas,svg{display:block;max-width:100%}" + "input,button,textarea,select{font:inherit}" + "body{font-family:var(--font-body,system-ui,sans-serif)}";
|
|
6902
6957
|
// ../shared/src/build-page.ts
|
|
@@ -8025,58 +8080,38 @@ var pageLogEntrySchema = object({
|
|
|
8025
8080
|
detail: pageLogDetailSchema.nullable(),
|
|
8026
8081
|
createdAt: string2().datetime()
|
|
8027
8082
|
}).strict();
|
|
8028
|
-
// ../shared/src/platform-updates.ts
|
|
8029
|
-
var PLATFORM_UPDATE_PHASES = [
|
|
8030
|
-
"queued",
|
|
8031
|
-
"start",
|
|
8032
|
-
"verify",
|
|
8033
|
-
"assess",
|
|
8034
|
-
"backup",
|
|
8035
|
-
"health-baseline",
|
|
8036
|
-
"migrations",
|
|
8037
|
-
"roll",
|
|
8038
|
-
"health",
|
|
8039
|
-
"rollback",
|
|
8040
|
-
"record",
|
|
8041
|
-
"self-update",
|
|
8042
|
-
"finish"
|
|
8043
|
-
];
|
|
8044
|
-
var PLATFORM_UPDATE_EVENT_LEVELS = ["info", "success", "warn", "error"];
|
|
8045
|
-
var PLATFORM_UPDATE_TRIGGERS = ["manual", "auto"];
|
|
8046
|
-
var PLATFORM_UPDATE_STALE_MINUTES = 90;
|
|
8047
|
-
var PLATFORM_UPDATE_STALE_REASON = "The upgrader stopped before it finished (its run timed out or crashed). The previous release may still serve, or the new one may be partly rolled out: open the site, and if it misbehaves run the upgrade by hand once \u2014 Settings \u2192 Updates shows how for this install.";
|
|
8048
|
-
var PLATFORM_UPDATE_EVENT_MAX = 4000;
|
|
8049
|
-
var SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;
|
|
8050
|
-
var releaseVersionSchema = string2().regex(SEMVER, "expected a release version like 0.11.0 (no leading v)");
|
|
8051
|
-
var UPDATE_POLICY_MODES = ["off", "notify", "auto"];
|
|
8052
|
-
var UPDATE_POLICY_CHANNELS = ["stable", "rc", "beta", "alpha"];
|
|
8053
|
-
var WALL_CLOCK = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
8054
|
-
function isKnownTimeZone(tz) {
|
|
8055
|
-
try {
|
|
8056
|
-
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
8057
|
-
return true;
|
|
8058
|
-
} catch {
|
|
8059
|
-
return false;
|
|
8060
|
-
}
|
|
8061
|
-
}
|
|
8062
|
-
var updatePolicySchema = object({
|
|
8063
|
-
mode: _enum(UPDATE_POLICY_MODES),
|
|
8064
|
-
autoSecurity: boolean2(),
|
|
8065
|
-
autoPatch: boolean2(),
|
|
8066
|
-
autoMinor: boolean2(),
|
|
8067
|
-
channel: _enum(UPDATE_POLICY_CHANNELS),
|
|
8068
|
-
windowStart: string2().regex(WALL_CLOCK, "expected HH:MM").nullable(),
|
|
8069
|
-
windowEnd: string2().regex(WALL_CLOCK, "expected HH:MM").nullable(),
|
|
8070
|
-
windowTimezone: string2().min(1).max(64).refine(isKnownTimeZone, "unknown time zone"),
|
|
8071
|
-
soakHours: number2().int().min(0).max(720)
|
|
8072
|
-
}).strict().refine((p) => p.windowStart === null === (p.windowEnd === null), {
|
|
8073
|
-
message: "set both ends of the maintenance window, or neither"
|
|
8074
|
-
}).refine((p) => p.mode !== "auto" || p.channel === "stable", {
|
|
8075
|
-
message: "automatic installs follow the stable channel only"
|
|
8076
|
-
});
|
|
8077
8083
|
// ../shared/src/proposal-status.ts
|
|
8078
8084
|
var PROPOSAL_STATUSES = ["pending", "applied", "rejected", "superseded"];
|
|
8079
8085
|
var proposalStatus = _enum(PROPOSAL_STATUSES);
|
|
8086
|
+
// ../shared/src/redirect-emit-cloudfront.ts
|
|
8087
|
+
var CLOUDFRONT_KVS_MAX_TOTAL_BYTES = 5 * 1024 * 1024;
|
|
8088
|
+
// ../shared/src/redirect-plan.ts
|
|
8089
|
+
var REDIRECT_STATUSES = new Set([301, 302, 307, 308]);
|
|
8090
|
+
// ../shared/src/release-manifest.ts
|
|
8091
|
+
var RELEASE_CHANNELS = ["stable", "rc", "beta", "alpha"];
|
|
8092
|
+
var IMAGE_DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
8093
|
+
var SEMVER2 = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;
|
|
8094
|
+
var GHSA_ID = /^GHSA(-[23456789cfghjmpqrvwx]{4}){3}$/;
|
|
8095
|
+
var digest = string2().regex(IMAGE_DIGEST, "expected sha256:<64 hex>");
|
|
8096
|
+
var ReleaseManifestSchema = object({
|
|
8097
|
+
manifestVersion: literal(1),
|
|
8098
|
+
version: string2().regex(SEMVER2, "expected a SemVer version without a leading v"),
|
|
8099
|
+
channel: _enum(RELEASE_CHANNELS),
|
|
8100
|
+
digests: object({ admin: digest, gateway: digest, ops: digest }),
|
|
8101
|
+
minFromVersion: string2().regex(SEMVER2),
|
|
8102
|
+
infraContractVersion: number2().int().positive(),
|
|
8103
|
+
migrations: object({
|
|
8104
|
+
contract: boolean2(),
|
|
8105
|
+
lastContractVersion: string2().regex(SEMVER2).nullable(),
|
|
8106
|
+
head: string2().min(1)
|
|
8107
|
+
}),
|
|
8108
|
+
security: boolean2(),
|
|
8109
|
+
advisories: array(string2().regex(GHSA_ID, "expected a GHSA id"))
|
|
8110
|
+
});
|
|
8111
|
+
var OciManifestSchema = object({
|
|
8112
|
+
artifactType: string2().optional(),
|
|
8113
|
+
layers: array(object({ mediaType: string2(), digest: string2().regex(IMAGE_DIGEST) }))
|
|
8114
|
+
});
|
|
8080
8115
|
// ../shared/src/responsive-images.ts
|
|
8081
8116
|
var LADDER_REPLACEABLE_ORIG_FORMATS = new Set([
|
|
8082
8117
|
"png",
|
|
@@ -8118,7 +8153,7 @@ var seoSetInputSchema = object({
|
|
|
8118
8153
|
}).strict();
|
|
8119
8154
|
var seoAutofillInputSchema = object({
|
|
8120
8155
|
pageId: string2().uuid(),
|
|
8121
|
-
metaDescription: string2().min(1).max(SEO_DESCRIPTION_HARD_MAX),
|
|
8156
|
+
metaDescription: string2().trim().min(1).max(SEO_DESCRIPTION_HARD_MAX),
|
|
8122
8157
|
ogImageAssetId: string2().uuid().nullable().optional()
|
|
8123
8158
|
}).strict();
|
|
8124
8159
|
var seoOptimizeInputSchema = object({
|
|
@@ -8184,7 +8219,7 @@ var revertPageInput = object({
|
|
|
8184
8219
|
var STAGING_SESSION_TTL_SECONDS = 12 * 60 * 60;
|
|
8185
8220
|
var ENCODER = new TextEncoder;
|
|
8186
8221
|
// ../shared/src/static-cache-policy.ts
|
|
8187
|
-
var CONTENT_HASHED_PATH_PATTERN = "^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16
|
|
8222
|
+
var CONTENT_HASHED_PATH_PATTERN = "^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16}\\.woff2|_assets/fonts/pinned/[0-9a-f]{64}\\.[a-z]+(?:-[a-z]+)?\\.[0-9a-f]{12}\\.woff2|_assets/[a-z0-9][a-z0-9-]*(?:/[a-z][a-z0-9-]*)?\\.[0-9a-f]{16}\\.[a-z0-9]{2,5}|_caelo/plugin/[^/]+/[^/]+\\.[0-9a-f]{12}\\.(?:js|css))$";
|
|
8188
8223
|
var CONTENT_HASHED_PATH_RE = new RegExp(CONTENT_HASHED_PATH_PATTERN);
|
|
8189
8224
|
// ../shared/src/structured-sets.ts
|
|
8190
8225
|
var navMenuItem = lazy(() => object({
|
|
@@ -18073,9 +18108,12 @@ var policySchema = object({
|
|
|
18073
18108
|
windowEnd: string2().nullable(),
|
|
18074
18109
|
windowTimezone: string2(),
|
|
18075
18110
|
soakHours: number2(),
|
|
18111
|
+
securitySoakHours: number2(),
|
|
18076
18112
|
paused: boolean2(),
|
|
18077
18113
|
pausedReason: string2().nullable(),
|
|
18078
18114
|
pausedAt: string2().nullable(),
|
|
18115
|
+
pausedUntil: string2().nullable(),
|
|
18116
|
+
pausedByOwner: boolean2(),
|
|
18079
18117
|
updatedAt: string2()
|
|
18080
18118
|
});
|
|
18081
18119
|
var claimOutput = object({
|
|
@@ -18084,6 +18122,7 @@ var claimOutput = object({
|
|
|
18084
18122
|
id: string2(),
|
|
18085
18123
|
targetVersion: string2(),
|
|
18086
18124
|
trigger: _enum(PLATFORM_UPDATE_TRIGGERS),
|
|
18125
|
+
autoBasis: _enum(AUTO_UPDATE_BASES).nullable(),
|
|
18087
18126
|
policy: policySchema
|
|
18088
18127
|
}).nullable()
|
|
18089
18128
|
});
|
|
@@ -18127,7 +18166,7 @@ var jobClaimOp = defineOperation({
|
|
|
18127
18166
|
LIMIT 1
|
|
18128
18167
|
FOR UPDATE SKIP LOCKED
|
|
18129
18168
|
)
|
|
18130
|
-
RETURNING id::text AS id, target_version, trigger
|
|
18169
|
+
RETURNING id::text AS id, target_version, trigger, auto_basis
|
|
18131
18170
|
`);
|
|
18132
18171
|
const row = claimed[0];
|
|
18133
18172
|
if (!row)
|
|
@@ -18136,7 +18175,8 @@ var jobClaimOp = defineOperation({
|
|
|
18136
18175
|
SELECT mode, auto_security, auto_patch, auto_minor, channel,
|
|
18137
18176
|
to_char(window_start, 'HH24:MI') AS window_start,
|
|
18138
18177
|
to_char(window_end, 'HH24:MI') AS window_end,
|
|
18139
|
-
window_timezone, soak_hours, paused, paused_reason,
|
|
18178
|
+
window_timezone, soak_hours, security_soak_hours, paused, paused_reason,
|
|
18179
|
+
paused_at, paused_until, paused_by IS NOT NULL AS paused_by_owner, updated_at
|
|
18140
18180
|
FROM platform_update_policy WHERE id = 1
|
|
18141
18181
|
`);
|
|
18142
18182
|
const p = policies[0];
|
|
@@ -18149,6 +18189,7 @@ var jobClaimOp = defineOperation({
|
|
|
18149
18189
|
id: row.id,
|
|
18150
18190
|
targetVersion: row.target_version,
|
|
18151
18191
|
trigger: row.trigger,
|
|
18192
|
+
autoBasis: row.auto_basis,
|
|
18152
18193
|
policy: {
|
|
18153
18194
|
mode: p.mode,
|
|
18154
18195
|
autoSecurity: p.auto_security,
|
|
@@ -18159,9 +18200,12 @@ var jobClaimOp = defineOperation({
|
|
|
18159
18200
|
windowEnd: p.window_end,
|
|
18160
18201
|
windowTimezone: p.window_timezone,
|
|
18161
18202
|
soakHours: p.soak_hours,
|
|
18203
|
+
securitySoakHours: p.security_soak_hours,
|
|
18162
18204
|
paused: p.paused,
|
|
18163
18205
|
pausedReason: p.paused_reason,
|
|
18164
18206
|
pausedAt: p.paused_at === null ? null : new Date(p.paused_at).toISOString(),
|
|
18207
|
+
pausedUntil: p.paused_until === null ? null : new Date(p.paused_until).toISOString(),
|
|
18208
|
+
pausedByOwner: p.paused_by_owner,
|
|
18165
18209
|
updatedAt: new Date(p.updated_at).toISOString()
|
|
18166
18210
|
}
|
|
18167
18211
|
}
|
|
@@ -18187,7 +18231,7 @@ var jobEventOp = defineOperation({
|
|
|
18187
18231
|
return ok({});
|
|
18188
18232
|
}
|
|
18189
18233
|
});
|
|
18190
|
-
var
|
|
18234
|
+
var digest2 = string2().regex(/^sha256:[0-9a-f]{64}$/);
|
|
18191
18235
|
var jobRecordOp = defineOperation({
|
|
18192
18236
|
name: "platform_updates.job_record",
|
|
18193
18237
|
actorScope: ["system"],
|
|
@@ -18199,9 +18243,9 @@ var jobRecordOp = defineOperation({
|
|
|
18199
18243
|
contractMigrations: boolean2().optional(),
|
|
18200
18244
|
infraContractRequired: number2().int().optional(),
|
|
18201
18245
|
infraContractInstalled: number2().int().optional(),
|
|
18202
|
-
adminDigest:
|
|
18203
|
-
gatewayDigest:
|
|
18204
|
-
opsDigest:
|
|
18246
|
+
adminDigest: digest2.optional(),
|
|
18247
|
+
gatewayDigest: digest2.optional(),
|
|
18248
|
+
opsDigest: digest2.optional(),
|
|
18205
18249
|
backupId: string2().min(1).max(200).optional()
|
|
18206
18250
|
}).strict()
|
|
18207
18251
|
}).strict(),
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The container's shell script: Caddy in the foreground of the container's
|
|
3
|
+
* lifetime, reloaded when any file matching `snippetGlob` changes.
|
|
4
|
+
*
|
|
5
|
+
* @param snippetGlob Shell glob of the imported snippets, e.g.
|
|
6
|
+
* `/srv/caelo/output/*\/current/_redirects.caddy`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function caddyRedirectReloadScript(snippetGlob: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* A Compose `command:` line running {@link caddyRedirectReloadScript}. `$` is
|
|
11
|
+
* doubled because Compose interpolates `$VAR` in the file; the JSON string is
|
|
12
|
+
* a valid YAML double-quoted scalar.
|
|
13
|
+
*/
|
|
14
|
+
export declare function caddyRedirectReloadCommand(snippetGlob: string): string;
|
|
15
|
+
//# sourceMappingURL=caddy-redirects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caddy-redirects.d.ts","sourceRoot":"","sources":["../src/caddy-redirects.ts"],"names":[],"mappings":"AA2BA;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAuBrE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAGtE"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* How the self-hosted Caddy picks up a deploy's redirect snippet (#587).
|
|
4
|
+
*
|
|
5
|
+
* Each public site block imports `<site root>/_redirects.caddy`, which the
|
|
6
|
+
* static generator rewrites on every build. Caddy reads imports only when it
|
|
7
|
+
* loads a config, so something must reload it after a deploy. The container
|
|
8
|
+
* does that itself: its command runs Caddy plus a small loop that watches a
|
|
9
|
+
* checksum of the snippets and runs `caddy reload` (against Caddy's own
|
|
10
|
+
* localhost admin endpoint, inside the container) when they change.
|
|
11
|
+
*
|
|
12
|
+
* Why not the alternatives:
|
|
13
|
+
* - `caddy run --watch` stops watching for good after the first config that
|
|
14
|
+
* fails to load — a snippet read while a deploy is still copying it would
|
|
15
|
+
* freeze the redirects until Caddy restarts.
|
|
16
|
+
* - The admin reloading Caddy through the admin API would need a channel
|
|
17
|
+
* from the admin into Caddy and would post a file's content over HTTP.
|
|
18
|
+
*
|
|
19
|
+
* The loop waits until the checksum is stable across two reads before
|
|
20
|
+
* reloading (a deploy may be mid-copy), and a reload Caddy rejects only
|
|
21
|
+
* logs: Caddy keeps the previous config, and the next change retries.
|
|
22
|
+
*/
|
|
23
|
+
/** Seconds between checksum polls. */
|
|
24
|
+
const POLL_SECONDS = 2;
|
|
25
|
+
/**
|
|
26
|
+
* The container's shell script: Caddy in the foreground of the container's
|
|
27
|
+
* lifetime, reloaded when any file matching `snippetGlob` changes.
|
|
28
|
+
*
|
|
29
|
+
* @param snippetGlob Shell glob of the imported snippets, e.g.
|
|
30
|
+
* `/srv/caelo/output/*\/current/_redirects.caddy`.
|
|
31
|
+
*/
|
|
32
|
+
export function caddyRedirectReloadScript(snippetGlob) {
|
|
33
|
+
if (/[\s'"`$\\;&|<>]/.test(snippetGlob)) {
|
|
34
|
+
throw new Error(`caddy-redirects: unsafe snippet glob ${JSON.stringify(snippetGlob)}`);
|
|
35
|
+
}
|
|
36
|
+
const config = "--config /etc/caddy/Caddyfile --adapter caddyfile";
|
|
37
|
+
return [
|
|
38
|
+
`sum() { cat ${snippetGlob} 2>/dev/null | md5sum; }`,
|
|
39
|
+
"last=$(sum)",
|
|
40
|
+
`caddy run ${config} &`,
|
|
41
|
+
"pid=$!",
|
|
42
|
+
`trap 'kill -TERM "$pid" 2>/dev/null; wait "$pid"; exit $?' TERM INT`,
|
|
43
|
+
`while kill -0 "$pid" 2>/dev/null; do`,
|
|
44
|
+
` sleep ${POLL_SECONDS}`,
|
|
45
|
+
" now=$(sum)",
|
|
46
|
+
` [ "$now" = "$last" ] && continue`,
|
|
47
|
+
// A deploy may still be copying the file: reload only a stable one.
|
|
48
|
+
" sleep 1",
|
|
49
|
+
` [ "$(sum)" = "$now" ] || continue`,
|
|
50
|
+
" last=$now",
|
|
51
|
+
` caddy reload ${config} || echo "caelo: redirects changed but Caddy rejected the reload; still serving the previous redirects" >&2`,
|
|
52
|
+
"done",
|
|
53
|
+
`wait "$pid"`,
|
|
54
|
+
].join("\n");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A Compose `command:` line running {@link caddyRedirectReloadScript}. `$` is
|
|
58
|
+
* doubled because Compose interpolates `$VAR` in the file; the JSON string is
|
|
59
|
+
* a valid YAML double-quoted scalar.
|
|
60
|
+
*/
|
|
61
|
+
export function caddyRedirectReloadCommand(snippetGlob) {
|
|
62
|
+
const script = caddyRedirectReloadScript(snippetGlob).replaceAll("$", () => "$$");
|
|
63
|
+
return `command: ["/bin/sh", "-c", ${JSON.stringify(script)}]`;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=caddy-redirects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caddy-redirects.js","sourceRoot":"","sources":["../src/caddy-redirects.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,sCAAsC;AACtC,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,WAAmB;IAC3D,IAAI,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,MAAM,GAAG,mDAAmD,CAAC;IACnE,OAAO;QACL,eAAe,WAAW,0BAA0B;QACpD,aAAa;QACb,aAAa,MAAM,IAAI;QACvB,QAAQ;QACR,qEAAqE;QACrE,sCAAsC;QACtC,WAAW,YAAY,EAAE;QACzB,cAAc;QACd,oCAAoC;QACpC,oEAAoE;QACpE,WAAW;QACX,qCAAqC;QACrC,aAAa;QACb,kBAAkB,MAAM,6GAA6G;QACrI,MAAM;QACN,aAAa;KACd,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAmB;IAC5D,MAAM,MAAM,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAClF,OAAO,8BAA8B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;AACjE,CAAC"}
|
package/dist/caddy.d.ts
CHANGED
|
@@ -3,13 +3,33 @@ export interface CaddyDomainSpec {
|
|
|
3
3
|
readonly kind: "admin" | "public";
|
|
4
4
|
readonly env: "production" | "staging";
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* How Caddy gets certificates: `acme` — publicly trusted ones from Let's
|
|
8
|
+
* Encrypt / ZeroSSL (needs public DNS + ports 80/443 reachable); `internal`
|
|
9
|
+
* — Caddy's own local CA, for a LAN or evaluation install without public
|
|
10
|
+
* DNS (browsers warn until the CA root is trusted).
|
|
11
|
+
*/
|
|
12
|
+
export type CaddyTlsMode = "acme" | "internal";
|
|
6
13
|
export interface CaddyfileSpec {
|
|
7
14
|
readonly ownerEmail: string;
|
|
15
|
+
readonly tls: CaddyTlsMode;
|
|
8
16
|
readonly publicSiteRoot: string;
|
|
9
17
|
readonly stagingSiteRoot: string;
|
|
10
|
-
|
|
11
|
-
readonly
|
|
18
|
+
/** `host:port` of the admin as Caddy reaches it (Compose: `caelo-admin:5173`). */
|
|
19
|
+
readonly adminUpstream: string;
|
|
20
|
+
/** `host:port` of the API gateway as Caddy reaches it (Compose: `caelo-gateway:8090`). */
|
|
21
|
+
readonly gatewayUpstream: string;
|
|
12
22
|
readonly domains: ReadonlyArray<CaddyDomainSpec>;
|
|
13
23
|
}
|
|
24
|
+
/** The host the admin of a self-hosted install answers on (same convention as GCP). */
|
|
25
|
+
export declare function selfHostedAdminHost(domain: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* The vhosts every self-hosted install serves before an Owner adds domains
|
|
28
|
+
* in the admin: the admin on `admin.<domain>`, the live site on `<domain>`,
|
|
29
|
+
* the staging site on its own host. The admin needs its own host — it
|
|
30
|
+
* routes from `/` (`/setup`, `/login`, …), so it cannot share one with the
|
|
31
|
+
* public site, and Caddy refuses two site blocks for the same address.
|
|
32
|
+
*/
|
|
33
|
+
export declare function selfHostedSeedDomains(domain: string, stagingDomain: string): CaddyDomainSpec[];
|
|
14
34
|
export declare function generateCaddyfile(spec: CaddyfileSpec): string;
|
|
15
35
|
//# sourceMappingURL=caddy.d.ts.map
|
package/dist/caddy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"caddy.d.ts","sourceRoot":"","sources":["../src/caddy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"caddy.d.ts","sourceRoot":"","sources":["../src/caddy.ts"],"names":[],"mappings":"AA2DA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,kFAAkF;IAClF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CAClD;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,eAAe,EAAE,CAM9F;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAqC7D"}
|
package/dist/caddy.js
CHANGED
|
@@ -4,18 +4,32 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Reads the `domains` table + the deploy targets and emits a
|
|
6
6
|
* deterministic Caddyfile string. The CLI's `regenerate-caddy`
|
|
7
|
-
* sub-command writes this to
|
|
7
|
+
* sub-command writes this to `.caelo/Caddyfile` and runs
|
|
8
8
|
* `caddy reload`.
|
|
9
9
|
*
|
|
10
10
|
* Per-vhost shape:
|
|
11
11
|
* <hostname> {
|
|
12
|
-
* # admin → reverse_proxy
|
|
13
|
-
* # public →
|
|
14
|
-
*
|
|
12
|
+
* # admin → reverse_proxy <adminUpstream>
|
|
13
|
+
* # public → /api/* → <gatewayUpstream>; everything else is the
|
|
14
|
+
* # static site (try_files + file_server, 404 → /404.html)
|
|
15
15
|
* }
|
|
16
16
|
*
|
|
17
|
+
* Upstreams are `host:port` as seen FROM CADDY. In the Compose install
|
|
18
|
+
* Caddy runs in its own container, where `localhost` is Caddy itself, so
|
|
19
|
+
* the CLI passes the Compose service names (`caelo-admin:5173`,
|
|
20
|
+
* `caelo-gateway:8090`) — issue #707.
|
|
21
|
+
*
|
|
22
|
+
* Every directive here must be one Caddy accepts: the output is checked
|
|
23
|
+
* with `caddy validate` on the pinned Caddy image (caddy-validate.test.ts,
|
|
24
|
+
* run in CI) — issue #566 shipped a `try_files` nested inside
|
|
25
|
+
* `file_server { }`, which Caddy 2.11 refuses, so no vhost came up.
|
|
26
|
+
*
|
|
17
27
|
* Staging vhosts force `X-Robots-Tag: noindex`.
|
|
18
28
|
*
|
|
29
|
+
* Public vhosts import the redirect snippet of the build they serve
|
|
30
|
+
* (`_redirects.caddy`, #587); the Caddy container reloads itself when a
|
|
31
|
+
* deploy changes it (caddy-redirects.ts).
|
|
32
|
+
*
|
|
19
33
|
* Public vhosts mark content-hashed build outputs (fonts, plugin
|
|
20
34
|
* bundles — `CONTENT_HASHED_PATH_PATTERN` in @caelo-cms/shared)
|
|
21
35
|
* `immutable` for a year. Everything else keeps Caddy's file_server
|
|
@@ -25,17 +39,49 @@
|
|
|
25
39
|
* hashed URL (an old page requesting an asset the new build dropped)
|
|
26
40
|
* is never cached for a year.
|
|
27
41
|
*
|
|
42
|
+
* A path that matches no file is a real 404 serving the generator's
|
|
43
|
+
* `/404.html` — never the home page with a 200 (an SPA-style
|
|
44
|
+
* `/index.html` fallback would turn every dead URL into a soft 404).
|
|
45
|
+
* Same behaviour as the GCS / S3 / Blob adapters (CLAUDE.md §11.B).
|
|
46
|
+
*
|
|
28
47
|
* `.ico` files (theme favicons) are served as `image/x-icon`, the one
|
|
29
48
|
* icon MIME the media library stores and `<link rel="icon" type>`
|
|
30
49
|
* declares. file_server only fills Content-Type when no earlier handler
|
|
31
50
|
* set it, so the `header` line wins over the host's mime.types name.
|
|
32
51
|
*/
|
|
33
|
-
import { CONTENT_HASHED_PATH_PATTERN, IMMUTABLE_CACHE_CONTROL } from "@caelo-cms/shared";
|
|
52
|
+
import { CONTENT_HASHED_PATH_PATTERN, caddyRedirectsImport, IMMUTABLE_CACHE_CONTROL, } from "@caelo-cms/shared";
|
|
53
|
+
/** The host the admin of a self-hosted install answers on (same convention as GCP). */
|
|
54
|
+
export function selfHostedAdminHost(domain) {
|
|
55
|
+
return `admin.${domain}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The vhosts every self-hosted install serves before an Owner adds domains
|
|
59
|
+
* in the admin: the admin on `admin.<domain>`, the live site on `<domain>`,
|
|
60
|
+
* the staging site on its own host. The admin needs its own host — it
|
|
61
|
+
* routes from `/` (`/setup`, `/login`, …), so it cannot share one with the
|
|
62
|
+
* public site, and Caddy refuses two site blocks for the same address.
|
|
63
|
+
*/
|
|
64
|
+
export function selfHostedSeedDomains(domain, stagingDomain) {
|
|
65
|
+
return [
|
|
66
|
+
{ hostname: selfHostedAdminHost(domain), kind: "admin", env: "production" },
|
|
67
|
+
{ hostname: domain, kind: "public", env: "production" },
|
|
68
|
+
{ hostname: stagingDomain, kind: "public", env: "staging" },
|
|
69
|
+
];
|
|
70
|
+
}
|
|
34
71
|
export function generateCaddyfile(spec) {
|
|
72
|
+
const hostnames = new Set();
|
|
73
|
+
for (const d of spec.domains) {
|
|
74
|
+
if (hostnames.has(d.hostname)) {
|
|
75
|
+
// Caddy refuses a config with two site blocks for one address, so a
|
|
76
|
+
// duplicate would take every vhost down, not just this one.
|
|
77
|
+
throw new Error(`Caddyfile: ${d.hostname} is listed twice — one host serves either the admin or a public site, not both.`);
|
|
78
|
+
}
|
|
79
|
+
hostnames.add(d.hostname);
|
|
80
|
+
}
|
|
35
81
|
const blocks = [];
|
|
36
82
|
// Global options.
|
|
37
83
|
blocks.push(`{
|
|
38
|
-
email ${spec.ownerEmail}
|
|
84
|
+
email ${spec.ownerEmail}${spec.tls === "internal" ? "\n local_certs" : ""}
|
|
39
85
|
}
|
|
40
86
|
`);
|
|
41
87
|
for (const d of spec.domains) {
|
|
@@ -47,7 +93,7 @@ export function generateCaddyfile(spec) {
|
|
|
47
93
|
blocks.push(`# No domains configured yet — cms-provision regenerate-caddy
|
|
48
94
|
# will overwrite this file when you add one at /settings/domains.
|
|
49
95
|
:8081 {
|
|
50
|
-
reverse_proxy
|
|
96
|
+
reverse_proxy ${spec.adminUpstream}
|
|
51
97
|
}
|
|
52
98
|
`);
|
|
53
99
|
}
|
|
@@ -57,15 +103,18 @@ function vhost(d, spec) {
|
|
|
57
103
|
const noindex = d.env === "staging" ? `\n header X-Robots-Tag "noindex"` : "";
|
|
58
104
|
if (d.kind === "admin") {
|
|
59
105
|
return `${d.hostname} {${noindex}
|
|
60
|
-
reverse_proxy
|
|
106
|
+
reverse_proxy ${spec.adminUpstream}
|
|
61
107
|
}
|
|
62
108
|
`;
|
|
63
109
|
}
|
|
64
|
-
// public — API routes go to the gateway,
|
|
65
|
-
//
|
|
110
|
+
// public — API routes go to the gateway, the rest is the static site.
|
|
111
|
+
// `try_files` is its own directive (a rewrite), never a file_server
|
|
112
|
+
// subdirective (#566).
|
|
66
113
|
const root = d.env === "staging" ? spec.stagingSiteRoot : spec.publicSiteRoot;
|
|
114
|
+
// #587 — the redirects table of the build this vhost serves.
|
|
67
115
|
return `${d.hostname} {${noindex}
|
|
68
116
|
root * ${root}
|
|
117
|
+
${caddyRedirectsImport(root)}
|
|
69
118
|
@content_hashed {
|
|
70
119
|
path_regexp content_hashed ${CONTENT_HASHED_PATH_PATTERN}
|
|
71
120
|
file
|
|
@@ -74,15 +123,15 @@ function vhost(d, spec) {
|
|
|
74
123
|
@ico path *.ico
|
|
75
124
|
header @ico Content-Type "image/x-icon"
|
|
76
125
|
handle /api/* {
|
|
77
|
-
reverse_proxy
|
|
78
|
-
}
|
|
79
|
-
handle /admin/* {
|
|
80
|
-
reverse_proxy localhost:${spec.adminPort}
|
|
126
|
+
reverse_proxy ${spec.gatewayUpstream}
|
|
81
127
|
}
|
|
82
128
|
handle {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
129
|
+
try_files {path} {path}/index.html
|
|
130
|
+
file_server
|
|
131
|
+
}
|
|
132
|
+
handle_errors 404 {
|
|
133
|
+
rewrite * /404.html
|
|
134
|
+
file_server
|
|
86
135
|
}
|
|
87
136
|
}
|
|
88
137
|
`;
|
package/dist/caddy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"caddy.js","sourceRoot":"","sources":["../src/caddy.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC
|
|
1
|
+
{"version":3,"file":"caddy.js","sourceRoot":"","sources":["../src/caddy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-routing.d.ts","sourceRoot":"","sources":["../src/cli-routing.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,+CAA+C;AAC/C,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAElG;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"cli-routing.d.ts","sourceRoot":"","sources":["../src/cli-routing.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,+CAA+C;AAC/C,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAElG;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAkBjG;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE/D"}
|
package/dist/cli-routing.js
CHANGED
|
@@ -17,6 +17,13 @@ export function resolveCliRoute(argv, handlerNames) {
|
|
|
17
17
|
if (argv.includes("--no-wizard") || argv.includes("--help") || argv.includes("-h")) {
|
|
18
18
|
return { kind: "usage" };
|
|
19
19
|
}
|
|
20
|
+
// #707 — `--provider self-hosted --domain … --owner-email …` is the
|
|
21
|
+
// self-hosted one-command install: `init` writes `.caelo/` and starts the
|
|
22
|
+
// stack. (The cloud wizard has nothing to provision for it.)
|
|
23
|
+
const provider = argv.indexOf("--provider");
|
|
24
|
+
if (provider !== -1 && argv[provider + 1] === "self-hosted") {
|
|
25
|
+
return { kind: "handler", name: "init" };
|
|
26
|
+
}
|
|
20
27
|
return { kind: "wizard" };
|
|
21
28
|
}
|
|
22
29
|
/**
|
package/dist/cli-routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-routing.js","sourceRoot":"","sources":["../src/cli-routing.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAenC;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAuB,EAAE,YAA8B;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACzC,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO,QAAQ,KAAK,aAAa,CAAC;AACpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli-routing.js","sourceRoot":"","sources":["../src/cli-routing.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAenC;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAuB,EAAE,YAA8B;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACzC,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC3B,CAAC;IACD,oEAAoE;IACpE,0EAA0E;IAC1E,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO,QAAQ,KAAK,aAAa,CAAC;AACpC,CAAC"}
|