@lowdefy/server-dev 6.0.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 +63 -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 +224 -39
- 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/getAuth.js +46 -0
- 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/{getAuthConfig.js → getStrategies.js} +12 -10
- 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 +174 -41
- package/lib/server/createLowdefyContext.test.mjs +437 -0
- 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 +77 -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/scrubSecrets.js +23 -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 +61 -49
- package/package.original.json +61 -49
- 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 +196 -14
- 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 +4 -2
- 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/lib/server/auth/session.js +0 -39
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
|
|
19
|
+
import buildPageIfNeeded from '../../../lib/server/jitPageBuilder.js';
|
|
20
|
+
import getBuildId from '../../../lib/docs/getBuildId.js';
|
|
21
|
+
import listMutants from '../../../lib/server/mutants/listMutants.js';
|
|
22
|
+
import mapPageBuildErrors from '../../../lib/docs/mapPageBuildErrors.js';
|
|
23
|
+
import readBuildArtifact from '../../../lib/docs/readBuildArtifact.js';
|
|
24
|
+
import readMergedMaps from '../../../lib/server/readMergedMaps.js';
|
|
25
|
+
import validateMutantsBody from '../../../lib/server/mutants/validateMutantsBody.js';
|
|
26
|
+
|
|
27
|
+
// Lists every config mutant on the artifacts a set of journey runs exercised
|
|
28
|
+
// (`lowdefy journeys harden`, step 3). Pages are built first, as the page
|
|
29
|
+
// route builds them, so the artifacts read are the current config's. Reads
|
|
30
|
+
// are never made through a mutant cookie: this route answers for the
|
|
31
|
+
// unmutated build. A page that fails to build is a 422 with its errors.
|
|
32
|
+
async function docsMutantsHandler(c) {
|
|
33
|
+
const parsed = validateMutantsBody(await c.req.json().catch(() => null));
|
|
34
|
+
if (parsed.error) {
|
|
35
|
+
return c.json({ error: parsed.error }, 400);
|
|
36
|
+
}
|
|
37
|
+
const { body } = parsed;
|
|
38
|
+
// Read before the pages build: an edit that lands while they build then
|
|
39
|
+
// gives the answer an older build id than the keys it lists, so the journey
|
|
40
|
+
// route refuses its mutants as stale instead of running them.
|
|
41
|
+
const buildId = getBuildId();
|
|
42
|
+
const buildDirectory = path.join(process.cwd(), 'build');
|
|
43
|
+
const configDirectory = process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd();
|
|
44
|
+
const pageIds = [...new Set([...body.pages, ...body.requests.map((request) => request.pageId)])];
|
|
45
|
+
// A page no longer in the app lists no mutants, even while an older build
|
|
46
|
+
// of it is still on disk: a harden run asks after the pages an earlier run
|
|
47
|
+
// listed, to drop the mutants that are gone.
|
|
48
|
+
const removedPages = new Set();
|
|
49
|
+
for (const pageId of pageIds) {
|
|
50
|
+
try {
|
|
51
|
+
const built = await buildPageIfNeeded({ pageId, buildDirectory, configDirectory });
|
|
52
|
+
if (built === false) {
|
|
53
|
+
removedPages.add(pageId);
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return c.json(
|
|
57
|
+
{
|
|
58
|
+
error: `Page "${pageId}" fails to build, so its mutants cannot be listed until the errors are fixed.`,
|
|
59
|
+
buildErrors: mapPageBuildErrors(error),
|
|
60
|
+
},
|
|
61
|
+
422
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Page builds write their keys to jitMaps/, not keyMap.json.
|
|
66
|
+
const { keyMap, refMap } = await readMergedMaps({ buildDirectory });
|
|
67
|
+
const result = await listMutants({
|
|
68
|
+
...body,
|
|
69
|
+
pages: body.pages.filter((pageId) => !removedPages.has(pageId)),
|
|
70
|
+
requests: body.requests.filter(({ pageId }) => !removedPages.has(pageId)),
|
|
71
|
+
readConfigFile: async (name) => readBuildArtifact({ name, deserialize: true }),
|
|
72
|
+
keyMap,
|
|
73
|
+
refMap,
|
|
74
|
+
});
|
|
75
|
+
return c.json({ buildId, ...result });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default docsMutantsHandler;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import os from 'node:os';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
|
|
21
|
+
import { jest } from '@jest/globals';
|
|
22
|
+
import { Hono } from 'hono';
|
|
23
|
+
import { serializer } from '@lowdefy/helpers';
|
|
24
|
+
|
|
25
|
+
import { endpointFixture, pageFixture } from '../../../lib/server/mutants/test/fixtures.mjs';
|
|
26
|
+
|
|
27
|
+
const mockBuildPageIfNeeded = jest.fn();
|
|
28
|
+
jest.unstable_mockModule('../../../lib/server/jitPageBuilder.js', () => ({
|
|
29
|
+
default: mockBuildPageIfNeeded,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const { default: docsMutantsHandler } = await import('./mutants.js');
|
|
33
|
+
|
|
34
|
+
const originalCwd = process.cwd();
|
|
35
|
+
let serverDirectory;
|
|
36
|
+
|
|
37
|
+
function write(name, content) {
|
|
38
|
+
const filePath = path.join(serverDirectory, 'build', name);
|
|
39
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
40
|
+
fs.writeFileSync(filePath, typeof content === 'string' ? content : JSON.stringify(content));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
jest.clearAllMocks();
|
|
45
|
+
mockBuildPageIfNeeded.mockResolvedValue(true);
|
|
46
|
+
serverDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-mutants-route-'));
|
|
47
|
+
const page = pageFixture();
|
|
48
|
+
const endpoint = endpointFixture();
|
|
49
|
+
write('pages/tickets.json', serializer.serializeToString(page.root));
|
|
50
|
+
write('api/notify.json', serializer.serializeToString(endpoint.root));
|
|
51
|
+
write('keyMap.json', { ...page.keyMap });
|
|
52
|
+
write('refMap.json', {});
|
|
53
|
+
write('buildStatus.json', { status: 'ok', timestamp: '2026-10-03T08:00:00.000Z' });
|
|
54
|
+
process.chdir(serverDirectory);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
process.chdir(originalCwd);
|
|
59
|
+
fs.rmSync(serverDirectory, { recursive: true, force: true });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
async function post(body) {
|
|
63
|
+
const app = new Hono();
|
|
64
|
+
app.post('/lowdefy-docs/mutants', docsMutantsHandler);
|
|
65
|
+
const response = await app.request('/lowdefy-docs/mutants', {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: { 'content-type': 'application/json' },
|
|
68
|
+
body: JSON.stringify(body),
|
|
69
|
+
});
|
|
70
|
+
return { status: response.status, data: await response.json() };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
test('POST /lowdefy-docs/mutants lists the mutants of the posted pages and endpoints with the build id and artifact hashes', async () => {
|
|
74
|
+
const { status, data } = await post({ pages: ['tickets'], endpoints: ['notify'] });
|
|
75
|
+
expect(status).toBe(200);
|
|
76
|
+
expect(mockBuildPageIfNeeded).toHaveBeenCalledWith(
|
|
77
|
+
expect.objectContaining({ pageId: 'tickets' })
|
|
78
|
+
);
|
|
79
|
+
expect(data.buildId).toEqual(expect.any(String));
|
|
80
|
+
expect(Object.keys(data.artifacts)).toEqual(['pages/tickets.json', 'api/notify.json']);
|
|
81
|
+
expect(data.artifacts['pages/tickets.json']).toMatch(/^[0-9a-f]{40}$/);
|
|
82
|
+
const operators = new Set(data.mutants.map((mutant) => mutant.operator));
|
|
83
|
+
expect(operators).toEqual(
|
|
84
|
+
new Set([
|
|
85
|
+
'drop-action',
|
|
86
|
+
'skip-validate',
|
|
87
|
+
'flip-visible',
|
|
88
|
+
'swap-if',
|
|
89
|
+
'drop-payload',
|
|
90
|
+
'retarget-link',
|
|
91
|
+
'drop-block',
|
|
92
|
+
'drop-step',
|
|
93
|
+
])
|
|
94
|
+
);
|
|
95
|
+
const dropStep = data.mutants.find((mutant) => mutant.operator === 'drop-step');
|
|
96
|
+
expect(dropStep).toMatchObject({
|
|
97
|
+
artifact: 'api/notify.json',
|
|
98
|
+
anchor: { type: 'endpoint', endpointId: 'notify' },
|
|
99
|
+
copies: [],
|
|
100
|
+
copyTargets: [],
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('POST /lowdefy-docs/mutants resolves config paths from the keys a page build wrote to jitMaps', async () => {
|
|
105
|
+
const page = pageFixture();
|
|
106
|
+
write('keyMap.json', {});
|
|
107
|
+
write('jitMaps/1-1-1.json', { keyMap: { ...page.keyMap }, refMap: {} });
|
|
108
|
+
const { status, data } = await post({ pages: ['tickets'] });
|
|
109
|
+
expect(status).toBe(200);
|
|
110
|
+
expect(data.mutants.length).toBeGreaterThan(0);
|
|
111
|
+
data.mutants.forEach((mutant) => {
|
|
112
|
+
expect(mutant.config).toEqual(expect.any(String));
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('POST /lowdefy-docs/mutants keeps only the operators asked for', async () => {
|
|
117
|
+
const { data } = await post({ pages: ['tickets'], operators: ['drop-block'] });
|
|
118
|
+
expect(new Set(data.mutants.map((mutant) => mutant.operator))).toEqual(new Set(['drop-block']));
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('POST /lowdefy-docs/mutants builds the page of every posted request', async () => {
|
|
122
|
+
await post({ requests: [{ pageId: 'tickets', requestId: 'assign_ticket' }] });
|
|
123
|
+
expect(mockBuildPageIfNeeded.mock.calls.map(([args]) => args.pageId)).toEqual(['tickets']);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test.each([
|
|
127
|
+
[{ pages: 'tickets' }, '"pages" must be an array of page ids'],
|
|
128
|
+
[{ requests: [{ pageId: 'tickets' }] }, '"requests" must be an array of { pageId, requestId }'],
|
|
129
|
+
[{ endpoints: [1] }, '"endpoints" must be an array of endpoint ids'],
|
|
130
|
+
[{ appEvents: 'yes' }, '"appEvents" must be a boolean'],
|
|
131
|
+
[{ operators: ['drop-everything'] }, '"operators" must be an array of operator names'],
|
|
132
|
+
[{ pages: ['../../secrets'] }, '"pages" must be an array of page ids'],
|
|
133
|
+
[
|
|
134
|
+
{ requests: [{ pageId: 'tickets', requestId: '../x' }] },
|
|
135
|
+
'"requests" must be an array of { pageId, requestId }',
|
|
136
|
+
],
|
|
137
|
+
[{ endpoints: ['../notify'] }, '"endpoints" must be an array of endpoint ids'],
|
|
138
|
+
])(
|
|
139
|
+
'POST /lowdefy-docs/mutants answers a bad body %j with a 400 naming the field',
|
|
140
|
+
async (body, message) => {
|
|
141
|
+
const { status, data } = await post(body);
|
|
142
|
+
expect(status).toBe(400);
|
|
143
|
+
expect(data.error).toContain(message);
|
|
144
|
+
expect(mockBuildPageIfNeeded).not.toHaveBeenCalled();
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
test('POST /lowdefy-docs/mutants answers a page that fails to build with a 422 and its errors', async () => {
|
|
149
|
+
mockBuildPageIfNeeded.mockRejectedValue(new Error('Block type "Buton" not found.'));
|
|
150
|
+
const { status, data } = await post({ pages: ['tickets'] });
|
|
151
|
+
expect(status).toBe(422);
|
|
152
|
+
expect(data.buildErrors).toEqual([
|
|
153
|
+
{ type: 'Error', message: 'Block type "Buton" not found.', source: null },
|
|
154
|
+
]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('POST /lowdefy-docs/mutants answers with the build id read before the pages built', async () => {
|
|
158
|
+
// An edit lands while the page builds: its keys may be the new build's, so
|
|
159
|
+
// the answer must carry the older id and the journey route refuse it as stale.
|
|
160
|
+
mockBuildPageIfNeeded.mockImplementation(async () => {
|
|
161
|
+
write('buildStatus.json', { status: 'ok', timestamp: '2026-10-03T09:00:00.000Z' });
|
|
162
|
+
return true;
|
|
163
|
+
});
|
|
164
|
+
const { status, data } = await post({ pages: ['tickets'] });
|
|
165
|
+
expect(status).toBe(200);
|
|
166
|
+
expect(data.buildId).toEqual('2026-10-03T08:00:00.000Z');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('POST /lowdefy-docs/mutants lists no mutants for a page no longer in the app, though its old build is on disk', async () => {
|
|
170
|
+
mockBuildPageIfNeeded.mockResolvedValue(false);
|
|
171
|
+
const { status, data } = await post({
|
|
172
|
+
pages: ['tickets'],
|
|
173
|
+
requests: [{ pageId: 'tickets', requestId: 'load' }],
|
|
174
|
+
endpoints: ['notify'],
|
|
175
|
+
});
|
|
176
|
+
expect(status).toBe(200);
|
|
177
|
+
expect(Object.keys(data.artifacts)).toEqual(['api/notify.json']);
|
|
178
|
+
expect(data.mutants.every(({ artifact }) => artifact === 'api/notify.json')).toBe(true);
|
|
179
|
+
expect(data.ids).toEqual(data.mutants.map(({ id }) => id));
|
|
180
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
// The docs routes take a page instance's path values as a JSON string on the
|
|
20
|
+
// GET routes (query params are always strings) and as an object in the POST
|
|
21
|
+
// bodies. Returns { pathParams } or { error }; the page tools check the values
|
|
22
|
+
// against the page's pattern.
|
|
23
|
+
function parsePathParamsParam({ value }) {
|
|
24
|
+
if (type.isNone(value)) {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
if (!type.isString(value)) {
|
|
28
|
+
return { pathParams: value };
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return { pathParams: JSON.parse(value) };
|
|
32
|
+
} catch {
|
|
33
|
+
return {
|
|
34
|
+
error: `The "pathParams" param must be JSON, e.g. {"ticket_id":"1"}. Received ${JSON.stringify(
|
|
35
|
+
value
|
|
36
|
+
)}.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default parsePathParamsParam;
|
|
@@ -0,0 +1,42 @@
|
|
|
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 parsePathParamsParam from './parsePathParamsParam.js';
|
|
18
|
+
|
|
19
|
+
test('parsePathParamsParam returns nothing when the param is absent', () => {
|
|
20
|
+
expect(parsePathParamsParam({ value: undefined })).toEqual({});
|
|
21
|
+
expect(parsePathParamsParam({ value: null })).toEqual({});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('parsePathParamsParam parses a JSON string from a query param', () => {
|
|
25
|
+
expect(parsePathParamsParam({ value: '{"space":"s","ticket_id":"1"}' })).toEqual({
|
|
26
|
+
pathParams: { space: 's', ticket_id: '1' },
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('parsePathParamsParam passes an object from a JSON body through', () => {
|
|
31
|
+
expect(parsePathParamsParam({ value: { ticket_id: 1 } })).toEqual({
|
|
32
|
+
pathParams: { ticket_id: 1 },
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('parsePathParamsParam returns an error when the query param is not JSON', () => {
|
|
37
|
+
expect(parsePathParamsParam({ value: 'ticket_id=1' }).error).toMatch(/must be JSON/);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('parsePathParamsParam leaves a parsed non-object for the page tools to refuse', () => {
|
|
41
|
+
expect(parsePathParamsParam({ value: '["1"]' })).toEqual({ pathParams: ['1'] });
|
|
42
|
+
});
|
|
@@ -16,36 +16,42 @@
|
|
|
16
16
|
|
|
17
17
|
import { type } from '@lowdefy/helpers';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
19
|
+
const SHAPE =
|
|
20
|
+
'The "user" param must be a user object (JSON on a query string), e.g. {"roles":["admin"]}, "none" to act signed out, or the name of a user in the data set the "data" param names.';
|
|
21
|
+
|
|
22
|
+
// The docs routes take the caller in the forms the MCP tools take (see
|
|
23
|
+
// lib/docs/resolveToolCaller.js): a user object - a JSON string on the GET
|
|
24
|
+
// routes, since query params are always strings, and an object in the POST
|
|
25
|
+
// bodies - "none", or a data set user name. Both arrive here, so every route
|
|
26
|
+
// answers a bad `user` with the same message. Returns { user } or { error }.
|
|
23
27
|
function parseUserParam({ value }) {
|
|
24
28
|
if (type.isNone(value)) {
|
|
25
29
|
return {};
|
|
26
30
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (type.isString(value)) {
|
|
30
|
-
try {
|
|
31
|
-
user = JSON.parse(value);
|
|
32
|
-
} catch {
|
|
33
|
-
return {
|
|
34
|
-
error: `The "user" param must be JSON, e.g. {"roles":["admin"]}. Received ${JSON.stringify(
|
|
35
|
-
value
|
|
36
|
-
)}.`,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
31
|
+
if (type.isObject(value)) {
|
|
32
|
+
return { user: value };
|
|
39
33
|
}
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
if (!type.isString(value) || value === '') {
|
|
35
|
+
return { error: `${SHAPE} Received ${JSON.stringify(value)}.` };
|
|
36
|
+
}
|
|
37
|
+
// A plain string is "none" or a data set user name; one that opens like JSON
|
|
38
|
+
// is a user object written as a query param.
|
|
39
|
+
if (!value.startsWith('{') && !value.startsWith('[')) {
|
|
40
|
+
return { user: value };
|
|
41
|
+
}
|
|
42
|
+
let user;
|
|
43
|
+
try {
|
|
44
|
+
user = JSON.parse(value);
|
|
45
|
+
} catch {
|
|
42
46
|
return {
|
|
43
|
-
error: `The "user" param must be
|
|
44
|
-
|
|
47
|
+
error: `The "user" param must be JSON, e.g. {"roles":["admin"]}. Received ${JSON.stringify(
|
|
48
|
+
value
|
|
45
49
|
)}.`,
|
|
46
50
|
};
|
|
47
51
|
}
|
|
48
|
-
|
|
52
|
+
if (!type.isObject(user)) {
|
|
53
|
+
return { error: `${SHAPE} Received ${JSON.stringify(user)}.` };
|
|
54
|
+
}
|
|
49
55
|
return { user };
|
|
50
56
|
}
|
|
51
57
|
|
|
@@ -32,14 +32,26 @@ test('parseUserParam passes an object from a JSON body through', () => {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
test('parseUserParam
|
|
36
|
-
expect(parseUserParam({ value: '
|
|
35
|
+
test('parseUserParam passes a data set user name through', () => {
|
|
36
|
+
expect(parseUserParam({ value: 'member' })).toEqual({ user: 'member' });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('parseUserParam passes "none" through', () => {
|
|
40
|
+
expect(parseUserParam({ value: 'none' })).toEqual({ user: 'none' });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('parseUserParam returns an error when a query param that opens like JSON is not JSON', () => {
|
|
44
|
+
expect(parseUserParam({ value: '{roles: [admin]}' }).error).toMatch(/must be JSON/);
|
|
37
45
|
});
|
|
38
46
|
|
|
39
47
|
test('parseUserParam returns an error when the param parses to a non-object', () => {
|
|
40
|
-
expect(parseUserParam({ value: '["admin"]' }).error).toMatch(/must be
|
|
48
|
+
expect(parseUserParam({ value: '["admin"]' }).error).toMatch(/must be a user object/);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('parseUserParam returns an error when a body value is neither an object nor a string', () => {
|
|
52
|
+
expect(parseUserParam({ value: 42 }).error).toMatch(/must be a user object/);
|
|
41
53
|
});
|
|
42
54
|
|
|
43
|
-
test('parseUserParam returns an error
|
|
44
|
-
expect(parseUserParam({ value:
|
|
55
|
+
test('parseUserParam returns an error for an empty string', () => {
|
|
56
|
+
expect(parseUserParam({ value: '' }).error).toMatch(/must be a user object/);
|
|
45
57
|
});
|
|
@@ -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 { type } from '@lowdefy/helpers';
|
|
18
|
+
import requestRestart from '../../../lib/docs/requestRestart.js';
|
|
19
|
+
|
|
20
|
+
async function docsRestartHandler(c) {
|
|
21
|
+
let body = {};
|
|
22
|
+
try {
|
|
23
|
+
body = await c.req.json();
|
|
24
|
+
} catch {
|
|
25
|
+
// An empty body is a valid request with no reason.
|
|
26
|
+
}
|
|
27
|
+
const reason = type.isString(body?.reason) ? body.reason : undefined;
|
|
28
|
+
const result = requestRestart({ reason });
|
|
29
|
+
return c.json({
|
|
30
|
+
...result,
|
|
31
|
+
note: 'The dev server is restarting. Call GET /lowdefy-docs/build-status?wait=true (lowdefy_build_status with wait: true) before your next call; it answers once the server is back.',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default docsRestartHandler;
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { Hono } from 'hono';
|
|
21
|
+
|
|
22
|
+
const originalCwd = process.cwd();
|
|
23
|
+
const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-restart-route-test-'));
|
|
24
|
+
fs.mkdirSync(path.join(fixtureDir, 'build'), { recursive: true });
|
|
25
|
+
process.chdir(fixtureDir);
|
|
26
|
+
|
|
27
|
+
const { default: docsRestartHandler } = await import('./restart.js');
|
|
28
|
+
|
|
29
|
+
afterAll(() => {
|
|
30
|
+
process.chdir(originalCwd);
|
|
31
|
+
fs.rmSync(fixtureDir, { recursive: true, force: true });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function createApp() {
|
|
35
|
+
const app = new Hono();
|
|
36
|
+
app.post('/lowdefy-docs/restart', docsRestartHandler);
|
|
37
|
+
return app;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test('POST /lowdefy-docs/restart writes the sentinel and answers with the polling note', async () => {
|
|
41
|
+
const res = await createApp().request('/lowdefy-docs/restart', {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'content-type': 'application/json' },
|
|
44
|
+
body: JSON.stringify({ reason: 'stale cache' }),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(res.status).toBe(200);
|
|
48
|
+
expect(await res.json()).toEqual({
|
|
49
|
+
requested: true,
|
|
50
|
+
reason: 'stale cache',
|
|
51
|
+
note: 'The dev server is restarting. Call GET /lowdefy-docs/build-status?wait=true (lowdefy_build_status with wait: true) before your next call; it answers once the server is back.',
|
|
52
|
+
});
|
|
53
|
+
const sentinel = JSON.parse(fs.readFileSync(path.join(fixtureDir, 'build', '.restart'), 'utf8'));
|
|
54
|
+
expect(sentinel.reason).toBe('stale cache');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('POST /lowdefy-docs/restart accepts an empty body', async () => {
|
|
58
|
+
const res = await createApp().request('/lowdefy-docs/restart', { method: 'POST' });
|
|
59
|
+
|
|
60
|
+
expect(res.status).toBe(200);
|
|
61
|
+
const body = await res.json();
|
|
62
|
+
expect(body.requested).toBe(true);
|
|
63
|
+
expect(body).not.toHaveProperty('reason');
|
|
64
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
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 { ConfigError } from '@lowdefy/errors';
|
|
18
|
+
|
|
19
|
+
import parseUserParam from './parseUserParam.js';
|
|
20
|
+
import runEndpoint from '../../../lib/docs/runEndpoint.js';
|
|
21
|
+
|
|
22
|
+
// Refusals, routine rejects and endpoint errors are returned as 200 data (see
|
|
23
|
+
// runEndpoint.js) - only malformed input (missing endpointId or a bad user,
|
|
24
|
+
// thrown as a ConfigError) is a 400. Anything else is a fault and propagates to
|
|
25
|
+
// the error handler.
|
|
26
|
+
async function docsRunEndpointHandler(c) {
|
|
27
|
+
// Parse the body from a clone: runEndpoint builds a Lowdefy context whose
|
|
28
|
+
// resolveAuthentication reads c.req.raw (headers) to resolve the caller,
|
|
29
|
+
// so leave the original request body intact and read our own copy here.
|
|
30
|
+
const { endpointId, payload, user, data, system, saveResponse } = await c.req.raw.clone().json();
|
|
31
|
+
const { user: parsedUser, error: userError } = parseUserParam({ value: user });
|
|
32
|
+
if (userError) {
|
|
33
|
+
return c.json({ error: userError }, 400);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const result = await runEndpoint({
|
|
37
|
+
endpointId,
|
|
38
|
+
payload,
|
|
39
|
+
user: parsedUser,
|
|
40
|
+
data,
|
|
41
|
+
system,
|
|
42
|
+
saveResponse,
|
|
43
|
+
honoContext: c,
|
|
44
|
+
});
|
|
45
|
+
return c.json(result);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof ConfigError) {
|
|
48
|
+
return c.json({ error: error.message }, 400);
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default docsRunEndpointHandler;
|