@kitsy/cnos 0.0.1 → 1.0.1
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 +3 -1
- package/dist/chunk-44JOQPSN.js +109 -0
- package/dist/chunk-ASZ7I3JJ.js +35 -0
- package/dist/chunk-CGTFH4QQ.js +49 -0
- package/dist/chunk-GGYIRIGU.js +83 -0
- package/dist/chunk-H65FPTDM.js +23 -0
- package/dist/chunk-K2T4R5WH.js +1565 -0
- package/dist/chunk-KG6OZX5C.js +202 -0
- package/dist/envNaming-BrOk5ndZ.d.cts +8 -0
- package/dist/envNaming-DCaNdnrF.d.ts +8 -0
- package/dist/index.cjs +1942 -28
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +112 -23
- package/dist/internal.cjs +288 -0
- package/dist/internal.d.cts +20 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.js +18 -0
- package/dist/plugin/basic-schema.cjs +214 -3
- package/dist/plugin/basic-schema.d.cts +5 -6
- package/dist/plugin/basic-schema.d.ts +5 -6
- package/dist/plugin/basic-schema.js +7 -2
- package/dist/plugin/cli-args.cjs +132 -3
- package/dist/plugin/cli-args.d.cts +12 -1
- package/dist/plugin/cli-args.d.ts +12 -1
- package/dist/plugin/cli-args.js +11 -2
- package/dist/plugin/dotenv.cjs +212 -3
- package/dist/plugin/dotenv.d.cts +8 -1
- package/dist/plugin/dotenv.d.ts +8 -1
- package/dist/plugin/dotenv.js +11 -2
- package/dist/plugin/env-export.cjs +222 -3
- package/dist/plugin/env-export.d.cts +7 -1
- package/dist/plugin/env-export.d.ts +7 -1
- package/dist/plugin/env-export.js +14 -2
- package/dist/plugin/filesystem.cjs +320 -3
- package/dist/plugin/filesystem.d.cts +17 -1
- package/dist/plugin/filesystem.d.ts +17 -1
- package/dist/plugin/filesystem.js +17 -2
- package/dist/plugin/process-env.cjs +126 -3
- package/dist/plugin/process-env.d.cts +7 -1
- package/dist/plugin/process-env.d.ts +7 -1
- package/dist/plugin/process-env.js +9 -2
- package/dist/plugin-BVNEHj19.d.cts +309 -0
- package/dist/plugin-BVNEHj19.d.ts +309 -0
- package/dist/toPublicEnv-Dd152fFy.d.cts +7 -0
- package/dist/toPublicEnv-Gwz3xTK0.d.ts +7 -0
- package/package.json +15 -16
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,55 +17,1967 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
23
|
-
createCnos: () =>
|
|
33
|
+
createCnos: () => createCnos2,
|
|
24
34
|
defaultPlugins: () => defaultPlugins,
|
|
25
|
-
planDump: () =>
|
|
26
|
-
toEnv: () =>
|
|
27
|
-
toPublicEnv: () =>
|
|
28
|
-
writeDump: () =>
|
|
35
|
+
planDump: () => planDump,
|
|
36
|
+
toEnv: () => toEnv,
|
|
37
|
+
toPublicEnv: () => toPublicEnv,
|
|
38
|
+
writeDump: () => writeDump
|
|
29
39
|
});
|
|
30
40
|
module.exports = __toCommonJS(index_exports);
|
|
31
41
|
|
|
32
|
-
// src/
|
|
33
|
-
var
|
|
42
|
+
// ../core/src/errors.ts
|
|
43
|
+
var CnosError = class extends Error {
|
|
44
|
+
constructor(message) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = new.target.name;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var CnosManifestError = class extends CnosError {
|
|
50
|
+
constructor(message, manifestPath) {
|
|
51
|
+
super(manifestPath ? `${message} (${manifestPath})` : message);
|
|
52
|
+
this.manifestPath = manifestPath;
|
|
53
|
+
}
|
|
54
|
+
manifestPath;
|
|
55
|
+
};
|
|
56
|
+
var CnosKeyNotFoundError = class extends CnosError {
|
|
57
|
+
constructor(key) {
|
|
58
|
+
super(`Missing required CNOS config key: ${key}`);
|
|
59
|
+
this.key = key;
|
|
60
|
+
}
|
|
61
|
+
key;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ../core/src/runtime/inspect.ts
|
|
65
|
+
function inspectValue(graph, key) {
|
|
66
|
+
const entry = graph.entries.get(key);
|
|
67
|
+
if (!entry) {
|
|
68
|
+
throw new CnosKeyNotFoundError(key);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
key: entry.key,
|
|
72
|
+
value: entry.value,
|
|
73
|
+
namespace: entry.namespace,
|
|
74
|
+
profile: graph.profile,
|
|
75
|
+
profileSource: graph.profileSource,
|
|
76
|
+
workspace: {
|
|
77
|
+
id: graph.workspace.workspaceId,
|
|
78
|
+
source: graph.workspace.workspaceSource,
|
|
79
|
+
chain: graph.workspace.workspaceChain
|
|
80
|
+
},
|
|
81
|
+
winner: {
|
|
82
|
+
sourceId: entry.winner.sourceId,
|
|
83
|
+
pluginId: entry.winner.pluginId,
|
|
84
|
+
workspaceId: entry.winner.workspaceId,
|
|
85
|
+
...entry.winner.origin ? { origin: entry.winner.origin } : {}
|
|
86
|
+
},
|
|
87
|
+
overridden: entry.overridden.map((override) => ({
|
|
88
|
+
sourceId: override.sourceId,
|
|
89
|
+
pluginId: override.pluginId,
|
|
90
|
+
workspaceId: override.workspaceId,
|
|
91
|
+
value: override.value,
|
|
92
|
+
...override.origin ? { origin: override.origin } : {}
|
|
93
|
+
}))
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ../core/src/inspectors/provenance.ts
|
|
98
|
+
function createProvenanceInspector() {
|
|
99
|
+
return {
|
|
100
|
+
id: "provenance",
|
|
101
|
+
kind: "inspector",
|
|
102
|
+
async inspect(key, graph) {
|
|
103
|
+
return inspectValue(graph, key);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ../core/src/manifest/loadManifest.ts
|
|
109
|
+
var import_promises2 = require("fs/promises");
|
|
110
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
111
|
+
|
|
112
|
+
// ../core/src/utils/path.ts
|
|
113
|
+
var import_promises = require("fs/promises");
|
|
114
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
115
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
116
|
+
var PRIMARY_CNOS_DIR = ".cnos";
|
|
117
|
+
var LEGACY_CNOS_DIR = "cnos";
|
|
118
|
+
async function exists(filePath) {
|
|
119
|
+
try {
|
|
120
|
+
await (0, import_promises.access)(filePath);
|
|
121
|
+
return true;
|
|
122
|
+
} catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function resolveCnosRoot(root = process.cwd()) {
|
|
127
|
+
const basePath = import_node_path.default.resolve(root);
|
|
128
|
+
const candidates = [
|
|
129
|
+
import_node_path.default.join(basePath, PRIMARY_CNOS_DIR),
|
|
130
|
+
import_node_path.default.join(basePath, LEGACY_CNOS_DIR),
|
|
131
|
+
basePath
|
|
132
|
+
];
|
|
133
|
+
for (const candidate of candidates) {
|
|
134
|
+
if (await exists(import_node_path.default.join(candidate, "cnos.yml"))) {
|
|
135
|
+
return candidate;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
throw new CnosManifestError(
|
|
139
|
+
`Could not locate .cnos/cnos.yml or cnos/cnos.yml from root: ${basePath}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
async function resolveManifestRoot(root = process.cwd()) {
|
|
143
|
+
return resolveCnosRoot(root);
|
|
144
|
+
}
|
|
145
|
+
function interpolatePathTemplate(template, tokens) {
|
|
146
|
+
return Object.entries(tokens).reduce(
|
|
147
|
+
(result, [token, value]) => result.replaceAll(`{${token}}`, value),
|
|
148
|
+
template
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
function expandHomePath(targetPath) {
|
|
152
|
+
if (targetPath === "~") {
|
|
153
|
+
return import_node_os.default.homedir();
|
|
154
|
+
}
|
|
155
|
+
if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
|
|
156
|
+
return import_node_path.default.join(import_node_os.default.homedir(), targetPath.slice(2));
|
|
157
|
+
}
|
|
158
|
+
return targetPath;
|
|
159
|
+
}
|
|
160
|
+
function stripWorkspaceTemplatePrefix(template) {
|
|
161
|
+
const normalized = template.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
162
|
+
const marker = "workspaces/{workspace}";
|
|
163
|
+
if (normalized === marker) {
|
|
164
|
+
return ".";
|
|
165
|
+
}
|
|
166
|
+
if (normalized.startsWith(`${marker}/`)) {
|
|
167
|
+
return normalized.slice(marker.length + 1);
|
|
168
|
+
}
|
|
169
|
+
return template;
|
|
170
|
+
}
|
|
171
|
+
function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
|
|
172
|
+
const relativeTemplate = stripWorkspaceTemplatePrefix(template);
|
|
173
|
+
const interpolated = interpolatePathTemplate(relativeTemplate, tokens);
|
|
174
|
+
return import_node_path.default.resolve(workspaceRoot, interpolated);
|
|
175
|
+
}
|
|
176
|
+
function toPortablePath(targetPath) {
|
|
177
|
+
return targetPath.replace(/\\/g, "/");
|
|
178
|
+
}
|
|
179
|
+
function joinConfigPath(...parts) {
|
|
180
|
+
return parts.flatMap((part) => part.split(".")).map((part) => part.trim()).filter(Boolean).join(".");
|
|
181
|
+
}
|
|
182
|
+
function toLogicalKey(namespace, valuePath) {
|
|
183
|
+
return `${namespace}.${joinConfigPath(valuePath)}`;
|
|
184
|
+
}
|
|
185
|
+
function stripNamespace(key) {
|
|
186
|
+
return key.split(".").slice(1).join(".");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ../core/src/utils/yaml.ts
|
|
190
|
+
var import_yaml = require("yaml");
|
|
191
|
+
function parseYaml(source) {
|
|
192
|
+
return (0, import_yaml.parse)(source);
|
|
193
|
+
}
|
|
194
|
+
function stringifyYaml(value) {
|
|
195
|
+
return (0, import_yaml.stringify)(value);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ../core/src/manifest/normalizeManifest.ts
|
|
199
|
+
var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
200
|
+
var DEFAULT_LOADERS = [
|
|
201
|
+
"filesystem-values",
|
|
202
|
+
"filesystem-secrets",
|
|
203
|
+
"dotenv",
|
|
204
|
+
"process-env",
|
|
205
|
+
"cli-args"
|
|
206
|
+
];
|
|
207
|
+
var DEFAULT_VALIDATORS = ["basic-schema"];
|
|
208
|
+
var DEFAULT_EXPORTERS = ["env", "public-env"];
|
|
209
|
+
var DEFAULT_INSPECTORS = ["provenance"];
|
|
210
|
+
var DEFAULT_FRAMEWORK_PREFIXES = {
|
|
211
|
+
next: "NEXT_PUBLIC_",
|
|
212
|
+
vite: "VITE_",
|
|
213
|
+
nuxt: "NUXT_PUBLIC_"
|
|
214
|
+
};
|
|
215
|
+
function validateResolveFrom(resolveFrom) {
|
|
216
|
+
const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
217
|
+
for (const entry of resolveFrom) {
|
|
218
|
+
if (!validValues.includes(entry)) {
|
|
219
|
+
throw new CnosManifestError(`Unsupported profiles.resolveFrom entry: ${entry}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return resolveFrom;
|
|
223
|
+
}
|
|
224
|
+
function normalizeWorkspaceItems(items) {
|
|
225
|
+
return Object.fromEntries(
|
|
226
|
+
Object.entries(items ?? {}).map(([workspaceId, item]) => [
|
|
227
|
+
workspaceId,
|
|
228
|
+
{
|
|
229
|
+
extends: Array.isArray(item?.extends) ? item.extends.map((entry) => entry.trim()).filter(Boolean) : item?.extends ? [item.extends.trim()].filter(Boolean) : [],
|
|
230
|
+
...item?.globalId?.trim() ? { globalId: item.globalId.trim() } : {}
|
|
231
|
+
}
|
|
232
|
+
])
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
function normalizeManifest(manifest) {
|
|
236
|
+
const version = manifest.version ?? 1;
|
|
237
|
+
if (version !== 1) {
|
|
238
|
+
throw new CnosManifestError(`Unsupported CNOS manifest version: ${version}`);
|
|
239
|
+
}
|
|
240
|
+
const projectName = manifest.project?.name?.trim();
|
|
241
|
+
if (!projectName) {
|
|
242
|
+
throw new CnosManifestError("Manifest requires project.name");
|
|
243
|
+
}
|
|
244
|
+
const defaultProfile = manifest.profiles?.default?.trim() || "base";
|
|
245
|
+
const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
|
|
246
|
+
const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
|
|
247
|
+
const filesystemValues = {
|
|
248
|
+
root: "./",
|
|
249
|
+
format: "yaml",
|
|
250
|
+
...manifest.sources?.["filesystem-values"] ?? {}
|
|
251
|
+
};
|
|
252
|
+
const filesystemSecrets = {
|
|
253
|
+
root: "./",
|
|
254
|
+
format: "yaml",
|
|
255
|
+
...manifest.sources?.["filesystem-secrets"] ?? {}
|
|
256
|
+
};
|
|
257
|
+
const dotenv = {
|
|
258
|
+
root: "./env",
|
|
259
|
+
...manifest.sources?.dotenv ?? {}
|
|
260
|
+
};
|
|
261
|
+
return {
|
|
262
|
+
version: 1,
|
|
263
|
+
project: {
|
|
264
|
+
name: projectName
|
|
265
|
+
},
|
|
266
|
+
workspaces: {
|
|
267
|
+
...manifest.workspaces?.default?.trim() ? {
|
|
268
|
+
default: manifest.workspaces.default.trim()
|
|
269
|
+
} : {},
|
|
270
|
+
global: {
|
|
271
|
+
enabled: manifest.workspaces?.global?.enabled ?? false,
|
|
272
|
+
...manifest.workspaces?.global?.root?.trim() ? {
|
|
273
|
+
root: manifest.workspaces.global.root.trim()
|
|
274
|
+
} : {},
|
|
275
|
+
allowWrite: manifest.workspaces?.global?.allowWrite ?? false
|
|
276
|
+
},
|
|
277
|
+
items: workspaceItems
|
|
278
|
+
},
|
|
279
|
+
profiles: {
|
|
280
|
+
default: defaultProfile,
|
|
281
|
+
resolveFrom
|
|
282
|
+
},
|
|
283
|
+
plugins: {
|
|
284
|
+
loaders: manifest.plugins?.loaders ?? DEFAULT_LOADERS,
|
|
285
|
+
resolver: manifest.plugins?.resolver ?? "profile-aware",
|
|
286
|
+
validators: manifest.plugins?.validators ?? DEFAULT_VALIDATORS,
|
|
287
|
+
exporters: manifest.plugins?.exporters ?? DEFAULT_EXPORTERS,
|
|
288
|
+
inspectors: manifest.plugins?.inspectors ?? DEFAULT_INSPECTORS
|
|
289
|
+
},
|
|
290
|
+
sources: {
|
|
291
|
+
...manifest.sources ?? {},
|
|
292
|
+
"filesystem-values": filesystemValues,
|
|
293
|
+
"filesystem-secrets": filesystemSecrets,
|
|
294
|
+
dotenv
|
|
295
|
+
},
|
|
296
|
+
resolution: {
|
|
297
|
+
precedence: manifest.resolution?.precedence ?? [
|
|
298
|
+
"filesystem-values",
|
|
299
|
+
"filesystem-secrets",
|
|
300
|
+
"dotenv",
|
|
301
|
+
"process-env",
|
|
302
|
+
"cli-args"
|
|
303
|
+
],
|
|
304
|
+
arrayPolicy: manifest.resolution?.arrayPolicy ?? "replace"
|
|
305
|
+
},
|
|
306
|
+
envMapping: {
|
|
307
|
+
...manifest.envMapping?.convention ? {
|
|
308
|
+
convention: manifest.envMapping.convention
|
|
309
|
+
} : {},
|
|
310
|
+
explicit: manifest.envMapping?.explicit ?? {}
|
|
311
|
+
},
|
|
312
|
+
public: {
|
|
313
|
+
promote: manifest.public?.promote ?? [],
|
|
314
|
+
frameworks: {
|
|
315
|
+
...DEFAULT_FRAMEWORK_PREFIXES,
|
|
316
|
+
...manifest.public?.frameworks ?? {}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
writePolicy: {
|
|
320
|
+
define: {
|
|
321
|
+
defaultProfile: manifest.writePolicy?.define?.defaultProfile ?? defaultProfile,
|
|
322
|
+
targets: {
|
|
323
|
+
value: manifest.writePolicy?.define?.targets?.value ?? "./values/app.yml",
|
|
324
|
+
secret: manifest.writePolicy?.define?.targets?.secret ?? "./secrets/app.yml"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
schema: manifest.schema ?? {}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ../core/src/manifest/loadManifest.ts
|
|
333
|
+
async function loadManifest(options = {}) {
|
|
334
|
+
const manifestRoot = await resolveManifestRoot(options.root);
|
|
335
|
+
const manifestPath = import_node_path2.default.join(manifestRoot, "cnos.yml");
|
|
336
|
+
let source;
|
|
337
|
+
try {
|
|
338
|
+
source = await (0, import_promises2.readFile)(manifestPath, "utf8");
|
|
339
|
+
} catch {
|
|
340
|
+
throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
|
|
341
|
+
}
|
|
342
|
+
const rawManifest = parseYaml(source);
|
|
343
|
+
if (!rawManifest || typeof rawManifest !== "object") {
|
|
344
|
+
throw new CnosManifestError("CNOS manifest must be a YAML object", manifestPath);
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
manifestRoot,
|
|
348
|
+
repoRoot: import_node_path2.default.dirname(manifestRoot),
|
|
349
|
+
manifestPath,
|
|
350
|
+
manifest: normalizeManifest(rawManifest),
|
|
351
|
+
rawManifest
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ../core/src/manifest/loadWorkspaceFile.ts
|
|
356
|
+
var import_promises3 = require("fs/promises");
|
|
357
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
358
|
+
async function loadWorkspaceFile(repoRoot) {
|
|
359
|
+
const workspaceFilePath = import_node_path3.default.join(repoRoot, ".cnos-workspace.yml");
|
|
360
|
+
try {
|
|
361
|
+
const source = await (0, import_promises3.readFile)(workspaceFilePath, "utf8");
|
|
362
|
+
const parsed = parseYaml(source);
|
|
363
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
364
|
+
throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
|
|
365
|
+
}
|
|
366
|
+
const config = parsed;
|
|
367
|
+
return {
|
|
368
|
+
path: workspaceFilePath,
|
|
369
|
+
config: {
|
|
370
|
+
...config.workspace ? { workspace: config.workspace.trim() } : {},
|
|
371
|
+
...config.profile ? { profile: config.profile.trim() } : {},
|
|
372
|
+
...config.globalRoot ? { globalRoot: config.globalRoot.trim() } : {}
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
} catch (error) {
|
|
376
|
+
if (error.code === "ENOENT") {
|
|
377
|
+
return void 0;
|
|
378
|
+
}
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ../core/src/profiles/expandProfileChain.ts
|
|
384
|
+
var import_promises4 = require("fs/promises");
|
|
385
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
386
|
+
async function fileExists(targetPath) {
|
|
387
|
+
try {
|
|
388
|
+
await (0, import_promises4.access)(targetPath);
|
|
389
|
+
return true;
|
|
390
|
+
} catch {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
function normalizeProfileDefinition(profileName, rawDefinition, filePath) {
|
|
395
|
+
const normalizeActivationLayer = (entry, namespace) => {
|
|
396
|
+
const normalized = entry.trim();
|
|
397
|
+
if (!normalized) {
|
|
398
|
+
return normalized;
|
|
399
|
+
}
|
|
400
|
+
if (normalized.includes("/") || normalized.includes("\\") || normalized.startsWith(".")) {
|
|
401
|
+
return normalized.replace(/\\/g, "/");
|
|
402
|
+
}
|
|
403
|
+
return `${namespace}/${normalized}`;
|
|
404
|
+
};
|
|
405
|
+
return {
|
|
406
|
+
name: rawDefinition?.name?.trim() || profileName,
|
|
407
|
+
extends: Array.isArray(rawDefinition?.extends) ? rawDefinition.extends.map((entry) => entry.trim()).filter(Boolean) : rawDefinition?.extends ? [rawDefinition.extends.trim()].filter(Boolean) : [],
|
|
408
|
+
activate: {
|
|
409
|
+
values: rawDefinition?.activate?.values?.map((entry) => normalizeActivationLayer(entry, "values")).filter(Boolean) ?? [],
|
|
410
|
+
secrets: rawDefinition?.activate?.secrets?.map((entry) => normalizeActivationLayer(entry, "secrets")).filter(Boolean) ?? [],
|
|
411
|
+
envFiles: rawDefinition?.activate?.envFiles?.map((entry) => entry.trim()).filter(Boolean) ?? []
|
|
412
|
+
},
|
|
413
|
+
...filePath ? { filePath } : {}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
async function loadProfileDefinition(profileName, options) {
|
|
417
|
+
const workspaceRoots = options.workspace?.workspaceRoots ?? [];
|
|
418
|
+
if (workspaceRoots.length === 0) {
|
|
419
|
+
return normalizeProfileDefinition(profileName, void 0);
|
|
420
|
+
}
|
|
421
|
+
for (const workspaceRoot of [...workspaceRoots].reverse()) {
|
|
422
|
+
const profilePath = import_node_path4.default.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
|
|
423
|
+
if (!await fileExists(profilePath)) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
const document = await (0, import_promises4.readFile)(profilePath, "utf8");
|
|
427
|
+
const parsed = parseYaml(document);
|
|
428
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
429
|
+
throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
|
|
430
|
+
}
|
|
431
|
+
const definition = normalizeProfileDefinition(
|
|
432
|
+
profileName,
|
|
433
|
+
parsed,
|
|
434
|
+
options.manifestRoot ? toPortablePath(import_node_path4.default.relative(import_node_path4.default.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
|
|
435
|
+
);
|
|
436
|
+
if (definition.name !== profileName) {
|
|
437
|
+
throw new CnosManifestError(
|
|
438
|
+
`Profile file name mismatch: expected "${profileName}" but found "${definition.name}"`,
|
|
439
|
+
profilePath
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
return definition;
|
|
443
|
+
}
|
|
444
|
+
return normalizeProfileDefinition(profileName, void 0);
|
|
445
|
+
}
|
|
446
|
+
function pushUnique(target, values) {
|
|
447
|
+
for (const value of values) {
|
|
448
|
+
if (!target.includes(value)) {
|
|
449
|
+
target.push(value);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function buildFallbackActivation(activeProfile, orderedProfiles) {
|
|
454
|
+
const overlayProfiles = orderedProfiles.filter((profile) => profile !== "base");
|
|
455
|
+
return {
|
|
456
|
+
values: [
|
|
457
|
+
"values",
|
|
458
|
+
...activeProfile !== "base" ? ["values/base"] : [],
|
|
459
|
+
...overlayProfiles.flatMap((profile) => [`profiles/${profile}/values`, `values/${profile}`])
|
|
460
|
+
],
|
|
461
|
+
secrets: [
|
|
462
|
+
"secrets",
|
|
463
|
+
...overlayProfiles.flatMap((profile) => [`profiles/${profile}/secrets`, `secrets/${profile}`])
|
|
464
|
+
],
|
|
465
|
+
envFiles: activeProfile === "base" ? [".env"] : [".env", `.env.${activeProfile}`]
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
async function expandProfileChain(activeProfile, options = {}) {
|
|
469
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
470
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
471
|
+
const orderedProfiles = [];
|
|
472
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
473
|
+
const visit = async (profileName) => {
|
|
474
|
+
if (resolved.has(profileName)) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (visiting.has(profileName)) {
|
|
478
|
+
throw new CnosManifestError(`Detected profile inheritance cycle involving "${profileName}"`);
|
|
479
|
+
}
|
|
480
|
+
visiting.add(profileName);
|
|
481
|
+
const definition = await loadProfileDefinition(profileName, options);
|
|
482
|
+
definitions.set(profileName, definition);
|
|
483
|
+
for (const parent of definition.extends) {
|
|
484
|
+
await visit(parent);
|
|
485
|
+
}
|
|
486
|
+
visiting.delete(profileName);
|
|
487
|
+
resolved.add(profileName);
|
|
488
|
+
orderedProfiles.push(profileName);
|
|
489
|
+
};
|
|
490
|
+
await visit(activeProfile);
|
|
491
|
+
const activation = {
|
|
492
|
+
values: [],
|
|
493
|
+
secrets: [],
|
|
494
|
+
envFiles: []
|
|
495
|
+
};
|
|
496
|
+
for (const profileName of orderedProfiles) {
|
|
497
|
+
const definition = definitions.get(profileName);
|
|
498
|
+
if (!definition) {
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
pushUnique(activation.values, definition.activate.values);
|
|
502
|
+
pushUnique(activation.secrets, definition.activate.secrets);
|
|
503
|
+
pushUnique(activation.envFiles, definition.activate.envFiles);
|
|
504
|
+
}
|
|
505
|
+
const fallback = buildFallbackActivation(activeProfile, orderedProfiles);
|
|
506
|
+
if (activation.values.length === 0) {
|
|
507
|
+
activation.values = fallback.values;
|
|
508
|
+
}
|
|
509
|
+
if (activation.secrets.length === 0) {
|
|
510
|
+
activation.secrets = fallback.secrets;
|
|
511
|
+
}
|
|
512
|
+
if (activation.envFiles.length === 0) {
|
|
513
|
+
activation.envFiles = fallback.envFiles;
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
activeProfile,
|
|
517
|
+
profiles: orderedProfiles,
|
|
518
|
+
activation
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// ../core/src/profiles/resolveActiveProfile.ts
|
|
523
|
+
function resolveActiveProfile(manifest, options = {}) {
|
|
524
|
+
for (const source of manifest.profiles.resolveFrom) {
|
|
525
|
+
if (source === "cli.profile" && options.profile) {
|
|
526
|
+
return {
|
|
527
|
+
profile: options.profile,
|
|
528
|
+
source: "cli"
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (source === "env.CNOS_PROFILE") {
|
|
532
|
+
if (options.workspaceFile?.profile) {
|
|
533
|
+
return {
|
|
534
|
+
profile: options.workspaceFile.profile,
|
|
535
|
+
source: "workspace-file"
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
const envProfile = options.processEnv?.CNOS_PROFILE;
|
|
539
|
+
if (envProfile) {
|
|
540
|
+
return {
|
|
541
|
+
profile: envProfile,
|
|
542
|
+
source: "env"
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (source === "default") {
|
|
547
|
+
return {
|
|
548
|
+
profile: manifest.profiles.default,
|
|
549
|
+
source: "manifest-default"
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return {
|
|
554
|
+
profile: manifest.profiles.default,
|
|
555
|
+
source: "manifest-default"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// ../core/src/utils/deepMerge.ts
|
|
560
|
+
function isPlainObject(value) {
|
|
561
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
562
|
+
}
|
|
563
|
+
function deepMerge(base, override) {
|
|
564
|
+
const merged = { ...base };
|
|
565
|
+
for (const [key, value] of Object.entries(override)) {
|
|
566
|
+
const currentValue = merged[key];
|
|
567
|
+
if (isPlainObject(currentValue) && isPlainObject(value)) {
|
|
568
|
+
merged[key] = deepMerge(currentValue, value);
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
merged[key] = value;
|
|
572
|
+
}
|
|
573
|
+
return merged;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// ../core/src/resolvers/profileAwareResolver.ts
|
|
577
|
+
function mergeResolvedValue(currentValue, nextValue, arrayPolicy) {
|
|
578
|
+
if (Array.isArray(currentValue) && Array.isArray(nextValue)) {
|
|
579
|
+
if (arrayPolicy === "append") {
|
|
580
|
+
return [...currentValue, ...nextValue];
|
|
581
|
+
}
|
|
582
|
+
if (arrayPolicy === "unique-append") {
|
|
583
|
+
return [.../* @__PURE__ */ new Set([...currentValue, ...nextValue])];
|
|
584
|
+
}
|
|
585
|
+
return [...nextValue];
|
|
586
|
+
}
|
|
587
|
+
if (isPlainObject(currentValue) && isPlainObject(nextValue)) {
|
|
588
|
+
return deepMerge(currentValue, nextValue);
|
|
589
|
+
}
|
|
590
|
+
return nextValue;
|
|
591
|
+
}
|
|
592
|
+
function createProfileAwareResolver() {
|
|
593
|
+
return {
|
|
594
|
+
id: "profile-aware",
|
|
595
|
+
kind: "resolver",
|
|
596
|
+
async resolve(entries, context) {
|
|
597
|
+
const precedence = new Map(context.precedenceOrder.map((sourceId, index) => [sourceId, index]));
|
|
598
|
+
const sortedEntries = entries.map((entry, index) => ({
|
|
599
|
+
entry,
|
|
600
|
+
index,
|
|
601
|
+
precedence: precedence.get(entry.sourceId) ?? context.precedenceOrder.length
|
|
602
|
+
})).sort((left, right) => left.precedence - right.precedence || left.index - right.index);
|
|
603
|
+
const resolvedEntries = /* @__PURE__ */ new Map();
|
|
604
|
+
for (const { entry } of sortedEntries) {
|
|
605
|
+
const current = resolvedEntries.get(entry.key);
|
|
606
|
+
if (!current) {
|
|
607
|
+
resolvedEntries.set(entry.key, {
|
|
608
|
+
key: entry.key,
|
|
609
|
+
value: entry.value,
|
|
610
|
+
namespace: entry.namespace,
|
|
611
|
+
winner: entry,
|
|
612
|
+
overridden: []
|
|
613
|
+
});
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
resolvedEntries.set(entry.key, {
|
|
617
|
+
key: entry.key,
|
|
618
|
+
value: mergeResolvedValue(current.value, entry.value, context.manifest.resolution.arrayPolicy),
|
|
619
|
+
namespace: current.namespace,
|
|
620
|
+
winner: entry,
|
|
621
|
+
overridden: [...current.overridden, current.winner]
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
entries: resolvedEntries,
|
|
626
|
+
profile: context.profile,
|
|
627
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
628
|
+
profileSource: "manifest-default",
|
|
629
|
+
workspace: context.workspace
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// ../core/src/workspaces/resolveWorkspaceContext.ts
|
|
636
|
+
var import_promises5 = require("fs/promises");
|
|
637
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
638
|
+
|
|
639
|
+
// ../core/src/workspaces/expandWorkspaceChain.ts
|
|
640
|
+
function expandWorkspaceChain(workspaceId, items) {
|
|
641
|
+
if (Object.keys(items).length === 0) {
|
|
642
|
+
return [workspaceId];
|
|
643
|
+
}
|
|
644
|
+
if (!items[workspaceId]) {
|
|
645
|
+
throw new CnosManifestError(`Unknown workspace "${workspaceId}"`);
|
|
646
|
+
}
|
|
647
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
648
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
649
|
+
const chain = [];
|
|
650
|
+
const visit = (currentWorkspaceId) => {
|
|
651
|
+
if (resolved.has(currentWorkspaceId)) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (visiting.has(currentWorkspaceId)) {
|
|
655
|
+
throw new CnosManifestError(`Detected workspace inheritance cycle involving "${currentWorkspaceId}"`);
|
|
656
|
+
}
|
|
657
|
+
const item = items[currentWorkspaceId];
|
|
658
|
+
if (!item) {
|
|
659
|
+
throw new CnosManifestError(`Unknown workspace "${currentWorkspaceId}"`);
|
|
660
|
+
}
|
|
661
|
+
visiting.add(currentWorkspaceId);
|
|
662
|
+
for (const parentWorkspaceId of item.extends) {
|
|
663
|
+
visit(parentWorkspaceId);
|
|
664
|
+
}
|
|
665
|
+
visiting.delete(currentWorkspaceId);
|
|
666
|
+
resolved.add(currentWorkspaceId);
|
|
667
|
+
chain.push(currentWorkspaceId);
|
|
668
|
+
};
|
|
669
|
+
visit(workspaceId);
|
|
670
|
+
return chain;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// ../core/src/workspaces/resolveWorkspaceContext.ts
|
|
674
|
+
async function exists2(targetPath) {
|
|
675
|
+
try {
|
|
676
|
+
await (0, import_promises5.access)(targetPath);
|
|
677
|
+
return true;
|
|
678
|
+
} catch {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId) {
|
|
683
|
+
const workspaceRoot = import_node_path5.default.join(manifestRoot, "workspaces", workspaceId);
|
|
684
|
+
if (await exists2(workspaceRoot)) {
|
|
685
|
+
return workspaceRoot;
|
|
686
|
+
}
|
|
687
|
+
const legacyMarkers = ["values", "secrets", "env", "profiles"].map(
|
|
688
|
+
(segment) => import_node_path5.default.join(manifestRoot, segment)
|
|
689
|
+
);
|
|
690
|
+
if ((await Promise.all(legacyMarkers.map((marker) => exists2(marker)))).some(Boolean)) {
|
|
691
|
+
return manifestRoot;
|
|
692
|
+
}
|
|
693
|
+
return workspaceRoot;
|
|
694
|
+
}
|
|
695
|
+
function resolveWorkspaceSelection(manifest, workspaceFile, workspaceOption) {
|
|
696
|
+
if (workspaceOption) {
|
|
697
|
+
return {
|
|
698
|
+
workspaceId: workspaceOption,
|
|
699
|
+
source: "cli"
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
if (workspaceFile?.workspace) {
|
|
703
|
+
return {
|
|
704
|
+
workspaceId: workspaceFile.workspace,
|
|
705
|
+
source: "workspace-file"
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
if (manifest.workspaces.default) {
|
|
709
|
+
return {
|
|
710
|
+
workspaceId: manifest.workspaces.default,
|
|
711
|
+
source: "manifest-default"
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
if (Object.keys(manifest.workspaces.items).length === 0) {
|
|
715
|
+
return {
|
|
716
|
+
workspaceId: "default",
|
|
717
|
+
source: "implicit"
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
throw new CnosManifestError(
|
|
721
|
+
"Workspace selection requires --workspace, .cnos-workspace.yml, or workspaces.default when workspaces.items are defined"
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
function resolveGlobalRoot(manifest, workspaceFile, options) {
|
|
725
|
+
if (!manifest.workspaces.global.enabled) {
|
|
726
|
+
return {};
|
|
727
|
+
}
|
|
728
|
+
if (options.globalRoot) {
|
|
729
|
+
return {
|
|
730
|
+
value: import_node_path5.default.resolve(expandHomePath(options.globalRoot)),
|
|
731
|
+
source: "cli"
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
if (workspaceFile?.globalRoot) {
|
|
735
|
+
return {
|
|
736
|
+
value: import_node_path5.default.resolve(expandHomePath(workspaceFile.globalRoot)),
|
|
737
|
+
source: "workspace-file"
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
if (manifest.workspaces.global.root) {
|
|
741
|
+
return {
|
|
742
|
+
value: import_node_path5.default.resolve(expandHomePath(manifest.workspaces.global.root)),
|
|
743
|
+
source: "manifest"
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
const cnosHome = options.processEnv?.CNOS_HOME;
|
|
747
|
+
if (cnosHome) {
|
|
748
|
+
return {
|
|
749
|
+
value: import_node_path5.default.resolve(expandHomePath(cnosHome)),
|
|
750
|
+
source: "CNOS_HOME"
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
return {};
|
|
754
|
+
}
|
|
755
|
+
async function resolveWorkspaceContext(manifest, options) {
|
|
756
|
+
const selectedWorkspace = resolveWorkspaceSelection(manifest, options.workspaceFile, options.workspace);
|
|
757
|
+
const workspaceChain = expandWorkspaceChain(selectedWorkspace.workspaceId, manifest.workspaces.items);
|
|
758
|
+
const globalRoot = resolveGlobalRoot(manifest, options.workspaceFile, options);
|
|
759
|
+
const workspaceRoots = [];
|
|
760
|
+
if (globalRoot.value) {
|
|
761
|
+
for (const chainWorkspaceId of workspaceChain) {
|
|
762
|
+
const globalWorkspaceId = manifest.workspaces.items[chainWorkspaceId]?.globalId ?? chainWorkspaceId;
|
|
763
|
+
workspaceRoots.push({
|
|
764
|
+
scope: "global",
|
|
765
|
+
workspaceId: chainWorkspaceId,
|
|
766
|
+
path: import_node_path5.default.join(globalRoot.value, "workspaces", globalWorkspaceId)
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
for (const chainWorkspaceId of workspaceChain) {
|
|
771
|
+
workspaceRoots.push({
|
|
772
|
+
scope: "local",
|
|
773
|
+
workspaceId: chainWorkspaceId,
|
|
774
|
+
path: await resolveLocalWorkspaceRoot(options.manifestRoot, chainWorkspaceId)
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
return {
|
|
778
|
+
workspaceId: selectedWorkspace.workspaceId,
|
|
779
|
+
workspaceSource: selectedWorkspace.source,
|
|
780
|
+
...globalRoot.value ? { globalRoot: globalRoot.value } : {},
|
|
781
|
+
...globalRoot.source ? { globalRootSource: globalRoot.source } : {},
|
|
782
|
+
workspaceChain,
|
|
783
|
+
workspaceRoots
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// ../core/src/validation/basicSchema.ts
|
|
788
|
+
function describeValueType(value) {
|
|
789
|
+
if (Array.isArray(value)) {
|
|
790
|
+
return "array";
|
|
791
|
+
}
|
|
792
|
+
if (value === null) {
|
|
793
|
+
return "null";
|
|
794
|
+
}
|
|
795
|
+
return typeof value;
|
|
796
|
+
}
|
|
797
|
+
function coerceBoolean(value) {
|
|
798
|
+
if (value === "true") {
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
if (value === "false") {
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
return void 0;
|
|
805
|
+
}
|
|
806
|
+
function coerceValue(value, rule) {
|
|
807
|
+
if (typeof value !== "string" || !rule.type) {
|
|
808
|
+
return value;
|
|
809
|
+
}
|
|
810
|
+
switch (rule.type) {
|
|
811
|
+
case "number": {
|
|
812
|
+
const parsed = Number(value);
|
|
813
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
814
|
+
}
|
|
815
|
+
case "boolean":
|
|
816
|
+
return coerceBoolean(value) ?? value;
|
|
817
|
+
case "object":
|
|
818
|
+
case "array": {
|
|
819
|
+
try {
|
|
820
|
+
const parsed = JSON.parse(value);
|
|
821
|
+
if (rule.type === "array" && Array.isArray(parsed)) {
|
|
822
|
+
return parsed;
|
|
823
|
+
}
|
|
824
|
+
if (rule.type === "object" && parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
825
|
+
return parsed;
|
|
826
|
+
}
|
|
827
|
+
return value;
|
|
828
|
+
} catch {
|
|
829
|
+
return value;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
default:
|
|
833
|
+
return value;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function matchesType(value, type) {
|
|
837
|
+
if (!type) {
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
switch (type) {
|
|
841
|
+
case "array":
|
|
842
|
+
return Array.isArray(value);
|
|
843
|
+
case "object":
|
|
844
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
845
|
+
default:
|
|
846
|
+
return typeof value === type;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function enumMatches(value, allowed) {
|
|
850
|
+
const serialized = JSON.stringify(value);
|
|
851
|
+
return allowed.some((candidate) => JSON.stringify(candidate) === serialized);
|
|
852
|
+
}
|
|
853
|
+
function applySchemaRules(graph, schema) {
|
|
854
|
+
const nextEntries = new Map(graph.entries);
|
|
855
|
+
const issues = [];
|
|
856
|
+
for (const [key, rule] of Object.entries(schema).sort(([left], [right]) => left.localeCompare(right))) {
|
|
857
|
+
const resolvedEntry = nextEntries.get(key);
|
|
858
|
+
if (!resolvedEntry) {
|
|
859
|
+
if (rule.default !== void 0) {
|
|
860
|
+
const defaultEntry = {
|
|
861
|
+
key,
|
|
862
|
+
value: rule.default,
|
|
863
|
+
namespace: key.startsWith("secret.") ? "secret" : key.startsWith("meta.") ? "meta" : "value",
|
|
864
|
+
sourceId: "schema-default",
|
|
865
|
+
pluginId: "basic-schema",
|
|
866
|
+
workspaceId: graph.workspace.workspaceId,
|
|
867
|
+
metadata: {
|
|
868
|
+
schemaDefault: true
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
nextEntries.set(key, {
|
|
872
|
+
key,
|
|
873
|
+
value: rule.default,
|
|
874
|
+
namespace: defaultEntry.namespace,
|
|
875
|
+
winner: defaultEntry,
|
|
876
|
+
overridden: []
|
|
877
|
+
});
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
if (rule.required) {
|
|
881
|
+
issues.push({
|
|
882
|
+
code: "schema.required",
|
|
883
|
+
key,
|
|
884
|
+
message: `Missing required config key: ${key}`
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
const coercedValue = coerceValue(resolvedEntry.value, rule);
|
|
890
|
+
const nextResolvedEntry = coercedValue === resolvedEntry.value ? resolvedEntry : {
|
|
891
|
+
...resolvedEntry,
|
|
892
|
+
value: coercedValue
|
|
893
|
+
};
|
|
894
|
+
if (!matchesType(coercedValue, rule.type)) {
|
|
895
|
+
issues.push({
|
|
896
|
+
code: "schema.type",
|
|
897
|
+
key,
|
|
898
|
+
message: `Config key ${key} expected type ${rule.type} but got ${describeValueType(coercedValue)}`
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
if (rule.enum && !enumMatches(coercedValue, rule.enum)) {
|
|
902
|
+
issues.push({
|
|
903
|
+
code: "schema.enum",
|
|
904
|
+
key,
|
|
905
|
+
message: `Config key ${key} must be one of ${rule.enum.map((entry) => JSON.stringify(entry)).join(", ")}`
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
if (rule.pattern) {
|
|
909
|
+
if (typeof coercedValue !== "string") {
|
|
910
|
+
issues.push({
|
|
911
|
+
code: "schema.pattern",
|
|
912
|
+
key,
|
|
913
|
+
message: `Config key ${key} must be a string to match pattern ${rule.pattern}`
|
|
914
|
+
});
|
|
915
|
+
} else if (!new RegExp(rule.pattern).test(coercedValue)) {
|
|
916
|
+
issues.push({
|
|
917
|
+
code: "schema.pattern",
|
|
918
|
+
key,
|
|
919
|
+
message: `Config key ${key} does not match pattern ${rule.pattern}`
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
nextEntries.set(key, nextResolvedEntry);
|
|
924
|
+
}
|
|
925
|
+
return {
|
|
926
|
+
graph: {
|
|
927
|
+
...graph,
|
|
928
|
+
entries: nextEntries
|
|
929
|
+
},
|
|
930
|
+
issues
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// ../core/src/orchestrator/pipeline.ts
|
|
935
|
+
async function runPipeline(options) {
|
|
936
|
+
const collectedEntries = await Promise.all(
|
|
937
|
+
options.plugins.map(
|
|
938
|
+
(plugin) => plugin.load({
|
|
939
|
+
manifestConfig: {
|
|
940
|
+
...options.manifest.sources[plugin.id] ?? {},
|
|
941
|
+
envMapping: options.manifest.envMapping
|
|
942
|
+
},
|
|
943
|
+
profile: options.profile,
|
|
944
|
+
profileChain: options.profileChain,
|
|
945
|
+
profileActivation: options.profileActivation,
|
|
946
|
+
manifestRoot: options.manifestRoot,
|
|
947
|
+
workspace: options.workspace,
|
|
948
|
+
...options.cliArgs ? { cliArgs: options.cliArgs } : {},
|
|
949
|
+
...options.processEnv ? { processEnv: options.processEnv } : {}
|
|
950
|
+
})
|
|
951
|
+
)
|
|
952
|
+
);
|
|
953
|
+
return collectedEntries.flat();
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// ../core/src/runtime/projection.ts
|
|
957
|
+
function setNestedValue(target, pathSegments, value) {
|
|
958
|
+
const [head, ...tail] = pathSegments;
|
|
959
|
+
if (!head) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
if (tail.length === 0) {
|
|
963
|
+
target[head] = value;
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const current = target[head];
|
|
967
|
+
const nextTarget = current && typeof current === "object" && !Array.isArray(current) ? current : {};
|
|
968
|
+
target[head] = nextTarget;
|
|
969
|
+
setNestedValue(nextTarget, tail, value);
|
|
970
|
+
}
|
|
971
|
+
function toNamespaceObject(graph, namespace) {
|
|
972
|
+
const output = {};
|
|
973
|
+
const resolvedEntries = Array.from(graph.entries.values()).sort(
|
|
974
|
+
(left, right) => left.key.localeCompare(right.key)
|
|
975
|
+
);
|
|
976
|
+
for (const entry of resolvedEntries) {
|
|
977
|
+
if (namespace && entry.namespace !== namespace) {
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
|
|
981
|
+
setNestedValue(output, valuePath.split("."), entry.value);
|
|
982
|
+
}
|
|
983
|
+
return output;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// ../core/src/runtime/read.ts
|
|
987
|
+
function readValue(graph, key) {
|
|
988
|
+
return graph.entries.get(key)?.value;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// ../core/src/runtime/readOr.ts
|
|
992
|
+
function readOrValue(graph, key, fallback) {
|
|
993
|
+
const value = readValue(graph, key);
|
|
994
|
+
return value === void 0 ? fallback : value;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// ../core/src/runtime/require.ts
|
|
998
|
+
function requireValue(graph, key) {
|
|
999
|
+
const value = readValue(graph, key);
|
|
1000
|
+
if (value === void 0) {
|
|
1001
|
+
throw new CnosKeyNotFoundError(key);
|
|
1002
|
+
}
|
|
1003
|
+
return value;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// ../core/src/utils/envNaming.ts
|
|
1007
|
+
function normalizeMappingConfig(config = {}) {
|
|
1008
|
+
return {
|
|
1009
|
+
convention: config.convention,
|
|
1010
|
+
explicit: config.explicit ?? {}
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
function toScreamingSnakeSegment(segment) {
|
|
1014
|
+
return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
1015
|
+
}
|
|
1016
|
+
function toScreamingSnake(path10) {
|
|
1017
|
+
return path10.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
|
|
1018
|
+
}
|
|
1019
|
+
function fromScreamingSnake(path10) {
|
|
1020
|
+
return path10.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
|
|
1021
|
+
}
|
|
1022
|
+
function logicalKeyToEnvVar(key, config = {}) {
|
|
1023
|
+
const normalized = normalizeMappingConfig(config);
|
|
1024
|
+
const explicitEntry = Object.entries(normalized.explicit).find(([, logicalKey]) => logicalKey === key);
|
|
1025
|
+
if (explicitEntry) {
|
|
1026
|
+
return explicitEntry[0];
|
|
1027
|
+
}
|
|
1028
|
+
if (normalized.convention !== "SCREAMING_SNAKE") {
|
|
1029
|
+
return void 0;
|
|
1030
|
+
}
|
|
1031
|
+
if (key.startsWith("value.")) {
|
|
1032
|
+
return toScreamingSnake(key.slice("value.".length));
|
|
1033
|
+
}
|
|
1034
|
+
if (key.startsWith("secret.")) {
|
|
1035
|
+
return `SECRET_${toScreamingSnake(key.slice("secret.".length))}`;
|
|
1036
|
+
}
|
|
1037
|
+
return void 0;
|
|
1038
|
+
}
|
|
1039
|
+
function envVarToLogicalKey(envVar, config = {}) {
|
|
1040
|
+
const normalized = normalizeMappingConfig(config);
|
|
1041
|
+
const explicitMatch = normalized.explicit[envVar];
|
|
1042
|
+
if (explicitMatch) {
|
|
1043
|
+
return explicitMatch;
|
|
1044
|
+
}
|
|
1045
|
+
if (normalized.convention !== "SCREAMING_SNAKE") {
|
|
1046
|
+
return void 0;
|
|
1047
|
+
}
|
|
1048
|
+
if (envVar.startsWith("SECRET_")) {
|
|
1049
|
+
const stripped = envVar.slice("SECRET_".length);
|
|
1050
|
+
if (!stripped) {
|
|
1051
|
+
return void 0;
|
|
1052
|
+
}
|
|
1053
|
+
return `secret.${fromScreamingSnake(stripped)}`;
|
|
1054
|
+
}
|
|
1055
|
+
if (!/^[A-Z][A-Z0-9_]*$/.test(envVar)) {
|
|
1056
|
+
return void 0;
|
|
1057
|
+
}
|
|
1058
|
+
return `value.${fromScreamingSnake(envVar)}`;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// ../core/src/runtime/toEnv.ts
|
|
1062
|
+
function fallbackLogicalKeyToEnvVar(key) {
|
|
1063
|
+
if (key.startsWith("value.")) {
|
|
1064
|
+
return key.slice("value.".length).replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
1065
|
+
}
|
|
1066
|
+
if (key.startsWith("secret.")) {
|
|
1067
|
+
const normalized = key.slice("secret.".length).replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
1068
|
+
return `SECRET_${normalized}`;
|
|
1069
|
+
}
|
|
1070
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
1071
|
+
}
|
|
1072
|
+
function normalizeEnvValue(value) {
|
|
1073
|
+
if (value === void 0 || value === null) {
|
|
1074
|
+
return "";
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof value === "string") {
|
|
1077
|
+
return value;
|
|
1078
|
+
}
|
|
1079
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
1080
|
+
return String(value);
|
|
1081
|
+
}
|
|
1082
|
+
return JSON.stringify(value);
|
|
1083
|
+
}
|
|
1084
|
+
function toEnv(graph, manifest, options = {}) {
|
|
1085
|
+
const includeSecrets = options.includeSecrets ?? true;
|
|
1086
|
+
const output = {};
|
|
1087
|
+
const resolvedEntries = Array.from(graph.entries.values()).sort(
|
|
1088
|
+
(left, right) => left.key.localeCompare(right.key)
|
|
1089
|
+
);
|
|
1090
|
+
for (const entry of resolvedEntries) {
|
|
1091
|
+
if (entry.namespace === "meta") {
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
if (!includeSecrets && entry.namespace === "secret") {
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
const envVar = logicalKeyToEnvVar(entry.key, manifest.envMapping) ?? fallbackLogicalKeyToEnvVar(entry.key);
|
|
1098
|
+
output[envVar] = normalizeEnvValue(entry.value);
|
|
1099
|
+
}
|
|
1100
|
+
return output;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// ../core/src/runtime/toPublicEnv.ts
|
|
1104
|
+
function fallbackValueEnvVar(key) {
|
|
1105
|
+
return key.replace(/^value\./, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
1106
|
+
}
|
|
1107
|
+
function normalizeEnvValue2(value) {
|
|
1108
|
+
if (value === void 0 || value === null) {
|
|
1109
|
+
return "";
|
|
1110
|
+
}
|
|
1111
|
+
if (typeof value === "string") {
|
|
1112
|
+
return value;
|
|
1113
|
+
}
|
|
1114
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
1115
|
+
return String(value);
|
|
1116
|
+
}
|
|
1117
|
+
return JSON.stringify(value);
|
|
1118
|
+
}
|
|
1119
|
+
function resolvePublicPrefix(manifest, options) {
|
|
1120
|
+
if (options.prefix) {
|
|
1121
|
+
return options.prefix;
|
|
1122
|
+
}
|
|
1123
|
+
if (!options.framework) {
|
|
1124
|
+
return "";
|
|
1125
|
+
}
|
|
1126
|
+
const configuredPrefix = manifest.public.frameworks[options.framework];
|
|
1127
|
+
if (!configuredPrefix) {
|
|
1128
|
+
throw new CnosManifestError(`Unknown public framework prefix: ${options.framework}`);
|
|
1129
|
+
}
|
|
1130
|
+
return configuredPrefix;
|
|
1131
|
+
}
|
|
1132
|
+
function ensurePublicPromotionKey(key) {
|
|
1133
|
+
if (!key.startsWith("value.")) {
|
|
1134
|
+
throw new CnosManifestError(`public.promote may only contain value.* keys: ${key}`);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
function toPublicEnv(graph, manifest, options = {}) {
|
|
1138
|
+
const prefix = resolvePublicPrefix(manifest, options);
|
|
1139
|
+
const output = {};
|
|
1140
|
+
const promotions = [...manifest.public.promote].sort((left, right) => left.localeCompare(right));
|
|
1141
|
+
for (const key of promotions) {
|
|
1142
|
+
ensurePublicPromotionKey(key);
|
|
1143
|
+
const resolved = graph.entries.get(key);
|
|
1144
|
+
if (!resolved) {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
const baseEnvVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? fallbackValueEnvVar(key);
|
|
1148
|
+
const envVar = prefix && !baseEnvVar.startsWith(prefix) ? `${prefix}${baseEnvVar}` : baseEnvVar;
|
|
1149
|
+
output[envVar] = normalizeEnvValue2(resolved.value);
|
|
1150
|
+
}
|
|
1151
|
+
return output;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// ../core/src/orchestrator/runtime.ts
|
|
1155
|
+
function createRuntime(manifest, graph, plugins = []) {
|
|
1156
|
+
return {
|
|
1157
|
+
manifest,
|
|
1158
|
+
plugins,
|
|
1159
|
+
graph,
|
|
1160
|
+
read(key) {
|
|
1161
|
+
return readValue(graph, key);
|
|
1162
|
+
},
|
|
1163
|
+
require(key) {
|
|
1164
|
+
return requireValue(graph, key);
|
|
1165
|
+
},
|
|
1166
|
+
readOr(key, fallback) {
|
|
1167
|
+
return readOrValue(graph, key, fallback);
|
|
1168
|
+
},
|
|
1169
|
+
value(path10) {
|
|
1170
|
+
return readValue(graph, toLogicalKey("value", path10));
|
|
1171
|
+
},
|
|
1172
|
+
secret(path10) {
|
|
1173
|
+
return readValue(graph, toLogicalKey("secret", path10));
|
|
1174
|
+
},
|
|
1175
|
+
meta(path10) {
|
|
1176
|
+
return readValue(graph, toLogicalKey("meta", path10));
|
|
1177
|
+
},
|
|
1178
|
+
inspect(key) {
|
|
1179
|
+
return inspectValue(graph, key);
|
|
1180
|
+
},
|
|
1181
|
+
toObject() {
|
|
1182
|
+
return toNamespaceObject(graph);
|
|
1183
|
+
},
|
|
1184
|
+
toNamespace(namespace) {
|
|
1185
|
+
return toNamespaceObject(graph, namespace);
|
|
1186
|
+
},
|
|
1187
|
+
toEnv(options) {
|
|
1188
|
+
return toEnv(graph, manifest, options);
|
|
1189
|
+
},
|
|
1190
|
+
toPublicEnv(options) {
|
|
1191
|
+
return toPublicEnv(graph, manifest, options);
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// ../core/src/orchestrator/createCnos.ts
|
|
1197
|
+
function buildMetaEntries(graph, cnosVersion) {
|
|
1198
|
+
return [
|
|
1199
|
+
{
|
|
1200
|
+
key: "meta.profile",
|
|
1201
|
+
value: graph.profile,
|
|
1202
|
+
namespace: "meta",
|
|
1203
|
+
sourceId: "profile-resolver",
|
|
1204
|
+
pluginId: "core",
|
|
1205
|
+
workspaceId: graph.workspace.workspaceId
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
key: "meta.cnos.version",
|
|
1209
|
+
value: cnosVersion ?? "0.0.0-dev",
|
|
1210
|
+
namespace: "meta",
|
|
1211
|
+
sourceId: "core",
|
|
1212
|
+
pluginId: "core",
|
|
1213
|
+
workspaceId: graph.workspace.workspaceId
|
|
1214
|
+
},
|
|
1215
|
+
{
|
|
1216
|
+
key: "meta.resolved.at",
|
|
1217
|
+
value: graph.resolvedAt,
|
|
1218
|
+
namespace: "meta",
|
|
1219
|
+
sourceId: "core",
|
|
1220
|
+
pluginId: "core",
|
|
1221
|
+
workspaceId: graph.workspace.workspaceId
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
key: "meta.resolved.from",
|
|
1225
|
+
value: graph.profileSource,
|
|
1226
|
+
namespace: "meta",
|
|
1227
|
+
sourceId: "profile-resolver",
|
|
1228
|
+
pluginId: "core",
|
|
1229
|
+
workspaceId: graph.workspace.workspaceId
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
key: "meta.workspace",
|
|
1233
|
+
value: graph.workspace.workspaceId,
|
|
1234
|
+
namespace: "meta",
|
|
1235
|
+
sourceId: "workspace-resolver",
|
|
1236
|
+
pluginId: "core",
|
|
1237
|
+
workspaceId: graph.workspace.workspaceId
|
|
1238
|
+
},
|
|
1239
|
+
{
|
|
1240
|
+
key: "meta.workspace.source",
|
|
1241
|
+
value: graph.workspace.workspaceSource,
|
|
1242
|
+
namespace: "meta",
|
|
1243
|
+
sourceId: "workspace-resolver",
|
|
1244
|
+
pluginId: "core",
|
|
1245
|
+
workspaceId: graph.workspace.workspaceId
|
|
1246
|
+
},
|
|
1247
|
+
{
|
|
1248
|
+
key: "meta.workspace.chain",
|
|
1249
|
+
value: graph.workspace.workspaceChain,
|
|
1250
|
+
namespace: "meta",
|
|
1251
|
+
sourceId: "workspace-resolver",
|
|
1252
|
+
pluginId: "core",
|
|
1253
|
+
workspaceId: graph.workspace.workspaceId
|
|
1254
|
+
},
|
|
1255
|
+
{
|
|
1256
|
+
key: "meta.globalRoot",
|
|
1257
|
+
value: graph.workspace.globalRoot ?? null,
|
|
1258
|
+
namespace: "meta",
|
|
1259
|
+
sourceId: "workspace-resolver",
|
|
1260
|
+
pluginId: "core",
|
|
1261
|
+
workspaceId: graph.workspace.workspaceId
|
|
1262
|
+
},
|
|
1263
|
+
{
|
|
1264
|
+
key: "meta.global.enabled",
|
|
1265
|
+
value: Boolean(graph.workspace.globalRoot),
|
|
1266
|
+
namespace: "meta",
|
|
1267
|
+
sourceId: "workspace-resolver",
|
|
1268
|
+
pluginId: "core",
|
|
1269
|
+
workspaceId: graph.workspace.workspaceId
|
|
1270
|
+
}
|
|
1271
|
+
];
|
|
1272
|
+
}
|
|
1273
|
+
function appendMetaEntries(graph, cnosVersion) {
|
|
1274
|
+
const nextEntries = new Map(graph.entries);
|
|
1275
|
+
for (const entry of buildMetaEntries(graph, cnosVersion)) {
|
|
1276
|
+
nextEntries.set(entry.key, {
|
|
1277
|
+
key: entry.key,
|
|
1278
|
+
value: entry.value,
|
|
1279
|
+
namespace: entry.namespace,
|
|
1280
|
+
winner: entry,
|
|
1281
|
+
overridden: []
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
return {
|
|
1285
|
+
...graph,
|
|
1286
|
+
entries: nextEntries
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
async function createCnos(options = {}) {
|
|
1290
|
+
const loadedManifest = await loadManifest(options.root ? { root: options.root } : {});
|
|
1291
|
+
const workspaceFile = await loadWorkspaceFile(loadedManifest.repoRoot);
|
|
1292
|
+
const workspace = await resolveWorkspaceContext(loadedManifest.manifest, {
|
|
1293
|
+
manifestRoot: loadedManifest.manifestRoot,
|
|
1294
|
+
...workspaceFile ? { workspaceFile: workspaceFile.config } : {},
|
|
1295
|
+
...options.workspace ? { workspace: options.workspace } : {},
|
|
1296
|
+
...options.globalRoot ? { globalRoot: options.globalRoot } : {},
|
|
1297
|
+
...options.processEnv ? { processEnv: options.processEnv } : {}
|
|
1298
|
+
});
|
|
1299
|
+
const activeProfile = resolveActiveProfile(loadedManifest.manifest, {
|
|
1300
|
+
...options.profile ? { profile: options.profile } : {},
|
|
1301
|
+
...workspaceFile ? { workspaceFile: workspaceFile.config } : {},
|
|
1302
|
+
...options.processEnv ? { processEnv: options.processEnv } : {}
|
|
1303
|
+
});
|
|
1304
|
+
const profileChain = await expandProfileChain(activeProfile.profile, {
|
|
1305
|
+
manifestRoot: loadedManifest.manifestRoot,
|
|
1306
|
+
workspace
|
|
1307
|
+
});
|
|
1308
|
+
const plugins = options.plugins ?? [];
|
|
1309
|
+
const loaderPlugins = plugins.filter((plugin) => plugin.kind === "loader");
|
|
1310
|
+
const resolverPlugin = plugins.find((plugin) => plugin.kind === "resolver") ?? createProfileAwareResolver();
|
|
1311
|
+
const entries = await runPipeline({
|
|
1312
|
+
manifestRoot: loadedManifest.manifestRoot,
|
|
1313
|
+
manifest: loadedManifest.manifest,
|
|
1314
|
+
profile: activeProfile.profile,
|
|
1315
|
+
profileChain: profileChain.profiles,
|
|
1316
|
+
profileActivation: profileChain.activation,
|
|
1317
|
+
workspace,
|
|
1318
|
+
plugins: loaderPlugins,
|
|
1319
|
+
...options.cliArgs ? { cliArgs: options.cliArgs } : {},
|
|
1320
|
+
...options.processEnv ? { processEnv: options.processEnv } : {}
|
|
1321
|
+
});
|
|
1322
|
+
const graph = await resolverPlugin.resolve(entries, {
|
|
1323
|
+
manifest: loadedManifest.manifest,
|
|
1324
|
+
profile: activeProfile.profile,
|
|
1325
|
+
profileChain: profileChain.profiles,
|
|
1326
|
+
precedenceOrder: loadedManifest.manifest.resolution.precedence,
|
|
1327
|
+
workspace
|
|
1328
|
+
});
|
|
1329
|
+
const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
|
|
1330
|
+
return createRuntime(
|
|
1331
|
+
loadedManifest.manifest,
|
|
1332
|
+
appendMetaEntries({
|
|
1333
|
+
...schemaApplied.graph,
|
|
1334
|
+
profileSource: activeProfile.source
|
|
1335
|
+
}, options.cnosVersion),
|
|
1336
|
+
plugins
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// ../core/src/runtime/dump.ts
|
|
1341
|
+
var import_promises6 = require("fs/promises");
|
|
1342
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1343
|
+
function buildDumpFiles(graph, options = {}) {
|
|
1344
|
+
const basePath = options.flatten ? "" : import_node_path6.default.posix.join("workspaces", graph.workspace.workspaceId);
|
|
1345
|
+
const values = toNamespaceObject(graph, "value");
|
|
1346
|
+
const secrets = toNamespaceObject(graph, "secret");
|
|
1347
|
+
const files = [];
|
|
1348
|
+
if (Object.keys(values).length > 0) {
|
|
1349
|
+
files.push({
|
|
1350
|
+
path: import_node_path6.default.posix.join(basePath, "values", graph.profile, "app.yml"),
|
|
1351
|
+
namespace: "value",
|
|
1352
|
+
content: stringifyYaml(values)
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
if (Object.keys(secrets).length > 0) {
|
|
1356
|
+
files.push({
|
|
1357
|
+
path: import_node_path6.default.posix.join(basePath, "secrets", graph.profile, "app.yml"),
|
|
1358
|
+
namespace: "secret",
|
|
1359
|
+
content: stringifyYaml(secrets)
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
return files.sort((left, right) => left.path.localeCompare(right.path));
|
|
1363
|
+
}
|
|
1364
|
+
function planDump(graph, options = {}) {
|
|
1365
|
+
return {
|
|
1366
|
+
workspaceId: graph.workspace.workspaceId,
|
|
1367
|
+
profile: graph.profile,
|
|
1368
|
+
flatten: options.flatten ?? false,
|
|
1369
|
+
files: buildDumpFiles(graph, options)
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
async function writeDump(graph, options) {
|
|
1373
|
+
const root = import_node_path6.default.resolve(options.to);
|
|
1374
|
+
const plan = planDump(graph, options);
|
|
1375
|
+
for (const file of plan.files) {
|
|
1376
|
+
const destination = import_node_path6.default.join(root, file.path);
|
|
1377
|
+
await (0, import_promises6.mkdir)(import_node_path6.default.dirname(destination), { recursive: true });
|
|
1378
|
+
await (0, import_promises6.writeFile)(destination, file.content, "utf8");
|
|
1379
|
+
}
|
|
1380
|
+
return {
|
|
1381
|
+
...plan,
|
|
1382
|
+
root
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
// ../core/src/utils/secretStore.ts
|
|
1387
|
+
var import_node_crypto = require("crypto");
|
|
1388
|
+
var import_promises7 = require("fs/promises");
|
|
1389
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
1390
|
+
function isObject(value) {
|
|
1391
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1392
|
+
}
|
|
1393
|
+
function isSecretReference(value) {
|
|
1394
|
+
return isObject(value) && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.ref === "string" && value.ref.trim().length > 0 && Object.keys(value).every((key) => ["provider", "ref"].includes(key));
|
|
1395
|
+
}
|
|
1396
|
+
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
1397
|
+
return import_node_path7.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
1398
|
+
}
|
|
1399
|
+
function resolveSecretStoreFile(storeRoot, ref) {
|
|
1400
|
+
return import_node_path7.default.join(storeRoot, "store", ...ref.split("/")).concat(".json");
|
|
1401
|
+
}
|
|
1402
|
+
function deriveKey(passphrase, salt) {
|
|
1403
|
+
return (0, import_node_crypto.scryptSync)(passphrase, salt, 32);
|
|
1404
|
+
}
|
|
1405
|
+
function decryptDocument(document, passphrase) {
|
|
1406
|
+
const salt = Buffer.from(document.salt, "base64");
|
|
1407
|
+
const iv = Buffer.from(document.iv, "base64");
|
|
1408
|
+
const tag = Buffer.from(document.tag, "base64");
|
|
1409
|
+
const ciphertext = Buffer.from(document.ciphertext, "base64");
|
|
1410
|
+
const key = deriveKey(passphrase, salt);
|
|
1411
|
+
const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", key, iv);
|
|
1412
|
+
decipher.setAuthTag(tag);
|
|
1413
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
1414
|
+
return plaintext.toString("utf8");
|
|
1415
|
+
}
|
|
1416
|
+
async function readLocalSecret(storeRoot, ref, passphrase) {
|
|
1417
|
+
if (!passphrase) {
|
|
1418
|
+
throw new CnosManifestError(
|
|
1419
|
+
`Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
const filePath = resolveSecretStoreFile(storeRoot, ref);
|
|
1423
|
+
const source = await (0, import_promises7.readFile)(filePath, "utf8");
|
|
1424
|
+
const document = JSON.parse(source);
|
|
1425
|
+
if (document.version !== 1 || document.algorithm !== "aes-256-gcm" || typeof document.salt !== "string" || typeof document.iv !== "string" || typeof document.tag !== "string" || typeof document.ciphertext !== "string") {
|
|
1426
|
+
throw new CnosManifestError("Invalid local secret document", filePath);
|
|
1427
|
+
}
|
|
1428
|
+
return decryptDocument(document, passphrase);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
// package.json
|
|
1432
|
+
var package_default = {
|
|
1433
|
+
name: "@kitsy/cnos",
|
|
1434
|
+
version: "1.0.1",
|
|
1435
|
+
description: "Batteries-included CNOS runtime package wired with the official plugins.",
|
|
1436
|
+
type: "module",
|
|
1437
|
+
main: "./dist/index.cjs",
|
|
1438
|
+
module: "./dist/index.js",
|
|
1439
|
+
types: "./dist/index.d.ts",
|
|
1440
|
+
exports: {
|
|
1441
|
+
".": {
|
|
1442
|
+
types: "./dist/index.d.ts",
|
|
1443
|
+
import: "./dist/index.js",
|
|
1444
|
+
require: "./dist/index.cjs"
|
|
1445
|
+
},
|
|
1446
|
+
"./internal": {
|
|
1447
|
+
types: "./dist/internal.d.ts",
|
|
1448
|
+
import: "./dist/internal.js",
|
|
1449
|
+
require: "./dist/internal.cjs"
|
|
1450
|
+
},
|
|
1451
|
+
"./plugins/filesystem": {
|
|
1452
|
+
types: "./dist/plugin/filesystem.d.ts",
|
|
1453
|
+
import: "./dist/plugin/filesystem.js",
|
|
1454
|
+
require: "./dist/plugin/filesystem.cjs"
|
|
1455
|
+
},
|
|
1456
|
+
"./plugins/dotenv": {
|
|
1457
|
+
types: "./dist/plugin/dotenv.d.ts",
|
|
1458
|
+
import: "./dist/plugin/dotenv.js",
|
|
1459
|
+
require: "./dist/plugin/dotenv.cjs"
|
|
1460
|
+
},
|
|
1461
|
+
"./plugins/process-env": {
|
|
1462
|
+
types: "./dist/plugin/process-env.d.ts",
|
|
1463
|
+
import: "./dist/plugin/process-env.js",
|
|
1464
|
+
require: "./dist/plugin/process-env.cjs"
|
|
1465
|
+
},
|
|
1466
|
+
"./plugins/cli-args": {
|
|
1467
|
+
types: "./dist/plugin/cli-args.d.ts",
|
|
1468
|
+
import: "./dist/plugin/cli-args.js",
|
|
1469
|
+
require: "./dist/plugin/cli-args.cjs"
|
|
1470
|
+
},
|
|
1471
|
+
"./plugins/basic-schema": {
|
|
1472
|
+
types: "./dist/plugin/basic-schema.d.ts",
|
|
1473
|
+
import: "./dist/plugin/basic-schema.js",
|
|
1474
|
+
require: "./dist/plugin/basic-schema.cjs"
|
|
1475
|
+
},
|
|
1476
|
+
"./plugins/env-export": {
|
|
1477
|
+
types: "./dist/plugin/env-export.d.ts",
|
|
1478
|
+
import: "./dist/plugin/env-export.js",
|
|
1479
|
+
require: "./dist/plugin/env-export.cjs"
|
|
1480
|
+
}
|
|
1481
|
+
},
|
|
1482
|
+
files: [
|
|
1483
|
+
"dist"
|
|
1484
|
+
],
|
|
1485
|
+
license: "MIT",
|
|
1486
|
+
repository: {
|
|
1487
|
+
type: "git",
|
|
1488
|
+
url: "https://github.com/kitsyai/cnos.git",
|
|
1489
|
+
directory: "packages/cnos"
|
|
1490
|
+
},
|
|
1491
|
+
homepage: "https://github.com/kitsyai/cnos/tree/main/packages/cnos",
|
|
1492
|
+
bugs: {
|
|
1493
|
+
url: "https://github.com/kitsyai/cnos/issues"
|
|
1494
|
+
},
|
|
1495
|
+
keywords: [
|
|
1496
|
+
"cnos",
|
|
1497
|
+
"config",
|
|
1498
|
+
"runtime"
|
|
1499
|
+
],
|
|
1500
|
+
publishConfig: {
|
|
1501
|
+
access: "public"
|
|
1502
|
+
},
|
|
1503
|
+
dependencies: {
|
|
1504
|
+
yaml: "^2.8.3"
|
|
1505
|
+
},
|
|
1506
|
+
scripts: {
|
|
1507
|
+
build: "tsup --config tsup.config.ts",
|
|
1508
|
+
clean: "rimraf dist",
|
|
1509
|
+
dev: "tsup --config tsup.config.ts --watch",
|
|
1510
|
+
lint: "eslint src test",
|
|
1511
|
+
test: "vitest run",
|
|
1512
|
+
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
// ../../plugins/basic-schema/src/index.ts
|
|
1517
|
+
function createBasicSchemaPlugin() {
|
|
1518
|
+
return {
|
|
1519
|
+
id: "@kitsy/cnos/plugins/basic-schema",
|
|
1520
|
+
kind: "validator",
|
|
1521
|
+
async validate(graph, context) {
|
|
1522
|
+
const result = applySchemaRules(graph, context.schema ?? {});
|
|
1523
|
+
return {
|
|
1524
|
+
pluginId: "@kitsy/cnos/plugins/basic-schema",
|
|
1525
|
+
valid: result.issues.length === 0,
|
|
1526
|
+
issues: result.issues
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// ../../plugins/cli-args/src/index.ts
|
|
1533
|
+
var CLI_ARGS_PLUGIN_ID = "@kitsy/cnos/plugins/cli-args";
|
|
1534
|
+
function isNamespaceName(value) {
|
|
1535
|
+
return value === "value" || value === "secret";
|
|
1536
|
+
}
|
|
1537
|
+
function parseCliArgs(args) {
|
|
1538
|
+
const parsed = [];
|
|
1539
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1540
|
+
const arg = args[index];
|
|
1541
|
+
if (!arg?.startsWith("--")) {
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
if (arg === "--profile") {
|
|
1545
|
+
index += 1;
|
|
1546
|
+
continue;
|
|
1547
|
+
}
|
|
1548
|
+
if (arg.startsWith("--profile=")) {
|
|
1549
|
+
continue;
|
|
1550
|
+
}
|
|
1551
|
+
const body = arg.slice(2);
|
|
1552
|
+
const separatorIndex = body.indexOf("=");
|
|
1553
|
+
if (separatorIndex >= 0) {
|
|
1554
|
+
parsed.push({
|
|
1555
|
+
key: body.slice(0, separatorIndex),
|
|
1556
|
+
value: body.slice(separatorIndex + 1),
|
|
1557
|
+
raw: arg
|
|
1558
|
+
});
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
const nextValue = args[index + 1];
|
|
1562
|
+
if (nextValue && !nextValue.startsWith("--")) {
|
|
1563
|
+
parsed.push({
|
|
1564
|
+
key: body,
|
|
1565
|
+
value: nextValue,
|
|
1566
|
+
raw: `${arg} ${nextValue}`
|
|
1567
|
+
});
|
|
1568
|
+
index += 1;
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
return parsed;
|
|
1572
|
+
}
|
|
1573
|
+
function cliArgEntriesFromArgs(args, workspaceId = "default") {
|
|
1574
|
+
return parseCliArgs(args).flatMap(({ key, value, raw }) => {
|
|
1575
|
+
const [candidateNamespace = "", ...pathSegments] = key.split(".");
|
|
1576
|
+
if (!isNamespaceName(candidateNamespace) || pathSegments.length === 0) {
|
|
1577
|
+
return [];
|
|
1578
|
+
}
|
|
1579
|
+
const namespace = candidateNamespace;
|
|
1580
|
+
const logicalKey = `${namespace}.${joinConfigPath(pathSegments.join("."))}`;
|
|
1581
|
+
return [
|
|
1582
|
+
{
|
|
1583
|
+
key: logicalKey,
|
|
1584
|
+
value,
|
|
1585
|
+
namespace,
|
|
1586
|
+
sourceId: "cli-args",
|
|
1587
|
+
pluginId: CLI_ARGS_PLUGIN_ID,
|
|
1588
|
+
workspaceId,
|
|
1589
|
+
origin: {
|
|
1590
|
+
cliArg: raw
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
];
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
function createCliArgsPlugin() {
|
|
1597
|
+
return {
|
|
1598
|
+
id: "cli-args",
|
|
1599
|
+
kind: "loader",
|
|
1600
|
+
async load(context) {
|
|
1601
|
+
return cliArgEntriesFromArgs(context.cliArgs ?? [], context.workspace.workspaceId);
|
|
1602
|
+
}
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// ../../plugins/dotenv/src/index.ts
|
|
1607
|
+
var import_promises8 = require("fs/promises");
|
|
1608
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
1609
|
+
var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
|
|
1610
|
+
function parseDoubleQuoted(value) {
|
|
1611
|
+
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
1612
|
+
}
|
|
1613
|
+
function parseDotenv(document) {
|
|
1614
|
+
const parsed = {};
|
|
1615
|
+
for (const rawLine of document.split(/\r?\n/)) {
|
|
1616
|
+
const line = rawLine.trim();
|
|
1617
|
+
if (!line || line.startsWith("#")) {
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
const withoutExport = line.startsWith("export ") ? line.slice("export ".length).trim() : line;
|
|
1621
|
+
const separatorIndex = withoutExport.indexOf("=");
|
|
1622
|
+
if (separatorIndex <= 0) {
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
const envVar = withoutExport.slice(0, separatorIndex).trim();
|
|
1626
|
+
let value = withoutExport.slice(separatorIndex + 1).trim();
|
|
1627
|
+
if (!envVar) {
|
|
1628
|
+
continue;
|
|
1629
|
+
}
|
|
1630
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
1631
|
+
value = parseDoubleQuoted(value.slice(1, -1));
|
|
1632
|
+
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
1633
|
+
value = value.slice(1, -1);
|
|
1634
|
+
} else {
|
|
1635
|
+
value = value.replace(/\s+#.*$/, "").trim();
|
|
1636
|
+
}
|
|
1637
|
+
parsed[envVar] = value;
|
|
1638
|
+
}
|
|
1639
|
+
return parsed;
|
|
1640
|
+
}
|
|
1641
|
+
function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId = "default") {
|
|
1642
|
+
return Object.entries(values).flatMap(([envVar, value]) => {
|
|
1643
|
+
const logicalKey = envVarToLogicalKey(envVar, mapping);
|
|
1644
|
+
if (!logicalKey) {
|
|
1645
|
+
return [];
|
|
1646
|
+
}
|
|
1647
|
+
return [
|
|
1648
|
+
{
|
|
1649
|
+
key: logicalKey,
|
|
1650
|
+
value,
|
|
1651
|
+
namespace: logicalKey.startsWith("secret.") ? "secret" : "value",
|
|
1652
|
+
sourceId: "dotenv",
|
|
1653
|
+
pluginId: DOTENV_PLUGIN_ID,
|
|
1654
|
+
workspaceId,
|
|
1655
|
+
origin: {
|
|
1656
|
+
envVar,
|
|
1657
|
+
...originFile ? { file: originFile } : {}
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
];
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
async function readIfPresent(filePath) {
|
|
1664
|
+
try {
|
|
1665
|
+
return await (0, import_promises8.readFile)(filePath, "utf8");
|
|
1666
|
+
} catch {
|
|
1667
|
+
return void 0;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
function createDotenvPlugin() {
|
|
1671
|
+
return {
|
|
1672
|
+
id: "dotenv",
|
|
1673
|
+
kind: "loader",
|
|
1674
|
+
async load(context) {
|
|
1675
|
+
const config = context.manifestConfig;
|
|
1676
|
+
const rootTemplate = config.root ?? "./env";
|
|
1677
|
+
const fileNames = context.profileActivation.envFiles;
|
|
1678
|
+
const entries = [];
|
|
1679
|
+
for (const workspaceRoot of context.workspace.workspaceRoots) {
|
|
1680
|
+
const envRoot = resolveWorkspaceScopedPath(workspaceRoot.path, rootTemplate, {
|
|
1681
|
+
workspace: workspaceRoot.workspaceId
|
|
1682
|
+
});
|
|
1683
|
+
for (const fileName of fileNames) {
|
|
1684
|
+
const absolutePath = import_node_path8.default.join(envRoot, fileName);
|
|
1685
|
+
const document = await readIfPresent(absolutePath);
|
|
1686
|
+
if (!document) {
|
|
1687
|
+
continue;
|
|
1688
|
+
}
|
|
1689
|
+
entries.push(
|
|
1690
|
+
...dotenvEntriesFromObject(
|
|
1691
|
+
parseDotenv(document),
|
|
1692
|
+
config.envMapping,
|
|
1693
|
+
toPortablePath(import_node_path8.default.relative(import_node_path8.default.dirname(context.manifestRoot), absolutePath)),
|
|
1694
|
+
workspaceRoot.workspaceId
|
|
1695
|
+
)
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
return entries;
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
// ../../plugins/env-export/src/index.ts
|
|
1705
|
+
function createEnvExportPlugin() {
|
|
1706
|
+
return {
|
|
1707
|
+
id: "@kitsy/cnos/plugins/env-export",
|
|
1708
|
+
kind: "exporter",
|
|
1709
|
+
async export(graph, context) {
|
|
1710
|
+
return {
|
|
1711
|
+
pluginId: "@kitsy/cnos/plugins/env-export",
|
|
1712
|
+
value: toEnv(graph, context.manifest)
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
function createPublicEnvExportPlugin() {
|
|
1718
|
+
return {
|
|
1719
|
+
id: "@kitsy/cnos/plugins/public-env-export",
|
|
1720
|
+
kind: "exporter",
|
|
1721
|
+
async export(graph, context) {
|
|
1722
|
+
return {
|
|
1723
|
+
pluginId: "@kitsy/cnos/plugins/public-env-export",
|
|
1724
|
+
value: toPublicEnv(graph, context.manifest)
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
1731
|
+
var import_promises10 = require("fs/promises");
|
|
1732
|
+
|
|
1733
|
+
// ../../plugins/filesystem/src/helpers.ts
|
|
1734
|
+
var import_promises9 = require("fs/promises");
|
|
1735
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
1736
|
+
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
|
|
1737
|
+
var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
|
|
1738
|
+
async function existsDirectory(targetPath) {
|
|
1739
|
+
try {
|
|
1740
|
+
const stat = await (0, import_promises9.readdir)(targetPath);
|
|
1741
|
+
void stat;
|
|
1742
|
+
return true;
|
|
1743
|
+
} catch {
|
|
1744
|
+
return false;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
async function collectYamlFiles(root) {
|
|
1748
|
+
const entries = await (0, import_promises9.readdir)(root, { withFileTypes: true });
|
|
1749
|
+
const results = [];
|
|
1750
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
1751
|
+
const absolutePath = import_node_path9.default.join(root, entry.name);
|
|
1752
|
+
if (entry.isDirectory()) {
|
|
1753
|
+
results.push(...await collectYamlFiles(absolutePath));
|
|
1754
|
+
continue;
|
|
1755
|
+
}
|
|
1756
|
+
if (entry.isFile() && YAML_EXTENSIONS.has(import_node_path9.default.extname(entry.name).toLowerCase())) {
|
|
1757
|
+
results.push(absolutePath);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return results;
|
|
1761
|
+
}
|
|
1762
|
+
async function collectFilesystemLayerFiles(manifestRoot, workspaceRoots, sourceRoot, activeLayers) {
|
|
1763
|
+
const files = [];
|
|
1764
|
+
const repoRoot = import_node_path9.default.dirname(manifestRoot);
|
|
1765
|
+
for (const workspaceRoot of workspaceRoots) {
|
|
1766
|
+
const resolvedRoot = import_node_path9.default.resolve(workspaceRoot.path, sourceRoot);
|
|
1767
|
+
for (const layer of activeLayers) {
|
|
1768
|
+
const layerRoot = import_node_path9.default.join(resolvedRoot, layer);
|
|
1769
|
+
if (!await existsDirectory(layerRoot)) {
|
|
1770
|
+
continue;
|
|
1771
|
+
}
|
|
1772
|
+
for (const absolutePath of await collectYamlFiles(layerRoot)) {
|
|
1773
|
+
const relativePath = import_node_path9.default.relative(repoRoot, absolutePath);
|
|
1774
|
+
files.push({
|
|
1775
|
+
absolutePath,
|
|
1776
|
+
relativePath: toPortablePath(relativePath.startsWith("..") ? absolutePath : relativePath),
|
|
1777
|
+
workspaceId: workspaceRoot.workspaceId
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
return files;
|
|
1783
|
+
}
|
|
1784
|
+
function assertObjectDocument(value, filePath) {
|
|
1785
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1786
|
+
throw new CnosManifestError("Filesystem loader expected a YAML object document", filePath);
|
|
1787
|
+
}
|
|
1788
|
+
return value;
|
|
1789
|
+
}
|
|
1790
|
+
function flattenConfigObject(value, options = {}, prefix = "") {
|
|
1791
|
+
return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
|
|
1792
|
+
const nextKey = prefix ? `${prefix}.${key}` : key;
|
|
1793
|
+
if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue) && !options.stopAtLeaf?.(nestedValue)) {
|
|
1794
|
+
Object.assign(
|
|
1795
|
+
accumulator,
|
|
1796
|
+
flattenConfigObject(nestedValue, options, nextKey)
|
|
1797
|
+
);
|
|
1798
|
+
return accumulator;
|
|
1799
|
+
}
|
|
1800
|
+
accumulator[nextKey] = nestedValue;
|
|
1801
|
+
return accumulator;
|
|
1802
|
+
}, {});
|
|
1803
|
+
}
|
|
1804
|
+
function yamlObjectToEntries(document, filePath, namespace, sourceId, workspaceId = "default") {
|
|
1805
|
+
const parsed = assertObjectDocument(parseYaml(document), filePath);
|
|
1806
|
+
const flattened = flattenConfigObject(parsed, {
|
|
1807
|
+
...namespace === "secret" ? {
|
|
1808
|
+
stopAtLeaf: isSecretReference
|
|
1809
|
+
} : {}
|
|
1810
|
+
});
|
|
1811
|
+
return Object.entries(flattened).map(([key, value]) => ({
|
|
1812
|
+
key: `${namespace}.${key}`,
|
|
1813
|
+
value,
|
|
1814
|
+
namespace,
|
|
1815
|
+
sourceId,
|
|
1816
|
+
pluginId: FILESYSTEM_PLUGIN_ID,
|
|
1817
|
+
workspaceId,
|
|
1818
|
+
origin: {
|
|
1819
|
+
file: filePath
|
|
1820
|
+
}
|
|
1821
|
+
}));
|
|
1822
|
+
}
|
|
1823
|
+
async function resolveSecretValue(value, processEnv) {
|
|
1824
|
+
if (!isSecretReference(value)) {
|
|
1825
|
+
return value;
|
|
1826
|
+
}
|
|
1827
|
+
if (value.provider === "local") {
|
|
1828
|
+
if (!processEnv?.CNOS_SECRET_PASSPHRASE) {
|
|
1829
|
+
return value;
|
|
1830
|
+
}
|
|
1831
|
+
return readLocalSecret(
|
|
1832
|
+
resolveSecretStoreRoot(processEnv),
|
|
1833
|
+
value.ref,
|
|
1834
|
+
processEnv?.CNOS_SECRET_PASSPHRASE
|
|
1835
|
+
);
|
|
1836
|
+
}
|
|
1837
|
+
if (value.provider === "env") {
|
|
1838
|
+
const resolved = processEnv?.[value.ref];
|
|
1839
|
+
if (resolved === void 0) {
|
|
1840
|
+
return value;
|
|
1841
|
+
}
|
|
1842
|
+
return resolved;
|
|
1843
|
+
}
|
|
1844
|
+
return value;
|
|
1845
|
+
}
|
|
1846
|
+
function toSecretReferenceMetadata(value) {
|
|
1847
|
+
if (!isSecretReference(value)) {
|
|
1848
|
+
return void 0;
|
|
1849
|
+
}
|
|
1850
|
+
return {
|
|
1851
|
+
secretRef: value
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
1856
|
+
function filesystemSecretsReader(filePath, document, workspaceId = "default") {
|
|
1857
|
+
return yamlObjectToEntries(document, filePath, "secret", "filesystem-secrets", workspaceId);
|
|
1858
|
+
}
|
|
1859
|
+
function createFilesystemSecretsPlugin() {
|
|
1860
|
+
return {
|
|
1861
|
+
id: "filesystem-secrets",
|
|
1862
|
+
kind: "loader",
|
|
1863
|
+
async load(context) {
|
|
1864
|
+
const sourceRoot = String(context.manifestConfig.root ?? "./");
|
|
1865
|
+
const files = await collectFilesystemLayerFiles(
|
|
1866
|
+
context.manifestRoot,
|
|
1867
|
+
context.workspace.workspaceRoots,
|
|
1868
|
+
sourceRoot,
|
|
1869
|
+
context.profileActivation.secrets
|
|
1870
|
+
);
|
|
1871
|
+
const entries = [];
|
|
1872
|
+
for (const file of files) {
|
|
1873
|
+
const document = await (0, import_promises10.readFile)(file.absolutePath, "utf8");
|
|
1874
|
+
const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
|
|
1875
|
+
for (const entry of fileEntries) {
|
|
1876
|
+
const metadata = toSecretReferenceMetadata(entry.value);
|
|
1877
|
+
const resolvedValue = await resolveSecretValue(entry.value, context.processEnv);
|
|
1878
|
+
entries.push({
|
|
1879
|
+
...entry,
|
|
1880
|
+
value: resolvedValue,
|
|
1881
|
+
...metadata ? { metadata } : {}
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
return entries;
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// ../../plugins/filesystem/src/filesystemValuesReader.ts
|
|
1891
|
+
var import_promises11 = require("fs/promises");
|
|
1892
|
+
function filesystemValuesReader(filePath, document, workspaceId = "default") {
|
|
1893
|
+
return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
|
|
1894
|
+
}
|
|
1895
|
+
function createFilesystemValuesPlugin() {
|
|
1896
|
+
return {
|
|
1897
|
+
id: "filesystem-values",
|
|
1898
|
+
kind: "loader",
|
|
1899
|
+
async load(context) {
|
|
1900
|
+
const sourceRoot = String(context.manifestConfig.root ?? "./");
|
|
1901
|
+
const files = await collectFilesystemLayerFiles(
|
|
1902
|
+
context.manifestRoot,
|
|
1903
|
+
context.workspace.workspaceRoots,
|
|
1904
|
+
sourceRoot,
|
|
1905
|
+
context.profileActivation.values
|
|
1906
|
+
);
|
|
1907
|
+
const entries = [];
|
|
1908
|
+
for (const file of files) {
|
|
1909
|
+
const document = await (0, import_promises11.readFile)(file.absolutePath, "utf8");
|
|
1910
|
+
entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
|
|
1911
|
+
}
|
|
1912
|
+
return entries;
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
// ../../plugins/process-env/src/index.ts
|
|
1918
|
+
var PROCESS_ENV_PLUGIN_ID = "@kitsy/cnos/plugins/process-env";
|
|
1919
|
+
function processEnvEntriesFromObject(env, mapping = {}, workspaceId = "default") {
|
|
1920
|
+
return Object.entries(env).flatMap(([envVar, value]) => {
|
|
1921
|
+
if (typeof value !== "string") {
|
|
1922
|
+
return [];
|
|
1923
|
+
}
|
|
1924
|
+
const logicalKey = envVarToLogicalKey(envVar, mapping);
|
|
1925
|
+
if (!logicalKey) {
|
|
1926
|
+
return [];
|
|
1927
|
+
}
|
|
1928
|
+
return [
|
|
1929
|
+
{
|
|
1930
|
+
key: logicalKey,
|
|
1931
|
+
value,
|
|
1932
|
+
namespace: logicalKey.startsWith("secret.") ? "secret" : "value",
|
|
1933
|
+
sourceId: "process-env",
|
|
1934
|
+
pluginId: PROCESS_ENV_PLUGIN_ID,
|
|
1935
|
+
workspaceId,
|
|
1936
|
+
origin: {
|
|
1937
|
+
envVar
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
];
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
function createProcessEnvPlugin() {
|
|
1944
|
+
return {
|
|
1945
|
+
id: "process-env",
|
|
1946
|
+
kind: "loader",
|
|
1947
|
+
async load(context) {
|
|
1948
|
+
const config = context.manifestConfig;
|
|
1949
|
+
return processEnvEntriesFromObject(
|
|
1950
|
+
context.processEnv ?? process.env,
|
|
1951
|
+
config.envMapping,
|
|
1952
|
+
context.workspace.workspaceId
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
34
1957
|
|
|
35
1958
|
// src/defaultPlugins.ts
|
|
36
|
-
var import_cnos_core = require("@kitsy/cnos-core");
|
|
37
|
-
var import_cnos_plugin_basic_schema = require("@kitsy/cnos-plugin-basic-schema");
|
|
38
|
-
var import_cnos_plugin_cli_args = require("@kitsy/cnos-plugin-cli-args");
|
|
39
|
-
var import_cnos_plugin_dotenv = require("@kitsy/cnos-plugin-dotenv");
|
|
40
|
-
var import_cnos_plugin_env_export = require("@kitsy/cnos-plugin-env-export");
|
|
41
|
-
var import_cnos_plugin_filesystem = require("@kitsy/cnos-plugin-filesystem");
|
|
42
|
-
var import_cnos_plugin_process_env = require("@kitsy/cnos-plugin-process-env");
|
|
43
1959
|
function defaultPlugins() {
|
|
44
1960
|
return [
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
1961
|
+
createFilesystemValuesPlugin(),
|
|
1962
|
+
createFilesystemSecretsPlugin(),
|
|
1963
|
+
createDotenvPlugin(),
|
|
1964
|
+
createProcessEnvPlugin(),
|
|
1965
|
+
createCliArgsPlugin(),
|
|
1966
|
+
createBasicSchemaPlugin(),
|
|
1967
|
+
createEnvExportPlugin(),
|
|
1968
|
+
createPublicEnvExportPlugin(),
|
|
1969
|
+
createProvenanceInspector()
|
|
54
1970
|
];
|
|
55
1971
|
}
|
|
56
1972
|
|
|
57
1973
|
// src/createCnos.ts
|
|
58
|
-
async function
|
|
59
|
-
return
|
|
1974
|
+
async function createCnos2(options = {}) {
|
|
1975
|
+
return createCnos({
|
|
60
1976
|
...options,
|
|
1977
|
+
cnosVersion: package_default.version,
|
|
61
1978
|
plugins: [...defaultPlugins(), ...options.plugins ?? []]
|
|
62
1979
|
});
|
|
63
1980
|
}
|
|
64
|
-
|
|
65
|
-
// src/index.ts
|
|
66
|
-
var import_cnos_core3 = require("@kitsy/cnos-core");
|
|
67
1981
|
// Annotate the CommonJS export names for ESM import in node:
|
|
68
1982
|
0 && (module.exports = {
|
|
69
1983
|
createCnos,
|