@styleflow.app/flowpress-deploy 1.0.0-beta.3 → 1.0.0-beta.31

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 (175) hide show
  1. package/CHANGELOG.md +162 -0
  2. package/README.md +5 -0
  3. package/composer.json +1 -1
  4. package/containers/cms/Dockerfile +35 -0
  5. package/containers/cms/Dockerfile.dockerignore +20 -0
  6. package/containers/cms/healthz.php +17 -0
  7. package/containers/cms/install-languages.sh +16 -0
  8. package/containers/cms/mpm.conf +10 -0
  9. package/containers/cms/php.ini +16 -0
  10. package/containers/cms/sanitize-integrations.php +14 -0
  11. package/containers/cms/sanitize.php +40 -0
  12. package/containers/cms/smtp.php +13 -0
  13. package/containers/cms/vhost.conf +61 -0
  14. package/containers/cms/wp-cli.yml +1 -0
  15. package/containers/local/cms/Dockerfile +18 -0
  16. package/containers/local/cms/entrypoint.sh +7 -0
  17. package/containers/local/cms/php.ini +8 -0
  18. package/containers/local/cms/vhost.conf +14 -0
  19. package/containers/local/runtimes.json +14 -0
  20. package/containers/local/web/Dockerfile +8 -0
  21. package/containers/local/web/entrypoint.sh +21 -0
  22. package/containers/php-runtime/Dockerfile +21 -0
  23. package/containers/web-ssr/Dockerfile +27 -0
  24. package/containers/web-ssr/Dockerfile.dockerignore +10 -0
  25. package/containers/web-static/Caddyfile +40 -0
  26. package/containers/web-static/Dockerfile +17 -0
  27. package/containers/web-static/Dockerfile.dockerignore +7 -0
  28. package/dist/development.d.ts +12 -0
  29. package/dist/development.d.ts.map +1 -0
  30. package/dist/development.js +57 -0
  31. package/dist/development.js.map +1 -0
  32. package/dist/node-fetch.d.ts +3 -0
  33. package/dist/node-fetch.d.ts.map +1 -0
  34. package/dist/node-fetch.js +20 -0
  35. package/dist/node-fetch.js.map +1 -0
  36. package/dist/ops/bootstrap.d.ts +24 -0
  37. package/dist/ops/bootstrap.d.ts.map +1 -0
  38. package/dist/ops/bootstrap.js +156 -0
  39. package/dist/ops/bootstrap.js.map +1 -0
  40. package/dist/ops/build.d.ts +45 -0
  41. package/dist/ops/build.d.ts.map +1 -0
  42. package/dist/ops/build.js +119 -0
  43. package/dist/ops/build.js.map +1 -0
  44. package/dist/ops/check.d.ts +14 -0
  45. package/dist/ops/check.d.ts.map +1 -0
  46. package/dist/ops/check.js +42 -0
  47. package/dist/ops/check.js.map +1 -0
  48. package/dist/ops/cli.d.ts +3 -0
  49. package/dist/ops/cli.d.ts.map +1 -0
  50. package/dist/ops/cli.js +198 -0
  51. package/dist/ops/cli.js.map +1 -0
  52. package/dist/ops/cms-migrate.d.ts +14 -0
  53. package/dist/ops/cms-migrate.d.ts.map +1 -0
  54. package/dist/ops/cms-migrate.js +133 -0
  55. package/dist/ops/cms-migrate.js.map +1 -0
  56. package/dist/ops/cms-template/command.d.mts +19 -0
  57. package/dist/ops/cms-template/command.d.mts.map +1 -0
  58. package/dist/ops/cms-template/command.mjs +145 -0
  59. package/dist/ops/cms-template/command.mjs.map +1 -0
  60. package/dist/ops/cms-template/confirm.d.mts +11 -0
  61. package/dist/ops/cms-template/confirm.d.mts.map +1 -0
  62. package/dist/ops/cms-template/confirm.mjs +18 -0
  63. package/dist/ops/cms-template/confirm.mjs.map +1 -0
  64. package/dist/ops/cms-template/entry.d.mts +2 -0
  65. package/dist/ops/cms-template/entry.d.mts.map +1 -0
  66. package/dist/ops/cms-template/entry.mjs +22 -0
  67. package/dist/ops/cms-template/entry.mjs.map +1 -0
  68. package/dist/ops/cms-template/git.d.mts +7 -0
  69. package/dist/ops/cms-template/git.d.mts.map +1 -0
  70. package/dist/ops/cms-template/git.mjs +22 -0
  71. package/dist/ops/cms-template/git.mjs.map +1 -0
  72. package/dist/ops/cms-template/plan.d.mts +7 -0
  73. package/dist/ops/cms-template/plan.d.mts.map +1 -0
  74. package/dist/ops/cms-template/plan.mjs +54 -0
  75. package/dist/ops/cms-template/plan.mjs.map +1 -0
  76. package/dist/ops/cms-template/store.d.mts +21 -0
  77. package/dist/ops/cms-template/store.d.mts.map +1 -0
  78. package/dist/ops/cms-template/store.mjs +184 -0
  79. package/dist/ops/cms-template/store.mjs.map +1 -0
  80. package/dist/ops/cms-template/target.d.mts +15 -0
  81. package/dist/ops/cms-template/target.d.mts.map +1 -0
  82. package/dist/ops/cms-template/target.mjs +24 -0
  83. package/dist/ops/cms-template/target.mjs.map +1 -0
  84. package/dist/ops/cms-template/transport.d.mts +26 -0
  85. package/dist/ops/cms-template/transport.d.mts.map +1 -0
  86. package/dist/ops/cms-template/transport.mjs +115 -0
  87. package/dist/ops/cms-template/transport.mjs.map +1 -0
  88. package/dist/ops/config.d.ts +54 -0
  89. package/dist/ops/config.d.ts.map +1 -0
  90. package/dist/ops/config.js +221 -0
  91. package/dist/ops/config.js.map +1 -0
  92. package/dist/ops/coolify.d.ts +2 -0
  93. package/dist/ops/coolify.d.ts.map +1 -0
  94. package/dist/ops/coolify.js +44 -0
  95. package/dist/ops/coolify.js.map +1 -0
  96. package/dist/ops/data.d.ts +31 -0
  97. package/dist/ops/data.d.ts.map +1 -0
  98. package/dist/ops/data.js +165 -0
  99. package/dist/ops/data.js.map +1 -0
  100. package/dist/ops/deploy.d.ts +38 -0
  101. package/dist/ops/deploy.d.ts.map +1 -0
  102. package/dist/ops/deploy.js +127 -0
  103. package/dist/ops/deploy.js.map +1 -0
  104. package/dist/ops/editorial.d.ts +23 -0
  105. package/dist/ops/editorial.d.ts.map +1 -0
  106. package/dist/ops/editorial.js +79 -0
  107. package/dist/ops/editorial.js.map +1 -0
  108. package/dist/ops/environment-files.d.ts +9 -0
  109. package/dist/ops/environment-files.d.ts.map +1 -0
  110. package/dist/ops/environment-files.js +127 -0
  111. package/dist/ops/environment-files.js.map +1 -0
  112. package/dist/ops/environment.d.ts +31 -0
  113. package/dist/ops/environment.d.ts.map +1 -0
  114. package/dist/ops/environment.js +165 -0
  115. package/dist/ops/environment.js.map +1 -0
  116. package/dist/ops/features.d.ts +12 -0
  117. package/dist/ops/features.d.ts.map +1 -0
  118. package/dist/ops/features.js +71 -0
  119. package/dist/ops/features.js.map +1 -0
  120. package/dist/ops/health.d.ts +26 -0
  121. package/dist/ops/health.d.ts.map +1 -0
  122. package/dist/ops/health.js +27 -0
  123. package/dist/ops/health.js.map +1 -0
  124. package/dist/ops/local.d.ts +198 -0
  125. package/dist/ops/local.d.ts.map +1 -0
  126. package/dist/ops/local.js +187 -0
  127. package/dist/ops/local.js.map +1 -0
  128. package/dist/ops/media-config.d.ts +61 -0
  129. package/dist/ops/media-config.d.ts.map +1 -0
  130. package/dist/ops/media-config.js +96 -0
  131. package/dist/ops/media-config.js.map +1 -0
  132. package/dist/ops/media.d.ts +47 -0
  133. package/dist/ops/media.d.ts.map +1 -0
  134. package/dist/ops/media.js +81 -0
  135. package/dist/ops/media.js.map +1 -0
  136. package/dist/ops/monitor.d.ts +25 -0
  137. package/dist/ops/monitor.d.ts.map +1 -0
  138. package/dist/ops/monitor.js +143 -0
  139. package/dist/ops/monitor.js.map +1 -0
  140. package/dist/ops/process.d.ts +9 -0
  141. package/dist/ops/process.d.ts.map +1 -0
  142. package/dist/ops/process.js +56 -0
  143. package/dist/ops/process.js.map +1 -0
  144. package/dist/ops/provision.d.ts +41 -0
  145. package/dist/ops/provision.d.ts.map +1 -0
  146. package/dist/ops/provision.js +268 -0
  147. package/dist/ops/provision.js.map +1 -0
  148. package/dist/ops/registry.d.ts +14 -0
  149. package/dist/ops/registry.d.ts.map +1 -0
  150. package/dist/ops/registry.js +112 -0
  151. package/dist/ops/registry.js.map +1 -0
  152. package/dist/ops/release.d.ts +26 -0
  153. package/dist/ops/release.d.ts.map +1 -0
  154. package/dist/ops/release.js +79 -0
  155. package/dist/ops/release.js.map +1 -0
  156. package/dist/ops/runtimes.d.ts +16 -0
  157. package/dist/ops/runtimes.d.ts.map +1 -0
  158. package/dist/ops/runtimes.js +70 -0
  159. package/dist/ops/runtimes.js.map +1 -0
  160. package/dist/ops/s3.d.ts +8 -0
  161. package/dist/ops/s3.d.ts.map +1 -0
  162. package/dist/ops/s3.js +38 -0
  163. package/dist/ops/s3.js.map +1 -0
  164. package/dist/ops/static-config.d.ts +14 -0
  165. package/dist/ops/static-config.d.ts.map +1 -0
  166. package/dist/ops/static-config.js +92 -0
  167. package/dist/ops/static-config.js.map +1 -0
  168. package/dist/ops/storage.d.ts +39 -0
  169. package/dist/ops/storage.d.ts.map +1 -0
  170. package/dist/ops/storage.js +108 -0
  171. package/dist/ops/storage.js.map +1 -0
  172. package/flowpress-deploy.php +2 -2
  173. package/includes/pilot-aliases.php +69 -0
  174. package/package.json +43 -6
  175. package/schema/deployment.schema.json +306 -0
