@multiplatform.one/platform 7.6.3 → 7.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/config/runtimeConfig.cjs +6 -5
- package/dist/esm/config/runtimeConfig.mjs +6 -4
- package/dist/esm/config/runtimeConfig.mjs.map +1 -1
- package/package.json +2 -3
- package/src/config/runtimeConfig.spec.ts +33 -0
- package/src/config/runtimeConfig.ts +46 -50
- package/types/config/runtimeConfig.d.ts +29 -41
- package/types/config/runtimeConfig.d.ts.map +1 -1
- package/src/config/runtimeConfig.native.ts +0 -84
- package/types/config/runtimeConfig.native.d.ts +0 -21
- package/types/config/runtimeConfig.native.d.ts.map +0 -1
|
@@ -32,14 +32,15 @@ __export(runtimeConfig_exports, {
|
|
|
32
32
|
serializeRuntimePublicConfig: () => serializeRuntimePublicConfig
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(runtimeConfig_exports);
|
|
35
|
-
const import_meta = {};
|
|
36
35
|
const runtimePublicConfigKey = "__mp_public_config__";
|
|
37
36
|
const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
38
37
|
const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
39
|
-
function
|
|
38
|
+
function bakedEnv() {
|
|
40
39
|
try {
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
return {
|
|
41
|
+
VITE_MP_CONFIG: process.env.VITE_MP_CONFIG,
|
|
42
|
+
VITE_MP_PUBLIC_CONFIG_KEYS: process.env.VITE_MP_PUBLIC_CONFIG_KEYS
|
|
43
|
+
};
|
|
43
44
|
} catch {
|
|
44
45
|
return {};
|
|
45
46
|
}
|
|
@@ -53,7 +54,7 @@ function processEnv() {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
function readBuildEnv(key) {
|
|
56
|
-
return
|
|
57
|
+
return bakedEnv()[key] ?? processEnv()[key];
|
|
57
58
|
}
|
|
58
59
|
function parseJson(raw) {
|
|
59
60
|
if (!raw) return void 0;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const runtimePublicConfigKey = "__mp_public_config__";
|
|
2
2
|
const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
3
3
|
const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
4
|
-
function
|
|
4
|
+
function bakedEnv() {
|
|
5
5
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
return {
|
|
7
|
+
VITE_MP_CONFIG: process.env.VITE_MP_CONFIG,
|
|
8
|
+
VITE_MP_PUBLIC_CONFIG_KEYS: process.env.VITE_MP_PUBLIC_CONFIG_KEYS
|
|
9
|
+
};
|
|
8
10
|
} catch {
|
|
9
11
|
return {};
|
|
10
12
|
}
|
|
@@ -18,7 +20,7 @@ function processEnv() {
|
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
function readBuildEnv(key) {
|
|
21
|
-
return
|
|
23
|
+
return bakedEnv()[key] ?? processEnv()[key];
|
|
22
24
|
}
|
|
23
25
|
function parseJson(raw) {
|
|
24
26
|
if (!raw) return void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["runtimePublicConfigKey","publicConfigKeysEnvKey","bakedConfigEnvKey","
|
|
1
|
+
{"version":3,"names":["runtimePublicConfigKey","publicConfigKeysEnvKey","bakedConfigEnvKey","bakedEnv","VITE_MP_CONFIG","process","env","VITE_MP_PUBLIC_CONFIG_KEYS","processEnv","readBuildEnv","key","parseJson","raw","JSON","parse","stringifyValues","source","Object","entries","reduce","acc","value","String","publicConfigKeys","parsed","Array","isArray","filter","length","bakedPublicConfig","resolvePublicConfig","baked","readRuntimePublicConfig","globalThis","safeJsonStringify","stringify","replace","serializeRuntimePublicConfig","config"],"sources":["../../../src/config/runtimeConfig.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/platform",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.7.1",
|
|
4
4
|
"description": "Platform detection flags and utilities for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"detection",
|
|
@@ -50,13 +50,12 @@
|
|
|
50
50
|
"@tamagui/build": "2.7.6",
|
|
51
51
|
"@types/chrome": "^0.1.40",
|
|
52
52
|
"@types/firefox-webext-browser": "^143.0.0",
|
|
53
|
-
"@types/react": "~19.2.14",
|
|
54
53
|
"@vitest/coverage-v8": "^4.1.5",
|
|
55
54
|
"happy-dom": "^20.9.0",
|
|
56
55
|
"react": "19.2.5",
|
|
57
56
|
"typescript": "~5.9.3",
|
|
58
57
|
"vitest": "^4.1.5",
|
|
59
|
-
"@multiplatform.one/config": "7.
|
|
58
|
+
"@multiplatform.one/config": "7.7.1"
|
|
60
59
|
},
|
|
61
60
|
"peerDependencies": {
|
|
62
61
|
"expo-constants": "~55.0.15",
|
|
@@ -126,3 +126,36 @@ describe("readRuntimePublicConfig", () => {
|
|
|
126
126
|
expect(readRuntimePublicConfig()).toBeUndefined();
|
|
127
127
|
});
|
|
128
128
|
});
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Twin parity (MPO-192)
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
134
|
+
import { resolve } from "node:path";
|
|
135
|
+
import * as esm from "./runtimeConfig";
|
|
136
|
+
|
|
137
|
+
describe("runtimeConfig has no import.meta and bakes through static process.env reads", () => {
|
|
138
|
+
// vitest runs this package with cwd at its root and a browser-like
|
|
139
|
+
// environment where import.meta.url is not a file: URL, so anchor on cwd.
|
|
140
|
+
const here = resolve(process.cwd(), "src/config");
|
|
141
|
+
const source = readFileSync(`${here}/runtimeConfig.ts`, "utf8").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
142
|
+
|
|
143
|
+
it("contains no import.meta token, because a classic script (Expo DOM component, Hermes) cannot even parse one", () => {
|
|
144
|
+
expect(source).not.toMatch(/import\.meta/);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("reads each baked key as a static process.env member expression, the only spelling bundlers inline", () => {
|
|
148
|
+
expect(source).toMatch(/process\.env\.VITE_MP_CONFIG\b/);
|
|
149
|
+
expect(source).toMatch(/process\.env\.VITE_MP_PUBLIC_CONFIG_KEYS\b/);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("has no platform twin, because One's web build and tamagui-build resolve .web.ts like Metro and a twin replaced the bake once", () => {
|
|
153
|
+
for (const twin of [
|
|
154
|
+
"runtimeConfig.web.ts",
|
|
155
|
+
"runtimeConfig.native.ts",
|
|
156
|
+
"runtimeConfig.classic.ts",
|
|
157
|
+
]) {
|
|
158
|
+
expect(existsSync(`${here}/${twin}`), twin).toBe(false);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -1,42 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Build-time and runtime public config, with no `import.meta` anywhere.
|
|
3
3
|
*
|
|
4
|
-
* Why
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
4
|
+
* Why no `import.meta`: two bundles execute mpo as a CLASSIC script rather
|
|
5
|
+
* than an ES module, and in a classic script `import.meta` is a PARSE-time
|
|
6
|
+
* SyntaxError, so no `typeof import.meta` guard ever runs: the vxrn/rolldown
|
|
7
|
+
* native bundle for Hermes, and any Metro bundle for platform=web, which is
|
|
8
|
+
* what an Expo DOM component (`'use dom'`) and Expo web are (MPO-192: a
|
|
9
|
+
* knob-driven component inside a DOM component blanked the whole WebView with
|
|
10
|
+
* no diagnostics). A `.web.ts` / `.native.ts` twin is not a way out either:
|
|
11
|
+
* One's web build and tamagui-build both resolve `.web.ts` exactly as Metro
|
|
12
|
+
* does, so a web twin replaced this module in the Vite web build too and the
|
|
13
|
+
* bake vanished there. One file, one behaviour.
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* process
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* `server/ServerContextScript`), deliberately sitting ALONGSIDE it rather
|
|
22
|
-
* than being a second, differently-shaped invention.
|
|
15
|
+
* Baking: `createViteConfig` sets `VITE_MP_CONFIG` (values) and
|
|
16
|
+
* `VITE_MP_PUBLIC_CONFIG_KEYS` (names) on `process.env` and defines both as
|
|
17
|
+
* `process.env.<KEY>` for the bundle; `bakedEnv` below reads exactly those two
|
|
18
|
+
* static expressions. The SSR document path (`readRuntimePublicConfig`) is
|
|
19
|
+
* unchanged: the node process resolves the allowlisted names from its own
|
|
20
|
+
* environment at request time and publishes them under
|
|
21
|
+
* `globalThis.__mp_public_config__`.
|
|
23
22
|
*
|
|
24
23
|
* Safety: `resolvePublicConfig` walks the BUILD-TIME PUBLIC ALLOWLIST, never
|
|
25
|
-
* the environment
|
|
26
|
-
*
|
|
27
|
-
* secrets never reach the document.
|
|
24
|
+
* the environment, so a private key present in `env` can not reach the
|
|
25
|
+
* returned object.
|
|
28
26
|
*/
|
|
29
27
|
|
|
30
|
-
/**
|
|
31
|
-
* Global key the SSR document assigns the resolved public config to.
|
|
32
|
-
* Sibling of one's `__one_server_context__`.
|
|
33
|
-
*/
|
|
28
|
+
/** Global the SSR document publishes the resolved public config under. */
|
|
34
29
|
export const runtimePublicConfigKey = "__mp_public_config__";
|
|
35
30
|
|
|
36
31
|
/**
|
|
37
|
-
* Build-time env key carrying the JSON array of PUBLIC config key names
|
|
38
|
-
*
|
|
39
|
-
*
|
|
32
|
+
* Build-time env key carrying the JSON array of PUBLIC config key names. Names
|
|
33
|
+
* only, never a value: the SSR node process resolves values from its own
|
|
34
|
+
* environment at request time, so one build deploys to every environment.
|
|
40
35
|
*/
|
|
41
36
|
export const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
42
37
|
|
|
@@ -47,10 +42,23 @@ export const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
|
47
42
|
*/
|
|
48
43
|
export const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The two baked keys, read as STATIC `process.env.<KEY>` member expressions.
|
|
47
|
+
* That exact spelling is what every bundler on the way to a browser inlines:
|
|
48
|
+
* `createViteConfig` defines both keys (like `process.env.VITE_FRAPPE_ENABLED`),
|
|
49
|
+
* vxrn's loadEnv under One defines every public key the same way, and Metro's
|
|
50
|
+
* babel does the same for `EXPO_PUBLIC_*`. A dynamic `env[key]` read is never
|
|
51
|
+
* inlined, and One's client build folds `typeof process` to "undefined", so
|
|
52
|
+
* anything that consults the environment first returns `{}` before the bake
|
|
53
|
+
* is ever seen. Where nothing defined the keys and `process` does not exist,
|
|
54
|
+
* the reads throw and the catch returns `{}`.
|
|
55
|
+
*/
|
|
56
|
+
function bakedEnv(): Record<string, string | undefined> {
|
|
51
57
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
return {
|
|
59
|
+
VITE_MP_CONFIG: process.env.VITE_MP_CONFIG,
|
|
60
|
+
VITE_MP_PUBLIC_CONFIG_KEYS: process.env.VITE_MP_PUBLIC_CONFIG_KEYS,
|
|
61
|
+
};
|
|
54
62
|
} catch {
|
|
55
63
|
return {};
|
|
56
64
|
}
|
|
@@ -68,7 +76,7 @@ function processEnv(): Record<string, string | undefined> {
|
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
function readBuildEnv(key: string): string | undefined {
|
|
71
|
-
return
|
|
79
|
+
return bakedEnv()[key] ?? processEnv()[key];
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
function parseJson(raw: string | undefined): unknown {
|
|
@@ -89,7 +97,7 @@ function stringifyValues(source: Record<string, unknown>): Record<string, string
|
|
|
89
97
|
|
|
90
98
|
/**
|
|
91
99
|
* The PUBLIC key allowlist baked at build time. Empty when the app was not
|
|
92
|
-
* built through `createViteConfig` (tests, storybook, plain node)
|
|
100
|
+
* built through `createViteConfig` (tests, storybook, plain node), in which
|
|
93
101
|
* case nothing is publishable and the payload stays empty, which is the safe
|
|
94
102
|
* direction to fail.
|
|
95
103
|
*/
|
|
@@ -109,8 +117,8 @@ export function bakedPublicConfig(): Record<string, string> {
|
|
|
109
117
|
/**
|
|
110
118
|
* Resolve the public config the SSR document should publish.
|
|
111
119
|
*
|
|
112
|
-
* Iterates the ALLOWLIST
|
|
113
|
-
*
|
|
120
|
+
* Iterates the ALLOWLIST, never the environment, so a private key present in
|
|
121
|
+
* `env` can not reach the returned object. Runtime env wins over the
|
|
114
122
|
* build-time bake, so a redeployed container overrides a stale baked value.
|
|
115
123
|
*/
|
|
116
124
|
export function resolvePublicConfig(
|
|
@@ -124,21 +132,13 @@ export function resolvePublicConfig(
|
|
|
124
132
|
}, {});
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
/**
|
|
128
|
-
* Read the payload the SSR document published. Returns undefined anywhere the
|
|
129
|
-
* document never ran (native, SSR itself, tests).
|
|
130
|
-
*/
|
|
135
|
+
/** The config the served document published, when there is one. */
|
|
131
136
|
export function readRuntimePublicConfig(): Record<string, string> | undefined {
|
|
132
137
|
const raw = (globalThis as unknown as Record<string, unknown>)[runtimePublicConfigKey];
|
|
133
138
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
|
|
134
139
|
return stringifyValues(raw as Record<string, unknown>);
|
|
135
140
|
}
|
|
136
141
|
|
|
137
|
-
/**
|
|
138
|
-
* HTML-safe JSON: an inline `<script>` body must not be able to close its own
|
|
139
|
-
* tag, and U+2028/U+2029 are line terminators to a JS parser but legal inside
|
|
140
|
-
* a JSON string.
|
|
141
|
-
*/
|
|
142
142
|
function safeJsonStringify(value: unknown): string {
|
|
143
143
|
return JSON.stringify(value ?? {})
|
|
144
144
|
.replace(/</g, "\\u003c")
|
|
@@ -147,11 +147,7 @@ function safeJsonStringify(value: unknown): string {
|
|
|
147
147
|
.replace(/\u2029/g, "\\u2029");
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
/**
|
|
151
|
-
* The inline `<script>` body that publishes the public config to the browser.
|
|
152
|
-
* Runs during document parse, so it lands before the deferred app bundle
|
|
153
|
-
* constructs its `Config`.
|
|
154
|
-
*/
|
|
150
|
+
/** The inline script the SSR document carries so the client can read the config. */
|
|
155
151
|
export function serializeRuntimePublicConfig(
|
|
156
152
|
config: Record<string, string> = resolvePublicConfig(),
|
|
157
153
|
): string {
|
|
@@ -1,40 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Build-time and runtime public config, with no `import.meta` anywhere.
|
|
3
3
|
*
|
|
4
|
-
* Why
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
4
|
+
* Why no `import.meta`: two bundles execute mpo as a CLASSIC script rather
|
|
5
|
+
* than an ES module, and in a classic script `import.meta` is a PARSE-time
|
|
6
|
+
* SyntaxError, so no `typeof import.meta` guard ever runs: the vxrn/rolldown
|
|
7
|
+
* native bundle for Hermes, and any Metro bundle for platform=web, which is
|
|
8
|
+
* what an Expo DOM component (`'use dom'`) and Expo web are (MPO-192: a
|
|
9
|
+
* knob-driven component inside a DOM component blanked the whole WebView with
|
|
10
|
+
* no diagnostics). A `.web.ts` / `.native.ts` twin is not a way out either:
|
|
11
|
+
* One's web build and tamagui-build both resolve `.web.ts` exactly as Metro
|
|
12
|
+
* does, so a web twin replaced this module in the Vite web build too and the
|
|
13
|
+
* bake vanished there. One file, one behaviour.
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* process
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* `server/ServerContextScript`), deliberately sitting ALONGSIDE it rather
|
|
22
|
-
* than being a second, differently-shaped invention.
|
|
15
|
+
* Baking: `createViteConfig` sets `VITE_MP_CONFIG` (values) and
|
|
16
|
+
* `VITE_MP_PUBLIC_CONFIG_KEYS` (names) on `process.env` and defines both as
|
|
17
|
+
* `process.env.<KEY>` for the bundle; `bakedEnv` below reads exactly those two
|
|
18
|
+
* static expressions. The SSR document path (`readRuntimePublicConfig`) is
|
|
19
|
+
* unchanged: the node process resolves the allowlisted names from its own
|
|
20
|
+
* environment at request time and publishes them under
|
|
21
|
+
* `globalThis.__mp_public_config__`.
|
|
23
22
|
*
|
|
24
23
|
* Safety: `resolvePublicConfig` walks the BUILD-TIME PUBLIC ALLOWLIST, never
|
|
25
|
-
* the environment
|
|
26
|
-
*
|
|
27
|
-
* secrets never reach the document.
|
|
28
|
-
*/
|
|
29
|
-
/**
|
|
30
|
-
* Global key the SSR document assigns the resolved public config to.
|
|
31
|
-
* Sibling of one's `__one_server_context__`.
|
|
24
|
+
* the environment, so a private key present in `env` can not reach the
|
|
25
|
+
* returned object.
|
|
32
26
|
*/
|
|
27
|
+
/** Global the SSR document publishes the resolved public config under. */
|
|
33
28
|
export declare const runtimePublicConfigKey = "__mp_public_config__";
|
|
34
29
|
/**
|
|
35
|
-
* Build-time env key carrying the JSON array of PUBLIC config key names
|
|
36
|
-
*
|
|
37
|
-
*
|
|
30
|
+
* Build-time env key carrying the JSON array of PUBLIC config key names. Names
|
|
31
|
+
* only, never a value: the SSR node process resolves values from its own
|
|
32
|
+
* environment at request time, so one build deploys to every environment.
|
|
38
33
|
*/
|
|
39
34
|
export declare const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
40
35
|
/**
|
|
@@ -45,7 +40,7 @@ export declare const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
|
45
40
|
export declare const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
46
41
|
/**
|
|
47
42
|
* The PUBLIC key allowlist baked at build time. Empty when the app was not
|
|
48
|
-
* built through `createViteConfig` (tests, storybook, plain node)
|
|
43
|
+
* built through `createViteConfig` (tests, storybook, plain node), in which
|
|
49
44
|
* case nothing is publishable and the payload stays empty, which is the safe
|
|
50
45
|
* direction to fail.
|
|
51
46
|
*/
|
|
@@ -55,20 +50,13 @@ export declare function bakedPublicConfig(): Record<string, string>;
|
|
|
55
50
|
/**
|
|
56
51
|
* Resolve the public config the SSR document should publish.
|
|
57
52
|
*
|
|
58
|
-
* Iterates the ALLOWLIST
|
|
59
|
-
*
|
|
53
|
+
* Iterates the ALLOWLIST, never the environment, so a private key present in
|
|
54
|
+
* `env` can not reach the returned object. Runtime env wins over the
|
|
60
55
|
* build-time bake, so a redeployed container overrides a stale baked value.
|
|
61
56
|
*/
|
|
62
57
|
export declare function resolvePublicConfig(env?: Record<string, string | undefined>): Record<string, string>;
|
|
63
|
-
/**
|
|
64
|
-
* Read the payload the SSR document published. Returns undefined anywhere the
|
|
65
|
-
* document never ran (native, SSR itself, tests).
|
|
66
|
-
*/
|
|
58
|
+
/** The config the served document published, when there is one. */
|
|
67
59
|
export declare function readRuntimePublicConfig(): Record<string, string> | undefined;
|
|
68
|
-
/**
|
|
69
|
-
* The inline `<script>` body that publishes the public config to the browser.
|
|
70
|
-
* Runs during document parse, so it lands before the deferred app bundle
|
|
71
|
-
* constructs its `Config`.
|
|
72
|
-
*/
|
|
60
|
+
/** The inline script the SSR document carries so the client can read the config. */
|
|
73
61
|
export declare function serializeRuntimePublicConfig(config?: Record<string, string>): string;
|
|
74
62
|
//# sourceMappingURL=runtimeConfig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeConfig.d.ts","sourceRoot":"","sources":["../../src/config/runtimeConfig.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtimeConfig.d.ts","sourceRoot":"","sources":["../../src/config/runtimeConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,+BAA+B,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAuDlD;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAI3C;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI1D;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAgB,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,mEAAmE;AACnE,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAI5E;AAUD,oFAAoF;AACpF,wBAAgB,4BAA4B,CAC1C,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAyB,GACrD,MAAM,CAER"}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Native twin of `runtimeConfig.ts`.
|
|
3
|
-
*
|
|
4
|
-
* Identical API, minus `import.meta`: the vxrn/rolldown native bundle is a
|
|
5
|
-
* CLASSIC script for Hermes, where `import.meta` is a syntax error (the same
|
|
6
|
-
* reason `config.native.ts` exists as a hand-written twin of `config.ts`).
|
|
7
|
-
*
|
|
8
|
-
* Native has no SSR document, so `readRuntimePublicConfig` normally returns
|
|
9
|
-
* undefined and native keeps resolving through `expo-constants` +
|
|
10
|
-
* `process.env` exactly as before. The exports are kept so that shared code
|
|
11
|
-
* importing from `@multiplatform.one/platform` compiles on every target.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export const runtimePublicConfigKey = "__mp_public_config__";
|
|
15
|
-
export const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
16
|
-
export const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
17
|
-
|
|
18
|
-
function processEnv(): Record<string, string | undefined> {
|
|
19
|
-
try {
|
|
20
|
-
if (typeof process === "undefined") return {};
|
|
21
|
-
return (process.env || {}) as Record<string, string | undefined>;
|
|
22
|
-
} catch {
|
|
23
|
-
return {};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function parseJson(raw: string | undefined): unknown {
|
|
28
|
-
if (!raw) return undefined;
|
|
29
|
-
try {
|
|
30
|
-
return JSON.parse(raw);
|
|
31
|
-
} catch {
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function stringifyValues(source: Record<string, unknown>): Record<string, string> {
|
|
37
|
-
return Object.entries(source).reduce<Record<string, string>>((acc, [key, value]) => {
|
|
38
|
-
if (typeof value !== "undefined" && value !== null) acc[key] = String(value);
|
|
39
|
-
return acc;
|
|
40
|
-
}, {});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function publicConfigKeys(): string[] {
|
|
44
|
-
const parsed = parseJson(processEnv()[publicConfigKeysEnvKey]);
|
|
45
|
-
if (!Array.isArray(parsed)) return [];
|
|
46
|
-
return parsed.filter((key): key is string => typeof key === "string" && key.length > 0);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function bakedPublicConfig(): Record<string, string> {
|
|
50
|
-
const parsed = parseJson(processEnv()[bakedConfigEnvKey]);
|
|
51
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
52
|
-
return stringifyValues(parsed as Record<string, unknown>);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function resolvePublicConfig(
|
|
56
|
-
env: Record<string, string | undefined> = processEnv(),
|
|
57
|
-
): Record<string, string> {
|
|
58
|
-
const baked = bakedPublicConfig();
|
|
59
|
-
return publicConfigKeys().reduce<Record<string, string>>((acc, key) => {
|
|
60
|
-
const value = env[key] ?? baked[key];
|
|
61
|
-
if (typeof value === "string" && value.length > 0) acc[key] = value;
|
|
62
|
-
return acc;
|
|
63
|
-
}, {});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function readRuntimePublicConfig(): Record<string, string> | undefined {
|
|
67
|
-
const raw = (globalThis as unknown as Record<string, unknown>)[runtimePublicConfigKey];
|
|
68
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
|
|
69
|
-
return stringifyValues(raw as Record<string, unknown>);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function safeJsonStringify(value: unknown): string {
|
|
73
|
-
return JSON.stringify(value ?? {})
|
|
74
|
-
.replace(/</g, "\\u003c")
|
|
75
|
-
.replace(/>/g, "\\u003e")
|
|
76
|
-
.replace(/\u2028/g, "\\u2028")
|
|
77
|
-
.replace(/\u2029/g, "\\u2029");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function serializeRuntimePublicConfig(
|
|
81
|
-
config: Record<string, string> = resolvePublicConfig(),
|
|
82
|
-
): string {
|
|
83
|
-
return `globalThis[${JSON.stringify(runtimePublicConfigKey)}]=${safeJsonStringify(config)};`;
|
|
84
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Native twin of `runtimeConfig.ts`.
|
|
3
|
-
*
|
|
4
|
-
* Identical API, minus `import.meta`: the vxrn/rolldown native bundle is a
|
|
5
|
-
* CLASSIC script for Hermes, where `import.meta` is a syntax error (the same
|
|
6
|
-
* reason `config.native.ts` exists as a hand-written twin of `config.ts`).
|
|
7
|
-
*
|
|
8
|
-
* Native has no SSR document, so `readRuntimePublicConfig` normally returns
|
|
9
|
-
* undefined and native keeps resolving through `expo-constants` +
|
|
10
|
-
* `process.env` exactly as before. The exports are kept so that shared code
|
|
11
|
-
* importing from `@multiplatform.one/platform` compiles on every target.
|
|
12
|
-
*/
|
|
13
|
-
export declare const runtimePublicConfigKey = "__mp_public_config__";
|
|
14
|
-
export declare const publicConfigKeysEnvKey = "VITE_MP_PUBLIC_CONFIG_KEYS";
|
|
15
|
-
export declare const bakedConfigEnvKey = "VITE_MP_CONFIG";
|
|
16
|
-
export declare function publicConfigKeys(): string[];
|
|
17
|
-
export declare function bakedPublicConfig(): Record<string, string>;
|
|
18
|
-
export declare function resolvePublicConfig(env?: Record<string, string | undefined>): Record<string, string>;
|
|
19
|
-
export declare function readRuntimePublicConfig(): Record<string, string> | undefined;
|
|
20
|
-
export declare function serializeRuntimePublicConfig(config?: Record<string, string>): string;
|
|
21
|
-
//# sourceMappingURL=runtimeConfig.native.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeConfig.native.d.ts","sourceRoot":"","sources":["../../src/config/runtimeConfig.native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAC7D,eAAO,MAAM,sBAAsB,+BAA+B,CAAC;AACnE,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AA2BlD,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAI3C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI1D;AAED,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAgB,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAI5E;AAUD,wBAAgB,4BAA4B,CAC1C,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAyB,GACrD,MAAM,CAER"}
|