@lowdefy/server-dev 6.1.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +78 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +727 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/describeTargetKey.js +29 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +52 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +133 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +493 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +83 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +251 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sessionDatabaseName.js +32 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +36 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +225 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +12 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +81 -7
- package/lib/docs/getBuildStatus.test.mjs +229 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +92 -0
- package/lib/server/applyDataSetRedirect.test.mjs +446 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +207 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +134 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +331 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +115 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +25 -3
- package/manager/processes/initialBuild.mjs +17 -1
- package/manager/processes/initialBuild.test.mjs +104 -0
- package/manager/processes/lowdefyBuild.mjs +31 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +72 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
package/client/Routing.jsx
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import React, { Suspense, useEffect, useState } from 'react';
|
|
17
|
+
import React, { Suspense, useCallback, useEffect, useState } from 'react';
|
|
18
18
|
|
|
19
19
|
import Head from '@lowdefy/client/adapters/Head.js';
|
|
20
20
|
import createLinkComponent from '@lowdefy/client/adapters/Link.js';
|
|
@@ -23,10 +23,12 @@ import BuildingPage from '../lib/client/BuildingPage.jsx';
|
|
|
23
23
|
import RestartingPage from '../lib/client/RestartingPage.jsx';
|
|
24
24
|
import FeedbackMount from './feedback/FeedbackMount.jsx';
|
|
25
25
|
import Inspector from './Inspector.jsx';
|
|
26
|
+
import JourneyObserver from './JourneyObserver.jsx';
|
|
26
27
|
import OpenInEditorListener from './openInEditor/OpenInEditorListener.jsx';
|
|
28
|
+
import Recorder from './Recorder.jsx';
|
|
27
29
|
import Reload from './Reload.jsx';
|
|
28
30
|
import Page from './Page.jsx';
|
|
29
|
-
import
|
|
31
|
+
import getPagePath from '../lib/client/getPagePath.js';
|
|
30
32
|
import { bumpNavVersion, getReloadVersion } from '../lib/client/utils/useMutateCache.js';
|
|
31
33
|
import useRootConfig from '../lib/client/utils/useRootConfig.js';
|
|
32
34
|
|
|
@@ -39,12 +41,18 @@ import staticJsMap from '../build/plugins/operators/clientJsMap.js';
|
|
|
39
41
|
|
|
40
42
|
// Replaces lib/client/App.js — page resolution driven by the custom router
|
|
41
43
|
// instead of next/router, everything else preserved.
|
|
42
|
-
function Routing({ auth, lowdefy, router }) {
|
|
44
|
+
function Routing({ auth, lowdefy, recording, router }) {
|
|
43
45
|
const { data: rootConfig } = useRootConfig(router.basePath);
|
|
44
46
|
const [location, setLocation] = useState(() => router.getLocation());
|
|
45
47
|
|
|
46
48
|
useEffect(() => {
|
|
47
49
|
return router.subscribe((location) => {
|
|
50
|
+
// The URL already names the next page, but window.lowdefy.pageId and
|
|
51
|
+
// its context stay the previous page's until Page renders the next
|
|
52
|
+
// one. Marked here, synchronously inside the navigation (a Link in
|
|
53
|
+
// onInit included), so a headless caller waiting on isPageReady does
|
|
54
|
+
// not settle on the page being left. Page.jsx clears it.
|
|
55
|
+
lowdefy._devNavigating = true;
|
|
48
56
|
// Dynamic pages re-resolve per navigation — bump before setLocation so
|
|
49
57
|
// the page config SWR key changes with the navigation. The router
|
|
50
58
|
// notifies with a fresh location object per event, so same-URL
|
|
@@ -52,40 +60,55 @@ function Routing({ auth, lowdefy, router }) {
|
|
|
52
60
|
bumpNavVersion();
|
|
53
61
|
setLocation(location);
|
|
54
62
|
});
|
|
55
|
-
}, [router]);
|
|
63
|
+
}, [lowdefy, router]);
|
|
56
64
|
|
|
57
65
|
const [Link] = useState(() => createLinkComponent({ router }));
|
|
58
66
|
|
|
67
|
+
// The page instance on screen, { pageId, pathParams, instanceKey }, as the fetched page names
|
|
68
|
+
// it. null until the first page renders; it names the previous page while the next one fetches.
|
|
69
|
+
const [shownPage, setShownPage] = useState(null);
|
|
70
|
+
const onPageShown = useCallback((page) => {
|
|
71
|
+
setShownPage((current) => (current?.instanceKey === page.instanceKey ? current : page));
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
59
74
|
if (rootConfig?.theme) {
|
|
60
75
|
lowdefy.theme = rootConfig.theme;
|
|
61
76
|
}
|
|
62
77
|
|
|
63
|
-
|
|
78
|
+
// The page is fetched by path; the server says which page it is.
|
|
79
|
+
const { redirect, path } = getPagePath(location, rootConfig);
|
|
64
80
|
useEffect(() => {
|
|
65
81
|
if (redirect) {
|
|
66
|
-
router.replace({ pathname: `/${
|
|
82
|
+
router.replace({ pathname: `/${path}` });
|
|
67
83
|
}
|
|
68
|
-
}, [redirect,
|
|
84
|
+
}, [redirect, path, router]);
|
|
69
85
|
if (redirect) {
|
|
70
86
|
return '';
|
|
71
87
|
}
|
|
72
|
-
|
|
73
88
|
return (
|
|
74
89
|
<>
|
|
75
|
-
<FeedbackMount basePath={router.basePath} lowdefy={lowdefy}
|
|
76
|
-
<OpenInEditorListener basePath={router.basePath} pageId={pageId} />
|
|
90
|
+
<FeedbackMount basePath={router.basePath} lowdefy={lowdefy} page={shownPage} />
|
|
91
|
+
<OpenInEditorListener basePath={router.basePath} pageId={shownPage?.pageId} />
|
|
77
92
|
<Reload basePath={router.basePath} lowdefy={lowdefy}>
|
|
78
93
|
{(resetContext) => (
|
|
79
94
|
<>
|
|
80
95
|
{/* Inside Reload so it can share Reload's event stream (DevStreamContext). */}
|
|
81
|
-
<Inspector basePath={router.basePath} lowdefy={lowdefy}
|
|
96
|
+
<Inspector basePath={router.basePath} lowdefy={lowdefy} page={shownPage} />
|
|
97
|
+
<JourneyObserver lowdefy={lowdefy} />
|
|
98
|
+
<Recorder
|
|
99
|
+
basePath={router.basePath}
|
|
100
|
+
lowdefy={lowdefy}
|
|
101
|
+
page={shownPage}
|
|
102
|
+
path={path}
|
|
103
|
+
recording={recording}
|
|
104
|
+
/>
|
|
82
105
|
{/* Rendered here, not in Page — Page sits below the Suspense boundary
|
|
83
106
|
and cannot render anything while its config fetch is suspended, so
|
|
84
107
|
a restarting server would present as "Building page..." forever. */}
|
|
85
108
|
{resetContext.restarting ? (
|
|
86
109
|
<RestartingPage />
|
|
87
110
|
) : (
|
|
88
|
-
<Suspense key={`${
|
|
111
|
+
<Suspense key={`${path}_${getReloadVersion()}`} fallback={<BuildingPage />}>
|
|
89
112
|
<Page
|
|
90
113
|
auth={auth}
|
|
91
114
|
Components={{ Head, Link }}
|
|
@@ -94,7 +117,8 @@ function Routing({ auth, lowdefy, router }) {
|
|
|
94
117
|
}}
|
|
95
118
|
jsMap={staticJsMap}
|
|
96
119
|
lowdefy={lowdefy}
|
|
97
|
-
|
|
120
|
+
onPageShown={onPageShown}
|
|
121
|
+
path={path}
|
|
98
122
|
resetContext={resetContext}
|
|
99
123
|
router={router}
|
|
100
124
|
types={{
|
|
@@ -36,6 +36,8 @@ const allowed = new Set([
|
|
|
36
36
|
'plugins/icons.js',
|
|
37
37
|
'plugins/operators/client.js',
|
|
38
38
|
'plugins/operators/clientJsMap.js',
|
|
39
|
+
// The whole theme already reaches the browser in the root config.
|
|
40
|
+
'theme.json',
|
|
39
41
|
]);
|
|
40
42
|
|
|
41
43
|
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
|
|
21
|
+
const clientDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
|
|
23
|
+
function listSourceFiles(directory) {
|
|
24
|
+
return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
25
|
+
const full = path.join(directory, entry.name);
|
|
26
|
+
if (entry.isDirectory()) return listSourceFiles(full);
|
|
27
|
+
return /\.(js|jsx|mjs)$/.test(entry.name) && !entry.name.includes('.test.') ? [full] : [];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Dev serves HTTP/1.1, where a browser holds at most six connections per host.
|
|
32
|
+
// A second long-lived stream per tab once made dev pages load forever, so
|
|
33
|
+
// every dev channel shares Reload.jsx's one EventSource (DevStreamContext).
|
|
34
|
+
test('the dev client constructs exactly one EventSource, in Reload.jsx', () => {
|
|
35
|
+
const constructions = listSourceFiles(clientDirectory).flatMap((file) => {
|
|
36
|
+
const count = (fs.readFileSync(file, 'utf8').match(/new EventSource\(/g) ?? []).length;
|
|
37
|
+
return Array.from({ length: count }, () => path.relative(clientDirectory, file));
|
|
38
|
+
});
|
|
39
|
+
expect(constructions).toEqual(['Reload.jsx']);
|
|
40
|
+
});
|
|
@@ -53,7 +53,7 @@ const LazyOverlay = React.lazy(() => import('./FeedbackOverlay.jsx'));
|
|
|
53
53
|
// contract — nothing here may ever throw into the app it's riding along
|
|
54
54
|
// with. Stays inert until the developer presses Cmd/Ctrl+/, at which point
|
|
55
55
|
// the overlay mounts.
|
|
56
|
-
function FeedbackMount({ basePath, lowdefy,
|
|
56
|
+
function FeedbackMount({ basePath, lowdefy, page }) {
|
|
57
57
|
const [active, setActive] = useState(false);
|
|
58
58
|
|
|
59
59
|
useFeedbackToggle({
|
|
@@ -71,7 +71,7 @@ function FeedbackMount({ basePath, lowdefy, pageId }) {
|
|
|
71
71
|
<LazyOverlay
|
|
72
72
|
basePath={basePath}
|
|
73
73
|
lowdefy={lowdefy}
|
|
74
|
-
|
|
74
|
+
page={page}
|
|
75
75
|
onClose={() => setActive(false)}
|
|
76
76
|
/>
|
|
77
77
|
</Suspense>
|
|
@@ -188,12 +188,15 @@ function buildAnnotation(state) {
|
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
function buildBatch({ annotations, includeScreenshot,
|
|
191
|
+
function buildBatch({ annotations, includeScreenshot, page }) {
|
|
192
|
+
const pageId = page?.pageId;
|
|
193
|
+
const pathParams = page?.pathParams ?? {};
|
|
192
194
|
return {
|
|
193
195
|
batchId: generateId(),
|
|
194
196
|
timestamp: new Date().toISOString(),
|
|
195
197
|
pageId,
|
|
196
198
|
url: `${window.location.pathname}${window.location.search}`,
|
|
199
|
+
pathParams,
|
|
197
200
|
urlQuery: window.location.search,
|
|
198
201
|
viewport: {
|
|
199
202
|
width: window.innerWidth,
|
|
@@ -204,7 +207,7 @@ function buildBatch({ annotations, includeScreenshot, pageId }) {
|
|
|
204
207
|
},
|
|
205
208
|
annotations,
|
|
206
209
|
includeScreenshot,
|
|
207
|
-
stateRef: { captured: true, pageId },
|
|
210
|
+
stateRef: { captured: true, pageId, pathParams },
|
|
208
211
|
};
|
|
209
212
|
}
|
|
210
213
|
|
|
@@ -288,7 +291,7 @@ function renderShape(shape, key) {
|
|
|
288
291
|
// app down with it — event handlers are individually try/caught, and the
|
|
289
292
|
// whole render is wrapped so a bad state shape returns null rather than
|
|
290
293
|
// throwing into the app's React tree.
|
|
291
|
-
function FeedbackOverlay({ basePath,
|
|
294
|
+
function FeedbackOverlay({ basePath, page, onClose }) {
|
|
292
295
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
293
296
|
const primarySendRef = useRef(null);
|
|
294
297
|
const stateRef = useRef(state);
|
|
@@ -624,7 +627,7 @@ function FeedbackOverlay({ basePath, pageId, onClose }) {
|
|
|
624
627
|
const batch = buildBatch({
|
|
625
628
|
annotations,
|
|
626
629
|
includeScreenshot: current.includeScreenshot,
|
|
627
|
-
|
|
630
|
+
page,
|
|
628
631
|
});
|
|
629
632
|
// Capture the annotated screenshot in THIS tab — the pixels the
|
|
630
633
|
// developer is actually looking at (theme, loaded data) — and ship it
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
// above ErrorBar.jsx (bottom: 40px, zIndex 99999) but under nothing — this
|
|
19
19
|
// overlay is the topmost thing on the page while active.
|
|
20
20
|
|
|
21
|
+
import getCspNonce from '../../lib/client/getCspNonce.js';
|
|
22
|
+
|
|
21
23
|
const STYLE_TAG_ID = 'lowdefy-feedback-style-tag';
|
|
22
24
|
|
|
23
25
|
const colors = {
|
|
@@ -248,6 +250,7 @@ function injectFeedbackStyleTag() {
|
|
|
248
250
|
}
|
|
249
251
|
const style = document.createElement('style');
|
|
250
252
|
style.id = STYLE_TAG_ID;
|
|
253
|
+
style.nonce = getCspNonce();
|
|
251
254
|
style.textContent = `
|
|
252
255
|
.lowdefy-feedback-picking, .lowdefy-feedback-picking * {
|
|
253
256
|
cursor: crosshair !important;
|
|
@@ -0,0 +1,101 @@
|
|
|
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
|
+
const OBSERVE_BINDING = '__lowdefyJourneyObserve';
|
|
18
|
+
|
|
19
|
+
// Reports what a journey's page runs to the journey runner, through the
|
|
20
|
+
// binding the runner exposes on its own browser contexts only
|
|
21
|
+
// (lib/docs/createJourneyActors.js): every completed Lowdefy event from the
|
|
22
|
+
// engine's trace hook, and every block once it becomes visible, sampled in
|
|
23
|
+
// the animation frame after any DOM change so a message shown and cleared
|
|
24
|
+
// within one step is still seen. In a developer's tab there is no binding,
|
|
25
|
+
// and it does nothing. Returns a stop function, or null when it did not
|
|
26
|
+
// start. Never throws into the app: every callback is wrapped.
|
|
27
|
+
function startJourneyObserver({ window, lowdefy, getTrace, collectVisibleBlockIds }) {
|
|
28
|
+
const observe = window[OBSERVE_BINDING];
|
|
29
|
+
if (typeof observe !== 'function') {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function forward(message) {
|
|
34
|
+
try {
|
|
35
|
+
Promise.resolve(observe(message)).catch(() => {});
|
|
36
|
+
} catch {
|
|
37
|
+
// The binding is gone with its context; nothing to report to.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// The hook emits only completed events: bounced debounces and handledBy
|
|
42
|
+
// returns never arrive, so nothing is filtered here.
|
|
43
|
+
const unsubscribe = getTrace(lowdefy).subscribe((payload) => {
|
|
44
|
+
try {
|
|
45
|
+
forward({
|
|
46
|
+
kind: 'event',
|
|
47
|
+
scope: payload.scope,
|
|
48
|
+
pageId: payload.pageId,
|
|
49
|
+
blockId: payload.blockId,
|
|
50
|
+
eventName: payload.eventName,
|
|
51
|
+
actionIds: (payload.actions ?? []).map((action) => action?.id),
|
|
52
|
+
});
|
|
53
|
+
} catch {
|
|
54
|
+
// A payload this observer cannot read is skipped.
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const sent = new Set();
|
|
59
|
+
let frame = null;
|
|
60
|
+
function sample() {
|
|
61
|
+
frame = null;
|
|
62
|
+
try {
|
|
63
|
+
const pageId = lowdefy.pageId;
|
|
64
|
+
const fresh = collectVisibleBlockIds().filter(
|
|
65
|
+
(blockId) => !sent.has(JSON.stringify([pageId, blockId]))
|
|
66
|
+
);
|
|
67
|
+
if (fresh.length === 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
fresh.forEach((blockId) => sent.add(JSON.stringify([pageId, blockId])));
|
|
71
|
+
forward({ kind: 'rendered', pageId, blockIds: fresh });
|
|
72
|
+
} catch {
|
|
73
|
+
// Sampled again on the next change.
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const observer = new window.MutationObserver(() => {
|
|
78
|
+
if (frame === null) {
|
|
79
|
+
frame = window.requestAnimationFrame(sample);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Attributes too: antd shows and hides a modal or an alert by its style and
|
|
83
|
+
// class, without adding or removing nodes.
|
|
84
|
+
observer.observe(window.document.body, {
|
|
85
|
+
attributes: true,
|
|
86
|
+
characterData: true,
|
|
87
|
+
childList: true,
|
|
88
|
+
subtree: true,
|
|
89
|
+
});
|
|
90
|
+
sample();
|
|
91
|
+
|
|
92
|
+
return function stop() {
|
|
93
|
+
unsubscribe();
|
|
94
|
+
observer.disconnect();
|
|
95
|
+
if (frame !== null) {
|
|
96
|
+
window.cancelAnimationFrame(frame);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default startJourneyObserver;
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
import startJourneyObserver from './startJourneyObserver.js';
|
|
20
|
+
|
|
21
|
+
function createFakeWindow({ binding } = {}) {
|
|
22
|
+
const observers = [];
|
|
23
|
+
const frames = [];
|
|
24
|
+
class FakeMutationObserver {
|
|
25
|
+
constructor(callback) {
|
|
26
|
+
this.callback = callback;
|
|
27
|
+
this.disconnect = jest.fn();
|
|
28
|
+
this.observe = jest.fn();
|
|
29
|
+
observers.push(this);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const window = {
|
|
33
|
+
document: { body: {} },
|
|
34
|
+
MutationObserver: FakeMutationObserver,
|
|
35
|
+
requestAnimationFrame: jest.fn((callback) => {
|
|
36
|
+
frames.push(callback);
|
|
37
|
+
return frames.length;
|
|
38
|
+
}),
|
|
39
|
+
cancelAnimationFrame: jest.fn(),
|
|
40
|
+
};
|
|
41
|
+
if (binding !== undefined) {
|
|
42
|
+
window.__lowdefyJourneyObserve = binding;
|
|
43
|
+
}
|
|
44
|
+
function mutate() {
|
|
45
|
+
observers.forEach((observer) => observer.callback([]));
|
|
46
|
+
}
|
|
47
|
+
function runFrames() {
|
|
48
|
+
frames.splice(0).forEach((callback) => callback());
|
|
49
|
+
}
|
|
50
|
+
return { window, observers, mutate, runFrames };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createFakeTrace() {
|
|
54
|
+
const unsubscribe = jest.fn();
|
|
55
|
+
const trace = { subscribe: jest.fn(() => unsubscribe) };
|
|
56
|
+
return { getTrace: jest.fn(() => trace), trace, unsubscribe };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
test('startJourneyObserver does nothing in a developer tab, where there is no binding', () => {
|
|
60
|
+
const { window, observers } = createFakeWindow();
|
|
61
|
+
const { getTrace, trace } = createFakeTrace();
|
|
62
|
+
const stop = startJourneyObserver({
|
|
63
|
+
window,
|
|
64
|
+
lowdefy: { pageId: 'home' },
|
|
65
|
+
getTrace,
|
|
66
|
+
collectVisibleBlockIds: jest.fn(() => ['a']),
|
|
67
|
+
});
|
|
68
|
+
expect(stop).toBeNull();
|
|
69
|
+
expect(trace.subscribe).not.toHaveBeenCalled();
|
|
70
|
+
expect(observers).toHaveLength(0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('startJourneyObserver forwards completed events and each newly visible block once', () => {
|
|
74
|
+
const binding = jest.fn(async () => {});
|
|
75
|
+
const { window, observers, mutate, runFrames } = createFakeWindow({ binding });
|
|
76
|
+
const { getTrace, trace, unsubscribe } = createFakeTrace();
|
|
77
|
+
const lowdefy = { pageId: 'home' };
|
|
78
|
+
let visible = ['home_title'];
|
|
79
|
+
const stop = startJourneyObserver({
|
|
80
|
+
window,
|
|
81
|
+
lowdefy,
|
|
82
|
+
getTrace,
|
|
83
|
+
collectVisibleBlockIds: () => visible,
|
|
84
|
+
});
|
|
85
|
+
expect(getTrace).toHaveBeenCalledWith(lowdefy);
|
|
86
|
+
// Subscribed without state: the observer never reads it.
|
|
87
|
+
expect(trace.subscribe.mock.calls[0]).toHaveLength(1);
|
|
88
|
+
expect(binding).toHaveBeenCalledWith({
|
|
89
|
+
kind: 'rendered',
|
|
90
|
+
pageId: 'home',
|
|
91
|
+
blockIds: ['home_title'],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const listener = trace.subscribe.mock.calls[0][0];
|
|
95
|
+
listener({
|
|
96
|
+
scope: 'page',
|
|
97
|
+
pageId: 'home',
|
|
98
|
+
blockId: 'save_button',
|
|
99
|
+
blockType: 'Button',
|
|
100
|
+
eventName: 'onClick',
|
|
101
|
+
actions: [{ id: 'save' }, { id: 'set_saved' }],
|
|
102
|
+
record: {},
|
|
103
|
+
});
|
|
104
|
+
expect(binding).toHaveBeenLastCalledWith({
|
|
105
|
+
kind: 'event',
|
|
106
|
+
scope: 'page',
|
|
107
|
+
pageId: 'home',
|
|
108
|
+
blockId: 'save_button',
|
|
109
|
+
eventName: 'onClick',
|
|
110
|
+
actionIds: ['save', 'set_saved'],
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Two changes before the next frame sample once; only the new block is sent.
|
|
114
|
+
visible = ['home_title', 'flash_alert'];
|
|
115
|
+
mutate();
|
|
116
|
+
mutate();
|
|
117
|
+
expect(window.requestAnimationFrame).toHaveBeenCalledTimes(1);
|
|
118
|
+
runFrames();
|
|
119
|
+
expect(binding).toHaveBeenLastCalledWith({
|
|
120
|
+
kind: 'rendered',
|
|
121
|
+
pageId: 'home',
|
|
122
|
+
blockIds: ['flash_alert'],
|
|
123
|
+
});
|
|
124
|
+
const calls = binding.mock.calls.length;
|
|
125
|
+
mutate();
|
|
126
|
+
runFrames();
|
|
127
|
+
expect(binding.mock.calls).toHaveLength(calls);
|
|
128
|
+
|
|
129
|
+
stop();
|
|
130
|
+
expect(unsubscribe).toHaveBeenCalled();
|
|
131
|
+
expect(observers[0].disconnect).toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('startJourneyObserver keeps the app running when the binding or a payload throws', () => {
|
|
135
|
+
const binding = jest.fn(() => {
|
|
136
|
+
throw new Error('context closed');
|
|
137
|
+
});
|
|
138
|
+
const { window } = createFakeWindow({ binding });
|
|
139
|
+
const { getTrace, trace } = createFakeTrace();
|
|
140
|
+
startJourneyObserver({
|
|
141
|
+
window,
|
|
142
|
+
lowdefy: { pageId: 'home' },
|
|
143
|
+
getTrace,
|
|
144
|
+
collectVisibleBlockIds: () => ['a'],
|
|
145
|
+
});
|
|
146
|
+
const listener = trace.subscribe.mock.calls[0][0];
|
|
147
|
+
expect(() => listener(null)).not.toThrow();
|
|
148
|
+
expect(() => listener({ scope: 'page', actions: [] })).not.toThrow();
|
|
149
|
+
});
|
|
@@ -20,6 +20,7 @@ import { createPortal } from 'react-dom';
|
|
|
20
20
|
import { blockAncestorChain, nearestBlock } from '../feedback/elementInspect.js';
|
|
21
21
|
import { highlightBox, labelChip, overlayContainer } from '../feedback/feedbackStyles.js';
|
|
22
22
|
import findBlockLocation from './findBlockLocation.js';
|
|
23
|
+
import getCspNonce from '../../lib/client/getCspNonce.js';
|
|
23
24
|
|
|
24
25
|
const STYLE_TAG_ID = 'lowdefy-open-in-editor-style-tag';
|
|
25
26
|
const BODY_CLASS = 'lowdefy-open-in-editor-target';
|
|
@@ -32,6 +33,7 @@ function injectStyleTag() {
|
|
|
32
33
|
}
|
|
33
34
|
const style = document.createElement('style');
|
|
34
35
|
style.id = STYLE_TAG_ID;
|
|
36
|
+
style.nonce = getCspNonce();
|
|
35
37
|
style.textContent = `
|
|
36
38
|
.${BODY_CLASS}, .${BODY_CLASS} * {
|
|
37
39
|
cursor: pointer !important;
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
// An engine event no interaction caused (a mount event, an app event, a
|
|
18
|
+
// programmatic or off-path event) as a v1 trace record of kind engine. The
|
|
19
|
+
// compiler decides what each compiles to.
|
|
20
|
+
function buildEngineRecord({ engineEvent, session, roles }) {
|
|
21
|
+
return {
|
|
22
|
+
v: 1,
|
|
23
|
+
session,
|
|
24
|
+
t: new Date(engineEvent.startTimestamp).toISOString(),
|
|
25
|
+
kind: 'engine',
|
|
26
|
+
scope: engineEvent.scope,
|
|
27
|
+
page_id: engineEvent.pageId,
|
|
28
|
+
roles: roles ?? [],
|
|
29
|
+
person: null,
|
|
30
|
+
org: null,
|
|
31
|
+
target: null,
|
|
32
|
+
event: engineEvent.traceEvent,
|
|
33
|
+
build: engineEvent.build ?? null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default buildEngineRecord;
|
|
@@ -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 { type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
// describeElement's result without what a record keeps elsewhere: the page
|
|
20
|
+
// sits on the record and the enclosing block ids feed pairing only.
|
|
21
|
+
function recordTarget(target) {
|
|
22
|
+
if (type.isNone(target)) return null;
|
|
23
|
+
const { page_id: _pageId, block_ids: _blockIds, ...rest } = target;
|
|
24
|
+
return rest;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// A DOM interaction as a v1 trace record. `paired` are the trace events the
|
|
28
|
+
// pairing rule gave it, innermost first: the first is `event`, the rest go to
|
|
29
|
+
// `also`. `build` is the build of the page config the interaction happened
|
|
30
|
+
// on; `source` and `run` are stamped by the dev server, never the page.
|
|
31
|
+
function buildInteractionRecord({ interaction, paired = [], session, roles }) {
|
|
32
|
+
const record = {
|
|
33
|
+
v: 1,
|
|
34
|
+
session,
|
|
35
|
+
t: new Date(interaction.t).toISOString(),
|
|
36
|
+
kind: interaction.kind,
|
|
37
|
+
scope: 'page',
|
|
38
|
+
page_id: interaction.target?.page_id ?? interaction.pageId,
|
|
39
|
+
roles: roles ?? [],
|
|
40
|
+
person: null,
|
|
41
|
+
org: null,
|
|
42
|
+
target: recordTarget(interaction.target),
|
|
43
|
+
event: paired[0] ?? null,
|
|
44
|
+
build: interaction.build ?? null,
|
|
45
|
+
};
|
|
46
|
+
if (paired.length > 1) {
|
|
47
|
+
record.also = paired.slice(1);
|
|
48
|
+
}
|
|
49
|
+
if (interaction.kind === 'pageview') {
|
|
50
|
+
record.url = interaction.url;
|
|
51
|
+
if (!type.isNone(interaction.pathParams)) {
|
|
52
|
+
record.path_params = interaction.pathParams;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (interaction.kind === 'change') {
|
|
56
|
+
record.value = interaction.value ?? null;
|
|
57
|
+
}
|
|
58
|
+
if (interaction.kind === 'key') {
|
|
59
|
+
record.key = interaction.key;
|
|
60
|
+
}
|
|
61
|
+
return record;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default buildInteractionRecord;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
import collectEventActions from './collectEventActions.js';
|
|
20
|
+
import collectEventEndpoints from './collectEventEndpoints.js';
|
|
21
|
+
import collectEventRequests from './collectEventRequests.js';
|
|
22
|
+
import diffStateWrites from './diffStateWrites.js';
|
|
23
|
+
|
|
24
|
+
// One completed engine event as a trace record's `event` (or `also` entry),
|
|
25
|
+
// built from the engine's trace payload the moment it arrives: the state the
|
|
26
|
+
// event wrote is the difference between the copy taken before its actions ran
|
|
27
|
+
// and the state now, which later events would change.
|
|
28
|
+
function buildTraceEvent({ payload, urlAfter }) {
|
|
29
|
+
const { context, failure, record } = payload;
|
|
30
|
+
const responses = record?.responses ?? {};
|
|
31
|
+
const event = {
|
|
32
|
+
name: payload.eventName,
|
|
33
|
+
block_id: payload.blockId,
|
|
34
|
+
success: payload.success,
|
|
35
|
+
actions: collectEventActions({ responses }),
|
|
36
|
+
requests: collectEventRequests({ blockId: payload.blockId, context, responses }),
|
|
37
|
+
endpoints: collectEventEndpoints({ blockId: payload.blockId, context, responses }),
|
|
38
|
+
state_writes: diffStateWrites({
|
|
39
|
+
before: payload.stateBefore,
|
|
40
|
+
after: context?.state,
|
|
41
|
+
values: true,
|
|
42
|
+
}),
|
|
43
|
+
url_after: urlAfter ?? null,
|
|
44
|
+
};
|
|
45
|
+
if (!type.isNone(failure)) {
|
|
46
|
+
event.error = {
|
|
47
|
+
name: failure.errorName ?? 'Error',
|
|
48
|
+
config_key: failure.configKey ?? null,
|
|
49
|
+
action_type: failure.actionType ?? null,
|
|
50
|
+
action_id: failure.actionId ?? null,
|
|
51
|
+
};
|
|
52
|
+
event.invalid_blocks = failure.invalidBlocks ?? [];
|
|
53
|
+
}
|
|
54
|
+
return event;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default buildTraceEvent;
|