@@ -0,0 +1,165 @@
1
+ import { sharedMediaImport, withoutMediaCredentials } from "./media-config.js";
2
+ import { randomBytes } from "node:crypto";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { join, resolve, dirname } from "node:path";
5
+ import { createHash } from "node:crypto";
6
+ import { allowedComponents, ensureSecrets, identity, loadState, readEnv, readJson, saveState, targetConfig, writeJson } from "./config.js";
7
+ import { manifestEnvironment } from "./environment.js";
8
+ import { containers } from "./build.js";
9
+ import { capture, containerFor, run, shellQuote, sleep, ssh, sshFile } from "./process.js";
10
+ import { sqlIdentifier } from "./provision.js";
11
+ export function safeArchiveEntries(entries) {
12
+ if (!entries.length || entries.some(path => path.startsWith("/") || path.includes("\\") || path.split("/").includes("..")))
13
+ throw new Error("Unsafe or empty uploads archive.");
14
+ if (entries.some(path => /(?:^|\/)wp-migrate-db(?:\/|$)|\.(?:sql(?:\.gz)?|env|bak)$/i.test(path)))
15
+ throw new Error("Uploads archive contains private backup material.");
16
+ }
17
+ export async function pullSource(root, manifest, sourceName) {
18
+ const source = manifest.sources?.[sourceName];
19
+ if (!source || !/^[a-zA-Z0-9_.@-]+$/.test(source.ssh || "") || !/^[a-z_][a-z0-9_-]*$/.test(source.user || "") || !source.path?.startsWith("/") || source.path.includes("\n"))
20
+ throw new Error("Configure a read-only source with ssh, user and absolute CMS path.");
21
+ const directory = join(root, ".local/flowpress", "source-" + sourceName + "-" + Date.now());
22
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
23
+ const wp = "runuser -u " + shellQuote(source.user) + " -- wp --path=" + shellQuote(source.path + "/web/wp") + " --skip-plugins --skip-themes";
24
+ const dump = join(directory, "source.sql");
25
+ await sshFile(source, wp + " db export - --single-transaction --skip-lock-tables --quiet", { output: dump });
26
+ const archive = join(directory, "uploads.tar");
27
+ const excludes = ["./wp-migrate-db", "*.sql", "*.sql.gz", "*.env", "*.bak"].map(value => " --exclude=" + shellQuote(value)).join("");
28
+ await sshFile(source, "tar -C " + shellQuote(source.path + "/web/app/uploads") + excludes + " -cf - .", { output: archive });
29
+ safeArchiveEntries(capture("tar", ["-tf", archive]).split("\n").filter(Boolean));
30
+ const meta = { source: sourceName, createdAt: new Date().toISOString(), dump, archive,
31
+ sha256: createHash("sha256").update(readFileSync(dump)).digest("hex") };
32
+ writeJson(join(directory, "snapshot.json"), meta, 0o600);
33
+ return meta;
34
+ }
35
+ function mysql(container, password, args, input = "") {
36
+ if (!/^[a-zA-Z0-9_-]+$/.test(container) || /[\r\n]/.test(password))
37
+ throw new Error("Invalid database container credentials.");
38
+ return capture("docker", ["exec", "-i", container, "sh", "-c",
39
+ 'read -r MYSQL_PWD; export MYSQL_PWD; exec mariadb -uroot --batch ' + args.map(shellQuote).join(" ")], { input: password + "\n" + input });
40
+ }
41
+ function dumpCopy(container, password, database) {
42
+ return capture("docker", ["exec", "-i", container, "sh", "-c",
43
+ 'read -r MYSQL_PWD; export MYSQL_PWD; exec mariadb-dump -uroot --single-transaction --skip-lock-tables --skip-add-locks --skip-comments --no-tablespaces ' + sqlIdentifier(database)], { input: password + "\n", maxBuffer: 256 * 1024 * 1024 });
44
+ }
45
+ export async function prepareData(root, manifest, name, { file, image, source = "production" }) {
46
+ allowedComponents(manifest, name, ["cms"]);
47
+ if (name === "production")
48
+ throw new Error("Data preparation for production is not supported by this migration command.");
49
+ if (!file || !existsSync(file))
50
+ throw new Error("A source dump is required.");
51
+ const project = identity(root);
52
+ const values = ensureSecrets(root, name, project.slug);
53
+ const preserveCloudMedia = sharedMediaImport(manifest, name, source, target => manifestEnvironment(root, target, {}));
54
+ const env = { ...withoutMediaCredentials(manifestEnvironment(root, name, {})), FLOWPRESS_MEDIA_STORAGE: "local", FLOWPRESS_MEDIA_IMPORT_PRESERVE: String(preserveCloudMedia), DB_HOST: "127.0.0.1:3306", DB_NAME: values.DB_NAME, DB_USER: values.DB_USER, DB_PASSWORD: values.DB_PASSWORD, DB_PREFIX: values.DB_PREFIX };
55
+ // The source prefix belongs to the SQL snapshot, not to an environment credential.
56
+ const original = readFileSync(file, "utf8");
57
+ const match = original.match(/CREATE TABLE (?:IF NOT EXISTS )?\x60([a-zA-Z0-9_]+)options\x60/);
58
+ if (!match)
59
+ throw new Error("Cannot identify the WordPress table prefix in the snapshot.");
60
+ env.DB_PREFIX = match[1];
61
+ values.DB_PREFIX = match[1];
62
+ const secretsPath = join(root, ".secrets", name + ".env");
63
+ writeFileSync(secretsPath, Object.entries(values).map(([key, value]) => key + "=" + JSON.stringify(value)).join("\n") + "\n", { mode: 0o600 });
64
+ const release = readJson(join(root, ".local/flowpress", "release-" + name + "-cms.json"));
65
+ const cmsImage = image || (release && release.repository + ":" + release.tag);
66
+ if (!cmsImage)
67
+ throw new Error("Build the CMS image before preparing data.");
68
+ const directory = join(root, ".local/flowpress", "prepared-" + name + "-" + Date.now());
69
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
70
+ const envFile = join(directory, "cms.env");
71
+ writeFileSync(envFile, Object.entries(env).filter(([, value]) => typeof value === "string").map(([key, value]) => key + "=" + value).join("\n") + "\n", { mode: 0o600 });
72
+ const database = "flowpress-transform-" + process.pid;
73
+ const password = randomBytes(32).toString("hex");
74
+ run("docker", ["run", "--rm", "-d", "--name", database, "--network", "none", "-e", "MARIADB_ROOT_PASSWORD=" + password, "mariadb:11.4"], { stdio: "ignore" });
75
+ try {
76
+ let ready = false;
77
+ for (let attempt = 0; attempt < 60; attempt++) {
78
+ try {
79
+ capture("docker", ["exec", database, "healthcheck.sh", "--connect", "--innodb_initialized"]);
80
+ ready = true;
81
+ break;
82
+ }
83
+ catch {
84
+ await sleep(2000);
85
+ }
86
+ }
87
+ if (!ready)
88
+ throw new Error("Disposable database did not start.");
89
+ const account = "CREATE DATABASE " + sqlIdentifier(values.DB_NAME) + ";\nCREATE USER '" + sqlIdentifier(values.DB_USER) + "'@'127.0.0.1' IDENTIFIED BY '" + values.DB_PASSWORD + "';\nGRANT ALL ON " + values.DB_NAME + ".* TO '" + values.DB_USER + "'@'127.0.0.1';\n";
90
+ mysql(database, password, [], account);
91
+ mysql(database, password, [values.DB_NAME], original);
92
+ const wp = args => capture("docker", ["run", "--rm", "--network", "container:" + database, "--env-file", envFile,
93
+ "-v", join(containers, "cms") + ":/tmp/flowpress-sanitizers:ro", cmsImage, "wp", ...args], { maxBuffer: 256 * 1024 * 1024 });
94
+ const sourceTarget = targetConfig(manifest, source);
95
+ const replacements = [
96
+ [sourceTarget.backendUrl, env.BACKEND_URL],
97
+ ...(sourceTarget.backendAliases || []).map(from => [from, env.BACKEND_URL]),
98
+ [sourceTarget.frontendUrl, env.SITE_URL],
99
+ ...(sourceTarget.aliases || []).map(from => [from, env.SITE_URL]),
100
+ ...(!preserveCloudMedia ? [[sourceTarget.mediaUrl, env.BACKEND_URL + "/app/uploads"]] : []),
101
+ ].filter(([from, to]) => from && to && from !== to).sort((a, b) => b[0].length - a[0].length);
102
+ for (const [from, to] of replacements)
103
+ wp(["search-replace", from, to, "--all-tables-with-prefix", "--precise", "--quiet"]);
104
+ const output = wp(["eval-file", "/tmp/flowpress-sanitizers/sanitize.php"]);
105
+ const counts = JSON.parse(output.split("\n").findLast(line => line.startsWith("{")));
106
+ const transformed = join(directory, "staging.sql");
107
+ writeFileSync(transformed, dumpCopy(database, password, values.DB_NAME) + "\n", { mode: 0o600 });
108
+ writeJson(join(directory, "prepared.json"), { environment: name, source, preparedAt: new Date().toISOString(), prefix: env.DB_PREFIX, counts, file: transformed }, 0o600);
109
+ return { file: transformed, counts, prefix: env.DB_PREFIX };
110
+ }
111
+ finally {
112
+ run("docker", ["rm", "-fv", database], { stdio: "ignore" });
113
+ }
114
+ }
115
+ export async function pushData(root, manifest, name, file) {
116
+ allowedComponents(manifest, name, ["cms"]);
117
+ if (name === "production")
118
+ throw new Error("Production imports require a separate reviewed procedure.");
119
+ const state = loadState(root, name);
120
+ if (state.seededAt)
121
+ throw new Error("This database was already seeded. Refusing an implicit overwrite.");
122
+ const values = readEnv(join(root, ".secrets", name + ".env"));
123
+ if (!values.DB_PASSWORD || state.database?.name !== values.DB_NAME)
124
+ throw new Error("Database binding mismatch.");
125
+ const pool = sqlIdentifier(values.DB_NAME), user = sqlIdentifier(values.DB_USER);
126
+ const program = 'read -r MYSQL_PWD; export MYSQL_PWD; exec mariadb --batch -u' + user + " " + pool;
127
+ const existing = ssh(state.platform, "docker exec -i " + state.platform.poolUuid + " sh -c " + shellQuote(program), { input: values.DB_PASSWORD + "\nSELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE();\n" });
128
+ if (existing.trim() !== "COUNT(*)\n0" && existing.trim() !== "0")
129
+ throw new Error("Refusing to import into a nonempty database.");
130
+ const sql = readFileSync(resolve(file), "utf8");
131
+ if (/^\s*(?:CREATE|DROP)\s+(?:DATABASE|USER)\b/im.test(sql) || /^\s*USE\s+/im.test(sql))
132
+ throw new Error("The import must contain only the prepared schema, without database/user operations.");
133
+ ssh(state.platform, "docker exec -i " + state.platform.poolUuid + " sh -c " + shellQuote(program), { input: values.DB_PASSWORD + "\n" + sql, maxBuffer: 256 * 1024 * 1024 });
134
+ state.seededAt = new Date().toISOString();
135
+ saveState(root, name, state);
136
+ return { environment: name, imported: true, database: pool };
137
+ }
138
+ export async function pushUploads(root, manifest, name, archive) {
139
+ allowedComponents(manifest, name, ["cms"]);
140
+ const state = loadState(root, name);
141
+ const app = state.apps?.cms;
142
+ if (!app?.uuid)
143
+ throw new Error("CMS must be provisioned first.");
144
+ safeArchiveEntries(capture("tar", ["-tf", archive]).split("\n").filter(Boolean));
145
+ const listing = capture("tar", ["-tvf", archive]);
146
+ if (listing.split("\n").some(line => /^[lhbcps]/.test(line)))
147
+ throw new Error("Uploads archive contains links or special files.");
148
+ const container = containerFor(state.platform, app.uuid);
149
+ await sshFile(state.platform, "docker exec -i " + shellQuote(container) + " tar -C /srv/cms/web/app/uploads -xf -", { input: archive });
150
+ return { environment: name, uploadsCopied: true };
151
+ }
152
+ export async function cleanIntegrations(root, manifest, name) {
153
+ allowedComponents(manifest, name, ["cms"]);
154
+ if (name === "production")
155
+ throw new Error("Integration cleanup is restricted to non-production clones.");
156
+ const state = loadState(root, name), app = state.apps?.cms;
157
+ if (!app?.uuid)
158
+ throw new Error("CMS not provisioned.");
159
+ const container = containerFor(state.platform, app.uuid);
160
+ const script = readFileSync(join(containers, "cms/sanitize-integrations.php"), "utf8").replace(/^<\?php\s*/, "");
161
+ // This program contains no credentials. Only option names and counts are returned.
162
+ const output = ssh(state.platform, "docker exec " + shellQuote(container) + " wp eval " + shellQuote(script));
163
+ return { environment: name, output };
164
+ }
165
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/ops/data.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export function assertRelease(release: any, app: any, name: any, component: any): void;
2
+ export function waitHealth(app: any, release: any, { fetchImpl, attempts, delay }?: {
3
+ fetchImpl?: typeof fetch | undefined;
4
+ attempts?: number | undefined;
5
+ delay?: number | undefined;
6
+ }): Promise<any>;
7
+ export function waitDeployment(api: any, id: any): Promise<void>;
8
+ export function registryRelease(app: any, name: any, component: any, alias: any, operator: any): Promise<{
9
+ component: any;
10
+ environment: any;
11
+ repository: any;
12
+ tag: string;
13
+ sha: any;
14
+ digest: string;
15
+ buildId: any;
16
+ pushed: boolean;
17
+ } | null>;
18
+ export function deployedRelease(root: any, name: any, component: any): Promise<{
19
+ component: any;
20
+ environment: any;
21
+ repository: any;
22
+ tag: string;
23
+ sha: any;
24
+ digest: string;
25
+ buildId: any;
26
+ pushed: boolean;
27
+ } | null>;
28
+ export function deploy(root: any, manifest: any, name: any, component: any, { rollback, release: supplied }?: {
29
+ rollback?: boolean | undefined;
30
+ }): Promise<{
31
+ component: any;
32
+ environment: any;
33
+ release: any;
34
+ digest: any;
35
+ url: any;
36
+ rollback: boolean;
37
+ }>;
38
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/ops/deploy.js"],"names":[],"mappings":"AAOA,uFAIC;AACD;;;;iBAiBC;AACD,iEASC;AACD;;;;;;;;;UAMC;AACD;;;;;;;;;UAIC;AAaD;;;;;;;;;GA0CC"}
@@ -0,0 +1,127 @@
1
+ import { join } from "node:path";
2
+ import { allowedComponents, loadState, operatorEnvironment, readJson, releaseTag, saveState } from "./config.js";
3
+ import { existingDigest, imageMetadata } from "./registry.js";
4
+ import { coolifyClient } from "./coolify.js";
5
+ import { inspectDigest, registryLogin } from "./build.js";
6
+ import { run, sleep } from "./process.js";
7
+ export function assertRelease(release, app, name, component) {
8
+ if (!release || release.environment !== name || release.component !== component || release.repository !== app.repository
9
+ || !/^[a-f0-9]{40}$/.test(release.sha || "") || !/^sha256:[a-f0-9]{64}$/.test(release.digest || "")
10
+ || !/^[a-zA-Z0-9_.-]+$/.test(release.tag || ""))
11
+ throw new Error("Invalid or mismatched immutable release record.");
12
+ }
13
+ export async function waitHealth(app, release, { fetchImpl = fetch, attempts = 60, delay = 3000 } = {}) {
14
+ for (let attempt = 0; attempt < attempts; attempt++) {
15
+ try {
16
+ const res = await fetchImpl(app.url + app.health + "?release=" + Date.now(), { signal: AbortSignal.timeout(10000), redirect: "error", headers: { "cache-control": "no-cache" } });
17
+ const data = await res.json();
18
+ if (res.ok && data.status === "ok" && data.release === release.sha && (!release.environment || data.environment === release.environment) && (!release.buildId || data.buildId === release.buildId)) {
19
+ if (app.health === "/healthz.php") {
20
+ const graphql = await fetchImpl(app.url + "/index.php?graphql", { method: "POST", redirect: "error", signal: AbortSignal.timeout(10000), headers: { "content-type": "application/json" }, body: JSON.stringify({ query: "{ __typename }" }) });
21
+ const schema = await graphql.json();
22
+ if (!graphql.ok || !schema.data?.__typename || schema.errors?.length)
23
+ throw new Error("WordPress GraphQL runtime is not ready.");
24
+ }
25
+ return data;
26
+ }
27
+ }
28
+ catch { /* rolling replacement is expected to fail briefly */ }
29
+ if (attempt + 1 < attempts)
30
+ await sleep(delay);
31
+ }
32
+ throw new Error("Release health verification failed for " + app.name + ".");
33
+ }
34
+ export async function waitDeployment(api, id) {
35
+ if (!id)
36
+ throw new Error("Coolify returned no deployment ID.");
37
+ for (let attempt = 0; attempt < 240; attempt++) {
38
+ const result = await api("GET", "/deployments/" + id);
39
+ if (result.status === "finished")
40
+ return;
41
+ if (["failed", "cancelled", "cancelled-by-user"].includes(result.status))
42
+ throw new Error("Coolify deployment " + result.status + ".");
43
+ await sleep(5000);
44
+ }
45
+ throw new Error("Coolify deployment timeout.");
46
+ }
47
+ export async function registryRelease(app, name, component, alias, operator) {
48
+ const metadata = await imageMetadata(app.repository + ":" + alias, operator);
49
+ if (!metadata)
50
+ return null;
51
+ const tag = releaseTag(component, name, metadata.sha, metadata.buildId);
52
+ if (await existingDigest(app.repository + ":" + tag, operator) !== metadata.digest)
53
+ throw new Error("Release alias differs from its immutable tag.");
54
+ return { component, environment: name, repository: app.repository, tag, sha: metadata.sha, digest: metadata.digest, buildId: component === "cms" ? undefined : metadata.buildId, pushed: true };
55
+ }
56
+ export async function deployedRelease(root, name, component) {
57
+ const state = loadState(root, name), app = state.apps?.[component];
58
+ if (!app?.uuid)
59
+ throw new Error("Component not provisioned.");
60
+ return registryRelease(app, name, component, name, operatorEnvironment(root));
61
+ }
62
+ function retain(app, alias, release) {
63
+ run("docker", ["buildx", "imagetools", "create", "--prefer-index=false", "--tag", app.repository + ":" + alias, release.repository + "@" + release.digest]);
64
+ if (inspectDigest(app.repository + ":" + alias) !== release.digest)
65
+ throw new Error("Retained image digest mismatch.");
66
+ }
67
+ async function launch(api, app, release, name) {
68
+ retain(app, name, release);
69
+ const response = await api("POST", "/deploy?uuid=" + app.uuid + "&force=false");
70
+ const deployment = (response.deployments || [response]).find(item => item.deployment_uuid);
71
+ await waitDeployment(api, deployment?.deployment_uuid);
72
+ return waitHealth(app, release);
73
+ }
74
+ export async function deploy(root, manifest, name, component, { rollback = false, release: supplied } = {}) {
75
+ allowedComponents(manifest, name, [component]);
76
+ const state = loadState(root, name);
77
+ const app = state.apps?.[component];
78
+ if (!app?.uuid)
79
+ throw new Error("Provision this component first.");
80
+ const operator = operatorEnvironment(root);
81
+ registryLogin(state.platform, operator);
82
+ const record = supplied || (rollback ? await registryRelease(app, name, component, name + "-previous", operator) : readJson(join(root, ".local/flowpress", "release-" + name + "-" + component + ".json")));
83
+ assertRelease(record, app, name, component);
84
+ if (name === "production" && component === "cms" && !rollback) {
85
+ const staging = loadState(root, "staging").apps?.cms;
86
+ const verified = staging && await registryRelease(staging, "staging", "cms", "staging", operator);
87
+ if (!verified || verified.sha !== record.sha || verified.digest !== record.digest)
88
+ throw new Error("Production must promote the exact CMS image verified on staging.");
89
+ await waitHealth(staging, verified);
90
+ }
91
+ if (inspectDigest(record.repository + ":" + record.tag) !== record.digest)
92
+ throw new Error("Registry digest changed; deployment refused.");
93
+ const api = coolifyClient(state.platform.coolifyUrl, operator.COOLIFY_TOKEN);
94
+ const configured = await api("GET", "/applications/" + app.uuid);
95
+ if (configured.docker_registry_image_name !== app.repository)
96
+ throw new Error("Application repository drift; review provisioning before deployment.");
97
+ if (configured.docker_registry_image_tag !== name)
98
+ throw new Error("Run operator provisioning to configure the managed environment tag.");
99
+ let previous = await registryRelease(app, name, component, name, operator);
100
+ if (previous) {
101
+ try {
102
+ await waitHealth(app, previous, { attempts: 1 });
103
+ }
104
+ catch {
105
+ previous = await registryRelease(app, name, component, name + "-previous", operator);
106
+ }
107
+ }
108
+ if (previous && previous.digest !== record.digest)
109
+ retain(app, name + "-previous", previous);
110
+ try {
111
+ await launch(api, app, record, name);
112
+ }
113
+ catch (error) {
114
+ if (previous && previous.digest !== record.digest) {
115
+ await launch(api, app, previous, name);
116
+ throw new Error(error.message + " Previous image restored; database was not rolled back.");
117
+ }
118
+ throw error;
119
+ }
120
+ if (previous && previous.digest !== record.digest)
121
+ app.previous = previous;
122
+ app.current = record;
123
+ app.deployedAt = new Date().toISOString();
124
+ saveState(root, name, state);
125
+ return { component, environment: name, release: record.sha, digest: record.digest, url: app.url, rollback };
126
+ }
127
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/ops/deploy.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export function validateBuildRequest(payload: any): {
2
+ target: any;
3
+ batchId: any;
4
+ mode: any;
5
+ paths: string[];
6
+ deletedPaths: string[];
7
+ };
8
+ export function validateBuildId(value: any): any;
9
+ export function purgeFiles(site: any, routes: any, assets?: any[]): string[];
10
+ export function purgeFrontendFiles({ files, token, zone, fetchImpl }: {
11
+ files: any;
12
+ token: any;
13
+ zone: any;
14
+ fetchImpl?: typeof fetch | undefined;
15
+ }): Promise<void>;
16
+ export function acknowledgeBatch({ request, backend, token, status, fetchImpl }: {
17
+ request: any;
18
+ backend: any;
19
+ token: any;
20
+ status: any;
21
+ fetchImpl?: typeof fetch | undefined;
22
+ }): Promise<any>;
23
+ //# sourceMappingURL=editorial.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorial.d.ts","sourceRoot":"","sources":["../../src/ops/editorial.js"],"names":[],"mappings":"AAEA;;;;;;EAUC;AAED,iDAIC;AAED,6EAgBC;AAED;;;;;kBAWC;AAED;;;;;;iBAkBC"}
@@ -0,0 +1,79 @@
1
+ import { normalizeDeployPath } from "@styleflow.app/flowpress-deploy";
2
+ export function validateBuildRequest(payload) {
3
+ if (!payload || !["staging", "production"].includes(payload.target))
4
+ throw new Error("Invalid editorial target.");
5
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i.test(payload.batchId || ""))
6
+ throw new Error("Invalid editorial batchId.");
7
+ if (!["full", "partial"].includes(payload.mode))
8
+ throw new Error("Invalid editorial build mode.");
9
+ const paths = (key) => {
10
+ const values = payload[key] ?? [];
11
+ if (!Array.isArray(values) || values.length > 1000 || values.some((value) => typeof value !== "string" || value.length > 2048))
12
+ throw new Error(`Invalid editorial ${key}.`);
13
+ return [...new Set(values.map(normalizeDeployPath))];
14
+ };
15
+ return { target: payload.target, batchId: payload.batchId, mode: payload.mode, paths: paths("paths"), deletedPaths: paths("deletedPaths") };
16
+ }
17
+ export function validateBuildId(value) {
18
+ // Leave room for the environment and full SHA within the OCI tag limit (128).
19
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(value || ""))
20
+ throw new Error("Invalid frontend build ID.");
21
+ return value;
22
+ }
23
+ export function purgeFiles(site, routes, assets = []) {
24
+ const origin = new URL(site).origin;
25
+ const paths = new Set(["/", "/robots.txt", "/sitemap_index.xml", "/healthz.json", "/404.html"]);
26
+ for (const route of routes) {
27
+ const path = normalizeDeployPath(route);
28
+ paths.add(path);
29
+ if (path !== "/" && !path.split("/").at(-1)?.includes(".")) {
30
+ paths.add(path.replace(/\/+$/, ""));
31
+ paths.add(`${path.replace(/\/+$/, "")}/`);
32
+ }
33
+ }
34
+ for (const asset of assets) {
35
+ if (typeof asset !== "string" || !/^\/_astro\/[A-Za-z0-9_./@-]+$/.test(asset) || asset.split("/").some(part => [".", ".."].includes(part)))
36
+ throw new Error("Invalid frontend asset purge path.");
37
+ paths.add(asset);
38
+ }
39
+ return [...paths].map((path) => new URL(path, origin).href);
40
+ }
41
+ export async function purgeFrontendFiles({ files, token, zone, fetchImpl = fetch }) {
42
+ if (!token || !/^[a-f0-9]{32}$/i.test(zone || ""))
43
+ throw new Error("Missing purge-only Cloudflare token or CLOUDFLARE_ZONE_ID.");
44
+ for (let offset = 0; offset < files.length; offset += 30) {
45
+ const response = await fetchImpl(`https://api.cloudflare.com/client/v4/zones/${zone}/purge_cache`, {
46
+ method: "POST", signal: AbortSignal.timeout(30_000), redirect: "error",
47
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
48
+ body: JSON.stringify({ files: files.slice(offset, offset + 30) }),
49
+ });
50
+ const data = await response.json();
51
+ if (!response.ok || !data.success)
52
+ throw new Error(`Cloudflare URL purge failed (${response.status}).`);
53
+ }
54
+ }
55
+ export async function acknowledgeBatch({ request, backend, token, status, fetchImpl = fetch }) {
56
+ validateBuildRequest(request);
57
+ if (!["success", "failure"].includes(status) || !token)
58
+ throw new Error("Missing callback token or invalid callback status.");
59
+ const url = new URL("/wp-json/flowpress/v1/build-complete", backend);
60
+ let last;
61
+ for (let attempt = 0; attempt < 3; attempt++) {
62
+ try {
63
+ const response = await fetchImpl(url, {
64
+ method: "POST", redirect: "error", signal: AbortSignal.timeout(15_000),
65
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
66
+ body: JSON.stringify({ batchId: request.batchId, status }),
67
+ });
68
+ const body = await response.json();
69
+ if (!response.ok || body.ok !== true)
70
+ throw new Error(`CMS callback failed (${response.status}).`);
71
+ return body;
72
+ }
73
+ catch (error) {
74
+ last = error;
75
+ }
76
+ }
77
+ throw last;
78
+ }
79
+ //# sourceMappingURL=editorial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorial.js","sourceRoot":"","sources":["../../src/ops/editorial.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export function synchronizeEnvironmentFiles(root: any, { apply, localSecrets, manifest }?: {
2
+ apply?: boolean | undefined;
3
+ localSecrets?: boolean | undefined;
4
+ manifest?: any;
5
+ }): {
6
+ changed: string[];
7
+ applied: boolean;
8
+ };
9
+ //# sourceMappingURL=environment-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-files.d.ts","sourceRoot":"","sources":["../../src/ops/environment-files.js"],"names":[],"mappings":"AAuBA;;;;;;;EAiFC"}