@lowdefy/server-dev 6.1.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (624) hide show
  1. package/client/App.jsx +52 -24
  2. package/client/Inspector.jsx +73 -30
  3. package/client/JourneyObserver.jsx +47 -0
  4. package/client/Page.jsx +54 -22
  5. package/client/Recorder.jsx +73 -0
  6. package/client/Routing.jsx +37 -13
  7. package/client/clientBuildImports.test.mjs +2 -0
  8. package/client/devStreamConnections.test.mjs +40 -0
  9. package/client/feedback/FeedbackMount.jsx +2 -2
  10. package/client/feedback/FeedbackOverlay.jsx +7 -4
  11. package/client/feedback/feedbackStyles.js +3 -0
  12. package/client/journeyObserver/startJourneyObserver.js +101 -0
  13. package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
  14. package/client/openInEditor/OpenInEditorListener.jsx +2 -0
  15. package/client/recorder/buildEngineRecord.js +37 -0
  16. package/client/recorder/buildInteractionRecord.js +64 -0
  17. package/client/recorder/buildTraceEvent.js +57 -0
  18. package/client/recorder/buildTraceEvent.test.mjs +81 -0
  19. package/client/recorder/chunkRecords.js +69 -0
  20. package/client/recorder/chunkRecords.test.mjs +59 -0
  21. package/client/recorder/collectEventActions.js +30 -0
  22. package/client/recorder/collectEventEndpoints.js +40 -0
  23. package/client/recorder/collectEventRequests.js +39 -0
  24. package/client/recorder/createPairingBuffer.js +187 -0
  25. package/client/recorder/createPairingBuffer.test.mjs +405 -0
  26. package/client/recorder/createPasswordRedactor.js +84 -0
  27. package/client/recorder/createRecordBatcher.js +54 -0
  28. package/client/recorder/createRecordBatcher.test.mjs +76 -0
  29. package/client/recorder/createRecorder.js +216 -0
  30. package/client/recorder/createRecorder.test.mjs +318 -0
  31. package/client/recorder/createRecordingSession.js +61 -0
  32. package/client/recorder/createRecordingSession.test.mjs +72 -0
  33. package/client/recorder/diffStateWrites.js +77 -0
  34. package/client/recorder/diffStateWrites.test.mjs +66 -0
  35. package/client/recorder/isEventCall.js +30 -0
  36. package/client/recorder/jsonType.js +39 -0
  37. package/client/recorder/keyChord.js +47 -0
  38. package/client/recorder/keyChord.test.mjs +50 -0
  39. package/client/recorder/sendRecords.js +40 -0
  40. package/client/recorder/toJsonSafe.js +29 -0
  41. package/lib/client/BuildingPage.jsx +3 -1
  42. package/lib/client/ErrorBar.jsx +17 -13
  43. package/lib/client/RedirectingPage.jsx +56 -0
  44. package/lib/client/auth/Auth.jsx +11 -6
  45. package/lib/client/auth/AuthConfigured.jsx +222 -36
  46. package/lib/client/auth/AuthNotConfigured.js +45 -4
  47. package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
  48. package/lib/client/auth/authTemplateSync.test.mjs +40 -0
  49. package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
  50. package/lib/client/auth/createFetchCheckingBuild.js +45 -0
  51. package/lib/client/bundleBuildId.js +25 -0
  52. package/lib/client/collectVisibleBlockIds.js +51 -0
  53. package/lib/client/getCspNonce.js +25 -0
  54. package/lib/client/getPagePath.js +36 -0
  55. package/lib/client/getPagePath.test.mjs +51 -0
  56. package/lib/client/utils/formatErrorsForCopy.js +30 -0
  57. package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
  58. package/lib/client/utils/getErrorBarColor.js +25 -0
  59. package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
  60. package/lib/client/utils/request.js +8 -1
  61. package/lib/client/utils/usePageConfig.js +89 -25
  62. package/lib/client/utils/usePageConfig.test.mjs +198 -13
  63. package/lib/configTree/buildConfigTree.mjs +58 -0
  64. package/lib/configTree/buildConfigTree.test.mjs +77 -0
  65. package/lib/configTree/collectConfigText.mjs +101 -0
  66. package/lib/configTree/collectConfigText.test.mjs +116 -0
  67. package/lib/configTree/prepareScratchServer.mjs +46 -0
  68. package/lib/configTree/runConfigTreeBuild.mjs +88 -0
  69. package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
  70. package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
  71. package/lib/docs/JourneyStepError.js +30 -0
  72. package/lib/docs/acquireBrowserSlot.js +30 -0
  73. package/lib/docs/addNestedEndpoints.js +54 -0
  74. package/lib/docs/addNestedEndpoints.test.mjs +185 -0
  75. package/lib/docs/addWriteFlags.js +77 -0
  76. package/lib/docs/buildEditedPages.js +50 -0
  77. package/lib/docs/buildWaitHeader.js +21 -0
  78. package/lib/docs/captureAnnotatedScreenshot.js +23 -12
  79. package/lib/docs/checkAgentFiles.js +148 -0
  80. package/lib/docs/checkAgentFiles.test.mjs +225 -0
  81. package/lib/docs/checkStepReferences.js +239 -0
  82. package/lib/docs/checkStepReferences.test.mjs +173 -0
  83. package/lib/docs/checkpointStore.js +3 -0
  84. package/lib/docs/clientErrorStore.js +18 -1
  85. package/lib/docs/clientErrorStore.test.mjs +46 -0
  86. package/lib/docs/collectExercised.js +52 -0
  87. package/lib/docs/createBrowserLifecycle.js +102 -0
  88. package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
  89. package/lib/docs/createDocsMcpServer.js +345 -388
  90. package/lib/docs/createDocsMcpServer.test.mjs +644 -4
  91. package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
  92. package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
  93. package/lib/docs/createJourneyActors.js +213 -0
  94. package/lib/docs/createJourneyActors.test.mjs +79 -0
  95. package/lib/docs/createJourneyObservations.js +80 -0
  96. package/lib/docs/createLeftOriginError.js +26 -0
  97. package/lib/docs/createNetworkCounter.js +101 -0
  98. package/lib/docs/dataSets/checkSharedCollectionIds.js +78 -0
  99. package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
  100. package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +727 -0
  101. package/lib/docs/dataSets/describeDataSetResult.js +25 -0
  102. package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
  103. package/lib/docs/dataSets/describeTargetKey.js +29 -0
  104. package/lib/docs/dataSets/deserializeFixture.js +34 -0
  105. package/lib/docs/dataSets/drainSessionWork.js +37 -0
  106. package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
  107. package/lib/docs/dataSets/duplicateIndexName.js +24 -0
  108. package/lib/docs/dataSets/getDataStore.js +106 -0
  109. package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
  110. package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
  111. package/lib/docs/dataSets/groupDataSetByCollection.js +52 -0
  112. package/lib/docs/dataSets/insertFixture.js +57 -0
  113. package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
  114. package/lib/docs/dataSets/isDataStoreGone.js +29 -0
  115. package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
  116. package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
  117. package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
  118. package/lib/docs/dataSets/openDataSession.js +133 -0
  119. package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +493 -0
  120. package/lib/docs/dataSets/pickDataStorePort.js +58 -0
  121. package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
  122. package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
  123. package/lib/docs/dataSets/readDataSession.js +41 -0
  124. package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
  125. package/lib/docs/dataSets/readDataSet.js +83 -0
  126. package/lib/docs/dataSets/readDataSet.test.mjs +251 -0
  127. package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
  128. package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
  129. package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
  130. package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
  131. package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
  132. package/lib/docs/dataSets/sessionDatabaseName.js +32 -0
  133. package/lib/docs/dataSets/sweepOrphanDatabases.js +36 -0
  134. package/lib/docs/dataSets/test/app/lowdefy.yaml +225 -0
  135. package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
  136. package/lib/docs/dataSets/test/app/tests/data/shop.yaml +12 -0
  137. package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
  138. package/lib/docs/devEventBus.js +136 -0
  139. package/lib/docs/devEventBus.test.mjs +269 -0
  140. package/lib/docs/devToolDefinitions.js +529 -0
  141. package/lib/docs/docSources.js +21 -0
  142. package/lib/docs/docs.test.mjs +171 -15
  143. package/lib/docs/docsIndex.test.mjs +377 -0
  144. package/lib/docs/evalOperator.js +5 -3
  145. package/lib/docs/evalOperatorHeadless.js +84 -12
  146. package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
  147. package/lib/docs/evalOperatorInTab.js +2 -1
  148. package/lib/docs/findConfig.js +95 -49
  149. package/lib/docs/fitResponse.js +81 -0
  150. package/lib/docs/fitResponse.test.mjs +128 -0
  151. package/lib/docs/formatFeedback.js +26 -5
  152. package/lib/docs/formatFeedback.test.mjs +48 -0
  153. package/lib/docs/getAppMap.js +7 -1
  154. package/lib/docs/getBrowser.js +150 -80
  155. package/lib/docs/getBrowser.test.mjs +407 -16
  156. package/lib/docs/getBuildId.js +61 -0
  157. package/lib/docs/getBuildId.test.mjs +84 -0
  158. package/lib/docs/getBuildStatus.js +81 -7
  159. package/lib/docs/getBuildStatus.test.mjs +229 -0
  160. package/lib/docs/getBuildStatusAfterEdits.js +35 -0
  161. package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
  162. package/lib/docs/getCoreDoc.js +9 -1
  163. package/lib/docs/getDoc.js +100 -0
  164. package/lib/docs/getDocsIndex.js +152 -0
  165. package/lib/docs/getHazards.js +115 -0
  166. package/lib/docs/getHazards.test.mjs +175 -0
  167. package/lib/docs/getMailOutboxDirectory.js +26 -0
  168. package/lib/docs/getOverview.js +79 -13
  169. package/lib/docs/getOverviewBasePath.test.mjs +37 -0
  170. package/lib/docs/getPageBuildStatus.js +46 -0
  171. package/lib/docs/getPluginDoc.js +21 -23
  172. package/lib/docs/getSchema.js +33 -1
  173. package/lib/docs/getStaleStatus.js +36 -0
  174. package/lib/docs/getStaleStatus.test.mjs +74 -0
  175. package/lib/docs/guardJourneyOrigin.js +39 -0
  176. package/lib/docs/inspectState.js +5 -3
  177. package/lib/docs/inspectStateFromTab.js +2 -2
  178. package/lib/docs/inspectStateHeadless.js +89 -27
  179. package/lib/docs/inspectStateHeadless.test.mjs +20 -1
  180. package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
  181. package/lib/docs/installHeadlessShell.js +123 -0
  182. package/lib/docs/installHeadlessShell.test.mjs +70 -0
  183. package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
  184. package/lib/docs/isHeadlessShellIncomplete.js +34 -0
  185. package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
  186. package/lib/docs/isPageReady.js +77 -0
  187. package/lib/docs/isPageReady.test.mjs +235 -0
  188. package/lib/docs/isRunErrorEntry.js +25 -0
  189. package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
  190. package/lib/docs/journeyRunRecording.js +35 -0
  191. package/lib/docs/journeyRunRecording.test.mjs +39 -0
  192. package/lib/docs/keepEventStreamAlive.js +68 -0
  193. package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
  194. package/lib/docs/launchBrowser.js +83 -0
  195. package/lib/docs/launchBrowser.test.mjs +175 -0
  196. package/lib/docs/listModuleDocEntries.js +69 -0
  197. package/lib/docs/listPackageDocFiles.js +67 -0
  198. package/lib/docs/listPluginDocEntries.js +111 -0
  199. package/lib/docs/listPlugins.js +9 -58
  200. package/lib/docs/listTypes.js +14 -6
  201. package/lib/docs/loadFrameworkHazards.js +40 -0
  202. package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
  203. package/lib/docs/loadState.js +103 -35
  204. package/lib/docs/makeModuleManifestDoc.js +174 -0
  205. package/lib/docs/matchExercisedPages.js +35 -0
  206. package/lib/docs/matchJourneyRoute.js +69 -0
  207. package/lib/docs/matchJourneyRoute.test.mjs +178 -0
  208. package/lib/docs/mergeNetworkSnapshots.js +49 -0
  209. package/lib/docs/nextJourneySequence.js +30 -0
  210. package/lib/docs/noBrowserError.js +22 -0
  211. package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
  212. package/lib/docs/observe/claimExpectedErrors.js +67 -0
  213. package/lib/docs/observe/createJourneyAppErrors.js +236 -0
  214. package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
  215. package/lib/docs/observe/evaluateInvariants.js +183 -0
  216. package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
  217. package/lib/docs/observe/findingKey.js +29 -0
  218. package/lib/docs/observe/hasNoEffect.js +31 -0
  219. package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
  220. package/lib/docs/observe/installStepObserver.js +72 -0
  221. package/lib/docs/observe/isAppApiUrl.js +33 -0
  222. package/lib/docs/observe/parseAppApiUrl.js +37 -0
  223. package/lib/docs/observe/readStepObserver.js +42 -0
  224. package/lib/docs/observe/relativeSource.js +29 -0
  225. package/lib/docs/observe/resolveConfigKeySource.js +33 -0
  226. package/lib/docs/observe/takeJourneyEvents.js +36 -0
  227. package/lib/docs/observe/toAppErrorFailure.js +61 -0
  228. package/lib/docs/observe/usesSearchStage.js +45 -0
  229. package/lib/docs/observe/waitForClientErrorReports.js +31 -0
  230. package/lib/docs/observe/watchJourneyContext.js +75 -0
  231. package/lib/docs/observe/withAppErrors.js +31 -0
  232. package/lib/docs/observe/withAppErrors.test.mjs +101 -0
  233. package/lib/docs/openJourney.js +94 -0
  234. package/lib/docs/openJourneyEmail.js +41 -0
  235. package/lib/docs/openJourneyEmail.test.mjs +187 -0
  236. package/lib/docs/pageBlocks.js +47 -0
  237. package/lib/docs/pageBuildStatus.test.mjs +103 -0
  238. package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
  239. package/lib/docs/rails/authEngineActions.js +53 -0
  240. package/lib/docs/rails/authEngineActions.test.mjs +69 -0
  241. package/lib/docs/rails/authEngineMethods.js +52 -0
  242. package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
  243. package/lib/docs/rails/checkAuthActionsRan.js +66 -0
  244. package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
  245. package/lib/docs/rails/checkClickRails.js +56 -0
  246. package/lib/docs/rails/createDataSetRails.js +82 -0
  247. package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
  248. package/lib/docs/rails/findExternalBlocks.js +147 -0
  249. package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
  250. package/lib/docs/rails/installAuthActionRecorder.js +56 -0
  251. package/lib/docs/rails/readAuthActionRecorder.js +32 -0
  252. package/lib/docs/rails/readBuiltArtifact.js +30 -0
  253. package/lib/docs/readConnectionPlugins.js +26 -0
  254. package/lib/docs/readDevAuthMode.js +32 -0
  255. package/lib/docs/readDocEntry.js +40 -0
  256. package/lib/docs/readDocTitle.js +26 -0
  257. package/lib/docs/readJourneyEmailMatch.js +57 -0
  258. package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
  259. package/lib/docs/readJourneySession.js +56 -0
  260. package/lib/docs/readMailOutbox.js +37 -0
  261. package/lib/docs/readPagePath.js +27 -0
  262. package/lib/docs/readPluginPackages.js +99 -0
  263. package/lib/docs/readProxyBuildWait.js +38 -0
  264. package/lib/docs/readRoutineSteps.js +45 -0
  265. package/lib/docs/registerShownTextEngine.js +118 -0
  266. package/lib/docs/requestRestart.js +30 -0
  267. package/lib/docs/requestRestart.test.mjs +49 -0
  268. package/lib/docs/resolvePageInstance.js +46 -0
  269. package/lib/docs/resolvePageInstance.test.mjs +81 -0
  270. package/lib/docs/resolveSource.js +11 -7
  271. package/lib/docs/resolveSource.test.mjs +1 -1
  272. package/lib/docs/resolveToolCaller.js +62 -0
  273. package/lib/docs/reviewPage.js +51 -0
  274. package/lib/docs/reviewPageBuilds.js +56 -0
  275. package/lib/docs/reviewPageBuilds.test.mjs +207 -0
  276. package/lib/docs/runCheck.js +75 -0
  277. package/lib/docs/runCheck.test.mjs +91 -0
  278. package/lib/docs/runCheckChild.js +49 -0
  279. package/lib/docs/runEndpoint.js +185 -0
  280. package/lib/docs/runEndpoint.test.mjs +509 -0
  281. package/lib/docs/runErrorBuffers.js +99 -0
  282. package/lib/docs/runErrorBuffers.test.mjs +95 -0
  283. package/lib/docs/runJourney.js +347 -0
  284. package/lib/docs/runJourney.test.mjs +2383 -0
  285. package/lib/docs/runJourneyAsUsers.js +44 -0
  286. package/lib/docs/runJourneyDataSet.test.mjs +274 -0
  287. package/lib/docs/runJourneySteps.js +1320 -0
  288. package/lib/docs/runRequest.js +100 -59
  289. package/lib/docs/runRequest.test.mjs +190 -0
  290. package/lib/docs/saveAnnotatedScreenshot.js +1 -1
  291. package/lib/docs/scaffoldPage.js +3 -1
  292. package/lib/docs/screenshotPage.js +163 -11
  293. package/lib/docs/screenshotPage.test.mjs +263 -1
  294. package/lib/docs/screenshotPageClip.test.mjs +4 -0
  295. package/lib/docs/searchDocs.js +82 -30
  296. package/lib/docs/searchDocs.test.mjs +100 -0
  297. package/lib/docs/searchIcons.js +90 -0
  298. package/lib/docs/searchIcons.test.mjs +127 -0
  299. package/lib/docs/selectExercised.js +39 -0
  300. package/lib/docs/selectFinalState.js +66 -0
  301. package/lib/docs/selectFinalState.test.mjs +51 -0
  302. package/lib/docs/serverErrorStore.js +54 -0
  303. package/lib/docs/serverErrorStore.test.mjs +50 -0
  304. package/lib/docs/setupTestFixtures.mjs +133 -39
  305. package/lib/docs/shownTextSelector.js +28 -0
  306. package/lib/docs/snapshotState.js +13 -5
  307. package/lib/docs/splitSearchTerms.js +62 -0
  308. package/lib/docs/splitSearchTerms.test.mjs +50 -0
  309. package/lib/docs/stateCheckpoints.test.mjs +77 -0
  310. package/lib/docs/tabAvailable.js +6 -5
  311. package/lib/docs/tabChannel.js +127 -21
  312. package/lib/docs/tabChannel.test.mjs +187 -29
  313. package/lib/docs/unsettledPageNote.js +24 -0
  314. package/lib/docs/validateJourneyMail.js +36 -0
  315. package/lib/docs/validateJourneyTimeout.js +38 -0
  316. package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
  317. package/lib/docs/validateRecordingParam.js +42 -0
  318. package/lib/docs/validateStateSelection.js +33 -0
  319. package/lib/docs/validateStateSelection.test.mjs +33 -0
  320. package/lib/docs/validateViewport.js +51 -0
  321. package/lib/docs/validateViewport.test.mjs +54 -0
  322. package/lib/docs/waitForBuild.js +50 -0
  323. package/lib/docs/waitForBuild.test.mjs +75 -0
  324. package/lib/docs/waitForJourneyEmail.js +77 -0
  325. package/lib/docs/withBrowserSlot.js +45 -0
  326. package/lib/docs/withBrowserSlot.test.mjs +75 -0
  327. package/lib/docs/withDataSession.js +53 -0
  328. package/lib/server/applyDataSetRedirect.js +92 -0
  329. package/lib/server/applyDataSetRedirect.test.mjs +446 -0
  330. package/lib/server/applyDataSetRedirectTenantReach.test.mjs +207 -0
  331. package/lib/server/applyDataSetRedirectWalled.test.mjs +134 -0
  332. package/lib/server/auth/createSystemContext.js +73 -0
  333. package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
  334. package/lib/server/auth/getHeadlessUser.js +9 -8
  335. package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
  336. package/lib/server/auth/getMockUser.js +18 -14
  337. package/lib/server/auth/{session.js → getStrategies.js} +17 -16
  338. package/lib/server/auth/headlessUser.js +3 -2
  339. package/lib/server/auth/journeyActor.js +35 -0
  340. package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
  341. package/lib/server/checkPageRecord.js +44 -0
  342. package/lib/server/contextMapBudget.js +24 -0
  343. package/lib/server/contextMapBudget.test.mjs +98 -0
  344. package/lib/server/continueJitKeys.js +28 -0
  345. package/lib/server/continueJitKeys.test.mjs +43 -0
  346. package/lib/server/createDataSessionEndedError.js +33 -0
  347. package/lib/server/createDataSetRefusal.js +26 -0
  348. package/lib/server/createLowdefyContext.js +168 -41
  349. package/lib/server/createLowdefyContext.test.mjs +331 -8
  350. package/lib/server/getClientAddress.js +51 -0
  351. package/lib/server/getClientAddress.test.mjs +56 -0
  352. package/lib/server/getPageJitEnrichment.test.mjs +29 -11
  353. package/lib/server/hashConfigContent.js +26 -0
  354. package/lib/server/importAppCode.test.mjs +57 -0
  355. package/lib/server/isRoutineStep.js +27 -0
  356. package/lib/server/jitPageBuilder.js +309 -126
  357. package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
  358. package/lib/server/jitPageBuilder.test.mjs +218 -0
  359. package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
  360. package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
  361. package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
  362. package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
  363. package/lib/server/journeyCookies.js +22 -0
  364. package/lib/server/journeyCookies.test.mjs +145 -0
  365. package/lib/server/loadDynamicJsMap.js +47 -0
  366. package/lib/server/log/createHandleError.js +38 -2
  367. package/lib/server/log/createHandleError.test.mjs +125 -2
  368. package/lib/server/log/createLogger.js +3 -0
  369. package/lib/server/log/createLogger.test.mjs +15 -0
  370. package/lib/server/log/logRequest.js +2 -3
  371. package/lib/server/mutantDataSetWrappers.test.mjs +115 -0
  372. package/lib/server/mutants/applyMutant.js +39 -0
  373. package/lib/server/mutants/artifactPatterns.js +25 -0
  374. package/lib/server/mutants/buildAnchor.js +45 -0
  375. package/lib/server/mutants/collectSharedIds.js +41 -0
  376. package/lib/server/mutants/configPathSegments.js +38 -0
  377. package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
  378. package/lib/server/mutants/describeEvent.js +22 -0
  379. package/lib/server/mutants/enumerateArtifact.js +56 -0
  380. package/lib/server/mutants/findNodeByKey.js +45 -0
  381. package/lib/server/mutants/findNodeByPointer.js +49 -0
  382. package/lib/server/mutants/getArtifactKind.js +32 -0
  383. package/lib/server/mutants/groupMutantCopies.js +56 -0
  384. package/lib/server/mutants/hashArtifact.js +25 -0
  385. package/lib/server/mutants/hashMutantTarget.js +34 -0
  386. package/lib/server/mutants/listMutants.js +122 -0
  387. package/lib/server/mutants/listMutants.test.mjs +502 -0
  388. package/lib/server/mutants/mutantId.js +30 -0
  389. package/lib/server/mutants/mutantRuns.js +57 -0
  390. package/lib/server/mutants/mutantRuns.test.mjs +136 -0
  391. package/lib/server/mutants/operators/dropAction.js +47 -0
  392. package/lib/server/mutants/operators/dropBlock.js +44 -0
  393. package/lib/server/mutants/operators/dropPayload.js +52 -0
  394. package/lib/server/mutants/operators/dropStep.js +44 -0
  395. package/lib/server/mutants/operators/flipVisible.js +53 -0
  396. package/lib/server/mutants/operators/index.js +37 -0
  397. package/lib/server/mutants/operators/retargetLink.js +72 -0
  398. package/lib/server/mutants/operators/skipValidate.js +77 -0
  399. package/lib/server/mutants/operators/swapIf.js +112 -0
  400. package/lib/server/mutants/operators.test.mjs +396 -0
  401. package/lib/server/mutants/positionFreePath.js +38 -0
  402. package/lib/server/mutants/removeFromParent.js +28 -0
  403. package/lib/server/mutants/test/fixtures.mjs +173 -0
  404. package/lib/server/mutants/test/keyArtifact.mjs +63 -0
  405. package/lib/server/mutants/validateMutantParam.js +69 -0
  406. package/lib/server/mutants/validateMutantsBody.js +88 -0
  407. package/lib/server/mutants/walkArtifact.js +179 -0
  408. package/lib/server/pageBuildRecords.js +131 -0
  409. package/lib/server/pageBuildRecords.test.mjs +258 -0
  410. package/lib/server/pageCache.mjs +22 -7
  411. package/lib/server/pageCache.test.mjs +22 -7
  412. package/lib/server/pageRebuilds.test.mjs +543 -0
  413. package/lib/server/pruneJitMaps.js +36 -0
  414. package/lib/server/pruneJitMaps.test.mjs +55 -0
  415. package/lib/server/readInstanceRecord.js +33 -0
  416. package/lib/server/readInstanceRecord.test.mjs +99 -0
  417. package/lib/server/readMergedMaps.js +86 -0
  418. package/lib/server/readMergedMaps.test.mjs +79 -0
  419. package/lib/server/recording/appendRecords.js +33 -0
  420. package/lib/server/recording/errorRecordingStamp.js +34 -0
  421. package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
  422. package/lib/server/recording/isRecordingEnabled.js +31 -0
  423. package/lib/server/recording/readRecordingCookie.js +71 -0
  424. package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
  425. package/lib/server/recording/recordingCookiePayload.js +33 -0
  426. package/lib/server/recording/servedBuilds.js +46 -0
  427. package/lib/server/recording/servedBuilds.test.mjs +42 -0
  428. package/lib/server/sinkExternalConnections.js +95 -0
  429. package/lib/server/sinkExternalConnections.test.mjs +135 -0
  430. package/lib/server/skipStaleMapWrites.js +62 -0
  431. package/lib/server/skipStaleMapWrites.test.mjs +113 -0
  432. package/lib/server/startIdleGc.js +67 -0
  433. package/lib/server/startIdleGc.test.mjs +138 -0
  434. package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
  435. package/lib/server/trackSessionWork.js +30 -0
  436. package/lib/vite/createDevServerExclude.js +40 -0
  437. package/lib/vite/createDevServerExclude.test.mjs +79 -0
  438. package/manager/getContext.mjs +25 -3
  439. package/manager/processes/initialBuild.mjs +17 -1
  440. package/manager/processes/initialBuild.test.mjs +104 -0
  441. package/manager/processes/lowdefyBuild.mjs +31 -7
  442. package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +72 -0
  443. package/manager/processes/lowdefyBuild.test.mjs +136 -1
  444. package/manager/processes/optimizeDependencies.mjs +59 -0
  445. package/manager/processes/restartServer.mjs +34 -6
  446. package/manager/processes/restartServer.test.mjs +162 -0
  447. package/manager/processes/shutdownServer.mjs +11 -0
  448. package/manager/processes/shutdownServer.test.mjs +45 -0
  449. package/manager/processes/startFirstServer.mjs +46 -0
  450. package/manager/processes/startFirstServer.test.mjs +326 -0
  451. package/manager/processes/startMailSink.mjs +135 -0
  452. package/manager/processes/startMailSink.test.mjs +146 -0
  453. package/manager/processes/startProxy.mjs +129 -12
  454. package/manager/processes/startProxy.test.mjs +366 -0
  455. package/manager/processes/startServer.mjs +47 -6
  456. package/manager/processes/startServer.test.mjs +155 -0
  457. package/manager/processes/startWatchers.mjs +6 -4
  458. package/manager/processes/syncServer.mjs +69 -0
  459. package/manager/processes/syncServer.test.mjs +141 -0
  460. package/manager/processes/waitForDevServer.mjs +48 -0
  461. package/manager/processes/waitForDevServer.test.mjs +112 -0
  462. package/manager/run.mjs +128 -43
  463. package/manager/utils/BatchChanges.mjs +21 -5
  464. package/manager/utils/BatchChanges.test.mjs +77 -0
  465. package/manager/utils/acquireDevInstance.mjs +99 -0
  466. package/manager/utils/acquireDevInstance.test.mjs +160 -0
  467. package/manager/utils/createBuildActivity.mjs +67 -0
  468. package/manager/utils/createBuildActivity.test.mjs +58 -0
  469. package/manager/utils/createChangeSignal.mjs +39 -0
  470. package/manager/utils/createChangeSignal.test.mjs +62 -0
  471. package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
  472. package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
  473. package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
  474. package/manager/utils/createDotPathIgnore.mjs +44 -0
  475. package/manager/utils/createDotPathIgnore.test.mjs +65 -0
  476. package/manager/utils/createIdleGc.mjs +51 -0
  477. package/manager/utils/createIdleGc.test.mjs +77 -0
  478. package/manager/utils/createRequestActivity.mjs +100 -0
  479. package/manager/utils/createRequestActivity.test.mjs +121 -0
  480. package/manager/utils/createServerArtifactTracker.mjs +83 -0
  481. package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
  482. package/manager/utils/createServerEnv.mjs +39 -0
  483. package/manager/utils/filesHaveSameBytes.mjs +41 -0
  484. package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
  485. package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
  486. package/manager/utils/importFresh.mjs +46 -0
  487. package/manager/utils/importFresh.test.mjs +72 -0
  488. package/manager/utils/importFreshWorker.mjs +20 -0
  489. package/manager/utils/killTaggedBrowser.mjs +35 -0
  490. package/manager/utils/pagePathChanged.mjs +56 -0
  491. package/manager/utils/pruneRecordings.mjs +85 -0
  492. package/manager/utils/pruneRecordings.test.mjs +117 -0
  493. package/manager/utils/publishBuildDirectory.mjs +121 -0
  494. package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
  495. package/manager/utils/publishBuildDirectory.test.mjs +262 -0
  496. package/manager/utils/readBasePath.mjs +27 -0
  497. package/manager/utils/readBasePath.test.mjs +43 -0
  498. package/manager/utils/readBuildStatusWait.mjs +67 -0
  499. package/manager/utils/readManagerVersion.mjs +30 -0
  500. package/manager/utils/readManagerVersion.test.mjs +35 -0
  501. package/manager/utils/readPluginDefinitions.mjs +36 -0
  502. package/manager/utils/resolveDevAuthUrl.mjs +58 -0
  503. package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
  504. package/manager/utils/resolvePorts.mjs +49 -0
  505. package/manager/utils/setupWatcher.mjs +19 -11
  506. package/manager/utils/startRecordingPruner.mjs +45 -0
  507. package/manager/utils/startRecordingPruner.test.mjs +66 -0
  508. package/manager/utils/waitForChildExit.mjs +53 -0
  509. package/manager/utils/waitForChildExit.test.mjs +70 -0
  510. package/manager/utils/waitForServer.mjs +44 -0
  511. package/manager/utils/writeBuildStatus.mjs +1 -1
  512. package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
  513. package/manager/watchers/envWatcher.mjs +9 -2
  514. package/manager/watchers/envWatcher.test.mjs +87 -0
  515. package/manager/watchers/listServerSidePackages.mjs +47 -0
  516. package/manager/watchers/listServerSidePackages.test.mjs +38 -0
  517. package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
  518. package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
  519. package/manager/watchers/pluginSourceWatcher.mjs +79 -0
  520. package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
  521. package/manager/watchers/restartRequestWatcher.mjs +71 -0
  522. package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
  523. package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
  524. package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
  525. package/manager/watchers/serverPackageWatcher.mjs +38 -0
  526. package/package.json +60 -47
  527. package/package.original.json +60 -47
  528. package/src/app.js +131 -20
  529. package/src/html/renderDevPage.js +63 -11
  530. package/src/html/renderDevPage.test.mjs +138 -0
  531. package/src/lib/getRequestPath.js +29 -0
  532. package/src/middleware/createSameOriginGuard.js +37 -0
  533. package/src/middleware/createSameOriginGuard.test.mjs +102 -0
  534. package/src/middleware/errorHandler.js +51 -1
  535. package/src/middleware/errorHandler.test.mjs +173 -3
  536. package/src/middleware/isRebindingSafeHost.js +44 -0
  537. package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
  538. package/src/middleware/localDevToolsOnly.js +38 -0
  539. package/src/middleware/localDevToolsOnly.test.mjs +61 -0
  540. package/src/middleware/noStore.js +27 -0
  541. package/src/middleware/noStore.test.mjs +48 -0
  542. package/src/middleware/requestTimeout.js +38 -0
  543. package/src/middleware/staleFlag.js +76 -0
  544. package/src/middleware/staleFlag.test.mjs +127 -0
  545. package/src/middleware/stampCaller.js +38 -0
  546. package/src/middleware/stampCaller.test.mjs +64 -0
  547. package/src/routes/agent.js +15 -3
  548. package/src/routes/auth.js +29 -20
  549. package/src/routes/auth.test.mjs +30 -56
  550. package/src/routes/clientError.js +13 -13
  551. package/src/routes/cron.js +3 -1
  552. package/src/routes/cronForward.js +3 -1
  553. package/src/routes/detached.js +22 -9
  554. package/src/routes/devInspect.js +17 -8
  555. package/src/routes/devInspect.test.mjs +44 -7
  556. package/src/routes/devRecording.js +113 -0
  557. package/src/routes/devRecording.test.mjs +253 -0
  558. package/src/routes/docs/buildStatus.js +10 -2
  559. package/src/routes/docs/buildStatus.test.mjs +46 -0
  560. package/src/routes/docs/content.js +5 -3
  561. package/src/routes/docs/evalOperator.js +15 -1
  562. package/src/routes/docs/events.js +50 -0
  563. package/src/routes/docs/events.test.mjs +117 -0
  564. package/src/routes/docs/find.js +9 -1
  565. package/src/routes/docs/icons.js +30 -0
  566. package/src/routes/docs/inspectState.js +16 -1
  567. package/src/routes/docs/journey.js +194 -0
  568. package/src/routes/docs/journey.test.mjs +401 -0
  569. package/src/routes/docs/journeyRefusals.test.mjs +71 -0
  570. package/src/routes/docs/loadState.js +4 -2
  571. package/src/routes/docs/mcp.js +34 -3
  572. package/src/routes/docs/mcp.test.mjs +130 -0
  573. package/src/routes/docs/mutants.js +78 -0
  574. package/src/routes/docs/mutants.test.mjs +180 -0
  575. package/src/routes/docs/parsePathParamsParam.js +41 -0
  576. package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
  577. package/src/routes/docs/parseUserParam.js +27 -21
  578. package/src/routes/docs/parseUserParam.test.mjs +17 -5
  579. package/src/routes/docs/restart.js +35 -0
  580. package/src/routes/docs/restart.test.mjs +64 -0
  581. package/src/routes/docs/runEndpoint.js +54 -0
  582. package/src/routes/docs/runEndpoint.test.mjs +165 -0
  583. package/src/routes/docs/runRequest.js +25 -8
  584. package/src/routes/docs/runRequest.test.mjs +92 -0
  585. package/src/routes/docs/screenshot.js +50 -2
  586. package/src/routes/docs/screenshot.test.mjs +117 -0
  587. package/src/routes/docs/search.js +15 -2
  588. package/src/routes/docs/snapshotState.js +17 -3
  589. package/src/routes/endpoints.js +27 -26
  590. package/src/routes/endpointsTextAnswer.test.mjs +77 -0
  591. package/src/routes/feedback.js +10 -13
  592. package/src/routes/jitPage.js +99 -35
  593. package/src/routes/jitPage.test.mjs +248 -0
  594. package/src/routes/mcp.js +82 -5
  595. package/src/routes/mcp.test.mjs +215 -0
  596. package/src/routes/mcpMemberToken.test.mjs +125 -0
  597. package/src/routes/mcpProtectedResourceMetadata.js +34 -0
  598. package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
  599. package/src/routes/mountDevPageRoutes.js +25 -0
  600. package/src/routes/mountDevPageRoutes.test.mjs +30 -0
  601. package/src/routes/mountOauthDiscovery.js +44 -0
  602. package/src/routes/mountOauthDiscovery.test.mjs +79 -0
  603. package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
  604. package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
  605. package/src/routes/reload.js +16 -0
  606. package/src/routes/request.js +6 -4
  607. package/src/routes/request.test.mjs +9 -5
  608. package/src/routes/requestBody.test.mjs +159 -0
  609. package/src/routes/usage.js +6 -2
  610. package/src/routes/user.js +27 -0
  611. package/src/routes/websocket.js +29 -8
  612. package/src/routes/websocket.test.mjs +65 -0
  613. package/src/routes/wellKnownFallback.js +30 -0
  614. package/src/routes/wellKnownFallback.test.mjs +32 -0
  615. package/src/websocket/devWebSocket.js +41 -26
  616. package/src/websocket/devWebSocket.test.mjs +157 -0
  617. package/vite.config.js +53 -23
  618. package/lib/server/auth/getDevSession.js +0 -70
  619. package/lib/server/auth/getDevSession.test.mjs +0 -138
  620. package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
  621. package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
  622. package/manager/watchers/moduleBuildWatcher.mjs +0 -79
  623. package/manager/watchers/serverArtifactWatcher.mjs +0 -120
  624. package/src/routes/apiPage.js +0 -37
