@crossdelta/infrastructure 0.1.35 → 0.1.38
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/package.json +2 -5
- package/lib/env.ts +0 -10
- package/lib/helpers/config.ts +0 -45
- package/lib/helpers/discover-services.ts +0 -57
- package/lib/helpers/docker-hub-image.ts +0 -24
- package/lib/helpers/image.ts +0 -54
- package/lib/helpers/index.ts +0 -7
- package/lib/helpers/service-builder.ts +0 -61
- package/lib/helpers/service-runtime.ts +0 -62
- package/lib/helpers/service-urls.ts +0 -82
- package/lib/index.ts +0 -2
- package/lib/types/index.ts +0 -87
- package/lib/types/service-names.ts +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossdelta/infrastructure",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.38",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -9,18 +9,15 @@
|
|
|
9
9
|
"main": "dist/index.cjs",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
11
|
"files": [
|
|
12
|
-
"dist"
|
|
13
|
-
"lib"
|
|
12
|
+
"dist"
|
|
14
13
|
],
|
|
15
14
|
"exports": {
|
|
16
15
|
".": {
|
|
17
|
-
"bun": "./lib/index.ts",
|
|
18
16
|
"import": "./dist/index.js",
|
|
19
17
|
"require": "./dist/index.cjs",
|
|
20
18
|
"types": "./dist/index.d.ts"
|
|
21
19
|
},
|
|
22
20
|
"./env": {
|
|
23
|
-
"bun": "./lib/env.ts",
|
|
24
21
|
"import": "./dist/env.js",
|
|
25
22
|
"require": "./dist/env.cjs",
|
|
26
23
|
"types": "./dist/env.d.ts"
|
package/lib/env.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environment helpers for services to read configuration.
|
|
3
|
-
* Use this entry point in production services (Node.js, NestJS, etc.)
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* import { getServicePort, getServiceUrl } from '@crossdelta/infrastructure/env'
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export * from './helpers/service-runtime'
|
|
10
|
-
export type { ServiceName } from './types/service-names'
|
package/lib/helpers/config.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { Input } from '@pulumi/pulumi'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Ensures that a string ends with a dot (useful for DNS CNAME values).
|
|
5
|
-
*/
|
|
6
|
-
export const ensureDot = (str: string) => {
|
|
7
|
-
return str.endsWith('.') ? str : `${str}.`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Common alert configuration for services
|
|
12
|
-
*/
|
|
13
|
-
export const defaultAlerts = [
|
|
14
|
-
{
|
|
15
|
-
rule: 'CPU_UTILIZATION',
|
|
16
|
-
operator: 'GREATER_THAN',
|
|
17
|
-
value: 70,
|
|
18
|
-
window: 'FIVE_MINUTES',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
rule: 'MEM_UTILIZATION',
|
|
22
|
-
operator: 'GREATER_THAN',
|
|
23
|
-
value: 70,
|
|
24
|
-
window: 'FIVE_MINUTES',
|
|
25
|
-
},
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Creates log destinations config with Logtail token
|
|
30
|
-
*/
|
|
31
|
-
export const createLogDestinations = (logtailToken: Input<string>) => [
|
|
32
|
-
{
|
|
33
|
-
name: 'better-stacks-logs',
|
|
34
|
-
logtail: {
|
|
35
|
-
token: logtailToken,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Default health check configuration
|
|
42
|
-
*/
|
|
43
|
-
export const defaultHealthCheck = {
|
|
44
|
-
httpPath: '/health',
|
|
45
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { readdirSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import type { ServiceConfig } from '../types'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Get the primary port for a service (for validation).
|
|
7
|
-
* Prefers httpPort, falls back to first internalPort, then 8080.
|
|
8
|
-
*/
|
|
9
|
-
function getServicePort(config: ServiceConfig): number {
|
|
10
|
-
if (config.httpPort) return config.httpPort as number
|
|
11
|
-
const internalPorts = config.internalPorts as number[] | undefined
|
|
12
|
-
if (internalPorts?.[0]) return internalPorts[0]
|
|
13
|
-
return 8080
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Validates that no two services use the same port.
|
|
18
|
-
* @throws Error if duplicate ports are found
|
|
19
|
-
*/
|
|
20
|
-
function validateNoDuplicatePorts(configs: ServiceConfig[]): void {
|
|
21
|
-
const portMap = new Map<number, string[]>()
|
|
22
|
-
|
|
23
|
-
for (const config of configs) {
|
|
24
|
-
const port = getServicePort(config)
|
|
25
|
-
const existing = portMap.get(port) || []
|
|
26
|
-
existing.push(config.name)
|
|
27
|
-
portMap.set(port, existing)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const conflicts = [...portMap.entries()]
|
|
31
|
-
.filter(([, services]) => services.length > 1)
|
|
32
|
-
.map(([port, services]) => `Port ${port}: ${services.join(', ')}`)
|
|
33
|
-
|
|
34
|
-
if (conflicts.length > 0) {
|
|
35
|
-
throw new Error(`Port conflicts detected:\n${conflicts.join('\n')}`)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Auto-discovers all service configurations from a directory.
|
|
41
|
-
* Each .ts file (except index.ts) should export a ServiceConfig as default.
|
|
42
|
-
* @throws Error if duplicate ports are detected
|
|
43
|
-
*/
|
|
44
|
-
export function discoverServices(servicesDir: string): ServiceConfig[] {
|
|
45
|
-
const files = readdirSync(servicesDir).filter(
|
|
46
|
-
(file) => file.endsWith('.ts') && file !== 'index.ts'
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
const configs = files.map((file) => {
|
|
50
|
-
const module = require(join(servicesDir, file))
|
|
51
|
-
return module.default as ServiceConfig
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
validateNoDuplicatePorts(configs)
|
|
55
|
-
|
|
56
|
-
return configs
|
|
57
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type ImageConfig, RegistryType } from '../types'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Helper to create a Docker Hub image config.
|
|
5
|
-
* For official images, use 'library' as the registry.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* // Official image: library/nats:2.10-alpine
|
|
9
|
-
* dockerHubImage('nats', '2.10-alpine')
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* // User image: bitnami/redis:7.0
|
|
13
|
-
* dockerHubImage('redis', '7.0', 'bitnami')
|
|
14
|
-
*/
|
|
15
|
-
export const dockerHubImage = (
|
|
16
|
-
repository: string,
|
|
17
|
-
tag: string,
|
|
18
|
-
registry = 'library',
|
|
19
|
-
): ImageConfig => ({
|
|
20
|
-
registryType: RegistryType.DOCKER_HUB,
|
|
21
|
-
registry,
|
|
22
|
-
repository,
|
|
23
|
-
tag,
|
|
24
|
-
})
|
package/lib/helpers/image.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { Output } from '@pulumi/pulumi'
|
|
2
|
-
|
|
3
|
-
const scopeImageTagsRaw = process.env.SCOPE_IMAGE_TAGS ?? ''
|
|
4
|
-
const scopeImageTags = (() => {
|
|
5
|
-
if (!scopeImageTagsRaw.trim()) {
|
|
6
|
-
return {} as Record<string, string>
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
const parsed = JSON.parse(scopeImageTagsRaw) as Record<string, unknown>
|
|
11
|
-
const tags: Record<string, string> = {}
|
|
12
|
-
for (const [key, value] of Object.entries(parsed ?? {})) {
|
|
13
|
-
if (typeof value === 'string' && value.trim().length > 0) {
|
|
14
|
-
tags[key] = value.trim()
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return tags
|
|
18
|
-
} catch (error) {
|
|
19
|
-
console.warn('Unable to parse scope image tags from environment:', error)
|
|
20
|
-
return {} as Record<string, string>
|
|
21
|
-
}
|
|
22
|
-
})()
|
|
23
|
-
|
|
24
|
-
const resolveImageTag = (scopeName: string) => {
|
|
25
|
-
const tag = scopeImageTags[scopeName]
|
|
26
|
-
if (!tag) {
|
|
27
|
-
// Use 'latest' as fallback for local development/preview
|
|
28
|
-
console.warn(`No image tag for "${scopeName}", using "latest" as fallback`)
|
|
29
|
-
return 'latest'
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return tag
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Gets the image configuration for a given repository.
|
|
37
|
-
* @param repository - The name of the repository.
|
|
38
|
-
* @returns The image configuration.
|
|
39
|
-
*/
|
|
40
|
-
export const getImage = (repository: string, registryCredentials: Output<string>) => {
|
|
41
|
-
const scopeName = repository.split('/').pop()
|
|
42
|
-
|
|
43
|
-
if (!scopeName) {
|
|
44
|
-
throw new Error(`Invalid repository name: ${repository}`)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
registryType: 'GHCR' as any,
|
|
49
|
-
registry: 'orderboss',
|
|
50
|
-
repository,
|
|
51
|
-
registryCredentials,
|
|
52
|
-
tag: resolveImageTag(scopeName),
|
|
53
|
-
}
|
|
54
|
-
}
|
package/lib/helpers/index.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type { AppSpecService } from '@pulumi/digitalocean/types/input'
|
|
2
|
-
import type { Output } from '@pulumi/pulumi'
|
|
3
|
-
import type { ServiceConfig } from '../types'
|
|
4
|
-
import { createLogDestinations, defaultAlerts, defaultHealthCheck } from './config'
|
|
5
|
-
import { getImage } from './image'
|
|
6
|
-
|
|
7
|
-
export interface BuildServicesOptions {
|
|
8
|
-
serviceConfigs: ServiceConfig[]
|
|
9
|
-
registryCredentials: Output<string>
|
|
10
|
-
logtailToken: Output<string>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Builds the services array from service configs.
|
|
15
|
-
*/
|
|
16
|
-
export function buildServices(options: BuildServicesOptions): AppSpecService[] {
|
|
17
|
-
const { serviceConfigs, registryCredentials, logtailToken } = options
|
|
18
|
-
const logDestinations = createLogDestinations(logtailToken)
|
|
19
|
-
|
|
20
|
-
return serviceConfigs.map((config) => {
|
|
21
|
-
// Remove custom properties that shouldn't be passed to DO API
|
|
22
|
-
const {
|
|
23
|
-
ingressPrefix: _ingressPrefix,
|
|
24
|
-
skip: _skip,
|
|
25
|
-
image: configImage,
|
|
26
|
-
internalUrl: _internalUrl,
|
|
27
|
-
...serviceConfig
|
|
28
|
-
} = config
|
|
29
|
-
|
|
30
|
-
// Use provided image or default to GHCR
|
|
31
|
-
const image = configImage ?? getImage(`platform/${config.name}`, registryCredentials)
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
healthCheck: defaultHealthCheck,
|
|
35
|
-
alerts: defaultAlerts,
|
|
36
|
-
logDestinations,
|
|
37
|
-
...serviceConfig,
|
|
38
|
-
image,
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Builds the ingress rules from service configs.
|
|
45
|
-
* Only includes services that have both an ingressPrefix AND httpPort defined.
|
|
46
|
-
* Services with only internalPorts cannot have ingress rules.
|
|
47
|
-
*/
|
|
48
|
-
export function buildIngressRules(serviceConfigs: ServiceConfig[]) {
|
|
49
|
-
return serviceConfigs
|
|
50
|
-
.filter((config): config is ServiceConfig & { ingressPrefix: string; httpPort: number } =>
|
|
51
|
-
config.ingressPrefix !== undefined && config.httpPort !== undefined
|
|
52
|
-
)
|
|
53
|
-
.map((config) => ({
|
|
54
|
-
component: { name: config.name },
|
|
55
|
-
match: {
|
|
56
|
-
path: {
|
|
57
|
-
prefix: config.ingressPrefix,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
}))
|
|
61
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime helpers for services to access their configuration.
|
|
3
|
-
* These functions read from environment variables set by generate-env (local)
|
|
4
|
-
* or injected by DO App Platform (production).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ServiceName } from '../types'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Convert service name to valid env var key (e.g., api-gateway -> API_GATEWAY)
|
|
11
|
-
*/
|
|
12
|
-
const toEnvKey = (name: string) => name.toUpperCase().replace(/-/g, '_')
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Get the port for a service from environment variables.
|
|
16
|
-
* Reads from <SERVICE_NAME>_PORT (e.g., ORDERS_PORT, API_GATEWAY_PORT)
|
|
17
|
-
*
|
|
18
|
-
* @param serviceName - The service name (e.g., 'orders', 'api-gateway')
|
|
19
|
-
* @param defaultPort - Fallback port if env var is not set (default: 8080)
|
|
20
|
-
* @returns The configured port number
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```typescript
|
|
24
|
-
* import { getServicePort } from '@crossdelta/infrastructure/env'
|
|
25
|
-
*
|
|
26
|
-
* const port = getServicePort('orders', 3001)
|
|
27
|
-
* // Reads process.env.ORDERS_PORT, falls back to 3001
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
export function getServicePort(serviceName: ServiceName, defaultPort = 8080): number {
|
|
31
|
-
const envKey = `${toEnvKey(serviceName)}_PORT`
|
|
32
|
-
const envValue = process.env[envKey]
|
|
33
|
-
|
|
34
|
-
if (envValue) {
|
|
35
|
-
const parsed = Number(envValue)
|
|
36
|
-
if (!Number.isNaN(parsed)) {
|
|
37
|
-
return parsed
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return defaultPort
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get the URL for a service from environment variables.
|
|
46
|
-
* Reads from <SERVICE_NAME>_URL (e.g., ORDERS_URL, API_GATEWAY_URL)
|
|
47
|
-
*
|
|
48
|
-
* @param serviceName - The service name (e.g., 'orders', 'api-gateway')
|
|
49
|
-
* @returns The service URL or undefined if not set
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```typescript
|
|
53
|
-
* import { getServiceUrl } from '@crossdelta/infrastructure/env'
|
|
54
|
-
*
|
|
55
|
-
* const ordersUrl = getServiceUrl('orders')
|
|
56
|
-
* // Returns process.env.ORDERS_URL
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
export function getServiceUrl(serviceName: ServiceName): string | undefined {
|
|
60
|
-
const envKey = `${toEnvKey(serviceName)}_URL`
|
|
61
|
-
return process.env[envKey]
|
|
62
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { AppSpecEnv } from '@pulumi/digitalocean/types/input'
|
|
2
|
-
import type { ServiceConfig } from '../types'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Get the primary port for a service.
|
|
6
|
-
* Prefers httpPort, falls back to first internalPort, then 8080.
|
|
7
|
-
*/
|
|
8
|
-
function getServicePort(config: ServiceConfig): number {
|
|
9
|
-
if (config.httpPort) return config.httpPort as number
|
|
10
|
-
// internalPorts is Input<Input<number>[]> at type level, but plain number[] at runtime
|
|
11
|
-
const internalPorts = config.internalPorts as number[] | undefined
|
|
12
|
-
if (internalPorts?.[0]) return internalPorts[0]
|
|
13
|
-
return 8080
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Generate internal service URLs for service-to-service communication.
|
|
18
|
-
* Uses DigitalOcean App Platform's internal DNS (e.g., http://orders:3001)
|
|
19
|
-
* Uses internalUrl if defined, otherwise defaults to http://{name}:{port}
|
|
20
|
-
*/
|
|
21
|
-
export function buildInternalUrls(serviceConfigs: ServiceConfig[]): Record<string, string> {
|
|
22
|
-
return Object.fromEntries(
|
|
23
|
-
serviceConfigs.map((config) => {
|
|
24
|
-
const url = config.internalUrl ?? `http://${config.name}:${getServicePort(config)}`
|
|
25
|
-
return [config.name, url]
|
|
26
|
-
}),
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Generate external service URLs based on primary domain and ingress prefix.
|
|
32
|
-
*/
|
|
33
|
-
export function buildExternalUrls(
|
|
34
|
-
serviceConfigs: ServiceConfig[],
|
|
35
|
-
baseUrl: string,
|
|
36
|
-
): Record<string, string> {
|
|
37
|
-
return Object.fromEntries(
|
|
38
|
-
serviceConfigs
|
|
39
|
-
.filter((config) => config.ingressPrefix !== undefined)
|
|
40
|
-
.map((config) => {
|
|
41
|
-
const path = config.ingressPrefix === '/' ? '' : config.ingressPrefix
|
|
42
|
-
return [config.name, `${baseUrl}${path}`]
|
|
43
|
-
}),
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Generate local development URLs (localhost with configured ports).
|
|
49
|
-
*/
|
|
50
|
-
export function buildLocalUrls(serviceConfigs: ServiceConfig[]): Record<string, string> {
|
|
51
|
-
return Object.fromEntries(
|
|
52
|
-
serviceConfigs.map((config) => {
|
|
53
|
-
const port = getServicePort(config)
|
|
54
|
-
return [config.name, `http://localhost:${port}`]
|
|
55
|
-
}),
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Generate environment variables for service URLs.
|
|
61
|
-
* Used to inject service URLs into DO App Platform.
|
|
62
|
-
* Uses internalUrl if defined, otherwise defaults to http://{name}:{port}
|
|
63
|
-
*/
|
|
64
|
-
export function buildServiceUrlEnvs(serviceConfigs: ServiceConfig[]): AppSpecEnv[] {
|
|
65
|
-
return serviceConfigs.map((config) => ({
|
|
66
|
-
key: `${config.name.toUpperCase().replace(/-/g, '_')}_URL`,
|
|
67
|
-
scope: 'RUN_TIME' as const,
|
|
68
|
-
value: config.internalUrl ?? `http://${config.name}:${getServicePort(config)}`,
|
|
69
|
-
}))
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Generate environment variables for service ports.
|
|
74
|
-
* Used to inject service ports into DO App Platform.
|
|
75
|
-
*/
|
|
76
|
-
export function buildServicePortEnvs(serviceConfigs: ServiceConfig[]): AppSpecEnv[] {
|
|
77
|
-
return serviceConfigs.map((config) => ({
|
|
78
|
-
key: `${config.name.toUpperCase().replace(/-/g, '_')}_PORT`,
|
|
79
|
-
scope: 'RUN_TIME' as const,
|
|
80
|
-
value: String(getServicePort(config)),
|
|
81
|
-
}))
|
|
82
|
-
}
|
package/lib/index.ts
DELETED
package/lib/types/index.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { AppSpecService } from '@pulumi/digitalocean/types/input'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Supported container registry types for DigitalOcean App Platform.
|
|
5
|
-
*/
|
|
6
|
-
export const RegistryType = {
|
|
7
|
-
/** Docker Hub - public or private images */
|
|
8
|
-
DOCKER_HUB: 'DOCKER_HUB',
|
|
9
|
-
/** GitHub Container Registry */
|
|
10
|
-
GHCR: 'GHCR',
|
|
11
|
-
/** DigitalOcean Container Registry */
|
|
12
|
-
DOCR: 'DOCR',
|
|
13
|
-
} as const
|
|
14
|
-
|
|
15
|
-
export type RegistryType = (typeof RegistryType)[keyof typeof RegistryType]
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Image configuration for a service.
|
|
19
|
-
*/
|
|
20
|
-
export interface ImageConfig {
|
|
21
|
-
/** Registry type */
|
|
22
|
-
registryType: RegistryType
|
|
23
|
-
/** Registry name (e.g., 'library' for official Docker Hub images, 'orderboss' for GHCR) */
|
|
24
|
-
registry: string
|
|
25
|
-
/** Repository name (e.g., 'nats', 'platform/storefront') */
|
|
26
|
-
repository: string
|
|
27
|
-
/** Image tag (e.g., '2.10-alpine', 'latest') */
|
|
28
|
-
tag: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Configuration for a service that will be deployed to DigitalOcean App Platform.
|
|
33
|
-
* Each service in infra/services/*.ts should export a default object of this type.
|
|
34
|
-
*
|
|
35
|
-
* ## Port Configuration
|
|
36
|
-
*
|
|
37
|
-
* Services can expose ports in two ways:
|
|
38
|
-
*
|
|
39
|
-
* - `httpPort`: Public HTTP port with ingress routing (requires `ingressPrefix`)
|
|
40
|
-
* - `internalPorts`: Internal-only ports, not publicly accessible
|
|
41
|
-
*
|
|
42
|
-
* The **first port** (httpPort or internalPorts[0]) is used as the primary port for:
|
|
43
|
-
* - `<SERVICE>_PORT` environment variable
|
|
44
|
-
* - `<SERVICE>_URL` environment variable (unless `internalUrl` is set)
|
|
45
|
-
*
|
|
46
|
-
* ## Examples
|
|
47
|
-
*
|
|
48
|
-
* ```ts
|
|
49
|
-
* // Public service (API Gateway)
|
|
50
|
-
* { httpPort: 4000, ingressPrefix: '/api' }
|
|
51
|
-
*
|
|
52
|
-
* // Internal-only service (Orders)
|
|
53
|
-
* { internalPorts: [4001] }
|
|
54
|
-
*
|
|
55
|
-
* // Internal service with custom protocol (NATS)
|
|
56
|
-
* { internalPorts: [4222, 8222], internalUrl: 'nats://nats:4222' }
|
|
57
|
-
* ```
|
|
58
|
-
*
|
|
59
|
-
* @see https://docs.digitalocean.com/reference/api/digitalocean/#tag/Apps
|
|
60
|
-
*/
|
|
61
|
-
export type ServiceConfig = Partial<Omit<AppSpecService, 'image'>> & {
|
|
62
|
-
/** Unique name of the service (required) */
|
|
63
|
-
name: string
|
|
64
|
-
/**
|
|
65
|
-
* Ingress path prefix for public routing (e.g., '/api').
|
|
66
|
-
* Only used when `httpPort` is set. Services with only `internalPorts` cannot have ingress.
|
|
67
|
-
*/
|
|
68
|
-
ingressPrefix?: string
|
|
69
|
-
/** Set to true to exclude this service from deployment */
|
|
70
|
-
skip?: boolean
|
|
71
|
-
/** Custom image configuration (defaults to GHCR image based on service name) */
|
|
72
|
-
image?: ImageConfig
|
|
73
|
-
/**
|
|
74
|
-
* Override the internal URL for service-to-service communication.
|
|
75
|
-
* Use this for non-HTTP protocols (e.g., 'nats://nats:4222').
|
|
76
|
-
* If not set, defaults to `http://{name}:{primaryPort}`.
|
|
77
|
-
*/
|
|
78
|
-
internalUrl?: string
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Full service spec after merging with common config.
|
|
83
|
-
* This is what gets passed to the DigitalOcean App spec.
|
|
84
|
-
*/
|
|
85
|
-
export type FullServiceSpec = AppSpecService
|
|
86
|
-
|
|
87
|
-
export * from './service-names'
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-generated file - do not edit manually!
|
|
3
|
-
* Generated by: bun run generate-env
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Known service names in the platform.
|
|
8
|
-
* This type is auto-generated from infra/services/*.ts
|
|
9
|
-
*/
|
|
10
|
-
export type ServiceName = 'nats' | 'orders' | 'storefront' | 'api-gateway'
|