@happyvertical/smrt-config 0.55.3 → 0.55.5
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/AGENTS.md +4 -1
- package/dist/browser.d.ts +20 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +9 -0
- package/dist/browser.js.map +1 -0
- package/dist/chunks/shared-B81TOCQq.js +1065 -0
- package/dist/chunks/shared-B81TOCQq.js.map +1 -0
- package/dist/index.d.ts +2 -291
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1056
- package/dist/index.js.map +1 -1
- package/dist/loaded-config.d.ts +25 -0
- package/dist/loaded-config.d.ts.map +1 -0
- package/dist/loader-state.d.ts +38 -0
- package/dist/loader-state.d.ts.map +1 -0
- package/dist/loader.d.ts +1 -25
- package/dist/loader.d.ts.map +1 -1
- package/dist/shared.d.ts +277 -0
- package/dist/shared.d.ts.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,1065 @@
|
|
|
1
|
+
//#region src/loaded-config.ts
|
|
2
|
+
globalThis.__smrtConfigCache ??= null;
|
|
3
|
+
function getLoadedConfig() {
|
|
4
|
+
return globalThis.__smrtConfigCache ?? null;
|
|
5
|
+
}
|
|
6
|
+
function setLoadedConfig(config) {
|
|
7
|
+
globalThis.__smrtConfigCache = config;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/loader-state.ts
|
|
11
|
+
function getCachedConfig() {
|
|
12
|
+
return globalThis.__smrtLoaderCachedConfig ?? null;
|
|
13
|
+
}
|
|
14
|
+
function setCachedConfig(config) {
|
|
15
|
+
globalThis.__smrtLoaderCachedConfig = config;
|
|
16
|
+
}
|
|
17
|
+
function getExplorer() {
|
|
18
|
+
return globalThis.__smrtLoaderExplorer ?? null;
|
|
19
|
+
}
|
|
20
|
+
function setExplorer(exp) {
|
|
21
|
+
globalThis.__smrtLoaderExplorer = exp;
|
|
22
|
+
}
|
|
23
|
+
function clearConfigCache() {
|
|
24
|
+
setCachedConfig(null);
|
|
25
|
+
const explorer = getExplorer();
|
|
26
|
+
if (explorer) {
|
|
27
|
+
explorer.clearCaches();
|
|
28
|
+
setExplorer(null);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/ai.ts
|
|
33
|
+
var AI_PROVIDER_KEY_ENV = Object.freeze({
|
|
34
|
+
openai: "OPENAI_API_KEY",
|
|
35
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
36
|
+
gemini: "GEMINI_API_KEY"
|
|
37
|
+
});
|
|
38
|
+
var AUTO_DETECT_ORDER = [
|
|
39
|
+
"openai",
|
|
40
|
+
"anthropic",
|
|
41
|
+
"gemini"
|
|
42
|
+
];
|
|
43
|
+
var DEFAULT_AI_ENV_PREFIXES = Object.freeze(["SMRT_AI", "HAVE_AI"]);
|
|
44
|
+
function getDefaultAIKeyEnvName(provider) {
|
|
45
|
+
const normalized = nonEmpty(provider)?.toLowerCase();
|
|
46
|
+
return normalized && Object.hasOwn(AI_PROVIDER_KEY_ENV, normalized) ? AI_PROVIDER_KEY_ENV[normalized] : void 0;
|
|
47
|
+
}
|
|
48
|
+
var AIProviderNotConfiguredError = class extends Error {
|
|
49
|
+
code = "SMRT_AI_NOT_CONFIGURED";
|
|
50
|
+
constructor(message) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "AIProviderNotConfiguredError";
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
function nonEmpty(value) {
|
|
56
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
57
|
+
}
|
|
58
|
+
function redactBaseUrl(value) {
|
|
59
|
+
if (!value) return void 0;
|
|
60
|
+
try {
|
|
61
|
+
const url = new URL(value);
|
|
62
|
+
return `${url.protocol}//${url.host}`;
|
|
63
|
+
} catch {
|
|
64
|
+
return "[unparseable-url]";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function tryResolveAIProviderConfig(options = {}) {
|
|
68
|
+
const env = options.env ?? process.env;
|
|
69
|
+
const read = (name) => nonEmpty(env[name]);
|
|
70
|
+
const prefixes = options.prefixes ?? DEFAULT_AI_ENV_PREFIXES;
|
|
71
|
+
const explicit = options.explicit ?? {};
|
|
72
|
+
const block = options.config ?? {};
|
|
73
|
+
const fromEnv = (suffix) => prefixes.map((prefix) => ({
|
|
74
|
+
source: `env:${prefix}_${suffix}`,
|
|
75
|
+
value: read(`${prefix}_${suffix}`)
|
|
76
|
+
}));
|
|
77
|
+
const explicitCand = (value) => ({
|
|
78
|
+
source: "explicit",
|
|
79
|
+
value: nonEmpty(value)
|
|
80
|
+
});
|
|
81
|
+
const configCand = (value) => ({
|
|
82
|
+
source: "config",
|
|
83
|
+
value: nonEmpty(value)
|
|
84
|
+
});
|
|
85
|
+
const layered = (exp, cfg, envs) => options.envOverridesConfig ? [
|
|
86
|
+
...exp,
|
|
87
|
+
...envs,
|
|
88
|
+
...cfg
|
|
89
|
+
] : [
|
|
90
|
+
...exp,
|
|
91
|
+
...cfg,
|
|
92
|
+
...envs
|
|
93
|
+
];
|
|
94
|
+
const first = (candidates) => {
|
|
95
|
+
for (const c of candidates) if (c.value) return {
|
|
96
|
+
value: c.value,
|
|
97
|
+
source: c.source
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
const sources = {};
|
|
101
|
+
const result = {};
|
|
102
|
+
const set = (field, hit) => {
|
|
103
|
+
if (hit) {
|
|
104
|
+
result[field] = hit.value;
|
|
105
|
+
sources[field] = hit.source;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
set("provider", first(layered([explicitCand(nonEmpty(explicit.provider) ?? nonEmpty(explicit.type))], [configCand(block.provider)], fromEnv("PROVIDER"))));
|
|
109
|
+
set("model", first(layered([explicitCand(nonEmpty(explicit.model) ?? nonEmpty(explicit.defaultModel))], [configCand(block.model)], fromEnv("MODEL"))));
|
|
110
|
+
const autoDetected = result.provider || options.autoDetect === false ? void 0 : AUTO_DETECT_ORDER.find((p) => read(AI_PROVIDER_KEY_ENV[p]));
|
|
111
|
+
if (autoDetected) {
|
|
112
|
+
result.provider = autoDetected;
|
|
113
|
+
sources.provider = "auto-detect";
|
|
114
|
+
}
|
|
115
|
+
const selected = result.provider?.toLowerCase();
|
|
116
|
+
const configKeyEnv = nonEmpty(block.apiKeyEnv);
|
|
117
|
+
const explicitGroup = {
|
|
118
|
+
source: "explicit",
|
|
119
|
+
provider: nonEmpty(explicit.provider) ?? nonEmpty(explicit.type),
|
|
120
|
+
apiKey: nonEmpty(explicit.apiKey),
|
|
121
|
+
baseUrl: nonEmpty(explicit.baseUrl)
|
|
122
|
+
};
|
|
123
|
+
const configGroup = {
|
|
124
|
+
source: "config",
|
|
125
|
+
provider: nonEmpty(block.provider),
|
|
126
|
+
apiKey: nonEmpty(block.apiKey) ?? (configKeyEnv ? read(configKeyEnv) : void 0),
|
|
127
|
+
baseUrl: nonEmpty(block.baseUrl)
|
|
128
|
+
};
|
|
129
|
+
const envGroups = prefixes.map((prefix) => ({
|
|
130
|
+
source: `env:${prefix}`,
|
|
131
|
+
provider: read(`${prefix}_PROVIDER`),
|
|
132
|
+
apiKey: read(`${prefix}_API_KEY`),
|
|
133
|
+
baseUrl: read(`${prefix}_BASE_URL`)
|
|
134
|
+
}));
|
|
135
|
+
const groups = options.envOverridesConfig ? [
|
|
136
|
+
explicitGroup,
|
|
137
|
+
...envGroups,
|
|
138
|
+
configGroup
|
|
139
|
+
] : [
|
|
140
|
+
explicitGroup,
|
|
141
|
+
configGroup,
|
|
142
|
+
...envGroups
|
|
143
|
+
];
|
|
144
|
+
const usable = (g) => !g.provider || g.provider.toLowerCase() === selected;
|
|
145
|
+
const sourceName = (g, suffix) => g.source.startsWith("env:") ? `${g.source}_${suffix}` : g.source;
|
|
146
|
+
for (const g of groups) {
|
|
147
|
+
if (!usable(g)) continue;
|
|
148
|
+
if (g.baseUrl && !result.baseUrl) {
|
|
149
|
+
result.baseUrl = g.baseUrl;
|
|
150
|
+
sources.baseUrl = sourceName(g, "BASE_URL");
|
|
151
|
+
}
|
|
152
|
+
if (g.apiKey && !result.apiKey) {
|
|
153
|
+
result.apiKey = g.apiKey;
|
|
154
|
+
sources.apiKey = sourceName(g, "API_KEY");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const providerKeyEnv = getDefaultAIKeyEnvName(result.provider);
|
|
158
|
+
if (!result.apiKey && providerKeyEnv && options.providerKeyEnvFallback !== false && read(providerKeyEnv)) {
|
|
159
|
+
result.apiKey = read(providerKeyEnv);
|
|
160
|
+
sources.apiKey = "provider-key-env";
|
|
161
|
+
}
|
|
162
|
+
if (!result.provider && (options.requireProvider ?? true)) return;
|
|
163
|
+
if (!result.provider && !result.apiKey) return;
|
|
164
|
+
const resolved = {
|
|
165
|
+
...result,
|
|
166
|
+
sources,
|
|
167
|
+
toJSON: () => describeAIProviderConfig(resolved)
|
|
168
|
+
};
|
|
169
|
+
Object.defineProperty(resolved, "toJSON", { enumerable: false });
|
|
170
|
+
return resolved;
|
|
171
|
+
}
|
|
172
|
+
function resolveAIProviderConfig(options = {}) {
|
|
173
|
+
const resolved = tryResolveAIProviderConfig(options);
|
|
174
|
+
if (resolved) return resolved;
|
|
175
|
+
const envNames = (options.prefixes ?? DEFAULT_AI_ENV_PREFIXES).map((p) => `${p}_PROVIDER`).join(", ");
|
|
176
|
+
const keyNames = Object.values(AI_PROVIDER_KEY_ENV).join(", ");
|
|
177
|
+
throw new AIProviderNotConfiguredError(`No AI provider is configured. Set the \`ai\` block in smrt.config.ts (provider, model, apiKeyEnv), or set ${envNames}` + (options.autoDetect === false ? "." : `, or one of ${keyNames} to auto-detect the provider.`));
|
|
178
|
+
}
|
|
179
|
+
function describeAIProviderConfig(resolved) {
|
|
180
|
+
return {
|
|
181
|
+
provider: resolved.provider,
|
|
182
|
+
model: resolved.model,
|
|
183
|
+
baseUrl: redactBaseUrl(resolved.baseUrl),
|
|
184
|
+
apiKey: resolved.apiKey ? "[redacted]" : void 0,
|
|
185
|
+
sources: { ...resolved.sources }
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function toAIClientOptions(resolved) {
|
|
189
|
+
const out = {};
|
|
190
|
+
if (resolved.provider) {
|
|
191
|
+
out.type = resolved.provider;
|
|
192
|
+
out.provider = resolved.provider;
|
|
193
|
+
}
|
|
194
|
+
if (resolved.apiKey) out.apiKey = resolved.apiKey;
|
|
195
|
+
if (resolved.baseUrl) out.baseUrl = resolved.baseUrl;
|
|
196
|
+
if (resolved.model) out.defaultModel = resolved.model;
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
var OWNED_AI_FIELDS = [
|
|
200
|
+
"apiKey",
|
|
201
|
+
"apiKeyEnv",
|
|
202
|
+
"baseUrl",
|
|
203
|
+
"model"
|
|
204
|
+
];
|
|
205
|
+
function canonicalizeAIConfig(input) {
|
|
206
|
+
if (!input || typeof input !== "object") return {};
|
|
207
|
+
const out = {};
|
|
208
|
+
for (const [key, value] of Object.entries(input)) {
|
|
209
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
210
|
+
if (typeof value === "string" && value.trim().length === 0) continue;
|
|
211
|
+
out[key] = value;
|
|
212
|
+
}
|
|
213
|
+
const provider = nonEmpty(out.provider) ?? nonEmpty(out.type);
|
|
214
|
+
const model = nonEmpty(out.model) ?? nonEmpty(out.defaultModel);
|
|
215
|
+
delete out.type;
|
|
216
|
+
delete out.defaultModel;
|
|
217
|
+
if (provider) out.provider = provider;
|
|
218
|
+
else delete out.provider;
|
|
219
|
+
if (model) out.model = model;
|
|
220
|
+
else delete out.model;
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
function mergeAIConfigObjects(lower, higher) {
|
|
224
|
+
const low = canonicalizeAIConfig(lower);
|
|
225
|
+
const high = canonicalizeAIConfig(higher);
|
|
226
|
+
const lowName = nonEmpty(low.provider)?.toLowerCase();
|
|
227
|
+
const highName = nonEmpty(high.provider)?.toLowerCase();
|
|
228
|
+
if (lowName && highName && lowName !== highName) {
|
|
229
|
+
delete low.provider;
|
|
230
|
+
for (const f of OWNED_AI_FIELDS) delete low[f];
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
...low,
|
|
234
|
+
...high
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function withAIAliases(config) {
|
|
238
|
+
const out = { ...config };
|
|
239
|
+
const provider = nonEmpty(out.provider) ?? nonEmpty(out.type);
|
|
240
|
+
const model = nonEmpty(out.model) ?? nonEmpty(out.defaultModel);
|
|
241
|
+
for (const k of ["provider", "type"]) if (provider) out[k] = provider;
|
|
242
|
+
else delete out[k];
|
|
243
|
+
for (const k of ["model", "defaultModel"]) if (model) out[k] = model;
|
|
244
|
+
else delete out[k];
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/database-environment.ts
|
|
249
|
+
var POSTGRES_URL = /^postgres(?:ql)?:\/\//i;
|
|
250
|
+
function environmentType(value) {
|
|
251
|
+
const normalized = value?.trim().toLowerCase();
|
|
252
|
+
if (!normalized) return null;
|
|
253
|
+
if (normalized === "sqlite") return "sqlite";
|
|
254
|
+
if (normalized === "postgres" || normalized === "postgresql") return "postgres";
|
|
255
|
+
throw new TypeError("DATABASE_TYPE must be sqlite or postgres.");
|
|
256
|
+
}
|
|
257
|
+
function resolveCliDatabase(declared, env) {
|
|
258
|
+
if (typeof declared?.url === "string" && declared.url !== "") return {
|
|
259
|
+
source: "config",
|
|
260
|
+
database: typeof declared.type === "string" ? {
|
|
261
|
+
type: declared.type,
|
|
262
|
+
url: declared.url
|
|
263
|
+
} : { url: declared.url }
|
|
264
|
+
};
|
|
265
|
+
const url = env.DATABASE_URL?.trim();
|
|
266
|
+
if (!url) return {
|
|
267
|
+
source: "none",
|
|
268
|
+
database: null
|
|
269
|
+
};
|
|
270
|
+
let type;
|
|
271
|
+
try {
|
|
272
|
+
type = declared?.type === "sqlite" || declared?.type === "postgres" ? declared.type : environmentType(env.DATABASE_TYPE) ?? (POSTGRES_URL.test(url) ? "postgres" : "sqlite");
|
|
273
|
+
} catch (error) {
|
|
274
|
+
return {
|
|
275
|
+
source: "invalid-environment",
|
|
276
|
+
database: null,
|
|
277
|
+
error: error.message
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
source: "environment",
|
|
282
|
+
database: {
|
|
283
|
+
type,
|
|
284
|
+
url
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/runtime-profile.ts
|
|
290
|
+
function isApplicationRuntimeProfile(value) {
|
|
291
|
+
return value === "local" || value === "self-hosted" || value === "cloud";
|
|
292
|
+
}
|
|
293
|
+
function invalidProfileIssue() {
|
|
294
|
+
return {
|
|
295
|
+
code: "invalid_config",
|
|
296
|
+
path: "profile",
|
|
297
|
+
message: "must be local, self-hosted, or cloud.",
|
|
298
|
+
recovery: "Select one documented runtime profile."
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
var RuntimeProfileValidationError = class extends Error {
|
|
302
|
+
issues;
|
|
303
|
+
constructor(issues) {
|
|
304
|
+
super(`Invalid application runtime profile:
|
|
305
|
+
${issues.map((issue) => `- ${issue.path}: ${issue.message} Recovery: ${issue.recovery}`).join("\n")}`);
|
|
306
|
+
this.name = "RuntimeProfileValidationError";
|
|
307
|
+
this.issues = Object.freeze(issues.map((issue) => Object.freeze({ ...issue })));
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
var PROFILE_DEFAULTS = {
|
|
311
|
+
local: {
|
|
312
|
+
database: {
|
|
313
|
+
engine: "sqlite",
|
|
314
|
+
connectionOwnership: "user"
|
|
315
|
+
},
|
|
316
|
+
authentication: {
|
|
317
|
+
provider: "owner-bootstrap",
|
|
318
|
+
ownerBootstrap: "single-use"
|
|
319
|
+
},
|
|
320
|
+
tenancy: {
|
|
321
|
+
mode: "default-tenant",
|
|
322
|
+
context: "defaulted",
|
|
323
|
+
isolation: "application"
|
|
324
|
+
},
|
|
325
|
+
assets: {
|
|
326
|
+
provider: "local-files",
|
|
327
|
+
ownership: "user"
|
|
328
|
+
},
|
|
329
|
+
secrets: {
|
|
330
|
+
provider: "local-file",
|
|
331
|
+
ownership: "user"
|
|
332
|
+
},
|
|
333
|
+
jobs: { topology: "embedded" },
|
|
334
|
+
network: {
|
|
335
|
+
exposure: "loopback",
|
|
336
|
+
tls: false
|
|
337
|
+
},
|
|
338
|
+
portability: {
|
|
339
|
+
backup: "file-snapshot",
|
|
340
|
+
logicalExport: true,
|
|
341
|
+
logicalImport: true
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
"self-hosted": {
|
|
345
|
+
database: {
|
|
346
|
+
engine: "postgres",
|
|
347
|
+
connectionOwnership: "operator"
|
|
348
|
+
},
|
|
349
|
+
authentication: {
|
|
350
|
+
provider: "oidc",
|
|
351
|
+
ownerBootstrap: "disabled"
|
|
352
|
+
},
|
|
353
|
+
tenancy: {
|
|
354
|
+
mode: "single-tenant",
|
|
355
|
+
context: "defaulted",
|
|
356
|
+
isolation: "application"
|
|
357
|
+
},
|
|
358
|
+
assets: {
|
|
359
|
+
provider: "s3-compatible",
|
|
360
|
+
ownership: "operator"
|
|
361
|
+
},
|
|
362
|
+
secrets: {
|
|
363
|
+
provider: "environment",
|
|
364
|
+
ownership: "operator"
|
|
365
|
+
},
|
|
366
|
+
jobs: { topology: "external" },
|
|
367
|
+
network: {
|
|
368
|
+
exposure: "public",
|
|
369
|
+
tls: true
|
|
370
|
+
},
|
|
371
|
+
portability: {
|
|
372
|
+
backup: "operator",
|
|
373
|
+
logicalExport: true,
|
|
374
|
+
logicalImport: true
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
cloud: {
|
|
378
|
+
database: {
|
|
379
|
+
engine: "postgres",
|
|
380
|
+
connectionOwnership: "managed"
|
|
381
|
+
},
|
|
382
|
+
authentication: {
|
|
383
|
+
provider: "hosted-identity",
|
|
384
|
+
ownerBootstrap: "disabled"
|
|
385
|
+
},
|
|
386
|
+
tenancy: {
|
|
387
|
+
mode: "multi-tenant",
|
|
388
|
+
context: "required",
|
|
389
|
+
isolation: "database-rls"
|
|
390
|
+
},
|
|
391
|
+
assets: {
|
|
392
|
+
provider: "managed-object-storage",
|
|
393
|
+
ownership: "managed"
|
|
394
|
+
},
|
|
395
|
+
secrets: {
|
|
396
|
+
provider: "managed",
|
|
397
|
+
ownership: "managed"
|
|
398
|
+
},
|
|
399
|
+
jobs: { topology: "scalable" },
|
|
400
|
+
network: {
|
|
401
|
+
exposure: "public",
|
|
402
|
+
tls: true
|
|
403
|
+
},
|
|
404
|
+
portability: {
|
|
405
|
+
backup: "managed",
|
|
406
|
+
logicalExport: true,
|
|
407
|
+
logicalImport: true
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
var INVARIANTS = {
|
|
412
|
+
domainModels: "identical",
|
|
413
|
+
generatedRest: "identical",
|
|
414
|
+
generatedCli: "identical",
|
|
415
|
+
generatedMcp: "identical",
|
|
416
|
+
generatedWebMcp: "identical",
|
|
417
|
+
mcpExposurePolicy: "identical",
|
|
418
|
+
webMcpExposurePolicy: "identical",
|
|
419
|
+
actionEffects: "identical",
|
|
420
|
+
approvalPolicy: "identical",
|
|
421
|
+
authorizationRecords: "required",
|
|
422
|
+
jobInvocation: "identical",
|
|
423
|
+
portability: "logical-export-import"
|
|
424
|
+
};
|
|
425
|
+
var PROVIDER_FIELDS = {
|
|
426
|
+
database: ["engine", "connectionOwnership"],
|
|
427
|
+
authentication: ["provider", "ownerBootstrap"],
|
|
428
|
+
tenancy: [
|
|
429
|
+
"mode",
|
|
430
|
+
"context",
|
|
431
|
+
"isolation"
|
|
432
|
+
],
|
|
433
|
+
assets: ["provider", "ownership"],
|
|
434
|
+
secrets: ["provider", "ownership"],
|
|
435
|
+
jobs: ["topology"],
|
|
436
|
+
network: ["exposure", "tls"]
|
|
437
|
+
};
|
|
438
|
+
var PROVIDER_VALUE_DOMAINS = {
|
|
439
|
+
database: {
|
|
440
|
+
engine: ["sqlite", "postgres"],
|
|
441
|
+
connectionOwnership: [
|
|
442
|
+
"user",
|
|
443
|
+
"operator",
|
|
444
|
+
"managed"
|
|
445
|
+
]
|
|
446
|
+
},
|
|
447
|
+
authentication: {
|
|
448
|
+
provider: [
|
|
449
|
+
"owner-bootstrap",
|
|
450
|
+
"oidc",
|
|
451
|
+
"magic-link",
|
|
452
|
+
"hosted-identity"
|
|
453
|
+
],
|
|
454
|
+
ownerBootstrap: ["single-use", "disabled"]
|
|
455
|
+
},
|
|
456
|
+
tenancy: {
|
|
457
|
+
mode: [
|
|
458
|
+
"default-tenant",
|
|
459
|
+
"single-tenant",
|
|
460
|
+
"multi-tenant"
|
|
461
|
+
],
|
|
462
|
+
context: ["defaulted", "required"],
|
|
463
|
+
isolation: ["application", "database-rls"]
|
|
464
|
+
},
|
|
465
|
+
assets: {
|
|
466
|
+
provider: [
|
|
467
|
+
"local-files",
|
|
468
|
+
"s3-compatible",
|
|
469
|
+
"managed-object-storage"
|
|
470
|
+
],
|
|
471
|
+
ownership: [
|
|
472
|
+
"user",
|
|
473
|
+
"operator",
|
|
474
|
+
"managed"
|
|
475
|
+
]
|
|
476
|
+
},
|
|
477
|
+
secrets: {
|
|
478
|
+
provider: [
|
|
479
|
+
"local-file",
|
|
480
|
+
"environment",
|
|
481
|
+
"external",
|
|
482
|
+
"managed"
|
|
483
|
+
],
|
|
484
|
+
ownership: [
|
|
485
|
+
"user",
|
|
486
|
+
"operator",
|
|
487
|
+
"managed"
|
|
488
|
+
]
|
|
489
|
+
},
|
|
490
|
+
jobs: { topology: [
|
|
491
|
+
"inline",
|
|
492
|
+
"embedded",
|
|
493
|
+
"external",
|
|
494
|
+
"scalable"
|
|
495
|
+
] },
|
|
496
|
+
network: {
|
|
497
|
+
exposure: ["loopback", "public"],
|
|
498
|
+
tls: [false, true]
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
function isPlainRecord(value) {
|
|
502
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
503
|
+
const prototype = Object.getPrototypeOf(value);
|
|
504
|
+
return prototype === Object.prototype || prototype === null;
|
|
505
|
+
}
|
|
506
|
+
function cloneDefaults(profile) {
|
|
507
|
+
const defaults = PROFILE_DEFAULTS[profile];
|
|
508
|
+
return {
|
|
509
|
+
database: { ...defaults.database },
|
|
510
|
+
authentication: { ...defaults.authentication },
|
|
511
|
+
tenancy: { ...defaults.tenancy },
|
|
512
|
+
assets: { ...defaults.assets },
|
|
513
|
+
secrets: { ...defaults.secrets },
|
|
514
|
+
jobs: { ...defaults.jobs },
|
|
515
|
+
network: { ...defaults.network },
|
|
516
|
+
portability: { ...defaults.portability }
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function rejectUnknownFields(input) {
|
|
520
|
+
const issues = [];
|
|
521
|
+
for (const key of Object.keys(input).sort()) if (key !== "profile" && key !== "providers") issues.push({
|
|
522
|
+
code: "unsupported_field",
|
|
523
|
+
path: key,
|
|
524
|
+
message: "is not part of the runtime-profile contract.",
|
|
525
|
+
recovery: "Move provider selection under providers or remove this field."
|
|
526
|
+
});
|
|
527
|
+
if (Object.hasOwn(input, "profile") && !isApplicationRuntimeProfile(input.profile)) issues.push(invalidProfileIssue());
|
|
528
|
+
const providers = Object.hasOwn(input, "providers") ? input.providers : void 0;
|
|
529
|
+
if (providers === void 0) return issues;
|
|
530
|
+
if (!isPlainRecord(providers)) {
|
|
531
|
+
issues.push({
|
|
532
|
+
code: "invalid_config",
|
|
533
|
+
path: "providers",
|
|
534
|
+
message: "must be an object with Object.prototype or null.",
|
|
535
|
+
recovery: "Use providers: { database: { ... } } or omit providers."
|
|
536
|
+
});
|
|
537
|
+
return issues;
|
|
538
|
+
}
|
|
539
|
+
for (const providerName of Object.keys(providers).sort()) {
|
|
540
|
+
if (!Object.hasOwn(PROVIDER_FIELDS, providerName)) {
|
|
541
|
+
issues.push({
|
|
542
|
+
code: "unsupported_field",
|
|
543
|
+
path: `providers.${providerName}`,
|
|
544
|
+
message: "is not an overridable infrastructure provider.",
|
|
545
|
+
recovery: "Use database, authentication, tenancy, assets, secrets, jobs, or network."
|
|
546
|
+
});
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const value = providers[providerName];
|
|
550
|
+
if (!isPlainRecord(value)) {
|
|
551
|
+
issues.push({
|
|
552
|
+
code: "invalid_config",
|
|
553
|
+
path: `providers.${providerName}`,
|
|
554
|
+
message: "must be an object with Object.prototype or null.",
|
|
555
|
+
recovery: `Provide a partial ${providerName} provider object or omit it.`
|
|
556
|
+
});
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
const allowed = PROVIDER_FIELDS[providerName];
|
|
560
|
+
const valueDomains = PROVIDER_VALUE_DOMAINS[providerName];
|
|
561
|
+
for (const field of Object.keys(value).sort()) {
|
|
562
|
+
if (!allowed.includes(field)) {
|
|
563
|
+
issues.push({
|
|
564
|
+
code: "unsupported_field",
|
|
565
|
+
path: `providers.${providerName}.${field}`,
|
|
566
|
+
message: "is not a supported provider override.",
|
|
567
|
+
recovery: "Remove secret values and application-policy fields; configure only documented provider selectors."
|
|
568
|
+
});
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
const suppliedValue = Object.hasOwn(value, field) ? value[field] : void 0;
|
|
572
|
+
const allowedValues = valueDomains[field];
|
|
573
|
+
if (suppliedValue !== void 0 && !allowedValues.includes(suppliedValue)) issues.push({
|
|
574
|
+
code: "invalid_config",
|
|
575
|
+
path: `providers.${providerName}.${field}`,
|
|
576
|
+
message: `must be one of ${allowedValues.map(String).join(", ")}.`,
|
|
577
|
+
recovery: "Choose a documented provider selector value; supplied values are omitted from diagnostics."
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return issues;
|
|
582
|
+
}
|
|
583
|
+
function validateApplicationRuntimeConfigShape(config) {
|
|
584
|
+
if (!isPlainRecord(config)) return [{
|
|
585
|
+
code: "invalid_config",
|
|
586
|
+
path: "runtime",
|
|
587
|
+
message: "must be an object with Object.prototype or null.",
|
|
588
|
+
recovery: "Provide runtime: { profile: \"local\" | \"self-hosted\" | \"cloud\" }."
|
|
589
|
+
}];
|
|
590
|
+
return rejectUnknownFields(config);
|
|
591
|
+
}
|
|
592
|
+
function applyOverrides(providers, input) {
|
|
593
|
+
const overrideRoot = Object.hasOwn(input, "providers") && isPlainRecord(input.providers) ? input.providers : {};
|
|
594
|
+
const report = [];
|
|
595
|
+
for (const providerName of Object.keys(PROVIDER_FIELDS)) {
|
|
596
|
+
if (!Object.hasOwn(overrideRoot, providerName)) continue;
|
|
597
|
+
const supplied = overrideRoot[providerName];
|
|
598
|
+
if (!isPlainRecord(supplied)) continue;
|
|
599
|
+
const target = providers[providerName];
|
|
600
|
+
for (const field of PROVIDER_FIELDS[providerName]) {
|
|
601
|
+
if (!Object.hasOwn(supplied, field)) continue;
|
|
602
|
+
const value = supplied[field];
|
|
603
|
+
if (value === void 0) continue;
|
|
604
|
+
const previous = target[field];
|
|
605
|
+
target[field] = value;
|
|
606
|
+
if (value !== previous) report.push({
|
|
607
|
+
path: `providers.${providerName}.${field}`,
|
|
608
|
+
from: previous,
|
|
609
|
+
to: value
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return report;
|
|
614
|
+
}
|
|
615
|
+
function incompatible(issues, path, expected, recovery) {
|
|
616
|
+
issues.push({
|
|
617
|
+
code: "incompatible_provider",
|
|
618
|
+
path,
|
|
619
|
+
message: `is incompatible; ${expected}.`,
|
|
620
|
+
recovery
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
function requireAllowed(issues, path, actual, allowed, profile) {
|
|
624
|
+
if (!allowed.includes(actual)) incompatible(issues, path, `${profile} requires one of ${allowed.map(String).join(", ")}`, `Choose a supported ${profile} provider or select a different profile.`);
|
|
625
|
+
}
|
|
626
|
+
function validateComposition(profile, providers) {
|
|
627
|
+
const issues = [];
|
|
628
|
+
const allow = (path, actual, values) => requireAllowed(issues, path, actual, values, profile);
|
|
629
|
+
if (profile === "local") {
|
|
630
|
+
allow("providers.database.engine", providers.database.engine, ["sqlite"]);
|
|
631
|
+
allow("providers.database.connectionOwnership", providers.database.connectionOwnership, ["user"]);
|
|
632
|
+
allow("providers.authentication.provider", providers.authentication.provider, ["owner-bootstrap"]);
|
|
633
|
+
allow("providers.authentication.ownerBootstrap", providers.authentication.ownerBootstrap, ["single-use"]);
|
|
634
|
+
allow("providers.tenancy.mode", providers.tenancy.mode, ["default-tenant"]);
|
|
635
|
+
allow("providers.tenancy.context", providers.tenancy.context, ["defaulted"]);
|
|
636
|
+
allow("providers.tenancy.isolation", providers.tenancy.isolation, ["application"]);
|
|
637
|
+
allow("providers.assets.provider", providers.assets.provider, ["local-files"]);
|
|
638
|
+
allow("providers.assets.ownership", providers.assets.ownership, ["user"]);
|
|
639
|
+
allow("providers.secrets.provider", providers.secrets.provider, ["local-file"]);
|
|
640
|
+
allow("providers.secrets.ownership", providers.secrets.ownership, ["user"]);
|
|
641
|
+
allow("providers.jobs.topology", providers.jobs.topology, ["inline", "embedded"]);
|
|
642
|
+
allow("providers.network.exposure", providers.network.exposure, ["loopback"]);
|
|
643
|
+
allow("providers.network.tls", providers.network.tls, [false, true]);
|
|
644
|
+
} else if (profile === "self-hosted") {
|
|
645
|
+
allow("providers.database.engine", providers.database.engine, ["postgres"]);
|
|
646
|
+
allow("providers.database.connectionOwnership", providers.database.connectionOwnership, ["operator"]);
|
|
647
|
+
allow("providers.authentication.provider", providers.authentication.provider, ["oidc", "magic-link"]);
|
|
648
|
+
allow("providers.authentication.ownerBootstrap", providers.authentication.ownerBootstrap, ["disabled"]);
|
|
649
|
+
allow("providers.tenancy.mode", providers.tenancy.mode, ["single-tenant", "multi-tenant"]);
|
|
650
|
+
allow("providers.tenancy.context", providers.tenancy.context, providers.tenancy.mode === "multi-tenant" ? ["required"] : ["defaulted"]);
|
|
651
|
+
allow("providers.tenancy.isolation", providers.tenancy.isolation, ["application", "database-rls"]);
|
|
652
|
+
allow("providers.assets.provider", providers.assets.provider, ["local-files", "s3-compatible"]);
|
|
653
|
+
allow("providers.assets.ownership", providers.assets.ownership, ["operator"]);
|
|
654
|
+
allow("providers.secrets.provider", providers.secrets.provider, [
|
|
655
|
+
"environment",
|
|
656
|
+
"local-file",
|
|
657
|
+
"external"
|
|
658
|
+
]);
|
|
659
|
+
allow("providers.secrets.ownership", providers.secrets.ownership, ["operator"]);
|
|
660
|
+
allow("providers.jobs.topology", providers.jobs.topology, ["external"]);
|
|
661
|
+
allow("providers.network.exposure", providers.network.exposure, ["public"]);
|
|
662
|
+
allow("providers.network.tls", providers.network.tls, [true]);
|
|
663
|
+
} else {
|
|
664
|
+
allow("providers.database.engine", providers.database.engine, ["postgres"]);
|
|
665
|
+
allow("providers.database.connectionOwnership", providers.database.connectionOwnership, ["managed"]);
|
|
666
|
+
allow("providers.authentication.provider", providers.authentication.provider, ["hosted-identity"]);
|
|
667
|
+
allow("providers.authentication.ownerBootstrap", providers.authentication.ownerBootstrap, ["disabled"]);
|
|
668
|
+
allow("providers.tenancy.mode", providers.tenancy.mode, ["multi-tenant"]);
|
|
669
|
+
allow("providers.tenancy.context", providers.tenancy.context, ["required"]);
|
|
670
|
+
allow("providers.tenancy.isolation", providers.tenancy.isolation, ["application", "database-rls"]);
|
|
671
|
+
allow("providers.assets.provider", providers.assets.provider, ["managed-object-storage", "s3-compatible"]);
|
|
672
|
+
allow("providers.assets.ownership", providers.assets.ownership, ["managed"]);
|
|
673
|
+
allow("providers.secrets.provider", providers.secrets.provider, ["managed", "external"]);
|
|
674
|
+
allow("providers.secrets.ownership", providers.secrets.ownership, ["managed"]);
|
|
675
|
+
allow("providers.jobs.topology", providers.jobs.topology, ["scalable"]);
|
|
676
|
+
allow("providers.network.exposure", providers.network.exposure, ["public"]);
|
|
677
|
+
allow("providers.network.tls", providers.network.tls, [true]);
|
|
678
|
+
}
|
|
679
|
+
return issues;
|
|
680
|
+
}
|
|
681
|
+
function deriveCapabilities(profile, providers) {
|
|
682
|
+
return {
|
|
683
|
+
ownerBootstrap: providers.authentication.ownerBootstrap === "single-use",
|
|
684
|
+
publicAuthentication: providers.authentication.provider !== "owner-bootstrap",
|
|
685
|
+
defaultTenant: providers.tenancy.context === "defaulted",
|
|
686
|
+
multiTenant: providers.tenancy.mode === "multi-tenant",
|
|
687
|
+
localAssets: providers.assets.provider === "local-files",
|
|
688
|
+
externalWorkers: providers.jobs.topology === "external" || providers.jobs.topology === "scalable",
|
|
689
|
+
backup: true,
|
|
690
|
+
logicalExport: true,
|
|
691
|
+
logicalImport: true,
|
|
692
|
+
diagnostics: true,
|
|
693
|
+
orchestrationHealth: profile !== "local"
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function deepFreeze(value) {
|
|
697
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
698
|
+
Object.freeze(value);
|
|
699
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
700
|
+
}
|
|
701
|
+
return value;
|
|
702
|
+
}
|
|
703
|
+
function resolveApplicationRuntime(config) {
|
|
704
|
+
if (!isPlainRecord(config)) throw new RuntimeProfileValidationError([...validateApplicationRuntimeConfigShape(config)]);
|
|
705
|
+
const unknownIssues = validateApplicationRuntimeConfigShape(config);
|
|
706
|
+
const profile = Object.hasOwn(config, "profile") ? config.profile : void 0;
|
|
707
|
+
if (!isApplicationRuntimeProfile(profile)) throw new RuntimeProfileValidationError([...unknownIssues, ...Object.hasOwn(config, "profile") ? [] : [invalidProfileIssue()]]);
|
|
708
|
+
const providers = cloneDefaults(profile);
|
|
709
|
+
const overrides = applyOverrides(providers, config);
|
|
710
|
+
const issues = [...unknownIssues, ...validateComposition(profile, providers)];
|
|
711
|
+
if (issues.length > 0) throw new RuntimeProfileValidationError(issues);
|
|
712
|
+
return deepFreeze({
|
|
713
|
+
schemaVersion: 1,
|
|
714
|
+
profile,
|
|
715
|
+
providers,
|
|
716
|
+
capabilities: deriveCapabilities(profile, providers),
|
|
717
|
+
invariants: { ...INVARIANTS },
|
|
718
|
+
diagnostics: {
|
|
719
|
+
secretValuesIncluded: false,
|
|
720
|
+
overrides,
|
|
721
|
+
unsafeOverrides: []
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
function getApplicationRuntimePreset(profile) {
|
|
726
|
+
if (!isApplicationRuntimeProfile(profile)) throw new RuntimeProfileValidationError([invalidProfileIssue()]);
|
|
727
|
+
return deepFreeze(cloneDefaults(profile));
|
|
728
|
+
}
|
|
729
|
+
//#endregion
|
|
730
|
+
//#region src/merge.ts
|
|
731
|
+
globalThis.__smrtRuntimeConfig ??= {};
|
|
732
|
+
var UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
733
|
+
"__proto__",
|
|
734
|
+
"constructor",
|
|
735
|
+
"prototype"
|
|
736
|
+
]);
|
|
737
|
+
function defineOwn(target, key, value) {
|
|
738
|
+
Object.defineProperty(target, key, {
|
|
739
|
+
configurable: true,
|
|
740
|
+
enumerable: true,
|
|
741
|
+
value,
|
|
742
|
+
writable: true
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
function isPlainObject(value) {
|
|
746
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
747
|
+
const proto = Object.getPrototypeOf(value);
|
|
748
|
+
return proto === null || proto === Object.prototype;
|
|
749
|
+
}
|
|
750
|
+
function deepClone(value) {
|
|
751
|
+
if (Array.isArray(value)) return value.map((item) => deepClone(item));
|
|
752
|
+
if (isPlainObject(value)) {
|
|
753
|
+
const out = {};
|
|
754
|
+
for (const key of Object.keys(value)) {
|
|
755
|
+
if (UNSAFE_KEYS.has(key)) continue;
|
|
756
|
+
defineOwn(out, key, deepClone(value[key]));
|
|
757
|
+
}
|
|
758
|
+
return out;
|
|
759
|
+
}
|
|
760
|
+
return value;
|
|
761
|
+
}
|
|
762
|
+
function deepMerge(target, source) {
|
|
763
|
+
const result = {};
|
|
764
|
+
const tgt = target;
|
|
765
|
+
const src = source;
|
|
766
|
+
for (const key of Object.keys(tgt)) {
|
|
767
|
+
if (UNSAFE_KEYS.has(key) || Object.hasOwn(src, key)) continue;
|
|
768
|
+
defineOwn(result, key, deepClone(tgt[key]));
|
|
769
|
+
}
|
|
770
|
+
for (const key of Object.keys(src)) {
|
|
771
|
+
if (UNSAFE_KEYS.has(key)) continue;
|
|
772
|
+
const sourceValue = src[key];
|
|
773
|
+
const targetValue = Object.hasOwn(tgt, key) ? tgt[key] : void 0;
|
|
774
|
+
if (isPlainObject(sourceValue) && isPlainObject(targetValue)) defineOwn(result, key, deepMerge(targetValue, sourceValue));
|
|
775
|
+
else if (sourceValue !== void 0 && sourceValue !== null) defineOwn(result, key, deepClone(sourceValue));
|
|
776
|
+
else if (targetValue !== void 0) defineOwn(result, key, deepClone(targetValue));
|
|
777
|
+
}
|
|
778
|
+
return result;
|
|
779
|
+
}
|
|
780
|
+
function setConfig$1(config) {
|
|
781
|
+
const incomingRuntime = Object.hasOwn(config, "runtime") ? config.runtime : void 0;
|
|
782
|
+
if (incomingRuntime !== void 0 && (incomingRuntime === null || typeof incomingRuntime !== "object" || Array.isArray(incomingRuntime))) throw new RuntimeProfileValidationError([...validateApplicationRuntimeConfigShape(incomingRuntime)]);
|
|
783
|
+
if (incomingRuntime !== null && (typeof incomingRuntime === "object" || typeof incomingRuntime === "function") && Object.hasOwn(incomingRuntime, "profile")) {
|
|
784
|
+
const profileIssues = validateApplicationRuntimeConfigShape(incomingRuntime).filter((issue) => issue.path === "runtime" || issue.path === "profile");
|
|
785
|
+
if (profileIssues.length > 0) throw new RuntimeProfileValidationError([...profileIssues]);
|
|
786
|
+
}
|
|
787
|
+
let current = globalThis.__smrtRuntimeConfig || {};
|
|
788
|
+
const currentRuntime = Object.hasOwn(current, "runtime") && isPlainObject(current.runtime) ? current.runtime : void 0;
|
|
789
|
+
const incomingRuntimeMap = Object.hasOwn(config, "runtime") && isPlainObject(config.runtime) ? config.runtime : void 0;
|
|
790
|
+
if (currentRuntime !== void 0 && incomingRuntimeMap !== void 0 && Object.hasOwn(currentRuntime, "profile") && Object.hasOwn(incomingRuntimeMap, "profile") && currentRuntime.profile !== incomingRuntimeMap.profile) {
|
|
791
|
+
current = deepClone(current);
|
|
792
|
+
const resetRuntime = current.runtime;
|
|
793
|
+
delete resetRuntime.providers;
|
|
794
|
+
}
|
|
795
|
+
const merged = deepMerge(current, config);
|
|
796
|
+
const aiOf = (c) => isPlainObject(c) && isPlainObject(c.ai) ? c.ai : void 0;
|
|
797
|
+
const pkgAiOf = (c) => isPlainObject(c) && isPlainObject(c.packages) && isPlainObject(c.packages.ai) ? c.packages.ai : void 0;
|
|
798
|
+
if (aiOf(config)) merged.ai = mergeAIConfigObjects(aiOf(current) ?? {}, aiOf(config));
|
|
799
|
+
if (pkgAiOf(config)) merged.packages.ai = mergeAIConfigObjects(pkgAiOf(current) ?? {}, pkgAiOf(config));
|
|
800
|
+
globalThis.__smrtRuntimeConfig = merged;
|
|
801
|
+
}
|
|
802
|
+
function getRuntimeConfig() {
|
|
803
|
+
return globalThis.__smrtRuntimeConfig || {};
|
|
804
|
+
}
|
|
805
|
+
function clearRuntimeConfig() {
|
|
806
|
+
globalThis.__smrtRuntimeConfig = {};
|
|
807
|
+
}
|
|
808
|
+
function mergeConfigs(defaults, fileConfig, runtime) {
|
|
809
|
+
let result = { ...defaults };
|
|
810
|
+
result = deepMerge(result, fileConfig);
|
|
811
|
+
result = deepMerge(result, runtime);
|
|
812
|
+
return result;
|
|
813
|
+
}
|
|
814
|
+
//#endregion
|
|
815
|
+
//#region src/export.ts
|
|
816
|
+
var SECRET_PATTERNS = [
|
|
817
|
+
/secret/i,
|
|
818
|
+
/password/i,
|
|
819
|
+
/passwd/i,
|
|
820
|
+
/(^|[_-])pass([_-]|$)/i,
|
|
821
|
+
/(^|[_-])pwd([_-]|$)/i,
|
|
822
|
+
/[a-z0-9]Pass([_-]|$)/,
|
|
823
|
+
/[a-z0-9]Pwd([_-]|$)/,
|
|
824
|
+
/^(pass|pwd)$/i,
|
|
825
|
+
/token/i,
|
|
826
|
+
/credential/i,
|
|
827
|
+
/private/i,
|
|
828
|
+
/oauth/i,
|
|
829
|
+
/authorization/i,
|
|
830
|
+
/(^|[_-])auth([_-]|$)/i,
|
|
831
|
+
/cookie/i,
|
|
832
|
+
/salt/i,
|
|
833
|
+
/passphrase/i,
|
|
834
|
+
/\bcert\b/i,
|
|
835
|
+
/certificate/i,
|
|
836
|
+
/api[_-]?key/i,
|
|
837
|
+
/access[_-]?key/i,
|
|
838
|
+
/secret[_-]?key/i,
|
|
839
|
+
/signing[_-]?key/i,
|
|
840
|
+
/encryption[_-]?key/i,
|
|
841
|
+
/private[_-]?key/i,
|
|
842
|
+
/public[_-]?key/i,
|
|
843
|
+
/[a-z0-9]Key([_-]|Id|$)/,
|
|
844
|
+
/(^|[_-])key([_-]|id$|$)/i,
|
|
845
|
+
/connection[_-]?string/i,
|
|
846
|
+
/conn[_-]?str/i,
|
|
847
|
+
/(^|[_-])db[_-]?url/i,
|
|
848
|
+
/database[_-]?url/i,
|
|
849
|
+
/datasource[_-]?url/i
|
|
850
|
+
];
|
|
851
|
+
function isSecretKey(key) {
|
|
852
|
+
return SECRET_PATTERNS.some((pattern) => pattern.test(key));
|
|
853
|
+
}
|
|
854
|
+
var CREDENTIAL_URL_RE = /([a-z][a-z0-9+.-]*:\/\/)[^/?#@\s]+@/gi;
|
|
855
|
+
var VALUE_SECRET_PATTERNS = [
|
|
856
|
+
{
|
|
857
|
+
re: /-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z ]+ )?PRIVATE KEY-----/g,
|
|
858
|
+
replace: "***REDACTED PRIVATE KEY***"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
re: /\bsk-(?:proj-|ant-)?[A-Za-z0-9_-]{16,}/g,
|
|
862
|
+
replace: "***"
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
re: /\b[sr]k_(?:live|test)_[A-Za-z0-9]{16,}/g,
|
|
866
|
+
replace: "***"
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
re: /\bgh[pousr]_[A-Za-z0-9]{20,}/g,
|
|
870
|
+
replace: "***"
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
re: /\bgithub_pat_[A-Za-z0-9_]{22,}/g,
|
|
874
|
+
replace: "***"
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
re: /\bxox[abprs]-[A-Za-z0-9-]{10,}/g,
|
|
878
|
+
replace: "***"
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
re: /\bAIza[A-Za-z0-9_-]{35}/g,
|
|
882
|
+
replace: "***"
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
re: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,
|
|
886
|
+
replace: "***"
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
re: /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/gi,
|
|
890
|
+
replace: "Bearer ***"
|
|
891
|
+
}
|
|
892
|
+
];
|
|
893
|
+
function redactValueSecrets(value) {
|
|
894
|
+
let out = value.replace(CREDENTIAL_URL_RE, "$1***@");
|
|
895
|
+
for (const { re, replace } of VALUE_SECRET_PATTERNS) out = out.replace(re, replace);
|
|
896
|
+
return out;
|
|
897
|
+
}
|
|
898
|
+
function sanitizeConfig(config) {
|
|
899
|
+
if (config === null || config === void 0) return config;
|
|
900
|
+
if (Array.isArray(config)) return config.map((item) => sanitizeConfig(item));
|
|
901
|
+
if (typeof config === "object") {
|
|
902
|
+
const result = {};
|
|
903
|
+
for (const [key, value] of Object.entries(config)) {
|
|
904
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
905
|
+
if (isSecretKey(key)) continue;
|
|
906
|
+
result[key] = sanitizeConfig(value);
|
|
907
|
+
}
|
|
908
|
+
return result;
|
|
909
|
+
}
|
|
910
|
+
if (typeof config === "string") return redactValueSecrets(config);
|
|
911
|
+
return config;
|
|
912
|
+
}
|
|
913
|
+
function exportConfig(config, options = {}) {
|
|
914
|
+
const { includeSecrets = false, format = "json", indent = 2 } = options;
|
|
915
|
+
const exportData = includeSecrets ? config : sanitizeConfig(config);
|
|
916
|
+
const jsonString = JSON.stringify(exportData, null, indent);
|
|
917
|
+
if (format === "js") return `export default ${jsonString};
|
|
918
|
+
`;
|
|
919
|
+
return jsonString;
|
|
920
|
+
}
|
|
921
|
+
function parseExportedConfig(content) {
|
|
922
|
+
const trimmed = content.trim();
|
|
923
|
+
if (trimmed.startsWith("export default")) {
|
|
924
|
+
const jsonPart = trimmed.replace(/^export default\s*/, "").replace(/;\s*$/, "");
|
|
925
|
+
return JSON.parse(jsonPart);
|
|
926
|
+
}
|
|
927
|
+
return JSON.parse(content);
|
|
928
|
+
}
|
|
929
|
+
function mergeExportedConfig(baseConfig, exportedConfig) {
|
|
930
|
+
const result = { ...baseConfig };
|
|
931
|
+
for (const [key, value] of Object.entries(exportedConfig)) {
|
|
932
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
933
|
+
if (key === "ai" && value !== null && typeof value === "object" && !Array.isArray(value) && result[key] !== null && typeof result[key] === "object" && !Array.isArray(result[key])) result[key] = mergeAIConfigObjects(result[key], value);
|
|
934
|
+
else if (value !== null && typeof value === "object" && !Array.isArray(value) && result[key] !== null && typeof result[key] === "object" && !Array.isArray(result[key])) result[key] = mergeExportedConfig(result[key], value);
|
|
935
|
+
else result[key] = value;
|
|
936
|
+
}
|
|
937
|
+
return result;
|
|
938
|
+
}
|
|
939
|
+
//#endregion
|
|
940
|
+
//#region src/shared.ts
|
|
941
|
+
function getConfig() {
|
|
942
|
+
return getLoadedConfig();
|
|
943
|
+
}
|
|
944
|
+
function resolveConfiguredApplicationRuntime() {
|
|
945
|
+
return resolveRuntimeLayers(getLoadedConfig());
|
|
946
|
+
}
|
|
947
|
+
function resolveEffectiveApplicationRuntime(config) {
|
|
948
|
+
if (!declaresRuntime(config ?? null) && !declaresRuntime(getRuntimeConfig())) return resolveApplicationRuntime({ profile: "local" });
|
|
949
|
+
return resolveRuntimeLayers(config ?? null);
|
|
950
|
+
}
|
|
951
|
+
function declaresRuntime(layer) {
|
|
952
|
+
return layer !== null && Object.hasOwn(layer, "runtime") && layer.runtime !== void 0;
|
|
953
|
+
}
|
|
954
|
+
function resolveRuntimeLayers(loadedConfig) {
|
|
955
|
+
const runtimeConfig = getRuntimeConfig();
|
|
956
|
+
const fileRuntime = loadedConfig && Object.hasOwn(loadedConfig, "runtime") ? loadedConfig.runtime : void 0;
|
|
957
|
+
const runtimeOverride = Object.hasOwn(runtimeConfig, "runtime") ? runtimeConfig.runtime : void 0;
|
|
958
|
+
for (const layer of [fileRuntime, runtimeOverride]) {
|
|
959
|
+
if (layer === void 0) continue;
|
|
960
|
+
const shapeIssues = validateApplicationRuntimeConfigShape(layer);
|
|
961
|
+
if (shapeIssues.length > 0) throw new RuntimeProfileValidationError([...shapeIssues]);
|
|
962
|
+
}
|
|
963
|
+
const fileHasProfile = fileRuntime !== void 0 && Object.hasOwn(fileRuntime, "profile");
|
|
964
|
+
const profileChanged = runtimeOverride !== void 0 && Object.hasOwn(runtimeOverride, "profile") && runtimeOverride.profile !== (fileHasProfile ? fileRuntime.profile : void 0);
|
|
965
|
+
if (profileChanged && fileHasProfile) resolveApplicationRuntime(fileRuntime);
|
|
966
|
+
const fileRuntimeWithoutProviders = { ...fileRuntime ?? {} };
|
|
967
|
+
delete fileRuntimeWithoutProviders.providers;
|
|
968
|
+
return resolveApplicationRuntime(mergeConfigs({}, profileChanged ? fileRuntimeWithoutProviders : fileRuntime ?? {}, runtimeOverride ?? {}));
|
|
969
|
+
}
|
|
970
|
+
function getSiteConfig() {
|
|
971
|
+
return (getLoadedConfig() || {}).site || null;
|
|
972
|
+
}
|
|
973
|
+
function getModuleConfig(moduleName, defaults) {
|
|
974
|
+
const fileConfig = getLoadedConfig() || {};
|
|
975
|
+
const runtime = getRuntimeConfig();
|
|
976
|
+
const globalConfig = fileConfig.smrt || {};
|
|
977
|
+
const moduleConfig = fileConfig.modules?.[moduleName] || {};
|
|
978
|
+
const runtimeModuleConfig = runtime.modules?.[moduleName] || {};
|
|
979
|
+
return mergeConfigs(mergeConfigs(mergeConfigs(defaults || {}, globalConfig, {}), moduleConfig, {}), runtimeModuleConfig, {});
|
|
980
|
+
}
|
|
981
|
+
function resolveCliDatabaseConfig(env = process.env) {
|
|
982
|
+
const declared = getPackageConfig("cli").database;
|
|
983
|
+
return resolveCliDatabase(declared, env);
|
|
984
|
+
}
|
|
985
|
+
function getPackageConfig(packageName, defaults) {
|
|
986
|
+
const fileConfig = getLoadedConfig() || {};
|
|
987
|
+
const runtime = getRuntimeConfig();
|
|
988
|
+
const globalConfig = fileConfig.smrt || {};
|
|
989
|
+
const packageConfig = fileConfig.packages?.[packageName] || {};
|
|
990
|
+
const runtimePackageConfig = runtime.packages?.[packageName] || {};
|
|
991
|
+
return mergeConfigs(mergeConfigs(mergeConfigs(defaults || {}, globalConfig, {}), packageConfig, {}), runtimePackageConfig, {});
|
|
992
|
+
}
|
|
993
|
+
function setConfig(config) {
|
|
994
|
+
setConfig$1(config);
|
|
995
|
+
}
|
|
996
|
+
function clearCache() {
|
|
997
|
+
setLoadedConfig(null);
|
|
998
|
+
clearConfigCache();
|
|
999
|
+
clearRuntimeConfig();
|
|
1000
|
+
}
|
|
1001
|
+
function defineConfig(config) {
|
|
1002
|
+
return config;
|
|
1003
|
+
}
|
|
1004
|
+
function getAIConfigBlock() {
|
|
1005
|
+
const file = getLoadedConfig();
|
|
1006
|
+
const runtime = getRuntimeConfig();
|
|
1007
|
+
return mergeAIConfigLayers([
|
|
1008
|
+
file?.packages?.ai,
|
|
1009
|
+
file?.ai,
|
|
1010
|
+
runtime.packages?.ai,
|
|
1011
|
+
runtime.ai
|
|
1012
|
+
]);
|
|
1013
|
+
}
|
|
1014
|
+
function mergeAIConfigLayers(layers) {
|
|
1015
|
+
const FIELDS = [
|
|
1016
|
+
"model",
|
|
1017
|
+
"baseUrl",
|
|
1018
|
+
"apiKeyEnv",
|
|
1019
|
+
"apiKey"
|
|
1020
|
+
];
|
|
1021
|
+
let provider;
|
|
1022
|
+
const values = {};
|
|
1023
|
+
const owners = {};
|
|
1024
|
+
const text = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
1025
|
+
for (const layer of layers) {
|
|
1026
|
+
if (!layer || typeof layer !== "object") continue;
|
|
1027
|
+
const rec = layer;
|
|
1028
|
+
const named = text(rec.provider) ?? text(rec.type);
|
|
1029
|
+
if (named && provider && named.toLowerCase() !== provider.toLowerCase()) for (const f of FIELDS) {
|
|
1030
|
+
const owner = owners[f];
|
|
1031
|
+
if (owner && owner.toLowerCase() !== named.toLowerCase()) {
|
|
1032
|
+
delete values[f];
|
|
1033
|
+
delete owners[f];
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (named) provider = named;
|
|
1037
|
+
for (const f of FIELDS) {
|
|
1038
|
+
const v = f === "model" ? text(rec.model) ?? text(rec.defaultModel) : text(rec[f]);
|
|
1039
|
+
if (v) {
|
|
1040
|
+
values[f] = v;
|
|
1041
|
+
owners[f] = provider;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
if (!provider && FIELDS.every((f) => !values[f])) return null;
|
|
1046
|
+
const merged = { ...values };
|
|
1047
|
+
if (provider) merged.provider = provider;
|
|
1048
|
+
return merged;
|
|
1049
|
+
}
|
|
1050
|
+
function resolveConfiguredAIProvider(options = {}) {
|
|
1051
|
+
return resolveAIProviderConfig({
|
|
1052
|
+
...options,
|
|
1053
|
+
config: options.config === void 0 ? getAIConfigBlock() : options.config
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
function tryResolveConfiguredAIProvider(options = {}) {
|
|
1057
|
+
return tryResolveAIProviderConfig({
|
|
1058
|
+
...options,
|
|
1059
|
+
config: options.config === void 0 ? getAIConfigBlock() : options.config
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
//#endregion
|
|
1063
|
+
export { getDefaultAIKeyEnvName as A, setExplorer as B, getApplicationRuntimePreset as C, DEFAULT_AI_ENV_PREFIXES as D, AI_PROVIDER_KEY_ENV as E, tryResolveAIProviderConfig as F, withAIAliases as I, getCachedConfig as L, redactBaseUrl as M, resolveAIProviderConfig as N, canonicalizeAIConfig as O, toAIClientOptions as P, getExplorer as R, RuntimeProfileValidationError as S, AIProviderNotConfiguredError as T, setLoadedConfig as V, parseExportedConfig as _, getModuleConfig as a, getRuntimeConfig as b, mergeAIConfigLayers as c, resolveConfiguredApplicationRuntime as d, resolveEffectiveApplicationRuntime as f, mergeExportedConfig as g, exportConfig as h, getConfig as i, mergeAIConfigObjects as j, describeAIProviderConfig as k, resolveCliDatabaseConfig as l, tryResolveConfiguredAIProvider as m, defineConfig as n, getPackageConfig as o, setConfig as p, getAIConfigBlock as r, getSiteConfig as s, clearCache as t, resolveConfiguredAIProvider as u, sanitizeConfig as v, resolveApplicationRuntime as w, mergeConfigs as x, clearRuntimeConfig as y, setCachedConfig as z };
|
|
1064
|
+
|
|
1065
|
+
//# sourceMappingURL=shared-B81TOCQq.js.map
|