@codeyam/codeyam-cli 0.1.0-staging.a890816 → 0.1.0-staging.ad44cd3

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.
Files changed (477) hide show
  1. package/analyzer-template/.build-info.json +8 -8
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +10 -10
  4. package/analyzer-template/packages/ai/package.json +2 -2
  5. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +0 -33
  6. package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +13 -7
  7. package/analyzer-template/packages/analyze/src/lib/asts/index.ts +7 -2
  8. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +0 -98
  9. package/analyzer-template/packages/aws/package.json +2 -2
  10. package/analyzer-template/packages/database/package.json +3 -3
  11. package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +102 -0
  12. package/analyzer-template/packages/database/src/lib/loadEntities.ts +0 -6
  13. package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +0 -65
  14. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +9 -0
  15. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -1
  16. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +104 -0
  17. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  18. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
  19. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +0 -6
  20. package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
  21. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
  22. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +0 -25
  23. package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
  24. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  25. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  26. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
  27. package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
  28. package/analyzer-template/packages/github/package.json +1 -1
  29. package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
  30. package/analyzer-template/packages/ui-components/package.json +1 -1
  31. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
  32. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
  33. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
  34. package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
  35. package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js +196 -0
  36. package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js.map +1 -0
  37. package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js +114 -0
  38. package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js.map +1 -0
  39. package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js +149 -0
  40. package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js.map +1 -0
  41. package/codeyam-cli/src/cli.js +9 -0
  42. package/codeyam-cli/src/cli.js.map +1 -1
  43. package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js +51 -0
  44. package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js.map +1 -0
  45. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +56 -0
  46. package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js.map +1 -0
  47. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +101 -47
  48. package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
  49. package/codeyam-cli/src/commands/default.js +3 -46
  50. package/codeyam-cli/src/commands/default.js.map +1 -1
  51. package/codeyam-cli/src/commands/editor.js +3916 -419
  52. package/codeyam-cli/src/commands/editor.js.map +1 -1
  53. package/codeyam-cli/src/commands/editorIsolateArgs.js +25 -0
  54. package/codeyam-cli/src/commands/editorIsolateArgs.js.map +1 -0
  55. package/codeyam-cli/src/commands/init.js +74 -35
  56. package/codeyam-cli/src/commands/init.js.map +1 -1
  57. package/codeyam-cli/src/commands/telemetry.js +37 -0
  58. package/codeyam-cli/src/commands/telemetry.js.map +1 -0
  59. package/codeyam-cli/src/data/techStacks.js +77 -0
  60. package/codeyam-cli/src/data/techStacks.js.map +1 -0
  61. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js +173 -0
  62. package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js.map +1 -0
  63. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js +46 -0
  64. package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js.map +1 -0
  65. package/codeyam-cli/src/utils/__tests__/devServerState.test.js +134 -0
  66. package/codeyam-cli/src/utils/__tests__/devServerState.test.js.map +1 -0
  67. package/codeyam-cli/src/utils/__tests__/editorApi.test.js +137 -0
  68. package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -0
  69. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +1879 -0
  70. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -0
  71. package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js +76 -0
  72. package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js.map +1 -0
  73. package/codeyam-cli/src/utils/__tests__/editorCapture.test.js +93 -0
  74. package/codeyam-cli/src/utils/__tests__/editorCapture.test.js.map +1 -0
  75. package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js +100 -0
  76. package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js.map +1 -0
  77. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +304 -0
  78. package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -0
  79. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +194 -0
  80. package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -0
  81. package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js +261 -0
  82. package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js.map +1 -0
  83. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js +294 -0
  84. package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js.map +1 -0
  85. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +542 -0
  86. package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -0
  87. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +594 -0
  88. package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -0
  89. package/codeyam-cli/src/utils/__tests__/editorMigration.test.js +435 -0
  90. package/codeyam-cli/src/utils/__tests__/editorMigration.test.js.map +1 -0
  91. package/codeyam-cli/src/utils/__tests__/editorMockState.test.js +270 -0
  92. package/codeyam-cli/src/utils/__tests__/editorMockState.test.js.map +1 -0
  93. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js +217 -0
  94. package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js.map +1 -0
  95. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +353 -0
  96. package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -0
  97. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +153 -0
  98. package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
  99. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +139 -0
  100. package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -0
  101. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +221 -0
  102. package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -0
  103. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +1483 -0
  104. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -0
  105. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +280 -0
  106. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -0
  107. package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js +143 -0
  108. package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js.map +1 -0
  109. package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js +66 -0
  110. package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js.map +1 -0
  111. package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js +53 -0
  112. package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js.map +1 -0
  113. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +1857 -0
  114. package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -0
  115. package/codeyam-cli/src/utils/__tests__/git.editor.test.js +134 -0
  116. package/codeyam-cli/src/utils/__tests__/git.editor.test.js.map +1 -0
  117. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +107 -0
  118. package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -0
  119. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +129 -0
  120. package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -0
  121. package/codeyam-cli/src/utils/__tests__/project.test.js +65 -0
  122. package/codeyam-cli/src/utils/__tests__/project.test.js.map +1 -0
  123. package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js +118 -0
  124. package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js.map +1 -0
  125. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js +227 -0
  126. package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js.map +1 -0
  127. package/codeyam-cli/src/utils/__tests__/scenarioMarkers.test.js +121 -0
  128. package/codeyam-cli/src/utils/__tests__/scenarioMarkers.test.js.map +1 -0
  129. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +493 -0
  130. package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -0
  131. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +26 -5
  132. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  133. package/codeyam-cli/src/utils/__tests__/telemetry.test.js +159 -0
  134. package/codeyam-cli/src/utils/__tests__/telemetry.test.js.map +1 -0
  135. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +51 -0
  136. package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -0
  137. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +142 -0
  138. package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
  139. package/codeyam-cli/src/utils/analysisRunner.js +3 -1
  140. package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
  141. package/codeyam-cli/src/utils/analyzer.js +9 -0
  142. package/codeyam-cli/src/utils/analyzer.js.map +1 -1
  143. package/codeyam-cli/src/utils/analyzerFinalization.js +100 -0
  144. package/codeyam-cli/src/utils/analyzerFinalization.js.map +1 -0
  145. package/codeyam-cli/src/utils/backgroundServer.js +94 -18
  146. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  147. package/codeyam-cli/src/utils/buildFlags.js +4 -0
  148. package/codeyam-cli/src/utils/buildFlags.js.map +1 -0
  149. package/codeyam-cli/src/utils/database.js +37 -2
  150. package/codeyam-cli/src/utils/database.js.map +1 -1
  151. package/codeyam-cli/src/utils/devServerState.js +71 -0
  152. package/codeyam-cli/src/utils/devServerState.js.map +1 -0
  153. package/codeyam-cli/src/utils/editorApi.js +79 -0
  154. package/codeyam-cli/src/utils/editorApi.js.map +1 -0
  155. package/codeyam-cli/src/utils/editorAudit.js +355 -0
  156. package/codeyam-cli/src/utils/editorAudit.js.map +1 -0
  157. package/codeyam-cli/src/utils/editorBroadcastViewport.js +26 -0
  158. package/codeyam-cli/src/utils/editorBroadcastViewport.js.map +1 -0
  159. package/codeyam-cli/src/utils/editorCapture.js +102 -0
  160. package/codeyam-cli/src/utils/editorCapture.js.map +1 -0
  161. package/codeyam-cli/src/utils/editorDeleteScenario.js +67 -0
  162. package/codeyam-cli/src/utils/editorDeleteScenario.js.map +1 -0
  163. package/codeyam-cli/src/utils/editorDevServer.js +197 -0
  164. package/codeyam-cli/src/utils/editorDevServer.js.map +1 -0
  165. package/codeyam-cli/src/utils/editorEntityChangeStatus.js +50 -0
  166. package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -0
  167. package/codeyam-cli/src/utils/editorEntityHelpers.js +129 -0
  168. package/codeyam-cli/src/utils/editorEntityHelpers.js.map +1 -0
  169. package/codeyam-cli/src/utils/editorImageVerifier.js +155 -0
  170. package/codeyam-cli/src/utils/editorImageVerifier.js.map +1 -0
  171. package/codeyam-cli/src/utils/editorJournal.js +225 -0
  172. package/codeyam-cli/src/utils/editorJournal.js.map +1 -0
  173. package/codeyam-cli/src/utils/editorLoaderHelpers.js +152 -0
  174. package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -0
  175. package/codeyam-cli/src/utils/editorMigration.js +224 -0
  176. package/codeyam-cli/src/utils/editorMigration.js.map +1 -0
  177. package/codeyam-cli/src/utils/editorMockState.js +248 -0
  178. package/codeyam-cli/src/utils/editorMockState.js.map +1 -0
  179. package/codeyam-cli/src/utils/editorPreloadHelpers.js +135 -0
  180. package/codeyam-cli/src/utils/editorPreloadHelpers.js.map +1 -0
  181. package/codeyam-cli/src/utils/editorPreview.js +137 -0
  182. package/codeyam-cli/src/utils/editorPreview.js.map +1 -0
  183. package/codeyam-cli/src/utils/editorScenarioSwitch.js +112 -0
  184. package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -0
  185. package/codeyam-cli/src/utils/editorScenarios.js +548 -0
  186. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -0
  187. package/codeyam-cli/src/utils/editorSeedAdapter.js +422 -0
  188. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -0
  189. package/codeyam-cli/src/utils/editorShouldRevalidate.js +21 -0
  190. package/codeyam-cli/src/utils/editorShouldRevalidate.js.map +1 -0
  191. package/codeyam-cli/src/utils/entityChangeStatus.js +366 -0
  192. package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -0
  193. package/codeyam-cli/src/utils/entityChangeStatus.server.js +196 -0
  194. package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -0
  195. package/codeyam-cli/src/utils/fileWatcher.js +38 -0
  196. package/codeyam-cli/src/utils/fileWatcher.js.map +1 -1
  197. package/codeyam-cli/src/utils/git.js +51 -0
  198. package/codeyam-cli/src/utils/git.js.map +1 -1
  199. package/codeyam-cli/src/utils/install-skills.js +37 -17
  200. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  201. package/codeyam-cli/src/utils/parseRegisterArg.js +31 -0
  202. package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -0
  203. package/codeyam-cli/src/utils/progress.js +2 -2
  204. package/codeyam-cli/src/utils/progress.js.map +1 -1
  205. package/codeyam-cli/src/utils/project.js +15 -5
  206. package/codeyam-cli/src/utils/project.js.map +1 -1
  207. package/codeyam-cli/src/utils/routePatternMatching.js +129 -0
  208. package/codeyam-cli/src/utils/routePatternMatching.js.map +1 -0
  209. package/codeyam-cli/src/utils/scenarioCoverage.js +74 -0
  210. package/codeyam-cli/src/utils/scenarioCoverage.js.map +1 -0
  211. package/codeyam-cli/src/utils/scenarioMarkers.js +134 -0
  212. package/codeyam-cli/src/utils/scenarioMarkers.js.map +1 -0
  213. package/codeyam-cli/src/utils/scenariosManifest.js +249 -0
  214. package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -0
  215. package/codeyam-cli/src/utils/serverState.js +30 -0
  216. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  217. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +47 -16
  218. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  219. package/codeyam-cli/src/utils/simulationGateMiddleware.js +8 -1
  220. package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
  221. package/codeyam-cli/src/utils/slugUtils.js +25 -0
  222. package/codeyam-cli/src/utils/slugUtils.js.map +1 -0
  223. package/codeyam-cli/src/utils/syncMocksMiddleware.js +2 -2
  224. package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
  225. package/codeyam-cli/src/utils/telemetry.js +106 -0
  226. package/codeyam-cli/src/utils/telemetry.js.map +1 -0
  227. package/codeyam-cli/src/utils/telemetryMiddleware.js +22 -0
  228. package/codeyam-cli/src/utils/telemetryMiddleware.js.map +1 -0
  229. package/codeyam-cli/src/utils/testRunner.js +1 -1
  230. package/codeyam-cli/src/utils/testRunner.js.map +1 -1
  231. package/codeyam-cli/src/utils/webappDetection.js +21 -0
  232. package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
  233. package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js +35 -0
  234. package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js.map +1 -0
  235. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js +40 -0
  236. package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js.map +1 -0
  237. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +628 -0
  238. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
  239. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +146 -0
  240. package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -0
  241. package/codeyam-cli/src/webserver/app/lib/clientErrors.js +65 -0
  242. package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -0
  243. package/codeyam-cli/src/webserver/app/lib/git.js +397 -0
  244. package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -0
  245. package/codeyam-cli/src/webserver/app/types/editor.js +8 -0
  246. package/codeyam-cli/src/webserver/app/types/editor.js.map +1 -0
  247. package/codeyam-cli/src/webserver/backgroundServer.js +18 -4
  248. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  249. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CzTDWkF2.js +1 -0
  250. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-BFbq6iFk.js} +5 -5
  251. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-CQgyEGV-.js +1 -0
  252. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-B6OMi58N.js} +9 -9
  253. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-DuYodzo1.js +1 -0
  254. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-CXo9EeCl.js +25 -0
  255. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-DYCNb2It.js +3 -0
  256. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-BU_OAEMP.js → LoadingDots-By5zI316.js} +1 -1
  257. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-ceAyBX-H.js → LogViewer-CZgY3sxX.js} +3 -3
  258. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-CnYYwRDw.js} +4 -4
  259. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-CDoF7ZpU.js +1 -0
  260. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-B76aig_2.js → ScenarioViewer-DrnfvaLL.js} +3 -3
  261. package/codeyam-cli/src/webserver/build/client/assets/Spinner-Df3UCi8k.js +34 -0
  262. package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-CK7-NaPZ.js +1 -0
  263. package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-DRKR9T0U.js +1 -0
  264. package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-ClR-g3tY.js} +4 -4
  265. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-DTH6ydEA.js} +8 -8
  266. package/codeyam-cli/src/webserver/build/client/assets/addon-canvas-DpzMmAy5.js +1 -0
  267. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-YJmn1quW.js +12 -0
  268. package/codeyam-cli/src/webserver/build/client/assets/{addon-web-links-Duc5hnl7.js → addon-web-links-74hnHF59.js} +1 -1
  269. package/codeyam-cli/src/webserver/build/client/assets/addon-webgl-DI8QOUvO.js +58 -0
  270. package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-B8CYhCO9.js} +7 -7
  271. package/codeyam-cli/src/webserver/build/client/assets/api.editor-audit-l0sNRNKZ.js +1 -0
  272. package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-diff-l0sNRNKZ.js +1 -0
  273. package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-l0sNRNKZ.js +1 -0
  274. package/codeyam-cli/src/webserver/build/client/assets/api.editor-load-commit-l0sNRNKZ.js +1 -0
  275. package/codeyam-cli/src/webserver/build/client/assets/api.editor-project-info-l0sNRNKZ.js +1 -0
  276. package/codeyam-cli/src/webserver/build/client/assets/api.editor-rename-scenario-l0sNRNKZ.js +1 -0
  277. package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-seed-state-l0sNRNKZ.js +1 -0
  278. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-coverage-l0sNRNKZ.js +1 -0
  279. package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-prompt-l0sNRNKZ.js +1 -0
  280. package/codeyam-cli/src/webserver/build/client/assets/api.editor-session-l0sNRNKZ.js +1 -0
  281. package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-CLaoh4ac.js} +2 -2
  282. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-BZ2DZxbW.js} +2 -2
  283. package/codeyam-cli/src/webserver/build/client/assets/{chunk-JZWAC4HX-C4pqxYJB.js → chunk-JZWAC4HX-BBXArFPl.js} +13 -21
  284. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-CT4unAk-.js} +2 -2
  285. package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-zK0B6Nu-.js} +3 -3
  286. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-DJB0YQJL.js +41 -0
  287. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-CkXFP_i-.js +1 -0
  288. package/codeyam-cli/src/webserver/build/client/assets/editor._tab-DPw7NZHc.js +1 -0
  289. package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-CjC3_6JI.js +58 -0
  290. package/codeyam-cli/src/webserver/build/client/assets/editorPreview-DBa7T2FK.js +41 -0
  291. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CrjR3zZW.js → entity._sha._-BqAN7hyG.js} +3 -3
  292. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-BOi8kpwd.js +6 -0
  293. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-Dg1NhIms.js +6 -0
  294. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-CJX6kkkV.js +6 -0
  295. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMvVHNXU.js → entity._sha_.edit._scenarioId-BhVjZhKg.js} +2 -2
  296. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-DTvKq3TY.js → entry.client-_gzKltPN.js} +6 -6
  297. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-Daa96Fr1.js +1 -0
  298. package/codeyam-cli/src/webserver/build/client/assets/files-CV_17tZS.js +1 -0
  299. package/codeyam-cli/src/webserver/build/client/assets/git-D-YXmMbR.js +1 -0
  300. package/codeyam-cli/src/webserver/build/client/assets/globals-DRvOjyO3.css +1 -0
  301. package/codeyam-cli/src/webserver/build/client/assets/index-Blo6EK8G.js +15 -0
  302. package/codeyam-cli/src/webserver/build/client/assets/{index-10oVnAAH.js → index-BsX0F-9C.js} +1 -1
  303. package/codeyam-cli/src/webserver/build/client/assets/{index-BcvgDzbZ.js → index-CCrgCshv.js} +1 -1
  304. package/codeyam-cli/src/webserver/build/client/assets/jsx-runtime-D_zvdyIk.js +9 -0
  305. package/codeyam-cli/src/webserver/build/client/assets/labs-Byazq8Pv.js +1 -0
  306. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-DVQ0oHR7.js} +2 -2
  307. package/codeyam-cli/src/webserver/build/client/assets/manifest-75b1b319.js +1 -0
  308. package/codeyam-cli/src/webserver/build/client/assets/memory-b-VmA2Vj.js +101 -0
  309. package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-DGcndCAa.js} +3 -3
  310. package/codeyam-cli/src/webserver/build/client/assets/root-F-k2uYj5.js +67 -0
  311. package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-C0Uw0bcK.js} +2 -2
  312. package/codeyam-cli/src/webserver/build/client/assets/settings-OoNgHIfW.js +1 -0
  313. package/codeyam-cli/src/webserver/build/client/assets/simulations-Bcemfu8a.js +1 -0
  314. package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-BgMmG7R9.js} +3 -3
  315. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-Cs87hJYK.js} +2 -2
  316. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-BR3Rs7JY.js +1 -0
  317. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-C14nCb1q.js → useLastLogLine-BxxP_XF9.js} +1 -1
  318. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-BermyNU5.js +1 -0
  319. package/codeyam-cli/src/webserver/build/client/assets/useToast-a_QN_W9_.js +1 -0
  320. package/codeyam-cli/src/webserver/build/client/assets/xterm-BqvuqXEL.js +27 -0
  321. package/codeyam-cli/src/webserver/build/client/sound-test.html +98 -0
  322. package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-lv2ooewK.js +13 -0
  323. package/codeyam-cli/src/webserver/build/server/assets/index-Im3Smyei.js +1 -0
  324. package/codeyam-cli/src/webserver/build/server/assets/init-BjuAFKGM.js +10 -0
  325. package/codeyam-cli/src/webserver/build/server/assets/progress-CHTtrxFG.js +1 -0
  326. package/codeyam-cli/src/webserver/build/server/assets/server-build-CNjF0B9B.js +551 -0
  327. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  328. package/codeyam-cli/src/webserver/build-info.json +5 -5
  329. package/codeyam-cli/src/webserver/editorProxy.js +755 -51
  330. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  331. package/codeyam-cli/src/webserver/idleDetector.js +73 -0
  332. package/codeyam-cli/src/webserver/idleDetector.js.map +1 -0
  333. package/codeyam-cli/src/webserver/mockStateEvents.js +28 -0
  334. package/codeyam-cli/src/webserver/mockStateEvents.js.map +1 -0
  335. package/codeyam-cli/src/webserver/public/sound-test.html +98 -0
  336. package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +414 -0
  337. package/codeyam-cli/src/webserver/scripts/journalCapture.ts +94 -4
  338. package/codeyam-cli/src/webserver/server.js +176 -12
  339. package/codeyam-cli/src/webserver/server.js.map +1 -1
  340. package/codeyam-cli/src/webserver/terminalServer.js +218 -140
  341. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  342. package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
  343. package/codeyam-cli/templates/chrome-extension-react/README.md +46 -0
  344. package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
  345. package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
  346. package/codeyam-cli/templates/chrome-extension-react/package.json +27 -0
  347. package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
  348. package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
  349. package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
  350. package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
  351. package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
  352. package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
  353. package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
  354. package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
  355. package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +41 -0
  356. package/codeyam-cli/templates/codeyam-editor-claude.md +84 -5
  357. package/codeyam-cli/templates/editor-step-hook.py +198 -22
  358. package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +89 -0
  359. package/codeyam-cli/templates/expo-react-native/README.md +41 -0
  360. package/codeyam-cli/templates/expo-react-native/app/(tabs)/_layout.tsx +33 -0
  361. package/codeyam-cli/templates/expo-react-native/app/(tabs)/index.tsx +12 -0
  362. package/codeyam-cli/templates/expo-react-native/app/(tabs)/settings.tsx +12 -0
  363. package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +12 -0
  364. package/codeyam-cli/templates/expo-react-native/app.json +18 -0
  365. package/codeyam-cli/templates/expo-react-native/babel.config.js +9 -0
  366. package/codeyam-cli/templates/expo-react-native/gitignore +12 -0
  367. package/codeyam-cli/templates/expo-react-native/global.css +3 -0
  368. package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
  369. package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
  370. package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
  371. package/codeyam-cli/templates/expo-react-native/package.json +38 -0
  372. package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
  373. package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
  374. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
  375. package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
  376. package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +126 -0
  377. package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
  378. package/codeyam-cli/templates/nextjs-prisma-sqlite/README.md +53 -0
  379. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/codeyam-isolate/layout.tsx +12 -0
  380. package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
  381. package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
  382. package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +21 -0
  383. package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +5 -1
  384. package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
  385. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +127 -0
  386. package/codeyam-cli/templates/nextjs-prisma-sqlite/vitest.config.ts +13 -0
  387. package/codeyam-cli/templates/nextjs-prisma-supabase/README.md +52 -0
  388. package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
  389. package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
  390. package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
  391. package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
  392. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
  393. package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
  394. package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
  395. package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
  396. package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
  397. package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
  398. package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
  399. package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +37 -0
  400. package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
  401. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
  402. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
  403. package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
  404. package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
  405. package/codeyam-cli/templates/seed-adapters/supabase.ts +282 -0
  406. package/codeyam-cli/templates/{codeyam-dev-mode.md → skills/codeyam-dev-mode/SKILL.md} +3 -3
  407. package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +211 -0
  408. package/codeyam-cli/templates/{codeyam-memory.md → skills/codeyam-memory/SKILL.md} +215 -0
  409. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/deprecated-prompt.md +100 -0
  410. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.mjs +139 -0
  411. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.mjs +52 -0
  412. package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/misleading-api-prompt.md +117 -0
  413. package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/read-json-field.mjs +61 -0
  414. package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/ripgrep-fallback.mjs +155 -0
  415. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/analyze-prompt.md +46 -0
  416. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.mjs +13 -0
  417. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter-session.mjs +95 -0
  418. package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.mjs +160 -0
  419. package/package.json +16 -10
  420. package/packages/ai/src/lib/generateExecutionFlows.js +0 -11
  421. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
  422. package/packages/analyze/src/lib/ProjectAnalyzer.js +10 -4
  423. package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
  424. package/packages/analyze/src/lib/asts/index.js +4 -2
  425. package/packages/analyze/src/lib/asts/index.js.map +1 -1
  426. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +0 -40
  427. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
  428. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +104 -0
  429. package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
  430. package/packages/database/src/lib/loadEntities.js +0 -6
  431. package/packages/database/src/lib/loadEntities.js.map +1 -1
  432. package/packages/database/src/lib/updateCommitMetadata.js +0 -25
  433. package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
  434. package/packages/types/src/enums/ProjectFramework.js +2 -0
  435. package/packages/types/src/enums/ProjectFramework.js.map +1 -1
  436. package/scripts/npm-post-install.cjs +34 -0
  437. package/codeyam-cli/src/webserver/build/client/assets/CopyButton-DmJveP3T.js +0 -1
  438. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-g3saevPb.js +0 -1
  439. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-Bu6c6aDe.js +0 -1
  440. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-DYFW3lDD.js +0 -25
  441. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-DLeucoVX.js +0 -3
  442. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BED4B6sP.js +0 -1
  443. package/codeyam-cli/src/webserver/build/client/assets/Spinner-Bb5uFQ5V.js +0 -34
  444. package/codeyam-cli/src/webserver/build/client/assets/Terminal-CcG8YTLx.js +0 -41
  445. package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-C8OKAR5x.js +0 -1
  446. package/codeyam-cli/src/webserver/build/client/assets/addon-fit-CUXOrorO.js +0 -1
  447. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
  448. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BiM6z3Do.js +0 -1
  449. package/codeyam-cli/src/webserver/build/client/assets/editor-W_IGJ2Kd.js +0 -7
  450. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-D6SEzMCu.js +0 -6
  451. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-C28BiQzt.js +0 -6
  452. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-p9hhkjJM.js +0 -6
  453. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-cPo8LiG3.js +0 -1
  454. package/codeyam-cli/src/webserver/build/client/assets/files-DO4CZ16O.js +0 -1
  455. package/codeyam-cli/src/webserver/build/client/assets/git-CFCTYk9I.js +0 -15
  456. package/codeyam-cli/src/webserver/build/client/assets/globals-BZB_H1w2.css +0 -1
  457. package/codeyam-cli/src/webserver/build/client/assets/labs-Zk7ryIM1.js +0 -1
  458. package/codeyam-cli/src/webserver/build/client/assets/manifest-8daa4147.js +0 -1
  459. package/codeyam-cli/src/webserver/build/client/assets/memory-FweZHj5U.js +0 -93
  460. package/codeyam-cli/src/webserver/build/client/assets/root-DiRdBreB.js +0 -67
  461. package/codeyam-cli/src/webserver/build/client/assets/settings-DfuTtcJP.js +0 -1
  462. package/codeyam-cli/src/webserver/build/client/assets/simulations-B3aOzpCZ.js +0 -1
  463. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-ByhSyh0W.js +0 -1
  464. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-O-jkvSPx.js +0 -1
  465. package/codeyam-cli/src/webserver/build/client/assets/useToast-9FIWuYfK.js +0 -1
  466. package/codeyam-cli/src/webserver/build/client/assets/xterm-DMSzMhqy.js +0 -9
  467. package/codeyam-cli/src/webserver/build/server/assets/index-BzAbACSx.js +0 -1
  468. package/codeyam-cli/src/webserver/build/server/assets/server-build-OdUocH6P.js +0 -362
  469. package/codeyam-cli/templates/codeyam-editor.md +0 -68
  470. package/scripts/finalize-analyzer.cjs +0 -13
  471. /package/codeyam-cli/templates/{codeyam-diagnose.md → commands/codeyam-diagnose.md} +0 -0
  472. /package/codeyam-cli/templates/{codeyam-debug.md → skills/codeyam-debug/SKILL.md} +0 -0
  473. /package/codeyam-cli/templates/{codeyam-new-rule.md → skills/codeyam-new-rule/SKILL.md} +0 -0
  474. /package/codeyam-cli/templates/{codeyam-setup.md → skills/codeyam-setup/SKILL.md} +0 -0
  475. /package/codeyam-cli/templates/{codeyam-sim.md → skills/codeyam-sim/SKILL.md} +0 -0
  476. /package/codeyam-cli/templates/{codeyam-test.md → skills/codeyam-test/SKILL.md} +0 -0
  477. /package/codeyam-cli/templates/{codeyam-verify.md → skills/codeyam-verify/SKILL.md} +0 -0