@@ -0,0 +1,117 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import { Hono } from 'hono';
18
+ import { jest } from '@jest/globals';
19
+
20
+ const mockSubscribe = jest.fn();
21
+ const mockUnsubscribe = jest.fn();
22
+ jest.unstable_mockModule('../../../lib/docs/devEventBus.js', () => ({
23
+ bootedAt: '2026-05-06T07:08:09.000Z',
24
+ subscribe: mockSubscribe,
25
+ }));
26
+
27
+ const { default: docsEventsHandler } = await import('./events.js');
28
+
29
+ function createApp() {
30
+ const app = new Hono();
31
+ app.get('/lowdefy-docs/events', docsEventsHandler);
32
+ return app;
33
+ }
34
+
35
+ // Reads SSE frames off the response body one at a time.
36
+ function createFrameReader(response) {
37
+ const reader = response.body.getReader();
38
+ const decoder = new TextDecoder();
39
+ let buffer = '';
40
+ const nextFrame = async function nextFrame() {
41
+ while (!buffer.includes('\n\n')) {
42
+ const { value, done } = await reader.read();
43
+ if (done) throw new Error('Stream closed before a full frame arrived.');
44
+ buffer += decoder.decode(value, { stream: true });
45
+ }
46
+ const end = buffer.indexOf('\n\n');
47
+ const frame = buffer.slice(0, end);
48
+ buffer = buffer.slice(end + 2);
49
+ const lines = frame.split('\n');
50
+ return {
51
+ event: lines
52
+ .find((line) => line.startsWith('event:'))
53
+ ?.slice('event:'.length)
54
+ .trim(),
55
+ data: lines
56
+ .find((line) => line.startsWith('data:'))
57
+ ?.slice('data:'.length)
58
+ .trim(),
59
+ };
60
+ };
61
+ // Cancelling the body is what a dropped connection does to the stream.
62
+ nextFrame.close = () => reader.cancel();
63
+ return nextFrame;
64
+ }
65
+
66
+ beforeEach(() => {
67
+ mockSubscribe.mockReturnValue(mockUnsubscribe);
68
+ });
69
+
70
+ test('GET /lowdefy-docs/events opens an SSE stream whose first frame is the restart event', async () => {
71
+ const res = await createApp().request('/lowdefy-docs/events');
72
+
73
+ expect(res.status).toBe(200);
74
+ expect(res.headers.get('content-type')).toContain('text/event-stream');
75
+
76
+ const nextFrame = createFrameReader(res);
77
+ const frame = await nextFrame();
78
+ expect(frame.event).toBe('restart');
79
+ const data = JSON.parse(frame.data);
80
+ expect(data).toMatchObject({ type: 'restart', bootedAt: '2026-05-06T07:08:09.000Z' });
81
+ expect(new Date(data.timestamp).toISOString()).toEqual(data.timestamp);
82
+ await nextFrame.close();
83
+ });
84
+
85
+ test('a published event is written as an SSE frame named by its type', async () => {
86
+ const res = await createApp().request('/lowdefy-docs/events');
87
+ const nextFrame = createFrameReader(res);
88
+ await nextFrame();
89
+
90
+ expect(mockSubscribe).toHaveBeenCalledTimes(1);
91
+ const [send] = mockSubscribe.mock.calls[0];
92
+ const event = {
93
+ type: 'build',
94
+ timestamp: '2026-05-06T07:10:00.000Z',
95
+ status: 'error',
96
+ errorCount: 1,
97
+ stale: true,
98
+ };
99
+ await send(event);
100
+
101
+ const frame = await nextFrame();
102
+ expect(frame.event).toBe('build');
103
+ expect(JSON.parse(frame.data)).toEqual(event);
104
+ await nextFrame.close();
105
+ });
106
+
107
+ test('a dropped connection unsubscribes from the bus', async () => {
108
+ const res = await createApp().request('/lowdefy-docs/events');
109
+ const nextFrame = createFrameReader(res);
110
+ await nextFrame();
111
+ expect(mockSubscribe).toHaveBeenCalledTimes(1);
112
+ expect(mockUnsubscribe).not.toHaveBeenCalled();
113
+
114
+ await nextFrame.close();
115
+
116
+ expect(mockUnsubscribe).toHaveBeenCalledTimes(1);
117
+ });
@@ -14,8 +14,13 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
+ import { ConfigError } from '@lowdefy/errors';
18
+
17
19
  import findConfig from '../../../lib/docs/findConfig.js';
