@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,134 @@
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 createEvaluateOperators from '@lowdefy/api/context/createEvaluateOperators.js';
18
+ import createWalledResolver from '@lowdefy/api/routes/request/createWalledResolver.js';
19
+ import { ConfigError } from '@lowdefy/errors';
20
+ import { operatorsServer } from '@lowdefy/operators-js';
21
+
22
+ import applyDataSetRedirect from './applyDataSetRedirect.js';
23
+
24
+ const connections = {
25
+ MongoDBCollection: { meta: { tenant: true, dataSet: 'redirect' }, requests: {} },
26
+ WalledRuntime: { meta: { tenant: false, dataSet: 'walled' }, requests: {} },
27
+ };
28
+
29
+ const artifacts = {
30
+ 'connections/runtime.json': {
31
+ id: 'connection:runtime',
32
+ connectionId: 'runtime',
33
+ type: 'WalledRuntime',
34
+ properties: { mongoConnectionIds: ['matches'], apiKey: { _secret: 'RUNTIME_KEY' } },
35
+ },
36
+ 'connections/runtime_operator.json': {
37
+ id: 'connection:runtime_operator',
38
+ connectionId: 'runtime_operator',
39
+ type: 'WalledRuntime',
40
+ properties: { _if: { test: true, then: { mongoConnectionIds: ['matches'] }, else: {} } },
41
+ },
42
+ 'connections/matches.json': {
43
+ id: 'connection:matches',
44
+ connectionId: 'matches',
45
+ '~k': 'k_matches',
46
+ type: 'MongoDBCollection',
47
+ properties: { databaseUri: { _secret: 'MONGODB_URI' }, collection: 'matches', write: true },
48
+ },
49
+ 'connections/matches_operator.json': {
50
+ id: 'connection:matches_operator',
51
+ connectionId: 'matches_operator',
52
+ '~k': 'k_matches_operator',
53
+ type: 'MongoDBCollection',
54
+ properties: {
55
+ _if: { test: true, then: { databaseUri: 'mongodb://real/', collection: 'matches' } },
56
+ },
57
+ },
58
+ };
59
+
60
+ const session = {
61
+ id: 'abc',
62
+ name: 'staging-sample',
63
+ state: 'open',
64
+ databaseUri: 'mongodb://127.0.0.1:5555/?replicaSet=testset',
65
+ prefix: 'ld_000000000001',
66
+ databaseName: 'ld_000000000001_0',
67
+ databases: new Map([[JSON.stringify(['secret:MONGODB_URI', null]), 'ld_000000000001_0']]),
68
+ databaseCount: 1,
69
+ };
70
+
71
+ function createContext({ sessionState = 'open' } = {}) {
72
+ const context = {
73
+ appMeta: {},
74
+ config: {},
75
+ connections,
76
+ logger: { debug: () => {}, error: () => {}, info: () => {}, warn: () => {} },
77
+ operators: { ...operatorsServer },
78
+ organization: null,
79
+ payload: {},
80
+ readConfigFile: async (filePath) => artifacts[filePath] ?? null,
81
+ secrets: { MONGODB_URI: 'mongodb://real-host/app', RUNTIME_KEY: 'key' },
82
+ user: null,
83
+ };
84
+ context.evaluateOperators = createEvaluateOperators(context);
85
+ applyDataSetRedirect({
86
+ context,
87
+ session: { ...session, state: sessionState },
88
+ connections,
89
+ });
90
+ return context;
91
+ }
92
+
93
+ const requestConfig = { '~k': 'r.0', requestId: 'accept_match', connectionId: 'runtime' };
94
+
95
+ test('applyDataSetRedirect passes a connection whose type declares walled through with its properties untouched', async () => {
96
+ const context = createContext();
97
+ expect(await context.readConfigFile('connections/runtime.json')).toEqual(
98
+ artifacts['connections/runtime.json']
99
+ );
100
+ expect(await context.readConfigFile('connections/runtime_operator.json')).toEqual(
101
+ artifacts['connections/runtime_operator.json']
102
+ );
103
+ });
104
+
105
+ test('applyDataSetRedirect throws on a walled connection read after the session has closed', async () => {
106
+ const context = createContext({ sessionState: 'closed' });
107
+ await expect(context.readConfigFile('connections/runtime.json')).rejects.toThrow(
108
+ 'Data session abc has ended.'
109
+ );
110
+ });
111
+
112
+ test('the walled resolver under a data session gives the named MongoDBCollection the session database', async () => {
113
+ const context = createContext();
114
+ const walled = createWalledResolver(context, { requestConfig });
115
+ const bound = await walled('matches');
116
+ expect(bound.connection).toEqual({
117
+ databaseUri: session.databaseUri,
118
+ databaseName: session.databaseName,
119
+ collection: 'matches',
120
+ write: true,
121
+ });
122
+ expect(bound.connectionId).toEqual('matches');
123
+ });
124
+
125
+ test('the walled resolver under a data session refuses a named MongoDBCollection whose properties are an operator', async () => {
126
+ const context = createContext();
127
+ const walled = createWalledResolver(context, { requestConfig });
128
+ const error = await walled('matches_operator').catch((caught) => caught);
129
+ expect(error).toBeInstanceOf(ConfigError);
130
+ expect(error.message).toEqual(
131
+ 'Connection "matches_operator" (type MongoDBCollection) cannot run under data set "staging-sample": its properties are an operator, so the redirect cannot be checked.'
132
+ );
133
+ expect(error.configKey).toEqual('k_matches_operator');
134
+ });
@@ -0,0 +1,73 @@
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 path from 'node:path';
18
+ import { createSystemContext as buildSystemContext } from '@lowdefy/api';
19
+ import { getSecretsFromEnv } from '@lowdefy/node-utils';
20
+ import { v4 as uuid } from 'uuid';
21
+
22
+ import agents from '../../../build/plugins/agents.js';
23
+ import appMeta from '../../build/appMeta.js';
24
+ import config from '../../build/config.js';
25
+ import connections from '../../../build/plugins/connections.js';
26
+ import createHandleError from '../log/createHandleError.js';
27
+ import createLogger from '../log/createLogger.js';
28
+ import fileCache from '../fileCache.js';
29
+ import i18nConfig from '../../build/i18n.js';
30
+ import loadDynamicJsMap from '../loadDynamicJsMap.js';
31
+ import notifications from '../../../build/plugins/notifications.js';
32
+ import operators from '../../../build/plugins/operators/server.js';
33
+ import scrubSecrets from '../scrubSecrets.js';
34
+ import steps from '../../../build/plugins/steps.js';
35
+ import websockets from '../../../build/plugins/websockets.js';
36
+
37
+ const secrets = getSecretsFromEnv();
38
+
39
+ // Builds a fresh system context per auth hook fire - the trusted internal
40
+ // caller the BetterAuth engine uses to invoke hook endpoints. All fields are
41
+ // startup singletons except the per-fire rid, logger, handleError, the
42
+ // dynamic jsMap re-read (JIT rebuilds rewrite serverJsMap.js), and auth -
43
+ // auth is threaded in by the caller (createHookDispatch) rather than
44
+ // imported directly, since it comes from the same BetterAuth construction
45
+ // that this factory is a dependency of (see createHookDispatch.js).
46
+ function createSystemContext({ auth } = {}) {
47
+ const rid = uuid();
48
+ const buildDirectory = path.join(process.cwd(), 'build');
49
+ return buildSystemContext({
50
+ rid,
51
+ agents,
52
+ appMeta,
53
+ auth,
54
+ buildDirectory,
55
+ config,
56
+ configDirectory: process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd(),
57
+ connections,
58
+ createHandleError,
59
+ fileCache,
60
+ i18n: i18nConfig,
61
+ jsMap: loadDynamicJsMap(buildDirectory),
62
+ logger: createLogger({ rid }),
63
+ mode: 'dev',
64
+ notifications,
65
+ operators,
66
+ scrubSecrets,
67
+ secrets,
68
+ steps,
69
+ websockets,
70
+ });
71
+ }
72
+
73
+ export default createSystemContext;
@@ -14,27 +14,33 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import { getAuthConfig as getApiAuthConfig } from '@lowdefy/api';
17
+ import { getBetterAuth } from '@lowdefy/api';
18
18
  import { getSecretsFromEnv } from '@lowdefy/node-utils';