@@ -0,0 +1,628 @@
1
+ import http from 'http';
2
+ import zlib from 'zlib';
3
+ import { injectHealthScript, PREVIEW_HEALTH_SCRIPT, getPreviewHealthReport, resetPreviewHealth, } from "../editorProxy.js";
4
+ describe('editorProxy', () => {
5
+ describe('normalizeTargetUrl', () => {
6
+ it('should leave localhost as-is (no longer normalizes to 127.0.0.1)', () => {
7
+ const { normalizeTargetUrl } = require('../editorProxy');
8
+ expect(normalizeTargetUrl('http://localhost:3112')).toBe('http://localhost:3112');
9
+ });
10
+ it('should leave 127.0.0.1 unchanged', () => {
11
+ const { normalizeTargetUrl } = require('../editorProxy');
12
+ expect(normalizeTargetUrl('http://127.0.0.1:3112')).toBe('http://127.0.0.1:3112');
13
+ });
14
+ it('should leave other hostnames unchanged', () => {
15
+ const { normalizeTargetUrl } = require('../editorProxy');
16
+ expect(normalizeTargetUrl('http://myhost:3112')).toBe('http://myhost:3112');
17
+ });
18
+ it('should strip trailing slash', () => {
19
+ const { normalizeTargetUrl } = require('../editorProxy');
20
+ expect(normalizeTargetUrl('http://localhost:3112/')).toBe('http://localhost:3112');
21
+ });
22
+ });
23
+ describe('resolveLoopbackAddress', () => {
24
+ let server;
25
+ afterEach((done) => {
26
+ if (server?.listening) {
27
+ server.close(done);
28
+ }
29
+ else {
30
+ done();
31
+ }
32
+ });
33
+ it('should resolve to 127.0.0.1 when server binds to IPv4', async () => {
34
+ const { resolveLoopbackAddress } = require('../editorProxy');
35
+ server = http.createServer((_req, res) => res.end('ok'));
36
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', () => resolve()));
37
+ const port = server.address().port;
38
+ const host = await resolveLoopbackAddress(port);
39
+ expect(host).toBe('127.0.0.1');
40
+ });
41
+ it('should resolve to ::1 when server binds to IPv6 only', async () => {
42
+ const { resolveLoopbackAddress } = require('../editorProxy');
43
+ server = http.createServer((_req, res) => res.end('ok'));
44
+ await new Promise((resolve) => server.listen(0, '::1', () => resolve()));
45
+ const port = server.address().port;
46
+ const host = await resolveLoopbackAddress(port);
47
+ expect(host).toBe('::1');
48
+ });
49
+ it('should return null when no server is listening', async () => {
50
+ const { resolveLoopbackAddress } = require('../editorProxy');
51
+ const host = await resolveLoopbackAddress(19876);
52
+ expect(host).toBeNull();
53
+ });
54
+ });
55
+ describe('proxy forwarding uses 127.0.0.1', () => {
56
+ let targetServer;
57
+ let targetPort;
58
+ afterEach((done) => {
59
+ if (targetServer?.listening) {
60
+ targetServer.close(done);
61
+ }
62
+ else {
63
+ done();
64
+ }
65
+ });
66
+ it('should forward requests to target and return correct response', async () => {
67
+ const { startEditorProxy, stopEditorProxy } = require('../editorProxy');
68
+ // Start a target server that returns 200
69
+ targetServer = http.createServer((_req, res) => {
70
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
71
+ res.end('OK from target');
72
+ });
73
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
74
+ targetPort = targetServer.address().port;
75
+ // Start proxy pointing to the target using localhost URL
76
+ const result = await startEditorProxy({
77
+ port: 0, // let OS pick
78
+ targetUrl: `http://localhost:${targetPort}`,
79
+ });
80
+ expect(result).not.toBeNull();
81
+ // Make a request through the proxy
82
+ const response = await fetch(`http://127.0.0.1:${result.port}/`);
83
+ expect(response.status).toBe(200);
84
+ const body = await response.text();
85
+ expect(body).toBe('OK from target');
86
+ await stopEditorProxy();
87
+ });
88
+ it('should log when target returns non-2xx status', async () => {
89
+ const { startEditorProxy, stopEditorProxy } = require('../editorProxy');
90
+ // Start a target that returns 404
91
+ targetServer = http.createServer((_req, res) => {
92
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
93
+ res.end('Not Found');
94
+ });
95
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
96
+ targetPort = targetServer.address().port;
97
+ const warnSpy = jest.spyOn(console, 'warn').mockImplementation();
98
+ const result = await startEditorProxy({
99
+ port: 0,
100
+ targetUrl: `http://localhost:${targetPort}`,
101
+ });
102
+ const response = await fetch(`http://127.0.0.1:${result.port}/test-path`);
103
+ expect(response.status).toBe(404);
104
+ // Verify a warning was logged about the non-2xx response
105
+ expect(warnSpy.mock.calls.some((call) => String(call[0]).includes('[editorProxy]') &&
106
+ String(call[0]).includes('404') &&
107
+ String(call[0]).includes('/test-path'))).toBe(true);
108
+ warnSpy.mockRestore();
109
+ await stopEditorProxy();
110
+ });
111
+ it('should verify forwarding works after start via self-test', async () => {
112
+ const { startEditorProxy, stopEditorProxy, verifyProxyForwarding, } = require('../editorProxy');
113
+ // Start a target that returns 200
114
+ targetServer = http.createServer((_req, res) => {
115
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
116
+ res.end('healthy');
117
+ });
118
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
119
+ targetPort = targetServer.address().port;
120
+ const result = await startEditorProxy({
121
+ port: 0,
122
+ targetUrl: `http://localhost:${targetPort}`,
123
+ });
124
+ const verified = await verifyProxyForwarding();
125
+ expect(verified).toBe(true);
126
+ await stopEditorProxy();
127
+ });
128
+ it('should report verification failure when target is down', async () => {
129
+ const { startEditorProxy, stopEditorProxy, verifyProxyForwarding, } = require('../editorProxy');
130
+ const result = await startEditorProxy({
131
+ port: 0,
132
+ targetUrl: 'http://127.0.0.1:19876',
133
+ });
134
+ const verified = await verifyProxyForwarding();
135
+ expect(verified).toBe(false);
136
+ await stopEditorProxy();
137
+ });
138
+ it('should return false for verification when proxy is not running', async () => {
139
+ const { verifyProxyForwarding, stopEditorProxy, } = require('../editorProxy');
140
+ await stopEditorProxy();
141
+ const verified = await verifyProxyForwarding();
142
+ expect(verified).toBe(false);
143
+ });
144
+ it('should return 502 when target is unreachable', async () => {
145
+ const { startEditorProxy, stopEditorProxy } = require('../editorProxy');
146
+ // Start proxy pointing to a port with nothing listening
147
+ const result = await startEditorProxy({
148
+ port: 0,
149
+ targetUrl: 'http://localhost:19876',
150
+ });
151
+ expect(result).not.toBeNull();
152
+ const response = await fetch(`http://127.0.0.1:${result.port}/`);
153
+ expect(response.status).toBe(502);
154
+ await stopEditorProxy();
155
+ });
156
+ it('should forward requests to an IPv6-only target server', async () => {
157
+ const { startEditorProxy, stopEditorProxy } = require('../editorProxy');
158
+ // Start a target server bound to IPv6 only (::1) — this is what Vite 6 does on macOS
159
+ targetServer = http.createServer((_req, res) => {
160
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
161
+ res.end('OK from IPv6 target');
162
+ });
163
+ await new Promise((resolve) => targetServer.listen(0, '::1', () => resolve()));
164
+ targetPort = targetServer.address().port;
165
+ // Start proxy with a localhost URL (simulating Vite's "Local: http://localhost:PORT")
166
+ const result = await startEditorProxy({
167
+ port: 0,
168
+ targetUrl: `http://localhost:${targetPort}`,
169
+ });
170
+ expect(result).not.toBeNull();
171
+ // The proxy should successfully forward to the IPv6-only target
172
+ const response = await fetch(`http://127.0.0.1:${result.port}/`);
173
+ expect(response.status).toBe(200);
174
+ const body = await response.text();
175
+ expect(body).toBe('OK from IPv6 target');
176
+ await stopEditorProxy();
177
+ });
178
+ });
179
+ describe('injectHealthScript', () => {
180
+ it('should inject before </head> when present', () => {
181
+ const html = '<html><head><title>Test</title></head><body>Hello</body></html>';
182
+ const result = injectHealthScript(html);
183
+ expect(result).toContain(PREVIEW_HEALTH_SCRIPT + '</head>');
184
+ expect(result).toContain('<title>Test</title>');
185
+ });
186
+ it('should inject before </body> when no </head>', () => {
187
+ const html = '<html><body>Hello</body></html>';
188
+ const result = injectHealthScript(html);
189
+ expect(result).toContain(PREVIEW_HEALTH_SCRIPT + '</body>');
190
+ });
191
+ it('should append when no </head> or </body>', () => {
192
+ const html = '<div>Hello</div>';
193
+ const result = injectHealthScript(html);
194
+ expect(result).toBe('<div>Hello</div>' + PREVIEW_HEALTH_SCRIPT);
195
+ });
196
+ it('should include the data-codeyam-health attribute', () => {
197
+ const html = '<html><head></head><body></body></html>';
198
+ const result = injectHealthScript(html);
199
+ expect(result).toContain('data-codeyam-health');
200
+ });
201
+ });
202
+ describe('preview health endpoint', () => {
203
+ let targetServer;
204
+ let targetPort;
205
+ afterEach(async () => {
206
+ const { stopEditorProxy } = require('../editorProxy');
207
+ await stopEditorProxy();
208
+ if (targetServer?.listening) {
209
+ await new Promise((resolve) => targetServer.close(() => resolve()));
210
+ }
211
+ resetPreviewHealth();
212
+ });
213
+ it('should intercept POST /__codeyam__/preview-health and store errors', async () => {
214
+ const { startEditorProxy } = require('../editorProxy');
215
+ // Start a target that returns 200
216
+ targetServer = http.createServer((_req, res) => {
217
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
218
+ res.end('ok');
219
+ });
220
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
221
+ targetPort = targetServer.address().port;
222
+ const result = await startEditorProxy({
223
+ port: 0,
224
+ targetUrl: `http://localhost:${targetPort}`,
225
+ });
226
+ expect(result).not.toBeNull();
227
+ // Post error data to the health endpoint
228
+ const response = await fetch(`http://127.0.0.1:${result.port}/__codeyam__/preview-health`, {
229
+ method: 'POST',
230
+ headers: { 'Content-Type': 'application/json' },
231
+ body: JSON.stringify({
232
+ errors: [
233
+ {
234
+ type: 'error',
235
+ message: 'Cannot read properties of undefined',
236
+ timestamp: 1710000000,
237
+ },
238
+ ],
239
+ url: 'http://localhost:3112/',
240
+ }),
241
+ });
242
+ expect(response.status).toBe(204);
243
+ // Check the stored health data
244
+ const health = getPreviewHealthReport();
245
+ expect(health).not.toBeNull();
246
+ expect(health.errors).toHaveLength(1);
247
+ expect(health.errors[0].message).toBe('Cannot read properties of undefined');
248
+ expect(health.url).toBe('http://localhost:3112/');
249
+ });
250
+ it('should store loaded/hasContent from load report', async () => {
251
+ const { startEditorProxy } = require('../editorProxy');
252
+ targetServer = http.createServer((_req, res) => {
253
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
254
+ res.end('ok');
255
+ });
256
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
257
+ targetPort = targetServer.address().port;
258
+ const result = await startEditorProxy({
259
+ port: 0,
260
+ targetUrl: `http://localhost:${targetPort}`,
261
+ });
262
+ // Post load report
263
+ await fetch(`http://127.0.0.1:${result.port}/__codeyam__/preview-health`, {
264
+ method: 'POST',
265
+ headers: { 'Content-Type': 'application/json' },
266
+ body: JSON.stringify({
267
+ loaded: true,
268
+ hasContent: true,
269
+ url: 'http://localhost:3112/',
270
+ errorCount: 0,
271
+ }),
272
+ });
273
+ const health = getPreviewHealthReport();
274
+ expect(health).not.toBeNull();
275
+ expect(health.loaded).toBe(true);
276
+ expect(health.hasContent).toBe(true);
277
+ });
278
+ it('should inject health script into HTML responses', async () => {
279
+ const { startEditorProxy } = require('../editorProxy');
280
+ // Target that returns HTML
281
+ targetServer = http.createServer((_req, res) => {
282
+ res.writeHead(200, { 'Content-Type': 'text/html' });
283
+ res.end('<html><head><title>App</title></head><body><div>Hello</div></body></html>');
284
+ });
285
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
286
+ targetPort = targetServer.address().port;
287
+ const result = await startEditorProxy({
288
+ port: 0,
289
+ targetUrl: `http://localhost:${targetPort}`,
290
+ });
291
+ const response = await fetch(`http://127.0.0.1:${result.port}/`);
292
+ const body = await response.text();
293
+ expect(body).toContain('data-codeyam-health');
294
+ expect(body).toContain('/__codeyam__/preview-health');
295
+ expect(body).toContain('<title>App</title>');
296
+ expect(body).toContain('<div>Hello</div>');
297
+ });
298
+ it('should NOT inject health script into non-HTML responses', async () => {
299
+ const { startEditorProxy } = require('../editorProxy');
300
+ targetServer = http.createServer((_req, res) => {
301
+ res.writeHead(200, { 'Content-Type': 'application/json' });
302
+ res.end('{"data": "test"}');
303
+ });
304
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
305
+ targetPort = targetServer.address().port;
306
+ const result = await startEditorProxy({
307
+ port: 0,
308
+ targetUrl: `http://localhost:${targetPort}`,
309
+ });
310
+ const response = await fetch(`http://127.0.0.1:${result.port}/api/data`);
311
+ const body = await response.text();
312
+ expect(body).toBe('{"data": "test"}');
313
+ expect(body).not.toContain('data-codeyam-health');
314
+ });
315
+ it('should accumulate errors across multiple health reports', async () => {
316
+ const { startEditorProxy } = require('../editorProxy');
317
+ targetServer = http.createServer((_req, res) => {
318
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
319
+ res.end('ok');
320
+ });
321
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
322
+ targetPort = targetServer.address().port;
323
+ const result = await startEditorProxy({
324
+ port: 0,
325
+ targetUrl: `http://localhost:${targetPort}`,
326
+ });
327
+ // First error report
328
+ await fetch(`http://127.0.0.1:${result.port}/__codeyam__/preview-health`, {
329
+ method: 'POST',
330
+ headers: { 'Content-Type': 'application/json' },
331
+ body: JSON.stringify({
332
+ errors: [{ type: 'error', message: 'Error 1', timestamp: 1 }],
333
+ url: 'http://localhost:3112/',
334
+ }),
335
+ });
336
+ // Second error report
337
+ await fetch(`http://127.0.0.1:${result.port}/__codeyam__/preview-health`, {
338
+ method: 'POST',
339
+ headers: { 'Content-Type': 'application/json' },
340
+ body: JSON.stringify({
341
+ errors: [
342
+ { type: 'console.error', message: 'Error 2', timestamp: 2 },
343
+ ],
344
+ url: 'http://localhost:3112/',
345
+ }),
346
+ });
347
+ const health = getPreviewHealthReport();
348
+ expect(health).not.toBeNull();
349
+ expect(health.errors).toHaveLength(2);
350
+ expect(health.errors[0].message).toBe('Error 1');
351
+ expect(health.errors[1].message).toBe('Error 2');
352
+ });
353
+ });
354
+ describe('buildLocalStorageScript', () => {
355
+ it('should return empty string when no localStorage config', () => {
356
+ const { buildLocalStorageScript } = require('../editorProxy');
357
+ expect(buildLocalStorageScript(null, 'scenario-123')).toBe('');
358
+ expect(buildLocalStorageScript(undefined, 'scenario-123')).toBe('');
359
+ });
360
+ it('should emit cleanup script when localStorage config is empty object', () => {
361
+ // BUG FIX: When switching from a scenario with localStorage data to one
362
+ // with empty localStorage (e.g. "First Launch - Welcome"), we must still
363
+ // clean up the previous scenario's keys. Otherwise the app reads stale data.
364
+ const { buildLocalStorageScript } = require('../editorProxy');
365
+ const script = buildLocalStorageScript({}, 'scenario-123');
366
+ expect(script).not.toBe('');
367
+ // Should clean up previous keys
368
+ expect(script).toContain('localStorage.removeItem');
369
+ expect(script).toContain('__codeyam_ls_keys__');
370
+ expect(script).toContain('__codeyam_ls_sid__');
371
+ // Should NOT set any new keys (empty config)
372
+ expect(script).not.toContain('localStorage.setItem(\"margo');
373
+ });
374
+ it('should generate a script that sets localStorage entries', () => {
375
+ const { buildLocalStorageScript } = require('../editorProxy');
376
+ const config = {
377
+ margo_articles: [{ id: 'a1', title: 'Test Article' }],
378
+ margo_collections: [{ id: 'c1', name: 'Test Collection' }],
379
+ };
380
+ const script = buildLocalStorageScript(config, 'scenario-abc');
381
+ // Should be wrapped in a script tag
382
+ expect(script).toMatch(/^<script data-codeyam-ls>/);
383
+ expect(script).toMatch(/<\/script>$/);
384
+ // Should gate on scenario ID to avoid re-seeding on reload
385
+ expect(script).toContain('scenario-abc');
386
+ expect(script).toContain('__codeyam_ls_sid__');
387
+ // Should set the localStorage entries
388
+ expect(script).toContain('margo_articles');
389
+ expect(script).toContain('margo_collections');
390
+ expect(script).toContain('localStorage.setItem');
391
+ // Should track which keys were set for cleanup
392
+ expect(script).toContain('__codeyam_ls_keys__');
393
+ });
394
+ it('should emit gated localStorage.clear() when prototypeId is provided and config is null', () => {
395
+ const { buildLocalStorageScript } = require('../editorProxy');
396
+ const script = buildLocalStorageScript(null, 'scenario-123', 'proto-abc');
397
+ // Should not be empty — prototypeId triggers a clear script
398
+ expect(script).not.toBe('');
399
+ expect(script).toContain('localStorage.clear()');
400
+ // Should be gated by the __codeyam_proto__ marker
401
+ expect(script).toContain('__codeyam_proto__');
402
+ expect(script).toContain('proto-abc');
403
+ });
404
+ it('should not emit clear script when prototypeId is absent and config is null', () => {
405
+ const { buildLocalStorageScript } = require('../editorProxy');
406
+ // No prototypeId — same as before
407
+ expect(buildLocalStorageScript(null, 'scenario-123')).toBe('');
408
+ expect(buildLocalStorageScript(null, 'scenario-123', null)).toBe('');
409
+ expect(buildLocalStorageScript(undefined, 'scenario-123', null)).toBe('');
410
+ });
411
+ it('should clean up keys from previous scenario before setting new ones', () => {
412
+ const { buildLocalStorageScript } = require('../editorProxy');
413
+ const config = { my_key: 'my_value' };
414
+ const script = buildLocalStorageScript(config, 'scenario-xyz');
415
+ // Should read previous keys and remove them
416
+ expect(script).toContain('__codeyam_ls_keys__');
417
+ expect(script).toContain('localStorage.removeItem');
418
+ });
419
+ it('should JSON.stringify non-string values', () => {
420
+ const { buildLocalStorageScript } = require('../editorProxy');
421
+ const config = {
422
+ string_key: 'plain string',
423
+ object_key: { nested: true },
424
+ array_key: [1, 2, 3],
425
+ };
426
+ const script = buildLocalStorageScript(config, 'scenario-1');
427
+ // Object/array values should be JSON-stringified and embedded as JS string literals.
428
+ // JSON.stringify is applied twice: once to serialize the value, once to make it a safe JS string.
429
+ // So {"nested":true} becomes "{\"nested\":true}" in the script source.
430
+ expect(script).toContain('object_key');
431
+ expect(script).toContain('nested');
432
+ expect(script).toContain('array_key');
433
+ expect(script).toContain('[1,2,3]');
434
+ });
435
+ it('should include localStorage mutation watcher that sends postMessage on changes', () => {
436
+ const { buildLocalStorageScript } = require('../editorProxy');
437
+ const config = { my_key: 'my_value' };
438
+ const script = buildLocalStorageScript(config, 'scenario-1');
439
+ // Should hook setItem, removeItem, and clear
440
+ expect(script).toContain('__codeyam_orig_setItem__');
441
+ expect(script).toContain('__codeyam_orig_removeItem__');
442
+ expect(script).toContain('__codeyam_orig_clear__');
443
+ // Should send postMessage to parent
444
+ expect(script).toContain('codeyam-localstorage-changed');
445
+ expect(script).toContain('postMessage');
446
+ // Should filter out internal codeyam keys
447
+ expect(script).toContain('__codeyam_');
448
+ });
449
+ it('should include localStorage mutation watcher even for empty localStorage config', () => {
450
+ const { buildLocalStorageScript } = require('../editorProxy');
451
+ const script = buildLocalStorageScript({}, 'scenario-1');
452
+ // Empty config still needs the watcher since the app may write to localStorage
453
+ expect(script).toContain('codeyam-localstorage-changed');
454
+ });
455
+ it('should include a listener for codeyam-get-localstorage requests', () => {
456
+ const { buildLocalStorageScript } = require('../editorProxy');
457
+ const config = { my_key: 'my_value' };
458
+ const script = buildLocalStorageScript(config, 'scenario-1');
459
+ // Should listen for get-localstorage requests from parent
460
+ expect(script).toContain('codeyam-get-localstorage');
461
+ expect(script).toContain('codeyam-localstorage-state');
462
+ });
463
+ it('should not include mutation watcher when no localStorage config and no prototypeId', () => {
464
+ const { buildLocalStorageScript } = require('../editorProxy');
465
+ // No config at all — returns empty string, no watcher needed
466
+ expect(buildLocalStorageScript(null, 'scenario-1')).toBe('');
467
+ });
468
+ it('should re-seed localStorage when scenario data changes even if ID is the same', () => {
469
+ // BUG: When a scenario is re-registered with updated data (e.g., adding
470
+ // collections to articles), the scenario ID stays the same. The guard
471
+ // checked only the ID, so the browser skipped re-seeding and showed stale
472
+ // data. The screenshot (captured by Playwright with a fresh browser)
473
+ // showed the new data, but the live preview didn't.
474
+ const { buildLocalStorageScript } = require('../editorProxy');
475
+ const originalData = {
476
+ articles: '[{"id":"a1","title":"Test"}]',
477
+ };
478
+ const updatedData = {
479
+ articles: '[{"id":"a1","title":"Test","collectionIds":["c1"]}]',
480
+ collections: '[{"id":"c1","name":"Dev"}]',
481
+ };
482
+ const script1 = buildLocalStorageScript(originalData, 'scenario-abc');
483
+ const script2 = buildLocalStorageScript(updatedData, 'scenario-abc');
484
+ // Both scripts use the same scenario ID
485
+ expect(script1).toContain('scenario-abc');
486
+ expect(script2).toContain('scenario-abc');
487
+ // The guard values must be DIFFERENT so the browser re-seeds
488
+ // Extract the guard comparison value from each script
489
+ const guardPattern = /__codeyam_ls_sid__.*?===\s*([^\)]+)\)/;
490
+ const guard1 = script1.match(guardPattern)?.[1];
491
+ const guard2 = script2.match(guardPattern)?.[1];
492
+ expect(guard1).toBeDefined();
493
+ expect(guard2).toBeDefined();
494
+ expect(guard1).not.toEqual(guard2);
495
+ });
496
+ });
497
+ describe('localStorage injection in HTML responses', () => {
498
+ it('should inject localStorage script before health script in HTML', () => {
499
+ const { buildLocalStorageScript, injectHealthScript, } = require('../editorProxy');
500
+ const lsScript = buildLocalStorageScript({ items: [1, 2] }, 'scenario-1');
501
+ // localStorage script should be injected before the health script
502
+ // (needs to run before app loads)
503
+ const html = '<html><head><title>Test</title></head><body>Hello</body></html>';
504
+ const result = injectHealthScript(html, lsScript);
505
+ expect(result).toContain('data-codeyam-ls');
506
+ expect(result).toContain('data-codeyam-health');
507
+ // localStorage script should appear BEFORE health script in the output
508
+ const lsIdx = result.indexOf('data-codeyam-ls');
509
+ const healthIdx = result.indexOf('data-codeyam-health');
510
+ expect(lsIdx).toBeLessThan(healthIdx);
511
+ });
512
+ it('should not inject localStorage script when none provided', () => {
513
+ const html = '<html><head><title>Test</title></head><body>Hello</body></html>';
514
+ const result = injectHealthScript(html);
515
+ expect(result).toContain('data-codeyam-health');
516
+ expect(result).not.toContain('data-codeyam-ls');
517
+ });
518
+ });
519
+ describe('compressed response handling', () => {
520
+ let targetServer;
521
+ let targetPort;
522
+ afterEach(async () => {
523
+ const { stopEditorProxy } = require('../editorProxy');
524
+ await stopEditorProxy();
525
+ if (targetServer?.listening) {
526
+ await new Promise((resolve) => targetServer.close(() => resolve()));
527
+ }
528
+ resetPreviewHealth();
529
+ });
530
+ it('should strip accept-encoding so target returns uncompressed HTML for injection', async () => {
531
+ const { startEditorProxy } = require('../editorProxy');
532
+ const originalHtml = '<html><head><title>Compressed</title></head><body><div>Gzipped</div></body></html>';
533
+ // Target server that compresses only when client sends Accept-Encoding
534
+ // (simulates real dev servers like Next.js/Vite)
535
+ targetServer = http.createServer((req, res) => {
536
+ const acceptEncoding = req.headers['accept-encoding'] || '';
537
+ if (acceptEncoding.includes('gzip')) {
538
+ const compressed = zlib.gzipSync(Buffer.from(originalHtml));
539
+ res.writeHead(200, {
540
+ 'Content-Type': 'text/html',
541
+ 'Content-Encoding': 'gzip',
542
+ 'Content-Length': compressed.length,
543
+ });
544
+ res.end(compressed);
545
+ }
546
+ else {
547
+ res.writeHead(200, { 'Content-Type': 'text/html' });
548
+ res.end(originalHtml);
549
+ }
550
+ });
551
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
552
+ targetPort = targetServer.address().port;
553
+ const result = await startEditorProxy({
554
+ port: 0,
555
+ targetUrl: `http://localhost:${targetPort}`,
556
+ });
557
+ expect(result).not.toBeNull();
558
+ // Request through proxy WITH Accept-Encoding (simulating a real browser)
559
+ const response = await fetch(`http://127.0.0.1:${result.port}/`, {
560
+ headers: { 'Accept-Encoding': 'gzip, deflate, br' },
561
+ });
562
+ // The proxy should return a valid, readable response
563
+ expect(response.status).toBe(200);
564
+ const body = await response.text();
565
+ // Should contain the original HTML content (not corrupted binary)
566
+ expect(body).toContain('<title>Compressed</title>');
567
+ expect(body).toContain('<div>Gzipped</div>');
568
+ // Should have injected the health script
569
+ expect(body).toContain('data-codeyam-health');
570
+ // Should NOT have Content-Encoding since the proxy serves uncompressed
571
+ expect(response.headers.get('content-encoding')).toBeNull();
572
+ });
573
+ });
574
+ describe('Cache-Control on HTML responses', () => {
575
+ let targetServer;
576
+ let targetPort;
577
+ afterEach(async () => {
578
+ const { stopEditorProxy } = require('../editorProxy');
579
+ await stopEditorProxy();
580
+ if (targetServer?.listening) {
581
+ await new Promise((resolve) => targetServer.close(() => resolve()));
582
+ }
583
+ resetPreviewHealth();
584
+ });
585
+ it('should add Cache-Control: no-store to proxied HTML responses', async () => {
586
+ const { startEditorProxy } = require('../editorProxy');
587
+ // Target server that serves plain HTML without cache headers
588
+ targetServer = http.createServer((_req, res) => {
589
+ res.writeHead(200, { 'Content-Type': 'text/html' });
590
+ res.end('<html><head><title>Test</title></head><body>Hello</body></html>');
591
+ });
592
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
593
+ targetPort = targetServer.address().port;
594
+ const result = await startEditorProxy({
595
+ port: 0,
596
+ targetUrl: `http://localhost:${targetPort}`,
597
+ });
598
+ expect(result).not.toBeNull();
599
+ const response = await fetch(`http://127.0.0.1:${result.port}/`);
600
+ expect(response.status).toBe(200);
601
+ // Proxy must set no-store so the browser doesn't cache pages between
602
+ // scenario switches (application scenarios share the same proxy URL
603
+ // but differ in seed data).
604
+ expect(response.headers.get('cache-control')).toBe('no-store, must-revalidate');
605
+ });
606
+ it('should NOT add Cache-Control: no-store to non-HTML responses', async () => {
607
+ const { startEditorProxy } = require('../editorProxy');
608
+ // Target server that serves JSON without cache headers
609
+ targetServer = http.createServer((_req, res) => {
610
+ res.writeHead(200, { 'Content-Type': 'application/json' });
611
+ res.end(JSON.stringify({ ok: true }));
612
+ });
613
+ await new Promise((resolve) => targetServer.listen(0, '127.0.0.1', () => resolve()));
614
+ targetPort = targetServer.address().port;
615
+ const result = await startEditorProxy({
616
+ port: 0,
617
+ targetUrl: `http://localhost:${targetPort}`,
618
+ });
619
+ expect(result).not.toBeNull();
620
+ const response = await fetch(`http://127.0.0.1:${result.port}/api/data`);
621
+ expect(response.status).toBe(200);
622
+ // Non-HTML responses pass through the target's original headers;
623
+ // the proxy only forces no-store on HTML.
624
+ expect(response.headers.get('cache-control')).toBeNull();
625
+ });
626
+ });
627
+ });
628
+ //# sourceMappingURL=editorProxy.test.js.map