18
20
 
21
+ // findConfig throws a ConfigError only for a missing or non-string id; every
22
+ // other failure is a fault and propagates to the error handler rather than
23
+ // being reported to the caller as bad input.
19
24
  async function docsFindHandler(c) {
20
25
  const id = c.req.param('id');
21
26
  const pageId = c.req.query('pageId');
@@ -23,7 +28,10 @@ async function docsFindHandler(c) {
23
28
  const result = await findConfig({ id, pageId });
24
29
  return c.json(result);
25
30
  } catch (error) {
26
- return c.json({ error: error.message }, 400);
31
+ if (error instanceof ConfigError) {
32
+ return c.json({ error: error.message }, 400);
33
+ }
34
+ throw error;
27
35
  }
28
36
  }
29
37
 
@@ -0,0 +1,30 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import searchIcons from '../../../lib/docs/searchIcons.js';
18
+
19
+ async function docsIconsHandler(c) {
20
+ const query = c.req.query('q');
21
+ if (!query || query.trim() === '') {
22
+ return c.json(
23
+ { error: 'Missing search query. Use GET /lowdefy-docs/icons?q=your+keywords.' },
24
+ 400
25
+ );
26
+ }
27
+ return c.json(await searchIcons({ query }));
28
+ }
29
+
30
+ export default docsIconsHandler;
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  import inspectState from '../../../lib/docs/inspectState.js';
18
+ import parsePathParamsParam from './parsePathParamsParam.js';
18
19
  import parseUserParam from './parseUserParam.js';
