@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,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 { type } from '@lowdefy/helpers';
18
+
19
+ import dataSessionRegistry from './dataSessionRegistry.js';
20
+ import { JOURNEY_COOKIES, readJourneyCookie } from '../../server/journeyCookies.js';
21
+
22
+ // The data session a request's lowdefy_journey_data cookie names:
23
+ // - null when there is no cookie or its token is not this process's: not a journey's request, so it
24
+ // reads the app's own database like any other;
25
+ // - the session while it is open or closing;
26
+ // - { ended: id } when the token verifies but the session is not open (closed, or never opened). A
27
+ // verified token proves the request came from a journey, so the caller refuses it rather than let
28
+ // it fall back to the real database.
29
+ function readDataSession(cookieHeader) {
30
+ const id = readJourneyCookie({ cookieHeader, name: JOURNEY_COOKIES.data.name });
31
+ if (type.isNone(id)) {
32
+ return null;
33
+ }
34
+ const session = dataSessionRegistry.get(id);
35
+ if (type.isNone(session) || (session.state !== 'open' && session.state !== 'closing')) {
36
+ return { ended: id };
37
+ }
38
+ return session;
39
+ }
40
+
41
+ export default readDataSession;
@@ -0,0 +1,57 @@
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 dataSessionRegistry from './dataSessionRegistry.js';
18
+ import readDataSession from './readDataSession.js';
19
+ import { journeyActorToken } from '../../server/auth/journeyActor.js';
20
+
21
+ afterEach(() => {
22
+ dataSessionRegistry.clear();
23
+ });
24
+
25
+ function register(state) {
26
+ const session = { id: 'abc', state, work: new Set() };
27
+ dataSessionRegistry.set('abc', session);
28
+ return session;
29
+ }
30
+
31
+ test('readDataSession returns null without a data cookie', () => {
32
+ register('open');
33
+ expect(readDataSession(undefined)).toBeNull();
34
+ expect(readDataSession('other=1')).toBeNull();
35
+ });
36
+
37
+ test('readDataSession returns null for a cookie with the wrong token', () => {
38
+ register('open');
39
+ expect(readDataSession('lowdefy_journey_data=forged.abc')).toBeNull();
40
+ });
41
+
42
+ test('readDataSession returns an open or closing session for a verified cookie', () => {
43
+ const session = register('open');
44
+ expect(readDataSession(`a=1; lowdefy_journey_data=${journeyActorToken}.abc`)).toBe(session);
45
+ session.state = 'closing';
46
+ expect(readDataSession(`lowdefy_journey_data=${journeyActorToken}.abc`)).toBe(session);
47
+ });
48
+
49
+ test('readDataSession returns { ended } for a verified cookie naming an unknown or still loading session', () => {
50
+ expect(readDataSession(`lowdefy_journey_data=${journeyActorToken}.gone`)).toEqual({
51
+ ended: 'gone',
52
+ });
53
+ register('loading');
54
+ expect(readDataSession(`lowdefy_journey_data=${journeyActorToken}.abc`)).toEqual({
55
+ ended: 'abc',
56
+ });
57
+ });
@@ -0,0 +1,83 @@
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 { parseDataSet } from '@lowdefy/node-utils';
19
+
20
+ import checkSharedCollectionIds from './checkSharedCollectionIds.js';
21
+ import describeTargetKey from './describeTargetKey.js';
22
+ import readConnectionArtifacts from './readConnectionArtifacts.js';
23
+ import resolveDataSetCollection from './resolveDataSetCollection.js';
24
+
25
+ function getKeyedConnectionIds({ dataSet }) {
26
+ return [
27
+ ...new Set([
28
+ ...Object.keys(dataSet.fixtures),
29
+ ...Object.keys(dataSet.generated),
30
+ ...Object.keys(dataSet.indexes),
31
+ ]),
32
+ ];
33
+ }
34
+
35
+ // Sorts a URI's default database (no databaseName) before its named ones.
36
+ function sortKey(key) {
37
+ const [uri, databaseName] = JSON.parse(key);
38
+ return [uri, databaseName ?? ''].join('\u0000');
39
+ }
40
+
41
+ // Every database target the built connections name, sorted, so each run numbers them alike and the
42
+ // first one (the database a computed target reads) is the same on every run.
43
+ function listDatabaseTargets({ artifacts }) {
44
+ const keys = new Set();
45
+ Object.values(artifacts).forEach((artifact) => {
46
+ const key = describeTargetKey({ properties: artifact.properties });
47
+ if (!type.isNone(key)) keys.add(key);
48
+ });
49
+ return [...keys].sort((a, b) => sortKey(a).localeCompare(sortKey(b)));
50
+ }
51
+
52
+ // The data set checks only the dev build can make, on top of parseDataSet's: every connection the
53
+ // data set names is a MongoDBCollection with a literal collection, and a generated _id that another
54
+ // connection on the same collection in the same database target also holds is refused. Adds the
55
+ // database target of each connection it names (targets) and of every connection in the build
56
+ // (databaseTargets): a data session gives each target a database of its own. Runs before any
57
+ // browser opens.
58
+ async function readDataSet({ configDirectory, buildDirectory, name }) {
59
+ const dataSet = await parseDataSet({ configDirectory, name });
60
+ const artifacts = await readConnectionArtifacts({ buildDirectory });
61
+ const keyedIds = getKeyedConnectionIds({ dataSet });
62
+ const databaseTargets = listDatabaseTargets({ artifacts });
63
+ const collections = {};
64
+ const targets = {};
65
+ keyedIds.forEach((connectionId) => {
66
+ const artifact = artifacts[connectionId];
67
+ collections[connectionId] = resolveDataSetCollection({
68
+ dataSetName: name,
69
+ connectionId,
70
+ artifact,
71
+ }).collection;
72
+ // A target computed per request reads the session's first database, the first target's, so it
73
+ // groups and checks _ids with that target's connections.
74
+ targets[connectionId] =
75
+ describeTargetKey({ properties: artifact.properties }) ?? databaseTargets[0] ?? null;
76
+ });
77
+
78
+ checkSharedCollectionIds({ dataSetName: name, dataSet: { ...dataSet, collections, targets } });
79
+
80
+ return { ...dataSet, collections, targets, databaseTargets };
81
+ }
82
+
83
+ export default readDataSet;
@@ -0,0 +1,251 @@
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 fs from 'node:fs';
18
+ import os from 'node:os';
19
+ import path from 'node:path';
20
+
21
+ import readDataSet from './readDataSet.js';
22
+
23
+ let configDirectory;
24
+ let buildDirectory;
25
+
26
+ beforeEach(() => {
27
+ configDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-read-data-set-'));
28
+ buildDirectory = path.join(configDirectory, '.lowdefy', 'dev', 'build');
29
+ fs.mkdirSync(path.join(configDirectory, 'tests', 'data'), { recursive: true });
30
+ fs.mkdirSync(path.join(buildDirectory, 'connections'), { recursive: true });
31
+ });
32
+
33
+ afterEach(() => {
34
+ fs.rmSync(configDirectory, { recursive: true, force: true });
35
+ });
36
+
37
+ function writeDataSet(name, content) {
38
+ fs.writeFileSync(path.join(configDirectory, 'tests', 'data', `${name}.yaml`), content);
39
+ }
40
+
41
+ function writeConnection(connectionId, artifact) {
42
+ const filePath = path.join(buildDirectory, 'connections', `${connectionId}.json`);
43
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
44
+ fs.writeFileSync(
45
+ filePath,
46
+ JSON.stringify({ connectionId, '~k': `k_${connectionId}`, ...artifact })
47
+ );
48
+ }
49
+
50
+ function mongo(properties) {
51
+ return {
52
+ type: 'MongoDBCollection',
53
+ properties: { databaseUri: { _secret: 'MONGODB_URI', '~k': 'k' }, ...properties },
54
+ };
55
+ }
56
+
57
+ test('readDataSet maps each keyed connection to its collection', async () => {
58
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
59
+ writeConnection('tickets-archive', mongo({ collection: 'tickets' }));
60
+ writeConnection('organizations', mongo({ collection: 'orgs', databaseName: 'app' }));
61
+ writeConnection('api', { type: 'AxiosHttp', properties: { baseURL: 'https://example.com' } });
62
+ writeDataSet(
63
+ 'fixtures-only',
64
+ `fixtures:
65
+ tickets: [{ _id: t1 }]
66
+ tickets-archive: [{ _id: t2 }]
67
+ indexes:
68
+ organizations: [{ key: { name: 1 } }]
69
+ users:
70
+ owner: { id: u_1 }
71
+ `
72
+ );
73
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'fixtures-only' });
74
+ expect(dataSet.collections).toEqual({
75
+ tickets: 'tickets',
76
+ 'tickets-archive': 'tickets',
77
+ organizations: 'orgs',
78
+ });
79
+ expect(dataSet.warnings).toEqual([]);
80
+ expect(dataSet.users).toEqual({ owner: { id: 'u_1' } });
81
+ });
82
+
83
+ test('readDataSet reads module connections, which the build writes under their module folder', async () => {
84
+ writeConnection('contacts/contacts', mongo({ collection: 'contacts' }));
85
+ writeConnection('crm-contacts', mongo({ collection: 'contacts', databaseName: 'crm' }));
86
+ writeDataSet('alpha', 'fixtures:\n contacts/contacts: [{ _id: c1 }]\n');
87
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'alpha' });
88
+ expect(dataSet.databaseTargets).toEqual([
89
+ JSON.stringify(['secret:MONGODB_URI', null]),
90
+ JSON.stringify(['secret:MONGODB_URI', 'crm']),
91
+ ]);
92
+ });
93
+
94
+ test('readDataSet maps a module connection to its collection', async () => {
95
+ writeConnection('contacts/contacts', mongo({ collection: 'contacts' }));
96
+ writeDataSet('alpha', 'fixtures:\n contacts/contacts: [{ _id: c1 }]\n');
97
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'alpha' });
98
+ expect(dataSet.collections).toEqual({ 'contacts/contacts': 'contacts' });
99
+ });
100
+
101
+ test('readDataSet refuses a fixture keyed by a non-MongoDB connection', async () => {
102
+ writeConnection('api', { type: 'AxiosHttp', properties: { baseURL: 'https://example.com' } });
103
+ writeDataSet('alpha', 'fixtures:\n api: [{ _id: a }]\n');
104
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
105
+ 'Data set "alpha" connection "api" is a AxiosHttp connection; data sets load MongoDBCollection connections only.'
106
+ );
107
+ });
108
+
109
+ test('readDataSet refuses a key that is not a connection', async () => {
110
+ writeDataSet('alpha', 'fixtures:\n missing: [{ _id: a }]\n');
111
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
112
+ 'Data set "alpha" connection "missing" is not a connection in this app.'
113
+ );
114
+ });
115
+
116
+ test('readDataSet refuses an index keyed by a connection whose collection is an operator', async () => {
117
+ writeConnection('tickets', mongo({ collection: { _user: 'organizationId' } }));
118
+ writeDataSet('alpha', 'indexes:\n tickets: [{ key: { a: 1 } }]\n');
119
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
120
+ 'Data set "alpha" connection "tickets" has a computed "collection"'
121
+ );
122
+ });
123
+
124
+ test('readDataSet refuses an indexed connection whose databaseName is an operator', async () => {
125
+ writeConnection('tickets', mongo({ collection: 'tickets', databaseName: { _env: 'DB' } }));
126
+ writeDataSet('alpha', 'indexes:\n tickets:\n - { key: { number: 1 } }\n');
127
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
128
+ 'Data set "alpha" connection "tickets" has a computed "databaseName"'
129
+ );
130
+ });
131
+
132
+ test('readDataSet maps each keyed connection to its database target', async () => {
133
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
134
+ writeConnection('legacy-tickets', mongo({ collection: 'tickets', databaseName: 'legacy' }));
135
+ writeConnection('reporting', {
136
+ type: 'MongoDBCollection',
137
+ properties: { databaseUri: { _secret: 'REPORTING_URI' }, collection: 'tickets' },
138
+ });
139
+ writeConnection('computed', {
140
+ type: 'MongoDBCollection',
141
+ properties: { databaseUri: { _env: 'URI' }, collection: 'tickets' },
142
+ });
143
+ writeConnection('api', { type: 'AxiosHttp', properties: { baseURL: 'https://example.com' } });
144
+ writeDataSet(
145
+ 'alpha',
146
+ 'fixtures:\n tickets: [{ _id: a }]\n legacy-tickets: [{ _id: a }]\n reporting: [{ _id: a }]\n computed: [{ _id: b }]\n'
147
+ );
148
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'alpha' });
149
+ expect(dataSet.targets).toEqual({
150
+ tickets: JSON.stringify(['secret:MONGODB_URI', null]),
151
+ 'legacy-tickets': JSON.stringify(['secret:MONGODB_URI', 'legacy']),
152
+ reporting: JSON.stringify(['secret:REPORTING_URI', null]),
153
+ // Computed per request: the first target's, the database it reads.
154
+ computed: JSON.stringify(['secret:MONGODB_URI', null]),
155
+ });
156
+ // Every target in the build, sorted, whether or not the data set names it.
157
+ expect(dataSet.databaseTargets).toEqual([
158
+ JSON.stringify(['secret:MONGODB_URI', null]),
159
+ JSON.stringify(['secret:MONGODB_URI', 'legacy']),
160
+ JSON.stringify(['secret:REPORTING_URI', null]),
161
+ ]);
162
+ expect(dataSet.warnings).toEqual([]);
163
+ });
164
+
165
+ test('readDataSet accepts one _id generated on one collection in two database targets', async () => {
166
+ writeConnection('users', mongo({ collection: 'users' }));
167
+ writeConnection('auth-users', {
168
+ type: 'MongoDBCollection',
169
+ properties: { databaseUri: { _secret: 'AUTH_URI' }, collection: 'users' },
170
+ });
171
+ writeDataSet(
172
+ 'alpha',
173
+ 'fixtures:\n auth-users: [{ _id: users-1 }]\ngenerate:\n seed: 1\n users:\n count: 1\n'
174
+ );
175
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'alpha' });
176
+ expect(dataSet.collections).toEqual({ users: 'users', 'auth-users': 'users' });
177
+ });
178
+
179
+ test('readDataSet refuses a generated _id a computed-target connection also holds on the first target', async () => {
180
+ writeConnection('users', mongo({ collection: 'users' }));
181
+ writeConnection('computed-users', {
182
+ type: 'MongoDBCollection',
183
+ properties: { databaseUri: { _env: 'URI' }, collection: 'users' },
184
+ });
185
+ writeDataSet(
186
+ 'alpha',
187
+ 'fixtures:\n computed-users: [{ _id: users-1 }]\ngenerate:\n seed: 1\n users:\n count: 1\n'
188
+ );
189
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
190
+ 'connections "users" and "computed-users" both load collection "users".'
191
+ );
192
+ });
193
+
194
+ test('readDataSet resolves generated connections and refuses one the app does not have', async () => {
195
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
196
+ writeDataSet(
197
+ 'alpha',
198
+ 'generate:\n seed: 1\n tickets:\n count: 2\n invoices:\n count: 1\n'
199
+ );
200
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
201
+ 'Data set "alpha" connection "invoices" is not a connection in this app.'
202
+ );
203
+ writeDataSet('beta', 'generate:\n seed: 1\n tickets:\n count: 2\n');
204
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'beta' });
205
+ expect(dataSet.collections).toEqual({ tickets: 'tickets' });
206
+ expect(dataSet.generated.tickets.map(({ _id }) => _id)).toEqual(['tickets-1', 'tickets-2']);
207
+ });
208
+
209
+ test('readDataSet passes the size advice of a large data set on as a warning', async () => {
210
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
211
+ writeDataSet('big', 'generate:\n seed: 1\n tickets:\n count: 1200\n');
212
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'big' });
213
+ expect(dataSet.warnings).toEqual([
214
+ 'Data set "big" loads 1,200 documents for connection "tickets". More than 1,000 per collection is not advised: every journey on it loads slower, and journeys target fixture values, not volume.',
215
+ ]);
216
+ });
217
+
218
+ test('readDataSet refuses a fixture on another connection of the same collection sharing a generated _id', async () => {
219
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
220
+ writeConnection('tickets-archive', mongo({ collection: 'tickets' }));
221
+ writeDataSet(
222
+ 'alpha',
223
+ 'fixtures:\n tickets-archive: [{ _id: tickets-2 }]\ngenerate:\n seed: 1\n tickets:\n count: 2\n'
224
+ );
225
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
226
+ 'Data set "alpha" generate.tickets[1] _id "tickets-2" is also the _id of fixture tickets-archive[0]; connections "tickets" and "tickets-archive" both load collection "tickets".'
227
+ );
228
+ });
229
+
230
+ test('readDataSet refuses two connections of the same collection generating one _id', async () => {
231
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
232
+ writeConnection('tickets-archive', mongo({ collection: 'tickets' }));
233
+ writeDataSet(
234
+ 'alpha',
235
+ 'generate:\n seed: 1\n tickets:\n count: 1\n fields:\n _id: { sequence: { prefix: t-, start: 1 } }\n tickets-archive:\n count: 1\n fields:\n _id: { sequence: { prefix: t-, start: 1 } }\n'
236
+ );
237
+ await expect(readDataSet({ configDirectory, buildDirectory, name: 'alpha' })).rejects.toThrow(
238
+ 'Data set "alpha" generate.tickets-archive[0] _id "t-1" is also the _id of generate.tickets[0]; connections "tickets-archive" and "tickets" both load collection "tickets".'
239
+ );
240
+ });
241
+
242
+ test('readDataSet accepts the same _id on connections of different collections', async () => {
243
+ writeConnection('tickets', mongo({ collection: 'tickets' }));
244
+ writeConnection('invoices', mongo({ collection: 'invoices' }));
245
+ writeDataSet(
246
+ 'alpha',
247
+ 'fixtures:\n invoices: [{ _id: tickets-1 }]\ngenerate:\n seed: 1\n tickets:\n count: 1\n'
248
+ );
249
+ const dataSet = await readDataSet({ configDirectory, buildDirectory, name: 'alpha' });
250
+ expect(dataSet.generated.tickets.map(({ _id }) => _id)).toEqual(['tickets-1']);
251
+ });
@@ -0,0 +1,47 @@
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 removeDataStoreFiles from './removeDataStoreFiles.js';
18
+
19
+ const SHUTDOWN_SIGNALS = ['SIGTERM', 'SIGINT', 'SIGHUP'];
20
+
21
+ // A store is stopped, with its temporary database directory removed, when the dev server process
22
+ // shuts down. The manager stops the process with SIGTERM, a terminal Ctrl+C sends SIGINT and closing
23
+ // the terminal sends SIGHUP, whose default action ends the process without an exit event; on each
24
+ // the store stops first and the signal is raised again, so the process ends as it would have.
25
+ // Vite's own SIGTERM handler can exit before that stop finishes, so the exit hook kills mongod and
26
+ // removes its directory synchronously. mongodb-memory-server's killer process still stops mongod
27
+ // after a crash, which runs neither.
28
+ function registerDataStoreShutdown({ replSet, stop }) {
29
+ async function onSignal(signal) {
30
+ try {
31
+ await stop();
32
+ } finally {
33
+ process.kill(process.pid, signal);
34
+ }
35
+ }
36
+ function onExit() {
37
+ removeDataStoreFiles({ replSet });
38
+ }
39
+ SHUTDOWN_SIGNALS.forEach((signal) => process.once(signal, onSignal));
40
+ process.once('exit', onExit);
41
+ return function unregisterDataStoreShutdown() {
42
+ SHUTDOWN_SIGNALS.forEach((signal) => process.off(signal, onSignal));
43
+ process.off('exit', onExit);
44
+ };
45
+ }
46
+
47
+ export default registerDataStoreShutdown;
@@ -0,0 +1,32 @@
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 fs from 'node:fs';
18
+
19
+ // Kills each mongod of the store and removes its temporary database directory, synchronously, so
20
+ // it also runs from a process exit hook. A store already stopped with cleanup has no servers left.
21
+ function removeDataStoreFiles({ replSet }) {
22
+ replSet.servers.forEach((server) => {
23
+ const info = server.instanceInfo;
24
+ if (info === undefined) return;
25
+ info.instance.mongodProcess?.kill('SIGKILL');
26
+ if (info.tmpDir !== undefined) {
27
+ fs.rmSync(info.tmpDir, { recursive: true, force: true });
28
+ }
29
+ });
30
+ }
31
+
32
+ export default removeDataStoreFiles;
@@ -0,0 +1,46 @@
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
+
19
+ // A data set loads a connection only when the built artifact names its
20
+ // collection: an operator there is evaluated per request, so the collection cannot be known before
21
+ // one. Returns the literal collection and databaseName (or undefined).
22
+ function resolveDataSetCollection({ dataSetName, connectionId, artifact }) {
23
+ const where = `Data set "${dataSetName}" connection "${connectionId}"`;
24
+ if (type.isNone(artifact)) {
25
+ throw new Error(`${where} is not a connection in this app.`);
26
+ }
27
+ if (artifact.type !== 'MongoDBCollection') {
28
+ throw new Error(
29
+ `${where} is a ${artifact.type} connection; data sets load MongoDBCollection connections only.`
30
+ );
31
+ }
32
+ const { collection, databaseName } = artifact.properties ?? {};
33
+ if (!type.isString(collection)) {
34
+ throw new Error(
35
+ `${where} has a computed "collection"; a data set can only load a connection whose collection is a literal string.`
36
+ );
37
+ }
38
+ if (!type.isUndefined(databaseName) && !type.isString(databaseName)) {
39
+ throw new Error(
40
+ `${where} has a computed "databaseName"; a data set can only load a connection whose databaseName is a literal string or not set.`
41
+ );
42
+ }
43
+ return { collection, databaseName };
44
+ }
45
+
46
+ export default resolveDataSetCollection;
@@ -0,0 +1,106 @@
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
+
19
+ import readDataSet from './readDataSet.js';
20
+
21
+ function isUserName(user) {
22
+ return type.isString(user) && user !== 'none';
23
+ }
24
+
25
+ function describeDeclaredUsers({ users }) {
26
+ const names = Object.keys(users);
27
+ if (names.length === 0) {
28
+ return 'It declares no users.';
29
+ }
30
+ return `Declared: ${names.join(', ')}.`;
31
+ }
32
+
33
+ // Everything a journey's data set decides before a browser opens: the data set itself (read and
34
+ // checked against the built connections), and who the journey acts as. A string `user` other than
35
+ // "none" names a data set user. Returns { dataSet, user } (both undefined for a journey with no data
36
+ // set) or { error }.
37
+ //
38
+ // `user: none` while a dev mock user is active is refused: no caller cookie is injected, so the mock
39
+ // user would stand in for the journey instead of it running signed out.
40
+ //
41
+ // Two refusals keep a data-set journey off the app's real auth database:
42
+ // - `user: none` while auth is configured: a signed-out actor signs in through the auth engine,
43
+ // which is bound to the real auth database while its requests read the data set;
44
+ // - any data-set journey while a dev mock user is active: the mock user wins over the injected
45
+ // caller, so the journey would silently act as someone outside the data set.
46
+ //
47
+ // `subject` names the run in the refusals: "journey" for a journey, "call" for the other dev tools
48
+ // that act as someone (resolveToolCaller), which take the same user and data.
49
+ async function resolveJourneyDataSet({
50
+ data,
51
+ user,
52
+ subject = 'journey',
53
+ configDirectory,
54
+ buildDirectory,
55
+ authConfigured,
56
+ mockUserActive,
57
+ }) {
58
+ if (type.isNone(data)) {
59
+ if (user === 'none' && mockUserActive) {
60
+ return {
61
+ error: `The ${subject} has user "none", which cannot run while a dev mock user is active (auth.dev.mockUser or LOWDEFY_DEV_USER): with no caller of its own, every request would act as the mock user, not signed out. Remove the mock user to run signed out, or give the ${subject} a user.`,
62
+ };
63
+ }
64
+ if (isUserName(user)) {
65
+ return {
66
+ error: `The ${subject}'s user ${JSON.stringify(
67
+ user
68
+ )} names a data set user, but the ${subject} has no "data". Add data: <data set name>, or give user as an object.`,
69
+ };
70
+ }
71
+ return { user };
72
+ }
73
+ if (mockUserActive) {
74
+ return {
75
+ error: `The ${subject} on data set ${JSON.stringify(
76
+ data
77
+ )} cannot run while a dev mock user is active (auth.dev.mockUser or LOWDEFY_DEV_USER): every request would act as the mock user, who is not in the data set. Remove the mock user to run on data sets.`,
78
+ };
79
+ }
80
+ if (user === 'none' && authConfigured) {
81
+ return {
82
+ error: `The ${subject} on data set ${JSON.stringify(
83
+ data
84
+ )} has user "none", which is refused while auth is configured: signing in through the app would write to the app's real auth database. Name a data set user instead; runs that sign in stay off data sets.`,
85
+ };
86
+ }
87
+ let dataSet;
88
+ try {
89
+ dataSet = await readDataSet({ configDirectory, buildDirectory, name: data });
90
+ } catch (error) {
91
+ return { error: error.message };
92
+ }
93
+ if (!isUserName(user)) {
94
+ return { dataSet, user };
95
+ }
96
+ if (!Object.prototype.hasOwnProperty.call(dataSet.users, user)) {
97
+ return {
98
+ error: `Data set "${data}" declares no user ${JSON.stringify(user)}. ${describeDeclaredUsers(
99
+ dataSet
100
+ )}`,
101
+ };
102
+ }
103
+ return { dataSet, user: dataSet.users[user] };
104
+ }
105
+
106
+ export default resolveJourneyDataSet;