@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.
- package/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +78 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +727 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/describeTargetKey.js +29 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +52 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +133 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +493 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +83 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +251 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sessionDatabaseName.js +32 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +36 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +225 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +12 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +81 -7
- package/lib/docs/getBuildStatus.test.mjs +229 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +92 -0
- package/lib/server/applyDataSetRedirect.test.mjs +446 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +207 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +134 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +331 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +115 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +25 -3
- package/manager/processes/initialBuild.mjs +17 -1
- package/manager/processes/initialBuild.test.mjs +104 -0
- package/manager/processes/lowdefyBuild.mjs +31 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +72 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,130 @@
|
|
|
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 resolveJourneyDataSet from './resolveJourneyDataSet.js';
|
|
22
|
+
|
|
23
|
+
let configDirectory;
|
|
24
|
+
let buildDirectory;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
configDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-resolve-journey-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
|
+
fs.writeFileSync(
|
|
32
|
+
path.join(buildDirectory, 'connections', 'tickets.json'),
|
|
33
|
+
JSON.stringify({
|
|
34
|
+
connectionId: 'tickets',
|
|
35
|
+
type: 'MongoDBCollection',
|
|
36
|
+
properties: { databaseUri: { _secret: 'MONGODB_URI' }, collection: 'tickets' },
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
fs.writeFileSync(
|
|
40
|
+
path.join(configDirectory, 'tests', 'data', 'empty-org.yaml'),
|
|
41
|
+
`fixtures:
|
|
42
|
+
tickets: [{ _id: t1, organizationId: org_a }]
|
|
43
|
+
users:
|
|
44
|
+
owner: { id: u_1, roles: [admin], organizationId: org_a }
|
|
45
|
+
member: { id: u_2, roles: [member], organizationId: org_a }
|
|
46
|
+
`
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
fs.rmSync(configDirectory, { recursive: true, force: true });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function resolve(overrides) {
|
|
55
|
+
return resolveJourneyDataSet({
|
|
56
|
+
configDirectory,
|
|
57
|
+
buildDirectory,
|
|
58
|
+
authConfigured: true,
|
|
59
|
+
mockUserActive: false,
|
|
60
|
+
...overrides,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
test('resolveJourneyDataSet resolves a named user from the data set', async () => {
|
|
65
|
+
const { dataSet, user, error } = await resolve({ data: 'empty-org', user: 'member' });
|
|
66
|
+
expect(error).toBeUndefined();
|
|
67
|
+
expect(user).toEqual({ id: 'u_2', roles: ['member'], organizationId: 'org_a' });
|
|
68
|
+
expect(dataSet.name).toEqual('empty-org');
|
|
69
|
+
expect(dataSet.collections).toEqual({ tickets: 'tickets' });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('resolveJourneyDataSet keeps an inline user on a data set journey', async () => {
|
|
73
|
+
const { user, dataSet } = await resolve({ data: 'empty-org', user: { id: 'x', roles: [] } });
|
|
74
|
+
expect(user).toEqual({ id: 'x', roles: [] });
|
|
75
|
+
expect(dataSet.users.owner.id).toEqual('u_1');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('resolveJourneyDataSet refuses a user name the data set does not declare', async () => {
|
|
79
|
+
const { error } = await resolve({ data: 'empty-org', user: 'outsider' });
|
|
80
|
+
expect(error).toEqual(
|
|
81
|
+
'Data set "empty-org" declares no user "outsider". Declared: owner, member.'
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('resolveJourneyDataSet refuses a user name on a journey with no data', async () => {
|
|
86
|
+
const { error } = await resolve({ user: 'member' });
|
|
87
|
+
expect(error).toMatch(
|
|
88
|
+
'The journey\'s user "member" names a data set user, but the journey has no "data".'
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('resolveJourneyDataSet passes a journey with no data and no named user through untouched', async () => {
|
|
93
|
+
expect(await resolve({ user: 'none' })).toEqual({ user: 'none' });
|
|
94
|
+
expect(await resolve({ user: { roles: ['admin'] } })).toEqual({ user: { roles: ['admin'] } });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('resolveJourneyDataSet refuses user none on a data set while auth is configured', async () => {
|
|
98
|
+
const { error } = await resolve({ data: 'empty-org', user: 'none' });
|
|
99
|
+
expect(error).toMatch('has user "none", which is refused while auth is configured');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('resolveJourneyDataSet allows user none on a data set when auth is not configured', async () => {
|
|
103
|
+
const { error, user } = await resolve({ data: 'empty-org', user: 'none', authConfigured: false });
|
|
104
|
+
expect(error).toBeUndefined();
|
|
105
|
+
expect(user).toEqual('none');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test.each([['member'], [{ id: 'x', roles: ['admin'] }], [undefined]])(
|
|
109
|
+
'resolveJourneyDataSet refuses a data set journey with user %j while a dev mock user is active',
|
|
110
|
+
async (user) => {
|
|
111
|
+
const { error } = await resolve({ data: 'empty-org', user, mockUserActive: true });
|
|
112
|
+
expect(error).toMatch('cannot run while a dev mock user is active');
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
test('resolveJourneyDataSet returns readDataSet errors as its own', async () => {
|
|
117
|
+
const { error } = await resolve({ data: 'missing', user: 'member' });
|
|
118
|
+
expect(error).toEqual('Data set "missing" not found in tests/data. Declared: empty-org.');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('resolveJourneyDataSet refuses user none while a dev mock user is active', async () => {
|
|
122
|
+
const { error } = await resolve({ user: 'none', mockUserActive: true });
|
|
123
|
+
expect(error).toMatch(
|
|
124
|
+
'The journey has user "none", which cannot run while a dev mock user is active'
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('resolveJourneyDataSet keeps user none when no dev mock user is active', async () => {
|
|
129
|
+
expect(await resolve({ user: 'none' })).toEqual({ user: 'none' });
|
|
130
|
+
});
|
|
@@ -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 { type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
// The session database a database target (describeTargetKey) reads. Each target the build names has
|
|
20
|
+
// its own, numbered when the session opens; a target the build did not name (a config mutant's, say)
|
|
21
|
+
// gets the next number when first met, so it never merges with another. A target computed per
|
|
22
|
+
// request (null) reads the session's first database.
|
|
23
|
+
function sessionDatabaseName({ session, target }) {
|
|
24
|
+
if (type.isNone(target)) return session.databaseName;
|
|
25
|
+
if (!session.databases.has(target)) {
|
|
26
|
+
session.databases.set(target, `${session.prefix}_${session.databaseCount}`);
|
|
27
|
+
session.databaseCount += 1;
|
|
28
|
+
}
|
|
29
|
+
return session.databases.get(target);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default sessionDatabaseName;
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
|
|
19
|
+
// Drops every session database on the store that no registered session owns: one left behind by a
|
|
20
|
+
// write that was still in flight when its session dropped its databases, or by a dev server that
|
|
21
|
+
// stopped mid-run. A session owns every database under its prefix (<prefix>_<n>), including one it
|
|
22
|
+
// numbers after this sweep lists them.
|
|
23
|
+
async function sweepOrphanDatabases({ client }) {
|
|
24
|
+
const prefixes = [...dataSessionRegistry.values()].map((session) => `${session.prefix}_`);
|
|
25
|
+
const { databases } = await client.db('admin').admin().listDatabases({ nameOnly: true });
|
|
26
|
+
await Promise.all(
|
|
27
|
+
databases
|
|
28
|
+
.map((database) => database.name)
|
|
29
|
+
.filter(
|
|
30
|
+
(name) => name.startsWith('ld_') && !prefixes.some((prefix) => name.startsWith(prefix))
|
|
31
|
+
)
|
|
32
|
+
.map((name) => client.db(name).dropDatabase())
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default sweepOrphanDatabases;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# The app the data set journey end-to-end test (dataSetJourneys.chromium.mongodb.test.mjs) builds and
|
|
2
|
+
# serves. Its connections read the MONGODB_URI secret, which the test points at a stand-in for the
|
|
3
|
+
# developer's real database; a journey on the "shop" data set must never touch it.
|
|
4
|
+
# Auth is configured, with its adapter on the same stand-in, so the suite can prove that no journey
|
|
5
|
+
# request reaches the auth engine or writes an auth collection there.
|
|
6
|
+
lowdefy: local
|
|
7
|
+
name: Data set journeys
|
|
8
|
+
|
|
9
|
+
auth:
|
|
10
|
+
database:
|
|
11
|
+
id: auth_db
|
|
12
|
+
type: MongoDBAuthAdapter
|
|
13
|
+
properties:
|
|
14
|
+
uri:
|
|
15
|
+
_secret: MONGODB_URI
|
|
16
|
+
secret:
|
|
17
|
+
_secret: BETTER_AUTH_SECRET
|
|
18
|
+
emailAndPassword:
|
|
19
|
+
enabled: true
|
|
20
|
+
organizations:
|
|
21
|
+
policy: tenant
|
|
22
|
+
|
|
23
|
+
# Under policy: tenant a MongoDBCollection connection is walled by default: every read is filtered
|
|
24
|
+
# and every write stamped with the caller's organization_id.
|
|
25
|
+
connections:
|
|
26
|
+
- id: tickets
|
|
27
|
+
type: MongoDBCollection
|
|
28
|
+
properties:
|
|
29
|
+
databaseUri:
|
|
30
|
+
_secret: MONGODB_URI
|
|
31
|
+
collection: tickets
|
|
32
|
+
write: true
|
|
33
|
+
# A second database that also has a tickets collection: under a data set it reads a session
|
|
34
|
+
# database of its own, so its fixtures never merge with the app's tickets.
|
|
35
|
+
- id: crm_tickets
|
|
36
|
+
type: MongoDBCollection
|
|
37
|
+
properties:
|
|
38
|
+
databaseUri:
|
|
39
|
+
_secret: CRM_MONGODB_URI
|
|
40
|
+
collection: tickets
|
|
41
|
+
write: true
|
|
42
|
+
|
|
43
|
+
# A module connection is written under its module's folder (connections/archive/archive_db.json),
|
|
44
|
+
# which the data set redirect must reach too.
|
|
45
|
+
modules:
|
|
46
|
+
- id: archive
|
|
47
|
+
source: 'file:modules/archive'
|
|
48
|
+
|
|
49
|
+
api:
|
|
50
|
+
- id: create_ticket
|
|
51
|
+
type: Api
|
|
52
|
+
routine:
|
|
53
|
+
- id: insert
|
|
54
|
+
type: MongoDBInsertOne
|
|
55
|
+
connectionId: tickets
|
|
56
|
+
properties:
|
|
57
|
+
doc:
|
|
58
|
+
_id:
|
|
59
|
+
_payload: id
|
|
60
|
+
title:
|
|
61
|
+
_payload: title
|
|
62
|
+
- :return:
|
|
63
|
+
inserted:
|
|
64
|
+
_payload: id
|
|
65
|
+
- id: list_tickets
|
|
66
|
+
type: Api
|
|
67
|
+
routine:
|
|
68
|
+
- id: find
|
|
69
|
+
type: MongoDBFind
|
|
70
|
+
connectionId: tickets
|
|
71
|
+
properties:
|
|
72
|
+
query: {}
|
|
73
|
+
options:
|
|
74
|
+
sort:
|
|
75
|
+
_id: 1
|
|
76
|
+
- :return:
|
|
77
|
+
_step: find
|
|
78
|
+
# The developer's own cookieless tab: no caller, so the read opts out of the wall.
|
|
79
|
+
- id: list_all_tickets
|
|
80
|
+
type: Api
|
|
81
|
+
routine:
|
|
82
|
+
- id: find
|
|
83
|
+
type: MongoDBFind
|
|
84
|
+
connectionId: tickets
|
|
85
|
+
tenant: none
|
|
86
|
+
properties:
|
|
87
|
+
query: {}
|
|
88
|
+
options:
|
|
89
|
+
sort:
|
|
90
|
+
_id: 1
|
|
91
|
+
- :return:
|
|
92
|
+
_step: find
|
|
93
|
+
- id: list_crm_tickets
|
|
94
|
+
type: Api
|
|
95
|
+
routine:
|
|
96
|
+
- id: find
|
|
97
|
+
type: MongoDBFind
|
|
98
|
+
connectionId: crm_tickets
|
|
99
|
+
properties:
|
|
100
|
+
query: {}
|
|
101
|
+
options:
|
|
102
|
+
sort:
|
|
103
|
+
_id: 1
|
|
104
|
+
- :return:
|
|
105
|
+
_step: find
|
|
106
|
+
- id: create_ticket_later
|
|
107
|
+
type: Api
|
|
108
|
+
routine:
|
|
109
|
+
- id: dispatch
|
|
110
|
+
type: CallApi
|
|
111
|
+
properties:
|
|
112
|
+
endpointId: insert_detached
|
|
113
|
+
detached: true
|
|
114
|
+
payload:
|
|
115
|
+
id:
|
|
116
|
+
_payload: id
|
|
117
|
+
- :return:
|
|
118
|
+
dispatched: true
|
|
119
|
+
- id: insert_detached
|
|
120
|
+
type: Api
|
|
121
|
+
routine:
|
|
122
|
+
- id: insert
|
|
123
|
+
type: MongoDBInsertOne
|
|
124
|
+
connectionId: tickets
|
|
125
|
+
properties:
|
|
126
|
+
doc:
|
|
127
|
+
_id:
|
|
128
|
+
_payload: id
|
|
129
|
+
detached: true
|
|
130
|
+
|
|
131
|
+
# Run under a config mutant (`lowdefy journeys harden`) that drops their "log" step: a detached
|
|
132
|
+
# target and a direct endpoint, each writing a ticket and then a log entry.
|
|
133
|
+
- id: create_ticket_later_logged
|
|
134
|
+
type: Api
|
|
135
|
+
routine:
|
|
136
|
+
- id: dispatch
|
|
137
|
+
type: CallApi
|
|
138
|
+
properties:
|
|
139
|
+
endpointId: insert_detached_logged
|
|
140
|
+
detached: true
|
|
141
|
+
payload:
|
|
142
|
+
id:
|
|
143
|
+
_payload: id
|
|
144
|
+
- :return:
|
|
145
|
+
dispatched: true
|
|
146
|
+
- id: insert_detached_logged
|
|
147
|
+
type: Api
|
|
148
|
+
routine:
|
|
149
|
+
- id: insert
|
|
150
|
+
type: MongoDBInsertOne
|
|
151
|
+
connectionId: tickets
|
|
152
|
+
properties:
|
|
153
|
+
doc:
|
|
154
|
+
_id:
|
|
155
|
+
_payload: id
|
|
156
|
+
detached: true
|
|
157
|
+
- id: log
|
|
158
|
+
type: MongoDBInsertOne
|
|
159
|
+
connectionId: tickets
|
|
160
|
+
properties:
|
|
161
|
+
doc:
|
|
162
|
+
_id: log-detached
|
|
163
|
+
- id: create_ticket_logged
|
|
164
|
+
type: Api
|
|
165
|
+
routine:
|
|
166
|
+
- id: insert
|
|
167
|
+
type: MongoDBInsertOne
|
|
168
|
+
connectionId: tickets
|
|
169
|
+
properties:
|
|
170
|
+
doc:
|
|
171
|
+
_id:
|
|
172
|
+
_payload: id
|
|
173
|
+
- id: log
|
|
174
|
+
type: MongoDBInsertOne
|
|
175
|
+
connectionId: tickets
|
|
176
|
+
properties:
|
|
177
|
+
doc:
|
|
178
|
+
_id: log-direct
|
|
179
|
+
- :return:
|
|
180
|
+
inserted: true
|
|
181
|
+
|
|
182
|
+
# A detached run whose routine reaches an auth step: under a data session it has no auth engine,
|
|
183
|
+
# so the step fails and the insert after it never runs.
|
|
184
|
+
- id: create_ticket_later_auth
|
|
185
|
+
type: Api
|
|
186
|
+
routine:
|
|
187
|
+
- id: dispatch
|
|
188
|
+
type: CallApi
|
|
189
|
+
properties:
|
|
190
|
+
endpointId: insert_detached_auth
|
|
191
|
+
detached: true
|
|
192
|
+
payload: {}
|
|
193
|
+
- :return:
|
|
194
|
+
dispatched: true
|
|
195
|
+
- id: insert_detached_auth
|
|
196
|
+
type: Api
|
|
197
|
+
routine:
|
|
198
|
+
- id: before
|
|
199
|
+
type: MongoDBInsertOne
|
|
200
|
+
connectionId: tickets
|
|
201
|
+
properties:
|
|
202
|
+
doc:
|
|
203
|
+
_id: later-auth-before
|
|
204
|
+
- id: members
|
|
205
|
+
type: ListMembers
|
|
206
|
+
properties: {}
|
|
207
|
+
- id: after
|
|
208
|
+
type: MongoDBInsertOne
|
|
209
|
+
connectionId: tickets
|
|
210
|
+
properties:
|
|
211
|
+
doc:
|
|
212
|
+
_id: later-auth-after
|
|
213
|
+
|
|
214
|
+
websockets:
|
|
215
|
+
- id: ticket_changes
|
|
216
|
+
type: MongoDBChangeStream
|
|
217
|
+
connectionId: tickets
|
|
218
|
+
properties:
|
|
219
|
+
pipeline:
|
|
220
|
+
- $match:
|
|
221
|
+
operationType: insert
|
|
222
|
+
|
|
223
|
+
pages:
|
|
224
|
+
- id: tickets
|
|
225
|
+
type: Box
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Archive
|
|
2
|
+
|
|
3
|
+
secrets:
|
|
4
|
+
- name: MONGODB_URI
|
|
5
|
+
description: The app's database, the same stand-in the app's own connection reads.
|
|
6
|
+
|
|
7
|
+
connections:
|
|
8
|
+
- id: archive_db
|
|
9
|
+
type: MongoDBCollection
|
|
10
|
+
properties:
|
|
11
|
+
databaseUri:
|
|
12
|
+
_secret: MONGODB_URI
|
|
13
|
+
collection: archived
|
|
14
|
+
write: true
|
|
15
|
+
|
|
16
|
+
api:
|
|
17
|
+
- id: archive_ticket
|
|
18
|
+
type: Api
|
|
19
|
+
routine:
|
|
20
|
+
- id: insert
|
|
21
|
+
type: MongoDBInsertOne
|
|
22
|
+
connectionId:
|
|
23
|
+
_module.connectionId: archive_db
|
|
24
|
+
properties:
|
|
25
|
+
doc:
|
|
26
|
+
_id:
|
|
27
|
+
_payload: id
|
|
28
|
+
- :return:
|
|
29
|
+
archived:
|
|
30
|
+
_payload: id
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
fixtures:
|
|
2
|
+
tickets:
|
|
3
|
+
- { _id: t-a1, organization_id: org_a, title: First }
|
|
4
|
+
- { _id: t-a2, organization_id: org_a, title: Second }
|
|
5
|
+
- { _id: t-b1, organization_id: org_b, title: Other org }
|
|
6
|
+
# The same collection name in another database: it loads into a session database of its own.
|
|
7
|
+
crm_tickets:
|
|
8
|
+
- { _id: t-a1, organization_id: org_a, title: CRM copy }
|
|
9
|
+
- { _id: crm-a2, organization_id: org_a, title: CRM only }
|
|
10
|
+
users:
|
|
11
|
+
owner: { id: u_1, roles: [admin], organizationId: org_a }
|
|
12
|
+
outsider: { id: u_9, roles: [admin], organizationId: org_b }
|
|
@@ -0,0 +1,43 @@
|
|
|
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 path from 'node:path';
|
|
19
|
+
import { shallowBuild } from '@lowdefy/build/dev';
|
|
20
|
+
|
|
21
|
+
// Builds an app into <serverDirectory>/build for a test, in a Node process of its own: the build
|
|
22
|
+
// imports plugin modules dynamically, which jest's module runtime cannot load.
|
|
23
|
+
// node buildTestApp.mjs <configDirectory> <serverDirectory>
|
|
24
|
+
const [configDirectory, serverDirectory] = process.argv.slice(2);
|
|
25
|
+
const serverDevDirectory = path.resolve(import.meta.dirname, '../../../..');
|
|
26
|
+
const directories = {
|
|
27
|
+
config: configDirectory,
|
|
28
|
+
build: path.join(serverDirectory, 'build'),
|
|
29
|
+
server: path.join(serverDirectory, 'server'),
|
|
30
|
+
};
|
|
31
|
+
fs.mkdirSync(path.join(directories.server, 'public_default'), { recursive: true });
|
|
32
|
+
fs.copyFileSync(
|
|
33
|
+
path.join(serverDevDirectory, 'package.json'),
|
|
34
|
+
path.join(directories.server, 'package.json')
|
|
35
|
+
);
|
|
36
|
+
const quiet = () => {};
|
|
37
|
+
await shallowBuild({
|
|
38
|
+
customMessagesMap: {},
|
|
39
|
+
customTypesMap: {},
|
|
40
|
+
directories,
|
|
41
|
+
logger: { debug: quiet, info: quiet, warn: quiet, error: console.error, ui: {} },
|
|
42
|
+
stage: 'dev',
|
|
43
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
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
|
+
|
|
19
|
+
import chokidar from 'chokidar';
|
|
20
|
+
import { type } from '@lowdefy/helpers';
|
|
21
|
+
|
|
22
|
+
import getStaleStatus from './getStaleStatus.js';
|
|
23
|
+
import readBuildArtifact from './readBuildArtifact.js';
|
|
24
|
+
|
|
25
|
+
// In-process publish/subscribe bus behind the dev server's push channels
|
|
26
|
+
// (MCP notifications/message and GET /lowdefy-docs/events). Deliberately
|
|
27
|
+
// unbuffered: a subscriber that missed an event polls build_status, which is
|
|
28
|
+
// derived from the same build/buildStatus.json this bus watches, so the two
|
|
29
|
+
// always agree. Event shape is { type, timestamp, ...entry } with type one of
|
|
30
|
+
// build | client_error | server_error | restart.
|
|
31
|
+
const EVENT_TYPES = ['build', 'client_error', 'server_error', 'restart'];
|
|
32
|
+
|
|
33
|
+
// The Hono process boots once per (re)start, so module load time is the
|
|
34
|
+
// restart time — subscribers receive it as a restart event on connect.
|
|
35
|
+
const bootedAt = new Date().toISOString();
|
|
36
|
+
|
|
37
|
+
const subscribers = [];
|
|
38
|
+
|
|
39
|
+
let watcher = null;
|
|
40
|
+
|
|
41
|
+
function publish(event) {
|
|
42
|
+
if (!EVENT_TYPES.includes(event?.type)) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`devEventBus event type must be one of ${EVENT_TYPES.join(', ')}. Received ${JSON.stringify(
|
|
45
|
+
event?.type
|
|
46
|
+
)}.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const fullEvent = { timestamp: new Date().toISOString(), ...event };
|
|
50
|
+
// Iterate over a copy: a failing send unsubscribes itself mid-loop.
|
|
51
|
+
[...subscribers].forEach((send) => {
|
|
52
|
+
let result;
|
|
53
|
+
try {
|
|
54
|
+
result = send(fullEvent);
|
|
55
|
+
} catch {
|
|
56
|
+
unsubscribe(send);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (type.isFunction(result?.then)) {
|
|
60
|
+
result.catch(() => unsubscribe(send));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readBuildEvent() {
|
|
66
|
+
// The manager writes buildStatus.json from another process; a change event
|
|
67
|
+
// can fire while the write is still in flight. A half-written file is not an
|
|
68
|
+
// error worth surfacing — the completed write fires its own change event.
|
|
69
|
+
try {
|
|
70
|
+
const build = readBuildArtifact({ name: 'buildStatus.json' });
|
|
71
|
+
if (type.isNone(build)) return null;
|
|
72
|
+
return {
|
|
73
|
+
type: 'build',
|
|
74
|
+
status: build.status,
|
|
75
|
+
errorCount: (build.errors ?? []).length,
|
|
76
|
+
warningCount: (build.warnings ?? []).length,
|
|
77
|
+
errors: build.errors ?? [],
|
|
78
|
+
warnings: build.warnings ?? [],
|
|
79
|
+
stale: false,
|
|
80
|
+
staleSince: null,
|
|
81
|
+
...getStaleStatus(),
|
|
82
|
+
};
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function publishBuildStatus() {
|
|
89
|
+
const event = readBuildEvent();
|
|
90
|
+
if (event === null) return;
|
|
91
|
+
publish(event);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// The watcher is held open only while someone is listening. Starting it at
|
|
95
|
+
// module load would pin every process that imports an error store — including
|
|
96
|
+
// test runners — on a persistent fs handle for a file it may never need.
|
|
97
|
+
function startWatcher() {
|
|
98
|
+
watcher = chokidar.watch(path.join(process.cwd(), 'build', 'buildStatus.json'), {
|
|
99
|
+
persistent: true,
|
|
100
|
+
ignoreInitial: true,
|
|
101
|
+
});
|
|
102
|
+
watcher.on('add', publishBuildStatus);
|
|
103
|
+
watcher.on('change', publishBuildStatus);
|
|
104
|
+
// No unlink handler: cleanBuildDirectory removes the file mid-rebuild and the
|
|
105
|
+
// rebuild's own write re-adds it.
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function stopWatcher() {
|
|
109
|
+
const closing = watcher.close();
|
|
110
|
+
watcher = null;
|
|
111
|
+
return closing;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function unsubscribe(send) {
|
|
115
|
+
const index = subscribers.indexOf(send);
|
|
116
|
+
if (index === -1) return;
|
|
117
|
+
subscribers.splice(index, 1);
|
|
118
|
+
if (subscribers.length === 0 && watcher !== null) {
|
|
119
|
+
stopWatcher();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function subscribe(send) {
|
|
124
|
+
if (!type.isFunction(send)) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`devEventBus.subscribe requires a "send" function. Received ${JSON.stringify(send)}.`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
subscribers.push(send);
|
|
130
|
+
if (watcher === null) {
|
|
131
|
+
startWatcher();
|
|
132
|
+
}
|
|
133
|
+
return () => unsubscribe(send);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { bootedAt, publish, subscribe };
|