@tekki-forge/generator-docker 0.0.0-stage → 0.1.0
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/README.md +4 -2
- package/dist/index.d.ts +7 -0
- package/dist/index.js +135 -0
- package/dist/index.js.map +1 -0
- package/package.json +36 -3
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tekki-forge/generator-docker
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Forge generator: IR -> Docker and Compose configuration.
|
|
4
|
+
|
|
5
|
+
Part of [Tekki Forge](https://www.npmjs.com/package/tekki-forge), which turns a `forge.config.ts` into a production-ready full-stack app. Apps created with `forge new` install this package for you; see the [tekki-forge](https://www.npmjs.com/package/tekki-forge) package for the documentation.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AppIR, type GeneratedFile, type Generator } from "@tekki-forge/compiler";
|
|
2
|
+
/**
|
|
3
|
+
* Docker files are developer-owned after creation (scaffold): teams customize them.
|
|
4
|
+
* `forge docker --force` rewrites them from the current template.
|
|
5
|
+
*/
|
|
6
|
+
export declare function dockerFiles(ir: AppIR, ownership?: GeneratedFile["ownership"]): GeneratedFile[];
|
|
7
|
+
export declare const dockerGenerator: Generator;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {} from "@tekki-forge/compiler";
|
|
2
|
+
import { stringify } from "yaml";
|
|
3
|
+
/**
|
|
4
|
+
* Docker files are developer-owned after creation (scaffold): teams customize them.
|
|
5
|
+
* `forge docker --force` rewrites them from the current template.
|
|
6
|
+
*/
|
|
7
|
+
export function dockerFiles(ir, ownership = "scaffold") {
|
|
8
|
+
const db = ir.slug.replace(/-/g, "_");
|
|
9
|
+
const apiEnv = {
|
|
10
|
+
DATABASE_URL: `postgresql://app:app@postgres:5432/${db}`,
|
|
11
|
+
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:-change-me-in-production-use-openssl-rand-base64-32}",
|
|
12
|
+
BETTER_AUTH_URL: "${PUBLIC_URL:-http://localhost:${WEB_PORT:-3000}}",
|
|
13
|
+
PORT: "4000",
|
|
14
|
+
SEED: "${SEED:-true}",
|
|
15
|
+
ADMIN_EMAIL: "${ADMIN_EMAIL:-admin@example.com}",
|
|
16
|
+
ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin12345}",
|
|
17
|
+
SMTP_URL: "${SMTP_URL:-}",
|
|
18
|
+
RESEND_API_KEY: "${RESEND_API_KEY:-}",
|
|
19
|
+
EMAIL_FROM: "${EMAIL_FROM:-}",
|
|
20
|
+
};
|
|
21
|
+
for (const p of ir.auth.social) {
|
|
22
|
+
const key = p.toUpperCase();
|
|
23
|
+
apiEnv[`${key}_CLIENT_ID`] = `\${${key}_CLIENT_ID:-}`;
|
|
24
|
+
apiEnv[`${key}_CLIENT_SECRET`] = `\${${key}_CLIENT_SECRET:-}`;
|
|
25
|
+
}
|
|
26
|
+
const dependsOn = { postgres: { condition: "service_healthy" } };
|
|
27
|
+
const services = {
|
|
28
|
+
postgres: {
|
|
29
|
+
image: "postgres:17-alpine",
|
|
30
|
+
restart: "unless-stopped",
|
|
31
|
+
environment: { POSTGRES_DB: db, POSTGRES_USER: "app", POSTGRES_PASSWORD: "app" },
|
|
32
|
+
ports: ["${POSTGRES_PORT:-5432}:5432"],
|
|
33
|
+
volumes: ["postgres_data:/var/lib/postgresql/data"],
|
|
34
|
+
healthcheck: { test: ["CMD-SHELL", `pg_isready -U app -d ${db}`], interval: "3s", timeout: "3s", retries: 20 },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const volumes = { postgres_data: null };
|
|
38
|
+
for (const plugin of ir.plugins) {
|
|
39
|
+
for (const [name, svc] of Object.entries(plugin.docker.services)) {
|
|
40
|
+
services[name] = { restart: "unless-stopped", ...svc };
|
|
41
|
+
dependsOn[name] = { condition: svc.healthcheck ? "service_healthy" : "service_started" };
|
|
42
|
+
}
|
|
43
|
+
for (const v of plugin.docker.volumes)
|
|
44
|
+
volumes[v] = null;
|
|
45
|
+
for (const e of plugin.env)
|
|
46
|
+
if (e.docker !== undefined)
|
|
47
|
+
apiEnv[e.name] = `\${${e.name}:-${e.docker}}`;
|
|
48
|
+
}
|
|
49
|
+
const workers = ir.plugins.some((p) => p.runtime.worker);
|
|
50
|
+
if (workers && ir.backups)
|
|
51
|
+
volumes.backups = null;
|
|
52
|
+
services.api = {
|
|
53
|
+
build: { context: ".", dockerfile: "Dockerfile.api" },
|
|
54
|
+
restart: "unless-stopped",
|
|
55
|
+
depends_on: dependsOn,
|
|
56
|
+
environment: apiEnv,
|
|
57
|
+
ports: ["${API_PORT:-4000}:4000"],
|
|
58
|
+
};
|
|
59
|
+
if (workers) {
|
|
60
|
+
services.worker = {
|
|
61
|
+
build: { context: ".", dockerfile: "Dockerfile.api" },
|
|
62
|
+
restart: "unless-stopped",
|
|
63
|
+
command: ["sh", "-c", "pnpm worker"],
|
|
64
|
+
depends_on: { ...dependsOn, api: { condition: "service_started" } },
|
|
65
|
+
environment: { ...apiEnv, SEED: "false", ...(ir.backups ? { FORGE_BACKUP_DIR: "/backups" } : {}) },
|
|
66
|
+
// Scheduled backups (backups in forge.config.ts) land here unless the storage plugin uses S3.
|
|
67
|
+
...(ir.backups ? { volumes: ["backups:/backups"] } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
services.web = {
|
|
71
|
+
build: { context: ".", dockerfile: "Dockerfile.web" },
|
|
72
|
+
restart: "unless-stopped",
|
|
73
|
+
depends_on: ["api"],
|
|
74
|
+
environment: { API_INTERNAL_URL: "http://api:4000" },
|
|
75
|
+
ports: ["${WEB_PORT:-3000}:3000"],
|
|
76
|
+
};
|
|
77
|
+
const compose = `# Generated by Forge. Safe to edit — \`forge generate\` never touches this file.\n${stringify({ name: ir.slug, services, volumes }, { lineWidth: 0, nullStr: "", aliasDuplicateObjects: false })}`;
|
|
78
|
+
const base = `FROM node:24-alpine AS base
|
|
79
|
+
ENV PNPM_HOME=/pnpm PATH=/pnpm:$PATH CI=true NEXT_TELEMETRY_DISABLED=1
|
|
80
|
+
RUN corepack enable
|
|
81
|
+
WORKDIR /app
|
|
82
|
+
`;
|
|
83
|
+
const dockerfileApi = `# Generated by Forge. Safe to edit.
|
|
84
|
+
${base}
|
|
85
|
+
FROM base AS deps
|
|
86
|
+
COPY . .
|
|
87
|
+
RUN pnpm install --frozen-lockfile --filter "@app/api..." \\
|
|
88
|
+
&& pnpm --filter @app/database exec prisma generate
|
|
89
|
+
|
|
90
|
+
FROM deps AS runner
|
|
91
|
+
ENV NODE_ENV=production
|
|
92
|
+
# pg_dump/psql matching the PostgreSQL 17 server, for scheduled backups (forge backup).
|
|
93
|
+
RUN apk add --no-cache postgresql17-client
|
|
94
|
+
WORKDIR /app/apps/api
|
|
95
|
+
EXPOSE 4000
|
|
96
|
+
CMD ["sh", "-c", "pnpm --filter @app/database exec prisma migrate deploy && if [ \\"$SEED\\" = \\"true\\" ]; then pnpm seed; fi && pnpm start"]
|
|
97
|
+
`;
|
|
98
|
+
const dockerfileWeb = `# Generated by Forge. Safe to edit.
|
|
99
|
+
${base}
|
|
100
|
+
FROM base AS build
|
|
101
|
+
COPY . .
|
|
102
|
+
RUN pnpm install --frozen-lockfile --filter "@app/web..." \\
|
|
103
|
+
&& pnpm --filter @app/web build
|
|
104
|
+
|
|
105
|
+
FROM base AS runner
|
|
106
|
+
ENV NODE_ENV=production HOSTNAME=0.0.0.0 PORT=3000
|
|
107
|
+
WORKDIR /app
|
|
108
|
+
COPY --from=build /app/apps/web/.next/standalone ./
|
|
109
|
+
COPY --from=build /app/apps/web/.next/static ./apps/web/.next/static
|
|
110
|
+
COPY --from=build /app/apps/web/public ./apps/web/public
|
|
111
|
+
EXPOSE 3000
|
|
112
|
+
CMD ["node", "apps/web/server.js"]
|
|
113
|
+
`;
|
|
114
|
+
const dockerignore = `**/node_modules
|
|
115
|
+
**/.next
|
|
116
|
+
**/dist
|
|
117
|
+
**/.turbo
|
|
118
|
+
**/src/generated/prisma
|
|
119
|
+
.env
|
|
120
|
+
.env.*
|
|
121
|
+
!.env.example
|
|
122
|
+
.git
|
|
123
|
+
`;
|
|
124
|
+
return [
|
|
125
|
+
{ path: "docker-compose.yml", contents: compose, ownership },
|
|
126
|
+
{ path: "Dockerfile.api", contents: dockerfileApi, ownership },
|
|
127
|
+
{ path: "Dockerfile.web", contents: dockerfileWeb, ownership },
|
|
128
|
+
{ path: ".dockerignore", contents: dockerignore, ownership },
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
export const dockerGenerator = {
|
|
132
|
+
name: "docker",
|
|
133
|
+
generate: (ir) => dockerFiles(ir),
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekki-forge/generator-docker",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Forge generator: IR -> Docker and Compose configuration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"code-generator",
|
|
7
|
+
"forge",
|
|
8
|
+
"full-stack",
|
|
9
|
+
"tekki-forge"
|
|
10
|
+
],
|
|
11
|
+
"author": "Mahy KANE",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"yaml": "^2.9.1",
|
|
33
|
+
"@tekki-forge/compiler": "^0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
38
|
+
}
|
|
6
39
|
}
|