container-superposition 0.1.1 → 0.1.3
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 +206 -1
- package/dist/scripts/init.js +235 -179
- package/dist/scripts/init.js.map +1 -1
- package/dist/tool/commands/doctor.d.ts +15 -0
- package/dist/tool/commands/doctor.d.ts.map +1 -0
- package/dist/tool/commands/doctor.js +862 -0
- package/dist/tool/commands/doctor.js.map +1 -0
- package/dist/tool/commands/explain.d.ts +13 -0
- package/dist/tool/commands/explain.d.ts.map +1 -0
- package/dist/tool/commands/explain.js +211 -0
- package/dist/tool/commands/explain.js.map +1 -0
- package/dist/tool/commands/list.d.ts +16 -0
- package/dist/tool/commands/list.d.ts.map +1 -0
- package/dist/tool/commands/list.js +121 -0
- package/dist/tool/commands/list.js.map +1 -0
- package/dist/tool/commands/plan.d.ts +16 -0
- package/dist/tool/commands/plan.d.ts.map +1 -0
- package/dist/tool/commands/plan.js +329 -0
- package/dist/tool/commands/plan.js.map +1 -0
- package/dist/tool/questionnaire/composer.d.ts +6 -1
- package/dist/tool/questionnaire/composer.d.ts.map +1 -1
- package/dist/tool/questionnaire/composer.js +300 -202
- package/dist/tool/questionnaire/composer.js.map +1 -1
- package/dist/tool/readme/markdown-parser.d.ts.map +1 -1
- package/dist/tool/readme/markdown-parser.js.map +1 -1
- package/dist/tool/readme/readme-generator.d.ts.map +1 -1
- package/dist/tool/readme/readme-generator.js +11 -6
- package/dist/tool/readme/readme-generator.js.map +1 -1
- package/dist/tool/schema/deployment-targets.d.ts +77 -0
- package/dist/tool/schema/deployment-targets.d.ts.map +1 -0
- package/dist/tool/schema/deployment-targets.js +91 -0
- package/dist/tool/schema/deployment-targets.js.map +1 -0
- package/dist/tool/schema/manifest-migrations.d.ts +51 -0
- package/dist/tool/schema/manifest-migrations.d.ts.map +1 -0
- package/dist/tool/schema/manifest-migrations.js +159 -0
- package/dist/tool/schema/manifest-migrations.js.map +1 -0
- package/dist/tool/schema/overlay-loader.d.ts +1 -1
- package/dist/tool/schema/overlay-loader.d.ts.map +1 -1
- package/dist/tool/schema/overlay-loader.js +42 -14
- package/dist/tool/schema/overlay-loader.js.map +1 -1
- package/dist/tool/schema/types.d.ts +44 -2
- package/dist/tool/schema/types.d.ts.map +1 -1
- package/dist/tool/utils/merge.d.ts +134 -0
- package/dist/tool/utils/merge.d.ts.map +1 -0
- package/dist/tool/utils/merge.js +277 -0
- package/dist/tool/utils/merge.js.map +1 -0
- package/dist/tool/utils/port-utils.d.ts +29 -0
- package/dist/tool/utils/port-utils.d.ts.map +1 -0
- package/dist/tool/utils/port-utils.js +128 -0
- package/dist/tool/utils/port-utils.js.map +1 -0
- package/dist/tool/utils/version.d.ts +9 -0
- package/dist/tool/utils/version.d.ts.map +1 -0
- package/dist/tool/utils/version.js +32 -0
- package/dist/tool/utils/version.js.map +1 -0
- package/docs/architecture.md +25 -21
- package/docs/deployment-targets.md +150 -0
- package/docs/discovery-commands.md +442 -0
- package/docs/merge-strategy.md +700 -0
- package/docs/minimal-and-editor.md +265 -0
- package/docs/overlay-imports.md +209 -0
- package/docs/overlay-manifest-refactoring.md +2 -2
- package/docs/overlay-metadata-archive.md +1 -1
- package/docs/overlays.md +91 -23
- package/docs/presets-architecture.md +3 -3
- package/docs/presets.md +1 -1
- package/docs/publishing.md +36 -35
- package/docs/team-workflow.md +540 -0
- package/overlays/.presets/data-engineering.yml +392 -0
- package/overlays/.presets/event-sourced-service.yml +262 -0
- package/overlays/.presets/frontend.yml +287 -0
- package/overlays/.presets/k8s-operator-dev.yml +462 -0
- package/overlays/.registry/README.md +1 -1
- package/overlays/.registry/deployment-targets.yml +54 -0
- package/overlays/.shared/README.md +43 -0
- package/overlays/.shared/compose/common-healthchecks.yml +38 -0
- package/overlays/.shared/otel/instrumentation.env +20 -0
- package/overlays/.shared/otel/otel-base-config.yaml +30 -0
- package/overlays/.shared/vscode/recommended-extensions.json +14 -0
- package/overlays/README.md +1 -1
- package/overlays/codex/overlay.yml +1 -0
- package/overlays/duckdb/README.md +274 -0
- package/overlays/duckdb/devcontainer.patch.json +10 -0
- package/overlays/duckdb/overlay.yml +17 -0
- package/overlays/duckdb/setup.sh +45 -0
- package/overlays/duckdb/verify.sh +32 -0
- package/overlays/git-helpers/overlay.yml +1 -0
- package/overlays/grafana/README.md +5 -5
- package/overlays/grafana/dashboard-provider.yml +1 -1
- package/overlays/grafana/docker-compose.yml +2 -2
- package/overlays/grafana/overlay.yml +6 -1
- package/overlays/jaeger/overlay.yml +16 -3
- package/overlays/jupyter/.env.example +6 -0
- package/overlays/jupyter/README.md +210 -0
- package/overlays/jupyter/devcontainer.patch.json +14 -0
- package/overlays/jupyter/docker-compose.yml +23 -0
- package/overlays/jupyter/overlay.yml +18 -0
- package/overlays/jupyter/verify.sh +35 -0
- package/overlays/kind/README.md +221 -0
- package/overlays/kind/devcontainer.patch.json +10 -0
- package/overlays/kind/overlay.yml +18 -0
- package/overlays/kind/setup.sh +43 -0
- package/overlays/kind/verify.sh +40 -0
- package/overlays/localstack/.env.example +6 -0
- package/overlays/localstack/README.md +188 -0
- package/overlays/localstack/devcontainer.patch.json +21 -0
- package/overlays/localstack/docker-compose.yml +25 -0
- package/overlays/localstack/overlay.yml +18 -0
- package/overlays/localstack/verify.sh +47 -0
- package/overlays/loki/overlay.yml +6 -1
- package/overlays/modern-cli-tools/overlay.yml +1 -0
- package/overlays/mongodb/overlay.yml +12 -2
- package/overlays/mysql/overlay.yml +12 -2
- package/overlays/nats/overlay.yml +12 -2
- package/overlays/openapi-tools/README.md +243 -0
- package/overlays/openapi-tools/devcontainer.patch.json +10 -0
- package/overlays/openapi-tools/overlay.yml +16 -0
- package/overlays/openapi-tools/setup.sh +45 -0
- package/overlays/openapi-tools/verify.sh +51 -0
- package/overlays/otel-collector/overlay.yml.example +26 -0
- package/overlays/postgres/overlay.yml +6 -1
- package/overlays/prometheus/overlay.yml +6 -1
- package/overlays/rabbitmq/overlay.yml +12 -2
- package/overlays/redis/overlay.yml +6 -1
- package/overlays/tilt/README.md +259 -0
- package/overlays/tilt/devcontainer.patch.json +17 -0
- package/overlays/tilt/overlay.yml +19 -0
- package/overlays/tilt/setup.sh +25 -0
- package/overlays/tilt/verify.sh +24 -0
- package/package.json +8 -6
- package/tool/README.md +12 -16
- package/tool/schema/overlay-manifest.schema.json +64 -4
- package/tool/schema/superposition-manifest.schema.json +104 -0
- /package/overlays/{presets → .presets}/docs-site.yml +0 -0
- /package/overlays/{presets → .presets}/fullstack.yml +0 -0
- /package/overlays/{presets → .presets}/microservice.yml +0 -0
- /package/overlays/{presets → .presets}/web-api.yml +0 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge utilities for container-superposition
|
|
3
|
+
*
|
|
4
|
+
* This module implements the formal merge strategy specification for combining
|
|
5
|
+
* devcontainer configurations, docker-compose files, and environment variables.
|
|
6
|
+
*
|
|
7
|
+
* See docs/merge-strategy.md for the complete specification.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Deep merge two objects with special handling for arrays and specific fields.
|
|
11
|
+
*
|
|
12
|
+
* Merge strategy:
|
|
13
|
+
* - Objects: Recursively merged
|
|
14
|
+
* - Arrays: Concatenated and deduplicated (union strategy)
|
|
15
|
+
* - Primitives: Source overwrites target (last writer wins)
|
|
16
|
+
* - Special cases: remoteEnv (PATH handling), features, etc.
|
|
17
|
+
*
|
|
18
|
+
* @param target - Base object to merge into
|
|
19
|
+
* @param source - Object to merge from (takes precedence)
|
|
20
|
+
* @returns Merged object
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const base = { features: { "node:1": { version: "lts" } } };
|
|
24
|
+
* const overlay = { features: { "node:1": { nodeGypDependencies: true } } };
|
|
25
|
+
* const result = deepMerge(base, overlay);
|
|
26
|
+
* // Result: { features: { "node:1": { version: "lts", nodeGypDependencies: true } } }
|
|
27
|
+
*/
|
|
28
|
+
export function deepMerge(target, source) {
|
|
29
|
+
const output = { ...target };
|
|
30
|
+
for (const key in source) {
|
|
31
|
+
if (source[key] instanceof Object && key in target) {
|
|
32
|
+
if (Array.isArray(source[key])) {
|
|
33
|
+
// For arrays, concatenate and deduplicate
|
|
34
|
+
// Empty source arrays do not clear target arrays
|
|
35
|
+
if (source[key].length === 0) {
|
|
36
|
+
output[key] = target[key];
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
output[key] = Array.isArray(target[key])
|
|
40
|
+
? [...new Set([...target[key], ...source[key]])]
|
|
41
|
+
: source[key];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (key === 'remoteEnv') {
|
|
45
|
+
// Special handling for remoteEnv to merge PATH variables intelligently
|
|
46
|
+
output[key] = mergeRemoteEnv(target[key], source[key]);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Recursively merge objects
|
|
50
|
+
output[key] = deepMerge(target[key], source[key]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// Source value overwrites target (last writer wins)
|
|
55
|
+
output[key] = source[key];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return output;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Split PATH string on colons, preserving ${...} variable references.
|
|
62
|
+
*
|
|
63
|
+
* Handles environment variable references like ${containerEnv:HOME} without
|
|
64
|
+
* splitting them on the colon inside the braces.
|
|
65
|
+
*
|
|
66
|
+
* @param pathString - PATH value with colon-separated components
|
|
67
|
+
* @returns Array of path components
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* splitPath("${containerEnv:HOME}/bin:${containerEnv:PATH}")
|
|
71
|
+
* // Returns: ["${containerEnv:HOME}/bin", "${containerEnv:PATH}"]
|
|
72
|
+
*/
|
|
73
|
+
function splitPath(pathString) {
|
|
74
|
+
const paths = [];
|
|
75
|
+
let current = '';
|
|
76
|
+
let braceDepth = 0;
|
|
77
|
+
for (let i = 0; i < pathString.length; i++) {
|
|
78
|
+
const char = pathString[i];
|
|
79
|
+
const nextChar = pathString[i + 1];
|
|
80
|
+
if (char === '$' && nextChar === '{') {
|
|
81
|
+
current += char;
|
|
82
|
+
braceDepth++;
|
|
83
|
+
}
|
|
84
|
+
else if (char === '}' && braceDepth > 0) {
|
|
85
|
+
current += char;
|
|
86
|
+
braceDepth--;
|
|
87
|
+
}
|
|
88
|
+
else if (char === ':' && braceDepth === 0) {
|
|
89
|
+
// Split here - we're not inside ${...}
|
|
90
|
+
if (current) {
|
|
91
|
+
paths.push(current);
|
|
92
|
+
}
|
|
93
|
+
current = '';
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
current += char;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Add the last component
|
|
100
|
+
if (current) {
|
|
101
|
+
paths.push(current);
|
|
102
|
+
}
|
|
103
|
+
return paths;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Merge remoteEnv objects with intelligent PATH handling.
|
|
107
|
+
*
|
|
108
|
+
* For PATH variables:
|
|
109
|
+
* 1. Split on colons (preserving ${...} references)
|
|
110
|
+
* 2. Remove ${containerEnv:PATH} placeholders
|
|
111
|
+
* 3. Concatenate and deduplicate
|
|
112
|
+
* 4. Append ${containerEnv:PATH} at end
|
|
113
|
+
*
|
|
114
|
+
* For other variables:
|
|
115
|
+
* - Source overwrites target (last writer wins)
|
|
116
|
+
*
|
|
117
|
+
* @param target - Base environment variables
|
|
118
|
+
* @param source - Overlay environment variables
|
|
119
|
+
* @returns Merged environment variables
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* mergeRemoteEnv(
|
|
123
|
+
* { PATH: "/usr/local/bin:${containerEnv:PATH}", NODE_ENV: "development" },
|
|
124
|
+
* { PATH: "${containerEnv:HOME}/.local/bin:${containerEnv:PATH}", NODE_ENV: "production" }
|
|
125
|
+
* )
|
|
126
|
+
* // Returns:
|
|
127
|
+
* // {
|
|
128
|
+
* // PATH: "/usr/local/bin:${containerEnv:HOME}/.local/bin:${containerEnv:PATH}",
|
|
129
|
+
* // NODE_ENV: "production"
|
|
130
|
+
* // }
|
|
131
|
+
*/
|
|
132
|
+
export function mergeRemoteEnv(target, source) {
|
|
133
|
+
const output = { ...target };
|
|
134
|
+
for (const key in source) {
|
|
135
|
+
if (key === 'PATH' && target[key]) {
|
|
136
|
+
// Collect PATH components from both target and source using smart split
|
|
137
|
+
const targetPaths = splitPath(target[key]).filter((p) => p && p !== '${containerEnv:PATH}');
|
|
138
|
+
const sourcePaths = splitPath(source[key]).filter((p) => p && p !== '${containerEnv:PATH}');
|
|
139
|
+
// Combine and deduplicate paths, preserving order
|
|
140
|
+
const allPaths = [...new Set([...targetPaths, ...sourcePaths])];
|
|
141
|
+
// Rebuild PATH with original ${containerEnv:PATH} at the end
|
|
142
|
+
output[key] = [...allPaths, '${containerEnv:PATH}'].join(':');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// For non-PATH variables, source overwrites target
|
|
146
|
+
output[key] = source[key];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return output;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Merge space-separated package lists with deduplication.
|
|
153
|
+
*
|
|
154
|
+
* Used for apt, apk, and other package manager lists.
|
|
155
|
+
*
|
|
156
|
+
* @param existing - Current package list (space-separated)
|
|
157
|
+
* @param additional - Additional packages to merge (space-separated)
|
|
158
|
+
* @returns Merged package list (space-separated, deduplicated)
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* mergePackages("curl wget", "wget jq")
|
|
162
|
+
* // Returns: "curl wget jq"
|
|
163
|
+
*/
|
|
164
|
+
export function mergePackages(existing, additional) {
|
|
165
|
+
// Filter out empty tokens from split to avoid leading/trailing spaces
|
|
166
|
+
const existingPackages = existing.split(' ').filter((p) => p);
|
|
167
|
+
const newPackages = additional.split(' ').filter((p) => p);
|
|
168
|
+
// Merge and deduplicate
|
|
169
|
+
const merged = [...new Set([...existingPackages, ...newPackages])];
|
|
170
|
+
return merged.join(' ');
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Filter depends_on to only include services that exist in the final composition.
|
|
174
|
+
*
|
|
175
|
+
* Supports both Docker Compose syntaxes:
|
|
176
|
+
* - Array form: depends_on: [serviceA, serviceB]
|
|
177
|
+
* - Object form: depends_on: { serviceA: { condition: ... } }
|
|
178
|
+
*
|
|
179
|
+
* @param dependsOn - Original depends_on configuration
|
|
180
|
+
* @param existingServices - Set of service names that exist
|
|
181
|
+
* @returns Filtered depends_on (undefined if empty after filtering)
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* filterDependsOn(
|
|
185
|
+
* ["postgres", "redis", "rabbitmq"],
|
|
186
|
+
* new Set(["postgres", "redis"])
|
|
187
|
+
* )
|
|
188
|
+
* // Returns: ["postgres", "redis"]
|
|
189
|
+
*/
|
|
190
|
+
export function filterDependsOn(dependsOn, existingServices) {
|
|
191
|
+
if (Array.isArray(dependsOn)) {
|
|
192
|
+
const filtered = dependsOn.filter((dep) => typeof dep === 'string' && existingServices.has(dep));
|
|
193
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
194
|
+
}
|
|
195
|
+
if (dependsOn && typeof dependsOn === 'object') {
|
|
196
|
+
const filtered = Object.fromEntries(Object.entries(dependsOn).filter(([dep]) => existingServices.has(dep)));
|
|
197
|
+
return Object.keys(filtered).length > 0 ? filtered : undefined;
|
|
198
|
+
}
|
|
199
|
+
return dependsOn;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Apply port offset to port string or number.
|
|
203
|
+
*
|
|
204
|
+
* @param port - Port value (string or number)
|
|
205
|
+
* @param offset - Offset to apply
|
|
206
|
+
* @returns Port with offset applied
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* applyPortOffset("5432:5432", 100)
|
|
210
|
+
* // Returns: "5532:5432" (only host port offset)
|
|
211
|
+
*
|
|
212
|
+
* applyPortOffset(3000, 100)
|
|
213
|
+
* // Returns: 3100
|
|
214
|
+
*/
|
|
215
|
+
export function applyPortOffset(port, offset) {
|
|
216
|
+
if (typeof port === 'number') {
|
|
217
|
+
return port + offset;
|
|
218
|
+
}
|
|
219
|
+
// Handle string port mappings like "5432:5432" or "127.0.0.1:5432:5432"
|
|
220
|
+
const parts = port.split(':');
|
|
221
|
+
if (parts.length >= 2) {
|
|
222
|
+
// Format: "host:container" or "ip:host:container"
|
|
223
|
+
// Offset the host port (last or second-to-last number)
|
|
224
|
+
const isThreePart = parts.length === 3;
|
|
225
|
+
const hostPortIndex = isThreePart ? 1 : 0;
|
|
226
|
+
const hostPort = parseInt(parts[hostPortIndex], 10);
|
|
227
|
+
if (!isNaN(hostPort)) {
|
|
228
|
+
parts[hostPortIndex] = String(hostPort + offset);
|
|
229
|
+
return parts.join(':');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// If we can't parse it, return as-is
|
|
233
|
+
return port;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Apply port offset to environment variable content.
|
|
237
|
+
*
|
|
238
|
+
* Finds variables matching *PORT*=number pattern and applies offset.
|
|
239
|
+
*
|
|
240
|
+
* @param envContent - Environment file content
|
|
241
|
+
* @param offset - Port offset to apply
|
|
242
|
+
* @returns Modified environment content
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* applyPortOffsetToEnv("POSTGRES_PORT=5432\nAPP_NAME=myapp", 100)
|
|
246
|
+
* // Returns: "POSTGRES_PORT=5532\nAPP_NAME=myapp"
|
|
247
|
+
*/
|
|
248
|
+
export function applyPortOffsetToEnv(envContent, offset) {
|
|
249
|
+
const lines = envContent.split('\n');
|
|
250
|
+
const portVarPattern = /^([A-Z_]*PORT[A-Z_]*)=(\d+)$/;
|
|
251
|
+
const modifiedLines = lines.map((line) => {
|
|
252
|
+
const match = line.match(portVarPattern);
|
|
253
|
+
if (match) {
|
|
254
|
+
const [, varName, portValue] = match;
|
|
255
|
+
const newPort = parseInt(portValue, 10) + offset;
|
|
256
|
+
return `${varName}=${newPort}`;
|
|
257
|
+
}
|
|
258
|
+
return line;
|
|
259
|
+
});
|
|
260
|
+
return modifiedLines.join('\n');
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Merge strategy metadata for documentation and testing.
|
|
264
|
+
*/
|
|
265
|
+
export const MERGE_STRATEGY = {
|
|
266
|
+
version: '1.0.0',
|
|
267
|
+
description: 'Formal merge strategy specification for container-superposition',
|
|
268
|
+
rules: {
|
|
269
|
+
objects: 'deep-merge',
|
|
270
|
+
arrays: 'union-deduplicate',
|
|
271
|
+
primitives: 'last-writer-wins',
|
|
272
|
+
remoteEnv: 'intelligent-PATH-merging',
|
|
273
|
+
packages: 'space-separated-union',
|
|
274
|
+
dependsOn: 'filter-to-existing-services',
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../tool/utils/merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Port utilities for normalizing and documenting ports
|
|
3
|
+
*/
|
|
4
|
+
import type { PortMetadata, NormalizedPort, PortsDocumentation, OverlayMetadata } from '../schema/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Normalize a port entry (number or PortMetadata) to NormalizedPort format
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizePort(port: number | PortMetadata, offset: number, overlayId?: string): NormalizedPort;
|
|
9
|
+
/**
|
|
10
|
+
* Generate connection string from template
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateConnectionString(template: string, port: NormalizedPort, envVars?: Record<string, string>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get default connection string template for common services
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDefaultConnectionStringTemplate(service: string, protocol?: string): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Generate URL for HTTP/HTTPS services
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateUrl(port: NormalizedPort): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Generate ports documentation from overlays
|
|
23
|
+
*/
|
|
24
|
+
export declare function generatePortsDocumentation(overlays: OverlayMetadata[], portOffset: number, envVars?: Record<string, string>): PortsDocumentation;
|
|
25
|
+
/**
|
|
26
|
+
* Extract all unique ports from overlays (for offset calculation)
|
|
27
|
+
*/
|
|
28
|
+
export declare function extractPorts(overlays: OverlayMetadata[]): number[];
|
|
29
|
+
//# sourceMappingURL=port-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-utils.d.ts","sourceRoot":"","sources":["../../../tool/utils/port-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,eAAe,EAClB,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,wBAAgB,aAAa,CACzB,IAAI,EAAE,MAAM,GAAG,YAAY,EAC3B,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACnB,cAAc,CAgBhB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAoBR;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAC9C,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAiBpB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAMpE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACtC,QAAQ,EAAE,eAAe,EAAE,EAC3B,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,kBAAkB,CAgDpB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,CAelE"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Port utilities for normalizing and documenting ports
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Normalize a port entry (number or PortMetadata) to NormalizedPort format
|
|
6
|
+
*/
|
|
7
|
+
export function normalizePort(port, offset, overlayId) {
|
|
8
|
+
if (typeof port === 'number') {
|
|
9
|
+
// Legacy format - just a number
|
|
10
|
+
return {
|
|
11
|
+
port,
|
|
12
|
+
actualPort: port + offset,
|
|
13
|
+
service: overlayId,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
// Rich format - already an object
|
|
17
|
+
return {
|
|
18
|
+
...port,
|
|
19
|
+
actualPort: port.port + offset,
|
|
20
|
+
service: port.service || overlayId,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate connection string from template
|
|
25
|
+
*/
|
|
26
|
+
export function generateConnectionString(template, port, envVars = {}) {
|
|
27
|
+
let result = template;
|
|
28
|
+
// Replace port placeholder
|
|
29
|
+
result = result.replace(/\{port\}/g, String(port.actualPort));
|
|
30
|
+
// Replace other placeholders from environment variables or port metadata
|
|
31
|
+
const replacements = {
|
|
32
|
+
host: 'localhost',
|
|
33
|
+
service: port.service || 'unknown',
|
|
34
|
+
path: port.path || '',
|
|
35
|
+
...envVars,
|
|
36
|
+
};
|
|
37
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
38
|
+
const regex = new RegExp(`\\{${key}\\}`, 'g');
|
|
39
|
+
result = result.replace(regex, value);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get default connection string template for common services
|
|
45
|
+
*/
|
|
46
|
+
export function getDefaultConnectionStringTemplate(service, protocol) {
|
|
47
|
+
const templates = {
|
|
48
|
+
postgres: 'postgresql://{user}:{password}@{host}:{port}/{database}',
|
|
49
|
+
postgresql: 'postgresql://{user}:{password}@{host}:{port}/{database}',
|
|
50
|
+
mysql: 'mysql://{user}:{password}@{host}:{port}/{database}',
|
|
51
|
+
mongodb: 'mongodb://{user}:{password}@{host}:{port}/{database}',
|
|
52
|
+
redis: 'redis://{host}:{port}',
|
|
53
|
+
rabbitmq: 'amqp://{user}:{password}@{host}:{port}',
|
|
54
|
+
nats: 'nats://{host}:{port}',
|
|
55
|
+
};
|
|
56
|
+
// For HTTP/HTTPS services, use URL format
|
|
57
|
+
if (protocol === 'http' || protocol === 'https') {
|
|
58
|
+
return `${protocol}://{host}:{port}{path}`;
|
|
59
|
+
}
|
|
60
|
+
return templates[service.toLowerCase()];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate URL for HTTP/HTTPS services
|
|
64
|
+
*/
|
|
65
|
+
export function generateUrl(port) {
|
|
66
|
+
if (port.protocol === 'http' || port.protocol === 'https') {
|
|
67
|
+
const path = port.path || '';
|
|
68
|
+
return `${port.protocol}://localhost:${port.actualPort}${path}`;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generate ports documentation from overlays
|
|
74
|
+
*/
|
|
75
|
+
export function generatePortsDocumentation(overlays, portOffset, envVars = {}) {
|
|
76
|
+
const allPorts = [];
|
|
77
|
+
const connectionStrings = {};
|
|
78
|
+
for (const overlay of overlays) {
|
|
79
|
+
if (!overlay.ports || overlay.ports.length === 0) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
for (const portEntry of overlay.ports) {
|
|
83
|
+
const normalizedPort = normalizePort(portEntry, portOffset, overlay.id);
|
|
84
|
+
allPorts.push(normalizedPort);
|
|
85
|
+
// Generate connection string if template is provided or can be inferred
|
|
86
|
+
const template = typeof portEntry === 'object' && portEntry.connectionStringTemplate
|
|
87
|
+
? portEntry.connectionStringTemplate
|
|
88
|
+
: getDefaultConnectionStringTemplate(normalizedPort.service || '', normalizedPort.protocol);
|
|
89
|
+
if (template) {
|
|
90
|
+
const connStr = generateConnectionString(template, normalizedPort, envVars);
|
|
91
|
+
// Use unique key for multi-port services by appending port number if service already exists
|
|
92
|
+
let key = normalizedPort.service || `port-${normalizedPort.port}`;
|
|
93
|
+
// If key already exists, make it unique by adding port number
|
|
94
|
+
if (connectionStrings[key]) {
|
|
95
|
+
key = `${key}-${normalizedPort.port}`;
|
|
96
|
+
}
|
|
97
|
+
connectionStrings[key] = connStr;
|
|
98
|
+
}
|
|
99
|
+
// Generate URL for HTTP/HTTPS services
|
|
100
|
+
const url = generateUrl(normalizedPort);
|
|
101
|
+
if (url && normalizedPort.service) {
|
|
102
|
+
connectionStrings[`${normalizedPort.service}-url`] = url;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
portOffset,
|
|
108
|
+
ports: allPorts,
|
|
109
|
+
connectionStrings,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extract all unique ports from overlays (for offset calculation)
|
|
114
|
+
*/
|
|
115
|
+
export function extractPorts(overlays) {
|
|
116
|
+
const ports = new Set();
|
|
117
|
+
for (const overlay of overlays) {
|
|
118
|
+
if (!overlay.ports) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
for (const portEntry of overlay.ports) {
|
|
122
|
+
const port = typeof portEntry === 'number' ? portEntry : portEntry.port;
|
|
123
|
+
ports.add(port);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return Array.from(ports).sort((a, b) => a - b);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=port-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-utils.js","sourceRoot":"","sources":["../../../tool/utils/port-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for version management
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Get the current tool version from package.json
|
|
6
|
+
* Works in both source (TypeScript) and compiled (JavaScript) contexts
|
|
7
|
+
*/
|
|
8
|
+
export declare function getToolVersion(): string;
|
|
9
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../tool/utils/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAmBvC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for version management
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
// Get __dirname equivalent in ESM
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
/**
|
|
11
|
+
* Get the current tool version from package.json
|
|
12
|
+
* Works in both source (TypeScript) and compiled (JavaScript) contexts
|
|
13
|
+
*/
|
|
14
|
+
export function getToolVersion() {
|
|
15
|
+
try {
|
|
16
|
+
// Try multiple paths to handle different execution contexts
|
|
17
|
+
const packageJsonCandidates = [
|
|
18
|
+
// From tool/utils/ (source)
|
|
19
|
+
path.join(__dirname, '..', '..', 'package.json'),
|
|
20
|
+
// From dist/tool/utils/ (compiled)
|
|
21
|
+
path.join(__dirname, '..', '..', '..', 'package.json'),
|
|
22
|
+
];
|
|
23
|
+
const packageJsonPath = packageJsonCandidates.find((candidate) => fs.existsSync(candidate)) ??
|
|
24
|
+
packageJsonCandidates[0];
|
|
25
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
26
|
+
return packageJson.version || 'unknown';
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return 'unknown';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../tool/utils/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,kCAAkC;AAClC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC1B,IAAI,CAAC;QACD,4DAA4D;QAC5D,MAAM,qBAAqB,GAAG;YAC1B,4BAA4B;YAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;YAChD,mCAAmC;YACnC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;SACzD,CAAC;QAEF,MAAM,eAAe,GACjB,qBAAqB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YACnE,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAE7B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QAC1E,OAAO,WAAW,CAAC,OAAO,IAAI,SAAS,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC"}
|
package/docs/architecture.md
CHANGED
|
@@ -74,29 +74,33 @@ scripts/
|
|
|
74
74
|
5. **Merge .env.example** files from all selected overlays
|
|
75
75
|
6. **Write merged configuration** to output path
|
|
76
76
|
|
|
77
|
-
###
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
77
|
+
### Merge Strategy
|
|
78
|
+
|
|
79
|
+
Container-superposition uses a **formal, deterministic merge strategy** for combining configurations from base templates and overlays.
|
|
80
|
+
|
|
81
|
+
**Core principles:**
|
|
82
|
+
|
|
83
|
+
- **Deterministic**: Same inputs always produce same output
|
|
84
|
+
- **Deep merge**: Objects are recursively merged, not replaced
|
|
85
|
+
- **Union by default**: Arrays and collections are merged (unioned), not replaced
|
|
86
|
+
- **Last writer wins**: For conflicting primitive values
|
|
87
|
+
|
|
88
|
+
**Key behaviors:**
|
|
89
|
+
|
|
90
|
+
- **Objects**: Recursively merged
|
|
91
|
+
- **Arrays**: Concatenated and deduplicated (union strategy)
|
|
92
|
+
- **Features**: Deep merged by feature key
|
|
93
|
+
- **remoteEnv**: Intelligent PATH variable merging
|
|
94
|
+
- **Package lists**: Space-separated strings merged with deduplication
|
|
95
|
+
- **depends_on**: Filtered to only existing services
|
|
96
|
+
|
|
97
|
+
For the complete specification with examples, see **[Merge Strategy Specification](merge-strategy.md)**.
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
Implementation details:
|
|
94
100
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
- **Environment variables**: Merge key-value pairs
|
|
99
|
-
- **Port attributes**: Merge labeled port configurations
|
|
101
|
+
- Merge utilities: `tool/utils/merge.ts`
|
|
102
|
+
- Integration: `tool/questionnaire/composer.ts`
|
|
103
|
+
- Tests: `tool/__tests__/merge-strategy.test.ts`
|
|
100
104
|
|
|
101
105
|
### File Handling per Overlay
|
|
102
106
|
|