@styleflow.app/flowpress-deploy 1.0.0-beta.2 → 1.0.0-beta.21

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 (117) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +5 -0
  3. package/containers/cms/Dockerfile +35 -0
  4. package/containers/cms/Dockerfile.dockerignore +20 -0
  5. package/containers/cms/healthz.php +17 -0
  6. package/containers/cms/install-languages.sh +16 -0
  7. package/containers/cms/mpm.conf +10 -0
  8. package/containers/cms/php.ini +16 -0
  9. package/containers/cms/sanitize-integrations.php +14 -0
  10. package/containers/cms/sanitize.php +37 -0
  11. package/containers/cms/smtp.php +13 -0
  12. package/containers/cms/vhost.conf +61 -0
  13. package/containers/cms/wp-cli.yml +1 -0
  14. package/containers/local/cms/Dockerfile +18 -0
  15. package/containers/local/cms/entrypoint.sh +7 -0
  16. package/containers/local/cms/php.ini +8 -0
  17. package/containers/local/cms/vhost.conf +14 -0
  18. package/containers/local/web/Dockerfile +8 -0
  19. package/containers/local/web/entrypoint.sh +21 -0
  20. package/containers/php-runtime/Dockerfile +21 -0
  21. package/containers/web-ssr/Dockerfile +27 -0
  22. package/containers/web-ssr/Dockerfile.dockerignore +10 -0
  23. package/containers/web-static/Caddyfile +40 -0
  24. package/containers/web-static/Dockerfile +17 -0
  25. package/containers/web-static/Dockerfile.dockerignore +7 -0
  26. package/dist/development.d.ts +4 -0
  27. package/dist/development.d.ts.map +1 -0
  28. package/dist/development.js +10 -0
  29. package/dist/development.js.map +1 -0
  30. package/dist/node-fetch.d.ts +3 -0
  31. package/dist/node-fetch.d.ts.map +1 -0
  32. package/dist/node-fetch.js +20 -0
  33. package/dist/node-fetch.js.map +1 -0
  34. package/dist/ops/bootstrap.d.ts +21 -0
  35. package/dist/ops/bootstrap.d.ts.map +1 -0
  36. package/dist/ops/bootstrap.js +123 -0
  37. package/dist/ops/bootstrap.js.map +1 -0
  38. package/dist/ops/build.d.ts +39 -0
  39. package/dist/ops/build.d.ts.map +1 -0
  40. package/dist/ops/build.js +110 -0
  41. package/dist/ops/build.js.map +1 -0
  42. package/dist/ops/check.d.ts +18 -0
  43. package/dist/ops/check.d.ts.map +1 -0
  44. package/dist/ops/check.js +46 -0
  45. package/dist/ops/check.js.map +1 -0
  46. package/dist/ops/cli.d.ts +3 -0
  47. package/dist/ops/cli.d.ts.map +1 -0
  48. package/dist/ops/cli.js +166 -0
  49. package/dist/ops/cli.js.map +1 -0
  50. package/dist/ops/config.d.ts +54 -0
  51. package/dist/ops/config.d.ts.map +1 -0
  52. package/dist/ops/config.js +202 -0
  53. package/dist/ops/config.js.map +1 -0
  54. package/dist/ops/coolify.d.ts +2 -0
  55. package/dist/ops/coolify.d.ts.map +1 -0
  56. package/dist/ops/coolify.js +44 -0
  57. package/dist/ops/coolify.js.map +1 -0
  58. package/dist/ops/data.d.ts +31 -0
  59. package/dist/ops/data.d.ts.map +1 -0
  60. package/dist/ops/data.js +163 -0
  61. package/dist/ops/data.js.map +1 -0
  62. package/dist/ops/deploy.d.ts +38 -0
  63. package/dist/ops/deploy.d.ts.map +1 -0
  64. package/dist/ops/deploy.js +127 -0
  65. package/dist/ops/deploy.js.map +1 -0
  66. package/dist/ops/editorial.d.ts +23 -0
  67. package/dist/ops/editorial.d.ts.map +1 -0
  68. package/dist/ops/editorial.js +79 -0
  69. package/dist/ops/editorial.js.map +1 -0
  70. package/dist/ops/environment-files.d.ts +9 -0
  71. package/dist/ops/environment-files.d.ts.map +1 -0
  72. package/dist/ops/environment-files.js +125 -0
  73. package/dist/ops/environment-files.js.map +1 -0
  74. package/dist/ops/environment.d.ts +29 -0
  75. package/dist/ops/environment.d.ts.map +1 -0
  76. package/dist/ops/environment.js +159 -0
  77. package/dist/ops/environment.js.map +1 -0
  78. package/dist/ops/health.d.ts +26 -0
  79. package/dist/ops/health.d.ts.map +1 -0
  80. package/dist/ops/health.js +27 -0
  81. package/dist/ops/health.js.map +1 -0
  82. package/dist/ops/local.d.ts +161 -0
  83. package/dist/ops/local.d.ts.map +1 -0
  84. package/dist/ops/local.js +176 -0
  85. package/dist/ops/local.js.map +1 -0
  86. package/dist/ops/monitor.d.ts +23 -0
  87. package/dist/ops/monitor.d.ts.map +1 -0
  88. package/dist/ops/monitor.js +143 -0
  89. package/dist/ops/monitor.js.map +1 -0
  90. package/dist/ops/process.d.ts +9 -0
  91. package/dist/ops/process.d.ts.map +1 -0
  92. package/dist/ops/process.js +56 -0
  93. package/dist/ops/process.js.map +1 -0
  94. package/dist/ops/provision.d.ts +41 -0
  95. package/dist/ops/provision.d.ts.map +1 -0
  96. package/dist/ops/provision.js +268 -0
  97. package/dist/ops/provision.js.map +1 -0
  98. package/dist/ops/registry.d.ts +7 -0
  99. package/dist/ops/registry.d.ts.map +1 -0
  100. package/dist/ops/registry.js +73 -0
  101. package/dist/ops/registry.js.map +1 -0
  102. package/dist/ops/release.d.ts +26 -0
  103. package/dist/ops/release.d.ts.map +1 -0
  104. package/dist/ops/release.js +79 -0
  105. package/dist/ops/release.js.map +1 -0
  106. package/dist/ops/s3.d.ts +8 -0
  107. package/dist/ops/s3.d.ts.map +1 -0
  108. package/dist/ops/s3.js +38 -0
  109. package/dist/ops/s3.js.map +1 -0
  110. package/dist/ops/static-config.d.ts +14 -0
  111. package/dist/ops/static-config.d.ts.map +1 -0
  112. package/dist/ops/static-config.js +96 -0
  113. package/dist/ops/static-config.js.map +1 -0
  114. package/flowpress-deploy.php +2 -2
  115. package/includes/automatic-build.php +22 -5
  116. package/package.json +40 -6
  117. package/schema/deployment.schema.json +185 -0
