@lowdefy/server-dev 6.1.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +78 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +727 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/describeTargetKey.js +29 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +52 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +133 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +493 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +83 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +251 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sessionDatabaseName.js +32 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +36 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +225 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +12 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +81 -7
- package/lib/docs/getBuildStatus.test.mjs +229 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +92 -0
- package/lib/server/applyDataSetRedirect.test.mjs +446 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +207 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +134 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +331 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +115 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +25 -3
- package/manager/processes/initialBuild.mjs +17 -1
- package/manager/processes/initialBuild.test.mjs +104 -0
- package/manager/processes/lowdefyBuild.mjs +31 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +72 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,165 @@
|
|
|
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 mockRunEndpoint = jest.fn();
|
|
20
|
+
|
|
21
|
+
jest.unstable_mockModule('../../../lib/docs/runEndpoint.js', () => ({
|
|
22
|
+
default: mockRunEndpoint,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const { ConfigError } = await import('@lowdefy/errors');
|
|
26
|
+
const { default: docsRunEndpointHandler } = await import('./runEndpoint.js');
|
|
27
|
+
|
|
28
|
+
function createContext(body) {
|
|
29
|
+
const request = new Request('http://localhost:3224/lowdefy-docs/run-endpoint', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'content-type': 'application/json' },
|
|
32
|
+
body: JSON.stringify(body),
|
|
33
|
+
});
|
|
34
|
+
const json = jest.fn((data, status) => ({ data, status: status ?? 200 }));
|
|
35
|
+
return { req: { raw: request }, json };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
jest.clearAllMocks();
|
|
40
|
+
mockRunEndpoint.mockResolvedValue({ refused: false, status: 'success', response: { ok: true } });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('docsRunEndpointHandler passes endpointId, payload and a user object through to runEndpoint', async () => {
|
|
44
|
+
const c = createContext({
|
|
45
|
+
endpointId: 'create_order',
|
|
46
|
+
payload: { sku: 'A1' },
|
|
47
|
+
user: { roles: ['admin'] },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const result = await docsRunEndpointHandler(c);
|
|
51
|
+
|
|
52
|
+
expect(mockRunEndpoint).toHaveBeenCalledWith({
|
|
53
|
+
endpointId: 'create_order',
|
|
54
|
+
payload: { sku: 'A1' },
|
|
55
|
+
user: { roles: ['admin'] },
|
|
56
|
+
system: undefined,
|
|
57
|
+
honoContext: c,
|
|
58
|
+
});
|
|
59
|
+
expect(result.status).toBe(200);
|
|
60
|
+
expect(result.data).toEqual({ refused: false, status: 'success', response: { ok: true } });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('docsRunEndpointHandler leaves the original request body readable', async () => {
|
|
64
|
+
const c = createContext({ endpointId: 'create_order' });
|
|
65
|
+
|
|
66
|
+
await docsRunEndpointHandler(c);
|
|
67
|
+
|
|
68
|
+
expect(c.req.raw.bodyUsed).toBe(false);
|
|
69
|
+
await expect(c.req.raw.json()).resolves.toEqual({ endpointId: 'create_order' });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('docsRunEndpointHandler returns 400 when user is malformed', async () => {
|
|
73
|
+
const c = createContext({ endpointId: 'create_order', user: '{nope' });
|
|
74
|
+
|
|
75
|
+
const result = await docsRunEndpointHandler(c);
|
|
76
|
+
|
|
77
|
+
expect(result.status).toBe(400);
|
|
78
|
+
expect(result.data.error).toMatch(/The "user" param must be JSON/);
|
|
79
|
+
expect(mockRunEndpoint).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('docsRunEndpointHandler passes a data set user name and data through', async () => {
|
|
83
|
+
const c = createContext({ endpointId: 'create_order', user: 'member', data: 'crm' });
|
|
84
|
+
|
|
85
|
+
await docsRunEndpointHandler(c);
|
|
86
|
+
|
|
87
|
+
expect(mockRunEndpoint).toHaveBeenCalledWith(
|
|
88
|
+
expect.objectContaining({ user: 'member', data: 'crm' })
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('docsRunEndpointHandler passes an undefined user when the body omits it', async () => {
|
|
93
|
+
const c = createContext({ endpointId: 'create_order' });
|
|
94
|
+
|
|
95
|
+
await docsRunEndpointHandler(c);
|
|
96
|
+
|
|
97
|
+
expect(mockRunEndpoint).toHaveBeenCalledWith({
|
|
98
|
+
endpointId: 'create_order',
|
|
99
|
+
payload: undefined,
|
|
100
|
+
user: undefined,
|
|
101
|
+
system: undefined,
|
|
102
|
+
honoContext: c,
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('docsRunEndpointHandler passes system through to runEndpoint', async () => {
|
|
107
|
+
const c = createContext({ endpointId: 'purge_stale', system: true });
|
|
108
|
+
|
|
109
|
+
await docsRunEndpointHandler(c);
|
|
110
|
+
|
|
111
|
+
expect(mockRunEndpoint).toHaveBeenCalledWith({
|
|
112
|
+
endpointId: 'purge_stale',
|
|
113
|
+
payload: undefined,
|
|
114
|
+
user: undefined,
|
|
115
|
+
system: true,
|
|
116
|
+
honoContext: c,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('docsRunEndpointHandler returns 400 when system is combined with user', async () => {
|
|
121
|
+
mockRunEndpoint.mockRejectedValue(
|
|
122
|
+
new ConfigError('run_endpoint "system" cannot be combined with "user".')
|
|
123
|
+
);
|
|
124
|
+
const c = createContext({ endpointId: 'purge_stale', system: true, user: { roles: ['admin'] } });
|
|
125
|
+
|
|
126
|
+
const result = await docsRunEndpointHandler(c);
|
|
127
|
+
|
|
128
|
+
expect(result.status).toBe(400);
|
|
129
|
+
expect(result.data.error).toMatch(/cannot be combined with "user"/);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('docsRunEndpointHandler returns 400 when runEndpoint throws a ConfigError', async () => {
|
|
133
|
+
mockRunEndpoint.mockRejectedValue(
|
|
134
|
+
new ConfigError('run_endpoint requires an "endpointId" string. Received undefined.')
|
|
135
|
+
);
|
|
136
|
+
const c = createContext({ payload: {} });
|
|
137
|
+
|
|
138
|
+
const result = await docsRunEndpointHandler(c);
|
|
139
|
+
|
|
140
|
+
expect(result.status).toBe(400);
|
|
141
|
+
expect(result.data.error).toMatch(/requires an "endpointId" string/);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('docsRunEndpointHandler returns refusals and rejects as 200 data', async () => {
|
|
145
|
+
mockRunEndpoint.mockResolvedValue({
|
|
146
|
+
refused: false,
|
|
147
|
+
success: false,
|
|
148
|
+
status: 'reject',
|
|
149
|
+
error: { name: 'Error', message: 'Out of stock.' },
|
|
150
|
+
response: null,
|
|
151
|
+
});
|
|
152
|
+
const c = createContext({ endpointId: 'create_order' });
|
|
153
|
+
|
|
154
|
+
const result = await docsRunEndpointHandler(c);
|
|
155
|
+
|
|
156
|
+
expect(result.status).toBe(200);
|
|
157
|
+
expect(result.data.status).toBe('reject');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('docsRunEndpointHandler rethrows faults that are not ConfigErrors', async () => {
|
|
161
|
+
mockRunEndpoint.mockRejectedValue(new Error('boom'));
|
|
162
|
+
const c = createContext({ endpointId: 'create_order' });
|
|
163
|
+
|
|
164
|
+
await expect(docsRunEndpointHandler(c)).rejects.toThrow('boom');
|
|
165
|
+
});
|
|
@@ -14,22 +14,39 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
18
|
+
|
|
19
|
+
import parseUserParam from './parseUserParam.js';
|
|
17
20
|
import runRequest from '../../../lib/docs/runRequest.js';
|
|
18
21
|
|
|
19
22
|
// Refusals and request errors are returned as 200 data (see runRequest.js) —
|
|
20
|
-
// only malformed input (missing pageId/requestId) is a
|
|
23
|
+
// only malformed input (missing pageId/requestId, thrown as a ConfigError) is a
|
|
24
|
+
// 400. Anything else is a fault and propagates to the error handler.
|
|
21
25
|
async function docsRunRequestHandler(c) {
|
|
22
26
|
// Parse the body from a clone: runRequest builds a Lowdefy context whose
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
// resolveAuthentication reads c.req.raw (headers) to resolve the caller,
|
|
28
|
+
// so leave the original request body intact and read our own copy here.
|
|
29
|
+
const { pageId, requestId, payload, user, data, saveResponse } = await c.req.raw.clone().json();
|
|
30
|
+
const { user: parsedUser, error: userError } = parseUserParam({ value: user });
|
|
31
|
+
if (userError) {
|
|
32
|
+
return c.json({ error: userError }, 400);
|
|
33
|
+
}
|
|
28
34
|
try {
|
|
29
|
-
const result = await runRequest({
|
|
35
|
+
const result = await runRequest({
|
|
36
|
+
pageId,
|
|
37
|
+
requestId,
|
|
38
|
+
payload,
|
|
39
|
+
user: parsedUser,
|
|
40
|
+
data,
|
|
41
|
+
saveResponse,
|
|
42
|
+
honoContext: c,
|
|
43
|
+
});
|
|
30
44
|
return c.json(result);
|
|
31
45
|
} catch (error) {
|
|
32
|
-
|
|
46
|
+
if (error instanceof ConfigError) {
|
|
47
|
+
return c.json({ error: error.message }, 400);
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
33
50
|
}
|
|
34
51
|
}
|
|
35
52
|
|
|
@@ -0,0 +1,92 @@
|
|
|
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 mockRunRequest = jest.fn();
|
|
20
|
+
|
|
21
|
+
jest.unstable_mockModule('../../../lib/docs/runRequest.js', () => ({
|
|
22
|
+
default: mockRunRequest,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const { default: docsRunRequestHandler } = await import('./runRequest.js');
|
|
26
|
+
|
|
27
|
+
function createContext(body) {
|
|
28
|
+
const request = new Request('http://localhost:3204/lowdefy-docs/run-request', {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'content-type': 'application/json' },
|
|
31
|
+
body: JSON.stringify(body),
|
|
32
|
+
});
|
|
33
|
+
const json = jest.fn((data, status) => ({ data, status: status ?? 200 }));
|
|
34
|
+
return { req: { raw: request }, json };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
mockRunRequest.mockResolvedValue({ refused: false, response: [] });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('docsRunRequestHandler passes a user object through to runRequest', async () => {
|
|
43
|
+
const c = createContext({
|
|
44
|
+
pageId: 'home',
|
|
45
|
+
requestId: 'get_rows',
|
|
46
|
+
user: { roles: ['admin'] },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await docsRunRequestHandler(c);
|
|
50
|
+
|
|
51
|
+
expect(mockRunRequest).toHaveBeenCalledWith({
|
|
52
|
+
pageId: 'home',
|
|
53
|
+
requestId: 'get_rows',
|
|
54
|
+
payload: undefined,
|
|
55
|
+
user: { roles: ['admin'] },
|
|
56
|
+
honoContext: c,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('docsRunRequestHandler returns 400 when user is malformed', async () => {
|
|
61
|
+
const c = createContext({ pageId: 'home', requestId: 'get_rows', user: 42 });
|
|
62
|
+
|
|
63
|
+
const result = await docsRunRequestHandler(c);
|
|
64
|
+
|
|
65
|
+
expect(result.status).toBe(400);
|
|
66
|
+
expect(result.data.error).toMatch(/must be a user object/);
|
|
67
|
+
expect(mockRunRequest).not.toHaveBeenCalled();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('docsRunRequestHandler passes a data set user name and data through', async () => {
|
|
71
|
+
const c = createContext({ pageId: 'home', requestId: 'get_rows', user: 'member', data: 'crm' });
|
|
72
|
+
|
|
73
|
+
await docsRunRequestHandler(c);
|
|
74
|
+
|
|
75
|
+
expect(mockRunRequest).toHaveBeenCalledWith(
|
|
76
|
+
expect.objectContaining({ user: 'member', data: 'crm' })
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('docsRunRequestHandler passes an undefined user when the body omits it', async () => {
|
|
81
|
+
const c = createContext({ pageId: 'home', requestId: 'get_rows' });
|
|
82
|
+
|
|
83
|
+
await docsRunRequestHandler(c);
|
|
84
|
+
|
|
85
|
+
expect(mockRunRequest).toHaveBeenCalledWith({
|
|
86
|
+
pageId: 'home',
|
|
87
|
+
requestId: 'get_rows',
|
|
88
|
+
payload: undefined,
|
|
89
|
+
user: undefined,
|
|
90
|
+
honoContext: c,
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -16,8 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { type } from '@lowdefy/helpers';
|
|
18
18
|
|
|
19
|
+
import parsePathParamsParam from './parsePathParamsParam.js';
|
|
19
20
|
import parseUserParam from './parseUserParam.js';
|
|
20
21
|
import screenshotPage from '../../../lib/docs/screenshotPage.js';
|
|
22
|
+
import validateViewport from '../../../lib/docs/validateViewport.js';
|
|
21
23
|
|
|
22
24
|
// Parses a query param as a number, or undefined if absent/not a valid
|
|
23
25
|
// number — undefined (not NaN/0) so callers can tell "not provided" apart
|
|
@@ -56,14 +58,60 @@ async function docsScreenshotHandler(c) {
|
|
|
56
58
|
const scrollX = queryNumber(c, 'scrollX') ?? 0;
|
|
57
59
|
const scrollY = queryNumber(c, 'scrollY') ?? 0;
|
|
58
60
|
|
|
61
|
+
// `width` and `height` name the clip here, so the viewport size takes the
|
|
62
|
+
// `viewport` prefix; the MCP tool, which nests the clip, calls them width
|
|
63
|
+
// and height.
|
|
64
|
+
for (const key of ['viewportWidth', 'viewportHeight']) {
|
|
65
|
+
const raw = c.req.query(key);
|
|
66
|
+
if (!type.isNone(raw) && type.isUndefined(queryNumber(c, key))) {
|
|
67
|
+
return c.json(
|
|
68
|
+
{
|
|
69
|
+
error: `"${key}" must be a positive integer (CSS pixels). Received ${JSON.stringify(
|
|
70
|
+
raw
|
|
71
|
+
)}.`,
|
|
72
|
+
},
|
|
73
|
+
400
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const width = queryNumber(c, 'viewportWidth');
|
|
78
|
+
const height = queryNumber(c, 'viewportHeight');
|
|
79
|
+
const colorScheme = c.req.query('colorScheme');
|
|
80
|
+
const viewportError = validateViewport({ width, height, colorScheme });
|
|
81
|
+
if (viewportError) {
|
|
82
|
+
return c.json({ error: viewportError }, 400);
|
|
83
|
+
}
|
|
84
|
+
|
|
59
85
|
const { user, error: userError } = parseUserParam({ value: c.req.query('user') });
|
|
60
86
|
if (userError) {
|
|
61
87
|
return c.json({ error: userError }, 400);
|
|
62
88
|
}
|
|
63
89
|
|
|
64
|
-
const
|
|
90
|
+
const { pathParams, error: pathParamsError } = parsePathParamsParam({
|
|
91
|
+
value: c.req.query('pathParams'),
|
|
92
|
+
});
|
|
93
|
+
if (pathParamsError) {
|
|
94
|
+
return c.json({ error: pathParamsError }, 400);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = await screenshotPage({
|
|
98
|
+
origin,
|
|
99
|
+
pageId,
|
|
100
|
+
pathParams,
|
|
101
|
+
fullPage,
|
|
102
|
+
clip,
|
|
103
|
+
scrollX,
|
|
104
|
+
scrollY,
|
|
105
|
+
user,
|
|
106
|
+
data: c.req.query('data'),
|
|
107
|
+
width,
|
|
108
|
+
height,
|
|
109
|
+
colorScheme,
|
|
110
|
+
});
|
|
65
111
|
if (result.error) {
|
|
66
|
-
|
|
112
|
+
// pathParams the page cannot be opened with are the caller's to fix, not a
|
|
113
|
+
// failed render.
|
|
114
|
+
return c.json({ error: result.error }, result.invalidInput ? 400 : 502);
|
|
67
115
|
}
|
|
68
116
|
const buffer = Buffer.from(result.data, 'base64');
|
|
69
117
|
return c.body(buffer, 200, { 'Content-Type': result.mimeType });
|
|
@@ -0,0 +1,117 @@
|
|
|
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 mockScreenshotPage = jest.fn();
|
|
20
|
+
|
|
21
|
+
jest.unstable_mockModule('../../../lib/docs/screenshotPage.js', () => ({
|
|
22
|
+
default: mockScreenshotPage,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const { default: docsScreenshotHandler } = await import('./screenshot.js');
|
|
26
|
+
|
|
27
|
+
function createContext(url) {
|
|
28
|
+
const parsed = new URL(url);
|
|
29
|
+
const json = jest.fn((data, status) => ({ data, status: status ?? 200 }));
|
|
30
|
+
const body = jest.fn((data, status, headers) => ({ data, status, headers }));
|
|
31
|
+
return {
|
|
32
|
+
req: {
|
|
33
|
+
url,
|
|
34
|
+
param: () => parsed.pathname.split('/').pop(),
|
|
35
|
+
query: (key) => parsed.searchParams.get(key) ?? undefined,
|
|
36
|
+
},
|
|
37
|
+
json,
|
|
38
|
+
body,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
jest.clearAllMocks();
|
|
44
|
+
mockScreenshotPage.mockResolvedValue({ data: 'cG5n', mimeType: 'image/png' });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('docsScreenshotHandler passes the viewport size and colour scheme to screenshotPage', async () => {
|
|
48
|
+
const c = createContext(
|
|
49
|
+
'http://localhost:3227/lowdefy-docs/screenshot/home?viewportWidth=390&viewportHeight=844&colorScheme=dark'
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const result = await docsScreenshotHandler(c);
|
|
53
|
+
|
|
54
|
+
expect(mockScreenshotPage).toHaveBeenCalledWith(
|
|
55
|
+
expect.objectContaining({
|
|
56
|
+
origin: 'http://localhost:3227',
|
|
57
|
+
pageId: 'home',
|
|
58
|
+
width: 390,
|
|
59
|
+
height: 844,
|
|
60
|
+
colorScheme: 'dark',
|
|
61
|
+
clip: undefined,
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
expect(result.status).toBe(200);
|
|
65
|
+
expect(result.headers).toEqual({ 'Content-Type': 'image/png' });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('docsScreenshotHandler keeps width and height as the clip, apart from the viewport', async () => {
|
|
69
|
+
const c = createContext(
|
|
70
|
+
'http://localhost:3227/lowdefy-docs/screenshot/home?x=0&y=10&width=200&height=100&viewportWidth=800'
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
await docsScreenshotHandler(c);
|
|
74
|
+
|
|
75
|
+
expect(mockScreenshotPage).toHaveBeenCalledWith(
|
|
76
|
+
expect.objectContaining({
|
|
77
|
+
clip: { x: 0, y: 10, width: 200, height: 100 },
|
|
78
|
+
width: 800,
|
|
79
|
+
height: undefined,
|
|
80
|
+
colorScheme: undefined,
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('docsScreenshotHandler returns 400 for an unknown colour scheme', async () => {
|
|
86
|
+
const c = createContext('http://localhost:3227/lowdefy-docs/screenshot/home?colorScheme=dim');
|
|
87
|
+
|
|
88
|
+
const result = await docsScreenshotHandler(c);
|
|
89
|
+
|
|
90
|
+
expect(result.status).toBe(400);
|
|
91
|
+
expect(result.data.error).toEqual('Color scheme must be "light" or "dark". Received "dim".');
|
|
92
|
+
expect(mockScreenshotPage).not.toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('docsScreenshotHandler returns 400 for a viewport width that is not a positive integer', async () => {
|
|
96
|
+
const c = createContext('http://localhost:3227/lowdefy-docs/screenshot/home?viewportWidth=0');
|
|
97
|
+
|
|
98
|
+
const result = await docsScreenshotHandler(c);
|
|
99
|
+
|
|
100
|
+
expect(result.status).toBe(400);
|
|
101
|
+
expect(result.data.error).toMatch(/Viewport width must be a positive integer/);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test.each(['viewportWidth', 'viewportHeight'])(
|
|
105
|
+
'docsScreenshotHandler returns 400 naming a non-numeric %s',
|
|
106
|
+
async (key) => {
|
|
107
|
+
const c = createContext(`http://localhost:3227/lowdefy-docs/screenshot/home?${key}=wide`);
|
|
108
|
+
|
|
109
|
+
const result = await docsScreenshotHandler(c);
|
|
110
|
+
|
|
111
|
+
expect(result.status).toBe(400);
|
|
112
|
+
expect(result.data.error).toEqual(
|
|
113
|
+
`"${key}" must be a positive integer (CSS pixels). Received "wide".`
|
|
114
|
+
);
|
|
115
|
+
expect(mockScreenshotPage).not.toHaveBeenCalled();
|
|
116
|
+
}
|
|
117
|
+
);
|
|
@@ -14,14 +14,27 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import docSources from '../../../lib/docs/docSources.js';
|
|
17
18
|
import searchDocs from '../../../lib/docs/searchDocs.js';
|
|
18
19
|
|
|
19
20
|
function docsSearchHandler(c) {
|
|
20
21
|
const query = c.req.query('q');
|
|
22
|
+
const source = c.req.query('source');
|
|
21
23
|
if (!query || query.trim() === '') {
|
|
22
|
-
return c.json(
|
|
24
|
+
return c.json(
|
|
25
|
+
{ error: 'Missing search query. Use GET /lowdefy-docs/search?q=your+keywords.' },
|
|
26
|
+
400
|
|
27
|
+
);
|
|
23
28
|
}
|
|
24
|
-
|
|
29
|
+
if (source !== undefined && !docSources.includes(source)) {
|
|
30
|
+
return c.json(
|
|
31
|
+
{
|
|
32
|
+
error: `Unknown docs source "${source}". Use one of: ${docSources.join(', ')}.`,
|
|
33
|
+
},
|
|
34
|
+
400
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return c.json(searchDocs({ query, source }));
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
export default docsSearchHandler;
|
|
@@ -14,21 +14,35 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { parseRequestBody } from '@lowdefy/api';
|
|
18
|
+
|
|
17
19
|
import snapshotState from '../../../lib/docs/snapshotState.js';
|
|
18
20
|
|
|
19
21
|
// Lets an agent (or a developer) snapshot the running app's page state and
|
|
20
22
|
// recorded request/api responses into a checkpoint folder under .lowdefy,
|
|
21
23
|
// for later replay via POST /lowdefy-docs/state/load.
|
|
22
24
|
async function docsSnapshotStateHandler(c) {
|
|
23
|
-
const { pageId, name, notes, source, overwrite } =
|
|
25
|
+
const { pageId, pathParams, name, notes, source, overwrite } = parseRequestBody({
|
|
26
|
+
text: await c.req.text(),
|
|
27
|
+
});
|
|
24
28
|
// Derived from the incoming request rather than a config value — this is
|
|
25
29
|
// the origin an agent can actually reach the dev server on (host/port it
|
|
26
30
|
// just connected to), regardless of how the server is bound.
|
|
27
31
|
const origin = new URL(c.req.url).origin;
|
|
28
32
|
|
|
29
|
-
const result = await snapshotState({
|
|
33
|
+
const result = await snapshotState({
|
|
34
|
+
origin,
|
|
35
|
+
pageId,
|
|
36
|
+
pathParams,
|
|
37
|
+
name,
|
|
38
|
+
notes,
|
|
39
|
+
source,
|
|
40
|
+
overwrite,
|
|
41
|
+
});
|
|
30
42
|
if (result.error) {
|
|
31
|
-
|
|
43
|
+
// pathParams the page cannot be opened with are the caller's to fix, not a
|
|
44
|
+
// failed render.
|
|
45
|
+
return c.json({ error: result.error }, result.invalidInput ? 400 : 502);
|
|
32
46
|
}
|
|
33
47
|
return c.json(result);
|
|
34
48
|
}
|
package/src/routes/endpoints.js
CHANGED
|
@@ -14,55 +14,56 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
callEndpoint,
|
|
19
|
+
getEndpointConfig,
|
|
20
|
+
parseRequestBody,
|
|
21
|
+
runWebhookEndpoint,
|
|
22
|
+
} from '@lowdefy/api';
|
|
18
23
|
|
|
19
24
|
import getPathSegments from '../lib/getPathSegments.js';
|
|
20
25
|
|
|
21
26
|
async function endpointsHandler(c) {
|
|
22
27
|
if (c.req.method !== 'POST') {
|
|
23
|
-
|
|
28
|
+
// A wrong-method request is client-caused: answer 405 rather than raising a
|
|
29
|
+
// fault that would be logged at error level and answered with a 500.
|
|
30
|
+
return c.json({ error: 'Method not allowed.' }, 405);
|
|
24
31
|
}
|
|
25
32
|
const context = c.get('lowdefyContext');
|
|
26
33
|
const endpointId = getPathSegments(c, '/api/endpoints/').join('/');
|
|
27
34
|
|
|
28
|
-
// Endpoints opting in with `webhook
|
|
29
|
-
// (SNS, Event Grid, Stripe, ...): they take the
|
|
30
|
-
// caller's own format (not the { payload }
|
|
31
|
-
// and their return value is sent back
|
|
32
|
-
// (e.g. Event Grid's validationResponse)
|
|
33
|
-
// The config lookup is a cached file read; an
|
|
34
|
-
// to the standard path so its error shape is
|
|
35
|
-
// non-webhook endpoints is untouched.
|
|
35
|
+
// Endpoints opting in with `webhook` (true or a { verify } object) are
|
|
36
|
+
// third-party webhook receivers (SNS, Event Grid, Stripe, ...): they take the
|
|
37
|
+
// request RAW — body in the caller's own format (not the { payload }
|
|
38
|
+
// envelope), plus query + headers — and their return value is sent back
|
|
39
|
+
// verbatim, because webhook handshakes (e.g. Event Grid's validationResponse)
|
|
40
|
+
// require exact response shapes. The config lookup is a cached file read; an
|
|
41
|
+
// unknown endpoint falls through to the standard path so its error shape is
|
|
42
|
+
// unchanged. Everything about non-webhook endpoints is untouched.
|
|
36
43
|
let endpointConfig = null;
|
|
37
44
|
try {
|
|
38
45
|
endpointConfig = await getEndpointConfig(context, { endpointId });
|
|
39
46
|
} catch {
|
|
40
47
|
/* unknown endpoint — the standard path below reports it exactly as before */
|
|
41
48
|
}
|
|
42
|
-
if (endpointConfig?.webhook
|
|
43
|
-
// SNS posts JSON as text/plain — parse regardless of content-type; an
|
|
44
|
-
// unparseable body arrives as the raw string.
|
|
45
|
-
const raw = await c.req.text();
|
|
46
|
-
let body = raw;
|
|
47
|
-
try {
|
|
48
|
-
body = JSON.parse(raw);
|
|
49
|
-
} catch {
|
|
50
|
-
/* non-JSON body — raw string passthrough */
|
|
51
|
-
}
|
|
49
|
+
if (endpointConfig?.webhook) {
|
|
52
50
|
context.logger.info({ event: 'call_webhook_endpoint', endpointId });
|
|
53
|
-
const
|
|
51
|
+
const { status, body, contentType } = await runWebhookEndpoint(context, {
|
|
54
52
|
endpointId,
|
|
55
|
-
|
|
53
|
+
rawBody: await c.req.text(),
|
|
56
54
|
query: c.req.query(),
|
|
57
55
|
headers: c.req.header(),
|
|
58
56
|
});
|
|
59
|
-
if (
|
|
60
|
-
|
|
57
|
+
if (contentType === 'text/plain') {
|
|
58
|
+
// A text answer often echoes a value from the request (a handshake token), so the browser
|
|
59
|
+
// must not sniff it into HTML.
|
|
60
|
+
c.header('X-Content-Type-Options', 'nosniff');
|
|
61
|
+
return c.text(body, status);
|
|
61
62
|
}
|
|
62
|
-
return c.json(
|
|
63
|
+
return c.json(body, status);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
const { blockId, payload, pageId } = await c.req.
|
|
66
|
+
const { blockId, payload, pageId } = parseRequestBody({ text: await c.req.text() });
|
|
66
67
|
context.logger.info({ event: 'call_api_endpoint', blockId, endpointId, pageId });
|
|
67
68
|
const response = await callEndpoint(context, { blockId, endpointId, pageId, payload });
|
|
68
69
|
return c.json(response);
|