@multiplatform.one/config 6.7.0 → 7.1.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/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as createViteConfig } from "./vite-C6psj1Lz.js";
2
- import { createStorybookViteConfig } from "./storybook.js";
1
+ import { t as createViteConfig } from "./vite-C7884n3X.js";
2
+ import { t as createStorybookViteConfig } from "./storybook-CrdwuS_Y.js";
3
3
  import { createVitestConfig } from "./vitest.js";
4
4
 
5
5
  export { createStorybookViteConfig, createViteConfig, createVitestConfig };
@@ -0,0 +1,274 @@
1
+ import { r as resolvePackageMainSource, t as discoverPublicPackageRoots } from "./workspacePublicPackages-COicQSj4.js";
2
+ import { createRequire } from "node:module";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ //#region src/unexportedDepAliases.ts
7
+ /**
8
+ * Package subtrees that consumers deep-import but the publisher never declared
9
+ * in its `exports` map.
10
+ *
11
+ * `one`'s `fork/SSRNavigationContainer` (every dist flavour plus its source)
12
+ * imports three `@react-navigation/core` internals:
13
+ *
14
+ * @react-navigation/core/lib/module/NavigationBuilderContext
15
+ * @react-navigation/core/lib/module/NavigationStateContext
16
+ * @react-navigation/core/lib/module/EnsureSingleNavigator
17
+ *
18
+ * The published package exports only "." and "./package.json", so those are
19
+ * undeclared subpaths of a bare specifier — Node rejects them with
20
+ * ERR_PACKAGE_PATH_NOT_EXPORTED and Rolldown (Vite 8) rejects them at build
21
+ * time. Both are behaving correctly; the deep imports are the bug.
22
+ *
23
+ * vxrn papers over it by rewriting the dependency's package.json in place
24
+ * (`vxrn` builtInDepPatches, which leaves a package.json.vxrn.original behind),
25
+ * but that only runs when something invokes vxrn — never during a plain
26
+ * `vite build` or `storybook build`, and never on a fresh CI install. Mapping
27
+ * the subtree to its real directory resolves those files by path, which is
28
+ * exactly where the missing exports entries would have pointed.
29
+ */
30
+ const UNEXPORTED_SUBTREES = ["@react-navigation/core/lib/module"];
31
+ /**
32
+ * Vite `resolve.alias` entries that let known-undeclared package internals
33
+ * resolve by filesystem path.
34
+ *
35
+ * Scoped to one subtree of one package: Vite alias keys match the whole
36
+ * specifier or a `key + "/"` prefix, so sibling paths (`lib/moduleOther`) and
37
+ * the package's own entry (`@react-navigation/core`) keep going through the
38
+ * `exports` map. Nothing here disables exports enforcement globally.
39
+ *
40
+ * Entries are omitted when the package (or the target directory) is absent, so
41
+ * consumers that do not install `one`/react-navigation are unaffected.
42
+ *
43
+ * @param root Directory whose `node_modules` the packages resolve from.
44
+ */
45
+ function unexportedDepAliases(root = process.cwd()) {
46
+ const aliases = {};
47
+ const requireFrom = createRequire(path.join(root, "package.json"));
48
+ for (const specifier of UNEXPORTED_SUBTREES) {
49
+ const [pkgName, subpath] = splitPackageSubpath(specifier);
50
+ const pkgDir = resolvePackageDir(pkgName, root, requireFrom);
51
+ if (!pkgDir) continue;
52
+ const target = path.join(pkgDir, subpath);
53
+ if (fs.existsSync(target)) aliases[specifier] = target;
54
+ }
55
+ return aliases;
56
+ }
57
+ function splitPackageSubpath(specifier) {
58
+ const segments = specifier.split("/");
59
+ const nameLength = specifier.startsWith("@") ? 2 : 1;
60
+ return [segments.slice(0, nameLength).join("/"), segments.slice(nameLength).join("/")];
61
+ }
62
+ function resolvePackageDir(pkgName, root, requireFrom) {
63
+ try {
64
+ return path.dirname(requireFrom.resolve(`${pkgName}/package.json`));
65
+ } catch {
66
+ const hoisted = path.join(root, "node_modules", ...pkgName.split("/"));
67
+ return fs.existsSync(path.join(hoisted, "package.json")) ? hoisted : void 0;
68
+ }
69
+ }
70
+
71
+ //#endregion
72
+ //#region src/storybook.ts
73
+ /**
74
+ * Creates a Vite configuration for Storybook in the multiplatform.one monorepo.
75
+ *
76
+ * Auto-discovers packages/ entries (multiplatform.one, package, and root
77
+ * multiplatform.one scopes) and every workspace package under public/ with a
78
+ * package.json name (including other scopes such as bitspur). Aliases point at
79
+ * TypeScript source; sub-path exports come from each package exports field.
80
+ *
81
+ * Includes React plugin, node:async_hooks stub, and Storybook optimizeDeps.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * // apps/storybook/vite.config.ts
86
+ * import { createStorybookViteConfig } from "@multiplatform.one/config/storybook";
87
+ *
88
+ * export default createStorybookViteConfig();
89
+ * ```
90
+ */
91
+ function createStorybookViteConfig(options = {}) {
92
+ const workspaceRoot = options.workspaceRoot || findWorkspaceRoot();
93
+ const aliases = {
94
+ ...discoverPackageAliases(path.join(workspaceRoot, "packages")),
95
+ ...discoverPublicPackageViteAliases(workspaceRoot),
96
+ ...unexportedDepAliases(workspaceRoot)
97
+ };
98
+ if (options.aliases) Object.assign(aliases, options.aliases);
99
+ const sortedAliases = {};
100
+ for (const key of Object.keys(aliases).sort((a, b) => b.length - a.length)) sortedAliases[key] = aliases[key];
101
+ return {
102
+ define: {
103
+ "process.env.VITE_ENVIRONMENT": JSON.stringify("client"),
104
+ ...options.define
105
+ },
106
+ resolve: {
107
+ conditions: ["default"],
108
+ extensions: [
109
+ ".storybook.ts",
110
+ ".storybook.tsx",
111
+ ".storybook.js",
112
+ ".storybook.jsx",
113
+ ".web.ts",
114
+ ".web.tsx",
115
+ ".web.js",
116
+ ".web.jsx",
117
+ ".ts",
118
+ ".tsx",
119
+ ".js",
120
+ ".jsx",
121
+ ".mjs",
122
+ ".json"
123
+ ],
124
+ alias: sortedAliases
125
+ },
126
+ optimizeDeps: {
127
+ include: [
128
+ "react",
129
+ "react-dom",
130
+ "react-native-web",
131
+ "@tamagui/core",
132
+ "@tamagui/web",
133
+ "@tamagui/helpers-icon",
134
+ "tamagui",
135
+ "@mdx-js/react",
136
+ "i18next",
137
+ "react-i18next",
138
+ "d3-shape",
139
+ "d3-scale",
140
+ "@storybook-community/storybook-dark-mode",
141
+ "use-latest-callback",
142
+ "escape-string-regexp",
143
+ "use-sync-external-store",
144
+ "use-sync-external-store/with-selector",
145
+ "fast-deep-equal",
146
+ "color",
147
+ "query-string",
148
+ "react-is"
149
+ ],
150
+ exclude: [
151
+ "one/dist/esm/vite/one-server-only.mjs",
152
+ "@storybook/preview-api",
153
+ "@storybook/theming",
154
+ "@react-navigation/core",
155
+ "@react-navigation/native",
156
+ "@react-navigation/routers",
157
+ "@react-navigation/elements",
158
+ "@react-navigation/bottom-tabs",
159
+ "@react-navigation/native-stack"
160
+ ]
161
+ },
162
+ plugins: [nodeAsyncHooksStub(), ...options.plugins || []]
163
+ };
164
+ }
165
+ /**
166
+ * Scans packages/ for workspace packages (multiplatform.one and package scopes)
167
+ * and returns resolve aliases.
168
+ */
169
+ function discoverPackageAliases(packagesDir) {
170
+ const aliases = {};
171
+ if (!fs.existsSync(packagesDir)) return aliases;
172
+ const entries = fs.readdirSync(packagesDir, { withFileTypes: true });
173
+ for (const entry of entries) {
174
+ if (!entry.isDirectory()) continue;
175
+ const pkgDir = path.join(packagesDir, entry.name);
176
+ const pkgJsonPath = path.join(pkgDir, "package.json");
177
+ if (!fs.existsSync(pkgJsonPath)) continue;
178
+ let pkgJson;
179
+ try {
180
+ pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
181
+ } catch {
182
+ continue;
183
+ }
184
+ const pkgName = pkgJson.name;
185
+ if (!pkgName) continue;
186
+ if (!pkgName.startsWith("@multiplatform.one/") && !pkgName.startsWith("@package/") && pkgName !== "multiplatform.one") continue;
187
+ mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
188
+ }
189
+ return aliases;
190
+ }
191
+ /** All workspace packages under public/ (any npm scope), including export subpaths. */
192
+ function discoverPublicPackageViteAliases(workspaceRoot) {
193
+ const aliases = {};
194
+ for (const [pkgName, pkgDir] of discoverPublicPackageRoots(workspaceRoot)) {
195
+ const pkgJsonPath = path.join(pkgDir, "package.json");
196
+ let pkgJson;
197
+ try {
198
+ pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
199
+ } catch {
200
+ continue;
201
+ }
202
+ mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
203
+ }
204
+ return aliases;
205
+ }
206
+ function mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases) {
207
+ const mainEntry = resolvePackageMainSource(pkgDir);
208
+ if (mainEntry) aliases[pkgName] = mainEntry;
209
+ if (pkgJson.exports && typeof pkgJson.exports === "object") for (const exportKey of Object.keys(pkgJson.exports)) {
210
+ if (exportKey === "." || exportKey === "./package.json") continue;
211
+ const subpath = exportKey.replace(/^\.\//, "");
212
+ if (path.extname(subpath)) {
213
+ const parentDir = path.dirname(subpath);
214
+ if (parentDir && parentDir !== ".") {
215
+ const fullParentDir = path.join(pkgDir, parentDir);
216
+ if (fs.existsSync(fullParentDir) && fs.statSync(fullParentDir).isDirectory()) aliases[`${pkgName}/${parentDir}`] = fullParentDir;
217
+ }
218
+ } else {
219
+ const resolved = resolveSubpathSource(pkgDir, subpath);
220
+ if (resolved) aliases[`${pkgName}/${subpath}`] = resolved;
221
+ }
222
+ }
223
+ }
224
+ function resolveSubpathSource(pkgDir, subpath) {
225
+ const candidates = [
226
+ path.join(pkgDir, "src", `${subpath}.storybook.ts`),
227
+ path.join(pkgDir, "src", `${subpath}.storybook.tsx`),
228
+ path.join(pkgDir, "src", `${subpath}.ts`),
229
+ path.join(pkgDir, "src", `${subpath}.tsx`),
230
+ path.join(pkgDir, "src", subpath, "index.storybook.ts"),
231
+ path.join(pkgDir, "src", subpath, "index.storybook.tsx"),
232
+ path.join(pkgDir, "src", subpath, "index.ts"),
233
+ path.join(pkgDir, "src", subpath, "index.tsx"),
234
+ path.join(pkgDir, `${subpath}.storybook.ts`),
235
+ path.join(pkgDir, `${subpath}.storybook.tsx`),
236
+ path.join(pkgDir, `${subpath}.ts`),
237
+ path.join(pkgDir, `${subpath}.tsx`),
238
+ path.join(pkgDir, subpath, "index.storybook.ts"),
239
+ path.join(pkgDir, subpath, "index.storybook.tsx"),
240
+ path.join(pkgDir, subpath, "index.ts"),
241
+ path.join(pkgDir, subpath, "index.tsx"),
242
+ path.join(pkgDir, subpath, "index.js")
243
+ ];
244
+ for (const c of candidates) if (fs.existsSync(c)) return c;
245
+ const dirPath = path.join(pkgDir, subpath);
246
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) return dirPath;
247
+ }
248
+ /** Virtual module plugin that stubs `node:async_hooks` for browser environments. */
249
+ function nodeAsyncHooksStub() {
250
+ return {
251
+ name: "storybook:node-async-hooks-stub",
252
+ resolveId(id) {
253
+ if (id === "node:async_hooks") return "\0node:async_hooks";
254
+ },
255
+ load(id) {
256
+ if (id === "\0node:async_hooks") return "export class AsyncLocalStorage {}";
257
+ }
258
+ };
259
+ }
260
+ function findWorkspaceRoot() {
261
+ let dir = process.cwd();
262
+ while (dir !== path.dirname(dir)) {
263
+ if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
264
+ const pkgJsonPath = path.join(dir, "package.json");
265
+ if (fs.existsSync(pkgJsonPath)) try {
266
+ if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")).workspaces) return dir;
267
+ } catch {}
268
+ dir = path.dirname(dir);
269
+ }
270
+ return process.cwd();
271
+ }
272
+
273
+ //#endregion
274
+ export { createStorybookViteConfig as t };
package/lib/storybook.js CHANGED
@@ -1,206 +1,3 @@
1
- import { r as resolvePackageMainSource, t as discoverPublicPackageRoots } from "./workspacePublicPackages-CkDbm3QT.js";
2
- import fs from "node:fs";
3
- import path from "node:path";
1
+ import { t as createStorybookViteConfig } from "./storybook-CrdwuS_Y.js";
4
2
 
