@happyvertical/smrt-config 0.43.6 → 0.43.7
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 +6 -0
- package/README.md +71 -1
- package/dist/index.d.ts +213 -2
- package/dist/index.js +488 -9
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +95 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -76,6 +76,447 @@ function clearConfigCache() {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
//#endregion
|
|
79
|
+
//#region src/runtime-profile.ts
|
|
80
|
+
function isApplicationRuntimeProfile(value) {
|
|
81
|
+
return value === "local" || value === "self-hosted" || value === "cloud";
|
|
82
|
+
}
|
|
83
|
+
function invalidProfileIssue() {
|
|
84
|
+
return {
|
|
85
|
+
code: "invalid_config",
|
|
86
|
+
path: "profile",
|
|
87
|
+
message: "must be local, self-hosted, or cloud.",
|
|
88
|
+
recovery: "Select one documented runtime profile."
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
var RuntimeProfileValidationError = class extends Error {
|
|
92
|
+
issues;
|
|
93
|
+
constructor(issues) {
|
|
94
|
+
super(`Invalid application runtime profile:
|
|
95
|
+
${issues.map((issue) => `- ${issue.path}: ${issue.message} Recovery: ${issue.recovery}`).join("\n")}`);
|
|
96
|
+
this.name = "RuntimeProfileValidationError";
|
|
97
|
+
this.issues = Object.freeze(issues.map((issue) => Object.freeze({ ...issue })));
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var PROFILE_DEFAULTS = {
|
|
101
|
+
local: {
|
|
102
|
+
database: {
|
|
103
|
+
engine: "sqlite",
|
|
104
|
+
connectionOwnership: "user"
|
|
105
|
+
},
|
|
106
|
+
authentication: {
|
|
107
|
+
provider: "owner-bootstrap",
|
|
108
|
+
ownerBootstrap: "single-use"
|
|
109
|
+
},
|
|
110
|
+
tenancy: {
|
|
111
|
+
mode: "default-tenant",
|
|
112
|
+
context: "defaulted",
|
|
113
|
+
isolation: "application"
|
|
114
|
+
},
|
|
115
|
+
assets: {
|
|
116
|
+
provider: "local-files",
|
|
117
|
+
ownership: "user"
|
|
118
|
+
},
|
|
119
|
+
secrets: {
|
|
120
|
+
provider: "local-file",
|
|
121
|
+
ownership: "user"
|
|
122
|
+
},
|
|
123
|
+
jobs: { topology: "embedded" },
|
|
124
|
+
network: {
|
|
125
|
+
exposure: "loopback",
|
|
126
|
+
tls: false
|
|
127
|
+
},
|
|
128
|
+
portability: {
|
|
129
|
+
backup: "file-snapshot",
|
|
130
|
+
logicalExport: true,
|
|
131
|
+
logicalImport: true
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"self-hosted": {
|
|
135
|
+
database: {
|
|
136
|
+
engine: "postgres",
|
|
137
|
+
connectionOwnership: "operator"
|
|
138
|
+
},
|
|
139
|
+
authentication: {
|
|
140
|
+
provider: "oidc",
|
|
141
|
+
ownerBootstrap: "disabled"
|
|
142
|
+
},
|
|
143
|
+
tenancy: {
|
|
144
|
+
mode: "single-tenant",
|
|
145
|
+
context: "defaulted",
|
|
146
|
+
isolation: "application"
|
|
147
|
+
},
|
|
148
|
+
assets: {
|
|
149
|
+
provider: "s3-compatible",
|
|
150
|
+
ownership: "operator"
|
|
151
|
+
},
|
|
152
|
+
secrets: {
|
|
153
|
+
provider: "environment",
|
|
154
|
+
ownership: "operator"
|
|
155
|
+
},
|
|
156
|
+
jobs: { topology: "external" },
|
|
157
|
+
network: {
|
|
158
|
+
exposure: "public",
|
|
159
|
+
tls: true
|
|
160
|
+
},
|
|
161
|
+
portability: {
|
|
162
|
+
backup: "operator",
|
|
163
|
+
logicalExport: true,
|
|
164
|
+
logicalImport: true
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
cloud: {
|
|
168
|
+
database: {
|
|
169
|
+
engine: "postgres",
|
|
170
|
+
connectionOwnership: "managed"
|
|
171
|
+
},
|
|
172
|
+
authentication: {
|
|
173
|
+
provider: "hosted-identity",
|
|
174
|
+
ownerBootstrap: "disabled"
|
|
175
|
+
},
|
|
176
|
+
tenancy: {
|
|
177
|
+
mode: "multi-tenant",
|
|
178
|
+
context: "required",
|
|
179
|
+
isolation: "database-rls"
|
|
180
|
+
},
|
|
181
|
+
assets: {
|
|
182
|
+
provider: "managed-object-storage",
|
|
183
|
+
ownership: "managed"
|
|
184
|
+
},
|
|
185
|
+
secrets: {
|
|
186
|
+
provider: "managed",
|
|
187
|
+
ownership: "managed"
|
|
188
|
+
},
|
|
189
|
+
jobs: { topology: "scalable" },
|
|
190
|
+
network: {
|
|
191
|
+
exposure: "public",
|
|
192
|
+
tls: true
|
|
193
|
+
},
|
|
194
|
+
portability: {
|
|
195
|
+
backup: "managed",
|
|
196
|
+
logicalExport: true,
|
|
197
|
+
logicalImport: true
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
var INVARIANTS = {
|
|
202
|
+
domainModels: "identical",
|
|
203
|
+
generatedRest: "identical",
|
|
204
|
+
generatedCli: "identical",
|
|
205
|
+
generatedMcp: "identical",
|
|
206
|
+
generatedWebMcp: "identical",
|
|
207
|
+
mcpExposurePolicy: "identical",
|
|
208
|
+
webMcpExposurePolicy: "identical",
|
|
209
|
+
actionEffects: "identical",
|
|
210
|
+
approvalPolicy: "identical",
|
|
211
|
+
authorizationRecords: "required",
|
|
212
|
+
jobInvocation: "identical",
|
|
213
|
+
portability: "logical-export-import"
|
|
214
|
+
};
|
|
215
|
+
var PROVIDER_FIELDS = {
|
|
216
|
+
database: ["engine", "connectionOwnership"],
|
|
217
|
+
authentication: ["provider", "ownerBootstrap"],
|
|
218
|
+
tenancy: [
|
|
219
|
+
"mode",
|
|
220
|
+
"context",
|
|
221
|
+
"isolation"
|
|
222
|
+
],
|
|
223
|
+
assets: ["provider", "ownership"],
|
|
224
|
+
secrets: ["provider", "ownership"],
|
|
225
|
+
jobs: ["topology"],
|
|
226
|
+
network: ["exposure", "tls"]
|
|
227
|
+
};
|
|
228
|
+
var PROVIDER_VALUE_DOMAINS = {
|
|
229
|
+
database: {
|
|
230
|
+
engine: ["sqlite", "postgres"],
|
|
231
|
+
connectionOwnership: [
|
|
232
|
+
"user",
|
|
233
|
+
"operator",
|
|
234
|
+
"managed"
|
|
235
|
+
]
|
|
236
|
+
},
|
|
237
|
+
authentication: {
|
|
238
|
+
provider: [
|
|
239
|
+
"owner-bootstrap",
|
|
240
|
+
"oidc",
|
|
241
|
+
"magic-link",
|
|
242
|
+
"hosted-identity"
|
|
243
|
+
],
|
|
244
|
+
ownerBootstrap: ["single-use", "disabled"]
|
|
245
|
+
},
|
|
246
|
+
tenancy: {
|
|
247
|
+
mode: [
|
|
248
|
+
"default-tenant",
|
|
249
|
+
"single-tenant",
|
|
250
|
+
"multi-tenant"
|
|
251
|
+
],
|
|
252
|
+
context: ["defaulted", "required"],
|
|
253
|
+
isolation: ["application", "database-rls"]
|
|
254
|
+
},
|
|
255
|
+
assets: {
|
|
256
|
+
provider: [
|
|
257
|
+
"local-files",
|
|
258
|
+
"s3-compatible",
|
|
259
|
+
"managed-object-storage"
|
|
260
|
+
],
|
|
261
|
+
ownership: [
|
|
262
|
+
"user",
|
|
263
|
+
"operator",
|
|
264
|
+
"managed"
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
secrets: {
|
|
268
|
+
provider: [
|
|
269
|
+
"local-file",
|
|
270
|
+
"environment",
|
|
271
|
+
"external",
|
|
272
|
+
"managed"
|
|
273
|
+
],
|
|
274
|
+
ownership: [
|
|
275
|
+
"user",
|
|
276
|
+
"operator",
|
|
277
|
+
"managed"
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
jobs: { topology: [
|
|
281
|
+
"inline",
|
|
282
|
+
"embedded",
|
|
283
|
+
"external",
|
|
284
|
+
"scalable"
|
|
285
|
+
] },
|
|
286
|
+
network: {
|
|
287
|
+
exposure: ["loopback", "public"],
|
|
288
|
+
tls: [false, true]
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
function isPlainRecord(value) {
|
|
292
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
293
|
+
const prototype = Object.getPrototypeOf(value);
|
|
294
|
+
return prototype === Object.prototype || prototype === null;
|
|
295
|
+
}
|
|
296
|
+
function cloneDefaults(profile) {
|
|
297
|
+
const defaults = PROFILE_DEFAULTS[profile];
|
|
298
|
+
return {
|
|
299
|
+
database: { ...defaults.database },
|
|
300
|
+
authentication: { ...defaults.authentication },
|
|
301
|
+
tenancy: { ...defaults.tenancy },
|
|
302
|
+
assets: { ...defaults.assets },
|
|
303
|
+
secrets: { ...defaults.secrets },
|
|
304
|
+
jobs: { ...defaults.jobs },
|
|
305
|
+
network: { ...defaults.network },
|
|
306
|
+
portability: { ...defaults.portability }
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function rejectUnknownFields(input) {
|
|
310
|
+
const issues = [];
|
|
311
|
+
for (const key of Object.keys(input).sort()) if (key !== "profile" && key !== "providers") issues.push({
|
|
312
|
+
code: "unsupported_field",
|
|
313
|
+
path: key,
|
|
314
|
+
message: "is not part of the runtime-profile contract.",
|
|
315
|
+
recovery: "Move provider selection under providers or remove this field."
|
|
316
|
+
});
|
|
317
|
+
if (Object.hasOwn(input, "profile") && !isApplicationRuntimeProfile(input.profile)) issues.push(invalidProfileIssue());
|
|
318
|
+
const providers = Object.hasOwn(input, "providers") ? input.providers : void 0;
|
|
319
|
+
if (providers === void 0) return issues;
|
|
320
|
+
if (!isPlainRecord(providers)) {
|
|
321
|
+
issues.push({
|
|
322
|
+
code: "invalid_config",
|
|
323
|
+
path: "providers",
|
|
324
|
+
message: "must be an object with Object.prototype or null.",
|
|
325
|
+
recovery: "Use providers: { database: { ... } } or omit providers."
|
|
326
|
+
});
|
|
327
|
+
return issues;
|
|
328
|
+
}
|
|
329
|
+
for (const providerName of Object.keys(providers).sort()) {
|
|
330
|
+
if (!Object.hasOwn(PROVIDER_FIELDS, providerName)) {
|
|
331
|
+
issues.push({
|
|
332
|
+
code: "unsupported_field",
|
|
333
|
+
path: `providers.${providerName}`,
|
|
334
|
+
message: "is not an overridable infrastructure provider.",
|
|
335
|
+
recovery: "Use database, authentication, tenancy, assets, secrets, jobs, or network."
|
|
336
|
+
});
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const value = providers[providerName];
|
|
340
|
+
if (!isPlainRecord(value)) {
|
|
341
|
+
issues.push({
|
|
342
|
+
code: "invalid_config",
|
|
343
|
+
path: `providers.${providerName}`,
|
|
344
|
+
message: "must be an object with Object.prototype or null.",
|
|
345
|
+
recovery: `Provide a partial ${providerName} provider object or omit it.`
|
|
346
|
+
});
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const allowed = PROVIDER_FIELDS[providerName];
|
|
350
|
+
const valueDomains = PROVIDER_VALUE_DOMAINS[providerName];
|
|
351
|
+
for (const field of Object.keys(value).sort()) {
|
|
352
|
+
if (!allowed.includes(field)) {
|
|
353
|
+
issues.push({
|
|
354
|
+
code: "unsupported_field",
|
|
355
|
+
path: `providers.${providerName}.${field}`,
|
|
356
|
+
message: "is not a supported provider override.",
|
|
357
|
+
recovery: "Remove secret values and application-policy fields; configure only documented provider selectors."
|
|
358
|
+
});
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const suppliedValue = Object.hasOwn(value, field) ? value[field] : void 0;
|
|
362
|
+
const allowedValues = valueDomains[field];
|
|
363
|
+
if (suppliedValue !== void 0 && !allowedValues.includes(suppliedValue)) issues.push({
|
|
364
|
+
code: "invalid_config",
|
|
365
|
+
path: `providers.${providerName}.${field}`,
|
|
366
|
+
message: `must be one of ${allowedValues.map(String).join(", ")}.`,
|
|
367
|
+
recovery: "Choose a documented provider selector value; supplied values are omitted from diagnostics."
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return issues;
|
|
372
|
+
}
|
|
373
|
+
function validateApplicationRuntimeConfigShape(config) {
|
|
374
|
+
if (!isPlainRecord(config)) return [{
|
|
375
|
+
code: "invalid_config",
|
|
376
|
+
path: "runtime",
|
|
377
|
+
message: "must be an object with Object.prototype or null.",
|
|
378
|
+
recovery: "Provide runtime: { profile: \"local\" | \"self-hosted\" | \"cloud\" }."
|
|
379
|
+
}];
|
|
380
|
+
return rejectUnknownFields(config);
|
|
381
|
+
}
|
|
382
|
+
function applyOverrides(providers, input) {
|
|
383
|
+
const overrideRoot = Object.hasOwn(input, "providers") && isPlainRecord(input.providers) ? input.providers : {};
|
|
384
|
+
const report = [];
|
|
385
|
+
for (const providerName of Object.keys(PROVIDER_FIELDS)) {
|
|
386
|
+
if (!Object.hasOwn(overrideRoot, providerName)) continue;
|
|
387
|
+
const supplied = overrideRoot[providerName];
|
|
388
|
+
if (!isPlainRecord(supplied)) continue;
|
|
389
|
+
const target = providers[providerName];
|
|
390
|
+
for (const field of PROVIDER_FIELDS[providerName]) {
|
|
391
|
+
if (!Object.hasOwn(supplied, field)) continue;
|
|
392
|
+
const value = supplied[field];
|
|
393
|
+
if (value === void 0) continue;
|
|
394
|
+
const previous = target[field];
|
|
395
|
+
target[field] = value;
|
|
396
|
+
if (value !== previous) report.push({
|
|
397
|
+
path: `providers.${providerName}.${field}`,
|
|
398
|
+
from: previous,
|
|
399
|
+
to: value
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return report;
|
|
404
|
+
}
|
|
405
|
+
function incompatible(issues, path, expected, recovery) {
|
|
406
|
+
issues.push({
|
|
407
|
+
code: "incompatible_provider",
|
|
408
|
+
path,
|
|
409
|
+
message: `is incompatible; ${expected}.`,
|
|
410
|
+
recovery
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
function requireAllowed(issues, path, actual, allowed, profile) {
|
|
414
|
+
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.`);
|
|
415
|
+
}
|
|
416
|
+
function validateComposition(profile, providers) {
|
|
417
|
+
const issues = [];
|
|
418
|
+
const allow = (path, actual, values) => requireAllowed(issues, path, actual, values, profile);
|
|
419
|
+
if (profile === "local") {
|
|
420
|
+
allow("providers.database.engine", providers.database.engine, ["sqlite"]);
|
|
421
|
+
allow("providers.database.connectionOwnership", providers.database.connectionOwnership, ["user"]);
|
|
422
|
+
allow("providers.authentication.provider", providers.authentication.provider, ["owner-bootstrap"]);
|
|
423
|
+
allow("providers.authentication.ownerBootstrap", providers.authentication.ownerBootstrap, ["single-use"]);
|
|
424
|
+
allow("providers.tenancy.mode", providers.tenancy.mode, ["default-tenant"]);
|
|
425
|
+
allow("providers.tenancy.context", providers.tenancy.context, ["defaulted"]);
|
|
426
|
+
allow("providers.tenancy.isolation", providers.tenancy.isolation, ["application"]);
|
|
427
|
+
allow("providers.assets.provider", providers.assets.provider, ["local-files"]);
|
|
428
|
+
allow("providers.assets.ownership", providers.assets.ownership, ["user"]);
|
|
429
|
+
allow("providers.secrets.provider", providers.secrets.provider, ["local-file"]);
|
|
430
|
+
allow("providers.secrets.ownership", providers.secrets.ownership, ["user"]);
|
|
431
|
+
allow("providers.jobs.topology", providers.jobs.topology, ["inline", "embedded"]);
|
|
432
|
+
allow("providers.network.exposure", providers.network.exposure, ["loopback"]);
|
|
433
|
+
allow("providers.network.tls", providers.network.tls, [false, true]);
|
|
434
|
+
} else if (profile === "self-hosted") {
|
|
435
|
+
allow("providers.database.engine", providers.database.engine, ["postgres"]);
|
|
436
|
+
allow("providers.database.connectionOwnership", providers.database.connectionOwnership, ["operator"]);
|
|
437
|
+
allow("providers.authentication.provider", providers.authentication.provider, ["oidc", "magic-link"]);
|
|
438
|
+
allow("providers.authentication.ownerBootstrap", providers.authentication.ownerBootstrap, ["disabled"]);
|
|
439
|
+
allow("providers.tenancy.mode", providers.tenancy.mode, ["single-tenant", "multi-tenant"]);
|
|
440
|
+
allow("providers.tenancy.context", providers.tenancy.context, providers.tenancy.mode === "multi-tenant" ? ["required"] : ["defaulted"]);
|
|
441
|
+
allow("providers.tenancy.isolation", providers.tenancy.isolation, ["application", "database-rls"]);
|
|
442
|
+
allow("providers.assets.provider", providers.assets.provider, ["local-files", "s3-compatible"]);
|
|
443
|
+
allow("providers.assets.ownership", providers.assets.ownership, ["operator"]);
|
|
444
|
+
allow("providers.secrets.provider", providers.secrets.provider, [
|
|
445
|
+
"environment",
|
|
446
|
+
"local-file",
|
|
447
|
+
"external"
|
|
448
|
+
]);
|
|
449
|
+
allow("providers.secrets.ownership", providers.secrets.ownership, ["operator"]);
|
|
450
|
+
allow("providers.jobs.topology", providers.jobs.topology, ["external"]);
|
|
451
|
+
allow("providers.network.exposure", providers.network.exposure, ["public"]);
|
|
452
|
+
allow("providers.network.tls", providers.network.tls, [true]);
|
|
453
|
+
} else {
|
|
454
|
+
allow("providers.database.engine", providers.database.engine, ["postgres"]);
|
|
455
|
+
allow("providers.database.connectionOwnership", providers.database.connectionOwnership, ["managed"]);
|
|
456
|
+
allow("providers.authentication.provider", providers.authentication.provider, ["hosted-identity"]);
|
|
457
|
+
allow("providers.authentication.ownerBootstrap", providers.authentication.ownerBootstrap, ["disabled"]);
|
|
458
|
+
allow("providers.tenancy.mode", providers.tenancy.mode, ["multi-tenant"]);
|
|
459
|
+
allow("providers.tenancy.context", providers.tenancy.context, ["required"]);
|
|
460
|
+
allow("providers.tenancy.isolation", providers.tenancy.isolation, ["application", "database-rls"]);
|
|
461
|
+
allow("providers.assets.provider", providers.assets.provider, ["managed-object-storage", "s3-compatible"]);
|
|
462
|
+
allow("providers.assets.ownership", providers.assets.ownership, ["managed"]);
|
|
463
|
+
allow("providers.secrets.provider", providers.secrets.provider, ["managed", "external"]);
|
|
464
|
+
allow("providers.secrets.ownership", providers.secrets.ownership, ["managed"]);
|
|
465
|
+
allow("providers.jobs.topology", providers.jobs.topology, ["scalable"]);
|
|
466
|
+
allow("providers.network.exposure", providers.network.exposure, ["public"]);
|
|
467
|
+
allow("providers.network.tls", providers.network.tls, [true]);
|
|
468
|
+
}
|
|
469
|
+
return issues;
|
|
470
|
+
}
|
|
471
|
+
function deriveCapabilities(profile, providers) {
|
|
472
|
+
return {
|
|
473
|
+
ownerBootstrap: providers.authentication.ownerBootstrap === "single-use",
|
|
474
|
+
publicAuthentication: providers.authentication.provider !== "owner-bootstrap",
|
|
475
|
+
defaultTenant: providers.tenancy.context === "defaulted",
|
|
476
|
+
multiTenant: providers.tenancy.mode === "multi-tenant",
|
|
477
|
+
localAssets: providers.assets.provider === "local-files",
|
|
478
|
+
externalWorkers: providers.jobs.topology === "external" || providers.jobs.topology === "scalable",
|
|
479
|
+
backup: true,
|
|
480
|
+
logicalExport: true,
|
|
481
|
+
logicalImport: true,
|
|
482
|
+
diagnostics: true,
|
|
483
|
+
orchestrationHealth: profile !== "local"
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function deepFreeze(value) {
|
|
487
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
488
|
+
Object.freeze(value);
|
|
489
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
490
|
+
}
|
|
491
|
+
return value;
|
|
492
|
+
}
|
|
493
|
+
function resolveApplicationRuntime(config) {
|
|
494
|
+
if (!isPlainRecord(config)) throw new RuntimeProfileValidationError([...validateApplicationRuntimeConfigShape(config)]);
|
|
495
|
+
const unknownIssues = validateApplicationRuntimeConfigShape(config);
|
|
496
|
+
const profile = Object.hasOwn(config, "profile") ? config.profile : void 0;
|
|
497
|
+
if (!isApplicationRuntimeProfile(profile)) throw new RuntimeProfileValidationError([...unknownIssues, ...Object.hasOwn(config, "profile") ? [] : [invalidProfileIssue()]]);
|
|
498
|
+
const providers = cloneDefaults(profile);
|
|
499
|
+
const overrides = applyOverrides(providers, config);
|
|
500
|
+
const issues = [...unknownIssues, ...validateComposition(profile, providers)];
|
|
501
|
+
if (issues.length > 0) throw new RuntimeProfileValidationError(issues);
|
|
502
|
+
return deepFreeze({
|
|
503
|
+
schemaVersion: 1,
|
|
504
|
+
profile,
|
|
505
|
+
providers,
|
|
506
|
+
capabilities: deriveCapabilities(profile, providers),
|
|
507
|
+
invariants: { ...INVARIANTS },
|
|
508
|
+
diagnostics: {
|
|
509
|
+
secretValuesIncluded: false,
|
|
510
|
+
overrides,
|
|
511
|
+
unsafeOverrides: []
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function getApplicationRuntimePreset(profile) {
|
|
516
|
+
if (!isApplicationRuntimeProfile(profile)) throw new RuntimeProfileValidationError([invalidProfileIssue()]);
|
|
517
|
+
return deepFreeze(cloneDefaults(profile));
|
|
518
|
+
}
|
|
519
|
+
//#endregion
|
|
79
520
|
//#region src/merge.ts
|
|
80
521
|
globalThis.__smrtRuntimeConfig ??= {};
|
|
81
522
|
var UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -83,6 +524,14 @@ var UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
|
83
524
|
"constructor",
|
|
84
525
|
"prototype"
|
|
85
526
|
]);
|
|
527
|
+
function defineOwn(target, key, value) {
|
|
528
|
+
Object.defineProperty(target, key, {
|
|
529
|
+
configurable: true,
|
|
530
|
+
enumerable: true,
|
|
531
|
+
value,
|
|
532
|
+
writable: true
|
|
533
|
+
});
|
|
534
|
+
}
|
|
86
535
|
function isPlainObject(value) {
|
|
87
536
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
88
537
|
const proto = Object.getPrototypeOf(value);
|
|
@@ -94,7 +543,7 @@ function deepClone(value) {
|
|
|
94
543
|
const out = {};
|
|
95
544
|
for (const key of Object.keys(value)) {
|
|
96
545
|
if (UNSAFE_KEYS.has(key)) continue;
|
|
97
|
-
out
|
|
546
|
+
defineOwn(out, key, deepClone(value[key]));
|
|
98
547
|
}
|
|
99
548
|
return out;
|
|
100
549
|
}
|
|
@@ -105,21 +554,34 @@ function deepMerge(target, source) {
|
|
|
105
554
|
const tgt = target;
|
|
106
555
|
const src = source;
|
|
107
556
|
for (const key of Object.keys(tgt)) {
|
|
108
|
-
if (UNSAFE_KEYS.has(key) || key
|
|
109
|
-
result
|
|
557
|
+
if (UNSAFE_KEYS.has(key) || Object.hasOwn(src, key)) continue;
|
|
558
|
+
defineOwn(result, key, deepClone(tgt[key]));
|
|
110
559
|
}
|
|
111
560
|
for (const key of Object.keys(src)) {
|
|
112
561
|
if (UNSAFE_KEYS.has(key)) continue;
|
|
113
562
|
const sourceValue = src[key];
|
|
114
|
-
const targetValue = tgt[key];
|
|
115
|
-
if (isPlainObject(sourceValue) && isPlainObject(targetValue)) result
|
|
116
|
-
else if (sourceValue !== void 0 && sourceValue !== null) result
|
|
117
|
-
else if (targetValue !== void 0) result
|
|
563
|
+
const targetValue = Object.hasOwn(tgt, key) ? tgt[key] : void 0;
|
|
564
|
+
if (isPlainObject(sourceValue) && isPlainObject(targetValue)) defineOwn(result, key, deepMerge(targetValue, sourceValue));
|
|
565
|
+
else if (sourceValue !== void 0 && sourceValue !== null) defineOwn(result, key, deepClone(sourceValue));
|
|
566
|
+
else if (targetValue !== void 0) defineOwn(result, key, deepClone(targetValue));
|
|
118
567
|
}
|
|
119
568
|
return result;
|
|
120
569
|
}
|
|
121
570
|
function setConfig$1(config) {
|
|
122
|
-
|
|
571
|
+
const incomingRuntime = Object.hasOwn(config, "runtime") ? config.runtime : void 0;
|
|
572
|
+
if (incomingRuntime !== null && (typeof incomingRuntime === "object" || typeof incomingRuntime === "function") && Object.hasOwn(incomingRuntime, "profile")) {
|
|
573
|
+
const profileIssues = validateApplicationRuntimeConfigShape(incomingRuntime).filter((issue) => issue.path === "runtime" || issue.path === "profile");
|
|
574
|
+
if (profileIssues.length > 0) throw new RuntimeProfileValidationError([...profileIssues]);
|
|
575
|
+
}
|
|
576
|
+
let current = globalThis.__smrtRuntimeConfig || {};
|
|
577
|
+
const currentRuntime = Object.hasOwn(current, "runtime") && isPlainObject(current.runtime) ? current.runtime : void 0;
|
|
578
|
+
const incomingRuntimeMap = Object.hasOwn(config, "runtime") && isPlainObject(config.runtime) ? config.runtime : void 0;
|
|
579
|
+
if (currentRuntime !== void 0 && incomingRuntimeMap !== void 0 && Object.hasOwn(currentRuntime, "profile") && Object.hasOwn(incomingRuntimeMap, "profile") && currentRuntime.profile !== incomingRuntimeMap.profile) {
|
|
580
|
+
current = deepClone(current);
|
|
581
|
+
const resetRuntime = current.runtime;
|
|
582
|
+
delete resetRuntime.providers;
|
|
583
|
+
}
|
|
584
|
+
globalThis.__smrtRuntimeConfig = deepMerge(current, config);
|
|
123
585
|
}
|
|
124
586
|
function getRuntimeConfig() {
|
|
125
587
|
return globalThis.__smrtRuntimeConfig || {};
|
|
@@ -274,6 +736,23 @@ async function loadConfig(options) {
|
|
|
274
736
|
function getConfig() {
|
|
275
737
|
return getLoadedConfig();
|
|
276
738
|
}
|
|
739
|
+
function resolveConfiguredApplicationRuntime() {
|
|
740
|
+
const loadedConfig = getLoadedConfig();
|
|
741
|
+
const runtimeConfig = getRuntimeConfig();
|
|
742
|
+
const fileRuntime = loadedConfig && Object.hasOwn(loadedConfig, "runtime") ? loadedConfig.runtime : void 0;
|
|
743
|
+
const runtimeOverride = Object.hasOwn(runtimeConfig, "runtime") ? runtimeConfig.runtime : void 0;
|
|
744
|
+
for (const layer of [fileRuntime, runtimeOverride]) {
|
|
745
|
+
if (layer === void 0) continue;
|
|
746
|
+
const shapeIssues = validateApplicationRuntimeConfigShape(layer);
|
|
747
|
+
if (shapeIssues.length > 0) throw new RuntimeProfileValidationError([...shapeIssues]);
|
|
748
|
+
}
|
|
749
|
+
const fileHasProfile = fileRuntime !== void 0 && Object.hasOwn(fileRuntime, "profile");
|
|
750
|
+
const profileChanged = runtimeOverride !== void 0 && Object.hasOwn(runtimeOverride, "profile") && runtimeOverride.profile !== (fileHasProfile ? fileRuntime.profile : void 0);
|
|
751
|
+
if (profileChanged && fileHasProfile) resolveApplicationRuntime(fileRuntime);
|
|
752
|
+
const fileRuntimeWithoutProviders = { ...fileRuntime ?? {} };
|
|
753
|
+
delete fileRuntimeWithoutProviders.providers;
|
|
754
|
+
return resolveApplicationRuntime(mergeConfigs({}, profileChanged ? fileRuntimeWithoutProviders : fileRuntime ?? {}, runtimeOverride ?? {}));
|
|
755
|
+
}
|
|
277
756
|
function getSiteConfig() {
|
|
278
757
|
return (getLoadedConfig() || {}).site || null;
|
|
279
758
|
}
|
|
@@ -305,6 +784,6 @@ function defineConfig(config) {
|
|
|
305
784
|
return config;
|
|
306
785
|
}
|
|
307
786
|
//#endregion
|
|
308
|
-
export { clearCache, clearRuntimeConfig, defineConfig, exportConfig, getConfig, getModuleConfig, getPackageConfig, getRuntimeConfig, getSiteConfig, loadConfig, mergeConfigs, mergeExportedConfig, parseExportedConfig, sanitizeConfig, setConfig };
|
|
787
|
+
export { RuntimeProfileValidationError, clearCache, clearRuntimeConfig, defineConfig, exportConfig, getApplicationRuntimePreset, getConfig, getModuleConfig, getPackageConfig, getRuntimeConfig, getSiteConfig, loadConfig, mergeConfigs, mergeExportedConfig, parseExportedConfig, resolveApplicationRuntime, resolveConfiguredApplicationRuntime, sanitizeConfig, setConfig };
|
|
309
788
|
|
|
310
789
|
//# sourceMappingURL=index.js.map
|