@lowdefy/server-dev 6.1.0 → 7.0.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 +67 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +679 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -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/findCollectionCollisions.js +52 -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 +44 -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 +119 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +343 -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 +68 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +220 -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/sweepOrphanDatabases.js +33 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +203 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +8 -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 +54 -6
- package/lib/docs/getBuildStatus.test.mjs +133 -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 +83 -0
- package/lib/server/applyDataSetRedirect.test.mjs +340 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +204 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +131 -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 +328 -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 +112 -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 +24 -2
- package/manager/processes/initialBuild.mjs +14 -0
- package/manager/processes/initialBuild.test.mjs +101 -0
- package/manager/processes/lowdefyBuild.mjs +30 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +62 -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
|
@@ -14,24 +14,72 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import getLowdefyVersion from '../../manager/utils/getLowdefyVersion.mjs';
|
|
18
|
+
import checkAgentFiles from './checkAgentFiles.js';
|
|
17
19
|
import clientErrorStore from './clientErrorStore.js';
|
|
20
|
+
import getBuildId from './getBuildId.js';
|
|
21
|
+
import getPageBuildStatus from './getPageBuildStatus.js';
|
|
22
|
+
import serverErrorStore from './serverErrorStore.js';
|
|
18
23
|
import readBuildArtifact from './readBuildArtifact.js';
|
|
19
24
|
|
|
25
|
+
const EARLIER_ERRORS_NOTE =
|
|
26
|
+
'Reported under an earlier build, before the latest config build or page edit, so they may already be fixed. Reload or re-run the page to see whether they still happen.';
|
|
27
|
+
|
|
28
|
+
function splitByBuild({ entries, buildId }) {
|
|
29
|
+
return {
|
|
30
|
+
current: entries.filter((entry) => entry.buildId === buildId),
|
|
31
|
+
earlier: entries.filter((entry) => entry.buildId !== buildId),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Notices about Lowdefy's agent block (see checkAgentFiles), checked on every
|
|
36
|
+
// read: the root files are not watched, so a stored result would outlive a fix.
|
|
37
|
+
async function getAgentFiles() {
|
|
38
|
+
const configDirectory = process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd();
|
|
39
|
+
const lowdefyVersion = await getLowdefyVersion({
|
|
40
|
+
directories: { config: configDirectory },
|
|
41
|
+
}).catch(() => null);
|
|
42
|
+
return checkAgentFiles({ configDirectory, lowdefyVersion });
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
// Feedback loop for agents: build status (written by the build manager to
|
|
21
|
-
// build/buildStatus.json)
|
|
22
|
-
// POST /api/client-error
|
|
23
|
-
//
|
|
24
|
-
|
|
46
|
+
// build/buildStatus.json), the page builds (see getPageBuildStatus), plus
|
|
47
|
+
// recent browser errors reported via POST /api/client-error, plus recent server
|
|
48
|
+
// errors (request, endpoint, MCP and agent tool failures) collected by
|
|
49
|
+
// createHandleError. Lets an agent check "did my last edit work?" without
|
|
50
|
+
// tailing terminal logs. Errors reported under an earlier build are listed
|
|
51
|
+
// apart under earlierErrors. `buildId` names the build being served now.
|
|
52
|
+
// Notices about the agent files come under agentFiles, apart from the build's
|
|
53
|
+
// warnings, and only when there are any.
|
|
54
|
+
async function getBuildStatus({ checked } = {}) {
|
|
25
55
|
const build = readBuildArtifact({ name: 'buildStatus.json' }) ?? {
|
|
26
56
|
status: 'unknown',
|
|
27
57
|
message:
|
|
28
58
|
'No build status yet — the build manager has not written build/buildStatus.json. ' +
|
|
29
59
|
'This is expected before the first build completes.',
|
|
30
60
|
};
|
|
31
|
-
|
|
61
|
+
const buildId = getBuildId();
|
|
62
|
+
const clientErrors = splitByBuild({ entries: clientErrorStore.list(), buildId });
|
|
63
|
+
const serverErrors = splitByBuild({ entries: serverErrorStore.list(), buildId });
|
|
64
|
+
const status = {
|
|
65
|
+
buildId,
|
|
32
66
|
build,
|
|
33
|
-
|
|
67
|
+
pages: await getPageBuildStatus({ checked }),
|
|
68
|
+
clientErrors: clientErrors.current,
|
|
69
|
+
serverErrors: serverErrors.current,
|
|
34
70
|
};
|
|
71
|
+
if (clientErrors.earlier.length > 0 || serverErrors.earlier.length > 0) {
|
|
72
|
+
status.earlierErrors = {
|
|
73
|
+
note: EARLIER_ERRORS_NOTE,
|
|
74
|
+
clientErrors: clientErrors.earlier,
|
|
75
|
+
serverErrors: serverErrors.earlier,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const agentFiles = await getAgentFiles();
|
|
79
|
+
if (agentFiles.length > 0) {
|
|
80
|
+
status.agentFiles = agentFiles;
|
|
81
|
+
}
|
|
82
|
+
return status;
|
|
35
83
|
}
|
|
36
84
|
|
|
37
85
|
export default getBuildStatus;
|
|
@@ -0,0 +1,133 @@
|
|
|
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 { jest } from '@jest/globals';
|
|
21
|
+
|
|
22
|
+
const mockClientErrors = jest.fn();
|
|
23
|
+
jest.unstable_mockModule('./clientErrorStore.js', () => ({ default: { list: mockClientErrors } }));
|
|
24
|
+
const mockServerErrors = jest.fn();
|
|
25
|
+
jest.unstable_mockModule('./serverErrorStore.js', () => ({ default: { list: mockServerErrors } }));
|
|
26
|
+
jest.unstable_mockModule('./getBuildId.js', () => ({ default: () => 'build-2' }));
|
|
27
|
+
const mockGetPageBuildStatus = jest.fn(() => ({ unbuilt: 0 }));
|
|
28
|
+
jest.unstable_mockModule('./getPageBuildStatus.js', () => ({ default: mockGetPageBuildStatus }));
|
|
29
|
+
jest.unstable_mockModule('./readBuildArtifact.js', () => ({
|
|
30
|
+
default: () => ({ status: 'ok', errors: [], warnings: ['a build warning'] }),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
const { default: getBuildStatus } = await import('./getBuildStatus.js');
|
|
34
|
+
|
|
35
|
+
test('getBuildStatus lists errors from earlier builds apart from the current ones', async () => {
|
|
36
|
+
mockClientErrors.mockReturnValue([
|
|
37
|
+
{ message: 'old render error', buildId: 'build-1' },
|
|
38
|
+
{ message: 'live render error', buildId: 'build-2' },
|
|
39
|
+
]);
|
|
40
|
+
mockServerErrors.mockReturnValue([{ message: 'old request error', buildId: 'build-1' }]);
|
|
41
|
+
|
|
42
|
+
const status = await getBuildStatus();
|
|
43
|
+
|
|
44
|
+
expect(status.clientErrors).toEqual([{ message: 'live render error', buildId: 'build-2' }]);
|
|
45
|
+
expect(status.serverErrors).toEqual([]);
|
|
46
|
+
expect(status.earlierErrors).toEqual({
|
|
47
|
+
note: expect.stringContaining('may already be fixed'),
|
|
48
|
+
clientErrors: [{ message: 'old render error', buildId: 'build-1' }],
|
|
49
|
+
serverErrors: [{ message: 'old request error', buildId: 'build-1' }],
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('getBuildStatus leaves out earlierErrors when every error is current', async () => {
|
|
54
|
+
mockClientErrors.mockReturnValue([{ message: 'live', buildId: 'build-2' }]);
|
|
55
|
+
mockServerErrors.mockReturnValue([]);
|
|
56
|
+
|
|
57
|
+
expect((await getBuildStatus()).earlierErrors).toBeUndefined();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('getBuildStatus passes the pages build status just built to the page status', async () => {
|
|
61
|
+
mockClientErrors.mockReturnValue([]);
|
|
62
|
+
mockServerErrors.mockReturnValue([]);
|
|
63
|
+
|
|
64
|
+
const status = await getBuildStatus({ checked: ['home'] });
|
|
65
|
+
|
|
66
|
+
expect(mockGetPageBuildStatus).toHaveBeenCalledWith({ checked: ['home'] });
|
|
67
|
+
expect(status.pages).toEqual({ unbuilt: 0 });
|
|
68
|
+
expect(status.build.status).toBe('ok');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('getBuildStatus names the build being served as a top-level buildId', async () => {
|
|
72
|
+
mockClientErrors.mockReturnValue([]);
|
|
73
|
+
mockServerErrors.mockReturnValue([]);
|
|
74
|
+
|
|
75
|
+
expect((await getBuildStatus()).buildId).toBe('build-2');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('agentFiles', () => {
|
|
79
|
+
let root;
|
|
80
|
+
let previousConfigDirectory;
|
|
81
|
+
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
mockClientErrors.mockReturnValue([]);
|
|
84
|
+
mockServerErrors.mockReturnValue([]);
|
|
85
|
+
root = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-build-status-'));
|
|
86
|
+
fs.mkdirSync(path.join(root, '.git'));
|
|
87
|
+
fs.writeFileSync(path.join(root, 'lowdefy.yaml'), 'lowdefy: 7.1.0\n');
|
|
88
|
+
fs.writeFileSync(path.join(root, 'CLAUDE.md'), '@AGENTS.md\n');
|
|
89
|
+
previousConfigDirectory = process.env.LOWDEFY_DIRECTORY_CONFIG;
|
|
90
|
+
process.env.LOWDEFY_DIRECTORY_CONFIG = root;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
afterEach(() => {
|
|
94
|
+
if (previousConfigDirectory === undefined) {
|
|
95
|
+
delete process.env.LOWDEFY_DIRECTORY_CONFIG;
|
|
96
|
+
} else {
|
|
97
|
+
process.env.LOWDEFY_DIRECTORY_CONFIG = previousConfigDirectory;
|
|
98
|
+
}
|
|
99
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const writeBlock = (version) =>
|
|
103
|
+
fs.writeFileSync(
|
|
104
|
+
path.join(root, 'AGENTS.md'),
|
|
105
|
+
`<!-- BEGIN:lowdefy-agent-rules version=${version} -->\n<!-- END:lowdefy-agent-rules -->\n`
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
test('lists notices apart from the build warnings, and a fix shows on the next call', async () => {
|
|
109
|
+
writeBlock('7.0.0');
|
|
110
|
+
|
|
111
|
+
const before = await getBuildStatus();
|
|
112
|
+
expect(before.agentFiles).toEqual([
|
|
113
|
+
{
|
|
114
|
+
code: 'version_mismatch',
|
|
115
|
+
message: expect.stringContaining('npx lowdefy@7.1.0 agent-setup'),
|
|
116
|
+
},
|
|
117
|
+
]);
|
|
118
|
+
expect(before.build.warnings).toEqual(['a build warning']);
|
|
119
|
+
|
|
120
|
+
writeBlock('7.1.2');
|
|
121
|
+
|
|
122
|
+
const after = await getBuildStatus();
|
|
123
|
+
expect(after).not.toHaveProperty('agentFiles');
|
|
124
|
+
expect(after.build.warnings).toEqual(['a build warning']);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('leaves agentFiles out when lowdefy.yaml cannot be read', async () => {
|
|
128
|
+
writeBlock('6.0.0');
|
|
129
|
+
fs.rmSync(path.join(root, 'lowdefy.yaml'));
|
|
130
|
+
|
|
131
|
+
expect(await getBuildStatus()).not.toHaveProperty('agentFiles');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import buildEditedPages from './buildEditedPages.js';
|
|
18
|
+
import getBuildStatus from './getBuildStatus.js';
|
|
19
|
+
import waitForBuild from './waitForBuild.js';
|
|
20
|
+
|
|
21
|
+
// Build status for wait: true. Waits until the dev server has processed the
|
|
22
|
+
// latest edits, then builds the pages they touched, so the answer covers
|
|
23
|
+
// those pages whether or not anything has requested them since. A request
|
|
24
|
+
// through the manager's proxy has been held there until the edits - and any
|
|
25
|
+
// restart they caused - were processed (proxyWait), so it does not wait again.
|
|
26
|
+
async function getBuildStatusAfterEdits({ proxyWait } = {}) {
|
|
27
|
+
const waited = proxyWait ?? (await waitForBuild());
|
|
28
|
+
if (!waited.settled) {
|
|
29
|
+
return { ...waited, ...(await getBuildStatus()) };
|
|
30
|
+
}
|
|
31
|
+
const checked = await buildEditedPages();
|
|
32
|
+
return { ...waited, ...(await getBuildStatus({ checked })) };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default getBuildStatusAfterEdits;
|
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
|
|
19
|
+
const mockWaitForBuild = jest.fn();
|
|
20
|
+
jest.unstable_mockModule('./waitForBuild.js', () => ({ default: mockWaitForBuild }));
|
|
21
|
+
const mockBuildEditedPages = jest.fn();
|
|
22
|
+
jest.unstable_mockModule('./buildEditedPages.js', () => ({ default: mockBuildEditedPages }));
|
|
23
|
+
const mockGetBuildStatus = jest.fn(({ checked } = {}) => ({ build: { status: 'ok' }, checked }));
|
|
24
|
+
jest.unstable_mockModule('./getBuildStatus.js', () => ({ default: mockGetBuildStatus }));
|
|
25
|
+
|
|
26
|
+
const { default: getBuildStatusAfterEdits } = await import('./getBuildStatusAfterEdits.js');
|
|
27
|
+
const { default: readProxyBuildWait } = await import('./readProxyBuildWait.js');
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
jest.clearAllMocks();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('getBuildStatusAfterEdits builds the edited pages once the edits are processed', async () => {
|
|
34
|
+
mockWaitForBuild.mockResolvedValue({ settled: true, sawBuild: false, waitedMs: 1000 });
|
|
35
|
+
mockBuildEditedPages.mockResolvedValue(['home']);
|
|
36
|
+
|
|
37
|
+
const result = await getBuildStatusAfterEdits();
|
|
38
|
+
|
|
39
|
+
expect(mockWaitForBuild.mock.invocationCallOrder[0]).toBeLessThan(
|
|
40
|
+
mockBuildEditedPages.mock.invocationCallOrder[0]
|
|
41
|
+
);
|
|
42
|
+
expect(result).toEqual({
|
|
43
|
+
settled: true,
|
|
44
|
+
sawBuild: false,
|
|
45
|
+
waitedMs: 1000,
|
|
46
|
+
build: { status: 'ok' },
|
|
47
|
+
checked: ['home'],
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('getBuildStatusAfterEdits builds no pages when the wait gave up', async () => {
|
|
52
|
+
mockWaitForBuild.mockResolvedValue({ settled: false, waitedMs: 60000 });
|
|
53
|
+
|
|
54
|
+
const result = await getBuildStatusAfterEdits();
|
|
55
|
+
|
|
56
|
+
expect(mockBuildEditedPages).not.toHaveBeenCalled();
|
|
57
|
+
expect(result.settled).toBe(false);
|
|
58
|
+
expect(result.checked).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('getBuildStatusAfterEdits uses the wait the manager proxy made instead of waiting again', async () => {
|
|
62
|
+
mockBuildEditedPages.mockResolvedValue([]);
|
|
63
|
+
|
|
64
|
+
const result = await getBuildStatusAfterEdits({
|
|
65
|
+
proxyWait: readProxyBuildWait({
|
|
66
|
+
getHeader: () => 'settled=true&sawBuild=true&waitedMs=4200',
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(mockWaitForBuild).not.toHaveBeenCalled();
|
|
71
|
+
expect(result).toMatchObject({ settled: true, sawBuild: true, waitedMs: 4200, checked: [] });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('readProxyBuildWait returns null for a request that did not come through the proxy wait', () => {
|
|
75
|
+
expect(readProxyBuildWait({ getHeader: () => undefined })).toBe(null);
|
|
76
|
+
});
|
package/lib/docs/getCoreDoc.js
CHANGED
|
@@ -19,6 +19,7 @@ import path from 'node:path';
|
|
|
19
19
|
import { type } from '@lowdefy/helpers';
|
|
20
20
|
|
|
21
21
|
import getDocsManifest from './getDocsManifest.js';
|
|
22
|
+
import getHazards from './getHazards.js';
|
|
22
23
|
|
|
23
24
|
function findDoc({ manifest, slug, kind, typeName }) {
|
|
24
25
|
if (!type.isNone(slug)) {
|
|
@@ -57,7 +58,14 @@ function getCoreDoc({ slug, kind, type: typeName }) {
|
|
|
57
58
|
return null;
|
|
58
59
|
}
|
|
59
60
|
const markdown = fs.readFileSync(path.join(manifest.contentDir, doc.path), 'utf8');
|
|
60
|
-
|
|
61
|
+
const result = { slug: doc.slug, title: doc.title, section: doc.section, markdown };
|
|
62
|
+
// Hazards belong to the type the caller asked about, not to the doc page:
|
|
63
|
+
// findDoc remaps requests onto their connection's page, and a request
|
|
64
|
+
// must carry its own hazards rather than inherit the connection's.
|
|
65
|
+
if (type.isNone(slug) && !type.isNone(typeName)) {
|
|
66
|
+
result.hazards = getHazards({ kind, type: typeName });
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
export default getCoreDoc;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
import getCoreDoc from './getCoreDoc.js';
|
|
20
|
+
import getDocsIndex from './getDocsIndex.js';
|
|
21
|
+
import readDocEntry from './readDocEntry.js';
|
|
22
|
+
|
|
23
|
+
function singularKind({ kind }) {
|
|
24
|
+
return type.isNone(kind) ? null : String(kind).toLowerCase().replace(/s$/, '');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findTypeSlug({ typeDocs, kind, typeName, anyKind }) {
|
|
28
|
+
const exactKind = singularKind({ kind });
|
|
29
|
+
if (!type.isNone(exactKind) && typeDocs.has(`${exactKind}:${typeName}`)) {
|
|
30
|
+
return typeDocs.get(`${exactKind}:${typeName}`);
|
|
31
|
+
}
|
|
32
|
+
if (!type.isNone(exactKind) && !anyKind) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
for (const [key, slug] of typeDocs) {
|
|
36
|
+
if (key.slice(key.indexOf(':') + 1) === typeName) {
|
|
37
|
+
return slug;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// With no kind, a core page for exactly this type name belongs to a Lowdefy
|
|
44
|
+
// type, unless a plugin registers the name in that same kind and so replaces
|
|
45
|
+
// it. A plugin type of another kind must not take that page's place.
|
|
46
|
+
function namesOtherCoreType({ entries, typeDocs, kind, typeName }) {
|
|
47
|
+
if (!type.isNone(kind)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return entries.some(
|
|
51
|
+
(entry) =>
|
|
52
|
+
entry.source === 'core' &&
|
|
53
|
+
entry.typeName === typeName &&
|
|
54
|
+
!typeDocs.has(`${entry.kind}:${typeName}`)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function makePluginDoc({ entries, slug }) {
|
|
59
|
+
const entry = entries.find((item) => item.source !== 'core' && item.slug === slug);
|
|
60
|
+
if (type.isUndefined(entry)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
slug: entry.slug,
|
|
65
|
+
title: entry.title,
|
|
66
|
+
section: entry.section,
|
|
67
|
+
source: entry.source,
|
|
68
|
+
package: entry.package,
|
|
69
|
+
version: entry.version,
|
|
70
|
+
markdown: readDocEntry({ entry }),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// A doc page by slug or by type: the core docs, and the docs the app's own
|
|
75
|
+
// plugins and modules ship. A type a plugin registers is looked up in its
|
|
76
|
+
// plugin's docs before the core docs, whose type lookup falls back to a
|
|
77
|
+
// prefix match (MongoDB covers MongoDBFind) that would claim a plugin type
|
|
78
|
+
// named like a core one. Plugin types the caller names under another kind
|
|
79
|
+
// (the kinds get_doc takes do not cover every kind) come last.
|
|
80
|
+
function getDoc({ slug, kind, type: typeName }) {
|
|
81
|
+
const { entries, typeDocs } = getDocsIndex();
|
|
82
|
+
if (!type.isNone(slug)) {
|
|
83
|
+
return getCoreDoc({ slug }) ?? makePluginDoc({ entries, slug });
|
|
84
|
+
}
|
|
85
|
+
if (type.isNone(typeName)) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const pluginSlug = findTypeSlug({ typeDocs, kind, typeName, anyKind: false });
|
|
89
|
+
if (!type.isNone(pluginSlug) && !namesOtherCoreType({ entries, typeDocs, kind, typeName })) {
|
|
90
|
+
return makePluginDoc({ entries, slug: pluginSlug });
|
|
91
|
+
}
|
|
92
|
+
const coreDoc = getCoreDoc({ kind, type: typeName });
|
|
93
|
+
if (!type.isNone(coreDoc)) {
|
|
94
|
+
return coreDoc;
|
|
95
|
+
}
|
|
96
|
+
const otherKindSlug = findTypeSlug({ typeDocs, kind, typeName, anyKind: true });
|
|
97
|
+
return type.isNone(otherKindSlug) ? null : makePluginDoc({ entries, slug: otherKindSlug });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default getDoc;
|
|
@@ -0,0 +1,152 @@
|
|
|
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 { type } from '@lowdefy/helpers';
|
|
20
|
+
|
|
21
|
+
import getDocsManifest from './getDocsManifest.js';
|
|
22
|
+
import listModuleDocEntries from './listModuleDocEntries.js';
|
|
23
|
+
import listPackageDocFiles from './listPackageDocFiles.js';
|
|
24
|
+
import listPluginDocEntries from './listPluginDocEntries.js';
|
|
25
|
+
import readBuildArtifact from './readBuildArtifact.js';
|
|
26
|
+
|
|
27
|
+
// The build artifacts that change when the app's plugins change. The dev
|
|
28
|
+
// build leaves an artifact whose bytes are unchanged with its old mtime, so a
|
|
29
|
+
// config-only edit leaves their stats alone.
|
|
30
|
+
const PLUGIN_ARTIFACTS = [
|
|
31
|
+
'plugins/availableTypes.json',
|
|
32
|
+
'customTypesMap.json',
|
|
33
|
+
'installedPluginPackages.json',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
let coreEntries;
|
|
37
|
+
let index = null;
|
|
38
|
+
let indexKey = null;
|
|
39
|
+
let localDirs = [];
|
|
40
|
+
let modulesStat = null;
|
|
41
|
+
let modules = null;
|
|
42
|
+
let modulesKey = null;
|
|
43
|
+
|
|
44
|
+
// The core docs change only with a release, so their entries are read once.
|
|
45
|
+
function getCoreEntries() {
|
|
46
|
+
if (!type.isUndefined(coreEntries)) {
|
|
47
|
+
return coreEntries;
|
|
48
|
+
}
|
|
49
|
+
const manifest = getDocsManifest();
|
|
50
|
+
if (type.isNone(manifest)) {
|
|
51
|
+
coreEntries = [];
|
|
52
|
+
return coreEntries;
|
|
53
|
+
}
|
|
54
|
+
coreEntries = manifest.docs.map((doc) => ({
|
|
55
|
+
...doc,
|
|
56
|
+
source: 'core',
|
|
57
|
+
package: '@lowdefy/docs-content',
|
|
58
|
+
version: manifest.version,
|
|
59
|
+
filePath: path.join(manifest.contentDir, doc.path),
|
|
60
|
+
}));
|
|
61
|
+
return coreEntries;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function statKey(filePath) {
|
|
65
|
+
try {
|
|
66
|
+
const stat = fs.statSync(filePath);
|
|
67
|
+
return `${stat.mtimeMs}:${stat.size}`;
|
|
68
|
+
} catch {
|
|
69
|
+
return 'none';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Component bodies are left out: only the ids and descriptions are shown.
|
|
74
|
+
function componentsKey({ components }) {
|
|
75
|
+
if (!type.isArray(components)) {
|
|
76
|
+
return components;
|
|
77
|
+
}
|
|
78
|
+
return components.map((item) => (type.isObject(item) ? [item.id, item.description] : item));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// modules.json also holds what a config edit changes (resolved var values,
|
|
82
|
+
// page bodies), so only the parts the docs read are compared.
|
|
83
|
+
function readModules() {
|
|
84
|
+
const stat = statKey(path.join(process.cwd(), 'build', 'modules.json'));
|
|
85
|
+
if (stat === modulesStat) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
modulesStat = stat;
|
|
89
|
+
modules = readBuildArtifact({ name: 'modules.json', deserialize: true }) ?? {};
|
|
90
|
+
modulesKey = JSON.stringify(
|
|
91
|
+
Object.values(modules).map((moduleEntry) => [
|
|
92
|
+
moduleEntry.id,
|
|
93
|
+
moduleEntry.source,
|
|
94
|
+
moduleEntry.moduleRoot,
|
|
95
|
+
moduleEntry.isLocal,
|
|
96
|
+
moduleEntry.varDefs,
|
|
97
|
+
moduleEntry.manifest?.name,
|
|
98
|
+
moduleEntry.manifest?.description,
|
|
99
|
+
moduleEntry.manifest?.exports,
|
|
100
|
+
componentsKey({ components: moduleEntry.manifest?.components }),
|
|
101
|
+
])
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Doc files of local plugins and modules can be added, removed or edited
|
|
106
|
+
// while the server runs.
|
|
107
|
+
function localDocsKey() {
|
|
108
|
+
return localDirs
|
|
109
|
+
.map((dir) => {
|
|
110
|
+
const { readme, docs } = listPackageDocFiles({ dir });
|
|
111
|
+
return [readme, ...docs]
|
|
112
|
+
.filter((filePath) => !type.isNone(filePath))
|
|
113
|
+
.map((filePath) => `${filePath}@${statKey(filePath)}`);
|
|
114
|
+
})
|
|
115
|
+
.join('|');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function createIndexKey() {
|
|
119
|
+
readModules();
|
|
120
|
+
const buildDirectory = path.join(process.cwd(), 'build');
|
|
121
|
+
return [
|
|
122
|
+
...PLUGIN_ARTIFACTS.map((name) => statKey(path.join(buildDirectory, name))),
|
|
123
|
+
modulesKey,
|
|
124
|
+
localDocsKey(),
|
|
125
|
+
].join('\n');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function buildIndex() {
|
|
129
|
+
const plugins = listPluginDocEntries();
|
|
130
|
+
const moduleDocs = listModuleDocEntries({ modules });
|
|
131
|
+
localDirs = [...plugins.localDirs, ...moduleDocs.localDirs];
|
|
132
|
+
return {
|
|
133
|
+
entries: [...getCoreEntries(), ...plugins.entries, ...moduleDocs.entries],
|
|
134
|
+
typeDocs: plugins.typeDocs,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Every doc the app can use: the core docs, and the docs its own plugins and
|
|
139
|
+
// modules ship. Rebuilt on the first call after the plugins or modules change.
|
|
140
|
+
// The key of a rebuilt index names the local doc files the build found, so it
|
|
141
|
+
// is taken again after the build.
|
|
142
|
+
function getDocsIndex() {
|
|
143
|
+
const key = createIndexKey();
|
|
144
|
+
if (key === indexKey) {
|
|
145
|
+
return index;
|
|
146
|
+
}
|
|
147
|
+
index = buildIndex();
|
|
148
|
+
indexKey = createIndexKey();
|
|
149
|
+
return index;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export default getDocsIndex;
|