@lorion-org/runtime-config 1.0.0-beta.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,309 @@
1
+ # @lorion-org/runtime-config
2
+
3
+ Pure runtime-config contracts and helpers.
4
+
5
+ This package is free from file-system and framework dependencies.
6
+
7
+ It models small runtime-config fragments, projects them into runtime objects, and
8
+ creates deterministic environment variable names for adapter layers.
9
+
10
+ ## Install
11
+
12
+ ```shell
13
+ pnpm add @lorion-org/runtime-config
14
+ ```
15
+
16
+ ## What it is
17
+
18
+ - typed contracts for runtime-config fragments
19
+ - deterministic scope/key normalization
20
+ - projection helpers for flat sectioned runtime config
21
+ - projection helpers for namespaced runtime config objects
22
+ - configurable context input keys for adapter-specific fragment shapes
23
+ - context-aware lookup helpers
24
+ - scope-view helpers for reading flat runtime config through unprefixed keys
25
+ - environment variable rendering helpers
26
+
27
+ ## What it is not
28
+
29
+ - not a framework module
30
+ - not a file-system loader
31
+ - not a schema validator
32
+ - not a config-file parser
33
+ - not an application-specific naming policy
34
+
35
+ ## Adapter integration
36
+
37
+ Framework adapters can wire this package into their runtime config transport.
38
+ For Nuxt, use `@lorion-org/nuxt`.
39
+
40
+ The intended adapter shape is:
41
+
42
+ - projects define local fragments with unprefixed keys
43
+ - adapters map those fragments into the target runtime transport
44
+ - usage code can read back unprefixed public/private scope views
45
+ - application-specific names, file names, and defaults stay in the consuming adapter
46
+
47
+ Adapters may accept existing fragment field names and map them to generic
48
+ contexts with `contextInputKey`. For example, a project can read `tenants`
49
+ from its files while this package still works with the generic `contexts`
50
+ model internally.
51
+
52
+ ## The three runtime-config shapes
53
+
54
+ This package separates the local config shape from the runtime transport shape.
55
+
56
+ ### 1. Fragment shape
57
+
58
+ Fragments are written in local scope vocabulary. The scope id is not repeated in
59
+ the keys.
60
+
61
+ ```ts
62
+ const authFragment = {
63
+ public: {
64
+ url: 'https://auth.example.test',
65
+ realm: 'main',
66
+ },
67
+ private: {
68
+ clientSecret: 'secret',
69
+ },
70
+ };
71
+ ```
72
+
73
+ This is the shape that JSON files and schemas usually describe.
74
+
75
+ ### 2. Flat runtime shape
76
+
77
+ Some runtimes need one shared `public` and `private` object. The scope id becomes
78
+ a transport prefix so many fragments can coexist without key collisions.
79
+
80
+ ```ts
81
+ const runtimeConfig = projectSectionedRuntimeConfig(new Map([['auth', authFragment]]));
82
+
83
+ // For a single fragment, use:
84
+ projectRuntimeConfigFragment('auth', authFragment);
85
+
86
+ runtimeConfig.public.authUrl;
87
+ // => 'https://auth.example.test'
88
+ runtimeConfig.private.authClientSecret;
89
+ // => 'secret'
90
+ ```
91
+
92
+ ### 3. Environment variable shape
93
+
94
+ Environment variables keep the same transport prefix and add visibility.
95
+
96
+ ```ts
97
+ toRuntimeEnvVars(runtimeConfig, 'APP');
98
+ // => {
99
+ // APP_PUBLIC_AUTH_URL: 'https://auth.example.test',
100
+ // APP_PUBLIC_AUTH_REALM: 'main',
101
+ // APP_PRIVATE_AUTH_CLIENT_SECRET: 'secret'
102
+ // }
103
+ ```
104
+
105
+ Usage code can read the flat runtime shape back through local keys:
106
+
107
+ ```ts
108
+ const auth = getPublicRuntimeConfigScope(runtimeConfig, 'auth');
109
+
110
+ auth.url;
111
+ // => 'https://auth.example.test'
112
+ ```
113
+
114
+ ## Basic example
115
+
116
+ ```ts
117
+ import {
118
+ getPublicRuntimeConfigScope,
119
+ projectSectionedRuntimeConfig,
120
+ resolveRuntimeConfigValue,
121
+ } from '@lorion-org/runtime-config';
122
+
123
+ const fragments = new Map([
124
+ [
125
+ 'billing',
126
+ {
127
+ public: {
128
+ apiBase: '/api/billing',
129
+ },
130
+ private: {
131
+ apiSecret: 'secret',
132
+ },
133
+ contexts: {
134
+ tenantA: {
135
+ public: {
136
+ apiBase: '/tenant-a/billing',
137
+ },
138
+ },
139
+ },
140
+ },
141
+ ],
142
+ ]);
143
+
144
+ const runtimeConfig = projectSectionedRuntimeConfig(fragments);
145
+
146
+ runtimeConfig.public.billingApiBase;
147
+ // => '/api/billing'
148
+
149
+ resolveRuntimeConfigValue(runtimeConfig.public, 'billing', 'apiBase', {
150
+ contextId: 'tenantA',
151
+ });
152
+ // => '/tenant-a/billing'
153
+
154
+ getPublicRuntimeConfigScope(runtimeConfig, 'billing');
155
+ // => { apiBase: '/api/billing' }
156
+ ```
157
+
158
+ ## Example: custom context input key
159
+
160
+ ```ts
161
+ import { projectSectionedRuntimeConfig } from '@lorion-org/runtime-config';
162
+
163
+ projectSectionedRuntimeConfig(
164
+ [
165
+ {
166
+ scopeId: 'billing',
167
+ config: {
168
+ public: {
169
+ apiBase: '/api/billing',
170
+ },
171
+ tenants: {
172
+ tenantA: {
173
+ public: {
174
+ apiBase: '/tenant-a/billing',
175
+ },
176
+ },
177
+ },
178
+ },
179
+ },
180
+ ],
181
+ {
182
+ contextInputKey: 'tenants',
183
+ contextOutputKey: '__tenants',
184
+ },
185
+ );
186
+ // => {
187
+ // public: {
188
+ // billingApiBase: '/api/billing',
189
+ // __tenants: {
190
+ // tenantA: {
191
+ // billingApiBase: '/tenant-a/billing'
192
+ // }
193
+ // }
194
+ // },
195
+ // private: {}
196
+ // }
197
+ ```
198
+
199
+ ## Example: namespaced projection
200
+
201
+ Use `projectRuntimeConfigNamespace()` when one local fragment becomes one
202
+ runtime namespace. Use `projectRuntimeConfigNamespaces()` when combining many
203
+ fragments; in that case each item needs a `scopeId` so the output namespace is
204
+ explicit.
205
+
206
+ ```ts
207
+ import {
208
+ projectRuntimeConfigNamespace,
209
+ projectRuntimeConfigNamespaces,
210
+ } from '@lorion-org/runtime-config';
211
+
212
+ const runtimeConfig = projectRuntimeConfigNamespace('mail', {
213
+ public: {
214
+ apiBase: '/api/mail',
215
+ },
216
+ private: {
217
+ token: 'mail-token',
218
+ },
219
+ });
220
+
221
+ runtimeConfig.public.mail;
222
+ // => { apiBase: '/api/mail' }
223
+ runtimeConfig.mail;
224
+ // => { token: 'mail-token' }
225
+
226
+ const combinedRuntimeConfig = projectRuntimeConfigNamespaces([
227
+ {
228
+ scopeId: 'mail',
229
+ config: {
230
+ public: {
231
+ apiBase: '/api/mail',
232
+ },
233
+ private: {
234
+ token: 'mail-token',
235
+ },
236
+ },
237
+ },
238
+ ]);
239
+
240
+ combinedRuntimeConfig.public.mail;
241
+ // => { apiBase: '/api/mail' }
242
+ combinedRuntimeConfig.mail;
243
+ // => { token: 'mail-token' }
244
+ ```
245
+
246
+ ## Example: environment variables
247
+
248
+ Adapters choose their own prefix. The default prefix is deliberately generic.
249
+
250
+ ```ts
251
+ import {
252
+ projectRuntimeConfigEnvVars,
253
+ runtimeEnvVarsToShellAssignments,
254
+ runtimeEnvVarsToString,
255
+ toRuntimeEnvVars,
256
+ } from '@lorion-org/runtime-config';
257
+
258
+ const envVars = toRuntimeEnvVars(
259
+ {
260
+ public: {
261
+ billingApiBase: '/api/billing',
262
+ },
263
+ private: {
264
+ billingApiSecret: 'secret',
265
+ },
266
+ },
267
+ 'APP',
268
+ );
269
+
270
+ runtimeEnvVarsToString(envVars);
271
+ // => APP_PUBLIC_BILLING_API_BASE=/api/billing
272
+ // => APP_PRIVATE_BILLING_API_SECRET=secret
273
+
274
+ runtimeEnvVarsToShellAssignments(envVars);
275
+ // => APP_PUBLIC_BILLING_API_BASE='"/api/billing"'
276
+ // => APP_PRIVATE_BILLING_API_SECRET='"secret"'
277
+
278
+ projectRuntimeConfigEnvVars(
279
+ new Map([
280
+ [
281
+ 'billing',
282
+ {
283
+ public: {
284
+ apiBase: '/api/billing',
285
+ },
286
+ },
287
+ ],
288
+ ]),
289
+ {
290
+ prefix: 'APP',
291
+ },
292
+ );
293
+ // => {
294
+ // APP_PUBLIC_BILLING_API_BASE: '/api/billing'
295
+ // }
296
+ ```
297
+
298
+ Runnable example files live in [`examples/`](./examples).
299
+
300
+ ## Local commands
301
+
302
+ ```shell
303
+ cd packages/runtime-config
304
+ pnpm build
305
+ pnpm test
306
+ pnpm coverage
307
+ pnpm typecheck
308
+ pnpm package:check
309
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,368 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createRuntimeConfigEnvKey: () => createRuntimeConfigEnvKey,
24
+ createRuntimeConfigKey: () => createRuntimeConfigKey,
25
+ getPrivateRuntimeConfigScope: () => getPrivateRuntimeConfigScope,
26
+ getPublicRuntimeConfigScope: () => getPublicRuntimeConfigScope,
27
+ getRuntimeConfigFragment: () => getRuntimeConfigFragment,
28
+ getRuntimeConfigScope: () => getRuntimeConfigScope,
29
+ injectRuntimeEnvVars: () => injectRuntimeEnvVars,
30
+ normalizeRuntimeConfigFragments: () => normalizeRuntimeConfigFragments,
31
+ projectRuntimeConfigEnvVars: () => projectRuntimeConfigEnvVars,
32
+ projectRuntimeConfigFragment: () => projectRuntimeConfigFragment,
33
+ projectRuntimeConfigNamespace: () => projectRuntimeConfigNamespace,
34
+ projectRuntimeConfigNamespaces: () => projectRuntimeConfigNamespaces,
35
+ projectSectionedRuntimeConfig: () => projectSectionedRuntimeConfig,
36
+ resolveRuntimeConfigValue: () => resolveRuntimeConfigValue,
37
+ resolveRuntimeConfigValueFromRuntimeConfig: () => resolveRuntimeConfigValueFromRuntimeConfig,
38
+ runtimeConfigVisibilities: () => runtimeConfigVisibilities,
39
+ runtimeEnvValueToShellLiteral: () => runtimeEnvValueToShellLiteral,
40
+ runtimeEnvVarsToShellAssignments: () => runtimeEnvVarsToShellAssignments,
41
+ runtimeEnvVarsToString: () => runtimeEnvVarsToString,
42
+ stripRuntimeConfigScopePrefix: () => stripRuntimeConfigScopePrefix,
43
+ toRuntimeConfigFragment: () => toRuntimeConfigFragment,
44
+ toRuntimeEnvVars: () => toRuntimeEnvVars,
45
+ toSnakeUpperCase: () => toSnakeUpperCase
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+
49
+ // src/key.ts
50
+ function upperFirst(input) {
51
+ return input ? input[0].toUpperCase() + input.slice(1) : input;
52
+ }
53
+ function uncapitalize(input) {
54
+ return input ? input[0].toLowerCase() + input.slice(1) : input;
55
+ }
56
+ function camelCase(input) {
57
+ return input.replace(/['\u2019]/g, "").split(/[^A-Za-z0-9]+|(?=[A-Z][a-z])/).map((part) => part.trim()).filter(Boolean).map((part) => part.toLowerCase()).map((part, index) => index === 0 ? part : upperFirst(part)).join("");
58
+ }
59
+ function createRuntimeConfigKey(scopeId, key, options = {}) {
60
+ return options.keyStrategy?.(scopeId, key) ?? camelCase(`${scopeId} ${key}`);
61
+ }
62
+ function stripRuntimeConfigScopePrefix(scopeId, configKey, options = {}) {
63
+ const prefix = createRuntimeConfigKey(scopeId, "", options);
64
+ if (!prefix || !configKey.startsWith(prefix) || configKey.length <= prefix.length) {
65
+ return void 0;
66
+ }
67
+ return uncapitalize(configKey.slice(prefix.length));
68
+ }
69
+ function toSnakeUpperCase(input) {
70
+ return input.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toUpperCase();
71
+ }
72
+
73
+ // src/fragment.ts
74
+ var isObject = (value) => {
75
+ return typeof value === "object" && value !== null && !Array.isArray(value);
76
+ };
77
+ function toRuntimeConfigFragment(config, options = {}) {
78
+ const contextInputKey = options.contextInputKey ?? "contexts";
79
+ const contexts = contextInputKey === "contexts" ? config.contexts : config.contexts ?? config[contextInputKey];
80
+ return {
81
+ ...isObject(config.public) ? { public: config.public } : {},
82
+ ...isObject(config.private) ? { private: config.private } : {},
83
+ ...isObject(contexts) ? { contexts } : {}
84
+ };
85
+ }
86
+
87
+ // src/types.ts
88
+ var runtimeConfigVisibilities = ["public", "private"];
89
+
90
+ // src/project.ts
91
+ function normalizeRuntimeConfigFragments(fragments, options = {}) {
92
+ const entries = fragments instanceof Map ? Array.from(fragments.entries()).map(([scopeId, config]) => ({ scopeId, config })) : Array.from(fragments);
93
+ return entries.map((fragment) => ({
94
+ scopeId: fragment.scopeId.trim(),
95
+ config: toRuntimeConfigFragment(fragment.config, options)
96
+ })).filter((fragment) => fragment.scopeId.length > 0).sort((left, right) => left.scopeId.localeCompare(right.scopeId));
97
+ }
98
+ function filterFragments(input) {
99
+ const scopeIdSet = input.scopeIds ? new Set(input.scopeIds.map((id) => id.trim()).filter(Boolean)) : void 0;
100
+ return normalizeRuntimeConfigFragments(input.fragments, {
101
+ ...input.contextInputKey ? { contextInputKey: input.contextInputKey } : {}
102
+ }).filter((fragment) => !scopeIdSet || scopeIdSet.has(fragment.scopeId));
103
+ }
104
+ function getSection(config, visibility) {
105
+ return config?.[visibility];
106
+ }
107
+ function assignDefined(target, key, value) {
108
+ if (value !== void 0) {
109
+ target[key] = value;
110
+ }
111
+ }
112
+ function projectSectionedRuntimeConfig(fragments, options = {}) {
113
+ const result = {
114
+ public: {},
115
+ private: {}
116
+ };
117
+ const contextOutputKey = options.contextOutputKey ?? "__contexts";
118
+ const filteredFragments = filterFragments({
119
+ fragments,
120
+ ...options.contextInputKey ? { contextInputKey: options.contextInputKey } : {},
121
+ ...options.scopeIds ? { scopeIds: options.scopeIds } : {}
122
+ });
123
+ for (const fragment of filteredFragments) {
124
+ for (const visibility of runtimeConfigVisibilities) {
125
+ const section = getSection(fragment.config, visibility);
126
+ if (!section) continue;
127
+ for (const [key, value] of Object.entries(section)) {
128
+ assignDefined(
129
+ result[visibility],
130
+ createRuntimeConfigKey(fragment.scopeId, key, options),
131
+ value
132
+ );
133
+ }
134
+ }
135
+ if (options.includeContexts === false) continue;
136
+ for (const [contextId, context] of Object.entries(fragment.config.contexts ?? {})) {
137
+ for (const visibility of runtimeConfigVisibilities) {
138
+ const section = getSection(context, visibility);
139
+ if (!section) continue;
140
+ const contexts = result[visibility][contextOutputKey] ?? {};
141
+ const contextValues = contexts[contextId] ?? {};
142
+ for (const [key, value] of Object.entries(section)) {
143
+ assignDefined(
144
+ contextValues,
145
+ createRuntimeConfigKey(fragment.scopeId, key, options),
146
+ value
147
+ );
148
+ }
149
+ contexts[contextId] = contextValues;
150
+ result[visibility][contextOutputKey] = contexts;
151
+ }
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ function projectRuntimeConfigFragment(scopeId, config, options = {}) {
157
+ return projectSectionedRuntimeConfig(/* @__PURE__ */ new Map([[scopeId, config]]), options);
158
+ }
159
+ function projectRuntimeConfigNamespace(scopeId, config, options = {}) {
160
+ return projectRuntimeConfigNamespaces([{ scopeId, config }], options);
161
+ }
162
+ function projectRuntimeConfigNamespaces(fragments, options = {}) {
163
+ const result = {
164
+ public: {}
165
+ };
166
+ const namespaceStrategy = options.namespaceStrategy ?? "nested";
167
+ const filteredFragments = filterFragments({
168
+ fragments,
169
+ ...options.contextInputKey ? { contextInputKey: options.contextInputKey } : {},
170
+ ...options.scopeIds ? { scopeIds: options.scopeIds } : {}
171
+ });
172
+ for (const fragment of filteredFragments) {
173
+ const context = options.contextId ? fragment.config.contexts?.[options.contextId] : void 0;
174
+ const publicSection = {
175
+ ...fragment.config.public ?? {},
176
+ ...context?.public ?? {}
177
+ };
178
+ const privateSection = {
179
+ ...fragment.config.private ?? {},
180
+ ...context?.private ?? {}
181
+ };
182
+ if (namespaceStrategy === "flat") {
183
+ Object.assign(result.public, publicSection);
184
+ Object.assign(result, privateSection);
185
+ continue;
186
+ }
187
+ if (Object.keys(publicSection).length) {
188
+ result.public[fragment.scopeId] = {
189
+ ...result.public[fragment.scopeId] ?? {},
190
+ ...publicSection
191
+ };
192
+ }
193
+ if (Object.keys(privateSection).length) {
194
+ result[fragment.scopeId] = {
195
+ ...result[fragment.scopeId] ?? {},
196
+ ...privateSection
197
+ };
198
+ }
199
+ }
200
+ return result;
201
+ }
202
+
203
+ // src/env.ts
204
+ function createRuntimeConfigEnvKey(input) {
205
+ return toSnakeUpperCase(
206
+ [input.prefix ?? "APP", input.visibility, input.scopeId, input.key].filter(Boolean).join("_")
207
+ );
208
+ }
209
+ function toRuntimeEnvVars(runtimeConfig, prefix = "APP") {
210
+ const envVars = {};
211
+ for (const visibility of runtimeConfigVisibilities) {
212
+ for (const [key, value] of Object.entries(runtimeConfig[visibility])) {
213
+ if (key.startsWith("__")) continue;
214
+ envVars[createRuntimeConfigEnvKey({ prefix, visibility, key })] = value;
215
+ }
216
+ }
217
+ return envVars;
218
+ }
219
+ function projectRuntimeConfigEnvVars(fragments, options = {}) {
220
+ const { prefix = "APP", ...projectOptions } = options;
221
+ return toRuntimeEnvVars(
222
+ projectSectionedRuntimeConfig(fragments, {
223
+ ...projectOptions,
224
+ includeContexts: false
225
+ }),
226
+ prefix
227
+ );
228
+ }
229
+ function injectRuntimeEnvVars(envVars, processEnv) {
230
+ const items = {};
231
+ for (const key of Object.keys(envVars)) {
232
+ items[key] = processEnv[key] ?? envVars[key];
233
+ }
234
+ return items;
235
+ }
236
+ function runtimeEnvVarsToString(envVars) {
237
+ return Object.entries(envVars).map(([key, value]) => `${key}=${String(value)}`).join("\n");
238
+ }
239
+ function runtimeEnvValueToShellLiteral(value) {
240
+ const json = JSON.stringify(value) ?? "undefined";
241
+ return `'${json.replace(/'/g, "'\\''")}'`;
242
+ }
243
+ function runtimeEnvVarsToShellAssignments(envVars) {
244
+ return Object.entries(envVars).map(([key, value]) => `${key}=${runtimeEnvValueToShellLiteral(value)}`).join("\n");
245
+ }
246
+
247
+ // src/resolve.ts
248
+ function resolveRuntimeConfigValue(scopeConfig, scopeId, key, options = {}) {
249
+ const configKey = createRuntimeConfigKey(scopeId, key, options);
250
+ const contextOutputKey = options.contextOutputKey ?? "__contexts";
251
+ if (options.contextId) {
252
+ const contexts = scopeConfig?.[contextOutputKey];
253
+ const contextValue = contexts?.[options.contextId]?.[configKey];
254
+ if (contextValue !== void 0) {
255
+ return contextValue;
256
+ }
257
+ }
258
+ const globalValue = scopeConfig?.[configKey];
259
+ if (globalValue !== void 0) {
260
+ return globalValue;
261
+ }
262
+ return options.defaultValue;
263
+ }
264
+ function resolveRuntimeConfigValueFromRuntimeConfig(runtimeConfig, scopeId, key, options = {}) {
265
+ const { visibility = "public", ...resolveOptions } = options;
266
+ return resolveRuntimeConfigValue(runtimeConfig[visibility], scopeId, key, resolveOptions);
267
+ }
268
+
269
+ // src/scope.ts
270
+ function assignDefined2(target, key, value) {
271
+ if (value !== void 0) {
272
+ target[key] = value;
273
+ }
274
+ }
275
+ function collectRuntimeConfigScopeValues(input) {
276
+ const values = {};
277
+ for (const [configKey, value] of Object.entries(input.scopeConfig ?? {})) {
278
+ if (configKey.startsWith("__")) continue;
279
+ const key = stripRuntimeConfigScopePrefix(input.scopeId, configKey, input.options);
280
+ if (key) assignDefined2(values, key, value);
281
+ }
282
+ return values;
283
+ }
284
+ function getRuntimeConfigScope(runtimeConfig, scopeId, options = {}) {
285
+ const {
286
+ contextId,
287
+ contextOutputKey = "__contexts",
288
+ keys,
289
+ visibility = "public",
290
+ ...keyOptions
291
+ } = options;
292
+ const scopeConfig = runtimeConfig[visibility];
293
+ if (keys) {
294
+ return Object.fromEntries(
295
+ keys.map((key) => {
296
+ const value = resolveRuntimeConfigValue(scopeConfig, scopeId, key, {
297
+ ...keyOptions,
298
+ ...contextId ? { contextId } : {},
299
+ contextOutputKey
300
+ });
301
+ return [key, value];
302
+ }).filter(([, value]) => value !== void 0)
303
+ );
304
+ }
305
+ const values = collectRuntimeConfigScopeValues({
306
+ scopeConfig,
307
+ scopeId,
308
+ options: keyOptions
309
+ });
310
+ if (!contextId) return values;
311
+ const contexts = scopeConfig?.[contextOutputKey];
312
+ const contextValues = collectRuntimeConfigScopeValues({
313
+ scopeConfig: contexts?.[contextId],
314
+ scopeId,
315
+ options: keyOptions
316
+ });
317
+ return {
318
+ ...values,
319
+ ...contextValues
320
+ };
321
+ }
322
+ function getPublicRuntimeConfigScope(runtimeConfig, scopeId, options = {}) {
323
+ return getRuntimeConfigScope(runtimeConfig, scopeId, {
324
+ ...options,
325
+ visibility: "public"
326
+ });
327
+ }
328
+ function getPrivateRuntimeConfigScope(runtimeConfig, scopeId, options = {}) {
329
+ return getRuntimeConfigScope(runtimeConfig, scopeId, {
330
+ ...options,
331
+ visibility: "private"
332
+ });
333
+ }
334
+ function getRuntimeConfigFragment(runtimeConfig, scopeId, options = {}) {
335
+ const { keys, ...scopeOptions } = options;
336
+ const publicOptions = keys?.public ? { ...scopeOptions, keys: keys.public } : scopeOptions;
337
+ const privateOptions = keys?.private ? { ...scopeOptions, keys: keys.private } : scopeOptions;
338
+ return {
339
+ public: getPublicRuntimeConfigScope(runtimeConfig, scopeId, publicOptions),
340
+ private: getPrivateRuntimeConfigScope(runtimeConfig, scopeId, privateOptions)
341
+ };
342
+ }
343
+ // Annotate the CommonJS export names for ESM import in node:
344
+ 0 && (module.exports = {
345
+ createRuntimeConfigEnvKey,
346
+ createRuntimeConfigKey,
347
+ getPrivateRuntimeConfigScope,
348
+ getPublicRuntimeConfigScope,
349
+ getRuntimeConfigFragment,
350
+ getRuntimeConfigScope,
351
+ injectRuntimeEnvVars,
352
+ normalizeRuntimeConfigFragments,
353
+ projectRuntimeConfigEnvVars,
354
+ projectRuntimeConfigFragment,
355
+ projectRuntimeConfigNamespace,
356
+ projectRuntimeConfigNamespaces,
357
+ projectSectionedRuntimeConfig,
358
+ resolveRuntimeConfigValue,
359
+ resolveRuntimeConfigValueFromRuntimeConfig,
360
+ runtimeConfigVisibilities,
361
+ runtimeEnvValueToShellLiteral,
362
+ runtimeEnvVarsToShellAssignments,
363
+ runtimeEnvVarsToString,
364
+ stripRuntimeConfigScopePrefix,
365
+ toRuntimeConfigFragment,
366
+ toRuntimeEnvVars,
367
+ toSnakeUpperCase
368
+ });