19
19
 
20
20
  import adapters from '../../../build/plugins/auth/adapters.js';
21
21
  import appMeta from '../../build/appMeta.js';
22
22
  import authJson from '../../build/auth.js';
23
- import config from '../../build/config.js';
24
- import callbacks from '../../../build/plugins/auth/callbacks.js';
25
- import events from '../../../build/plugins/auth/events.js';
23
+ import createSystemContext from './createSystemContext.js';
24
+ import lowdefyConfig from '../../build/config.js';
26
25
  import providers from '../../../build/plugins/auth/providers.js';
27
26
 
28
- function getAuthConfig({ logger }) {
29
- return getApiAuthConfig({
27
+ // Returns the BetterAuth instance (memoized in @lowdefy/api), or null when
28
+ // auth is not configured. dev: true relaxes cookies for plain-http localhost
29
+ // and derives a per-app cookie prefix so parallel dev apps do not collide.
30
+ function getAuth({ logger }) {
31
+ if (authJson.configured !== true) {
32
+ return null;
33
+ }
34
+ return getBetterAuth({
30
35
  appMeta,
31
36
  authJson,
32
- config,
37
+ config: lowdefyConfig,
38
+ createSystemContext,
33
39
  dev: true,
34
40
  logger,
35
- plugins: { adapters, callbacks, events, providers },
41
+ plugins: { adapters, providers },
36
42
  secrets: getSecretsFromEnv(),
37
43
  });
38
44
  }
39
45
 
40
- export default getAuthConfig;
46
+ export default getAuth;
@@ -16,24 +16,25 @@
16
16
 
17
17
  import { HEADLESS_USER_COOKIE } from './headlessUser.js';
18
18
 
19
- // Decodes the headless renderer's user cookie (set by getBrowser.js openPage
20
- // on its own browser context, base64-encoded JSON) into the raw user object.
21
- // Returns just the user; getDevSession.js turns it into a session through
22
- // the same pipeline a real sign-in uses, so headless requests carry a
23
- // prod-shaped session while the developer's real browser (no cookie) is
24
- // unaffected.
19
+ // Mirrors the e2e user-injection pattern (server-e2e/lib/server/auth/getUser.js):
20
+ // the headless renderer sets a base64-JSON caller cookie on its own browser
21
+ // context, so its /api/* fetches carry a pre-resolved caller while the
22
+ // developer's real browser (no cookie) is unaffected. Returns { user, explicit }
23
+ // as getBrowser.js wrote it, or null on miss - the caller floors the user's
24
+ // shape via normalizeInjectedCaller. `explicit` is true when the tool call or
25
+ // journey named the user, so createLowdefyContext lets it beat a dev mock user.
25
26
  function getHeadlessUser(c) {
26
27
  const cookieHeader = c.req.header('cookie') ?? '';
27
28
  const match = cookieHeader.match(new RegExp(`${HEADLESS_USER_COOKIE}=([^;]+)`));
28
29
  if (!match) {
29
- return undefined;
30
+ return null;
30
31
  }
31
32
 
32
33
  try {
33
34
  const decoded = Buffer.from(decodeURIComponent(match[1]), 'base64').toString();
34
35
  return JSON.parse(decoded);
35
36
  } catch {
36
- return undefined;
37
+ return null;
37
38
  }
38
39
  }
39
40
 
@@ -0,0 +1,41 @@
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 getHeadlessUser from './getHeadlessUser.js';
18
+
19
+ function contextWithCookie(cookie) {
20
+ return { req: { header: (name) => (name === 'cookie' ? cookie : undefined) } };
21
+ }
22
+
23
+ function encode(value) {
24
+ return Buffer.from(JSON.stringify(value)).toString('base64');
25
+ }
26
+
27
+ test('getHeadlessUser reads the user and whether the caller named it', () => {
28
+ const caller = { user: { id: 'agent', roles: ['admin'] }, explicit: true };
29
+ expect(
30
+ getHeadlessUser(contextWithCookie(`other=1; lowdefy_headless_user=${encode(caller)}`))
31
+ ).toEqual(caller);
32
+ });
33
+
34
+ test('getHeadlessUser returns null with no headless cookie', () => {
35
+ expect(getHeadlessUser(contextWithCookie(undefined))).toBeNull();
36
+ expect(getHeadlessUser(contextWithCookie('other=1'))).toBeNull();
37
+ });
38
+
39
+ test('getHeadlessUser returns null for a cookie that is not base64 JSON', () => {
40
+ expect(getHeadlessUser(contextWithCookie('lowdefy_headless_user=%%%'))).toBeNull();
41
+ });
@@ -14,14 +14,19 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
+ import { ConfigError } from '@lowdefy/errors';
17
18
  import { serializer } from '@lowdefy/helpers';
18
19
 
19
20
  import authJson from '../../build/auth.js';
20
21
 
21
- // Resolves the raw mock user object — LOWDEFY_DEV_USER env var first (the
22
- // `lowdefy dev --mock-user` flag sets it), then auth.dev.mockUser from the
23
- // build config. Returns just the user object; getDevSession.js turns it into
24
- // a session through the same pipeline a real sign-in uses.
22
+ // dev.mockUser is a pre-resolved caller that substitutes for the whole
23
+ // resolveAuthentication step - no auth engine, no session lookup, no
24
+ // membership wall. Its roles are authoritative. LOWDEFY_DEV_USER takes
25
+ // priority over auth.dev.mockUser from lowdefy.yaml.
26
+ //
27
+ // A dev mock user needs no auth stack behind it: auth.dev is a dev-only
28
+ // concern, so an app whose only auth key is auth.dev runs signed out in
29
+ // production and has this caller in the dev server.
25
30
  function getMockUser() {
26
31
  const mockUserJson = process.env.LOWDEFY_DEV_USER;
27
32
  let mockUser;
@@ -30,25 +35,24 @@ function getMockUser() {
30
35
  try {
31
36
  mockUser = JSON.parse(mockUserJson);
32
37
  } catch (error) {
33
- throw new Error('Invalid JSON in LOWDEFY_DEV_USER environment variable.', { cause: error });
38
+ throw new ConfigError('Invalid JSON in LOWDEFY_DEV_USER environment variable.', {
39
+ cause: error,
40
+ });
34
41
  }
35
42
  } else {
36
43
  mockUser = authJson.dev?.mockUser;
37
44
  }
38
45
 
39
46
  if (!mockUser) {
40
- return undefined;
41
- }
42
-
43
- if (authJson.configured !== true) {
44
- throw new Error(
45
- 'Mock user configured but auth is not configured in lowdefy.yaml. ' +
46
- 'Add auth configuration to use mock user feature.'
47
- );
47
+ return null;
48
48
  }
49
49
 
50
50
  // Deserialize to restore arrays from ~arr markers and remove other build markers
51
- return serializer.deserialize(mockUser);
51
+ mockUser = serializer.deserialize(mockUser);
52
+
53
+ // The roles/attributes floor is applied at injection by
54
+ // normalizeInjectedCaller (createLowdefyContext.js) - return the raw user.
55
+ return mockUser;
52
56
  }
53
57
 
54
58
  export default getMockUser;
@@ -14,26 +14,27 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import { getAuthUser } from '@hono/auth-js';
17
+ import { getAuthStrategies } from '@lowdefy/api';
18
+ import { getSecretsFromEnv } from '@lowdefy/node-utils';
18
19
 
20
+ import appMeta from '../../build/appMeta.js';
19
21
  import authJson from '../../build/auth.js';
20
- import getDevSession from './getDevSession.js';
22
+ import strategyTypes from '../../../build/plugins/auth/strategies.js';
21
23
 
22
- // Replaces getServerSession.js — dev sessions (mock user, headless renderer)
23
- // first, then the session from the Hono context populated by initAuthConfig.
24
- // getDevSession is the same function the client's GET /api/auth/session is
25
- // answered from (routes/auth.js), so server and client sessions match by
26
- // construction.
27
- async function getSession(c) {
28
- const devSession = await getDevSession(c);
29
- if (devSession) {
30
- return devSession;
31
- }
24
+ // Returns the API auth strategy verifiers (memoized in @lowdefy/api), or an
25
+ // empty list when auth is not configured - resolveAuthentication tries them
26
+ // in config order when no session resolves.
27
+ function getStrategies({ logger }) {
32
28
  if (authJson.configured !== true) {
33
- return undefined;
29
+ return [];
34
30
  }
35
- const authUser = await getAuthUser(c);
36
- return authUser?.session ?? undefined;
31
+ return getAuthStrategies({
32
+ appMeta,
33
+ authJson,
34
+ logger,
35
+ plugins: { strategies: strategyTypes },
36
+ secrets: getSecretsFromEnv(),
37
+ });
37
38
  }
38
39
 
39
- export default getSession;
40
+ export default getStrategies;
@@ -15,12 +15,13 @@
15
15
  */
16
16
 
17
17
  // Shared between the headless renderer (getBrowser.js, which sets the cookie on
18
- // its browser context) and the dev session resolution (getHeadlessUser.js, which
18
+ // its browser context) and the dev caller resolver (getHeadlessUser.js, which
19
19
  // decodes it) so the cookie name and injected user shape live in one place.
20
20
  const HEADLESS_USER_COOKIE = 'lowdefy_headless_user';
21
21
 
22
+ // BetterAuth's session user carries `id`, never `sub`. attributes is floored to
23
+ // {} by normalizeInjectedCaller at injection, so it is not spelled out here.
22
24
  const headlessUser = {
23
- sub: 'lowdefy-headless',
24
25
  id: 'lowdefy-headless',
25
26
  name: 'Lowdefy Headless',
26
27
  roles: [],
@@ -0,0 +1,35 @@
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 crypto from 'node:crypto';
18
+
19
+ // Signs every journey cookie (journeyCookies.js): the headless renderer
20
+ // (getBrowser.js) writes them on a journey actor's browser context, and the dev
21
+ // server reads them back (getClientAddress.js for the actor address).
22
+ //
23
+ // Auth rate limits count attempts per client address, and every actor of every
24
+ // journey reaches the dev server from the same machine, so each actor is given
25
+ // its own address. The cookie carries it with a token minted once per dev
26
+ // server process, so only the dev server's own headless browser can pick an
27
+ // address: a cookie from anywhere else is ignored. The production server never
28
+ // reads it. The token is kept on globalThis because the renderer and the
29
+ // resolver may load as separate module instances in one process (Vite's SSR
30
+ // module graph and Node's).
31
+ const TOKEN_KEY = Symbol.for('lowdefy.devServer.journeyActorToken');
32
+ globalThis[TOKEN_KEY] ??= crypto.randomBytes(32).toString('hex');
33
+ const journeyActorToken = globalThis[TOKEN_KEY];
34
+
35
+ export { journeyActorToken };
@@ -19,7 +19,6 @@ import { headlessUser } from './headlessUser.js';
19
19
 
20
20
  test('resolveHeadlessUser returns the default roleless user when no user is given', () => {
21
21
  expect(resolveHeadlessUser({})).toEqual({
22
- sub: 'lowdefy-headless',
23
22
  id: 'lowdefy-headless',
24
23
  name: 'Lowdefy Headless',
25
24
  roles: [],
@@ -32,7 +31,6 @@ test('resolveHeadlessUser returns the default roleless user when user is null',
32
31
 
33
32
  test('resolveHeadlessUser merges roles over the default, keeping the default id and name', () => {
34
33
  expect(resolveHeadlessUser({ user: { roles: ['user-admin'] } })).toEqual({
35
- sub: 'lowdefy-headless',
36
34
  id: 'lowdefy-headless',
37
35
  name: 'Lowdefy Headless',
38
36
  roles: ['user-admin'],
@@ -45,7 +43,6 @@ test('resolveHeadlessUser keeps caller fields the app reads, like email and prof
45
43
  user: { id: 'agent', email: 'agent@example.com', profile: { name: 'Agent' } },
46
44
  })
47
45
  ).toEqual({
48
- sub: 'lowdefy-headless',
49
46
  id: 'agent',
50
47
  name: 'Lowdefy Headless',
51
48
  email: 'agent@example.com',
@@ -58,7 +55,6 @@ test('resolveHeadlessUser does not mutate the default user between calls', () =>
58
55
  resolveHeadlessUser({ user: { id: 'first', roles: ['admin'] } });
59
56
 
60
57
  expect(resolveHeadlessUser({})).toEqual({
61
- sub: 'lowdefy-headless',
62
58
  id: 'lowdefy-headless',
63
59
  name: 'Lowdefy Headless',
64
60
  roles: [],
@@ -0,0 +1,44 @@
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 hashConfigContent from './hashConfigContent.js';
18
+
19
+ async function readHash({ filePath, readConfigFile }) {
20
+ try {
21
+ return hashConfigContent(await readConfigFile(filePath));
22
+ } catch {
23
+ // A file that cannot be read now (EACCES, or EBUSY on Windows during a
24
+ // save) is treated as changed; the rebuild reads it again and reports it.
25
+ return null;
26
+ }
27
+ }
28
+
29
+ // Whether the inputs of a page's last build are unchanged: 'current' when every
30
+ // file it read still holds the content it read, else 'changed'. A build that
31
+ // ran app code is always 'changed': app code can read anything, so its record
32
+ // cannot be complete. Files are read through the build context's read cache,
33
+ // so pages that share a file read it once per change event.
34
+ async function checkPageRecord({ record, readConfigFile }) {
35
+ if (record.ranAppCode) return 'changed';
36
+ const recorded = [...record.files];
37
+ const hashes = await Promise.all(
38
+ recorded.map(([filePath]) => readHash({ filePath, readConfigFile }))
39
+ );
40
+ const unchanged = recorded.every(([, hash], index) => hashes[index] === hash);
41
+ return unchanged ? 'current' : 'changed';
42
+ }
43
+
44
+ export default checkPageRecord;
@@ -0,0 +1,24 @@
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
+ // Key and ref map entries the dev server's kept JIT build context may add
18
+ // before it is recreated. Every page build adds entries to both maps and they
19
+ // are released only with the context, so this bounds one dev server's memory.
20
+ // Measured on the docs app: about 530 entries and 400-750 KB of retained heap
21
+ // per page build, so this is about 90 page builds and 35-65 MB.
22
+ const contextMapBudget = 48000;
23
+
24
+ export default contextMapBudget;