@codeyam/codeyam-cli 0.1.26 → 0.1.27
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/analyzer-template/.build-info.json +6 -6
- package/analyzer-template/log.txt +3 -3
- package/codeyam-cli/src/commands/__tests__/editor.statePersistence.test.js +55 -0
- package/codeyam-cli/src/commands/__tests__/editor.statePersistence.test.js.map +1 -0
- package/codeyam-cli/src/commands/editor.js +30 -0
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/data/techStacks.js +1 -1
- package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +120 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +84 -0
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -1
- package/codeyam-cli/src/utils/editorScenarioSwitch.js +27 -12
- package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -1
- package/codeyam-cli/src/utils/editorSeedAdapter.js +27 -14
- package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{analysisRunner-B6HnVI5u.js → analysisRunner-OLsM110H.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-rV_xLS1u.js → index-WHdB6WTN.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{init-BdWDvetv.js → init-DbSiZoE6.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{server-build-B_jdq5dT.js → server-build-DZbLY6O_.js} +97 -96
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +50 -0
- package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +4 -2
- package/codeyam-cli/templates/expo-react-native/babel.config.js +1 -0
- package/codeyam-cli/templates/expo-react-native/gitignore +2 -0
- package/codeyam-cli/templates/expo-react-native/package.json +23 -18
- package/codeyam-cli/templates/expo-react-native/patches/expo-modules-autolinking+3.0.24.patch +29 -0
- package/codeyam-cli/templates/seed-adapters/supabase.ts +91 -8
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{aG as Z,aH as _,aw as $,ax as rr,aE as tr,ay as or,aA as ir,aB as pr,aD as mr,aC as ar,aF as sr,az as er}from"./assets/server-build-
|
|
1
|
+
import{aG as Z,aH as _,aw as $,ax as rr,aE as tr,ay as or,aA as ir,aB as pr,aD as mr,aC as ar,aF as sr,az as er}from"./assets/server-build-DZbLY6O_.js";import"react/jsx-runtime";import"node:stream";import"@react-router/node";import"react-router";import"isbot";import"react-dom/server";import"react";import"lucide-react";import"fetch-retry";import"better-sqlite3";import"pg";import"fs";import"path";import"kysely";import"kysely/helpers/sqlite";import"kysely/helpers/postgres";import"typescript";import"fs/promises";import"os";import"prompts";import"chalk";import"crypto";import"child_process";import"url";import"util";import"dotenv";import"events";import"uuid";import"http";import"net";import"ws";import"node-pty";import"openai";import"p-queue";import"p-retry";import"@aws-sdk/client-dynamodb";import"lru-cache";import"pluralize";import"piscina";import"json5";import"@aws-sdk/util-dynamodb";import"v8";import"react-syntax-highlighter";import"react-syntax-highlighter/dist/cjs/styles/prism/index.js";import"node:crypto";import"minimatch";import"react-markdown";import"remark-gfm";import"react-diff-viewer-continued";export{Z as allowedActionOrigins,_ as assets,$ as assetsBuildDirectory,rr as basename,tr as entry,or as future,ir as isSpaMode,pr as prerender,mr as publicPath,ar as routeDiscovery,sr as routes,er as ssr};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"buildTimestamp": "2026-03-
|
|
3
|
-
"buildTime":
|
|
4
|
-
"buildNumber":
|
|
5
|
-
"semanticVersion": "0.1.
|
|
6
|
-
"version": "0.1.
|
|
2
|
+
"buildTimestamp": "2026-03-28T18:03:48.783Z",
|
|
3
|
+
"buildTime": 1774721028783,
|
|
4
|
+
"buildNumber": 1296,
|
|
5
|
+
"semanticVersion": "0.1.1296",
|
|
6
|
+
"version": "0.1.1296 (2026-03-28T18:03)"
|
|
7
7
|
}
|
|
@@ -170,6 +170,56 @@ npx jest app/hooks/useCounter.ts # Run specific test file
|
|
|
170
170
|
|
|
171
171
|
The Jest config is in `package.json`. The `transformIgnorePatterns` is pre-configured to handle Expo and React Native module transforms — you should not need to modify it.
|
|
172
172
|
|
|
173
|
+
## Building for a Real iOS Device
|
|
174
|
+
|
|
175
|
+
### Prerequisites
|
|
176
|
+
|
|
177
|
+
- **Xcode 16.x** (Xcode 16.4 or later recommended)
|
|
178
|
+
- **Apple Developer account** (free is fine for personal devices)
|
|
179
|
+
- Device connected via USB or on the same Wi-Fi network
|
|
180
|
+
|
|
181
|
+
### Steps
|
|
182
|
+
|
|
183
|
+
1. Generate the native iOS project:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx expo prebuild --clean
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
2. Add Swift 5 enforcement to the generated Podfile. Open `ios/Podfile` and add this inside the `post_install` block, after `react_native_post_install(...)`:
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
# Fix Swift 6.1 (Xcode 16.4) strict concurrency errors
|
|
193
|
+
installer.pods_project.targets.each do |target|
|
|
194
|
+
target.build_configurations.each do |config|
|
|
195
|
+
config.build_settings['SWIFT_VERSION'] = '5.0'
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
3. Reinstall pods with the fix:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd ios && pod install && cd ..
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
4. Build and run on your device:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npx expo run:ios --device
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Troubleshooting
|
|
213
|
+
|
|
214
|
+
- **"Missing factory in ExpoAppDelegate"** crash: The native project is stale. Run `npx expo prebuild --clean` to regenerate it.
|
|
215
|
+
- **"ambiguous implicit access level for import"** error: The `patch-package` fix wasn't applied. Run `npm install` to reapply, then `cd ios && pod install`.
|
|
216
|
+
- **"No script URL provided"**: Metro bundler isn't running or the device can't reach it. Start Metro with `npx expo start` in a separate terminal. Your phone and Mac must be on the same Wi-Fi network.
|
|
217
|
+
|
|
218
|
+
### Notes
|
|
219
|
+
|
|
220
|
+
- The `ios/` and `android/` directories are gitignored — they're generated by `expo prebuild` and shouldn't be committed.
|
|
221
|
+
- The `patches/` directory IS committed — it contains a fix for Xcode 16.4 Swift compatibility that auto-applies on `npm install`.
|
|
222
|
+
|
|
173
223
|
## Web vs Native Differences
|
|
174
224
|
|
|
175
225
|
The CodeYam editor previews your app via **Expo Web** (react-native-web in a browser). Some differences from native iOS/Android devices are expected:
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import '../global.css';
|
|
2
2
|
import { Stack } from 'expo-router';
|
|
3
3
|
import { StatusBar } from 'expo-status-bar';
|
|
4
|
-
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
4
|
+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
5
5
|
|
|
6
6
|
export default function RootLayout() {
|
|
7
7
|
return (
|
|
8
8
|
<SafeAreaProvider>
|
|
9
|
-
<
|
|
9
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
10
|
+
<Stack screenOptions={{ headerShown: false }} />
|
|
11
|
+
</SafeAreaView>
|
|
10
12
|
<StatusBar style="auto" />
|
|
11
13
|
</SafeAreaProvider>
|
|
12
14
|
);
|
|
@@ -7,42 +7,47 @@
|
|
|
7
7
|
"setup": "npm install",
|
|
8
8
|
"dev": "expo start --web",
|
|
9
9
|
"start": "expo start",
|
|
10
|
-
"android": "expo
|
|
11
|
-
"ios": "expo
|
|
10
|
+
"android": "expo run:android",
|
|
11
|
+
"ios": "expo run:ios",
|
|
12
12
|
"build:web": "expo export --platform web",
|
|
13
|
-
"test": "jest"
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"postinstall": "patch-package"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
|
-
"expo": "~
|
|
17
|
-
"expo-router": "~
|
|
18
|
-
"expo-status-bar": "~
|
|
19
|
-
"expo-linking": "~
|
|
20
|
-
"expo-constants": "~
|
|
21
|
-
"expo-font": "~
|
|
22
|
-
"react": "19.
|
|
23
|
-
"react-dom": "19.
|
|
24
|
-
"react-native": "0.
|
|
17
|
+
"expo": "~54.0.0",
|
|
18
|
+
"expo-router": "~6.0.23",
|
|
19
|
+
"expo-status-bar": "~3.0.9",
|
|
20
|
+
"expo-linking": "~8.0.11",
|
|
21
|
+
"expo-constants": "~18.0.13",
|
|
22
|
+
"expo-font": "~14.0.11",
|
|
23
|
+
"react": "19.1.0",
|
|
24
|
+
"react-dom": "19.1.0",
|
|
25
|
+
"react-native": "0.81.5",
|
|
25
26
|
"react-native-web": "^0.21.0",
|
|
26
27
|
"react-native-safe-area-context": "~5.6.2",
|
|
27
|
-
"react-native-screens": "~4.
|
|
28
|
+
"react-native-screens": "~4.16.0",
|
|
29
|
+
"react-native-reanimated": "^4.3.0",
|
|
30
|
+
"react-native-worklets": "^0.8.1",
|
|
31
|
+
"react-refresh": "^0.18.0",
|
|
28
32
|
"@react-navigation/native": "^7.1.33",
|
|
29
33
|
"@expo/vector-icons": "^15.0.2",
|
|
30
34
|
"@react-native-async-storage/async-storage": "2.2.0",
|
|
31
35
|
"nativewind": "^4.2.2",
|
|
32
|
-
"tailwindcss": "^3.4.19"
|
|
36
|
+
"tailwindcss": "^3.4.19",
|
|
37
|
+
"patch-package": "^8.0.0"
|
|
33
38
|
},
|
|
34
39
|
"devDependencies": {
|
|
35
|
-
"@types/react": "~19.
|
|
36
|
-
"babel-preset-expo": "
|
|
40
|
+
"@types/react": "~19.1.10",
|
|
41
|
+
"babel-preset-expo": "~54.0.10",
|
|
37
42
|
"typescript": "~5.9.2",
|
|
38
43
|
"jest": "^29.7.0",
|
|
39
|
-
"jest-expo": "~
|
|
44
|
+
"jest-expo": "~54.0.17",
|
|
40
45
|
"@testing-library/react-native": "^13.2.0"
|
|
41
46
|
},
|
|
42
47
|
"jest": {
|
|
43
48
|
"preset": "jest-expo",
|
|
44
49
|
"transformIgnorePatterns": [
|
|
45
|
-
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|nativewind)"
|
|
50
|
+
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|nativewind|react-native-reanimated|react-native-worklets)"
|
|
46
51
|
]
|
|
47
52
|
}
|
|
48
53
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
diff --git a/node_modules/expo-modules-autolinking/build/platforms/apple/apple.js b/node_modules/expo-modules-autolinking/build/platforms/apple/apple.js
|
|
2
|
+
index 47487c0..58a6069 100644
|
|
3
|
+
--- a/node_modules/expo-modules-autolinking/build/platforms/apple/apple.js
|
|
4
|
+
+++ b/node_modules/expo-modules-autolinking/build/platforms/apple/apple.js
|
|
5
|
+
@@ -113,7 +113,7 @@ async function generatePackageListFileContentAsync(modules, className, entitleme
|
|
6
|
+
* but only these that are written in Swift and use the new API for creating Expo modules.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
-import ExpoModulesCore
|
|
10
|
+
+public import ExpoModulesCore
|
|
11
|
+
${generateCommonImportList(swiftModules)}
|
|
12
|
+
${generateDebugOnlyImportList(debugOnlySwiftModules)}
|
|
13
|
+
@objc(${className})
|
|
14
|
+
@@ -137,13 +137,13 @@ ${generateReactDelegateHandlers(reactDelegateHandlerModules, debugOnlyReactDeleg
|
|
15
|
+
`;
|
|
16
|
+
}
|
|
17
|
+
function generateCommonImportList(swiftModules) {
|
|
18
|
+
- return swiftModules.map((moduleName) => `import ${moduleName}`).join('\n');
|
|
19
|
+
+ return swiftModules.map((moduleName) => `public import ${moduleName}`).join('\n');
|
|
20
|
+
}
|
|
21
|
+
function generateDebugOnlyImportList(swiftModules) {
|
|
22
|
+
if (!swiftModules.length) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
- return (wrapInDebugConfigurationCheck(0, swiftModules.map((moduleName) => `import ${moduleName}`).join('\n')) + '\n');
|
|
26
|
+
+ return (wrapInDebugConfigurationCheck(0, swiftModules.map((moduleName) => `public import ${moduleName}`).join('\n')) + '\n');
|
|
27
|
+
}
|
|
28
|
+
function generateModuleClasses(classNames, debugOnlyClassName) {
|
|
29
|
+
const commonClassNames = formatArrayOfClassNames(classNames);
|
|
@@ -109,22 +109,42 @@ function getProjectRef(): string {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Build a mapping from lowercased seed-data keys to actual PostgreSQL table names.
|
|
114
|
+
* Prisma creates tables with the model name (PascalCase) unless @@map is used.
|
|
115
|
+
* PostgREST requires the exact table name, so we need this translation.
|
|
116
|
+
*/
|
|
117
|
+
function buildTableNameMap(): Record<string, string> {
|
|
118
|
+
const map: Record<string, string> = {};
|
|
119
|
+
for (const model of Prisma.dmmf.datamodel.models) {
|
|
120
|
+
// dbName is set when @@map is used, otherwise null → use model name
|
|
121
|
+
const dbName = (model as any).dbName || model.name;
|
|
122
|
+
// Map lowercased model name → actual table name
|
|
123
|
+
const lowered = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
124
|
+
map[lowered] = dbName;
|
|
125
|
+
map[model.name] = dbName; // Also map PascalCase for safety
|
|
126
|
+
}
|
|
127
|
+
return map;
|
|
128
|
+
}
|
|
129
|
+
|
|
112
130
|
async function seedTables(seed: Record<string, unknown[]>) {
|
|
113
131
|
if (Object.keys(seed).length === 0) return;
|
|
114
132
|
|
|
133
|
+
const tableMap = buildTableNameMap();
|
|
134
|
+
|
|
115
135
|
// Discover ALL models from the Prisma schema — not just the tables in the seed data.
|
|
116
136
|
// This ensures FK-dependent tables are cleared even when the seed only contains
|
|
117
137
|
// the parent table's data. Every editor project has Prisma installed.
|
|
118
|
-
const
|
|
119
|
-
(m) => m
|
|
138
|
+
const allTables = Prisma.dmmf.datamodel.models.map(
|
|
139
|
+
(m) => (m as any).dbName || m.name,
|
|
120
140
|
);
|
|
121
141
|
|
|
122
142
|
console.log(
|
|
123
|
-
`Clearing ${
|
|
143
|
+
`Clearing ${allTables.length} tables, seeding: ${Object.keys(seed).join(', ')}`,
|
|
124
144
|
);
|
|
125
145
|
|
|
126
146
|
// Clear ALL tables in reverse order (children before parents for FK safety)
|
|
127
|
-
for (const table of [...
|
|
147
|
+
for (const table of [...allTables].reverse()) {
|
|
128
148
|
const { error } = await supabase.from(table).delete().gte('id', 0);
|
|
129
149
|
if (error) {
|
|
130
150
|
const { error: error2 } = await supabase
|
|
@@ -141,9 +161,10 @@ async function seedTables(seed: Record<string, unknown[]>) {
|
|
|
141
161
|
}
|
|
142
162
|
}
|
|
143
163
|
|
|
144
|
-
// Insert seed data
|
|
145
|
-
for (const [
|
|
164
|
+
// Insert seed data — translate seed keys to actual table names
|
|
165
|
+
for (const [seedKey, rows] of Object.entries(seed)) {
|
|
146
166
|
if (!Array.isArray(rows) || rows.length === 0) continue;
|
|
167
|
+
const table = tableMap[seedKey] || seedKey;
|
|
147
168
|
const { error } = await supabase.from(table).insert(rows);
|
|
148
169
|
if (error) {
|
|
149
170
|
console.error(` Failed to seed ${table}: ${error.message}`);
|
|
@@ -153,6 +174,42 @@ async function seedTables(seed: Record<string, unknown[]>) {
|
|
|
153
174
|
}
|
|
154
175
|
}
|
|
155
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Build a minimal JWT with a far-future expiry.
|
|
179
|
+
* The signature is fake — it doesn't matter because the CodeYam preload module
|
|
180
|
+
* intercepts the Supabase auth validation endpoint and returns mock data.
|
|
181
|
+
*/
|
|
182
|
+
function buildFakeJwt(userId: string, email: string): string {
|
|
183
|
+
const header = { alg: 'HS256', typ: 'JWT' };
|
|
184
|
+
const payload = {
|
|
185
|
+
sub: userId,
|
|
186
|
+
email,
|
|
187
|
+
role: 'authenticated',
|
|
188
|
+
aud: 'authenticated',
|
|
189
|
+
exp: 9999999999,
|
|
190
|
+
iat: Math.floor(Date.now() / 1000),
|
|
191
|
+
};
|
|
192
|
+
const encode = (obj: object) =>
|
|
193
|
+
Buffer.from(JSON.stringify(obj)).toString('base64url');
|
|
194
|
+
return `${encode(header)}.${encode(payload)}.codeyam-mock-signature`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Build a Supabase user response object matching the /auth/v1/user endpoint format.
|
|
199
|
+
*/
|
|
200
|
+
function buildUserResponse(user: { id: string; email?: string }) {
|
|
201
|
+
return {
|
|
202
|
+
id: user.id,
|
|
203
|
+
aud: 'authenticated',
|
|
204
|
+
role: 'authenticated',
|
|
205
|
+
email: user.email || '',
|
|
206
|
+
email_confirmed_at: new Date().toISOString(),
|
|
207
|
+
app_metadata: { provider: 'email', providers: ['email'] },
|
|
208
|
+
user_metadata: {},
|
|
209
|
+
created_at: new Date().toISOString(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
156
213
|
/**
|
|
157
214
|
* Handle auth: create user, sign in, write session cookies.
|
|
158
215
|
* Returns the user ID so callers can replace __AUTH_USER_ID__ placeholders in seed data.
|
|
@@ -211,7 +268,13 @@ async function handleAuth(auth: {
|
|
|
211
268
|
const userId = signInData.user.id;
|
|
212
269
|
console.log(` Signed in as ${email} (user: ${userId})`);
|
|
213
270
|
|
|
214
|
-
//
|
|
271
|
+
// Use the REAL JWT from Supabase sign-in for the session cookie so auth
|
|
272
|
+
// works immediately against the real Supabase API. The externalApis below
|
|
273
|
+
// provide a fallback for when the CLI supports preload-based auth
|
|
274
|
+
// interception (no real Supabase calls needed at render time).
|
|
275
|
+
const fakeJwt = buildFakeJwt(userId, email);
|
|
276
|
+
const userResponse = buildUserResponse(signInData.user);
|
|
277
|
+
|
|
215
278
|
const projectRef = getProjectRef();
|
|
216
279
|
const sessionOutput = {
|
|
217
280
|
cookies: [
|
|
@@ -228,13 +291,33 @@ async function handleAuth(auth: {
|
|
|
228
291
|
sameSite: 'Lax' as const,
|
|
229
292
|
},
|
|
230
293
|
],
|
|
294
|
+
// External API mocks — when the CLI supports propagating these, the
|
|
295
|
+
// preload module will intercept server-side getUser() calls so Next.js
|
|
296
|
+
// middleware returns the mock user without hitting real Supabase.
|
|
297
|
+
externalApis: {
|
|
298
|
+
[`${supabaseUrl}/auth/v1/user`]: {
|
|
299
|
+
body: userResponse,
|
|
300
|
+
status: 200,
|
|
301
|
+
},
|
|
302
|
+
[`${supabaseUrl}/auth/v1/token`]: {
|
|
303
|
+
body: {
|
|
304
|
+
access_token: fakeJwt,
|
|
305
|
+
token_type: 'bearer',
|
|
306
|
+
expires_in: 315360000,
|
|
307
|
+
expires_at: 9999999999,
|
|
308
|
+
refresh_token: 'codeyam-mock-refresh-token',
|
|
309
|
+
user: userResponse,
|
|
310
|
+
},
|
|
311
|
+
status: 200,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
231
314
|
};
|
|
232
315
|
|
|
233
316
|
const outputDir = path.join(process.cwd(), '.codeyam', 'tmp');
|
|
234
317
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
235
318
|
const outputPath = path.join(outputDir, 'seed-session.json');
|
|
236
319
|
fs.writeFileSync(outputPath, JSON.stringify(sessionOutput, null, 2));
|
|
237
|
-
console.log(` Session cookies written to ${outputPath}`);
|
|
320
|
+
console.log(` Session cookies + auth mocks written to ${outputPath}`);
|
|
238
321
|
|
|
239
322
|
return userId;
|
|
240
323
|
}
|