5
- //#region src/storybook.ts
6
- /**
7
- * Creates a Vite configuration for Storybook in the multiplatform.one monorepo.
8
- *
9
- * Auto-discovers packages/ entries (multiplatform.one, package, and root
10
- * multiplatform.one scopes) and every workspace package under public/ with a
11
- * package.json name (including other scopes such as bitspur). Aliases point at
12
- * TypeScript source; sub-path exports come from each package exports field.
13
- *
14
- * Includes React plugin, node:async_hooks stub, and Storybook optimizeDeps.
15
- *
16
- * @example
17
- * ```ts
18
- * // apps/storybook/vite.config.ts
19
- * import { createStorybookViteConfig } from "@multiplatform.one/config/storybook";
20
- *
21
- * export default createStorybookViteConfig();
22
- * ```
23
- */
24
- function createStorybookViteConfig(options = {}) {
25
- const workspaceRoot = options.workspaceRoot || findWorkspaceRoot();
26
- const aliases = {
27
- ...discoverPackageAliases(path.join(workspaceRoot, "packages")),
28
- ...discoverPublicPackageViteAliases(workspaceRoot)
29
- };
30
- if (options.aliases) Object.assign(aliases, options.aliases);
31
- const sortedAliases = {};
32
- for (const key of Object.keys(aliases).sort((a, b) => b.length - a.length)) sortedAliases[key] = aliases[key];
33
- return {
34
- define: {
35
- "process.env.VITE_ENVIRONMENT": JSON.stringify("client"),
36
- ...options.define
37
- },
38
- resolve: {
39
- conditions: ["default"],
40
- extensions: [
41
- ".storybook.ts",
42
- ".storybook.tsx",
43
- ".storybook.js",
44
- ".storybook.jsx",
45
- ".web.ts",
46
- ".web.tsx",
47
- ".web.js",
48
- ".web.jsx",
49
- ".ts",
50
- ".tsx",
51
- ".js",
52
- ".jsx",
53
- ".mjs",
54
- ".json"
55
- ],
56
- alias: sortedAliases
57
- },
58
- optimizeDeps: {
59
- include: [
60
- "react",
61
- "react-dom",
62
- "react-native-web",
63
- "@tamagui/core",
64
- "@tamagui/web",
65
- "@tamagui/helpers-icon",
66
- "tamagui",
67
- "@mdx-js/react",
68
- "i18next",
69
- "react-i18next",
70
- "d3-shape",
71
- "d3-scale",
72
- "@storybook-community/storybook-dark-mode",
73
- "use-latest-callback",
74
- "escape-string-regexp",
75
- "use-sync-external-store",
76
- "use-sync-external-store/with-selector",
77
- "fast-deep-equal",
78
- "color",
79
- "query-string",
80
- "react-is"
81
- ],
82
- exclude: [
83
- "one/dist/esm/vite/one-server-only.mjs",
84
- "@storybook/preview-api",
85
- "@storybook/theming",
86
- "@react-navigation/core",
87
- "@react-navigation/native",
88
- "@react-navigation/routers",
89
- "@react-navigation/elements",
90
- "@react-navigation/bottom-tabs",
91
- "@react-navigation/native-stack"
92
- ]
93
- },
94
- plugins: [nodeAsyncHooksStub(), ...options.plugins || []]
95
- };
96
- }
97
- /**
98
- * Scans packages/ for workspace packages (multiplatform.one and package scopes)
99
- * and returns resolve aliases.
100
- */
101
- function discoverPackageAliases(packagesDir) {
102
- const aliases = {};
103
- if (!fs.existsSync(packagesDir)) return aliases;
104
- const entries = fs.readdirSync(packagesDir, { withFileTypes: true });
105
- for (const entry of entries) {
106
- if (!entry.isDirectory()) continue;
107
- const pkgDir = path.join(packagesDir, entry.name);
108
- const pkgJsonPath = path.join(pkgDir, "package.json");
109
- if (!fs.existsSync(pkgJsonPath)) continue;
110
- let pkgJson;
111
- try {
112
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
113
- } catch {
114
- continue;
115
- }
116
- const pkgName = pkgJson.name;
117
- if (!pkgName) continue;
118
- if (!pkgName.startsWith("@multiplatform.one/") && !pkgName.startsWith("@package/") && pkgName !== "multiplatform.one") continue;
119
- mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
120
- }
121
- return aliases;
122
- }
123
- /** All workspace packages under public/ (any npm scope), including export subpaths. */
124
- function discoverPublicPackageViteAliases(workspaceRoot) {
125
- const aliases = {};
126
- for (const [pkgName, pkgDir] of discoverPublicPackageRoots(workspaceRoot)) {
127
- const pkgJsonPath = path.join(pkgDir, "package.json");
128
- let pkgJson;
129
- try {
130
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
131
- } catch {
132
- continue;
133
- }
134
- mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases);
135
- }
136
- return aliases;
137
- }
138
- function mergePackageResolveAliases(pkgDir, pkgName, pkgJson, aliases) {
139
- const mainEntry = resolvePackageMainSource(pkgDir);
140
- if (mainEntry) aliases[pkgName] = mainEntry;
141
- if (pkgJson.exports && typeof pkgJson.exports === "object") for (const exportKey of Object.keys(pkgJson.exports)) {
142
- if (exportKey === "." || exportKey === "./package.json") continue;
143
- const subpath = exportKey.replace(/^\.\//, "");
144
- if (path.extname(subpath)) {
145
- const parentDir = path.dirname(subpath);
146
- if (parentDir && parentDir !== ".") {
147
- const fullParentDir = path.join(pkgDir, parentDir);
148
- if (fs.existsSync(fullParentDir) && fs.statSync(fullParentDir).isDirectory()) aliases[`${pkgName}/${parentDir}`] = fullParentDir;
149
- }
150
- } else {
151
- const resolved = resolveSubpathSource(pkgDir, subpath);
152
- if (resolved) aliases[`${pkgName}/${subpath}`] = resolved;
153
- }
154
- }
155
- }
156
- function resolveSubpathSource(pkgDir, subpath) {
157
- const candidates = [
158
- path.join(pkgDir, "src", `${subpath}.storybook.ts`),
159
- path.join(pkgDir, "src", `${subpath}.storybook.tsx`),
160
- path.join(pkgDir, "src", `${subpath}.ts`),
161
- path.join(pkgDir, "src", `${subpath}.tsx`),
162
- path.join(pkgDir, "src", subpath, "index.storybook.ts"),
163
- path.join(pkgDir, "src", subpath, "index.storybook.tsx"),
164
- path.join(pkgDir, "src", subpath, "index.ts"),
165
- path.join(pkgDir, "src", subpath, "index.tsx"),
166
- path.join(pkgDir, `${subpath}.storybook.ts`),
167
- path.join(pkgDir, `${subpath}.storybook.tsx`),
168
- path.join(pkgDir, `${subpath}.ts`),
169
- path.join(pkgDir, `${subpath}.tsx`),
170
- path.join(pkgDir, subpath, "index.storybook.ts"),
171
- path.join(pkgDir, subpath, "index.storybook.tsx"),
172
- path.join(pkgDir, subpath, "index.ts"),
173
- path.join(pkgDir, subpath, "index.tsx"),
174
- path.join(pkgDir, subpath, "index.js")
175
- ];
176
- for (const c of candidates) if (fs.existsSync(c)) return c;
177
- const dirPath = path.join(pkgDir, subpath);
178
- if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) return dirPath;
179
- }
180
- /** Virtual module plugin that stubs `node:async_hooks` for browser environments. */
181
- function nodeAsyncHooksStub() {
182
- return {
183
- name: "storybook:node-async-hooks-stub",
184
- resolveId(id) {
185
- if (id === "node:async_hooks") return "\0node:async_hooks";
186
- },
187
- load(id) {
188
- if (id === "\0node:async_hooks") return "export class AsyncLocalStorage {}";
189
- }
190
- };
191
- }
192
- function findWorkspaceRoot() {
193
- let dir = process.cwd();
194
- while (dir !== path.dirname(dir)) {
195
- if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
196
- const pkgJsonPath = path.join(dir, "package.json");
197
- if (fs.existsSync(pkgJsonPath)) try {
198
- if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")).workspaces) return dir;
199
- } catch {}
200
- dir = path.dirname(dir);
201
- }
202
- return process.cwd();
203
- }
204
-
205
- //#endregion
206
3
  export { createStorybookViteConfig };
