@empire-builder-kit/containers 0.0.1-alpha.4

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 (81) hide show
  1. package/README.md +20 -0
  2. package/dist/executors.json +3 -0
  3. package/dist/generators/service/files-go/Dockerfile.template +11 -0
  4. package/dist/generators/service/files-go/README.md.template +11 -0
  5. package/dist/generators/service/files-go/cmd/main.go.template +34 -0
  6. package/dist/generators/service/files-go/docs/contracts.md.template +9 -0
  7. package/dist/generators/service/files-go/go.mod.template +3 -0
  8. package/dist/generators/service/files-python/Dockerfile.template +12 -0
  9. package/dist/generators/service/files-python/README.md.template +11 -0
  10. package/dist/generators/service/files-python/docs/contracts.md.template +9 -0
  11. package/dist/generators/service/files-python/pyproject.toml.template +15 -0
  12. package/dist/generators/service/files-python/src/main.py.template +20 -0
  13. package/dist/generators/service/files-rust/Cargo.toml.template +16 -0
  14. package/dist/generators/service/files-rust/Dockerfile.template +12 -0
  15. package/dist/generators/service/files-rust/README.md.template +11 -0
  16. package/dist/generators/service/files-rust/docs/contracts.md.template +9 -0
  17. package/dist/generators/service/files-rust/src/main.rs.template +29 -0
  18. package/dist/generators/service/files-typescript/Dockerfile.template +30 -0
  19. package/dist/generators/service/files-typescript/README.md.template +24 -0
  20. package/dist/generators/service/files-typescript/docs/architecture.md.template +18 -0
  21. package/dist/generators/service/files-typescript/docs/contracts.md.template +20 -0
  22. package/dist/generators/service/files-typescript/docs/operations.md.template +24 -0
  23. package/dist/generators/service/files-typescript/eslint.config.mjs.template +3 -0
  24. package/dist/generators/service/files-typescript/infra/service.ts.template +64 -0
  25. package/dist/generators/service/files-typescript/package.json.template +7 -0
  26. package/dist/generators/service/files-typescript/src/index.ts.template +2 -0
  27. package/dist/generators/service/files-typescript/src/main.ts.template +60 -0
  28. package/dist/generators/service/files-typescript/src/service.spec.ts.template +49 -0
  29. package/dist/generators/service/files-typescript/src/service.ts.template +57 -0
  30. package/dist/generators/service/files-typescript/tsconfig.app.json.template +12 -0
  31. package/dist/generators/service/files-typescript/tsconfig.json.template +7 -0
  32. package/dist/generators/service/files-typescript/tsconfig.spec.json.template +7 -0
  33. package/dist/generators/service/files-typescript/vitest.config.mts.template +17 -0
  34. package/dist/generators/service/schema.d.ts +8 -0
  35. package/dist/generators/service/schema.json +40 -0
  36. package/dist/generators/service/service.d.ts +5 -0
  37. package/dist/generators/service/service.d.ts.map +1 -0
  38. package/dist/generators/service/service.js +198 -0
  39. package/dist/generators/task/files-go/Dockerfile.template +10 -0
  40. package/dist/generators/task/files-go/README.md.template +11 -0
  41. package/dist/generators/task/files-go/cmd/main.go.template +22 -0
  42. package/dist/generators/task/files-go/docs/contracts.md.template +9 -0
  43. package/dist/generators/task/files-go/go.mod.template +3 -0
  44. package/dist/generators/task/files-python/Dockerfile.template +10 -0
  45. package/dist/generators/task/files-python/README.md.template +11 -0
  46. package/dist/generators/task/files-python/docs/contracts.md.template +9 -0
  47. package/dist/generators/task/files-python/pyproject.toml.template +12 -0
  48. package/dist/generators/task/files-python/src/main.py.template +26 -0
  49. package/dist/generators/task/files-rust/Cargo.toml.template +15 -0
  50. package/dist/generators/task/files-rust/Dockerfile.template +11 -0
  51. package/dist/generators/task/files-rust/README.md.template +11 -0
  52. package/dist/generators/task/files-rust/docs/contracts.md.template +9 -0
  53. package/dist/generators/task/files-rust/src/main.rs.template +12 -0
  54. package/dist/generators/task/files-typescript/Dockerfile.template +25 -0
  55. package/dist/generators/task/files-typescript/README.md.template +24 -0
  56. package/dist/generators/task/files-typescript/docs/architecture.md.template +18 -0
  57. package/dist/generators/task/files-typescript/docs/contracts.md.template +20 -0
  58. package/dist/generators/task/files-typescript/docs/operations.md.template +24 -0
  59. package/dist/generators/task/files-typescript/eslint.config.mjs.template +3 -0
  60. package/dist/generators/task/files-typescript/infra/task.ts.template +35 -0
  61. package/dist/generators/task/files-typescript/package.json.template +7 -0
  62. package/dist/generators/task/files-typescript/src/index.ts.template +6 -0
  63. package/dist/generators/task/files-typescript/src/main.ts.template +45 -0
  64. package/dist/generators/task/files-typescript/src/task.spec.ts.template +66 -0
  65. package/dist/generators/task/files-typescript/src/task.ts.template +71 -0
  66. package/dist/generators/task/files-typescript/tsconfig.app.json.template +13 -0
  67. package/dist/generators/task/files-typescript/tsconfig.json.template +19 -0
  68. package/dist/generators/task/files-typescript/tsconfig.spec.json.template +11 -0
  69. package/dist/generators/task/files-typescript/vitest.config.mts.template +9 -0
  70. package/dist/generators/task/schema.d.ts +8 -0
  71. package/dist/generators/task/schema.json +40 -0
  72. package/dist/generators/task/task.d.ts +5 -0
  73. package/dist/generators/task/task.d.ts.map +1 -0
  74. package/dist/generators/task/task.js +198 -0
  75. package/dist/generators.json +14 -0
  76. package/dist/index.d.ts +3 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +7 -0
  79. package/executors.json +3 -0
  80. package/generators.json +14 -0
  81. package/package.json +92 -0
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ root: __dirname,
5
+ cacheDir: '<%= offsetFromRoot %>node_modules/.vite/<%= projectRoot %>',
6
+ test: {
7
+ name: '<%= projectName %>',
8
+ watch: false,
9
+ environment: 'node',
10
+ include: ['src/**/*.{test,spec}.ts'],
11
+ reporters: ['default'],
12
+ coverage: {
13
+ provider: 'v8',
14
+ reportsDirectory: './test-output/vitest/coverage',
15
+ },
16
+ },
17
+ });
@@ -0,0 +1,8 @@
1
+ export interface ServiceGeneratorSchema {
2
+ name: string;
3
+ app: string;
4
+ language?: 'typescript' | 'rust' | 'go' | 'python';
5
+ directory?: string;
6
+ skipFormat?: boolean;
7
+ tags?: string;
8
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "Service",
4
+ "title": "Generate an EBK container service",
5
+ "type": "object",
6
+ "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "description": "Name for the service within the app group.",
10
+ "$default": { "$source": "argv", "index": 0 },
11
+ "x-prompt": "What name should the service have?"
12
+ },
13
+ "app": {
14
+ "type": "string",
15
+ "description": "Owning Empire Builder Kit app-group name.",
16
+ "x-prompt": "Which app group should receive the service?"
17
+ },
18
+ "language": {
19
+ "type": "string",
20
+ "description": "Programming language for the service.",
21
+ "enum": ["typescript", "rust", "go", "python"],
22
+ "default": "typescript"
23
+ },
24
+ "directory": {
25
+ "type": "string",
26
+ "description": "Base directory for app groups.",
27
+ "default": "packages"
28
+ },
29
+ "tags": {
30
+ "type": "string",
31
+ "description": "Comma-separated additional tags to apply to the project."
32
+ },
33
+ "skipFormat": {
34
+ "type": "boolean",
35
+ "description": "Skip formatting files.",
36
+ "default": false
37
+ }
38
+ },
39
+ "required": ["name", "app"]
40
+ }
@@ -0,0 +1,5 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { ServiceGeneratorSchema } from './schema';
3
+ export declare function serviceGenerator(tree: Tree, options: ServiceGeneratorSchema): Promise<void>;
4
+ export default serviceGenerator;
5
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/generators/service/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AA+MlD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,sBAAsB,iBA8ChC;AAED,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serviceGenerator = serviceGenerator;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const path = tslib_1.__importStar(require("node:path"));
7
+ function runtimeForLanguage(language) {
8
+ switch (language) {
9
+ case 'typescript':
10
+ return 'node';
11
+ case 'rust':
12
+ return 'native';
13
+ case 'go':
14
+ return 'native';
15
+ case 'python':
16
+ return 'python';
17
+ }
18
+ }
19
+ function targetsForLanguage(language, projectRoot, projectName, outputPath) {
20
+ const cwd = projectRoot;
21
+ switch (language) {
22
+ case 'typescript':
23
+ return {
24
+ build: {
25
+ executor: 'nx:run-commands',
26
+ outputs: [`{workspaceRoot}/${outputPath}`],
27
+ options: { cwd, command: 'tsc -p tsconfig.app.json' },
28
+ },
29
+ lint: {
30
+ executor: 'nx:run-commands',
31
+ options: { cwd, command: 'eslint .' },
32
+ },
33
+ typecheck: {
34
+ executor: 'nx:run-commands',
35
+ options: { cwd, command: 'tsc --noEmit -p tsconfig.json' },
36
+ },
37
+ test: {
38
+ executor: 'nx:run-commands',
39
+ options: {
40
+ cwd,
41
+ command: 'vitest run --config vitest.config.mts',
42
+ },
43
+ },
44
+ dev: {
45
+ executor: 'nx:run-commands',
46
+ options: {
47
+ cwd,
48
+ command: 'node --watch --enable-source-maps --import @swc-node/register/esm-register src/main.ts',
49
+ },
50
+ },
51
+ 'docker-build': {
52
+ executor: 'nx:run-commands',
53
+ options: {
54
+ command: `docker build --tag ${projectName} ${projectRoot}`,
55
+ },
56
+ },
57
+ };
58
+ case 'rust':
59
+ return {
60
+ build: {
61
+ executor: 'nx:run-commands',
62
+ options: { cwd, command: 'cargo build --release' },
63
+ },
64
+ lint: {
65
+ executor: 'nx:run-commands',
66
+ options: { cwd, command: 'cargo clippy -- -D warnings' },
67
+ },
68
+ test: {
69
+ executor: 'nx:run-commands',
70
+ options: { cwd, command: 'cargo test' },
71
+ },
72
+ dev: {
73
+ executor: 'nx:run-commands',
74
+ options: { cwd, command: 'cargo watch -x run' },
75
+ },
76
+ 'docker-build': {
77
+ executor: 'nx:run-commands',
78
+ options: {
79
+ command: `docker build --tag ${projectName} ${projectRoot}`,
80
+ },
81
+ },
82
+ };
83
+ case 'go':
84
+ return {
85
+ build: {
86
+ executor: 'nx:run-commands',
87
+ options: { cwd, command: 'go build -o bin/service ./cmd/...' },
88
+ },
89
+ lint: {
90
+ executor: 'nx:run-commands',
91
+ options: { cwd, command: 'golangci-lint run' },
92
+ },
93
+ typecheck: {
94
+ executor: 'nx:run-commands',
95
+ options: { cwd, command: 'go vet ./...' },
96
+ },
97
+ test: {
98
+ executor: 'nx:run-commands',
99
+ options: { cwd, command: 'go test ./...' },
100
+ },
101
+ dev: {
102
+ executor: 'nx:run-commands',
103
+ options: { cwd, command: 'go run ./cmd/...' },
104
+ },
105
+ 'docker-build': {
106
+ executor: 'nx:run-commands',
107
+ options: {
108
+ command: `docker build --tag ${projectName} ${projectRoot}`,
109
+ },
110
+ },
111
+ };
112
+ case 'python':
113
+ return {
114
+ lint: {
115
+ executor: 'nx:run-commands',
116
+ options: { cwd, command: 'ruff check .' },
117
+ },
118
+ typecheck: {
119
+ executor: 'nx:run-commands',
120
+ options: { cwd, command: 'mypy src/' },
121
+ },
122
+ test: {
123
+ executor: 'nx:run-commands',
124
+ options: { cwd, command: 'pytest' },
125
+ },
126
+ dev: {
127
+ executor: 'nx:run-commands',
128
+ options: { cwd, command: 'uvicorn src.main:app --reload' },
129
+ },
130
+ 'docker-build': {
131
+ executor: 'nx:run-commands',
132
+ options: {
133
+ command: `docker build --tag ${projectName} ${projectRoot}`,
134
+ },
135
+ },
136
+ };
137
+ }
138
+ }
139
+ function normalizeOptions(options) {
140
+ const appNames = (0, devkit_1.names)(options.app);
141
+ const serviceNames = (0, devkit_1.names)(options.name);
142
+ const language = options.language ?? 'typescript';
143
+ const directory = (options.directory ?? 'packages').replace(/\\/g, '/');
144
+ const projectRoot = (0, devkit_1.joinPathFragments)(directory, appNames.fileName, 'apps', 'service', serviceNames.fileName);
145
+ const userTags = options.tags
146
+ ?.split(',')
147
+ .map((tag) => tag.trim())
148
+ .filter(Boolean) ?? [];
149
+ return {
150
+ app: appNames.fileName,
151
+ appName: appNames.fileName,
152
+ className: appNames.className,
153
+ directory,
154
+ language,
155
+ name: serviceNames.fileName,
156
+ offsetFromRoot: (0, devkit_1.offsetFromRoot)(projectRoot),
157
+ outputPath: (0, devkit_1.joinPathFragments)('dist', projectRoot),
158
+ projectName: `${appNames.fileName}-service-${serviceNames.fileName}`,
159
+ projectRoot,
160
+ projectTitle: `${appNames.className} Service ${serviceNames.className}`,
161
+ skipFormat: options.skipFormat,
162
+ tags: [
163
+ `scope:${appNames.fileName}`,
164
+ 'layer:app',
165
+ 'type:service',
166
+ `runtime:${runtimeForLanguage(language)}`,
167
+ 'deploy:container',
168
+ 'visibility:internal',
169
+ ...userTags,
170
+ ],
171
+ };
172
+ }
173
+ async function serviceGenerator(tree, options) {
174
+ const normalized = normalizeOptions(options);
175
+ const appRoot = (0, devkit_1.joinPathFragments)(normalized.directory, normalized.appName);
176
+ if (!tree.exists(appRoot)) {
177
+ throw new Error(`App group "${normalized.app}" does not exist at "${appRoot}". Generate the app group first.`);
178
+ }
179
+ if (tree.exists((0, devkit_1.joinPathFragments)(normalized.projectRoot, 'project.json')) ||
180
+ tree.exists((0, devkit_1.joinPathFragments)(normalized.projectRoot, 'package.json'))) {
181
+ throw new Error(`Service "${normalized.name}" already exists at "${normalized.projectRoot}".`);
182
+ }
183
+ (0, devkit_1.addProjectConfiguration)(tree, normalized.projectName, {
184
+ root: normalized.projectRoot,
185
+ projectType: 'application',
186
+ sourceRoot: `${normalized.projectRoot}/src`,
187
+ tags: normalized.tags,
188
+ targets: targetsForLanguage(normalized.language, normalized.projectRoot, normalized.projectName, normalized.outputPath),
189
+ });
190
+ (0, devkit_1.generateFiles)(tree, path.join(__dirname, `files-${normalized.language}`), normalized.projectRoot, {
191
+ ...normalized,
192
+ tmpl: '',
193
+ });
194
+ if (!normalized.skipFormat) {
195
+ await (0, devkit_1.formatFiles)(tree);
196
+ }
197
+ }
198
+ exports.default = serviceGenerator;
@@ -0,0 +1,10 @@
1
+ FROM golang:1-bookworm AS builder
2
+ WORKDIR /app
3
+ COPY go.mod go.sum* ./
4
+ RUN go mod download
5
+ COPY . .
6
+ RUN CGO_ENABLED=0 go build -o /task ./cmd/...
7
+
8
+ FROM gcr.io/distroless/static-debian12
9
+ COPY --from=builder /task /task
10
+ CMD ["/task"]
@@ -0,0 +1,11 @@
1
+ # <%= projectTitle %>
2
+
3
+ Go task for the `<%= app %>` app group.
4
+
5
+ ## Commands
6
+
7
+ - `pnpm nx run <%= projectName %>:build` — compile binary
8
+ - `pnpm nx run <%= projectName %>:dev` — run locally
9
+ - `pnpm nx run <%= projectName %>:test` — run tests
10
+ - `pnpm nx run <%= projectName %>:lint` — run golangci-lint
11
+ - `pnpm nx run <%= projectName %>:docker-build` — build container image
@@ -0,0 +1,22 @@
1
+ package main
2
+
3
+ import (
4
+ "log/slog"
5
+ "os"
6
+ )
7
+
8
+ func main() {
9
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
10
+ slog.SetDefault(logger)
11
+
12
+ trigger := os.Getenv("TASK_TRIGGER")
13
+ if trigger == "" {
14
+ trigger = "manual"
15
+ }
16
+
17
+ slog.Info("task started", "trigger", trigger, "task", "<%= projectName %>")
18
+
19
+ // Task logic goes here
20
+
21
+ slog.Info("task completed successfully")
22
+ }
@@ -0,0 +1,9 @@
1
+ # <%= projectTitle %> Contracts
2
+
3
+ ## Input
4
+
5
+ - `TASK_TRIGGER` env var controls the task trigger type (default: `manual`)
6
+
7
+ ## Local Development
8
+
9
+ - `pnpm nx run <%= projectName %>:dev`
@@ -0,0 +1,3 @@
1
+ module github.com/org/<%= projectName %>
2
+
3
+ go 1.22
@@ -0,0 +1,10 @@
1
+ FROM python:3.12-slim AS builder
2
+ WORKDIR /app
3
+ COPY pyproject.toml ./
4
+ RUN pip install --no-cache-dir .
5
+
6
+ FROM python:3.12-slim
7
+ WORKDIR /app
8
+ COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
9
+ COPY src/ src/
10
+ CMD ["python", "src/main.py"]
@@ -0,0 +1,11 @@
1
+ # <%= projectTitle %>
2
+
3
+ Python task for the `<%= app %>` app group.
4
+
5
+ ## Commands
6
+
7
+ - `pnpm nx run <%= projectName %>:dev` — run locally
8
+ - `pnpm nx run <%= projectName %>:test` — run pytest
9
+ - `pnpm nx run <%= projectName %>:lint` — run ruff
10
+ - `pnpm nx run <%= projectName %>:typecheck` — run mypy
11
+ - `pnpm nx run <%= projectName %>:docker-build` — build container image
@@ -0,0 +1,9 @@
1
+ # <%= projectTitle %> Contracts
2
+
3
+ ## Input
4
+
5
+ - `TASK_TRIGGER` env var controls the task trigger type (default: `manual`)
6
+
7
+ ## Local Development
8
+
9
+ - `pnpm nx run <%= projectName %>:dev`
@@ -0,0 +1,12 @@
1
+ [project]
2
+ name = "<%= projectName %>"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = []
6
+
7
+ [project.optional-dependencies]
8
+ dev = [
9
+ "pytest>=8",
10
+ "ruff>=0.8",
11
+ "mypy>=1.13",
12
+ ]
@@ -0,0 +1,26 @@
1
+ """<%= projectTitle %> — task runner for the <%= app %> app group."""
2
+
3
+ import json
4
+ import logging
5
+ import os
6
+ import sys
7
+
8
+ logging.basicConfig(
9
+ stream=sys.stdout,
10
+ level=logging.INFO,
11
+ format="%(message)s",
12
+ )
13
+ logger = logging.getLogger("<%= projectName %>")
14
+
15
+
16
+ def main():
17
+ trigger = os.environ.get("TASK_TRIGGER", "manual")
18
+ logger.info(json.dumps({"msg": "task started", "trigger": trigger, "task": "<%= projectName %>"}))
19
+
20
+ # Task logic goes here
21
+
22
+ logger.info(json.dumps({"msg": "task completed successfully"}))
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
@@ -0,0 +1,15 @@
1
+ [package]
2
+ name = "<%= projectName %>"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [[bin]]
7
+ name = "task"
8
+ path = "src/main.rs"
9
+
10
+ [dependencies]
11
+ serde = { version = "1", features = ["derive"] }
12
+ serde_json = "1"
13
+ tokio = { version = "1", features = ["full"] }
14
+ tracing = "0.1"
15
+ tracing-subscriber = { version = "0.3", features = ["json"] }
@@ -0,0 +1,11 @@
1
+ FROM rust:1-bookworm AS builder
2
+ WORKDIR /app
3
+ COPY Cargo.toml Cargo.lock* ./
4
+ RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src
5
+ COPY src/ src/
6
+ RUN cargo build --release
7
+
8
+ FROM debian:bookworm-slim
9
+ RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
10
+ COPY --from=builder /app/target/release/task /usr/local/bin/task
11
+ CMD ["task"]
@@ -0,0 +1,11 @@
1
+ # <%= projectTitle %>
2
+
3
+ Rust task for the `<%= app %>` app group.
4
+
5
+ ## Commands
6
+
7
+ - `pnpm nx run <%= projectName %>:build` — compile release binary
8
+ - `pnpm nx run <%= projectName %>:dev` — run locally
9
+ - `pnpm nx run <%= projectName %>:test` — run tests
10
+ - `pnpm nx run <%= projectName %>:lint` — run clippy
11
+ - `pnpm nx run <%= projectName %>:docker-build` — build container image
@@ -0,0 +1,9 @@
1
+ # <%= projectTitle %> Contracts
2
+
3
+ ## Input
4
+
5
+ - `TASK_TRIGGER` env var controls the task trigger type (default: `manual`)
6
+
7
+ ## Local Development
8
+
9
+ - `pnpm nx run <%= projectName %>:dev`
@@ -0,0 +1,12 @@
1
+ use std::env;
2
+
3
+ #[tokio::main]
4
+ async fn main() {
5
+ tracing_subscriber::fmt().json().init();
6
+
7
+ let trigger = env::var("TASK_TRIGGER").unwrap_or_else(|_| "manual".to_string());
8
+ tracing::info!(trigger = %trigger, task = "<%= projectName %>", "task started");
9
+
10
+ // Task logic goes here
11
+ tracing::info!("task completed successfully");
12
+ }
@@ -0,0 +1,25 @@
1
+ # syntax=docker/dockerfile:1.7
2
+
3
+ FROM node:22-bookworm-slim AS build
4
+ WORKDIR /workspace
5
+
6
+ ENV CI=true
7
+
8
+ RUN corepack enable
9
+
10
+ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml nx.json tsconfig.base.json tsconfig.json eslint.config.mjs ./
11
+ COPY packages ./packages
12
+ COPY tools ./tools
13
+
14
+ RUN pnpm install --frozen-lockfile
15
+ RUN pnpm nx run <%= projectName %>:build
16
+
17
+ FROM node:22-bookworm-slim AS runtime
18
+ WORKDIR /app
19
+
20
+ ENV NODE_ENV=production
21
+ ENV TASK_NAME=<%= className %>Task
22
+
23
+ COPY --from=build /workspace/dist/<%= projectRoot %>/ ./
24
+
25
+ CMD ["node", "main.js"]
@@ -0,0 +1,24 @@
1
+ # <%= projectTitle %>
2
+
3
+ TypeScript-first backend container task for the `<%= appName %>` app group.
4
+
5
+ ## Purpose
6
+
7
+ This package provides a first mergeable ECS-style task slice for scheduled, queue-driven, and ad hoc operational work without forcing a broader multi-language preset decision yet.
8
+
9
+ ## Nx Targets
10
+
11
+ - `pnpm nx run <%= projectName %>:build`
12
+ - `pnpm nx run <%= projectName %>:lint`
13
+ - `pnpm nx run <%= projectName %>:typecheck`
14
+ - `pnpm nx run <%= projectName %>:test`
15
+ - `pnpm nx run <%= projectName %>:dev`
16
+ - `pnpm nx run <%= projectName %>:docker-build`
17
+
18
+ ## Current Conventions
19
+
20
+ - keep batch and worker logic in `src/`
21
+ - treat `src/main.ts` as the command entrypoint for local and container runs
22
+ - prefer structured JSON logs so ECS, EventBridge, and CloudWatch parsing stay predictable
23
+ - keep SST composition scaffolding in `infra/task.ts` so remote execution and local proxying use the same contract
24
+ - treat this package as app-group-internal until a supported SDK or API contract is published
@@ -0,0 +1,18 @@
1
+ # <%= projectTitle %> Architecture
2
+
3
+ ## Scope
4
+
5
+ `<%= projectName %>` is the first TypeScript-first container task slice for `<%= appName %>`. It gives the app group a batch-oriented workload under `packages/<%= appName %>/apps/task` without introducing language-preset sprawl in the first milestone.
6
+
7
+ ## Runtime Shape
8
+
9
+ - `src/main.ts` runs the task entrypoint and emits structured lifecycle logs
10
+ - `src/task.ts` keeps config, result creation, and task behavior testable
11
+ - `TASK_TRIGGER` provides a simple starting contract for schedule, queue, or manual execution context
12
+ - `infra/task.ts` captures the recommended SST `Cluster` + `Task` composition seam and `sst dev` proxy command contract
13
+
14
+ ## Current Boundaries
15
+
16
+ - keep scheduled, queue-driven, and ad hoc operational work here
17
+ - publish cross-app contracts through the owning app group's SDK instead of importing internals directly
18
+ - compose this workload into the owning app group's root `infra/` entrypoint instead of letting runtime code instantiate SST resources ad hoc
@@ -0,0 +1,20 @@
1
+ # <%= projectTitle %> Contracts
2
+
3
+ ## Local Development
4
+
5
+ - `pnpm nx run <%= projectName %>:dev` is the canonical local command for this workload.
6
+ - `infra/task.ts` passes the same command to SST via `dev.command` so `sst dev` can proxy remote task runs back to local code.
7
+ - `TASK_NAME`, `TASK_VERSION`, and `TASK_TRIGGER` are the supported starter env overrides.
8
+
9
+ ## Infra Composition
10
+
11
+ - import `register<%= className %>Task` from `apps/task/infra/task` into the owning app group's root `infra/` entrypoint
12
+ - provide an existing `sst.aws.Cluster` from app-group infrastructure instead of constructing a cluster inside runtime code
13
+ - pass linked SST resources through `link` so runtime code can consume them through `Resource.*`
14
+ - use `TASK_TRIGGER` as the starter trigger contract for local runs, EventBridge invocations, or task SDK calls
15
+
16
+ ## Deployment Defaults
17
+
18
+ - image build context stays rooted at `packages/<%= appName %>/apps/task`
19
+ - local dev runs the same command SST uses when proxying task executions
20
+ - logging defaults to a one-month CloudWatch retention window until app-specific requirements are known
@@ -0,0 +1,24 @@
1
+ # <%= projectTitle %> Operations
2
+
3
+ ## Local Verification
4
+
5
+ - `pnpm nx run <%= projectName %>:build`
6
+ - `pnpm nx run <%= projectName %>:test`
7
+ - `pnpm nx run <%= projectName %>:dev`
8
+ - `node dist/<%= projectRoot %>/main.js`
9
+
10
+ Set `TASK_NAME`, `TASK_VERSION`, or `TASK_TRIGGER` in the environment to override the defaults exposed by the starter task.
11
+
12
+ `<%= projectName %>:dev` uses `@swc-node/register` so SST can proxy remote task invocations back to the same local command during `sst dev`.
13
+
14
+ ## Container Workflow
15
+
16
+ - `pnpm nx run <%= projectName %>:docker-build`
17
+ - image build runs the workspace install plus `pnpm nx run <%= projectName %>:build`
18
+ - run the image with `docker run --rm -e TASK_TRIGGER=schedule <%= projectName %>` to exercise the starter command path
19
+ - `infra/task.ts` keeps the SST `Task` image path, linked-resource surface, and local proxy command aligned
20
+
21
+ ## Next Steps
22
+
23
+ - replace the starter task body with app-specific batch or worker logic
24
+ - import `register<%= className %>Task` into the owning app group's `infra/` entrypoint when the workload is ready to deploy
@@ -0,0 +1,3 @@
1
+ import baseConfig from '<%= offsetFromRoot %>eslint.config.mjs';
2
+
3
+ export default [...baseConfig];
@@ -0,0 +1,35 @@
1
+ export interface Register<%= className %>TaskArgs {
2
+ cluster: sst.aws.Cluster;
3
+ environment?: Record<string, string>;
4
+ link?: any[];
5
+ }
6
+
7
+ export function register<%= className %>Task({
8
+ cluster,
9
+ environment = {},
10
+ link = [],
11
+ }: Register<%= className %>TaskArgs) {
12
+ const task = new sst.aws.Task('<%= projectName %>', {
13
+ cluster,
14
+ image: {
15
+ context: './apps/task/<%= name %>',
16
+ dockerfile: 'Dockerfile',
17
+ },
18
+ dev: {
19
+ command: 'pnpm nx run <%= projectName %>:dev',
20
+ directory: '../../..',
21
+ },
22
+ environment: {
23
+ TASK_NAME: '<%= className %>Task',
24
+ TASK_VERSION: '0.0.1',
25
+ TASK_TRIGGER: 'manual',
26
+ ...environment,
27
+ },
28
+ link,
29
+ logging: {
30
+ retention: '1 month',
31
+ },
32
+ });
33
+
34
+ return { task };
35
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@<%= appName %>/task",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "main": "./dist/main.js"
7
+ }
@@ -0,0 +1,6 @@
1
+ export {
2
+ createTaskResult,
3
+ formatLogEvent,
4
+ readTaskConfig,
5
+ runTask,
6
+ } from './task.js';