@crossdelta/platform-sdk 0.2.24 → 0.2.26
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 +18 -30
- package/bin/cli.js +147 -370
- package/bin/integration.collection.json +5 -5
- package/bin/templates/hono-microservice/Dockerfile.hbs +16 -0
- package/bin/templates/hono-microservice/src/index.ts.hbs +18 -0
- package/bin/templates/hono-microservice/tsconfig.json.hbs +12 -0
- package/bin/templates/nest-microservice/Dockerfile.hbs +37 -0
- package/bin/templates/nest-microservice/src/main.ts.hbs +25 -0
- package/bin/templates/workspace/apps/.gitkeep +0 -0
- package/bin/templates/workspace/biome.json.hbs +60 -0
- package/bin/templates/workspace/bunfig.toml.hbs +5 -0
- package/bin/templates/workspace/docs/.gitkeep +0 -0
- package/bin/templates/workspace/editorconfig.hbs +9 -0
- package/bin/templates/workspace/gitignore.hbs +15 -0
- package/bin/templates/workspace/infra/Pulumi.dev.yaml.hbs +5 -0
- package/bin/templates/workspace/infra/Pulumi.yaml.hbs +6 -0
- package/bin/templates/workspace/infra/index.ts.hbs +56 -0
- package/bin/templates/workspace/infra/package.json.hbs +20 -0
- package/bin/templates/workspace/infra/services/example.ts.hbs +21 -0
- package/bin/templates/workspace/infra/tsconfig.json.hbs +15 -0
- package/bin/templates/workspace/npmrc.hbs +2 -0
- package/bin/templates/workspace/package.json.hbs +28 -0
- package/bin/templates/workspace/packages/.gitkeep +0 -0
- package/bin/templates/workspace/services/.gitkeep +0 -0
- package/bin/templates/workspace/turbo.json.hbs +32 -0
- package/package.json +18 -7
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"name": "@crossdelta/cloudevents",
|
|
4
|
-
"description": "
|
|
5
|
-
"link": "https://
|
|
6
|
-
"install": "@crossdelta/cloudevents@^0.1
|
|
4
|
+
"description": "Type-safe event-driven microservices with NATS and Zod validation",
|
|
5
|
+
"link": "https://www.npmjs.com/package/@crossdelta/cloudevents",
|
|
6
|
+
"install": "@crossdelta/cloudevents@^0.3.1",
|
|
7
7
|
"run": [],
|
|
8
8
|
"initial": true
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"name": "@crossdelta/telemetry",
|
|
12
12
|
"description": "Zero-config OpenTelemetry instrumentation for TypeScript services",
|
|
13
|
-
"link": "https://
|
|
13
|
+
"link": "https://www.npmjs.com/package/@crossdelta/telemetry",
|
|
14
14
|
"install": "@crossdelta/telemetry@latest",
|
|
15
15
|
"run": [],
|
|
16
16
|
"initial": true
|
|
17
17
|
}
|
|
18
|
-
]
|
|
18
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.7-labs
|
|
2
|
+
ARG BUN_VERSION={{bunVersion}}
|
|
3
|
+
|
|
4
|
+
FROM oven/bun:${BUN_VERSION}-alpine AS production
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
COPY bunfig.toml package.json ./
|
|
8
|
+
COPY src ./src
|
|
9
|
+
|
|
10
|
+
RUN --mount=type=secret,id=NPM_TOKEN \
|
|
11
|
+
export NPM_TOKEN="$(cat /run/secrets/NPM_TOKEN)" && \
|
|
12
|
+
bun install --production --omit=optional
|
|
13
|
+
|
|
14
|
+
USER bun
|
|
15
|
+
|
|
16
|
+
CMD ["bun", "run", "src/index.ts"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// IMPORTANT: telemetry must be imported first to patch modules before they're loaded
|
|
2
|
+
import '@crossdelta/telemetry'
|
|
3
|
+
|
|
4
|
+
import { Hono } from 'hono'
|
|
5
|
+
|
|
6
|
+
const port = Number(process.env.PORT || process.env.{{envKey}}_PORT) || 8080
|
|
7
|
+
const app = new Hono()
|
|
8
|
+
|
|
9
|
+
app.get('/health', (c) => {
|
|
10
|
+
return c.json({ status: 'ok' })
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
console.log('Starting {{serviceName}} service on port', port)
|
|
14
|
+
|
|
15
|
+
Bun.serve({
|
|
16
|
+
port,
|
|
17
|
+
fetch: app.fetch,
|
|
18
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
ARG NODE_VERSION={{nodeVersion}}
|
|
2
|
+
ARG BUN_VERSION={{bunVersion}}
|
|
3
|
+
|
|
4
|
+
# STAGE 1 — Build
|
|
5
|
+
FROM oven/bun:${BUN_VERSION}-alpine AS builder
|
|
6
|
+
WORKDIR /app
|
|
7
|
+
|
|
8
|
+
COPY package.json tsconfig*.json nest-cli.json ./
|
|
9
|
+
COPY src ./src
|
|
10
|
+
|
|
11
|
+
RUN --mount=type=secret,id=NPM_TOKEN \
|
|
12
|
+
export NPM_TOKEN="$(cat /run/secrets/NPM_TOKEN)" && \
|
|
13
|
+
bun install
|
|
14
|
+
|
|
15
|
+
RUN bun run build
|
|
16
|
+
|
|
17
|
+
# STAGE 2 — Production dependencies
|
|
18
|
+
FROM oven/bun:${BUN_VERSION}-alpine AS deps
|
|
19
|
+
WORKDIR /app
|
|
20
|
+
|
|
21
|
+
COPY package.json ./
|
|
22
|
+
|
|
23
|
+
RUN --mount=type=secret,id=NPM_TOKEN \
|
|
24
|
+
export NPM_TOKEN="$(cat /run/secrets/NPM_TOKEN)" && \
|
|
25
|
+
bun install --production --omit=optional
|
|
26
|
+
|
|
27
|
+
# STAGE 3 — Runtime
|
|
28
|
+
FROM node:${NODE_VERSION}-alpine AS production
|
|
29
|
+
WORKDIR /app
|
|
30
|
+
|
|
31
|
+
COPY --from=builder /app/dist ./dist
|
|
32
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
33
|
+
|
|
34
|
+
USER node
|
|
35
|
+
ENV NODE_ENV=production
|
|
36
|
+
|
|
37
|
+
CMD ["node", "dist/main.js"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// IMPORTANT: telemetry must be imported first to patch modules before they're loaded
|
|
2
|
+
import '@crossdelta/telemetry'
|
|
3
|
+
|
|
4
|
+
import { env } from 'node:process'
|
|
5
|
+
import { ConsoleLogger } from '@nestjs/common'
|
|
6
|
+
import { NestFactory } from '@nestjs/core'
|
|
7
|
+
import { AppModule } from './app.module'
|
|
8
|
+
|
|
9
|
+
const port = Number(process.env.PORT || process.env.{{envKey}}_PORT) || {{defaultPort}}
|
|
10
|
+
const serviceName = '{{displayName}}'
|
|
11
|
+
|
|
12
|
+
const logger = new ConsoleLogger({
|
|
13
|
+
json: env.JSON_LOGS === 'true',
|
|
14
|
+
prefix: serviceName,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
async function bootstrap() {
|
|
18
|
+
const app = await NestFactory.create(AppModule, { logger })
|
|
19
|
+
|
|
20
|
+
await app
|
|
21
|
+
.listen(port)
|
|
22
|
+
.then(() => logger.log(`${serviceName} is running on port ${port}`))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
bootstrap()
|
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.3.7/schema.json",
|
|
3
|
+
"formatter": {
|
|
4
|
+
"indentStyle": "space"
|
|
5
|
+
},
|
|
6
|
+
"assist": {
|
|
7
|
+
"actions": {
|
|
8
|
+
"source": {
|
|
9
|
+
"organizeImports": "on"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"linter": {
|
|
14
|
+
"enabled": true,
|
|
15
|
+
"rules": {
|
|
16
|
+
"security": {
|
|
17
|
+
"recommended": true
|
|
18
|
+
},
|
|
19
|
+
"style": {
|
|
20
|
+
"recommended": true,
|
|
21
|
+
"useAsConstAssertion": "warn",
|
|
22
|
+
"noUselessElse": "error",
|
|
23
|
+
"useConst": "error"
|
|
24
|
+
},
|
|
25
|
+
"complexity": {
|
|
26
|
+
"recommended": true,
|
|
27
|
+
"noUselessEmptyExport": "error",
|
|
28
|
+
"noExcessiveCognitiveComplexity": {
|
|
29
|
+
"level": "warn",
|
|
30
|
+
"options": {
|
|
31
|
+
"maxAllowedComplexity": 15
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"javascript": {
|
|
38
|
+
"formatter": {
|
|
39
|
+
"indentWidth": 2,
|
|
40
|
+
"quoteStyle": "single",
|
|
41
|
+
"semicolons": "asNeeded",
|
|
42
|
+
"lineWidth": 120,
|
|
43
|
+
"trailingCommas": "all",
|
|
44
|
+
"arrowParentheses": "always"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"files": {
|
|
48
|
+
"includes": [
|
|
49
|
+
"**/src/**/*.ts",
|
|
50
|
+
"infra/**/*.ts",
|
|
51
|
+
"!**/vendor",
|
|
52
|
+
"!**/dist",
|
|
53
|
+
"!**/node_modules",
|
|
54
|
+
"!reports",
|
|
55
|
+
"!coverage",
|
|
56
|
+
"!stryker-tmp",
|
|
57
|
+
"!**/.stryker-tmp"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import {
|
|
3
|
+
buildExternalUrls,
|
|
4
|
+
buildIngressRules,
|
|
5
|
+
buildInternalUrls,
|
|
6
|
+
buildServicePortEnvs,
|
|
7
|
+
buildServices,
|
|
8
|
+
buildServiceUrlEnvs,
|
|
9
|
+
discoverServices,
|
|
10
|
+
} from '@crossdelta/infrastructure'
|
|
11
|
+
import { App } from '@pulumi/digitalocean'
|
|
12
|
+
import { Config, getStack } from '@pulumi/pulumi'
|
|
13
|
+
|
|
14
|
+
const allServiceConfigs = discoverServices(join(__dirname, 'services'))
|
|
15
|
+
const serviceConfigs = allServiceConfigs.filter((config) => !config.skip)
|
|
16
|
+
const cfg = new Config()
|
|
17
|
+
const logtailToken = cfg.requireSecret('logtailToken')
|
|
18
|
+
const registryCredentials = cfg.requireSecret('registryCredentials')
|
|
19
|
+
|
|
20
|
+
const stack = getStack()
|
|
21
|
+
|
|
22
|
+
const doAppName = `{{projectName}}-${stack}`
|
|
23
|
+
|
|
24
|
+
const app = new App('{{projectName}}', {
|
|
25
|
+
spec: {
|
|
26
|
+
name: doAppName,
|
|
27
|
+
region: 'fra',
|
|
28
|
+
|
|
29
|
+
alerts: [{ rule: 'DEPLOYMENT_FAILED' }, { rule: 'DOMAIN_FAILED' }],
|
|
30
|
+
|
|
31
|
+
features: ['buildpack-stack=ubuntu-22'],
|
|
32
|
+
|
|
33
|
+
envs: [
|
|
34
|
+
...buildServiceUrlEnvs(serviceConfigs),
|
|
35
|
+
...buildServicePortEnvs(serviceConfigs),
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
services: buildServices({
|
|
39
|
+
serviceConfigs,
|
|
40
|
+
registryCredentials,
|
|
41
|
+
logtailToken,
|
|
42
|
+
}),
|
|
43
|
+
|
|
44
|
+
ingress: {
|
|
45
|
+
rules: buildIngressRules(serviceConfigs),
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Outputs
|
|
51
|
+
export const appId = app.id
|
|
52
|
+
export const appDefaultIngress = app.defaultIngress
|
|
53
|
+
export const internalUrls = buildInternalUrls(serviceConfigs)
|
|
54
|
+
export const serviceUrls = app.defaultIngress.apply((baseUrl) =>
|
|
55
|
+
buildExternalUrls(serviceConfigs, baseUrl ?? ''),
|
|
56
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "infra",
|
|
3
|
+
"private": true,
|
|
4
|
+
"scripts": {
|
|
5
|
+
"generate-env": "echo '# Generated .env.local' > ../.env.local",
|
|
6
|
+
"lint": "biome lint --fix",
|
|
7
|
+
"pulumi": "pulumi"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@crossdelta/infrastructure": "latest",
|
|
11
|
+
"@pulumi/digitalocean": "^4.55.0",
|
|
12
|
+
"@pulumi/pulumi": "^3.208.0",
|
|
13
|
+
"tsx": "^4.19.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@biomejs/biome": "2.3.7",
|
|
17
|
+
"@types/node": "^24.10.1",
|
|
18
|
+
"typescript": "^5.9.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ServiceConfig } from '@crossdelta/infrastructure'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Example service configuration.
|
|
5
|
+
*
|
|
6
|
+
* See ServiceConfig type for all available options:
|
|
7
|
+
* - httpPort: Public port with ingress routing
|
|
8
|
+
* - internalPorts: Internal-only ports
|
|
9
|
+
* - ingressPrefix: URL path prefix (e.g., '/api')
|
|
10
|
+
* - healthCheck: Health check configuration
|
|
11
|
+
*/
|
|
12
|
+
const config: ServiceConfig = {
|
|
13
|
+
name: 'example-service',
|
|
14
|
+
instanceSizeSlug: 'apps-s-1vcpu-0.5gb',
|
|
15
|
+
environmentSlug: 'node-js',
|
|
16
|
+
httpPort: 3000,
|
|
17
|
+
ingressPrefix: '/',
|
|
18
|
+
skip: true, // Set to false when ready to deploy
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default config
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "./dist"
|
|
12
|
+
},
|
|
13
|
+
"include": ["**/*.ts"],
|
|
14
|
+
"exclude": ["node_modules"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "bun pf dev",
|
|
6
|
+
"generate-env": "turbo run generate-env --ui=stream",
|
|
7
|
+
"build": "bun --env-file .env.local turbo run build",
|
|
8
|
+
"preview": "bun --env-file .env.local turbo run preview",
|
|
9
|
+
"lint": "bun turbo run lint",
|
|
10
|
+
"format": "bun turbo run format",
|
|
11
|
+
"pulumi": "turbo run pulumi --",
|
|
12
|
+
"test": "bun --env-file .env.local turbo run test"
|
|
13
|
+
},
|
|
14
|
+
"pf": {
|
|
15
|
+
"registry": "{{projectName}}/platform",
|
|
16
|
+
"dev": {
|
|
17
|
+
"watchDirs": ["infra/services"],
|
|
18
|
+
"watchPackages": ["services", "apps"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@biomejs/biome": "2.3.7",
|
|
23
|
+
"@crossdelta/platform-sdk": "latest",
|
|
24
|
+
"turbo": "^2.5.6"
|
|
25
|
+
},
|
|
26
|
+
"packageManager": "bun@1.2.7",
|
|
27
|
+
"workspaces": ["packages/*", "apps/*", "services/*", "infra"]
|
|
28
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turborepo.org/schema.json",
|
|
3
|
+
"tasks": {
|
|
4
|
+
"start:dev": {
|
|
5
|
+
"cache": false,
|
|
6
|
+
"persistent": true
|
|
7
|
+
},
|
|
8
|
+
"generate-env": {
|
|
9
|
+
"cache": false
|
|
10
|
+
},
|
|
11
|
+
"pulumi": {},
|
|
12
|
+
"build": {
|
|
13
|
+
"cache": false
|
|
14
|
+
},
|
|
15
|
+
"test": {
|
|
16
|
+
"cache": false
|
|
17
|
+
},
|
|
18
|
+
"format": {
|
|
19
|
+
"cache": false
|
|
20
|
+
},
|
|
21
|
+
"lint": {
|
|
22
|
+
"cache": false
|
|
23
|
+
},
|
|
24
|
+
"preview": {
|
|
25
|
+
"cache": false,
|
|
26
|
+
"persistent": true
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"ui": "tui",
|
|
30
|
+
"concurrency": "50",
|
|
31
|
+
"globalPassThroughEnv": ["*"]
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/platform-sdk",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.26",
|
|
4
|
+
"description": "CLI toolkit for scaffolding Turborepo workspaces with Pulumi infrastructure and Hono/NestJS microservices",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"scaffolding",
|
|
8
|
+
"microservices",
|
|
9
|
+
"turborepo",
|
|
10
|
+
"monorepo",
|
|
11
|
+
"pulumi",
|
|
12
|
+
"infrastructure-as-code",
|
|
13
|
+
"hono",
|
|
14
|
+
"nestjs",
|
|
15
|
+
"bun",
|
|
16
|
+
"devtools"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://www.npmjs.com/package/@crossdelta/platform-sdk",
|
|
5
19
|
"bin": {
|
|
6
20
|
"platform": "./bin/cli.js",
|
|
7
21
|
"pf": "./bin/cli.js"
|
|
@@ -20,10 +34,6 @@
|
|
|
20
34
|
"exports": {
|
|
21
35
|
"./schemas/event.schema.json": "./schemas/event.schema.json"
|
|
22
36
|
},
|
|
23
|
-
"repository": {
|
|
24
|
-
"type": "git",
|
|
25
|
-
"url": "git@github.com:crossdelta/platform-sdk.git"
|
|
26
|
-
},
|
|
27
37
|
"publishConfig": {
|
|
28
38
|
"access": "public"
|
|
29
39
|
},
|
|
@@ -34,7 +44,7 @@
|
|
|
34
44
|
"scripts": {
|
|
35
45
|
"start:dev": "DEBUG=true esbuild cli/src/index.ts --bundle --platform=node --format=cjs --outfile=bin/cli.js --banner:js=\"#!/usr/bin/env node\" --external:@crossdelta/infrastructure --watch",
|
|
36
46
|
"build:cli": "esbuild cli/src/index.ts --minify --bundle --platform=node --format=cjs --outfile=bin/cli.js --banner:js=\"#!/usr/bin/env node\" --external:@crossdelta/infrastructure",
|
|
37
|
-
"build:cli:copy": "cp cli/integration.collection.json bin/integration.collection.json",
|
|
47
|
+
"build:cli:copy": "cp cli/integration.collection.json bin/integration.collection.json && rm -rf bin/templates && mkdir -p bin/templates && cp -r cli/src/commands/create/workspace/templates bin/templates/workspace && cp -r cli/src/commands/create/hono-microservice/templates bin/templates/hono-microservice && cp -r cli/src/commands/create/nest-microservice/templates bin/templates/nest-microservice",
|
|
38
48
|
"build:schematics:transpile": "tsc --project tsconfig.schematics.json",
|
|
39
49
|
"build:schematics:copy": "cp -R schematics/* dist/schematics && find dist/schematics -name '*.ts' -delete",
|
|
40
50
|
"build:schematics": "npm run build:schematics:transpile && npm run build:schematics:copy",
|
|
@@ -58,6 +68,7 @@
|
|
|
58
68
|
"execa": "^9.5.2",
|
|
59
69
|
"fs-extra": "^11.3.0",
|
|
60
70
|
"globby": "^14.1.0",
|
|
71
|
+
"handlebars": "^4.7.8",
|
|
61
72
|
"listr2": "^8.3.2",
|
|
62
73
|
"ora": "^8.2.0",
|
|
63
74
|
"os": "^0.1.2",
|