@@ -1,4 +1,4 @@
1
- import { t as discoverPublicPackageRoots } from "./workspacePublicPackages-CkDbm3QT.js";
1
+ import { t as discoverPublicPackageRoots } from "./workspacePublicPackages-COicQSj4.js";
2
2
  import { createRequire } from "node:module";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
@@ -77,10 +77,13 @@ function lookupProjectRoot() {
77
77
  * ```
78
78
  */
79
79
  function createViteConfig(options = {}) {
80
- const { projectRoot: _projectRoot, publicConfigKeys = [], tamagui = true, i18n = false, one = false, ssr, server, plugins: extraPlugins = [], externalReactRouter, ssrDeps, ssrEntries } = options;
80
+ const { projectRoot: _projectRoot, publicConfigKeys = [], tamagui = true, i18n = false, one = false, ssr, server, plugins: extraPlugins = [], externalReactRouter, ssrDeps, ssrEntries, ssrCjsExternal, nativeFixes } = options;
81
81
  const projectRoot = _projectRoot || findProjectRoot();
82
82
  dotenv.config({ path: path.resolve(projectRoot, ".env") });
83
- if (publicConfigKeys.length > 0) process.env.VITE_MP_CONFIG = JSON.stringify(resolveConfig(publicConfigKeys));
83
+ if (publicConfigKeys.length > 0) {
84
+ process.env.VITE_MP_CONFIG = JSON.stringify(resolveConfig(publicConfigKeys));
85
+ process.env.VITE_MP_PUBLIC_CONFIG_KEYS = JSON.stringify(publicConfigKeys);
86
+ }
84
87
  const vitePlugins = [];
85
88
  vitePlugins.push(preferBuiltWorkspaceEntryPlugin());
86
89
  if (one) {
@@ -89,6 +92,9 @@ function createViteConfig(options = {}) {
89
92
  registerNativeEngineIoBrowserTransports();
90
93
  registerNativeWorkspaceEntries();
91
94
  registerNativePhosphorIcons();
95
+ if (nativeFixes?.protoShadow !== false) registerNativeProtoShadowFix();
96
+ if (nativeFixes?.web3Stub !== false) registerNativeWeb3Stub();
97
+ if (ssrCjsExternal !== false) vitePlugins.push(ssrCjsExternalFixPlugin([...DEFAULT_SSR_CJS_EXTERNAL, ...ssrCjsExternal ?? []]));
92
98
  }
93
99
  if (tamagui) {
94
100
  const tamaguiOpts = typeof tamagui === "object" ? tamagui : {};
@@ -324,6 +330,111 @@ function registerNativeWorkspaceEntries() {
324
330
  }
325
331
  });
326
332
  }
333
+ /**
334
+ * CJS-only ids (no usable ESM build) that escape Vite's SSR dep optimizer and
335
+ * hit the ESM evaluator ("module is not defined" / "exports is not defined")
336
+ * unless Node's native CJS loader handles them. Union of the lists the
337
+ * monorepo's apps/one and downstream consumer apps (desibox) carried as
338
+ * app-side ssrExternalFix plugins; ids for packages an app never imports are
339
+ * inert, so one shared default list is safe.
340
+ */
341
+ const DEFAULT_SSR_CJS_EXTERNAL = [
342
+ "better-sqlite3",
343
+ "dotenv",
344
+ "color",
345
+ "use-sync-external-store",
346
+ "use-sync-external-store/shim",
347
+ "use-sync-external-store/shim/with-selector",
348
+ "highlight.js",
349
+ "highlight.js/lib/core",
350
+ "turndown",
351
+ "@mixmark-io/domino",
352
+ "lowlight",
353
+ "shallowequal",
354
+ "@emotion/is-prop-valid",
355
+ "hoist-non-react-statics",
356
+ "qrcode"
357
+ ];
358
+ /**
359
+ * Force-append CJS-only ids to `ssr.external`. The one() plugin REPLACES
360
+ * ssr.external with its own list during the config hook, dropping anything
361
+ * set statically by createViteConfig — configResolved runs after all config
362
+ * hooks are merged, so appends here survive.
363
+ */
364
+ function ssrCjsExternalFixPlugin(extras) {
365
+ return {
366
+ name: "multiplatform-ssr-cjs-external-fix",
367
+ configResolved(config) {
368
+ const external = config.ssr.external ?? [];
369
+ if (!Array.isArray(external)) return;
370
+ for (const e of extras) if (!external.includes(e)) external.push(e);
371
+ config.ssr.external = external;
372
+ }
373
+ };
374
+ }
375
+ /**
376
+ * Restore Object.prototype methods shadowed by hoisted globals on NATIVE.
377
+ *
378
+ * vxrn's rolldown native mode emits the whole dev bundle as ONE classic
379
+ * script and forces Hermes V1. Hermes V1 implements spec-compliant global
380
+ * var hoisting, so a flattened module's top-level `var hasOwnProperty`
381
+ * (e.g. acorn via an mdx pipeline) creates
382
+ * `globalThis.hasOwnProperty = undefined` at parse time, shadowing
383
+ * Object.prototype.hasOwnProperty for the entire runtime. React Native core
384
+ * calls `global.hasOwnProperty()` during boot (FuseboxSessionObserver) and
385
+ * dies with "undefined is not a function". Prepend a snippet that copies any
386
+ * Object.prototype method back over an undefined shadowing own-property
387
+ * before any module code runs — the shadowed vars are reassigned by their
388
+ * own modules on init, so this only bridges the parse-to-init window.
389
+ * Registered through globalThis.__vxrnAddNativePlugins (vxrn's native engine
390
+ * ignores vite resolve/config). Web/SSR bundles are ESM (module-scoped vars)
391
+ * and unaffected.
392
+ */
393
+ function registerNativeProtoShadowFix() {
394
+ const g = globalThis;
395
+ const name = "vxrn-proto-shadow-fix";
396
+ g.__vxrnAddNativePlugins = g.__vxrnAddNativePlugins ?? [];
397
+ if (g.__vxrnAddNativePlugins.some((p) => p?.name === name)) return;
398
+ const snippet = "(function(){var p=Object.prototype,h=p.hasOwnProperty,ns=Object.getOwnPropertyNames(p);for(var i=0;i<ns.length;i++){var k=ns[i];if(typeof p[k]===\"function\"&&globalThis[k]===void 0&&h.call(globalThis,k)){try{globalThis[k]=p[k]}catch(e){}}}})();";
399
+ g.__vxrnAddNativePlugins.push({
400
+ name,
401
+ renderChunk(code) {
402
+ return {
403
+ code: `${snippet}\n${code}`,
404
+ map: null
405
+ };
406
+ }
407
+ });
408
+ }
409
+ /**
410
+ * Redirect the OPTIONAL `@multiplatform.one/web3` native import to a no-op
411
+ * shim on NATIVE when the package is not installed (see the nativeFixes
412
+ * option docs). Rolldown leaves the unresolvable specifier as a bare dynamic
413
+ * `import()` in the classic-script native bundle — Hermes rejects that at
414
+ * lazy-compile time ("SyntaxError: Invalid expression encountered"), killing
415
+ * the root _layout route. Web/SSR resolve the same specifier through vite's
416
+ * normal pipeline and are unaffected.
417
+ */
418
+ function registerNativeWeb3Stub() {
419
+ const g = globalThis;
420
+ const name = "vxrn-web3-stub";
421
+ g.__vxrnAddNativePlugins = g.__vxrnAddNativePlugins ?? [];
422
+ if (g.__vxrnAddNativePlugins.some((p) => p?.name === name)) return;
423
+ try {
424
+ __require.resolve("@multiplatform.one/web3", { paths: [findProjectRoot(), process.cwd()] });
425
+ return;
426
+ } catch {}
427
+ const here = path.dirname(new URL(import.meta.url).pathname);
428
+ const shim = [path.resolve(here, "shims/web3Stub.native.js"), path.resolve(here, "../src/shims/web3Stub.native.js")].find((candidate) => fs.existsSync(candidate));
429
+ if (!shim) return;
430
+ g.__vxrnAddNativePlugins.push({
431
+ name,
432
+ resolveId(id) {
433
+ if (id === "@multiplatform.one/web3/native" || id === "@multiplatform.one/web3") return shim;
434
+ return null;
435
+ }
436
+ });
437
+ }
327
438
  function findProjectRoot() {
328
439
  try {
329
440
  const { execSync } = __require("node:child_process");
package/lib/vite.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createViteConfig } from "./vite-C6psj1Lz.js";
2
- import { n as publicPackageViteSourceAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-CkDbm3QT.js";
1
+ import { t as createViteConfig } from "./vite-C7884n3X.js";
2
+ import { n as publicPackageViteSourceAliases, t as discoverPublicPackageRoots } from "./workspacePublicPackages-COicQSj4.js";
3
3
 
4
4
  export { createViteConfig, discoverPublicPackageRoots, publicPackageViteSourceAliases };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/config",
3
- "version": "6.7.0",
3
+ "version": "7.1.0",
4
4
  "description": "Shared build and test configuration presets for multiplatform.one",
5
5
  "keywords": [
6
6
  "config",
@@ -80,14 +80,14 @@
80
80
  "access": "public"
81
81
  },
82
82
  "dependencies": {
83
- "@tamagui/vite-plugin": "2.0.0-rc.41",
83
+ "@tamagui/vite-plugin": "2.7.6",
84
84
  "@vitejs/plugin-react": "^6.0.1",
85
85
  "dotenv": "^17.4.2",
86
86
  "vite": "^8.0.10",
87
87
  "vite-plugin-external": "^6.2.2",
88
88
  "vite-plugin-i18next-loader": "^3.1.3",
89
89
  "vitest": "^4.1.5",
90
- "@multiplatform.one/utils": "6.7.0"
90
+ "@multiplatform.one/utils": "7.1.0"
91
91
  },
92
92
  "devDependencies": {
93
93
  "tsdown": "^0.21.10",
@@ -110,6 +110,7 @@
110
110
  },
111
111
  "scripts": {
112
112
  "typecheck": "tsgo --noEmit",
113
- "build": "rm -rf lib types 2>/dev/null && tsc -p tsconfig.build.json && tsdown"
113
+ "build": "rm -rf lib types 2>/dev/null && tsc -p tsconfig.build.json && tsdown",
114
+ "test": "vitest run --coverage --coverage.provider=v8 --coverage.reporter=text --coverage.reporter=lcov --coverage.reporter=html"
114
115
  }
115
116
  }