@@ -0,0 +1,20 @@
1
+ /** Fetch adapter for proxies running on Node, whose fetch decompresses bodies. */
2
+ export const nodeProxyFetch = async (input, init) => {
3
+ const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
4
+ headers.set("accept-encoding", "identity");
5
+ const response = await fetch(input, { ...init, headers });
6
+ const encoding = response.headers.get("content-encoding")?.trim().toLowerCase();
7
+ const method = init?.method ?? (input instanceof Request ? input.method : "GET");
8
+ if (method === "HEAD" || !response.body || !encoding || !/^(gzip|deflate|br)$/.test(encoding))
9
+ return response;
10
+ // A server ignoring identity negotiation must not label decoded bytes as gzip.
11
+ if (response.status === 206) {
12
+ await response.body.cancel();
13
+ throw new Error("Encoded partial media response cannot be proxied safely.");
14
+ }
15
+ const decodedHeaders = new Headers(response.headers);
16
+ decodedHeaders.delete("content-encoding");
17
+ decodedHeaders.delete("content-length");
18
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers: decodedHeaders });
19
+ };
20
+ //# sourceMappingURL=node-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-fetch.js","sourceRoot":"","sources":["../src/node-fetch.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAiB,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;IAChE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACrG,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChF,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACjF,IAAI,MAAM,KAAK,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/G,+EAA+E;IAC/E,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrD,cAAc,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC1C,cAAc,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACxC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;AAC5H,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ export function provisionRegistry(root: any, manifest: any, { file, apply }?: {
2
+ apply?: boolean | undefined;
3
+ }): Promise<{
4
+ changes: string[];
5
+ applied: boolean;
6
+ credentials?: undefined;
7
+ } | {
8
+ changes: string[];
9
+ applied: boolean;
10
+ credentials: string;
11
+ }>;
12
+ export function provisionDns(root: any, manifest: any, name: any, { file, apply }?: {
13
+ apply?: boolean | undefined;
14
+ }): Promise<{
15
+ host: string;
16
+ exists: boolean;
17
+ applied: boolean;
18
+ target: any;
19
+ frontendChanged: boolean;
20
+ }>;
21
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/ops/bootstrap.js"],"names":[],"mappings":"AAIA;;;;;;;;;;GA+EC;AACD;;;;;;;;GAqBC"}
@@ -0,0 +1,123 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { identity, operatorEnvironment, platformConfig, publicPlatform, writeJson, readJson } from "./config.js";
4
+ export async function provisionRegistry(root, manifest, { file, apply = false } = {}) {
5
+ const platform = platformConfig(root, manifest, file), operator = operatorEnvironment(root);
6
+ const username = operator.HARBOR_ADMIN_USER, password = operator.HARBOR_ADMIN_PASSWORD;
7
+ if (!username || !password || !operator.HARBOR_API_URL)
8
+ throw new Error("Set private HARBOR_API_URL/HARBOR_ADMIN_USER/HARBOR_ADMIN_PASSWORD.");
9
+ const api = async (method, path, body) => {
10
+ const response = await fetch(operator.HARBOR_API_URL.replace(/\/$/, "") + "/api/v2.0" + path, {
11
+ method, redirect: "error", signal: AbortSignal.timeout(30000),
12
+ headers: { authorization: "Basic " + Buffer.from(username + ":" + password).toString("base64"), "content-type": "application/json" },
13
+ ...(body ? { body: JSON.stringify(body) } : {}),
14
+ });
15
+ if (!response.ok)
16
+ throw new Error("Harbor " + method + " " + path + " refused (HTTP " + response.status + ").");
17
+ const text = await response.text();
18
+ return text ? JSON.parse(text) : {};
19
+ };
20
+ const projects = [platform.registryProject, "flowpress"];
21
+ const changes = [];
22
+ const existing = await api("GET", "/projects?page_size=100");
23
+ for (const name of projects) {
24
+ if (!/^[a-z0-9][a-z0-9_.-]+$/.test(name))
25
+ throw new Error("Invalid Harbor project.");
26
+ if (!existing.some(project => project.name === name)) {
27
+ changes.push("Create private Harbor project " + name);
28
+ if (apply)
29
+ await api("POST", "/projects", { project_name: name, public: false, storage_limit: (name === "flowpress" ? 2 : 5) * 1024 ** 3 });
30
+ }
31
+ }
32
+ if (!apply)
33
+ return { changes, applied: false };
34
+ const current = await api("GET", "/projects?page_size=100");
35
+ const robots = await api("GET", "/robots?page_size=100");
36
+ const privateFile = join(root, ".secrets/registry-created.json");
37
+ const created = readJson(privateFile, {});
38
+ for (const name of projects) {
39
+ const project = current.find(item => item.name === name);
40
+ const robotName = name + "-ci";
41
+ const expected = "robot$" + robotName;
42
+ if (!robots.some(robot => robot.name === expected)) {
43
+ const robot = await api("POST", "/robots", {
44
+ name: robotName, description: "FlowPress build/push for " + name, duration: 365, level: "system",
45
+ permissions: [{ kind: "project", namespace: name, access: [{ resource: "repository", action: "pull" }, { resource: "repository", action: "push" }] },
46
+ ...(name === "flowpress" ? [] : [{ kind: "project", namespace: "flowpress", access: [{ resource: "repository", action: "pull" }] }])],
47
+ });
48
+ created[name] = { name: robot.name, secret: robot.secret };
49
+ writeJson(privateFile, created, 0o600);
50
+ }
51
+ const existingRobot = robots.find(robot => robot.name === expected);
52
+ if (name !== "flowpress" && existingRobot) {
53
+ const detail = await api("GET", "/robots/" + existingRobot.id);
54
+ if (!detail.permissions.some(permission => permission.namespace === "flowpress")) {
55
+ detail.permissions.push({ kind: "project", namespace: "flowpress", access: [{ resource: "repository", action: "pull" }] });
56
+ await api("PUT", "/robots/" + existingRobot.id, { name: detail.name, level: detail.level, description: detail.description, duration: detail.duration, disable: detail.disable, permissions: detail.permissions });
57
+ }
58
+ }
59
+ const metadata = await api("GET", "/projects/" + project.project_id);
60
+ if (metadata.metadata?.retention_id) {
61
+ const retention = await api("GET", "/retentions/" + metadata.metadata.retention_id);
62
+ const selector = retention.rules?.flatMap(rule => rule.tag_selectors || []).find(item => item.pattern === "{staging,production,preview,latest}");
63
+ if (selector) {
64
+ selector.pattern = "{staging,production,preview,latest,staging-previous,production-previous,preview-previous}";
65
+ await api("PUT", "/retentions/" + metadata.metadata.retention_id, retention);
66
+ }
67
+ }
68
+ if (!metadata.metadata?.retention_id)
69
+ await api("POST", "/retentions", {
70
+ algorithm: "or", scope: { level: "project", ref: project.project_id },
71
+ trigger: { kind: "Schedule", settings: { cron: "0 0 1 * * *" } },
72
+ rules: [
73
+ { id: 0, priority: 0, disabled: false, action: "retain", template: "always", tag_selectors: [{ kind: "doublestar", decoration: "matches", pattern: "{staging,production,preview,latest,staging-previous,production-previous,preview-previous}" }], scope_selectors: { repository: [{ kind: "doublestar", decoration: "repoMatches", pattern: "**" }] } },
74
+ { id: 0, priority: 0, disabled: false, action: "retain", template: "latestPushedK", params: { latestPushedK: 3 }, tag_selectors: [{ kind: "doublestar", decoration: "matches", pattern: "**" }], scope_selectors: { repository: [{ kind: "doublestar", decoration: "repoMatches", pattern: "**" }] } },
75
+ ],
76
+ });
77
+ }
78
+ // Add pull scope without replacing permissions belonging to existing installations.
79
+ const nodes = robots.find(robot => robot.name === "robot$nodes-pull");
80
+ if (!nodes)
81
+ throw new Error("The existing nodes-pull robot was not found.");
82
+ const detail = await api("GET", "/robots/" + nodes.id);
83
+ let changed = false;
84
+ for (const name of projects)
85
+ if (!detail.permissions.some(permission => permission.namespace === name)) {
86
+ detail.permissions.push({ kind: "project", namespace: name, access: [{ resource: "repository", action: "pull" }] });
87
+ changed = true;
88
+ }
89
+ if (changed)
90
+ await api("PUT", "/robots/" + nodes.id, { name: detail.name, level: detail.level, description: detail.description, duration: detail.duration, disable: detail.disable, permissions: detail.permissions });
91
+ if (Object.keys(created).length)
92
+ writeJson(privateFile, created, 0o600);
93
+ return { changes, applied: true, credentials: Object.keys(created).length ? ".secrets/registry-created.json" : "existing" };
94
+ }
95
+ export async function provisionDns(root, manifest, name, { file, apply = false } = {}) {
96
+ const target = manifest.environments[name];
97
+ if (!target?.publish.includes("cms"))
98
+ throw new Error("CMS publication is disabled.");
99
+ const platform = platformConfig(root, manifest, file), operator = operatorEnvironment(root);
100
+ const { coolifyClient } = await import("./coolify.js");
101
+ const server = await coolifyClient(platform.coolifyUrl, operator.COOLIFY_TOKEN)("GET", "/servers/" + platform.serverUuid);
102
+ const host = new URL(target.backendUrl).hostname;
103
+ const api = async (method, path, body) => {
104
+ const res = await fetch("https://api.cloudflare.com/client/v4" + path, { method, redirect: "error", signal: AbortSignal.timeout(30000), headers: { authorization: "Bearer " + operator.CLOUDFLARE_API_TOKEN, "content-type": "application/json" }, ...(body ? { body: JSON.stringify(body) } : {}) });
105
+ const data = await res.json();
106
+ if (!res.ok || !data.success)
107
+ throw new Error("DNS API refused " + method + " (HTTP " + res.status + ").");
108
+ return data.result;
109
+ };
110
+ let zone;
111
+ const labels = host.split(".");
112
+ for (let offset = 0; offset < labels.length - 1 && !zone; offset++)
113
+ zone = (await api("GET", "/zones?name=" + labels.slice(offset).join(".")))[0];
114
+ if (!zone)
115
+ throw new Error("No accessible DNS zone for the staging backend.");
116
+ const existing = await api("GET", "/zones/" + zone.id + "/dns_records?name=" + host);
117
+ if (existing.length && !existing.some(item => item.type === "A" && item.content === server.ip))
118
+ throw new Error("An existing DNS record has a different target; no record was changed.");
119
+ if (!existing.length && apply)
120
+ await api("POST", "/zones/" + zone.id + "/dns_records", { type: "A", name: host, content: server.ip, proxied: true, ttl: 1, comment: "FlowPress staging backend" });
121
+ return { host, exists: Boolean(existing.length), applied: apply, target: server.ip, frontendChanged: false };
122
+ }
123
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/ops/bootstrap.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export function registryLogin(platform: any, operator: any): void;
2
+ export function inspectDigest(image: any): any;
3
+ export function buildBase(root: any, platform: any, { push }?: {
4
+ push?: boolean | undefined;
5
+ }): {
6
+ image: string;
7
+ };
8
+ export function frontendBuild(root: any, manifest: any, name: any, { sha, buildId }: {
9
+ sha: any;
10
+ buildId: any;
11
+ }): {
12
+ env: any;
13
+ dist: any;
14
+ };
15
+ export function build(root: any, manifest: any, name: any, component: any, { sha, buildId, push, file, skipFrontend }?: {
16
+ push?: boolean | undefined;
17
+ skipFrontend?: boolean | undefined;
18
+ }): Promise<{
19
+ component: any;
20
+ environment: any;
21
+ repository: string;
22
+ tag: string;
23
+ digest: string;
24
+ sha: any;
25
+ pushed: boolean;
26
+ reused: boolean;
27
+ } | {
28
+ component: any;
29
+ environment: any;
30
+ repository: string;
31
+ tag: string;
32
+ digest: any;
33
+ sha: any;
34
+ buildId: any;
35
+ pushed: boolean;
36
+ }>;
37
+ export const packageRoot: string;
38
+ export const containers: string;
39
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/ops/build.js"],"names":[],"mappings":"AAWA,kEAGC;AACD,+CAKC;AACD;;;;EAMC;AACD;;;;;;EAqBC;AACD;;;;;;;;;;;;;;;;;;;;;GA8CC;AAvFD,iCAA6E;AAC7E,gCAA0D"}
@@ -0,0 +1,110 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { allowedComponents, identity, imageRepository, loadState, operatorEnvironment, platformConfig, readJson, releaseTag, targetConfig, writeJson } from "./config.js";
5
+ import { manifestEnvironment, resolveFrontendEnvironment, shellEnvironment } from "./environment.js";
6
+ import { buildRoutesCaddy } from "./static-config.js";
7
+ import { capture, run } from "./process.js";
8
+ import { existingDigest } from "./registry.js";
9
+ export const packageRoot = fileURLToPath(new URL("../../", import.meta.url));
10
+ export const containers = join(packageRoot, "containers");
11
+ export function registryLogin(platform, operator) {
12
+ if (!operator.REGISTRY_USERNAME || !operator.REGISTRY_PASSWORD)
13
+ throw new Error("Missing registry push/pull credentials.");
14
+ capture("docker", ["login", platform.registry, "--username", operator.REGISTRY_USERNAME, "--password-stdin"], { input: operator.REGISTRY_PASSWORD + "\n" });
15
+ }
16
+ export function inspectDigest(image) {
17
+ const result = capture("docker", ["buildx", "imagetools", "inspect", image, "--format", "{{json .Manifest}}"]);
18
+ const digest = JSON.parse(result).digest;
19
+ if (!/^sha256:[a-f0-9]{64}$/.test(digest || ""))
20
+ throw new Error("Registry returned no valid manifest digest.");
21
+ return digest;
22
+ }
23
+ export function buildBase(root, platform, { push = false } = {}) {
24
+ const version = readJson(join(packageRoot, "package.json")).version;
25
+ const image = platform.registry + "/flowpress/php-runtime:" + version;
26
+ if (push)
27
+ registryLogin(platform, operatorEnvironment(root));
28
+ run("docker", ["buildx", "build", "--platform", "linux/amd64", "--file", join(containers, "php-runtime", "Dockerfile"), "--tag", image, push ? "--push" : "--load", containers]);
29
+ return { image: push ? image.slice(0, image.lastIndexOf(":")) + "@" + inspectDigest(image) : image };
30
+ }
31
+ export function frontendBuild(root, manifest, name, { sha, buildId }) {
32
+ const values = manifestEnvironment(root, name, { ...process.env, RELEASE_SHA: sha, FRONTEND_BUILD_ID: buildId });
33
+ const env = resolveFrontendEnvironment(values, target => manifestEnvironment(root, target, {}));
34
+ const web = readJson(join(root, "apps/web/package.json"));
35
+ const childEnv = { ...process.env, ...shellEnvironment(env), RELEASE_SHA: sha, FRONTEND_BUILD_ID: buildId };
36
+ const dist = resolve(root, env.SF_DIST_DIR);
37
+ if (!dist.startsWith(root + "/"))
38
+ throw new Error("Build output must stay inside the project.");
39
+ run("pnpm", ["styleflow:build"], { cwd: root, env: childEnv });
40
+ run("pnpm", ["--filter", web.name, "build"], { cwd: root, env: childEnv });
41
+ if (env.ASTRO_OUTPUT_MODE === "static") {
42
+ if (!existsSync(join(dist, "index.html")))
43
+ throw new Error("Static build has no index.html.");
44
+ const read = name => existsSync(join(dist, name)) ? readFileSync(join(dist, name), "utf8") : "";
45
+ mkdirSync(join(dist, ".container"), { recursive: true });
46
+ writeFileSync(join(dist, ".container", "routes.caddy"), buildRoutesCaddy({
47
+ redirects: read("_redirects"), headers: read("_headers"),
48
+ media: env.FLOWPRESS_MEDIA && env.FLOWPRESS_MEDIA !== env.BACKEND_URL ? env.FLOWPRESS_MEDIA : env.BACKEND_URL + "/app/uploads",
49
+ backend: env.BACKEND_URL,
50
+ }));
51
+ writeJson(join(dist, "healthz.json"), { status: "ok", release: sha, buildId, environment: name, output: "static", backendTarget: env.FRONTEND_BACKEND_TARGET });
52
+ }
53
+ return { env, dist: env.SF_DIST_DIR };
54
+ }
55
+ export async function build(root, manifest, name, component, { sha, buildId, push = false, file, skipFrontend = false } = {}) {
56
+ const target = targetConfig(manifest, name);
57
+ const supported = component === "cms" ? ["backend", "headless-static", "headless-ssr"] : null;
58
+ if (supported && !supported.includes(target.profile || manifest.profile))
59
+ throw new Error("Profile does not contain a CMS.");
60
+ if (!["cms", "web-static", "web-ssr"].includes(component))
61
+ throw new Error("Unknown component.");
62
+ if (push)
63
+ allowedComponents(manifest, name, [component]);
64
+ const platform = platformConfig(root, manifest, file);
65
+ const project = identity(root);
66
+ const revision = sha || capture("git", ["rev-parse", "HEAD"], { cwd: root });
67
+ const id = buildId || String(Date.now());
68
+ const tag = releaseTag(component, name, revision, id);
69
+ const repository = imageRepository(platform, project.slug, component);
70
+ const operator = operatorEnvironment(root);
71
+ if (push)
72
+ registryLogin(platform, operator);
73
+ mkdirSync(join(root, ".local/flowpress"), { recursive: true, mode: 0o700 });
74
+ if (push && component === "cms") {
75
+ const digest = await existingDigest(repository + ":" + tag, operator);
76
+ if (digest) {
77
+ const result = { component, environment: name, repository, tag, digest, sha: revision, pushed: true, reused: true };
78
+ writeJson(join(root, ".local/flowpress", "release-" + name + "-" + component + ".json"), result, 0o600);
79
+ return result;
80
+ }
81
+ }
82
+ const metadata = join(root, ".local/flowpress", "build-" + name + "-" + component + ".json");
83
+ const args = ["buildx", "build", "--platform", "linux/amd64", "--file", join(containers, component, "Dockerfile"),
84
+ "--build-context", "flowpress=" + containers, "--tag", repository + ":" + tag,
85
+ "--build-arg", "RELEASE_SHA=" + revision, "--metadata-file", metadata, push ? "--push" : "--load"];
86
+ if (component !== "cms")
87
+ args.push("--build-arg", "FRONTEND_BUILD_ID=" + id);
88
+ if (component === "cms") {
89
+ if (!platform.phpImage)
90
+ throw new Error("Build and pin the shared PHP runtime first.");
91
+ args.push("--build-arg", "FLOWPRESS_PHP_IMAGE=" + platform.phpImage);
92
+ const authFile = join(root, "apps/cms/auth.json");
93
+ const composerAuth = operator.COMPOSER_AUTH || (existsSync(authFile) ? readFileSync(authFile, "utf8") : "");
94
+ if (!composerAuth)
95
+ throw new Error("COMPOSER_AUTH or private apps/cms/auth.json is required.");
96
+ args.push("--secret", "id=composer_auth,env=COMPOSER_AUTH");
97
+ run("docker", [...args, "."], { cwd: root, env: { ...process.env, COMPOSER_AUTH: composerAuth } });
98
+ }
99
+ else {
100
+ const frontend = skipFrontend ? { dist: manifestEnvironment(root, name).SF_DIST_DIR } : frontendBuild(root, manifest, name, { sha: revision, buildId: id });
101
+ const web = readJson(join(root, "apps/web/package.json"));
102
+ args.push("--build-arg", "DIST_DIR=" + frontend.dist, "--build-arg", "WEB_PACKAGE=" + web.name);
103
+ run("docker", [...args, "."], { cwd: root });
104
+ }
105
+ const digest = push ? inspectDigest(repository + ":" + tag) : undefined;
106
+ const result = { component, environment: name, repository, tag, digest, sha: revision, buildId: component === "cms" ? undefined : id, pushed: push };
107
+ writeJson(join(root, ".local/flowpress", "release-" + name + "-" + component + ".json"), result, 0o600);
108
+ return result;
109
+ }
110
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/ops/build.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export function checkProject(root: any, kind: any): {
2
+ features: string;
3
+ phpFiles?: undefined;
4
+ checks?: undefined;
5
+ manifest?: undefined;
6
+ } | {
7
+ phpFiles: number;
8
+ features?: undefined;
9
+ checks?: undefined;
10
+ manifest?: undefined;
11
+ } | {
12
+ checks: string[];
13
+ manifest: string;
14
+ features?: undefined;
15
+ phpFiles?: undefined;
16
+ };
17
+ export const projectChecks: string[];
18
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/ops/check.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;EA2BC;AA5BD,qCAAkP"}
@@ -0,0 +1,46 @@
1
+ import { existsSync, readdirSync, statSync } from "node:fs";
2
+ import { join, extname } from "node:path";
3
+ import { readJson, readManifest } from "./config.js";
4
+ import { run } from "./process.js";
5
+ export const projectChecks = ["styleflow:validate", "styleflow:build", "components:check", "project:scaffold:check", "features:check", "check:boundaries", "check:forbidden", "check:php", "typecheck", "test", "web:check", "test:static-build"];
6
+ export function checkProject(root, kind) {
7
+ if (kind === "features") {
8
+ const features = readJson(join(root, "flowpress.features.json"));
9
+ if (features?.schemaVersion !== 1 || !Array.isArray(features.features))
10
+ throw new Error("Invalid feature manifest.");
11
+ for (const feature of features.features.filter(item => item.enabled))
12
+ run("pnpm", ["exec", "flowpress-scaffold", "feature", "check", feature.id], { cwd: root });
13
+ return { features: "valid" };
14
+ }
15
+ if (kind === "php") {
16
+ const files = [];
17
+ function collect(path) {
18
+ if (!existsSync(path))
19
+ return;
20
+ if (statSync(path).isFile()) {
21
+ if (extname(path) === ".php")
22
+ files.push(path);
23
+ return;
24
+ }
25
+ for (const item of readdirSync(path))
26
+ if (!["vendor", "node_modules", "dist"].includes(item))
27
+ collect(join(path, item));
28
+ }
29
+ for (const name of ["check-updates.php", "config", "project", "tests", "web/index.php", "web/wp-config.php", "web/app/mu-plugins/bedrock-autoloader.php"])
30
+ collect(join(root, "apps/cms", name));
31
+ for (const file of files)
32
+ run("php", ["-l", file], { stdio: "pipe", encoding: "utf8" });
33
+ return { phpFiles: files.length };
34
+ }
35
+ if (kind)
36
+ throw new Error("Use check [features|php].");
37
+ readManifest(root);
38
+ const scripts = readJson(join(root, "package.json")).scripts || {};
39
+ const selected = projectChecks.filter(key => scripts[key]);
40
+ for (const key of selected) {
41
+ console.info("[check] " + key);
42
+ run("pnpm", ["run", key], { cwd: root });
43
+ }
44
+ return { checks: selected, manifest: "valid" };
45
+ }
46
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/ops/check.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/ops/cli.js"],"names":[],"mappings":""}
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ import { allowedComponents, identity, loadState, operatorEnvironment, platformConfig, projectRoot, readManifest, saveState } from "./config.js";
3
+ import { argValue, containerFor, shellQuote, ssh } from "./process.js";
4
+ import { build, buildBase, frontendBuild } from "./build.js";
5
+ import { deploy, deployedRelease } from "./deploy.js";
6
+ import { provision, provisionPlatform } from "./provision.js";
7
+ import { pullSource, prepareData, pushData, pushUploads, cleanIntegrations } from "./data.js";
8
+ import { backupRun, backupVerify, status } from "./monitor.js";
9
+ import { coolifyClient } from "./coolify.js";
10
+ import { release, editorialCommit } from "./release.js";
11
+ import { readFileSync, appendFileSync } from "node:fs";
12
+ import { provisionRegistry, provisionDns } from "./bootstrap.js";
13
+ import { synchronizeEnvironmentFiles } from "./environment-files.js";
14
+ import { localCommand } from "./local.js";
15
+ import { checkProject } from "./check.js";
16
+ const args = process.argv.slice(2);
17
+ const [command, name, component] = args;
18
+ function help() {
19
+ return "FlowPress Ops\n\n"
20
+ + " flowpress-ops plan|provision <environment> [component] [--apply]\n"
21
+ + " flowpress-ops env sync [--apply] [--local-secrets]\n"
22
+ + " flowpress-ops local start|stop|status|doctor|logs|exec|backup|datagrip\n"
23
+ + " flowpress-ops check [features|php] | cms install\n"
24
+ + " flowpress-ops platform plan|provision|build-base [--apply] [--push]\n"
25
+ + " flowpress-ops registry [--apply] | dns <environment> [--apply]\n"
26
+ + " flowpress-ops build <environment> <cms|web-static|web-ssr> [--push] [--sha SHA]\n"
27
+ + " flowpress-ops frontend <environment> [--sha SHA] [--build-id ID]\n"
28
+ + " flowpress-ops deploy|rollback <environment> <component>\n"
29
+ + " flowpress-ops release <environment> [component] [--editorial]\n"
30
+ + " flowpress-ops db pull <source> | prepare <environment> --from FILE | push <environment> --from FILE\n"
31
+ + " flowpress-ops db clean-integrations <environment>\n"
32
+ + " flowpress-ops uploads <environment> --from ARCHIVE\n"
33
+ + " flowpress-ops backup run|verify <environment>\n"
34
+ + " flowpress-ops preview start|stop [--backend staging|production]\n"
35
+ + " flowpress-ops status [environment] [--check] [--json]\n"
36
+ + " flowpress-ops logs <environment> [component]\n\n"
37
+ + "Provisioning is read-only without --apply. Publish lists are enforced by every remote write.\n";
38
+ }
39
+ async function main() {
40
+ if (!command || ["--help", "-h"].includes(command)) {
41
+ console.log(help());
42
+ return;
43
+ }
44
+ const root = projectRoot(), manifest = readManifest(root);
45
+ const file = argValue(args, "--platform-file");
46
+ let result;
47
+ if (command === "check") {
48
+ result = checkProject(root, name);
49
+ }
50
+ else if (command === "cms" && name === "install") {
51
+ const { run } = await import("./process.js");
52
+ run("composer", ["install", "--working-dir=apps/cms", "--no-interaction", "--prefer-dist", "--optimize-autoloader"], { cwd: root });
53
+ result = { cms: "installed" };
54
+ }
55
+ else if (command === "local") {
56
+ result = await localCommand(root, manifest, name, args.slice(2));
57
+ }
58
+ else if (command === "env") {
59
+ if (name !== "sync")
60
+ throw new Error("Use env sync [--apply] [--local-secrets].");
61
+ result = synchronizeEnvironmentFiles(root, { apply: args.includes("--apply"), localSecrets: args.includes("--local-secrets") });
62
+ }
63
+ else if (command === "validate") {
64
+ result = { project: identity(root).slug, profile: manifest.profile, environments: Object.fromEntries(Object.entries(manifest.environments).map(([key, value]) => [key, value.publish])) };
65
+ }
66
+ else if (command === "plan" || command === "provision") {
67
+ result = await provision(root, manifest, name, { file, apply: command === "provision" && args.includes("--apply"), components: component && !component.startsWith("--") ? [component] : [] });
68
+ }
69
+ else if (command === "platform") {
70
+ if (name === "build-base")
71
+ result = buildBase(root, platformConfig(root, manifest, file), { push: args.includes("--push") });
72
+ else if (["plan", "provision"].includes(name))
73
+ result = await provisionPlatform(root, manifest, { file, apply: name === "provision" && args.includes("--apply") });
74
+ else
75
+ throw new Error("Use platform plan|provision|build-base.");
76
+ }
77
+ else if (command === "registry") {
78
+ result = await provisionRegistry(root, manifest, { file, apply: args.includes("--apply") });
79
+ }
80
+ else if (command === "dns") {
81
+ result = await provisionDns(root, manifest, name, { file, apply: args.includes("--apply") });
82
+ }
83
+ else if (command === "build") {
84
+ result = await build(root, manifest, name, component, { file, push: args.includes("--push"), sha: argValue(args, "--sha"), buildId: argValue(args, "--build-id"), skipFrontend: args.includes("--skip-frontend") });
85
+ }
86
+ else if (command === "frontend") {
87
+ result = frontendBuild(root, manifest, name, { sha: argValue(args, "--sha") || (await import("./process.js")).capture("git", ["rev-parse", "HEAD"], { cwd: root }), buildId: argValue(args, "--build-id") || String(Date.now()) });
88
+ result = { environment: name, output: result.dist };
89
+ }
90
+ else if (command === "deploy" || command === "rollback") {
91
+ result = await deploy(root, manifest, name, component, { rollback: command === "rollback" });
92
+ }
93
+ else if (command === "release") {
94
+ result = await release(root, manifest, name, { component: component && !component.startsWith("--") ? component : undefined, sha: argValue(args, "--sha"), buildId: argValue(args, "--build-id"), editorial: args.includes("--editorial") });
95
+ }
96
+ else if (command === "editorial") {
97
+ const event = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, "utf8"));
98
+ result = await editorialCommit(root, manifest, event.client_payload);
99
+ if (process.env.GITHUB_OUTPUT)
100
+ appendFileSync(process.env.GITHUB_OUTPUT, "sha=" + result.sha + "\ntarget=" + result.request.target + "\n");
101
+ }
102
+ else if (command === "db") {
103
+ const target = component;
104
+ if (name === "pull")
105
+ result = await pullSource(root, manifest, target);
106
+ else if (name === "prepare")
107
+ result = await prepareData(root, manifest, target, { file: argValue(args, "--from"), source: argValue(args, "--source") || "production", image: argValue(args, "--image") });
108
+ else if (name === "clean-integrations")
109
+ result = await cleanIntegrations(root, manifest, target);
110
+ else if (name === "push")
111
+ result = await pushData(root, manifest, target, argValue(args, "--from"));
112
+ else
113
+ throw new Error("Use db pull|prepare|push.");
114
+ }
115
+ else if (command === "uploads")
116
+ result = await pushUploads(root, manifest, name, argValue(args, "--from"));
117
+ else if (command === "backup")
118
+ result = await (name === "run" ? backupRun : name === "verify" ? backupVerify : () => { throw new Error("Use backup run|verify."); })(root, manifest, component);
119
+ else if (command === "status") {
120
+ result = await status(root, manifest, name && !name.startsWith("--") ? name : undefined);
121
+ if (args.includes("--check") && !result.ok)
122
+ process.exitCode = 1;
123
+ }
124
+ else if (command === "logs") {
125
+ const state = loadState(root, name), app = state.apps?.[component || "cms"];
126
+ if (!app?.uuid)
127
+ throw new Error("Component not provisioned.");
128
+ console.log(ssh(state.platform, "docker logs --tail 100 " + shellQuote(containerFor(state.platform, app.uuid))));
129
+ return;
130
+ }
131
+ else if (command === "preview") {
132
+ allowedComponents(manifest, "preview", ["web-ssr"]);
133
+ const target = manifest.environments.preview;
134
+ if (argValue(args, "--backend") && argValue(args, "--backend") !== target.backend)
135
+ throw new Error("Update the manifest backend before starting preview.");
136
+ if (!["start", "stop"].includes(name))
137
+ throw new Error("Use preview start|stop.");
138
+ const state = loadState(root, "preview"), app = state.apps?.["web-ssr"];
139
+ if (!app?.uuid)
140
+ throw new Error("Provision preview first.");
141
+ if (name === "start") {
142
+ const current = await deployedRelease(root, "preview", "web-ssr");
143
+ if (!current)
144
+ throw new Error("Build and deploy preview once before starting it.");
145
+ result = await deploy(root, manifest, "preview", "web-ssr", { release: current });
146
+ }
147
+ else {
148
+ const api = coolifyClient(state.platform.coolifyUrl, operatorEnvironment(root).COOLIFY_TOKEN);
149
+ await api("POST", "/applications/" + app.uuid + "/stop");
150
+ result = { preview: "stopped", dataPreserved: true };
151
+ }
152
+ }
153
+ else
154
+ throw new Error("Unknown command. Use --help.");
155
+ if (args.includes("--json"))
156
+ console.log(JSON.stringify(result, null, 2));
157
+ else {
158
+ console.log("FlowPress: " + command + (name ? " " + name : ""));
159
+ console.log(JSON.stringify(result, null, 2));
160
+ }
161
+ }
162
+ main().catch(error => {
163
+ console.error("FlowPress: " + error.message);
164
+ process.exitCode = 1;
165
+ });
166
+ //# sourceMappingURL=cli.js.map