zelune 1.5.2 → 1.5.5

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/vite.config.ts CHANGED
@@ -6,6 +6,7 @@ import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { viteRnSourceInject } from './plugins/viteRnSourceInject';
8
8
  import { viteVirtualScreensPlugin } from './plugins/viteVirtualScreensPlugin';
9
+ import { viteReactNativeFallbackPlugin } from './plugins/viteReactNativeFallbackPlugin';
9
10
  import { viteCanvasApiMiddleware } from './src/server/apiMiddleware';
10
11
  import { findMobileAppRoot } from './src/server/astEngine';
11
12
 
@@ -16,9 +17,21 @@ const rawTargetRoot = process.env.ANTIGRAVITY_TARGET_PROJECT
16
17
  ? path.resolve(process.env.ANTIGRAVITY_TARGET_PROJECT)
17
18
  : __dirname;
18
19
 
20
+ const workspaceRoot = process.env.ANTIGRAVITY_WORKSPACE_ROOT
21
+ ? path.resolve(process.env.ANTIGRAVITY_WORKSPACE_ROOT)
22
+ : rawTargetRoot;
23
+
19
24
  const targetProjectRoot = findMobileAppRoot(rawTargetRoot);
20
25
  const mockNavShimPath = path.resolve(__dirname, 'src/runtime/MockNavigationContext.tsx');
21
26
 
