@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
|
@@ -14,24 +14,98 @@
|
|
|
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
|
+
// buildStatus.json covers the config build only; pages build later, on first
|
|
36
|
+
// request. So that build.status alone answers "does the app build", an ok
|
|
37
|
+
// config build with a failed page reads pages_failed, and failedPages names
|
|
38
|
+
// those pages. A failed page changed since that build is left out: its failure
|
|
39
|
+
// may already be fixed, and pages.changedSinceBuild lists it until it is
|
|
40
|
+
// rebuilt. A config build that is not ok keeps its status and names no pages,
|
|
41
|
+
// since the config is what to fix first. The page errors stay under
|
|
42
|
+
// pages.failed either way. configStatus keeps the config build's own status for
|
|
43
|
+
// callers that wait on a published config build, whatever the pages do.
|
|
44
|
+
function withFailedPages({ build, pages }) {
|
|
45
|
+
const configBuild = { ...build, configStatus: build.status };
|
|
46
|
+
if (build.status !== 'ok') {
|
|
47
|
+
return configBuild;
|
|
48
|
+
}
|
|
49
|
+
const changedSinceBuild = new Set(pages.changedSinceBuild ?? []);
|
|
50
|
+
const failedPages = (pages.failed ?? [])
|
|
51
|
+
.map(({ pageId }) => pageId)
|
|
52
|
+
.filter((pageId) => !changedSinceBuild.has(pageId));
|
|
53
|
+
if (failedPages.length === 0) {
|
|
54
|
+
return configBuild;
|
|
55
|
+
}
|
|
56
|
+
return { ...configBuild, status: 'pages_failed', failedPages };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Notices about Lowdefy's agent block (see checkAgentFiles), checked on every
|
|
60
|
+
// read: the root files are not watched, so a stored result would outlive a fix.
|
|
61
|
+
async function getAgentFiles() {
|
|
62
|
+
const configDirectory = process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd();
|
|
63
|
+
const lowdefyVersion = await getLowdefyVersion({
|
|
64
|
+
directories: { config: configDirectory },
|
|
65
|
+
}).catch(() => null);
|
|
66
|
+
return checkAgentFiles({ configDirectory, lowdefyVersion });
|
|
67
|
+
}
|
|
68
|
+
|
|
20
69
|
// Feedback loop for agents: build status (written by the build manager to
|
|
21
|
-
// build/buildStatus.json
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
70
|
+
// build/buildStatus.json, with page failures folded in by withFailedPages),
|
|
71
|
+
// the page builds (see getPageBuildStatus), plus
|
|
72
|
+
// recent browser errors reported via POST /api/client-error, plus recent server
|
|
73
|
+
// errors (request, endpoint, MCP and agent tool failures) collected by
|
|
74
|
+
// createHandleError. Lets an agent check "did my last edit work?" without
|
|
75
|
+
// tailing terminal logs. Errors reported under an earlier build are listed
|
|
76
|
+
// apart under earlierErrors. `buildId` names the build being served now.
|
|
77
|
+
// Notices about the agent files come under agentFiles, apart from the build's
|
|
78
|
+
// warnings, and only when there are any.
|
|
79
|
+
async function getBuildStatus({ checked } = {}) {
|
|
25
80
|
const build = readBuildArtifact({ name: 'buildStatus.json' }) ?? {
|
|
26
81
|
status: 'unknown',
|
|
27
82
|
message:
|
|
28
83
|
'No build status yet — the build manager has not written build/buildStatus.json. ' +
|
|
29
84
|
'This is expected before the first build completes.',
|
|
30
85
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
86
|
+
const buildId = getBuildId();
|
|
87
|
+
const clientErrors = splitByBuild({ entries: clientErrorStore.list(), buildId });
|
|
88
|
+
const serverErrors = splitByBuild({ entries: serverErrorStore.list(), buildId });
|
|
89
|
+
const pages = await getPageBuildStatus({ checked });
|
|
90
|
+
const status = {
|
|
91
|
+
buildId,
|
|
92
|
+
build: withFailedPages({ build, pages }),
|
|
93
|
+
pages,
|
|
94
|
+
clientErrors: clientErrors.current,
|
|
95
|
+
serverErrors: serverErrors.current,
|
|
34
96
|
};
|
|
97
|
+
if (clientErrors.earlier.length > 0 || serverErrors.earlier.length > 0) {
|
|
98
|
+
status.earlierErrors = {
|
|
99
|
+
note: EARLIER_ERRORS_NOTE,
|
|
100
|
+
clientErrors: clientErrors.earlier,
|
|
101
|
+
serverErrors: serverErrors.earlier,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const agentFiles = await getAgentFiles();
|
|
105
|
+
if (agentFiles.length > 0) {
|
|
106
|
+
status.agentFiles = agentFiles;
|
|
107
|
+
}
|
|
108
|
+
return status;
|
|
35
109
|
}
|
|
36
110
|
|
|
37
111
|
export default getBuildStatus;
|
|
@@ -0,0 +1,229 @@
|
|
|
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
|
+
const okBuild = () => ({ status: 'ok', errors: [], warnings: ['a build warning'] });
|
|
30
|
+
const mockReadBuildArtifact = jest.fn(okBuild);
|
|
31
|
+
jest.unstable_mockModule('./readBuildArtifact.js', () => ({ default: mockReadBuildArtifact }));
|
|
32
|
+
|
|
33
|
+
const { default: getBuildStatus } = await import('./getBuildStatus.js');
|
|
34
|
+
|
|
35
|
+
describe('page failures in build.status', () => {
|
|
36
|
+
const failed = [
|
|
37
|
+
{ pageId: 'orders', errors: [{ type: 'ConfigError', message: 'Bad.', source: null }] },
|
|
38
|
+
{ pageId: 'invoices', errors: [{ type: 'ConfigError', message: 'Worse.', source: null }] },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
mockClientErrors.mockReturnValue([]);
|
|
43
|
+
mockServerErrors.mockReturnValue([]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
mockReadBuildArtifact.mockImplementation(okBuild);
|
|
48
|
+
mockGetPageBuildStatus.mockImplementation(() => ({ unbuilt: 0 }));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('reads pages_failed and names the pages when the config builds but a page fails', async () => {
|
|
52
|
+
mockGetPageBuildStatus.mockResolvedValue({ failed, unbuilt: 0 });
|
|
53
|
+
|
|
54
|
+
const status = await getBuildStatus();
|
|
55
|
+
|
|
56
|
+
expect(status.build).toEqual({
|
|
57
|
+
status: 'pages_failed',
|
|
58
|
+
configStatus: 'ok',
|
|
59
|
+
errors: [],
|
|
60
|
+
warnings: ['a build warning'],
|
|
61
|
+
failedPages: ['orders', 'invoices'],
|
|
62
|
+
});
|
|
63
|
+
expect(status.pages.failed).toEqual(failed);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('keeps error and names no pages when the config build failed too', async () => {
|
|
67
|
+
mockReadBuildArtifact.mockReturnValue({
|
|
68
|
+
status: 'error',
|
|
69
|
+
errors: ['Bad config.'],
|
|
70
|
+
warnings: [],
|
|
71
|
+
});
|
|
72
|
+
mockGetPageBuildStatus.mockResolvedValue({ failed: failed.slice(0, 1), unbuilt: 0 });
|
|
73
|
+
|
|
74
|
+
const status = await getBuildStatus();
|
|
75
|
+
|
|
76
|
+
expect(status.build.status).toBe('error');
|
|
77
|
+
expect(status.build.configStatus).toBe('error');
|
|
78
|
+
expect(status.build).not.toHaveProperty('failedPages');
|
|
79
|
+
expect(status.pages.failed).toEqual(failed.slice(0, 1));
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('keeps unknown and names no pages before the first config build is written', async () => {
|
|
83
|
+
mockReadBuildArtifact.mockReturnValue(null);
|
|
84
|
+
mockGetPageBuildStatus.mockResolvedValue({ failed, unbuilt: 0 });
|
|
85
|
+
|
|
86
|
+
const { build } = await getBuildStatus();
|
|
87
|
+
|
|
88
|
+
expect(build.status).toBe('unknown');
|
|
89
|
+
expect(build.configStatus).toBe('unknown');
|
|
90
|
+
expect(build).not.toHaveProperty('failedPages');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('leaves out a failed page changed since its last build, since its failure may be fixed', async () => {
|
|
94
|
+
mockGetPageBuildStatus.mockResolvedValue({
|
|
95
|
+
failed,
|
|
96
|
+
changedSinceBuild: ['orders'],
|
|
97
|
+
unbuilt: 0,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const { build } = await getBuildStatus();
|
|
101
|
+
|
|
102
|
+
expect(build.status).toBe('pages_failed');
|
|
103
|
+
expect(build.failedPages).toEqual(['invoices']);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('stays ok when every failed page has changed since its last build', async () => {
|
|
107
|
+
mockGetPageBuildStatus.mockResolvedValue({
|
|
108
|
+
failed: failed.slice(0, 1),
|
|
109
|
+
changedSinceBuild: ['orders', 'home'],
|
|
110
|
+
unbuilt: 0,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const status = await getBuildStatus();
|
|
114
|
+
|
|
115
|
+
expect(status.build.status).toBe('ok');
|
|
116
|
+
expect(status.build).not.toHaveProperty('failedPages');
|
|
117
|
+
expect(status.pages.failed).toEqual(failed.slice(0, 1));
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('stays ok with no failedPages when every built page builds', async () => {
|
|
121
|
+
mockGetPageBuildStatus.mockResolvedValue({ checked: ['orders'], unbuilt: 2 });
|
|
122
|
+
|
|
123
|
+
const { build } = await getBuildStatus({ checked: ['orders'] });
|
|
124
|
+
|
|
125
|
+
expect(build.status).toBe('ok');
|
|
126
|
+
expect(build.configStatus).toBe('ok');
|
|
127
|
+
expect(build).not.toHaveProperty('failedPages');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('getBuildStatus lists errors from earlier builds apart from the current ones', async () => {
|
|
132
|
+
mockClientErrors.mockReturnValue([
|
|
133
|
+
{ message: 'old render error', buildId: 'build-1' },
|
|
134
|
+
{ message: 'live render error', buildId: 'build-2' },
|
|
135
|
+
]);
|
|
136
|
+
mockServerErrors.mockReturnValue([{ message: 'old request error', buildId: 'build-1' }]);
|
|
137
|
+
|
|
138
|
+
const status = await getBuildStatus();
|
|
139
|
+
|
|
140
|
+
expect(status.clientErrors).toEqual([{ message: 'live render error', buildId: 'build-2' }]);
|
|
141
|
+
expect(status.serverErrors).toEqual([]);
|
|
142
|
+
expect(status.earlierErrors).toEqual({
|
|
143
|
+
note: expect.stringContaining('may already be fixed'),
|
|
144
|
+
clientErrors: [{ message: 'old render error', buildId: 'build-1' }],
|
|
145
|
+
serverErrors: [{ message: 'old request error', buildId: 'build-1' }],
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('getBuildStatus leaves out earlierErrors when every error is current', async () => {
|
|
150
|
+
mockClientErrors.mockReturnValue([{ message: 'live', buildId: 'build-2' }]);
|
|
151
|
+
mockServerErrors.mockReturnValue([]);
|
|
152
|
+
|
|
153
|
+
expect((await getBuildStatus()).earlierErrors).toBeUndefined();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('getBuildStatus passes the pages build status just built to the page status', async () => {
|
|
157
|
+
mockClientErrors.mockReturnValue([]);
|
|
158
|
+
mockServerErrors.mockReturnValue([]);
|
|
159
|
+
|
|
160
|
+
const status = await getBuildStatus({ checked: ['home'] });
|
|
161
|
+
|
|
162
|
+
expect(mockGetPageBuildStatus).toHaveBeenCalledWith({ checked: ['home'] });
|
|
163
|
+
expect(status.pages).toEqual({ unbuilt: 0 });
|
|
164
|
+
expect(status.build.status).toBe('ok');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('getBuildStatus names the build being served as a top-level buildId', async () => {
|
|
168
|
+
mockClientErrors.mockReturnValue([]);
|
|
169
|
+
mockServerErrors.mockReturnValue([]);
|
|
170
|
+
|
|
171
|
+
expect((await getBuildStatus()).buildId).toBe('build-2');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('agentFiles', () => {
|
|
175
|
+
let root;
|
|
176
|
+
let previousConfigDirectory;
|
|
177
|
+
|
|
178
|
+
beforeEach(() => {
|
|
179
|
+
mockClientErrors.mockReturnValue([]);
|
|
180
|
+
mockServerErrors.mockReturnValue([]);
|
|
181
|
+
root = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-build-status-'));
|
|
182
|
+
fs.mkdirSync(path.join(root, '.git'));
|
|
183
|
+
fs.writeFileSync(path.join(root, 'lowdefy.yaml'), 'lowdefy: 7.1.0\n');
|
|
184
|
+
fs.writeFileSync(path.join(root, 'CLAUDE.md'), '@AGENTS.md\n');
|
|
185
|
+
previousConfigDirectory = process.env.LOWDEFY_DIRECTORY_CONFIG;
|
|
186
|
+
process.env.LOWDEFY_DIRECTORY_CONFIG = root;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
afterEach(() => {
|
|
190
|
+
if (previousConfigDirectory === undefined) {
|
|
191
|
+
delete process.env.LOWDEFY_DIRECTORY_CONFIG;
|
|
192
|
+
} else {
|
|
193
|
+
process.env.LOWDEFY_DIRECTORY_CONFIG = previousConfigDirectory;
|
|
194
|
+
}
|
|
195
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const writeBlock = (version) =>
|
|
199
|
+
fs.writeFileSync(
|
|
200
|
+
path.join(root, 'AGENTS.md'),
|
|
201
|
+
`<!-- BEGIN:lowdefy-agent-rules version=${version} -->\n<!-- END:lowdefy-agent-rules -->\n`
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
test('lists notices apart from the build warnings, and a fix shows on the next call', async () => {
|
|
205
|
+
writeBlock('7.0.0');
|
|
206
|
+
|
|
207
|
+
const before = await getBuildStatus();
|
|
208
|
+
expect(before.agentFiles).toEqual([
|
|
209
|
+
{
|
|
210
|
+
code: 'version_mismatch',
|
|
211
|
+
message: expect.stringContaining('npx lowdefy@7.1.0 agent-setup'),
|
|
212
|
+
},
|
|
213
|
+
]);
|
|
214
|
+
expect(before.build.warnings).toEqual(['a build warning']);
|
|
215
|
+
|
|
216
|
+
writeBlock('7.1.2');
|
|
217
|
+
|
|
218
|
+
const after = await getBuildStatus();
|
|
219
|
+
expect(after).not.toHaveProperty('agentFiles');
|
|
220
|
+
expect(after.build.warnings).toEqual(['a build warning']);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('leaves agentFiles out when lowdefy.yaml cannot be read', async () => {
|
|
224
|
+
writeBlock('6.0.0');
|
|
225
|
+
fs.rmSync(path.join(root, 'lowdefy.yaml'));
|
|
226
|
+
|
|
227
|
+
expect(await getBuildStatus()).not.toHaveProperty('agentFiles');
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -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;
|