@lowdefy/server-dev 6.1.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +67 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +679 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/findCollectionCollisions.js +52 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +44 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +119 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +343 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +68 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +220 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +33 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +203 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +8 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +54 -6
- package/lib/docs/getBuildStatus.test.mjs +133 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +83 -0
- package/lib/server/applyDataSetRedirect.test.mjs +340 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +204 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +131 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +328 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +112 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +24 -2
- package/manager/processes/initialBuild.mjs +14 -0
- package/manager/processes/initialBuild.test.mjs +101 -0
- package/manager/processes/lowdefyBuild.mjs +30 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +62 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,56 @@
|
|
|
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 {
|
|
18
|
+
buildSessionReport,
|
|
19
|
+
formatSessionReport,
|
|
20
|
+
parseSince,
|
|
21
|
+
readRecordings,
|
|
22
|
+
} from '@lowdefy/node-utils';
|
|
23
|
+
import { type } from '@lowdefy/helpers';
|
|
24
|
+
|
|
25
|
+
import { getConfigDirectory } from './checkpointPaths.js';
|
|
26
|
+
import readBuildArtifact from './readBuildArtifact.js';
|
|
27
|
+
|
|
28
|
+
function describeEmpty() {
|
|
29
|
+
if (process.env.LOWDEFY_DEV_RECORD === 'false') {
|
|
30
|
+
return 'No recorded dev sessions: recording is off (LOWDEFY_DEV_RECORD=false).';
|
|
31
|
+
}
|
|
32
|
+
return 'No recorded dev sessions in this window.';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// What lowdefy_journey_session answers, as `lowdefy journeys session` prints
|
|
36
|
+
// it: without an id, the dev sessions this app recorded, newest first; with
|
|
37
|
+
// one, that session's log. Returns { text } or { error }.
|
|
38
|
+
function readJourneySession({ id, since, now = Date.now() }) {
|
|
39
|
+
const start = type.isNone(since) ? undefined : parseSince({ since, now });
|
|
40
|
+
const records = readRecordings({
|
|
41
|
+
configDirectory: getConfigDirectory(),
|
|
42
|
+
source: 'dev',
|
|
43
|
+
since: type.isUndefined(start) ? undefined : new Date(start),
|
|
44
|
+
}).filter((record) => type.isUndefined(start) || Date.parse(record?.t) >= start);
|
|
45
|
+
const report = buildSessionReport({
|
|
46
|
+
records,
|
|
47
|
+
id,
|
|
48
|
+
blockMetas: readBuildArtifact({ name: 'plugins/blockMetas.json' }) ?? {},
|
|
49
|
+
});
|
|
50
|
+
if (!type.isUndefined(report.error)) {
|
|
51
|
+
return { error: report.error };
|
|
52
|
+
}
|
|
53
|
+
return { text: formatSessionReport({ report, empty: describeEmpty() }).join('\n') };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default readJourneySession;
|
|
@@ -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
|
+
import fs from 'fs';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
|
|
20
|
+
import getMailOutboxDirectory from './getMailOutboxDirectory.js';
|
|
21
|
+
|
|
22
|
+
// The messages the dev mail sink has captured this session, oldest first. The
|
|
23
|
+
// sink names each file by its receive sequence and writes it in one rename, so
|
|
24
|
+
// a listing never sees half a message.
|
|
25
|
+
async function readMailOutbox({ configDirectory }) {
|
|
26
|
+
const directory = getMailOutboxDirectory({ configDirectory });
|
|
27
|
+
const fileNames = (await fs.promises.readdir(directory))
|
|
28
|
+
.filter((fileName) => fileName.endsWith('.json'))
|
|
29
|
+
.sort();
|
|
30
|
+
return Promise.all(
|
|
31
|
+
fileNames.map(async (fileName) =>
|
|
32
|
+
JSON.parse(await fs.promises.readFile(path.join(directory, fileName), 'utf8'))
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default readMailOutbox;
|
|
@@ -0,0 +1,27 @@
|
|
|
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 readBuildArtifact from './readBuildArtifact.js';
|
|
18
|
+
|
|
19
|
+
// A page's path pattern, from the route table the skeleton build writes. A page
|
|
20
|
+
// the table does not hold has none, so its URL is its id, which the server
|
|
21
|
+
// answers as it answers any unknown page.
|
|
22
|
+
function readPagePath({ pageId }) {
|
|
23
|
+
const routes = readBuildArtifact({ name: 'routes.json', deserialize: true });
|
|
24
|
+
return routes.find((route) => route.pageId === pageId)?.path;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default readPagePath;
|
|
@@ -0,0 +1,99 @@
|
|
|
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 readBuildArtifact from './readBuildArtifact.js';
|
|
18
|
+
|
|
19
|
+
function addTypes({ plugins, store, kind }) {
|
|
20
|
+
for (const [typeName, definition] of Object.entries(store ?? {})) {
|
|
21
|
+
if (!plugins[definition.package]) {
|
|
22
|
+
plugins[definition.package] = {
|
|
23
|
+
package: definition.package,
|
|
24
|
+
version: definition.version,
|
|
25
|
+
types: {},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const plugin = plugins[definition.package];
|
|
29
|
+
if (!plugin.types[kind]) {
|
|
30
|
+
plugin.types[kind] = [];
|
|
31
|
+
}
|
|
32
|
+
plugin.types[kind].push(typeName);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Icon sets are keyed by set id, with one layer per plugin that declares it.
|
|
37
|
+
function addIconSets({ plugins, iconSets }) {
|
|
38
|
+
for (const [setId, layers] of Object.entries(iconSets ?? {})) {
|
|
39
|
+
for (const layer of layers) {
|
|
40
|
+
addTypes({ plugins, store: { [setId]: layer }, kind: 'iconSets' });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readPluginPackages() {
|
|
46
|
+
const availableTypes = readBuildArtifact({ name: 'plugins/availableTypes.json' }) ?? {};
|
|
47
|
+
const customTypesMap = readBuildArtifact({ name: 'customTypesMap.json' }) ?? {};
|
|
48
|
+
const installedPackages = readBuildArtifact({ name: 'installedPluginPackages.json' }) ?? [];
|
|
49
|
+
|
|
50
|
+
const plugins = {};
|
|
51
|
+
addTypes({ plugins, store: availableTypes.actions, kind: 'actions' });
|
|
52
|
+
addTypes({ plugins, store: availableTypes.agents, kind: 'agents' });
|
|
53
|
+
addTypes({ plugins, store: availableTypes.blocks, kind: 'blocks' });
|
|
54
|
+
addTypes({ plugins, store: availableTypes.connections, kind: 'connections' });
|
|
55
|
+
addTypes({ plugins, store: availableTypes.notifications, kind: 'notifications' });
|
|
56
|
+
addTypes({ plugins, store: availableTypes.operators?.client, kind: 'operators' });
|
|
57
|
+
addTypes({ plugins, store: availableTypes.operators?.server, kind: 'operators' });
|
|
58
|
+
addTypes({ plugins, store: availableTypes.requests, kind: 'requests' });
|
|
59
|
+
addTypes({ plugins, store: availableTypes.websockets, kind: 'websockets' });
|
|
60
|
+
addIconSets({ plugins, iconSets: customTypesMap.iconSets });
|
|
61
|
+
|
|
62
|
+
const customPackages = new Set();
|
|
63
|
+
const customStores = [
|
|
64
|
+
customTypesMap.actions,
|
|
65
|
+
customTypesMap.agents,
|
|
66
|
+
customTypesMap.blocks,
|
|
67
|
+
customTypesMap.connections,
|
|
68
|
+
customTypesMap.operators?.client,
|
|
69
|
+
customTypesMap.operators?.server,
|
|
70
|
+
customTypesMap.requests,
|
|
71
|
+
customTypesMap.websockets,
|
|
72
|
+
];
|
|
73
|
+
for (const store of customStores) {
|
|
74
|
+
for (const definition of Object.values(store ?? {})) {
|
|
75
|
+
customPackages.add(definition.package);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const layers of Object.values(customTypesMap.iconSets ?? {})) {
|
|
79
|
+
for (const layer of layers) {
|
|
80
|
+
customPackages.add(layer.package);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Object.values(plugins)
|
|
85
|
+
.map((plugin) => ({
|
|
86
|
+
...plugin,
|
|
87
|
+
custom: customPackages.has(plugin.package),
|
|
88
|
+
installed: installedPackages.includes(plugin.package),
|
|
89
|
+
types: Object.fromEntries(
|
|
90
|
+
Object.entries(plugin.types).map(([kind, typeNames]) => [
|
|
91
|
+
kind,
|
|
92
|
+
[...new Set(typeNames)].sort(),
|
|
93
|
+
])
|
|
94
|
+
),
|
|
95
|
+
}))
|
|
96
|
+
.sort((a, b) => a.package.localeCompare(b.package));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default readPluginPackages;
|
|
@@ -0,0 +1,38 @@
|
|
|
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 buildWaitHeader from './buildWaitHeader.js';
|
|
20
|
+
|
|
21
|
+
// A build can restart this process, which ends any wait running in it, so
|
|
22
|
+
// the manager's proxy waits for builds and restarts before it forwards a
|
|
23
|
+
// build-status wait, and passes what it saw in this header. Null when the
|
|
24
|
+
// request did not come through that wait.
|
|
25
|
+
function readProxyBuildWait({ getHeader }) {
|
|
26
|
+
const header = getHeader(buildWaitHeader);
|
|
27
|
+
if (type.isNone(header)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const params = new URLSearchParams(header);
|
|
31
|
+
return {
|
|
32
|
+
settled: params.get('settled') === 'true',
|
|
33
|
+
sawBuild: params.get('sawBuild') === 'true',
|
|
34
|
+
waitedMs: Number(params.get('waitedMs')),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default readProxyBuildWait;
|
|
@@ -0,0 +1,45 @@
|
|
|
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 isRoutineStep from '../server/isRoutineStep.js';
|
|
20
|
+
|
|
21
|
+
// Every step of an endpoint routine, at any depth: steps sit in arrays, and
|
|
22
|
+
// control objects (`:if`, `:try`, `:parallel`, ...) hold more arrays of steps
|
|
23
|
+
// under their `:` keys. A step's own properties are data, never more steps.
|
|
24
|
+
function readRoutineSteps({ routine }) {
|
|
25
|
+
const steps = [];
|
|
26
|
+
function walk(node) {
|
|
27
|
+
if (type.isArray(node)) {
|
|
28
|
+
node.forEach(walk);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (isRoutineStep(node)) {
|
|
32
|
+
steps.push(node);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (type.isObject(node)) {
|
|
36
|
+
Object.keys(node)
|
|
37
|
+
.filter((key) => key.startsWith(':'))
|
|
38
|
+
.forEach((key) => walk(node[key]));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
walk(routine);
|
|
42
|
+
return steps;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default readRoutineSteps;
|
|
@@ -0,0 +1,118 @@
|
|
|
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 { SHOWN_TEXT_ENGINE } from './shownTextSelector.js';
|
|
18
|
+
|
|
19
|
+
// The selector engine a `containing` target is found by: the innermost
|
|
20
|
+
// elements whose shown text contains the string. Playwright's getByText reads
|
|
21
|
+
// an element's text nodes joined with nothing between them, so a label and
|
|
22
|
+
// value that only layout separates (`<span>Assigned to</span><b>Jane</b>` in a
|
|
23
|
+
// flex row, table cells, block children) read as "Assigned toJane" and match
|
|
24
|
+
// nothing. innerText is the text as the page lays it out, with a break between
|
|
25
|
+
// block-level boxes. Like getByText, matching collapses whitespace and ignores
|
|
26
|
+
// case, and an element matches only when none of its children does, so a
|
|
27
|
+
// strict target still names one element and not its every ancestor.
|
|
28
|
+
//
|
|
29
|
+
// Playwright serialises the function and runs it in the page, so everything
|
|
30
|
+
// it uses is inside it. The selector body is a JSON string, so `>>` or quotes
|
|
31
|
+
// in the text never split the selector.
|
|
32
|
+
function createShownTextEngine() {
|
|
33
|
+
const SKIPPED = new Set(['HEAD', 'SCRIPT', 'STYLE', 'NOSCRIPT', 'TEMPLATE']);
|
|
34
|
+
const BUTTON_INPUTS = 'input[type=button], input[type=submit]';
|
|
35
|
+
|
|
36
|
+
function normalize(text) {
|
|
37
|
+
return text
|
|
38
|
+
.replace(/[\u200b\u00ad]/g, '')
|
|
39
|
+
.replace(/\s+/g, ' ')
|
|
40
|
+
.trim()
|
|
41
|
+
.toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// innerText only adds whitespace to textContent and drops hidden text, so an
|
|
45
|
+
// element whose textContent, spaces removed, lacks the string, spaces
|
|
46
|
+
// removed, cannot match. This check skips the layout innerText costs on
|
|
47
|
+
// almost every element.
|
|
48
|
+
function squash(text) {
|
|
49
|
+
return text.replace(/[\s\u200b\u00ad]/g, '').toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function queryAll(root, selector) {
|
|
53
|
+
const needle = normalize(JSON.parse(selector));
|
|
54
|
+
const squashed = squash(needle);
|
|
55
|
+
const matches = [];
|
|
56
|
+
// Children are visited first: an element with a matching child is no match
|
|
57
|
+
// itself and needs no innerText, so innerText is read only on the
|
|
58
|
+
// innermost candidates, not on every ancestor up to <html>.
|
|
59
|
+
function visit(element) {
|
|
60
|
+
if (SKIPPED.has(element.tagName) || !squash(element.textContent ?? '').includes(squashed)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
let childMatches = false;
|
|
64
|
+
for (const child of element.children) {
|
|
65
|
+
if (visit(child)) {
|
|
66
|
+
childMatches = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (childMatches) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (!normalize(element.innerText ?? element.textContent ?? '').includes(needle)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
matches.push(element);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
const start = root.nodeType === Node.DOCUMENT_NODE ? root.documentElement : root;
|
|
79
|
+
if (start) {
|
|
80
|
+
visit(start);
|
|
81
|
+
// A button input shows its value, which no textContent holds, so it is
|
|
82
|
+
// looked for apart from the walk, as getByText finds it.
|
|
83
|
+
const inputs = [
|
|
84
|
+
...(start.matches?.(BUTTON_INPUTS) ? [start] : []),
|
|
85
|
+
...start.querySelectorAll(BUTTON_INPUTS),
|
|
86
|
+
];
|
|
87
|
+
for (const input of inputs) {
|
|
88
|
+
if (normalize(input.value).includes(needle)) {
|
|
89
|
+
matches.push(input);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return matches;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
query(root, selector) {
|
|
98
|
+
return queryAll(root, selector)[0] ?? null;
|
|
99
|
+
},
|
|
100
|
+
queryAll,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let registered = null;
|
|
105
|
+
|
|
106
|
+
// Registers the engine with Playwright once per process. Playwright applies a
|
|
107
|
+
// registered engine to every browser context, open or yet to be created.
|
|
108
|
+
function registerShownTextEngine(selectors) {
|
|
109
|
+
if (registered === null) {
|
|
110
|
+
registered = selectors.register(SHOWN_TEXT_ENGINE, createShownTextEngine).catch((error) => {
|
|
111
|
+
registered = null;
|
|
112
|
+
throw error;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return registered;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export default registerShownTextEngine;
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
|
|
20
|
+
// The manager's child is the Vite process, not this Hono app, so there is no
|
|
21
|
+
// IPC channel back to the manager. Like build/reload and build/invalidatePages,
|
|
22
|
+
// a sentinel file in the build directory is the channel: the manager watches
|
|
23
|
+
// for .restart and restarts the server when it appears.
|
|
24
|
+
function requestRestart({ reason }) {
|
|
25
|
+
const filePath = path.join(process.cwd(), 'build', '.restart');
|
|
26
|
+
fs.writeFileSync(filePath, JSON.stringify({ requestedAt: new Date().toISOString(), reason }));
|
|
27
|
+
return { requested: true, reason };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default requestRestart;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'fs';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
|
|
21
|
+
const originalCwd = process.cwd();
|
|
22
|
+
const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-request-restart-test-'));
|
|
23
|
+
fs.mkdirSync(path.join(fixtureDir, 'build'), { recursive: true });
|
|
24
|
+
process.chdir(fixtureDir);
|
|
25
|
+
|
|
26
|
+
const { default: requestRestart } = await import('./requestRestart.js');
|
|
27
|
+
|
|
28
|
+
afterAll(() => {
|
|
29
|
+
process.chdir(originalCwd);
|
|
30
|
+
fs.rmSync(fixtureDir, { recursive: true, force: true });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('requestRestart writes the .restart sentinel with the reason and a timestamp', () => {
|
|
34
|
+
const result = requestRestart({ reason: 'Added a server operator' });
|
|
35
|
+
|
|
36
|
+
expect(result).toEqual({ requested: true, reason: 'Added a server operator' });
|
|
37
|
+
const sentinel = JSON.parse(fs.readFileSync(path.join(fixtureDir, 'build', '.restart'), 'utf8'));
|
|
38
|
+
expect(sentinel.reason).toBe('Added a server operator');
|
|
39
|
+
expect(new Date(sentinel.requestedAt).toISOString()).toBe(sentinel.requestedAt);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('requestRestart writes the sentinel without a reason', () => {
|
|
43
|
+
const result = requestRestart({ reason: undefined });
|
|
44
|
+
|
|
45
|
+
expect(result).toEqual({ requested: true, reason: undefined });
|
|
46
|
+
const sentinel = JSON.parse(fs.readFileSync(path.join(fixtureDir, 'build', '.restart'), 'utf8'));
|
|
47
|
+
expect(sentinel).not.toHaveProperty('reason');
|
|
48
|
+
expect(sentinel.requestedAt).toEqual(expect.any(String));
|
|
49
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
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 { buildPagePath, pageInstanceKey, type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
import readPagePath from './readPagePath.js';
|
|
20
|
+
|
|
21
|
+
// The page instance a dev tool names by `pageId` and `pathParams`: the page's
|
|
22
|
+
// path pattern (readPagePath, undefined for a page the route table does not
|
|
23
|
+
// list) and the key its context and input are stored under. Returns
|
|
24
|
+
// { path, instanceKey }, or { error } for pathParams that are not an object or
|
|
25
|
+
// that miss a placeholder of the pattern, as data for the tool to return to the
|
|
26
|
+
// agent before it opens a browser.
|
|
27
|
+
function resolvePageInstance({ pageId, pathParams }) {
|
|
28
|
+
if (!type.isNone(pathParams) && !type.isObject(pathParams)) {
|
|
29
|
+
return {
|
|
30
|
+
error: `"pathParams" must be an object of path values, e.g. {"ticket_id": "1"}. Received ${JSON.stringify(
|
|
31
|
+
pathParams
|
|
32
|
+
)}.`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const path = readPagePath({ pageId });
|
|
36
|
+
try {
|
|
37
|
+
buildPagePath({ pageId, path, pathParams });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
error: `${error.message} Page "${pageId}" is served at "${path}": pass "pathParams" with a value for each placeholder.`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return { path, instanceKey: pageInstanceKey({ pageId, path, pathParams }) };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default resolvePageInstance;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'fs';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
|
|
21
|
+
// readPagePath reads build/routes.json from process.cwd(): chdir into a fixture
|
|
22
|
+
// that has one before the module loads.
|
|
23
|
+
const originalCwd = process.cwd();
|
|
24
|
+
const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-page-instance-test-'));
|
|
25
|
+
fs.mkdirSync(path.join(fixtureDir, 'build'), { recursive: true });
|
|
26
|
+
fs.writeFileSync(
|
|
27
|
+
path.join(fixtureDir, 'build', 'routes.json'),
|
|
28
|
+
JSON.stringify([
|
|
29
|
+
{ pageId: 'home', path: 'home' },
|
|
30
|
+
{ pageId: 'about', path: 'company/about' },
|
|
31
|
+
{ pageId: 'ticket', path: 'tickets/{space}/{ticket_id}' },
|
|
32
|
+
])
|
|
33
|
+
);
|
|
34
|
+
process.chdir(fixtureDir);
|
|
35
|
+
|
|
36
|
+
const { default: resolvePageInstance } = await import('./resolvePageInstance.js');
|
|
37
|
+
|
|
38
|
+
afterAll(() => {
|
|
39
|
+
process.chdir(originalCwd);
|
|
40
|
+
fs.rmSync(fixtureDir, { recursive: true, force: true });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('resolvePageInstance keys a page without placeholders by its id', () => {
|
|
44
|
+
expect(resolvePageInstance({ pageId: 'home' })).toEqual({
|
|
45
|
+
path: 'home',
|
|
46
|
+
instanceKey: 'page:home',
|
|
47
|
+
});
|
|
48
|
+
expect(resolvePageInstance({ pageId: 'about' })).toEqual({
|
|
49
|
+
path: 'company/about',
|
|
50
|
+
instanceKey: 'page:about',
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('resolvePageInstance keys a patterned page instance by the path its values build', () => {
|
|
55
|
+
expect(
|
|
56
|
+
resolvePageInstance({ pageId: 'ticket', pathParams: { space: 's', ticket_id: 1 } })
|
|
57
|
+
).toEqual({
|
|
58
|
+
path: 'tickets/{space}/{ticket_id}',
|
|
59
|
+
instanceKey: 'page:ticket#tickets/s/1',
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('resolvePageInstance returns the builder error naming a missing placeholder', () => {
|
|
64
|
+
expect(resolvePageInstance({ pageId: 'ticket', pathParams: { space: 's' } })).toEqual({
|
|
65
|
+
error:
|
|
66
|
+
'Link to page "ticket" is missing a value for path placeholder "ticket_id". Page "ticket" is served at "tickets/{space}/{ticket_id}": pass "pathParams" with a value for each placeholder.',
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('resolvePageInstance returns an error for pathParams that are not an object', () => {
|
|
71
|
+
expect(resolvePageInstance({ pageId: 'ticket', pathParams: '1' }).error).toMatch(
|
|
72
|
+
/"pathParams" must be an object of path values/
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('resolvePageInstance builds a page the route table does not list as its id', () => {
|
|
77
|
+
expect(resolvePageInstance({ pageId: 'missing' })).toEqual({
|
|
78
|
+
path: undefined,
|
|
79
|
+
instanceKey: 'page:missing',
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -24,24 +24,28 @@ import tabAvailable from './tabAvailable.js';
|
|
|
24
24
|
// actually looking at (their own interactions, in-flight requests), while
|
|
25
25
|
// headless always starts a clean navigation.
|
|
26
26
|
//
|
|
27
|
-
// `user`
|
|
28
|
-
//
|
|
29
|
-
// and contradicts an explicit
|
|
27
|
+
// `user` and `data` are headless-only — the developer's tab carries their real
|
|
28
|
+
// session and reads the app's real database, which the dev server cannot
|
|
29
|
+
// swap — so either selects the headless source, and contradicts an explicit
|
|
30
|
+
// `source: 'tab'`.
|
|
30
31
|
//
|
|
31
32
|
// Returns { tryTab }, or { error, invalidInput } for a contradictory call.
|
|
32
33
|
// `invalidInput` marks the caller's own mistake rather than a failed render, so
|
|
33
34
|
// the HTTP routes can answer 400 instead of a 502 that reads as "the renderer
|
|
34
35
|
// broke, retry".
|
|
35
|
-
function resolveSource({ name, pageId, source, user }) {
|
|
36
|
-
const hasUser = !type.isNone(user);
|
|
36
|
+
function resolveSource({ name, pageId, pathParams, source, user, data }) {
|
|
37
|
+
const hasUser = !type.isNone(user) || !type.isNone(data);
|
|
37
38
|
if (hasUser && source === 'tab') {
|
|
39
|
+
const param = type.isNone(user) ? 'data' : 'user';
|
|
38
40
|
return {
|
|
39
|
-
error: `${name} cannot apply "
|
|
41
|
+
error: `${name} cannot apply "${param}" to the developer's live tab — it carries their real session and database. Omit "source", or use "headless".`,
|
|
40
42
|
invalidInput: true,
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
45
|
return {
|
|
44
|
-
tryTab:
|
|
46
|
+
tryTab:
|
|
47
|
+
source === 'tab' ||
|
|
48
|
+
(source === undefined && !hasUser && tabAvailable({ pageId, pathParams })),
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
51
|
|