@codeyam/codeyam-cli 0.1.0-staging.2ea44f6 → 0.1.0-staging.3ef993e
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 +8 -8
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +1 -1
- package/analyzer-template/packages/aws/package.json +1 -1
- package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +73 -0
- package/analyzer-template/packages/database/src/lib/loadEntities.ts +0 -6
- package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +0 -65
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +6 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +73 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +0 -6
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +0 -25
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts +2 -0
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
- package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
- package/analyzer-template/packages/ui-components/package.json +1 -1
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
- package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +45 -0
- package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +101 -47
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
- package/codeyam-cli/src/commands/editor.js +1265 -213
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/commands/init.js +67 -34
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/data/techStacks.js +77 -0
- package/codeyam-cli/src/data/techStacks.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js +173 -0
- package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js +46 -0
- package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +508 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +152 -3
- package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js +140 -12
- package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +238 -2
- package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +128 -1
- package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +191 -5
- package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +153 -0
- package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +139 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +221 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +887 -2
- package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +213 -0
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +289 -40
- package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +107 -0
- package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +129 -0
- package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js +227 -0
- package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +426 -218
- package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +13 -5
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +51 -0
- package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +142 -0
- package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
- package/codeyam-cli/src/utils/analyzer.js +9 -0
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/analyzerFinalization.js +100 -0
- package/codeyam-cli/src/utils/analyzerFinalization.js.map +1 -0
- package/codeyam-cli/src/utils/backgroundServer.js +92 -16
- package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/utils/database.js +37 -2
- package/codeyam-cli/src/utils/database.js.map +1 -1
- package/codeyam-cli/src/utils/editorAudit.js +91 -3
- package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
- package/codeyam-cli/src/utils/editorDevServer.js +89 -1
- package/codeyam-cli/src/utils/editorDevServer.js.map +1 -1
- package/codeyam-cli/src/utils/editorImageVerifier.js +45 -10
- package/codeyam-cli/src/utils/editorImageVerifier.js.map +1 -1
- package/codeyam-cli/src/utils/editorJournal.js +78 -3
- package/codeyam-cli/src/utils/editorJournal.js.map +1 -1
- package/codeyam-cli/src/utils/editorLoaderHelpers.js +32 -0
- package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -1
- package/codeyam-cli/src/utils/editorPreview.js +43 -2
- package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
- package/codeyam-cli/src/utils/editorScenarioSwitch.js +112 -0
- package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -0
- package/codeyam-cli/src/utils/editorScenarios.js +291 -0
- package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
- package/codeyam-cli/src/utils/editorSeedAdapter.js +173 -0
- package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -0
- package/codeyam-cli/src/utils/entityChangeStatus.js +42 -19
- package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -1
- package/codeyam-cli/src/utils/entityChangeStatus.server.js +56 -5
- package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -1
- package/codeyam-cli/src/utils/parseRegisterArg.js +31 -0
- package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -0
- package/codeyam-cli/src/utils/progress.js +2 -2
- package/codeyam-cli/src/utils/progress.js.map +1 -1
- package/codeyam-cli/src/utils/scenarioCoverage.js +75 -0
- package/codeyam-cli/src/utils/scenarioCoverage.js.map +1 -0
- package/codeyam-cli/src/utils/scenariosManifest.js +204 -75
- package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -1
- package/codeyam-cli/src/utils/serverState.js +30 -0
- package/codeyam-cli/src/utils/serverState.js.map +1 -1
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +13 -5
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
- package/codeyam-cli/src/utils/simulationGateMiddleware.js +8 -1
- package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
- package/codeyam-cli/src/utils/slugUtils.js +25 -0
- package/codeyam-cli/src/utils/slugUtils.js.map +1 -0
- package/codeyam-cli/src/utils/syncMocksMiddleware.js +2 -2
- package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
- package/codeyam-cli/src/utils/webappDetection.js +21 -0
- package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js +40 -0
- package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +567 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +146 -0
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.js +65 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -0
- package/codeyam-cli/src/webserver/app/lib/git.js +3 -2
- package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-DmJveP3T.js → CopyButton-BPXZwM4t.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-BcgbViKV.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-CQIG2qda.js} +9 -9
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-BzHcG7SE.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-ZlRKbhrq.js → ScenarioViewer-TSD3C211.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-DLxKhri3.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-BcY3q6nt.js} +6 -6
- package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-Bni3iiUj.js} +5 -5
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-project-info-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-coverage-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-BYOypzCa.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-C_Pmso5S.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-BVMi9VA5.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-n2FB0_Sw.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CC6AbExI.js +41 -0
- package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-CltMNppm.js → dev.empty-Ii3inc0_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor-COWCNVyV.js +10 -0
- package/codeyam-cli/src/webserver/build/client/assets/editorPreview-CNB06EIa.js +41 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-DItJnD8s.js → entity._sha._-DwCV5__E.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.dev-CCa2trIL.js → entity._sha.scenarios._scenarioId.dev-CXSi2aeZ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-CHMiAog3.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{files-DO4CZ16O.js → files-BZrlFE1F.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{git-CdN8sCqs.js → git-DdZcvjGh.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-phvmGvat.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-DaAZ_H2w.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/manifest-6134dc40.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-9gnxSZlb.js +101 -0
- package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-f5-1lKBt.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/root-BWAyuj0r.js +67 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-Di64LWVb.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{settings-DfuTtcJP.js → settings-0OrEMU6J.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-B3aOzpCZ.js → simulations-DWT-CvLy.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-Br7MOqts.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-BLdiCuG-.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-C-_hOl_g.js +1 -0
- package/codeyam-cli/src/webserver/build/client/sound-test.html +98 -0
- package/codeyam-cli/src/webserver/build/server/assets/index-ChX0hPcu.js +1 -0
- package/codeyam-cli/src/webserver/build/server/assets/init-kSNsMjj8.js +10 -0
- package/codeyam-cli/src/webserver/build/server/assets/server-build-Bm2xIhmh.js +439 -0
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/src/webserver/editorProxy.js +487 -17
- package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
- package/codeyam-cli/src/webserver/idleDetector.js +73 -0
- package/codeyam-cli/src/webserver/idleDetector.js.map +1 -0
- package/codeyam-cli/src/webserver/public/sound-test.html +98 -0
- package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +21 -3
- package/codeyam-cli/src/webserver/scripts/journalCapture.ts +94 -4
- package/codeyam-cli/src/webserver/server.js +59 -34
- package/codeyam-cli/src/webserver/server.js.map +1 -1
- package/codeyam-cli/src/webserver/terminalServer.js +64 -32
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
- package/codeyam-cli/templates/chrome-extension-react/README.md +46 -0
- package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
- package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
- package/codeyam-cli/templates/chrome-extension-react/package.json +27 -0
- package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
- package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
- package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
- package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
- package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
- package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
- package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
- package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
- package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +41 -0
- package/codeyam-cli/templates/codeyam-editor-claude.md +84 -5
- package/codeyam-cli/templates/editor-step-hook.py +37 -8
- package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +89 -0
- package/codeyam-cli/templates/expo-react-native/README.md +41 -0
- package/codeyam-cli/templates/expo-react-native/app/(tabs)/_layout.tsx +33 -0
- package/codeyam-cli/templates/expo-react-native/app/(tabs)/index.tsx +12 -0
- package/codeyam-cli/templates/expo-react-native/app/(tabs)/settings.tsx +12 -0
- package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +12 -0
- package/codeyam-cli/templates/expo-react-native/app.json +18 -0
- package/codeyam-cli/templates/expo-react-native/babel.config.js +9 -0
- package/codeyam-cli/templates/expo-react-native/gitignore +12 -0
- package/codeyam-cli/templates/expo-react-native/global.css +3 -0
- package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
- package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
- package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
- package/codeyam-cli/templates/expo-react-native/package.json +38 -0
- package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
- package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +126 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/README.md +53 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
- package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +1 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +1 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
- package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +92 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/README.md +52 -0
- package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +37 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
- package/codeyam-cli/templates/skills/codeyam-dev-mode/SKILL.md +1 -1
- package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +28 -9
- package/package.json +1 -1
- package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +73 -0
- package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
- package/packages/database/src/lib/loadEntities.js +0 -6
- package/packages/database/src/lib/loadEntities.js.map +1 -1
- package/packages/database/src/lib/updateCommitMetadata.js +0 -25
- package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/packages/types/src/enums/ProjectFramework.js +2 -0
- package/packages/types/src/enums/ProjectFramework.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
- package/codeyam-cli/src/webserver/build/client/assets/editor-Rfq_y0VR.js +0 -10
- package/codeyam-cli/src/webserver/build/client/assets/editorPreview-GNwaLSmC.js +0 -41
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-CF164ouH.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/globals-Bd0cs8vw.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-9ab0aba3.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-Dg0mvYrI.js +0 -96
- package/codeyam-cli/src/webserver/build/client/assets/root-3ciuWk-c.js +0 -67
- package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-CrAK28Bc.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/index-DCxIbVvl.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-E-peu3XZ.js +0 -367
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{aw as Z,ax as _,am as $,an as rr,au as tr,ao as or,aq as ir,ar as pr,at as mr,as as ar,av as sr,ap as er}from"./assets/server-build-Bm2xIhmh.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-13T16:47:36.668Z",
|
|
3
|
+
"buildTime": 1773420456668,
|
|
4
|
+
"buildNumber": 1005,
|
|
5
|
+
"semanticVersion": "0.1.1005",
|
|
6
|
+
"version": "0.1.1005 (2026-03-13T16:47)"
|
|
7
7
|
}
|
|
@@ -4,10 +4,144 @@ import fs from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { getProjectRoot } from "../state.js";
|
|
6
6
|
import { createMockStateManager, } from "../utils/editorMockState.js";
|
|
7
|
+
import { computeEditorPorts } from "../utils/editorDevServer.js";
|
|
8
|
+
/**
|
|
9
|
+
* Normalize a target URL by stripping trailing slashes for consistency.
|
|
10
|
+
*
|
|
11
|
+
* Previously this also replaced `localhost` with `127.0.0.1`, but that broke
|
|
12
|
+
* forwarding to dev servers that bind to IPv6 only (e.g. Vite 6 on macOS
|
|
13
|
+
* binds to `[::1]`). The hostname is now left as-is — `resolveLoopbackAddress`
|
|
14
|
+
* probes the actual target at startup to pick the right address.
|
|
15
|
+
*/
|
|
16
|
+
export function normalizeTargetUrl(url) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = new URL(url);
|
|
19
|
+
return parsed.toString().replace(/\/$/, '');
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return url;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Probe a localhost port to determine the correct loopback address.
|
|
27
|
+
* Dev servers may bind to IPv4 (127.0.0.1), IPv6 (::1), or both.
|
|
28
|
+
* Returns the first address that accepts a TCP connection.
|
|
29
|
+
*/
|
|
30
|
+
export async function resolveLoopbackAddress(port) {
|
|
31
|
+
const candidates = ['127.0.0.1', '::1'];
|
|
32
|
+
for (const host of candidates) {
|
|
33
|
+
try {
|
|
34
|
+
const connected = await new Promise((resolve) => {
|
|
35
|
+
const socket = new net.Socket();
|
|
36
|
+
socket.setTimeout(1000);
|
|
37
|
+
socket.once('connect', () => {
|
|
38
|
+
socket.destroy();
|
|
39
|
+
resolve(true);
|
|
40
|
+
});
|
|
41
|
+
socket.once('error', () => {
|
|
42
|
+
socket.destroy();
|
|
43
|
+
resolve(false);
|
|
44
|
+
});
|
|
45
|
+
socket.once('timeout', () => {
|
|
46
|
+
socket.destroy();
|
|
47
|
+
resolve(false);
|
|
48
|
+
});
|
|
49
|
+
socket.connect(port, host);
|
|
50
|
+
});
|
|
51
|
+
if (connected) {
|
|
52
|
+
return host;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Try next candidate
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
7
61
|
// Global key so the proxy survives HMR
|
|
8
62
|
const GLOBAL_KEY = '__codeyam_editor_proxy__';
|
|
63
|
+
// ─── Live Preview Health ─────────────────────────────────────────────
|
|
64
|
+
const PREVIEW_HEALTH_KEY = '__codeyam_preview_health__';
|
|
65
|
+
function getPreviewHealth() {
|
|
66
|
+
return globalThis[PREVIEW_HEALTH_KEY] ?? null;
|
|
67
|
+
}
|
|
68
|
+
function setPreviewHealth(report) {
|
|
69
|
+
globalThis[PREVIEW_HEALTH_KEY] = report;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the current live preview health report (read by API endpoint).
|
|
73
|
+
*/
|
|
74
|
+
export function getPreviewHealthReport() {
|
|
75
|
+
return getPreviewHealth();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Reset preview health state (called when a new HTML page is served).
|
|
79
|
+
*/
|
|
80
|
+
export function resetPreviewHealth() {
|
|
81
|
+
setPreviewHealth(null);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Error-catching script injected into HTML responses.
|
|
85
|
+
* Uses vanilla JS for maximum compatibility.
|
|
86
|
+
*/
|
|
87
|
+
export const PREVIEW_HEALTH_SCRIPT = `<script data-codeyam-health>
|
|
88
|
+
(function() {
|
|
89
|
+
var errors = [];
|
|
90
|
+
var reported = false;
|
|
91
|
+
function report(type, msg, stack) {
|
|
92
|
+
errors.push({ type: type, message: msg, stack: stack, timestamp: Date.now() });
|
|
93
|
+
if (!reported) {
|
|
94
|
+
reported = true;
|
|
95
|
+
setTimeout(function() { flush(); }, 500);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function flush() {
|
|
99
|
+
fetch('/__codeyam__/preview-health', {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: { 'Content-Type': 'application/json' },
|
|
102
|
+
body: JSON.stringify({ errors: errors, url: location.href })
|
|
103
|
+
}).catch(function(){});
|
|
104
|
+
reported = false;
|
|
105
|
+
errors = [];
|
|
106
|
+
}
|
|
107
|
+
window.addEventListener('error', function(e) {
|
|
108
|
+
report('error', e.message, e.error && e.error.stack);
|
|
109
|
+
});
|
|
110
|
+
window.addEventListener('unhandledrejection', function(e) {
|
|
111
|
+
report('unhandledrejection', String(e.reason), e.reason && e.reason.stack);
|
|
112
|
+
});
|
|
113
|
+
var origError = console.error;
|
|
114
|
+
console.error = function() {
|
|
115
|
+
report('console.error', Array.prototype.join.call(arguments, ' '));
|
|
116
|
+
origError.apply(console, arguments);
|
|
117
|
+
};
|
|
118
|
+
window.addEventListener('load', function() {
|
|
119
|
+
setTimeout(function() {
|
|
120
|
+
var hasContent = document.body && document.body.innerText.trim().length > 0;
|
|
121
|
+
fetch('/__codeyam__/preview-health', {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { 'Content-Type': 'application/json' },
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
loaded: true,
|
|
126
|
+
hasContent: hasContent,
|
|
127
|
+
url: location.href,
|
|
128
|
+
errorCount: errors.length
|
|
129
|
+
})
|
|
130
|
+
}).catch(function(){});
|
|
131
|
+
}, 1000);
|
|
132
|
+
});
|
|
133
|
+
})();
|
|
134
|
+
</script>`;
|
|
9
135
|
const CACHE_TTL_MS = 500;
|
|
10
136
|
let scenarioCache = { data: null, timestamp: 0 };
|
|
137
|
+
// Session config extracted from the active scenario — drives cookie injection
|
|
138
|
+
let sessionConfig = undefined;
|
|
139
|
+
// localStorage config extracted from the active scenario — drives HTML injection
|
|
140
|
+
let localStorageConfig = null;
|
|
141
|
+
// Active scenario ID — used to gate localStorage seeding (only re-seed on switch)
|
|
142
|
+
let activeScenarioId = null;
|
|
143
|
+
// Prototype ID — used to gate a one-time localStorage.clear() when a new project is scaffolded
|
|
144
|
+
let currentPrototypeId = null;
|
|
11
145
|
// Max body size to buffer for mock matching (10MB)
|
|
12
146
|
const MAX_BODY_SIZE = 10 * 1024 * 1024;
|
|
13
147
|
function getProxyState() {
|
|
@@ -38,6 +172,12 @@ export function getProxyUrl() {
|
|
|
38
172
|
/**
|
|
39
173
|
* Read the active scenario's mock data from disk, with brief caching.
|
|
40
174
|
* Feeds the data into the MockStateManager.
|
|
175
|
+
*
|
|
176
|
+
* For application/user scenarios (type-aware): only loads `externalApis`
|
|
177
|
+
* into the mock state manager. All DB-backed routes flow through to the
|
|
178
|
+
* real app (database is seeded with real data).
|
|
179
|
+
*
|
|
180
|
+
* For component scenarios (or legacy): loads all routes as before.
|
|
41
181
|
*/
|
|
42
182
|
function readScenarioData() {
|
|
43
183
|
const now = Date.now();
|
|
@@ -55,6 +195,8 @@ function readScenarioData() {
|
|
|
55
195
|
const active = JSON.parse(fs.readFileSync(activeScenarioPath, 'utf-8'));
|
|
56
196
|
const scenarioId = active.scenarioId;
|
|
57
197
|
if (!scenarioId) {
|
|
198
|
+
// No active scenario — but may have a prototypeId for localStorage clearing
|
|
199
|
+
currentPrototypeId = active.prototypeId || null;
|
|
58
200
|
scenarioCache = { data: null, timestamp: now };
|
|
59
201
|
return null;
|
|
60
202
|
}
|
|
@@ -64,11 +206,34 @@ function readScenarioData() {
|
|
|
64
206
|
scenarioCache = { data: null, timestamp: now };
|
|
65
207
|
return null;
|
|
66
208
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
209
|
+
const rawData = JSON.parse(fs.readFileSync(dataFilePath, 'utf-8'));
|
|
210
|
+
// Extract session config for cookie injection
|
|
211
|
+
sessionConfig = rawData.session || null;
|
|
212
|
+
// Extract localStorage config for HTML injection
|
|
213
|
+
localStorageConfig = rawData.localStorage || null;
|
|
214
|
+
activeScenarioId = scenarioId;
|
|
215
|
+
// Type-aware: for seed-based scenarios, only serve externalApis via proxy
|
|
216
|
+
const scenarioType = active.type || rawData.type || null;
|
|
217
|
+
let mockData;
|
|
218
|
+
if ((scenarioType === 'application' || scenarioType === 'user') &&
|
|
219
|
+
rawData.seed) {
|
|
220
|
+
// Seed-based scenario: only load externalApis as routes for the proxy
|
|
221
|
+
if (rawData.externalApis && typeof rawData.externalApis === 'object') {
|
|
222
|
+
mockData = { routes: rawData.externalApis };
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// No external APIs — proxy passes everything through
|
|
226
|
+
mockData = {};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Component/legacy scenario: load all data
|
|
231
|
+
mockData = rawData;
|
|
232
|
+
}
|
|
233
|
+
scenarioCache = { data: mockData, timestamp: now };
|
|
69
234
|
// Feed into mock state manager (smart reload handles dedup)
|
|
70
|
-
getMockStateManager().loadScenario(
|
|
71
|
-
return
|
|
235
|
+
getMockStateManager().loadScenario(mockData);
|
|
236
|
+
return mockData;
|
|
72
237
|
}
|
|
73
238
|
catch (err) {
|
|
74
239
|
console.warn('[editorProxy] Error reading scenario data:', err);
|
|
@@ -104,26 +269,67 @@ function bufferRequestBody(req) {
|
|
|
104
269
|
});
|
|
105
270
|
});
|
|
106
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Strip IPv6 bracket notation for use with http.request hostname.
|
|
274
|
+
* URL.hostname returns `[::1]` for IPv6 but http.request needs `::1`.
|
|
275
|
+
*/
|
|
276
|
+
function stripIPv6Brackets(hostname) {
|
|
277
|
+
if (hostname.startsWith('[') && hostname.endsWith(']')) {
|
|
278
|
+
return hostname.slice(1, -1);
|
|
279
|
+
}
|
|
280
|
+
return hostname;
|
|
281
|
+
}
|
|
107
282
|
/**
|
|
108
283
|
* Forward a buffered request to the target dev server.
|
|
109
284
|
* Unlike the streaming forwardRequest, this replays a buffered body.
|
|
110
285
|
*/
|
|
111
286
|
function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
|
|
112
287
|
const target = new URL(targetUrl);
|
|
288
|
+
const hostname = stripIPv6Brackets(target.hostname);
|
|
113
289
|
const headers = { ...req.headers, host: `${target.hostname}:${target.port}` };
|
|
290
|
+
// Remove accept-encoding so the dev server returns uncompressed responses.
|
|
291
|
+
// The proxy injects a health script into HTML — this fails on compressed bodies.
|
|
292
|
+
delete headers['accept-encoding'];
|
|
114
293
|
// Update content-length if we have the body buffer
|
|
115
294
|
if (bodyBuffer) {
|
|
116
295
|
headers['content-length'] = String(bodyBuffer.length);
|
|
117
296
|
}
|
|
118
297
|
const options = {
|
|
119
|
-
hostname
|
|
298
|
+
hostname,
|
|
120
299
|
port: target.port,
|
|
121
300
|
path: req.url,
|
|
122
301
|
method: req.method,
|
|
123
302
|
headers,
|
|
124
303
|
};
|
|
125
304
|
const proxyReq = http.request(options, (proxyRes) => {
|
|
126
|
-
|
|
305
|
+
const status = proxyRes.statusCode || 200;
|
|
306
|
+
if (status >= 400) {
|
|
307
|
+
console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
|
|
308
|
+
}
|
|
309
|
+
const headers = { ...proxyRes.headers };
|
|
310
|
+
injectSessionCookie(headers);
|
|
311
|
+
// Check if response is HTML — if so, buffer and inject health script
|
|
312
|
+
const contentType = proxyRes.headers['content-type'] || '';
|
|
313
|
+
if (contentType.includes('text/html')) {
|
|
314
|
+
resetPreviewHealth();
|
|
315
|
+
const chunks = [];
|
|
316
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
317
|
+
proxyRes.on('end', () => {
|
|
318
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
319
|
+
const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
|
|
320
|
+
const injected = injectHealthScript(body, lsScript);
|
|
321
|
+
delete headers['content-length'];
|
|
322
|
+
delete headers['content-encoding'];
|
|
323
|
+
// Prevent browser from caching HTML responses — scenario switches
|
|
324
|
+
// serve different content from the same URL (seed data changes the
|
|
325
|
+
// rendered page but the proxy URL stays the same).
|
|
326
|
+
headers['cache-control'] = 'no-store, must-revalidate';
|
|
327
|
+
res.writeHead(status, headers);
|
|
328
|
+
res.end(injected);
|
|
329
|
+
});
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
res.writeHead(status, headers);
|
|
127
333
|
proxyRes.pipe(res, { end: true });
|
|
128
334
|
});
|
|
129
335
|
proxyReq.on('error', (err) => {
|
|
@@ -141,19 +347,58 @@ function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
|
|
|
141
347
|
}
|
|
142
348
|
}
|
|
143
349
|
/**
|
|
144
|
-
* Forward an HTTP request to the target dev server
|
|
350
|
+
* Forward an HTTP request to the target dev server.
|
|
351
|
+
* For HTML responses: buffers body to inject health-check script.
|
|
352
|
+
* For non-HTML responses: pipes directly (no buffering).
|
|
145
353
|
*/
|
|
146
354
|
function forwardRequest(req, res, targetUrl) {
|
|
147
355
|
const target = new URL(targetUrl);
|
|
356
|
+
const hostname = stripIPv6Brackets(target.hostname);
|
|
357
|
+
// Build headers, stripping accept-encoding so the dev server returns uncompressed
|
|
358
|
+
// responses. The proxy injects a health script into HTML — this fails on compressed bodies.
|
|
359
|
+
const { 'accept-encoding': _ae, ...forwardHeaders } = req.headers;
|
|
148
360
|
const options = {
|
|
149
|
-
hostname
|
|
361
|
+
hostname,
|
|
150
362
|
port: target.port,
|
|
151
363
|
path: req.url,
|
|
152
364
|
method: req.method,
|
|
153
|
-
headers: {
|
|
365
|
+
headers: {
|
|
366
|
+
...forwardHeaders,
|
|
367
|
+
host: `${target.hostname}:${target.port}`,
|
|
368
|
+
},
|
|
154
369
|
};
|
|
155
370
|
const proxyReq = http.request(options, (proxyRes) => {
|
|
156
|
-
|
|
371
|
+
const status = proxyRes.statusCode || 200;
|
|
372
|
+
if (status >= 400) {
|
|
373
|
+
console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
|
|
374
|
+
}
|
|
375
|
+
const headers = { ...proxyRes.headers };
|
|
376
|
+
injectSessionCookie(headers);
|
|
377
|
+
// Check if response is HTML — if so, buffer and inject health script
|
|
378
|
+
const contentType = proxyRes.headers['content-type'] || '';
|
|
379
|
+
if (contentType.includes('text/html')) {
|
|
380
|
+
// Reset health state for new page loads
|
|
381
|
+
resetPreviewHealth();
|
|
382
|
+
const chunks = [];
|
|
383
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
384
|
+
proxyRes.on('end', () => {
|
|
385
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
386
|
+
const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
|
|
387
|
+
const injected = injectHealthScript(body, lsScript);
|
|
388
|
+
// Remove content-length since body size changed; use chunked transfer
|
|
389
|
+
delete headers['content-length'];
|
|
390
|
+
// Remove content-encoding since we're serving uncompressed
|
|
391
|
+
delete headers['content-encoding'];
|
|
392
|
+
// Prevent browser from caching HTML responses — scenario switches
|
|
393
|
+
// serve different content from the same URL (seed data changes the
|
|
394
|
+
// rendered page but the proxy URL stays the same).
|
|
395
|
+
headers['cache-control'] = 'no-store, must-revalidate';
|
|
396
|
+
res.writeHead(status, headers);
|
|
397
|
+
res.end(injected);
|
|
398
|
+
});
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
res.writeHead(status, headers);
|
|
157
402
|
proxyRes.pipe(res, { end: true });
|
|
158
403
|
});
|
|
159
404
|
proxyReq.on('error', (err) => {
|
|
@@ -165,14 +410,166 @@ function forwardRequest(req, res, targetUrl) {
|
|
|
165
410
|
});
|
|
166
411
|
req.pipe(proxyReq, { end: true });
|
|
167
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Inject or clear the session-token cookie on proxied responses.
|
|
415
|
+
* When a scenario has session.cookieValue, sets the cookie to auto-log the user in.
|
|
416
|
+
* When a scenario has no session field (null), clears any existing session cookie.
|
|
417
|
+
* When sessionConfig is undefined (no scenario loaded yet), does nothing.
|
|
418
|
+
*/
|
|
419
|
+
function injectSessionCookie(headers) {
|
|
420
|
+
if (sessionConfig === undefined)
|
|
421
|
+
return;
|
|
422
|
+
let cookie;
|
|
423
|
+
if (sessionConfig?.cookieValue) {
|
|
424
|
+
cookie = `session-token=${sessionConfig.cookieValue}; Path=/; SameSite=Lax`;
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
// No session config — clear any existing session cookie
|
|
428
|
+
cookie = `session-token=; Path=/; Max-Age=0`;
|
|
429
|
+
}
|
|
430
|
+
const existing = headers['set-cookie'];
|
|
431
|
+
if (existing) {
|
|
432
|
+
headers['set-cookie'] = [
|
|
433
|
+
...(Array.isArray(existing) ? existing : [existing]),
|
|
434
|
+
cookie,
|
|
435
|
+
];
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
headers['set-cookie'] = [cookie];
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Get the current session config (for testing).
|
|
443
|
+
*/
|
|
444
|
+
export function getSessionConfig() {
|
|
445
|
+
return sessionConfig;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Get the current localStorage config (for testing and script generation).
|
|
449
|
+
*/
|
|
450
|
+
export function getLocalStorageConfig() {
|
|
451
|
+
return localStorageConfig;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Get the active scenario ID (for testing and script generation).
|
|
455
|
+
*/
|
|
456
|
+
export function getActiveScenarioId() {
|
|
457
|
+
return activeScenarioId;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Get the current prototype ID (for testing).
|
|
461
|
+
*/
|
|
462
|
+
export function getCurrentPrototypeId() {
|
|
463
|
+
return currentPrototypeId;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Build a script tag that seeds localStorage with scenario data on first load.
|
|
467
|
+
* Gated by scenario ID — only seeds when the scenario changes, preserving
|
|
468
|
+
* interactive modifications across page reloads / HMR.
|
|
469
|
+
*
|
|
470
|
+
* Returns empty string if no localStorage config is provided.
|
|
471
|
+
*/
|
|
472
|
+
export function buildLocalStorageScript(localStorageConfig, scenarioId, prototypeId) {
|
|
473
|
+
// null/undefined means no localStorage config at all — but if we have a
|
|
474
|
+
// prototypeId, emit a one-time localStorage.clear() to flush stale data
|
|
475
|
+
// from a previous prototype session.
|
|
476
|
+
if (!localStorageConfig || typeof localStorageConfig !== 'object') {
|
|
477
|
+
if (prototypeId) {
|
|
478
|
+
return `<script data-codeyam-ls>
|
|
479
|
+
(function() {
|
|
480
|
+
if (localStorage.getItem('__codeyam_proto__') === ${JSON.stringify(prototypeId)}) return;
|
|
481
|
+
localStorage.clear();
|
|
482
|
+
localStorage.setItem('__codeyam_proto__', ${JSON.stringify(prototypeId)});
|
|
483
|
+
})();
|
|
484
|
+
</script>`;
|
|
485
|
+
}
|
|
486
|
+
return '';
|
|
487
|
+
}
|
|
488
|
+
// Even an empty object needs a cleanup script — switching from a scenario
|
|
489
|
+
// with localStorage data to one without must clear the previous keys.
|
|
490
|
+
const entries = Object.entries(localStorageConfig);
|
|
491
|
+
const keys = entries.map(([k]) => k);
|
|
492
|
+
// Build setItem calls — stringify non-string values
|
|
493
|
+
const setStatements = entries
|
|
494
|
+
.map(([key, value]) => {
|
|
495
|
+
const serialized = typeof value === 'string' ? value : JSON.stringify(value);
|
|
496
|
+
return `localStorage.setItem(${JSON.stringify(key)}, ${JSON.stringify(serialized)});`;
|
|
497
|
+
})
|
|
498
|
+
.join('\n');
|
|
499
|
+
return `<script data-codeyam-ls>
|
|
500
|
+
(function() {
|
|
501
|
+
if (localStorage.getItem('__codeyam_ls_sid__') === ${JSON.stringify(scenarioId)}) return;
|
|
502
|
+
var prev = JSON.parse(localStorage.getItem('__codeyam_ls_keys__') || '[]');
|
|
503
|
+
for (var i = 0; i < prev.length; i++) localStorage.removeItem(prev[i]);
|
|
504
|
+
${setStatements}
|
|
505
|
+
localStorage.setItem('__codeyam_ls_keys__', ${JSON.stringify(JSON.stringify(keys))});
|
|
506
|
+
localStorage.setItem('__codeyam_ls_sid__', ${JSON.stringify(scenarioId)});
|
|
507
|
+
})();
|
|
508
|
+
</script>`;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Inject the health-check script (and optional localStorage script) into an HTML response body.
|
|
512
|
+
* Inserts before </head> if present, otherwise before </body>, otherwise appends.
|
|
513
|
+
* When a localStorageScript is provided, it's injected BEFORE the health script
|
|
514
|
+
* so localStorage is populated before the app loads.
|
|
515
|
+
*/
|
|
516
|
+
export function injectHealthScript(html, localStorageScript) {
|
|
517
|
+
const scripts = (localStorageScript || '') + PREVIEW_HEALTH_SCRIPT;
|
|
518
|
+
if (html.includes('</head>')) {
|
|
519
|
+
return html.replace('</head>', scripts + '</head>');
|
|
520
|
+
}
|
|
521
|
+
if (html.includes('</body>')) {
|
|
522
|
+
return html.replace('</body>', scripts + '</body>');
|
|
523
|
+
}
|
|
524
|
+
return html + scripts;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Handle POST /__codeyam__/preview-health — store health data in globalThis.
|
|
528
|
+
*/
|
|
529
|
+
function handlePreviewHealthPost(req, res) {
|
|
530
|
+
const chunks = [];
|
|
531
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
532
|
+
req.on('end', () => {
|
|
533
|
+
try {
|
|
534
|
+
const body = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
535
|
+
const current = getPreviewHealth() || {
|
|
536
|
+
errors: [],
|
|
537
|
+
loaded: false,
|
|
538
|
+
hasContent: false,
|
|
539
|
+
url: '',
|
|
540
|
+
lastUpdated: 0,
|
|
541
|
+
};
|
|
542
|
+
if (body.errors && Array.isArray(body.errors)) {
|
|
543
|
+
current.errors = current.errors.concat(body.errors);
|
|
544
|
+
}
|
|
545
|
+
if (body.loaded !== undefined) {
|
|
546
|
+
current.loaded = body.loaded;
|
|
547
|
+
}
|
|
548
|
+
if (body.hasContent !== undefined) {
|
|
549
|
+
current.hasContent = body.hasContent;
|
|
550
|
+
}
|
|
551
|
+
if (body.url) {
|
|
552
|
+
current.url = body.url;
|
|
553
|
+
}
|
|
554
|
+
current.lastUpdated = Date.now();
|
|
555
|
+
setPreviewHealth(current);
|
|
556
|
+
}
|
|
557
|
+
catch {
|
|
558
|
+
// Ignore malformed JSON
|
|
559
|
+
}
|
|
560
|
+
res.writeHead(204);
|
|
561
|
+
res.end();
|
|
562
|
+
});
|
|
563
|
+
}
|
|
168
564
|
/**
|
|
169
565
|
* Handle WebSocket upgrade by piping to the target dev server.
|
|
170
566
|
*/
|
|
171
567
|
function handleUpgrade(req, socket, head, targetUrl) {
|
|
172
568
|
const target = new URL(targetUrl);
|
|
569
|
+
const hostname = stripIPv6Brackets(target.hostname);
|
|
173
570
|
const port = parseInt(target.port, 10) || 80;
|
|
174
|
-
console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${
|
|
175
|
-
const proxySocket = net.connect(port,
|
|
571
|
+
console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${hostname}:${port}`);
|
|
572
|
+
const proxySocket = net.connect(port, hostname, () => {
|
|
176
573
|
// Reconstruct the HTTP upgrade request
|
|
177
574
|
const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\r\n`;
|
|
178
575
|
const headers = Object.entries(req.headers)
|
|
@@ -234,10 +631,34 @@ function removeProxyConfig() {
|
|
|
234
631
|
* Supports all HTTP methods (GET, POST, PUT, DELETE, PATCH) with body buffering.
|
|
235
632
|
*/
|
|
236
633
|
export async function startEditorProxy(options) {
|
|
237
|
-
//
|
|
634
|
+
// If proxy is already running, reuse it (prevents second tab from killing first tab's proxy)
|
|
635
|
+
const existing = getProxyState();
|
|
636
|
+
if (existing) {
|
|
637
|
+
console.log(`[editorProxy] Proxy already running on port ${existing.port} → ${existing.targetUrl}`);
|
|
638
|
+
return { port: existing.port };
|
|
639
|
+
}
|
|
640
|
+
// Stop any leftover state (shouldn't happen, but defensive)
|
|
238
641
|
await stopEditorProxy();
|
|
239
|
-
|
|
642
|
+
let targetUrl = normalizeTargetUrl(options.targetUrl);
|
|
240
643
|
let port = options.port;
|
|
644
|
+
// When the target is localhost, probe to find the correct loopback address.
|
|
645
|
+
// Dev servers may bind to IPv4 (127.0.0.1) or IPv6 (::1) — Vite 6 on macOS
|
|
646
|
+
// binds to ::1 by default. We need to match the actual binding.
|
|
647
|
+
try {
|
|
648
|
+
const parsed = new URL(targetUrl);
|
|
649
|
+
if (parsed.hostname === 'localhost') {
|
|
650
|
+
const targetPort = parseInt(parsed.port || '80', 10);
|
|
651
|
+
const resolvedHost = await resolveLoopbackAddress(targetPort);
|
|
652
|
+
if (resolvedHost) {
|
|
653
|
+
parsed.hostname = resolvedHost;
|
|
654
|
+
targetUrl = parsed.toString().replace(/\/$/, '');
|
|
655
|
+
console.log(`[editorProxy] Resolved localhost to ${resolvedHost} for port ${targetPort}`);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
catch {
|
|
660
|
+
// Keep original targetUrl
|
|
661
|
+
}
|
|
241
662
|
console.log(`[editorProxy] Starting proxy (requested port ${port}, target ${targetUrl})`);
|
|
242
663
|
const mockState = getMockStateManager();
|
|
243
664
|
const server = http.createServer((req, res) => {
|
|
@@ -256,6 +677,11 @@ export async function startEditorProxy(options) {
|
|
|
256
677
|
res.end();
|
|
257
678
|
return;
|
|
258
679
|
}
|
|
680
|
+
// Intercept preview health reports from the injected script
|
|
681
|
+
if (method === 'POST' && pathname === '/__codeyam__/preview-health') {
|
|
682
|
+
handlePreviewHealthPost(req, res);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
259
685
|
// Load scenario data (also feeds MockStateManager)
|
|
260
686
|
readScenarioData();
|
|
261
687
|
// For methods that may carry a body, buffer it first
|
|
@@ -287,6 +713,7 @@ export async function startEditorProxy(options) {
|
|
|
287
713
|
'Content-Type': 'application/json',
|
|
288
714
|
'Access-Control-Allow-Origin': '*',
|
|
289
715
|
'X-CodeYam-Proxy': 'scenario-data',
|
|
716
|
+
'Cache-Control': 'no-store',
|
|
290
717
|
});
|
|
291
718
|
res.end(match.body != null ? JSON.stringify(match.body) : '');
|
|
292
719
|
return;
|
|
@@ -303,6 +730,7 @@ export async function startEditorProxy(options) {
|
|
|
303
730
|
'Content-Type': 'application/json',
|
|
304
731
|
'Access-Control-Allow-Origin': '*',
|
|
305
732
|
'X-CodeYam-Proxy': 'scenario-data',
|
|
733
|
+
'Cache-Control': 'no-store',
|
|
306
734
|
});
|
|
307
735
|
res.end(match.body != null ? JSON.stringify(match.body) : '');
|
|
308
736
|
return;
|
|
@@ -327,7 +755,10 @@ export async function startEditorProxy(options) {
|
|
|
327
755
|
resolve();
|
|
328
756
|
});
|
|
329
757
|
});
|
|
330
|
-
port
|
|
758
|
+
// When port 0 is requested, the OS assigns an ephemeral port
|
|
759
|
+
const addr = server.address();
|
|
760
|
+
port =
|
|
761
|
+
typeof addr === 'object' && addr !== null ? addr.port : currentPort;
|
|
331
762
|
const state = { server, port, targetUrl };
|
|
332
763
|
setProxyState(state);
|
|
333
764
|
// Write proxy-config.json for the preload module
|
|
@@ -370,6 +801,40 @@ export async function stopEditorProxy() {
|
|
|
370
801
|
*/
|
|
371
802
|
export function invalidateScenarioCache() {
|
|
372
803
|
scenarioCache = { data: null, timestamp: 0 };
|
|
804
|
+
sessionConfig = undefined;
|
|
805
|
+
localStorageConfig = null;
|
|
806
|
+
activeScenarioId = null;
|
|
807
|
+
currentPrototypeId = null;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Verify that the proxy can successfully forward a request to the target dev server.
|
|
811
|
+
* Makes a HEAD request through the proxy and checks that it gets a response (any status).
|
|
812
|
+
* Returns false if the proxy isn't running or if the request fails entirely.
|
|
813
|
+
*/
|
|
814
|
+
export async function verifyProxyForwarding() {
|
|
815
|
+
const state = getProxyState();
|
|
816
|
+
if (!state) {
|
|
817
|
+
console.warn('[editorProxy] Cannot verify — proxy is not running');
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
try {
|
|
821
|
+
const response = await fetch(`http://127.0.0.1:${state.port}/`, {
|
|
822
|
+
method: 'HEAD',
|
|
823
|
+
signal: AbortSignal.timeout(5000),
|
|
824
|
+
});
|
|
825
|
+
// Any response from the target (even 404) means forwarding works.
|
|
826
|
+
// Only 502 (our own Bad Gateway) means the target is unreachable.
|
|
827
|
+
if (response.status === 502) {
|
|
828
|
+
console.warn(`[editorProxy] Verification failed — proxy returned 502 (target unreachable)`);
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
console.log(`[editorProxy] Verification passed — proxy forwarding to ${state.targetUrl} (status ${response.status})`);
|
|
832
|
+
return true;
|
|
833
|
+
}
|
|
834
|
+
catch (err) {
|
|
835
|
+
console.warn(`[editorProxy] Verification failed — could not reach proxy on port ${state.port}`);
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
373
838
|
}
|
|
374
839
|
/**
|
|
375
840
|
* Ensure the proxy is running. If it's not, start it using the current dev server URL.
|
|
@@ -391,9 +856,10 @@ export async function ensureProxyRunning() {
|
|
|
391
856
|
return null;
|
|
392
857
|
}
|
|
393
858
|
const codeyamPort = parseInt(process.env.CODEYAM_PORT || '3111', 10);
|
|
394
|
-
|
|
859
|
+
const { proxyPort } = computeEditorPorts(codeyamPort);
|
|
860
|
+
console.log(`[editorProxy] Proxy not running, starting on-demand (port ${proxyPort}, target ${devServer.url})`);
|
|
395
861
|
const result = await startEditorProxy({
|
|
396
|
-
port:
|
|
862
|
+
port: proxyPort,
|
|
397
863
|
targetUrl: devServer.url,
|
|
398
864
|
});
|
|
399
865
|
if (result) {
|
|
@@ -404,4 +870,8 @@ export async function ensureProxyRunning() {
|
|
|
404
870
|
console.error('[editorProxy] Failed to start on-demand proxy');
|
|
405
871
|
return null;
|
|
406
872
|
}
|
|
873
|
+
/**
|
|
874
|
+
* Test-only export: trigger readScenarioData so tests can verify session config extraction.
|
|
875
|
+
*/
|
|
876
|
+
export const _readScenarioDataForTest = readScenarioData;
|
|
407
877
|
//# sourceMappingURL=editorProxy.js.map
|