@zintrust/core 0.4.39 → 0.4.41
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/package.json +2 -2
- package/src/cli/cloudflare/CloudflareEnvTargetConfig.d.ts +37 -0
- package/src/cli/cloudflare/CloudflareEnvTargetConfig.d.ts.map +1 -0
- package/src/cli/cloudflare/CloudflareEnvTargetConfig.js +104 -0
- package/src/cli/cloudflare/CloudflareSecretSync.d.ts +34 -0
- package/src/cli/cloudflare/CloudflareSecretSync.d.ts.map +1 -0
- package/src/cli/cloudflare/CloudflareSecretSync.js +147 -0
- package/src/cli/commands/DeployCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployCommand.js +27 -3
- package/src/cli/commands/DeployContainersProxyCommand.d.ts.map +1 -1
- package/src/cli/commands/DeployContainersProxyCommand.js +27 -3
- package/src/cli/commands/ProxyScaffoldUtils.d.ts.map +1 -1
- package/src/cli/commands/ProxyScaffoldUtils.js +2 -3
- package/src/cli/commands/PutCommand.d.ts.map +1 -1
- package/src/cli/commands/PutCommand.js +14 -117
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +68 -25
- package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.js +24 -0
- package/src/cli/scaffolding/ServiceScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +32 -2
- package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
- package/src/cli/utils/EnvFileLoader.js +21 -4
- package/src/config/env.d.ts +16 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +126 -2
- package/src/index.js +3 -3
- package/src/runtime/RuntimeServices.d.ts.map +1 -1
- package/src/runtime/RuntimeServices.js +4 -34
package/src/config/env.js
CHANGED
|
@@ -5,16 +5,32 @@
|
|
|
5
5
|
* Sealed namespace pattern - all exports through Env namespace
|
|
6
6
|
* Safe for both Node.js and serverless runtimes (Cloudflare Workers, Deno, Lambda)
|
|
7
7
|
*/
|
|
8
|
+
import { isArray, isNonEmptyString, isObject } from '../helper/index.js';
|
|
8
9
|
// Cache process check once at module load time
|
|
9
10
|
const processLike = typeof process === 'undefined' ? undefined : process;
|
|
10
11
|
let externalEnvSource = null;
|
|
12
|
+
const DIRECT_ENV_SOURCE = 'direct-env';
|
|
13
|
+
const PACKED_ENV_ENABLE_KEY = 'USE_PACK';
|
|
14
|
+
const PACKED_ENV_KEYS_KEY = 'PACK_KEYS';
|
|
15
|
+
const PACKED_ENV_CONTROL_KEYS = new Set([PACKED_ENV_ENABLE_KEY, PACKED_ENV_KEYS_KEY]);
|
|
16
|
+
const createPackedEnvError = (message, details) => {
|
|
17
|
+
const error = Object.create(globalThis.Error.prototype);
|
|
18
|
+
error.name = 'ConfigError';
|
|
19
|
+
error.message = message;
|
|
20
|
+
error.code = 'CONFIG_ERROR';
|
|
21
|
+
error.statusCode = 500;
|
|
22
|
+
if (details !== undefined) {
|
|
23
|
+
error.details = details;
|
|
24
|
+
}
|
|
25
|
+
return error;
|
|
26
|
+
};
|
|
11
27
|
const getGlobalEnv = () => {
|
|
12
28
|
const env = globalThis.env;
|
|
13
29
|
if (env === undefined || env === null || typeof env !== 'object')
|
|
14
30
|
return undefined;
|
|
15
31
|
return env;
|
|
16
32
|
};
|
|
17
|
-
const
|
|
33
|
+
const getRawEnvSource = () => {
|
|
18
34
|
if (typeof externalEnvSource === 'function')
|
|
19
35
|
return externalEnvSource();
|
|
20
36
|
if (externalEnvSource !== null)
|
|
@@ -28,6 +44,14 @@ const getEnvSource = () => {
|
|
|
28
44
|
}
|
|
29
45
|
return processLike?.env ?? {};
|
|
30
46
|
};
|
|
47
|
+
const normalizePackedScalar = (packName, key, value) => {
|
|
48
|
+
if (typeof value === 'string')
|
|
49
|
+
return value;
|
|
50
|
+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
51
|
+
return String(value);
|
|
52
|
+
}
|
|
53
|
+
throw createPackedEnvError(`${packName} contains unsupported value for ${key}. Expected a flat string-compatible value.`);
|
|
54
|
+
};
|
|
31
55
|
const normalizeEnvValue = (value) => {
|
|
32
56
|
if (value === null || value === undefined)
|
|
33
57
|
return '';
|
|
@@ -38,6 +62,86 @@ const normalizeEnvValue = (value) => {
|
|
|
38
62
|
}
|
|
39
63
|
return '';
|
|
40
64
|
};
|
|
65
|
+
const isDirectEnvScalar = (value) => {
|
|
66
|
+
return (value === null ||
|
|
67
|
+
value === undefined ||
|
|
68
|
+
typeof value === 'string' ||
|
|
69
|
+
typeof value === 'number' ||
|
|
70
|
+
typeof value === 'boolean' ||
|
|
71
|
+
typeof value === 'bigint');
|
|
72
|
+
};
|
|
73
|
+
const parsePackedEnvKeys = (env) => {
|
|
74
|
+
const enabled = normalizeEnvValue(env[PACKED_ENV_ENABLE_KEY]).trim().toLowerCase() === 'true';
|
|
75
|
+
if (!enabled) {
|
|
76
|
+
return { enabled: false, packKeys: [] };
|
|
77
|
+
}
|
|
78
|
+
const raw = normalizeEnvValue(env[PACKED_ENV_KEYS_KEY]);
|
|
79
|
+
const packKeys = raw
|
|
80
|
+
.split(',')
|
|
81
|
+
.map((item) => item.trim())
|
|
82
|
+
.filter((item, index, items) => item !== '' && items.indexOf(item) === index);
|
|
83
|
+
if (packKeys.length === 0) {
|
|
84
|
+
throw createPackedEnvError('USE_PACK is true but PACK_KEYS is empty');
|
|
85
|
+
}
|
|
86
|
+
return { enabled: true, packKeys };
|
|
87
|
+
};
|
|
88
|
+
const parsePackedPayload = (packName, payload) => {
|
|
89
|
+
if (!isNonEmptyString(normalizeEnvValue(payload))) {
|
|
90
|
+
throw createPackedEnvError(`PACK_KEYS contains ${packName} but env.${packName} is missing`);
|
|
91
|
+
}
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(normalizeEnvValue(payload));
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw createPackedEnvError(`${packName} did not parse as a JSON object`, error);
|
|
98
|
+
}
|
|
99
|
+
if (!isObject(parsed) || isArray(parsed)) {
|
|
100
|
+
throw createPackedEnvError(`${packName} did not parse as a JSON object`);
|
|
101
|
+
}
|
|
102
|
+
return parsed;
|
|
103
|
+
};
|
|
104
|
+
const applyPackedPayload = (values, sources, packName, payload) => {
|
|
105
|
+
for (const [rawKey, rawValue] of Object.entries(payload)) {
|
|
106
|
+
const key = rawKey.trim();
|
|
107
|
+
if (!isNonEmptyString(key))
|
|
108
|
+
continue;
|
|
109
|
+
if (PACKED_ENV_CONTROL_KEYS.has(key))
|
|
110
|
+
continue;
|
|
111
|
+
if (isObject(rawValue) || isArray(rawValue) || rawValue === null || rawValue === undefined) {
|
|
112
|
+
throw createPackedEnvError(`${packName} contains unsupported value for ${key}. Nested or null values are not supported.`);
|
|
113
|
+
}
|
|
114
|
+
values[key] = normalizePackedScalar(packName, key, rawValue);
|
|
115
|
+
sources[key] = packName;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const overlayDirectEnvValues = (values, sources, env) => {
|
|
119
|
+
for (const [key, rawValue] of Object.entries(env)) {
|
|
120
|
+
if (!isDirectEnvScalar(rawValue))
|
|
121
|
+
continue;
|
|
122
|
+
values[key] = normalizeEnvValue(rawValue);
|
|
123
|
+
sources[key] = DIRECT_ENV_SOURCE;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const resolvePackedEnvState = (env) => {
|
|
127
|
+
const values = {};
|
|
128
|
+
const sources = {};
|
|
129
|
+
const { enabled, packKeys } = parsePackedEnvKeys(env);
|
|
130
|
+
if (enabled) {
|
|
131
|
+
for (const packName of packKeys) {
|
|
132
|
+
applyPackedPayload(values, sources, packName, parsePackedPayload(packName, env[packName]));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
overlayDirectEnvValues(values, sources, env);
|
|
136
|
+
return {
|
|
137
|
+
values,
|
|
138
|
+
sources,
|
|
139
|
+
packedEnabled: enabled,
|
|
140
|
+
packedKeys: packKeys,
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
const getResolvedEnvState = () => resolvePackedEnvState(getRawEnvSource());
|
|
144
|
+
const getEnvSource = () => getResolvedEnvState().values;
|
|
41
145
|
export const getProcessLike = () => processLike;
|
|
42
146
|
export const dirnameFromExecPath = (execPath, platform) => {
|
|
43
147
|
const separator = platform === 'win32' ? '\\' : '/';
|
|
@@ -46,11 +150,26 @@ export const dirnameFromExecPath = (execPath, platform) => {
|
|
|
46
150
|
return '';
|
|
47
151
|
return execPath.slice(0, lastSep);
|
|
48
152
|
};
|
|
153
|
+
export const getOptional = (key) => {
|
|
154
|
+
const env = getEnvSource();
|
|
155
|
+
return Object.prototype.hasOwnProperty.call(env, key) ? normalizeEnvValue(env[key]) : undefined;
|
|
156
|
+
};
|
|
157
|
+
export const has = (key) => {
|
|
158
|
+
const env = getEnvSource();
|
|
159
|
+
return Object.prototype.hasOwnProperty.call(env, key);
|
|
160
|
+
};
|
|
161
|
+
export const getSourceOf = (key) => {
|
|
162
|
+
return getResolvedEnvState().sources[key];
|
|
163
|
+
};
|
|
164
|
+
export const snapshotSources = () => {
|
|
165
|
+
return { ...getResolvedEnvState().sources };
|
|
166
|
+
};
|
|
167
|
+
export const getResolvedState = () => getResolvedEnvState();
|
|
49
168
|
// Private helper functions
|
|
50
169
|
export const get = (key, defaultValue) => {
|
|
51
170
|
const env = getEnvSource();
|
|
52
171
|
const value = normalizeEnvValue(env[key]);
|
|
53
|
-
return value === '' ? defaultValue ?? '' : value;
|
|
172
|
+
return value === '' ? (defaultValue ?? '') : value;
|
|
54
173
|
};
|
|
55
174
|
export const getInt = (key, defaultValue) => {
|
|
56
175
|
const value = get(key, String(defaultValue ?? 0));
|
|
@@ -107,13 +226,18 @@ const PROXY_SECRET_FALLBACK = get('APP_KEY', '');
|
|
|
107
226
|
export const Env = Object.freeze({
|
|
108
227
|
// Helper functions
|
|
109
228
|
get,
|
|
229
|
+
getOptional,
|
|
110
230
|
getInt,
|
|
111
231
|
getBool,
|
|
112
232
|
getFloat,
|
|
233
|
+
has,
|
|
113
234
|
set,
|
|
114
235
|
unset,
|
|
115
236
|
setSource,
|
|
116
237
|
snapshot,
|
|
238
|
+
getSourceOf,
|
|
239
|
+
snapshotSources,
|
|
240
|
+
getResolvedState,
|
|
117
241
|
// Core
|
|
118
242
|
NODE_ENV: get('NODE_ENV', 'development'),
|
|
119
243
|
// Prefer PORT, fallback to APP_PORT for compatibility
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v0.4.
|
|
2
|
+
* @zintrust/core v0.4.41
|
|
3
3
|
*
|
|
4
4
|
* ZinTrust Framework - Production-Grade TypeScript Backend
|
|
5
5
|
* Built for performance, type safety, and exceptional developer experience
|
|
6
6
|
*
|
|
7
7
|
* Build Information:
|
|
8
|
-
* Built: 2026-03-
|
|
8
|
+
* Built: 2026-03-31T14:32:01.889Z
|
|
9
9
|
* Node: >=20.0.0
|
|
10
10
|
* License: MIT
|
|
11
11
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* Available at runtime for debugging and health checks
|
|
22
22
|
*/
|
|
23
23
|
export const ZINTRUST_VERSION = '0.1.41';
|
|
24
|
-
export const ZINTRUST_BUILD_DATE = '2026-03-
|
|
24
|
+
export const ZINTRUST_BUILD_DATE = '2026-03-31T14:32:01.844Z'; // Replaced during build
|
|
25
25
|
export { Application } from './boot/Application.js';
|
|
26
26
|
export { AwsSigV4 } from './common/index.js';
|
|
27
27
|
export { SignedRequest } from './security/SignedRequest.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuntimeServices.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeServices.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAEtF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;CAC3D,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,iBAAiB,GACjB,WAAW,GACX,WAAW,GACX,SAAS,GACT,UAAU,GACV,UAAU,GACV,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,CAAC,CAAC,SAAS,iBAAiB,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9D,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,WAAW,EAAE,OAAO,WAAW,CAAC;IAChC,aAAa,EAAE,OAAO,aAAa,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MAAM,GAAG,MAAM,CAAC;IAC3E,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACxC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,GAAG,EAAE,gBAAgB,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,uBAAuB,QAAO,OAE1C,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,eAGxC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,eAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"RuntimeServices.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeServices.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAEtF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;CAC3D,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,iBAAiB,GACjB,WAAW,GACX,WAAW,GACX,SAAS,GACT,UAAU,GACV,UAAU,GACV,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,CAAC,CAAC,SAAS,iBAAiB,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9D,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,WAAW,EAAE,OAAO,WAAW,CAAC;IAChC,aAAa,EAAE,OAAO,aAAa,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MAAM,GAAG,MAAM,CAAC;IAC3E,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACxC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,GAAG,EAAE,gBAAgB,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,OAAO,KAAK,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,uBAAuB,QAAO,OAE1C,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,eAGxC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,eAAyC,CAAC;AA2GzE,eAAO,MAAM,eAAe;qBACT,eAAe,GAAG,eAAe;EAqBlD,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -17,42 +17,12 @@ export const detectRuntimePlatform = () => {
|
|
|
17
17
|
return 'nodejs';
|
|
18
18
|
};
|
|
19
19
|
export const RUNTIME_PLATFORM = detectRuntimePlatform();
|
|
20
|
-
const normalizeEnvValue = (value) => {
|
|
21
|
-
if (value === null || value === undefined)
|
|
22
|
-
return '';
|
|
23
|
-
if (typeof value === 'string')
|
|
24
|
-
return value;
|
|
25
|
-
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
26
|
-
return String(value);
|
|
27
|
-
}
|
|
28
|
-
return '';
|
|
29
|
-
};
|
|
30
|
-
const readEnvFromRecord = (record, key) => {
|
|
31
|
-
return normalizeEnvValue(record[key]);
|
|
32
|
-
};
|
|
33
20
|
const createWorkersEnvReader = () => {
|
|
34
21
|
return {
|
|
35
|
-
get(key, defaultValue
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
getInt(key, defaultValue = 0) {
|
|
41
|
-
const raw = this.get(key, String(defaultValue));
|
|
42
|
-
const parsed = Number.parseInt(raw, 10);
|
|
43
|
-
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
44
|
-
},
|
|
45
|
-
getFloat(key, defaultValue = 0) {
|
|
46
|
-
const raw = this.get(key, String(defaultValue));
|
|
47
|
-
const parsed = Number.parseFloat(raw);
|
|
48
|
-
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
49
|
-
},
|
|
50
|
-
getBool(key, defaultValue = false) {
|
|
51
|
-
const raw = this.get(key, defaultValue ? 'true' : 'false').toLowerCase();
|
|
52
|
-
if (raw === '')
|
|
53
|
-
return defaultValue;
|
|
54
|
-
return raw === 'true' || raw === '1';
|
|
55
|
-
},
|
|
22
|
+
get: (key, defaultValue) => Env.get(key, defaultValue),
|
|
23
|
+
getInt: (key, defaultValue) => Env.getInt(key, defaultValue ?? 0),
|
|
24
|
+
getFloat: (key, defaultValue) => Env.getFloat(key, defaultValue ?? 0),
|
|
25
|
+
getBool: (key, defaultValue) => Env.getBool(key, defaultValue),
|
|
56
26
|
};
|
|
57
27
|
};
|
|
58
28
|
const createNodeEnvReader = () => {
|