27
+ function safeRealpath(targetPath: string): string {
28
+ try {
29
+ return fs.realpathSync(targetPath);
30
+ } catch {
31
+ return path.resolve(targetPath);
32
+ }
33
+ }
34
+
22
35
  function resolvePackageRootDir(pkgName: string): string {
23
36
  try {
24
37
  const pkgJsonPath = requireFromZelune.resolve(`${pkgName}/package.json`);
@@ -33,98 +46,153 @@ const resolvedReactDomDir = resolvePackageRootDir('react-dom');
33
46
  const resolvedRnWebDir = resolvePackageRootDir('react-native-web');
34
47
  const resolvedLucideDir = resolvePackageRootDir('lucide-react');
35
48
 
36
- const PROTECTED_CORE_ALIASES = new Set([
37
- 'react',
38
- 'react-dom',
39
- 'react-native',
40
- 'react-native-web',
41
- 'lucide-react',
42
- 'lucide-react-native',
43
- '@react-navigation/native',
44
- 'expo-router',
45
- 'react-native-safe-area-context',
46
- 'expo-status-bar',
47
- '__proto__',
48
- 'constructor',
49
- 'prototype',
50
- ]);
49
+ /**
50
+ * Loads only safe client-public environment variables (EXPO_PUBLIC_*, NEXT_PUBLIC_*, VITE_*)
51
+ * from the target project's .env files so top-level SDK initializers in mobile screens work.
52
+ */
53
+ function loadPublicProjectEnv(roots: string[]): Record<string, string> {
54
+ const publicEnv: Record<string, string> = {
55
+ NODE_ENV: 'development',
56
+ EXPO_PUBLIC_PLATFORM: 'web',
57
+ };
58
+ const envFiles = ['.env', '.env.development', '.env.local'];
59
+ const uniqueRoots = Array.from(new Set(roots.map((r) => path.resolve(r))));
51
60
 
52
- function stripJsonComments(input: string): string {
53
- return input.replace(
54
- /("(?:\\.|[^"\\])*")|\/\*[\s\S]*?\*\/|\/\/.*/g,
55
- (_match, quotedString?: string) => quotedString ?? ''
56
- );
57
- }
58
-
59
- function resolveTargetProjectPathAliases(projectRoot: string): Record<string, string> {
60
- const normalizedRoot = path.resolve(projectRoot);
61
- const aliases: Record<string, string> = {};
62
- try {
63
- const tsconfigPath = path.join(normalizedRoot, 'tsconfig.json');
64
- if (fs.existsSync(tsconfigPath)) {
65
- const raw = fs.readFileSync(tsconfigPath, 'utf-8');
66
- const cleaned = stripJsonComments(raw);
67
- const parsed = JSON.parse(cleaned) as {
68
- compilerOptions?: {
69
- baseUrl?: string;
70
- paths?: Record<string, string[]>;
71
- };
72
- };
73
- const baseUrl = parsed.compilerOptions?.baseUrl ?? '.';
74
- const paths = parsed.compilerOptions?.paths ?? {};
75
- for (const [pattern, targets] of Object.entries(paths)) {
76
- if (!targets || targets.length === 0) continue;
77
- const cleanKey = pattern.replace(/\/\*$/, '');
78
- if (!cleanKey || PROTECTED_CORE_ALIASES.has(cleanKey)) continue;
79
- const cleanTarget = targets[0].replace(/\/\*$/, '');
80
- const resolvedTarget = path.resolve(normalizedRoot, baseUrl, cleanTarget);
81
- if (
82
- resolvedTarget === normalizedRoot ||
83
- resolvedTarget.startsWith(normalizedRoot + path.sep)
84
- ) {
85
- aliases[cleanKey] = resolvedTarget;
61
+ for (const rootDir of uniqueRoots) {
62
+ for (const fileName of envFiles) {
63
+ const fullPath = path.join(rootDir, fileName);
64
+ try {
65
+ if (!fs.existsSync(fullPath)) continue;
66
+ const raw = fs.readFileSync(fullPath, 'utf-8');
67
+ for (const line of raw.split(/\r?\n/)) {
68
+ const trimmed = line.trim();
69
+ if (!trimmed || trimmed.startsWith('#')) continue;
70
+ const eqIdx = trimmed.indexOf('=');
71
+ if (eqIdx <= 0) continue;
72
+ const key = trimmed.slice(0, eqIdx).trim();
73
+ if (
74
+ !key.startsWith('EXPO_PUBLIC_') &&
75
+ !key.startsWith('NEXT_PUBLIC_') &&
76
+ !key.startsWith('VITE_')
77
+ ) {
78
+ continue;
79
+ }
80
+ let val = trimmed.slice(eqIdx + 1).trim();
81
+ if (
82
+ (val.startsWith('"') && val.endsWith('"')) ||
83
+ (val.startsWith("'") && val.endsWith("'"))
84
+ ) {
85
+ val = val.slice(1, -1);
86
+ }
87
+ publicEnv[key] = val;
86
88
  }
89
+ } catch {
90
+ // Ignore unreadable .env files
87
91
  }
88
92
  }
89
- } catch {
90
- // Ignore malformed tsconfig.json and fall back to standard @ alias below
91
93
  }
94
+ return publicEnv;
95
+ }
92
96
 
93
- if (!aliases['@']) {
94
- const srcDir = path.join(normalizedRoot, 'src');
95
- aliases['@'] = fs.existsSync(srcDir) ? srcDir : normalizedRoot;
96
- }
97
+ const publicProjectEnv = loadPublicProjectEnv([workspaceRoot, rawTargetRoot, targetProjectRoot]);
97
98
 
98
- return aliases;
99
- }
99
+ const allowedFsRoots = Array.from(
100
+ new Set([
101
+ __dirname,
102
+ safeRealpath(__dirname),
103
+ workspaceRoot,
104
+ safeRealpath(workspaceRoot),
105
+ rawTargetRoot,
106
+ safeRealpath(rawTargetRoot),
107
+ targetProjectRoot,
108
+ safeRealpath(targetProjectRoot),
109
+ ])
110
+ );
100
111
 
101
112
  export default defineConfig({
102
113
  plugins: [
114
+ {
115
+ name: 'vite-zelune-process-env-shim',
116
+ transformIndexHtml(html) {
117
+ const serializedEnv = JSON.stringify(publicProjectEnv);
118
+ const envScript = `<script>
119
+ (function() {
120
+ var baseEnv = ${serializedEnv};
121
+ var envProxy = new Proxy(baseEnv, {
122
+ get: function(target, prop) {
123
+ if (typeof prop !== 'string') return target[prop];
124
+ if (prop in target && target[prop] !== undefined && target[prop] !== '') {
125
+ return target[prop];
126
+ }
127
+ var upper = prop.toUpperCase();
128
+ if (upper.includes('URL') || upper.includes('ENDPOINT') || upper.includes('HOST')) {
129
+ return 'https://placeholder.example.com';
130
+ }
131
+ if (upper.includes('KEY') || upper.includes('TOKEN') || upper.includes('ID') || upper.includes('SECRET')) {
132
+ return 'placeholder-public-token';
133
+ }
134
+ return '';
135
+ }
136
+ });
137
+ function createRequireProxy() {
138
+ var fn = function() { return proxy; };
139
+ var proxy = new Proxy(fn, {
140
+ get: function(_t, prop) {
141
+ if (prop === Symbol.toPrimitive) return function(hint) { return hint === 'number' ? 0 : ''; };
142
+ if (prop === 'valueOf') return function() { return 0; };
143
+ if (prop === 'toString') return function() { return ''; };
144
+ if (prop === 'uri' || prop === 'default') return '';
145
+ return proxy;
146
+ }
147
+ });
148
+ return proxy;
149
+ }
150
+ window.global = window;
151
+ window.__DEV__ = true;
152
+ window.process = window.process || { env: envProxy, platform: 'browser', version: '', cwd: function() { return '/'; } };
153
+ window.process.env = envProxy;
154
+ window.require = window.require || function(modId) {
155
+ if (typeof modId === 'string' && /\\.(png|jpe?g|gif|webp|svg|avif|bmp)$/i.test(modId)) {
156
+ return { uri: modId, default: modId };
157
+ }
158
+ return createRequireProxy();
159
+ };
160
+ })();
161
+ </script>`;
162
+ return html.replace('<head>', `<head>\n ${envScript}`);
163
+ },
164
+ },
165
+ viteReactNativeFallbackPlugin(targetProjectRoot, mockNavShimPath, workspaceRoot),
103
166
  viteVirtualScreensPlugin(targetProjectRoot),
104
167
  viteRnSourceInject(targetProjectRoot),
105
168
  react(),
106
169
  viteCanvasApiMiddleware(targetProjectRoot),
107
170
  ],
171
+ optimizeDeps: {
172
+ noDiscovery: true,
173
+ include: [
174
+ 'react',
175
+ 'react/jsx-runtime',
176
+ 'react/jsx-dev-runtime',
177
+ 'react-dom',
178
+ 'react-dom/client',
179
+ 'react-native-web',
180
+ 'lucide-react',
181
+ ],
182
+ },
108
183
  esbuild: {
109
- // Ensure .tsx/.ts/.jsx files are transpiled even when zelune is installed inside node_modules/zelune
110
- include: /\.(tsx|ts|jsx)$/,
184
+ // Ensure .tsx/.ts/.jsx/.js files (including RN .js files with JSX) are transpiled cleanly
185
+ include: /\.(tsx|ts|jsx|js)$/,
111
186
  exclude: [],
112
187
  loader: 'tsx',
113
188
  },
114
189
  resolve: {
115
190
  dedupe: ['react', 'react-dom', 'react-native-web'],
116
191
  alias: {
117
- ...resolveTargetProjectPathAliases(targetProjectRoot),
118
192
  react: resolvedReactDir,
119
193
  'react-dom': resolvedReactDomDir,
120
- 'react-native': resolvedRnWebDir,
121
194
  'react-native-web': resolvedRnWebDir,
122
195
  'lucide-react': resolvedLucideDir,
123
- 'lucide-react-native': resolvedLucideDir,
124
- '@react-navigation/native': mockNavShimPath,
125
- 'expo-router': mockNavShimPath,
126
- 'react-native-safe-area-context': mockNavShimPath,
127
- 'expo-status-bar': mockNavShimPath,
128
196
  },
129
197
  extensions: ['.web.tsx', '.web.ts', '.web.js', '.tsx', '.ts', '.jsx', '.js'],
130
198
  },
@@ -142,7 +210,8 @@ export default defineConfig({
142
210
  cors: false,
143
211
  allowedHosts: ['127.0.0.1', 'localhost', '::1'],
144
212
  fs: {
145
- allow: Array.from(new Set([__dirname, rawTargetRoot, targetProjectRoot])),
213
+ strict: false,
214
+ allow: allowedFsRoots,
146
215
  },
147
216
  },
148
217
  });