@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
package/manager/run.mjs
CHANGED
|
@@ -15,22 +15,30 @@
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { wait } from '@lowdefy/helpers';
|
|
19
|
-
import { findAvailablePort } from '@lowdefy/node-utils';
|
|
20
18
|
import opener from 'opener';
|
|
19
|
+
import { registerServer, watchOwner } from '@lowdefy/node-utils';
|
|
20
|
+
import checkAgentFiles from '../lib/docs/checkAgentFiles.js';
|
|
21
21
|
import getContext from './getContext.mjs';
|
|
22
|
+
import getLowdefyVersion from './utils/getLowdefyVersion.mjs';
|
|
23
|
+
import acquireDevInstance from './utils/acquireDevInstance.mjs';
|
|
24
|
+
import createBuildActivity from './utils/createBuildActivity.mjs';
|
|
25
|
+
import createIdleGc from './utils/createIdleGc.mjs';
|
|
26
|
+
import createRequestActivity from './utils/createRequestActivity.mjs';
|
|
27
|
+
import startMailSink from './processes/startMailSink.mjs';
|
|
22
28
|
import startProxy from './processes/startProxy.mjs';
|
|
23
|
-
import
|
|
29
|
+
import startFirstServer from './processes/startFirstServer.mjs';
|
|
30
|
+
import startRecordingPruner from './utils/startRecordingPruner.mjs';
|
|
24
31
|
import formatNoticeBox from './utils/formatNoticeBox.mjs';
|
|
32
|
+
import resolvePorts from './utils/resolvePorts.mjs';
|
|
25
33
|
|
|
26
34
|
/*
|
|
27
35
|
The run script does the following:
|
|
28
|
-
-
|
|
36
|
+
- Read .env, run the initial Lowdefy build and install plugins
|
|
29
37
|
- Start file watchers to reload config and restart server if necessary
|
|
30
38
|
- Start the server
|
|
31
39
|
- Open a browser window.
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
Watchers (see processes/startWatchers.mjs):
|
|
34
42
|
|
|
35
43
|
## Lowdefy build watcher
|
|
36
44
|
Watches:
|
|
@@ -48,25 +56,14 @@ The run script does the following:
|
|
|
48
56
|
If the .env file is changed, the new file is parsed, and the server restarted with the new env
|
|
49
57
|
and the server hard reloads.
|
|
50
58
|
|
|
51
|
-
##
|
|
59
|
+
## Local plugin, restart request and server package.json watchers
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
- <build-dir>/config.json
|
|
57
|
-
- <server-dir>/package.json
|
|
61
|
+
A local plugin change rebuilds (and restarts when the plugin has server-side types), a restart
|
|
62
|
+
requested by the dev tools rebuilds and restarts, and a plugin package a page build added to
|
|
63
|
+
the server's package.json is installed.
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
If user styles change:
|
|
63
|
-
- <public-dir>/styles.css changes, rebuild and restart server.
|
|
64
|
-
|
|
65
|
-
If new plugin type in an existing plugin package is used:
|
|
66
|
-
- <build-dir>/plugins/** changes, rebuild next and restart server.
|
|
67
|
-
|
|
68
|
-
If new plugin type in a new plugin package is used:
|
|
69
|
-
- <server-dir>/package.json changes, run npm install, rebuild next and restart server.
|
|
65
|
+
After every build, syncServer restarts the server when a file it read at start changed (config,
|
|
66
|
+
auth, connections, server operators), installing new plugin packages first.
|
|
70
67
|
|
|
71
68
|
# Reload mechanism
|
|
72
69
|
|
|
@@ -81,45 +78,123 @@ The run script does the following:
|
|
|
81
78
|
|
|
82
79
|
const context = await getContext();
|
|
83
80
|
|
|
81
|
+
const instance = acquireDevInstance({
|
|
82
|
+
configDirectory: context.directories.config,
|
|
83
|
+
owner: context.options.owner,
|
|
84
|
+
version: context.version,
|
|
85
|
+
});
|
|
86
|
+
if (instance.acquired === false) {
|
|
87
|
+
const { holder } = instance;
|
|
88
|
+
const where = holder.port ? `, http://localhost:${holder.port}` : '';
|
|
89
|
+
context.logger.error(
|
|
90
|
+
`A dev server for this app is already running (${holder.owner ?? 'terminal'}${where}, pid ${
|
|
91
|
+
holder.pid
|
|
92
|
+
}). ` +
|
|
93
|
+
'Two dev servers race writing the build directory. Use the running one, or stop it first.'
|
|
94
|
+
);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
process.on('exit', () => instance.release());
|
|
98
|
+
startRecordingPruner({ configDirectory: context.directories.config, logger: context.logger });
|
|
99
|
+
|
|
100
|
+
// Requests through the proxy and finished builds are use of the server; the
|
|
101
|
+
// hub stops a server nobody has used for its idle limit (see
|
|
102
|
+
// createRequestActivity).
|
|
103
|
+
context.requestActivity = createRequestActivity({
|
|
104
|
+
onChange: (fields) => instance.update(fields),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// `building` is true while a change is queued or being processed, restarts
|
|
108
|
+
// included. lowdefy_build_status({ wait: true }) waits on it, so an agent
|
|
109
|
+
// reads the build that includes its last edit instead of the one before.
|
|
110
|
+
// One full GC shortly after each build, which is when the manager's heap grows.
|
|
111
|
+
const idleGc = createIdleGc();
|
|
112
|
+
|
|
113
|
+
context.buildActivity = createBuildActivity({
|
|
114
|
+
onChange: (building) => {
|
|
115
|
+
instance.update({ building });
|
|
116
|
+
idleGc.onBuildingChange(building);
|
|
117
|
+
if (!building) {
|
|
118
|
+
context.requestActivity.touch();
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Machine-wide record of this manager and its owner, for `lowdefy hub ps|prune`.
|
|
124
|
+
// Written only when the CLI sets the registry directory.
|
|
125
|
+
const registration = registerServer({
|
|
126
|
+
kind: 'dev',
|
|
127
|
+
port: context.options.port,
|
|
128
|
+
configDirectory: context.directories.config,
|
|
129
|
+
logger: context.logger,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
function shutdown() {
|
|
133
|
+
context.shutdownServer();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
|
|
84
137
|
// Shut the Vite child down on direct signals (process managers, scripts/dev.mjs
|
|
85
138
|
// signal forwarding) — terminal Ctrl+C signals the whole process group, but a
|
|
86
139
|
// targeted SIGTERM would otherwise orphan the child.
|
|
87
|
-
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
88
|
-
process.on(signal,
|
|
89
|
-
context.shutdownServer();
|
|
90
|
-
process.exit(0);
|
|
91
|
-
});
|
|
140
|
+
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
|
|
141
|
+
process.on(signal, shutdown);
|
|
92
142
|
}
|
|
93
143
|
|
|
144
|
+
// A manager started by the CLI, a test runner or a script stops when that
|
|
145
|
+
// owner stops, however it ends. Inert unless the spawner set its variables.
|
|
146
|
+
watchOwner({
|
|
147
|
+
onExit: ({ reason }) => {
|
|
148
|
+
context.logger.info(`The process that started this dev server is gone (${reason}).`);
|
|
149
|
+
shutdown();
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
94
153
|
try {
|
|
95
154
|
await context.initialBuild();
|
|
96
155
|
|
|
97
|
-
//
|
|
98
|
-
//
|
|
156
|
+
// Not awaited: chokidar's ready event is unreliable. Started now so an edit
|
|
157
|
+
// made during the rest of the start-up is seen; a batch that syncs before
|
|
158
|
+
// the first child start waits for it (see syncServer).
|
|
99
159
|
context.startWatchers();
|
|
100
160
|
|
|
101
|
-
// The manager is the component that binds the port, so it
|
|
161
|
+
// The manager is the component that binds the port, so it checks here to
|
|
102
162
|
// cover every launch path (CLI, monorepo dev script, direct run.mjs) and any
|
|
103
163
|
// process that grabbed the port during the initial build.
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
164
|
+
const { port, internalPort } = await resolvePorts(context);
|
|
165
|
+
context.options.port = port;
|
|
166
|
+
context.internalPort = internalPort;
|
|
167
|
+
instance.update({ port, internalPort });
|
|
168
|
+
registration?.update({ port });
|
|
169
|
+
context.instance = instance;
|
|
170
|
+
|
|
171
|
+
// Called by waitForDevServer whenever a child answers: the first start's,
|
|
172
|
+
// one that answers after its wait, or a restart's after a first child that
|
|
173
|
+
// exited. The hub and the MCP shim wait on ready.
|
|
174
|
+
let ready = false;
|
|
175
|
+
context.markServerReady = () => {
|
|
176
|
+
if (ready) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
ready = true;
|
|
180
|
+
// A slow first build must not make a fresh server look idle the moment it is ready.
|
|
181
|
+
context.requestActivity.touch();
|
|
182
|
+
instance.update({ state: 'ready' });
|
|
183
|
+
};
|
|
111
184
|
|
|
112
185
|
// The manager holds the public port for the whole session and proxies to the
|
|
113
186
|
// Vite child on an internal loopback port — restarting the child (js module
|
|
114
187
|
// or .env change) then never drops the listener, so long-lived clients (MCP
|
|
115
188
|
// agents, the reload SSE stream, HMR websockets) reconnect instead of dying
|
|
116
189
|
// on ECONNREFUSED.
|
|
117
|
-
context.internalPort = await findAvailablePort({ port: context.options.port + 1 });
|
|
118
190
|
await startProxy(context);
|
|
191
|
+
context.mailSink = await startMailSink(context);
|
|
119
192
|
|
|
120
|
-
|
|
121
|
-
await
|
|
122
|
-
|
|
193
|
+
// Optimises dependencies, starts the child and waits for it to answer.
|
|
194
|
+
if (!(await startFirstServer(context))) {
|
|
195
|
+
context.logger.warn('The dev server did not answer within 2 minutes - check the output above.');
|
|
196
|
+
}
|
|
197
|
+
const docsUrl = `${context.url}/lowdefy-docs`;
|
|
123
198
|
context.logger.info(
|
|
124
199
|
{ color: 'blue' },
|
|
125
200
|
formatNoticeBox({
|
|
@@ -137,9 +212,19 @@ try {
|
|
|
137
212
|
],
|
|
138
213
|
})
|
|
139
214
|
);
|
|
140
|
-
|
|
215
|
+
// Lowdefy's agent block: missing, from another version, or not imported by
|
|
216
|
+
// CLAUDE.md. Build status reports the same notices to agents on every read.
|
|
217
|
+
const agentFiles = checkAgentFiles({
|
|
218
|
+
configDirectory: context.directories.config,
|
|
219
|
+
lowdefyVersion: await getLowdefyVersion(context).catch(() => null),
|
|
220
|
+
});
|
|
221
|
+
for (const notice of agentFiles) {
|
|
222
|
+
context.logger.warn(notice.message);
|
|
223
|
+
}
|
|
224
|
+
// A hub-owned server was started for an agent, not for a person at a browser.
|
|
225
|
+
if (process.env.LOWDEFY_SERVER_DEV_OPEN_BROWSER === 'true' && context.options.owner !== 'hub') {
|
|
141
226
|
// TODO: Wait 1 sec for a ping and don't open if a ping is seen
|
|
142
|
-
opener(
|
|
227
|
+
opener(context.url);
|
|
143
228
|
}
|
|
144
229
|
await new Promise(() => {});
|
|
145
230
|
} catch (error) {
|
|
@@ -17,21 +17,40 @@
|
|
|
17
17
|
import { type } from '@lowdefy/helpers';
|
|
18
18
|
|
|
19
19
|
class BatchChanges {
|
|
20
|
-
constructor({ context, fn, delay }) {
|
|
20
|
+
constructor({ context, fn, delay, onBusy }) {
|
|
21
21
|
this.context = context;
|
|
22
22
|
this._call = this._call.bind(this);
|
|
23
23
|
this.args = [];
|
|
24
|
+
this.busy = false;
|
|
24
25
|
this.delay = delay || 500;
|
|
25
26
|
this.fn = fn;
|
|
27
|
+
this.onBusy = onBusy ?? (() => {});
|
|
26
28
|
this.repeat = false;
|
|
27
29
|
this.running = false;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
newChange(...args) {
|
|
31
33
|
this.args.push(args.filter((arg) => type.isString(arg))); // filter for string paths since chokidar also returns an stats object on windows.
|
|
34
|
+
// Busy from the first change of a batch until the batch - and any batch
|
|
35
|
+
// queued behind it - has been processed, so a reader can wait for its
|
|
36
|
+
// edits to land instead of racing the debounce.
|
|
37
|
+
if (!this.busy) {
|
|
38
|
+
this.busy = true;
|
|
39
|
+
this.onBusy(true);
|
|
40
|
+
}
|
|
32
41
|
this._startTimer();
|
|
33
42
|
}
|
|
34
43
|
|
|
44
|
+
_settle() {
|
|
45
|
+
if (this.repeat) {
|
|
46
|
+
this.repeat = false;
|
|
47
|
+
this._call();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.busy = false;
|
|
51
|
+
this.onBusy(false);
|
|
52
|
+
}
|
|
53
|
+
|
|
35
54
|
_startTimer() {
|
|
36
55
|
if (this.timer) {
|
|
37
56
|
clearTimeout(this.timer);
|
|
@@ -50,14 +69,11 @@ class BatchChanges {
|
|
|
50
69
|
this.args = [];
|
|
51
70
|
await this.fn(args);
|
|
52
71
|
this.running = false;
|
|
53
|
-
if (this.repeat) {
|
|
54
|
-
this.repeat = false;
|
|
55
|
-
this._call();
|
|
56
|
-
}
|
|
57
72
|
} catch (error) {
|
|
58
73
|
this.running = false;
|
|
59
74
|
this.context.logger.error(error?.message ?? error);
|
|
60
75
|
}
|
|
76
|
+
this._settle();
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
|
|
@@ -0,0 +1,77 @@
|
|
|
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 { jest } from '@jest/globals';
|
|
18
|
+
import { wait } from '@lowdefy/helpers';
|
|
19
|
+
|
|
20
|
+
import BatchChanges from './BatchChanges.mjs';
|
|
21
|
+
|
|
22
|
+
const context = { logger: { error: jest.fn() } };
|
|
23
|
+
|
|
24
|
+
test('BatchChanges reports busy from the first change until the batch is processed', async () => {
|
|
25
|
+
const events = [];
|
|
26
|
+
const fn = jest.fn(async () => {
|
|
27
|
+
events.push('processed');
|
|
28
|
+
});
|
|
29
|
+
const batch = new BatchChanges({
|
|
30
|
+
context,
|
|
31
|
+
fn,
|
|
32
|
+
delay: 20,
|
|
33
|
+
onBusy: (busy) => events.push(busy ? 'busy' : 'idle'),
|
|
34
|
+
});
|
|
35
|
+
batch.newChange('a.yaml');
|
|
36
|
+
batch.newChange('b.yaml');
|
|
37
|
+
expect(events).toEqual(['busy']);
|
|
38
|
+
await wait(80);
|
|
39
|
+
expect(events).toEqual(['busy', 'processed', 'idle']);
|
|
40
|
+
expect(fn).toHaveBeenCalledWith([['a.yaml'], ['b.yaml']]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('BatchChanges stays busy through a change that arrives while a batch is running', async () => {
|
|
44
|
+
const events = [];
|
|
45
|
+
let batch;
|
|
46
|
+
const fn = jest.fn(async (args) => {
|
|
47
|
+
events.push(`processed ${args.flat().join(',')}`);
|
|
48
|
+
if (args.flat().includes('a.yaml')) {
|
|
49
|
+
batch.newChange('b.yaml');
|
|
50
|
+
await wait(10);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
batch = new BatchChanges({
|
|
54
|
+
context,
|
|
55
|
+
fn,
|
|
56
|
+
delay: 10,
|
|
57
|
+
onBusy: (busy) => events.push(busy ? 'busy' : 'idle'),
|
|
58
|
+
});
|
|
59
|
+
batch.newChange('a.yaml');
|
|
60
|
+
await wait(100);
|
|
61
|
+
expect(events).toEqual(['busy', 'processed a.yaml', 'processed b.yaml', 'idle']);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('BatchChanges clears busy when processing throws', async () => {
|
|
65
|
+
const events = [];
|
|
66
|
+
const batch = new BatchChanges({
|
|
67
|
+
context,
|
|
68
|
+
fn: async () => {
|
|
69
|
+
throw new Error('build failed');
|
|
70
|
+
},
|
|
71
|
+
delay: 10,
|
|
72
|
+
onBusy: (busy) => events.push(busy ? 'busy' : 'idle'),
|
|
73
|
+
});
|
|
74
|
+
batch.newChange('a.yaml');
|
|
75
|
+
await wait(50);
|
|
76
|
+
expect(events).toEqual(['busy', 'idle']);
|
|
77
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
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 'fs';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
|
|
20
|
+
import { getDevInstancePath, getProcessStartTime, readDevInstance } from '@lowdefy/node-utils';
|
|
21
|
+
|
|
22
|
+
function writeRecord({ instancePath, record }) {
|
|
23
|
+
// Written whole and renamed into place so readers never see half a record.
|
|
24
|
+
const temporaryPath = `${instancePath}.${process.pid}.tmp`;
|
|
25
|
+
fs.mkdirSync(path.dirname(instancePath), { recursive: true });
|
|
26
|
+
fs.writeFileSync(temporaryPath, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 });
|
|
27
|
+
fs.renameSync(temporaryPath, instancePath);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// One dev server per app. Two managers on one app race each other's builds -
|
|
31
|
+
// one wedges on a half-deleted pages directory and keeps serving a stale build
|
|
32
|
+
// with no error anywhere - so the second refuses. The record doubles as the
|
|
33
|
+
// discovery file: the CLI, the MCP shim and the hub read it to find this
|
|
34
|
+
// server's port, owner and readiness without a registry of their own.
|
|
35
|
+
// Creating the file exclusively decides a race between two managers starting
|
|
36
|
+
// at once: exactly one create succeeds.
|
|
37
|
+
function createRecord({ instancePath, record }) {
|
|
38
|
+
fs.mkdirSync(path.dirname(instancePath), { recursive: true });
|
|
39
|
+
try {
|
|
40
|
+
const fd = fs.openSync(instancePath, 'wx', 0o600);
|
|
41
|
+
fs.writeSync(fd, `${JSON.stringify(record, null, 2)}\n`);
|
|
42
|
+
fs.closeSync(fd);
|
|
43
|
+
return true;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error.code === 'EEXIST') {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function acquireDevInstance({ configDirectory, owner, version }) {
|
|
53
|
+
const instancePath = getDevInstancePath({ configDirectory });
|
|
54
|
+
let record = {
|
|
55
|
+
pid: process.pid,
|
|
56
|
+
// Readers check it against the pid's process, so a record left by a
|
|
57
|
+
// killed manager never passes for a live one on a reused pid.
|
|
58
|
+
processStartTime: getProcessStartTime({ pid: process.pid }),
|
|
59
|
+
// The path as stored on disk, whatever case the terminal's working
|
|
60
|
+
// directory was typed in (macOS), so lowdefy mcp and the hub match it.
|
|
61
|
+
configDirectory: fs.realpathSync.native(configDirectory),
|
|
62
|
+
owner,
|
|
63
|
+
state: 'starting',
|
|
64
|
+
building: false,
|
|
65
|
+
version,
|
|
66
|
+
startedAt: new Date().toISOString(),
|
|
67
|
+
};
|
|
68
|
+
if (!createRecord({ instancePath, record })) {
|
|
69
|
+
const holder = readDevInstance({ configDirectory });
|
|
70
|
+
if (holder !== null && holder.pid !== process.pid) {
|
|
71
|
+
return { acquired: false, holder, instancePath };
|
|
72
|
+
}
|
|
73
|
+
// Stale: the holder exited, or the file was copied from another checkout.
|
|
74
|
+
fs.rmSync(instancePath, { force: true });
|
|
75
|
+
if (!createRecord({ instancePath, record })) {
|
|
76
|
+
return { acquired: false, holder: readDevInstance({ configDirectory }) ?? {}, instancePath };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function update(fields) {
|
|
81
|
+
record = { ...record, ...fields };
|
|
82
|
+
writeRecord({ instancePath, record });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function release() {
|
|
86
|
+
try {
|
|
87
|
+
const current = JSON.parse(fs.readFileSync(instancePath, 'utf8'));
|
|
88
|
+
if (current.pid === process.pid) {
|
|
89
|
+
fs.rmSync(instancePath, { force: true });
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
// Already gone, or taken over after a crash - nothing to release.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { acquired: true, instancePath, release, update };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default acquireDevInstance;
|
|
@@ -0,0 +1,160 @@
|
|
|
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 'fs';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { spawnSync } from 'child_process';
|
|
21
|
+
|
|
22
|
+
import { getProcessStartTime, isProcessStartTime, readDevInstance } from '@lowdefy/node-utils';
|
|
23
|
+
|
|
24
|
+
import acquireDevInstance from './acquireDevInstance.mjs';
|
|
25
|
+
|
|
26
|
+
let configDirectory;
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
configDirectory = fs.realpathSync.native(fs.mkdtempSync(path.join(os.tmpdir(), 'dev-instance-')));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
fs.rmSync(configDirectory, { recursive: true, force: true });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function instancePath() {
|
|
37
|
+
return path.join(configDirectory, '.lowdefy', 'instance.json');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readRecord() {
|
|
41
|
+
return JSON.parse(fs.readFileSync(instancePath(), 'utf8'));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Windows has no owner-only file mode bits.
|
|
45
|
+
const onPosix = process.platform === 'win32' ? test.skip : test;
|
|
46
|
+
|
|
47
|
+
test('acquireDevInstance writes a starting record for this process', () => {
|
|
48
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
49
|
+
expect(instance.acquired).toBe(true);
|
|
50
|
+
expect(readRecord()).toMatchObject({
|
|
51
|
+
pid: process.pid,
|
|
52
|
+
configDirectory,
|
|
53
|
+
owner: 'terminal',
|
|
54
|
+
state: 'starting',
|
|
55
|
+
version: '6.0.0',
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
onPosix('acquireDevInstance writes the record readable only by the owner', () => {
|
|
60
|
+
acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
61
|
+
expect(fs.statSync(instancePath()).mode & 0o777).toBe(0o600);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('acquireDevInstance update merges fields into the record', () => {
|
|
65
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'hub', version: '6.0.0' });
|
|
66
|
+
instance.update({ port: 4100, internalPort: 4101 });
|
|
67
|
+
instance.update({ state: 'ready' });
|
|
68
|
+
expect(readRecord()).toMatchObject({
|
|
69
|
+
owner: 'hub',
|
|
70
|
+
port: 4100,
|
|
71
|
+
internalPort: 4101,
|
|
72
|
+
state: 'ready',
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('acquireDevInstance release removes the record', () => {
|
|
77
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
78
|
+
instance.release();
|
|
79
|
+
expect(fs.existsSync(instancePath())).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('acquireDevInstance refuses when a live process holds this app', () => {
|
|
83
|
+
// The parent process is alive for the whole test and is never this process,
|
|
84
|
+
// on every platform (Windows has no pid 1).
|
|
85
|
+
const livePid = process.ppid;
|
|
86
|
+
fs.mkdirSync(path.dirname(instancePath()), { recursive: true });
|
|
87
|
+
fs.writeFileSync(instancePath(), JSON.stringify({ pid: livePid, configDirectory, port: 3000 }));
|
|
88
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
89
|
+
expect(instance.acquired).toBe(false);
|
|
90
|
+
expect(instance.holder).toEqual({ pid: livePid, configDirectory, port: 3000 });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('acquireDevInstance takes over a record whose process has exited', () => {
|
|
94
|
+
const dead = spawnSync(process.execPath, ['-e', '']).pid;
|
|
95
|
+
fs.mkdirSync(path.dirname(instancePath()), { recursive: true });
|
|
96
|
+
fs.writeFileSync(instancePath(), JSON.stringify({ pid: dead, configDirectory }));
|
|
97
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
98
|
+
expect(instance.acquired).toBe(true);
|
|
99
|
+
expect(readRecord().pid).toBe(process.pid);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('acquireDevInstance takes over a record copied from another checkout', () => {
|
|
103
|
+
fs.mkdirSync(path.dirname(instancePath()), { recursive: true });
|
|
104
|
+
fs.writeFileSync(instancePath(), JSON.stringify({ pid: 1, configDirectory: '/other/checkout' }));
|
|
105
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
106
|
+
expect(instance.acquired).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('acquireDevInstance release leaves a record taken over by a newer manager', () => {
|
|
110
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
111
|
+
fs.writeFileSync(instancePath(), JSON.stringify({ pid: 1, configDirectory }));
|
|
112
|
+
instance.release();
|
|
113
|
+
expect(fs.existsSync(instancePath())).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// A start time in the form this platform reads, but not the one the pid's process has: on
|
|
117
|
+
// Linux, the same ticks in another boot.
|
|
118
|
+
function otherStartTime(pid) {
|
|
119
|
+
const startTime = getProcessStartTime({ pid });
|
|
120
|
+
if (typeof startTime === 'string') {
|
|
121
|
+
return startTime.replace(/^linux:[^:]+:/, 'linux:00000000-0000-0000-0000-000000000000:');
|
|
122
|
+
}
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
test('acquireDevInstance takes over a record left on a pid another process now has', () => {
|
|
127
|
+
// pid 1 is alive, but it is not the manager that wrote this record.
|
|
128
|
+
fs.mkdirSync(path.dirname(instancePath()), { recursive: true });
|
|
129
|
+
fs.writeFileSync(
|
|
130
|
+
instancePath(),
|
|
131
|
+
JSON.stringify({ pid: 1, processStartTime: otherStartTime(1), configDirectory })
|
|
132
|
+
);
|
|
133
|
+
const instance = acquireDevInstance({ configDirectory, owner: 'terminal', version: '6.0.0' });
|
|
134
|
+
expect(instance.acquired).toBe(true);
|
|
135
|
+
expect(isProcessStartTime(readRecord().processStartTime)).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Case variants name one directory only where the file system ignores case.
|
|
139
|
+
const tmpReal = fs.realpathSync.native(os.tmpdir());
|
|
140
|
+
const onCaseInsensitiveFs =
|
|
141
|
+
tmpReal !== tmpReal.toUpperCase() && fs.existsSync(tmpReal.toUpperCase()) ? test : test.skip;
|
|
142
|
+
|
|
143
|
+
onCaseInsensitiveFs(
|
|
144
|
+
'acquireDevInstance records the path as stored on disk when started from a case variant of it',
|
|
145
|
+
() => {
|
|
146
|
+
const variant = configDirectory.toUpperCase();
|
|
147
|
+
const instance = acquireDevInstance({
|
|
148
|
+
configDirectory: variant,
|
|
149
|
+
owner: 'terminal',
|
|
150
|
+
version: '6.0.0',
|
|
151
|
+
});
|
|
152
|
+
try {
|
|
153
|
+
expect(readRecord().configDirectory).toEqual(configDirectory);
|
|
154
|
+
expect(readDevInstance({ configDirectory })).toMatchObject({ pid: process.pid });
|
|
155
|
+
expect(readDevInstance({ configDirectory: variant })).toMatchObject({ pid: process.pid });
|
|
156
|
+
} finally {
|
|
157
|
+
instance.release();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
);
|