19
20
 
20
21
  async function docsInspectStateHandler(c) {
@@ -30,7 +31,21 @@ async function docsInspectStateHandler(c) {
30
31
  return c.json({ error: userError }, 400);
31
32
  }
32
33
 
33
- const result = await inspectState({ origin, pageId, source, user });
34
+ const { pathParams, error: pathParamsError } = parsePathParamsParam({
35
+ value: c.req.query('pathParams'),
36
+ });
37
+ if (pathParamsError) {
38
+ return c.json({ error: pathParamsError }, 400);
39
+ }
40
+
41
+ const result = await inspectState({
42
+ origin,
43
+ pageId,
44
+ pathParams,
45
+ source,
46
+ user,
47
+ data: c.req.query('data'),
48
+ });
34
49
  if (result.error) {
35
50
  // A contradictory call (`user` with `source=tab`) is the caller's mistake,
36
51
  // not a failed render — 502 would read as "the renderer broke" and invite a
@@ -0,0 +1,194 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import { type } from '@lowdefy/helpers';
18
+ import { validateJourneySteps } from '@lowdefy/node-utils';
19
+
20
+ import getBuildId from '../../../lib/docs/getBuildId.js';
21
+ import lowdefyConfig from '../../../lib/build/config.js';
22
+ import { openMutantRun } from '../../../lib/server/mutants/mutantRuns.js';
23
+ import parseUserParam from './parseUserParam.js';
24
+ import runJourney from '../../../lib/docs/runJourney.js';
25
+ import validateJourneyTimeout from '../../../lib/docs/validateJourneyTimeout.js';
26
+ import validateMutantParam from '../../../lib/server/mutants/validateMutantParam.js';
27
+ import validateRecordingParam from '../../../lib/docs/validateRecordingParam.js';
28
+ import validateStateSelection from '../../../lib/docs/validateStateSelection.js';
29
+
30
+ // A failed journey is a 200 with passed: false — it is the result the caller
31
+ // asked for. Malformed input (pageId, pathParams, steps, user, data) is a 400 before any browser
32
+ // opens; only a render that could not run at all is a 502, so it is not
33
+ // mistaken for a journey that failed on an assertion.
34
+ async function docsJourneyHandler(c) {
35
+ const body = await c.req.json().catch(() => ({}));
36
+ const { pageId, pathParams, steps, urlQuery, state, timeout } = body;
37
+ if (type.isNone(pageId) || !type.isString(pageId)) {
38
+ return c.json(
39
+ {
40
+ error: `POST /lowdefy-docs/journey requires a "pageId" string in the JSON body, e.g. {"pageId": "home", "steps": [{"click": "submit"}]}. Received ${JSON.stringify(
41
+ pageId
42
+ )}.`,
43
+ },
44
+ 400
45
+ );
46
+ }
47
+ const { error: stepsError } = validateJourneySteps({ steps });
48
+ if (stepsError) {
49
+ return c.json({ error: stepsError }, 400);
50
+ }
51
+ if (
52
+ !type.isNone(pathParams) &&
53
+ (!type.isObject(pathParams) || !Object.values(pathParams).every(type.isString))
54
+ ) {
55
+ return c.json(
56
+ {
57
+ error: `The "pathParams" param must be an object of strings, one per path placeholder. Received ${JSON.stringify(
58
+ pathParams
59
+ )}.`,
60
+ },
61
+ 400
62
+ );
63
+ }
64
+ if (!type.isNone(urlQuery) && !type.isObject(urlQuery)) {
65
+ return c.json(
66
+ { error: `The "urlQuery" param must be an object. Received ${JSON.stringify(urlQuery)}.` },
67
+ 400
68
+ );
69
+ }
70
+ const stateSelectionError = validateStateSelection({ state });
71
+ if (stateSelectionError) {
72
+ return c.json({ error: stateSelectionError }, 400);
73
+ }
74
+ const timeoutError = validateJourneyTimeout({ timeout });
75
+ if (timeoutError) {
76
+ return c.json({ error: timeoutError }, 400);
77
+ }
78
+ if (!type.isNone(body.data) && !type.isString(body.data)) {
79
+ return c.json(
80
+ {
81
+ error: `The "data" param must be a data set name string. Received ${JSON.stringify(
82
+ body.data
83
+ )}.`,
84
+ },
85
+ 400
86
+ );
87
+ }
88
+ // One POST is one run. A journey with a list of users runs once per user:
89
+ // lowdefy test and lowdefy_run_journey expand the list, posting or running
90
+ // each user on its own.
91
+ if (type.isArray(body.user)) {
92
+ return c.json(
93
+ {
94
+ error: `POST /lowdefy-docs/journey runs one user. For a list of data set users, post once per user, or use lowdefy test or lowdefy_run_journey, which run the journey once as each. Received ${JSON.stringify(
95
+ body.user
96
+ )}.`,
97
+ },
98
+ 400
99
+ );
100
+ }
101
+ // A string is a journey's own: `none` injects no caller, so the app's auth
102
+ // decides who the journey is, and any other string names a user of the
103
+ // journey's data set (runJourney looks it up). An object is a headless caller.
104
+ const { user, error: userError } = type.isString(body.user)
105
+ ? { user: body.user }
106
+ : parseUserParam({ value: body.user });
107
+ if (userError) {
108
+ return c.json({ error: userError }, 400);
109
+ }
110
+ const recordingError = validateRecordingParam(body.recording);
111
+ if (recordingError) {
112
+ return c.json({ error: recordingError }, 400);
113
+ }
114
+ if (!type.isNone(body.mutant)) {
115
+ const mutantError = validateMutantParam(body.mutant);
116
+ if (mutantError) {
117
+ return c.json({ error: mutantError }, 400);
118
+ }
119
+ // A mutant's key names a node only within the build it was listed
120
+ // against; against any other build it would mutate the wrong node.
121
+ if (body.mutant.buildId !== getBuildId()) {
122
+ return c.json(
123
+ {
124
+ error:
125
+ 'The mutant was listed against another build. List the mutants again (POST /lowdefy-docs/mutants) and run the new one.',
126
+ stale: true,
127
+ },
128
+ 409
129
+ );
130
+ }
131
+ }
132
+ // Derived from the incoming request rather than a config value — this is
133
+ // the origin an agent can actually reach the dev server on (host/port it
134
+ // just connected to), regardless of how the server is bound.
135
+ const origin = new URL(c.req.url).origin;
136
+
137
+ const mutantRun = type.isNone(body.mutant)
138
+ ? null
139
+ : openMutantRun({
140
+ mutant: {
141
+ buildId: body.mutant.buildId,
142
+ artifact: body.mutant.artifact,
143
+ key: body.mutant.key,
144
+ ...(type.isNone(body.mutant.pointer)
145
+ ? {}
146
+ : { pointer: body.mutant.pointer, nodeHash: body.mutant.nodeHash ?? null }),
147
+ arg: body.mutant.arg ?? null,
148
+ operator: body.mutant.operator,
149
+ },
150
+ });
151
+ let result;
152
+ try {
153
+ result = await runJourney({
154
+ origin,
155
+ pageId,
156
+ pathParams,
157
+ steps,
158
+ user,
159
+ urlQuery,
160
+ state,
161
+ stepTimeout: timeout,
162
+ basePath: lowdefyConfig.basePath ?? '',
163
+ mutantCookie: mutantRun?.cookiePayload,
164
+ data: body.data,
165
+ by: 'test',
166
+ // Journeys posted here come from `lowdefy test` and lowdefy_run_tests.
167
+ recording: type.isNone(body.recording)
168
+ ? undefined
169
+ : {
170
+ source: 'journey',
171
+ run: { id: body.recording.run, by: 'test', journey: body.recording.journey ?? null },
172
+ },
173
+ });
174
+ } finally {
175
+ // runJourney has closed every actor by now, so no request still carries
176
+ // the run's cookie.
177
+ mutantRun?.close();
178
+ }
179
+ // A journey refused before any browser opened (its data set, or who it acts
180
+ // as on one) is the caller's to fix: a 400, like the checks above.
181
+ if (result.refused === true) {
182
+ return c.json({ error: result.error }, 400);
183
+ }
184
+ if (result.error) {
185
+ return c.json({ error: result.error }, 502);
186
+ }
187
+ if (mutantRun !== null) {
188
+ const { id, applied, misses } = mutantRun.run;
189
+ return c.json({ ...result, mutant: { id, applied, misses } });
190
+ }
191
+ return c.json(result);
192
+ }
193
+
194
+ export default docsJourneyHandler;