@lowdefy/server-dev 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +63 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +224 -39
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +67 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +679 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/findCollectionCollisions.js +52 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +44 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +119 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +343 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +68 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +220 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +33 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +203 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +8 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +54 -6
- package/lib/docs/getBuildStatus.test.mjs +133 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +83 -0
- package/lib/server/applyDataSetRedirect.test.mjs +340 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +204 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +131 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/getAuth.js +46 -0
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{getAuthConfig.js → getStrategies.js} +12 -10
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +174 -41
- package/lib/server/createLowdefyContext.test.mjs +437 -0
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +77 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +112 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/scrubSecrets.js +23 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +24 -2
- package/manager/processes/initialBuild.mjs +14 -0
- package/manager/processes/initialBuild.test.mjs +101 -0
- package/manager/processes/lowdefyBuild.mjs +30 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +62 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +61 -49
- package/package.original.json +61 -49
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +196 -14
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +4 -2
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/lib/server/auth/session.js +0 -39
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { createSystemContext as buildSystemContext } from '@lowdefy/api';
|
|
19
|
+
import { getSecretsFromEnv } from '@lowdefy/node-utils';
|
|
20
|
+
import { v4 as uuid } from 'uuid';
|
|
21
|
+
|
|
22
|
+
import agents from '../../../build/plugins/agents.js';
|
|
23
|
+
import appMeta from '../../build/appMeta.js';
|
|
24
|
+
import config from '../../build/config.js';
|
|
25
|
+
import connections from '../../../build/plugins/connections.js';
|
|
26
|
+
import createHandleError from '../log/createHandleError.js';
|
|
27
|
+
import createLogger from '../log/createLogger.js';
|
|
28
|
+
import fileCache from '../fileCache.js';
|
|
29
|
+
import i18nConfig from '../../build/i18n.js';
|
|
30
|
+
import loadDynamicJsMap from '../loadDynamicJsMap.js';
|
|
31
|
+
import notifications from '../../../build/plugins/notifications.js';
|
|
32
|
+
import operators from '../../../build/plugins/operators/server.js';
|
|
33
|
+
import scrubSecrets from '../scrubSecrets.js';
|
|
34
|
+
import steps from '../../../build/plugins/steps.js';
|
|
35
|
+
import websockets from '../../../build/plugins/websockets.js';
|
|
36
|
+
|
|
37
|
+
const secrets = getSecretsFromEnv();
|
|
38
|
+
|
|
39
|
+
// Builds a fresh system context per auth hook fire - the trusted internal
|
|
40
|
+
// caller the BetterAuth engine uses to invoke hook endpoints. All fields are
|
|
41
|
+
// startup singletons except the per-fire rid, logger, handleError, the
|
|
42
|
+
// dynamic jsMap re-read (JIT rebuilds rewrite serverJsMap.js), and auth -
|
|
43
|
+
// auth is threaded in by the caller (createHookDispatch) rather than
|
|
44
|
+
// imported directly, since it comes from the same BetterAuth construction
|
|
45
|
+
// that this factory is a dependency of (see createHookDispatch.js).
|
|
46
|
+
function createSystemContext({ auth } = {}) {
|
|
47
|
+
const rid = uuid();
|
|
48
|
+
const buildDirectory = path.join(process.cwd(), 'build');
|
|
49
|
+
return buildSystemContext({
|
|
50
|
+
rid,
|
|
51
|
+
agents,
|
|
52
|
+
appMeta,
|
|
53
|
+
auth,
|
|
54
|
+
buildDirectory,
|
|
55
|
+
config,
|
|
56
|
+
configDirectory: process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd(),
|
|
57
|
+
connections,
|
|
58
|
+
createHandleError,
|
|
59
|
+
fileCache,
|
|
60
|
+
i18n: i18nConfig,
|
|
61
|
+
jsMap: loadDynamicJsMap(buildDirectory),
|
|
62
|
+
logger: createLogger({ rid }),
|
|
63
|
+
mode: 'dev',
|
|
64
|
+
notifications,
|
|
65
|
+
operators,
|
|
66
|
+
scrubSecrets,
|
|
67
|
+
secrets,
|
|
68
|
+
steps,
|
|
69
|
+
websockets,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default createSystemContext;
|
|
@@ -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 { getBetterAuth } from '@lowdefy/api';
|
|
18
|
+
import { getSecretsFromEnv } from '@lowdefy/node-utils';
|
|
19
|
+
|
|
20
|
+
import adapters from '../../../build/plugins/auth/adapters.js';
|
|
21
|
+
import appMeta from '../../build/appMeta.js';
|
|
22
|
+
import authJson from '../../build/auth.js';
|
|
23
|
+
import createSystemContext from './createSystemContext.js';
|
|
24
|
+
import lowdefyConfig from '../../build/config.js';
|
|
25
|
+
import providers from '../../../build/plugins/auth/providers.js';
|
|
26
|
+
|
|
27
|
+
// Returns the BetterAuth instance (memoized in @lowdefy/api), or null when
|
|
28
|
+
// auth is not configured. dev: true relaxes cookies for plain-http localhost
|
|
29
|
+
// and derives a per-app cookie prefix so parallel dev apps do not collide.
|
|
30
|
+
function getAuth({ logger }) {
|
|
31
|
+
if (authJson.configured !== true) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return getBetterAuth({
|
|
35
|
+
appMeta,
|
|
36
|
+
authJson,
|
|
37
|
+
config: lowdefyConfig,
|
|
38
|
+
createSystemContext,
|
|
39
|
+
dev: true,
|
|
40
|
+
logger,
|
|
41
|
+
plugins: { adapters, providers },
|
|
42
|
+
secrets: getSecretsFromEnv(),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default getAuth;
|
|
@@ -16,24 +16,25 @@
|
|
|
16
16
|
|
|
17
17
|
import { HEADLESS_USER_COOKIE } from './headlessUser.js';
|
|
18
18
|
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
19
|
+
// Mirrors the e2e user-injection pattern (server-e2e/lib/server/auth/getUser.js):
|
|
20
|
+
// the headless renderer sets a base64-JSON caller cookie on its own browser
|
|
21
|
+
// context, so its /api/* fetches carry a pre-resolved caller while the
|
|
22
|
+
// developer's real browser (no cookie) is unaffected. Returns { user, explicit }
|
|
23
|
+
// as getBrowser.js wrote it, or null on miss - the caller floors the user's
|
|
24
|
+
// shape via normalizeInjectedCaller. `explicit` is true when the tool call or
|
|
25
|
+
// journey named the user, so createLowdefyContext lets it beat a dev mock user.
|
|
25
26
|
function getHeadlessUser(c) {
|
|
26
27
|
const cookieHeader = c.req.header('cookie') ?? '';
|
|
27
28
|
const match = cookieHeader.match(new RegExp(`${HEADLESS_USER_COOKIE}=([^;]+)`));
|
|
28
29
|
if (!match) {
|
|
29
|
-
return
|
|
30
|
+
return null;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
try {
|
|
33
34
|
const decoded = Buffer.from(decodeURIComponent(match[1]), 'base64').toString();
|
|
34
35
|
return JSON.parse(decoded);
|
|
35
36
|
} catch {
|
|
36
|
-
return
|
|
37
|
+
return null;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import getHeadlessUser from './getHeadlessUser.js';
|
|
18
|
+
|
|
19
|
+
function contextWithCookie(cookie) {
|
|
20
|
+
return { req: { header: (name) => (name === 'cookie' ? cookie : undefined) } };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function encode(value) {
|
|
24
|
+
return Buffer.from(JSON.stringify(value)).toString('base64');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test('getHeadlessUser reads the user and whether the caller named it', () => {
|
|
28
|
+
const caller = { user: { id: 'agent', roles: ['admin'] }, explicit: true };
|
|
29
|
+
expect(
|
|
30
|
+
getHeadlessUser(contextWithCookie(`other=1; lowdefy_headless_user=${encode(caller)}`))
|
|
31
|
+
).toEqual(caller);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('getHeadlessUser returns null with no headless cookie', () => {
|
|
35
|
+
expect(getHeadlessUser(contextWithCookie(undefined))).toBeNull();
|
|
36
|
+
expect(getHeadlessUser(contextWithCookie('other=1'))).toBeNull();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('getHeadlessUser returns null for a cookie that is not base64 JSON', () => {
|
|
40
|
+
expect(getHeadlessUser(contextWithCookie('lowdefy_headless_user=%%%'))).toBeNull();
|
|
41
|
+
});
|
|
@@ -14,14 +14,19 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
17
18
|
import { serializer } from '@lowdefy/helpers';
|
|
18
19
|
|
|
19
20
|
import authJson from '../../build/auth.js';
|
|
20
21
|
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
22
|
+
// dev.mockUser is a pre-resolved caller that substitutes for the whole
|
|
23
|
+
// resolveAuthentication step - no auth engine, no session lookup, no
|
|
24
|
+
// membership wall. Its roles are authoritative. LOWDEFY_DEV_USER takes
|
|
25
|
+
// priority over auth.dev.mockUser from lowdefy.yaml.
|
|
26
|
+
//
|
|
27
|
+
// A dev mock user needs no auth stack behind it: auth.dev is a dev-only
|
|
28
|
+
// concern, so an app whose only auth key is auth.dev runs signed out in
|
|
29
|
+
// production and has this caller in the dev server.
|
|
25
30
|
function getMockUser() {
|
|
26
31
|
const mockUserJson = process.env.LOWDEFY_DEV_USER;
|
|
27
32
|
let mockUser;
|
|
@@ -30,25 +35,24 @@ function getMockUser() {
|
|
|
30
35
|
try {
|
|
31
36
|
mockUser = JSON.parse(mockUserJson);
|
|
32
37
|
} catch (error) {
|
|
33
|
-
throw new
|
|
38
|
+
throw new ConfigError('Invalid JSON in LOWDEFY_DEV_USER environment variable.', {
|
|
39
|
+
cause: error,
|
|
40
|
+
});
|
|
34
41
|
}
|
|
35
42
|
} else {
|
|
36
43
|
mockUser = authJson.dev?.mockUser;
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
if (!mockUser) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (authJson.configured !== true) {
|
|
44
|
-
throw new Error(
|
|
45
|
-
'Mock user configured but auth is not configured in lowdefy.yaml. ' +
|
|
46
|
-
'Add auth configuration to use mock user feature.'
|
|
47
|
-
);
|
|
47
|
+
return null;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// Deserialize to restore arrays from ~arr markers and remove other build markers
|
|
51
|
-
|
|
51
|
+
mockUser = serializer.deserialize(mockUser);
|
|
52
|
+
|
|
53
|
+
// The roles/attributes floor is applied at injection by
|
|
54
|
+
// normalizeInjectedCaller (createLowdefyContext.js) - return the raw user.
|
|
55
|
+
return mockUser;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
export default getMockUser;
|
|
@@ -14,25 +14,27 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { getAuthStrategies } from '@lowdefy/api';
|
|
18
18
|
import { getSecretsFromEnv } from '@lowdefy/node-utils';
|
|
19
19
|
|
|
20
|
-
import adapters from '../../../build/plugins/auth/adapters.js';
|
|
21
20
|
import appMeta from '../../build/appMeta.js';
|
|
22
21
|
import authJson from '../../build/auth.js';
|
|
23
|
-
import
|
|
24
|
-
import events from '../../../build/plugins/auth/events.js';
|
|
25
|
-
import providers from '../../../build/plugins/auth/providers.js';
|
|
22
|
+
import strategyTypes from '../../../build/plugins/auth/strategies.js';
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
// Returns the API auth strategy verifiers (memoized in @lowdefy/api), or an
|
|
25
|
+
// empty list when auth is not configured - resolveAuthentication tries them
|
|
26
|
+
// in config order when no session resolves.
|
|
27
|
+
function getStrategies({ logger }) {
|
|
28
|
+
if (authJson.configured !== true) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return getAuthStrategies({
|
|
29
32
|
appMeta,
|
|
30
33
|
authJson,
|
|
31
|
-
dev: true,
|
|
32
34
|
logger,
|
|
33
|
-
plugins: {
|
|
35
|
+
plugins: { strategies: strategyTypes },
|
|
34
36
|
secrets: getSecretsFromEnv(),
|
|
35
37
|
});
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
export default
|
|
40
|
+
export default getStrategies;
|
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
// Shared between the headless renderer (getBrowser.js, which sets the cookie on
|
|
18
|
-
// its browser context) and the dev
|
|
18
|
+
// its browser context) and the dev caller resolver (getHeadlessUser.js, which
|
|
19
19
|
// decodes it) so the cookie name and injected user shape live in one place.
|
|
20
20
|
const HEADLESS_USER_COOKIE = 'lowdefy_headless_user';
|
|
21
21
|
|
|
22
|
+
// BetterAuth's session user carries `id`, never `sub`. attributes is floored to
|
|
23
|
+
// {} by normalizeInjectedCaller at injection, so it is not spelled out here.
|
|
22
24
|
const headlessUser = {
|
|
23
|
-
sub: 'lowdefy-headless',
|
|
24
25
|
id: 'lowdefy-headless',
|
|
25
26
|
name: 'Lowdefy Headless',
|
|
26
27
|
roles: [],
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import crypto from 'node:crypto';
|
|
18
|
+
|
|
19
|
+
// Signs every journey cookie (journeyCookies.js): the headless renderer
|
|
20
|
+
// (getBrowser.js) writes them on a journey actor's browser context, and the dev
|
|
21
|
+
// server reads them back (getClientAddress.js for the actor address).
|
|
22
|
+
//
|
|
23
|
+
// Auth rate limits count attempts per client address, and every actor of every
|
|
24
|
+
// journey reaches the dev server from the same machine, so each actor is given
|
|
25
|
+
// its own address. The cookie carries it with a token minted once per dev
|
|
26
|
+
// server process, so only the dev server's own headless browser can pick an
|
|
27
|
+
// address: a cookie from anywhere else is ignored. The production server never
|
|
28
|
+
// reads it. The token is kept on globalThis because the renderer and the
|
|
29
|
+
// resolver may load as separate module instances in one process (Vite's SSR
|
|
30
|
+
// module graph and Node's).
|
|
31
|
+
const TOKEN_KEY = Symbol.for('lowdefy.devServer.journeyActorToken');
|
|
32
|
+
globalThis[TOKEN_KEY] ??= crypto.randomBytes(32).toString('hex');
|
|
33
|
+
const journeyActorToken = globalThis[TOKEN_KEY];
|
|
34
|
+
|
|
35
|
+
export { journeyActorToken };
|
|
@@ -19,7 +19,6 @@ import { headlessUser } from './headlessUser.js';
|
|
|
19
19
|
|
|
20
20
|
test('resolveHeadlessUser returns the default roleless user when no user is given', () => {
|
|
21
21
|
expect(resolveHeadlessUser({})).toEqual({
|
|
22
|
-
sub: 'lowdefy-headless',
|
|
23
22
|
id: 'lowdefy-headless',
|
|
24
23
|
name: 'Lowdefy Headless',
|
|
25
24
|
roles: [],
|
|
@@ -32,7 +31,6 @@ test('resolveHeadlessUser returns the default roleless user when user is null',
|
|
|
32
31
|
|
|
33
32
|
test('resolveHeadlessUser merges roles over the default, keeping the default id and name', () => {
|
|
34
33
|
expect(resolveHeadlessUser({ user: { roles: ['user-admin'] } })).toEqual({
|
|
35
|
-
sub: 'lowdefy-headless',
|
|
36
34
|
id: 'lowdefy-headless',
|
|
37
35
|
name: 'Lowdefy Headless',
|
|
38
36
|
roles: ['user-admin'],
|
|
@@ -45,7 +43,6 @@ test('resolveHeadlessUser keeps caller fields the app reads, like email and prof
|
|
|
45
43
|
user: { id: 'agent', email: 'agent@example.com', profile: { name: 'Agent' } },
|
|
46
44
|
})
|
|
47
45
|
).toEqual({
|
|
48
|
-
sub: 'lowdefy-headless',
|
|
49
46
|
id: 'agent',
|
|
50
47
|
name: 'Lowdefy Headless',
|
|
51
48
|
email: 'agent@example.com',
|
|
@@ -58,7 +55,6 @@ test('resolveHeadlessUser does not mutate the default user between calls', () =>
|
|
|
58
55
|
resolveHeadlessUser({ user: { id: 'first', roles: ['admin'] } });
|
|
59
56
|
|
|
60
57
|
expect(resolveHeadlessUser({})).toEqual({
|
|
61
|
-
sub: 'lowdefy-headless',
|
|
62
58
|
id: 'lowdefy-headless',
|
|
63
59
|
name: 'Lowdefy Headless',
|
|
64
60
|
roles: [],
|
|
@@ -0,0 +1,44 @@
|
|
|
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 hashConfigContent from './hashConfigContent.js';
|
|
18
|
+
|
|
19
|
+
async function readHash({ filePath, readConfigFile }) {
|
|
20
|
+
try {
|
|
21
|
+
return hashConfigContent(await readConfigFile(filePath));
|
|
22
|
+
} catch {
|
|
23
|
+
// A file that cannot be read now (EACCES, or EBUSY on Windows during a
|
|
24
|
+
// save) is treated as changed; the rebuild reads it again and reports it.
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Whether the inputs of a page's last build are unchanged: 'current' when every
|
|
30
|
+
// file it read still holds the content it read, else 'changed'. A build that
|
|
31
|
+
// ran app code is always 'changed': app code can read anything, so its record
|
|
32
|
+
// cannot be complete. Files are read through the build context's read cache,
|
|
33
|
+
// so pages that share a file read it once per change event.
|
|
34
|
+
async function checkPageRecord({ record, readConfigFile }) {
|
|
35
|
+
if (record.ranAppCode) return 'changed';
|
|
36
|
+
const recorded = [...record.files];
|
|
37
|
+
const hashes = await Promise.all(
|
|
38
|
+
recorded.map(([filePath]) => readHash({ filePath, readConfigFile }))
|
|
39
|
+
);
|
|
40
|
+
const unchanged = recorded.every(([, hash], index) => hashes[index] === hash);
|
|
41
|
+
return unchanged ? 'current' : 'changed';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default checkPageRecord;
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
// Key and ref map entries the dev server's kept JIT build context may add
|
|
18
|
+
// before it is recreated. Every page build adds entries to both maps and they
|
|
19
|
+
// are released only with the context, so this bounds one dev server's memory.
|
|
20
|
+
// Measured on the docs app: about 530 entries and 400-750 KB of retained heap
|
|
21
|
+
// per page build, so this is about 90 page builds and 35-65 MB.
|
|
22
|
+
const contextMapBudget = 48000;
|
|
23
|
+
|
|
24
|
+
export default contextMapBudget;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'fs';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { jest } from '@jest/globals';
|
|
21
|
+
|
|
22
|
+
// A budget one page build passes, so the next request recreates the context.
|
|
23
|
+
jest.unstable_mockModule('./contextMapBudget.js', () => ({ default: 1 }));
|
|
24
|
+
|
|
25
|
+
const { default: buildPageIfNeeded, getBuildContext } = await import('./jitPageBuilder.js');
|
|
26
|
+
|
|
27
|
+
jest.setTimeout(30000);
|
|
28
|
+
|
|
29
|
+
function writeJson(filePath, data) {
|
|
30
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
31
|
+
fs.writeFileSync(filePath, JSON.stringify(data));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
test('a build context past its map budget is recreated, and every page rebuilds on the new one', async () => {
|
|
35
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ldf-context-budget-'));
|
|
36
|
+
const buildDirectory = path.join(root, 'server', 'build');
|
|
37
|
+
const configDirectory = path.join(root, 'config');
|
|
38
|
+
writeJson(path.join(buildDirectory, 'idCounter.json'), { prefix: 'cfg1_', counter: 10 });
|
|
39
|
+
writeJson(path.join(buildDirectory, 'installedPluginPackages.json'), ['@lowdefy/blocks-basic']);
|
|
40
|
+
writeJson(path.join(buildDirectory, 'theme.json'), {});
|
|
41
|
+
const registry = {};
|
|
42
|
+
for (const pageId of ['a', 'b']) {
|
|
43
|
+
fs.mkdirSync(path.join(configDirectory, 'pages'), { recursive: true });
|
|
44
|
+
fs.writeFileSync(
|
|
45
|
+
path.join(configDirectory, 'pages', `${pageId}.yaml`),
|
|
46
|
+
`id: ${pageId}\ntype: Box\n`
|
|
47
|
+
);
|
|
48
|
+
registry[pageId] = {
|
|
49
|
+
pageId,
|
|
50
|
+
auth: { public: true },
|
|
51
|
+
refId: `ref-${pageId}`,
|
|
52
|
+
refPath: `pages/${pageId}.yaml`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
writeJson(path.join(buildDirectory, 'pageRegistry.json'), registry);
|
|
56
|
+
const request = (pageId) => buildPageIfNeeded({ pageId, buildDirectory, configDirectory });
|
|
57
|
+
|
|
58
|
+
expect(await request('a')).toEqual({ built: true, warnings: undefined });
|
|
59
|
+
const firstContext = getBuildContext(buildDirectory, configDirectory);
|
|
60
|
+
expect(await request('b')).toEqual({ built: true, warnings: undefined });
|
|
61
|
+
const secondContext = getBuildContext(buildDirectory, configDirectory);
|
|
62
|
+
expect(secondContext).not.toBe(firstContext);
|
|
63
|
+
|
|
64
|
+
// b was built past the budget too, so the next request recreates again and
|
|
65
|
+
// a, built two contexts ago, rebuilds.
|
|
66
|
+
expect(await request('a')).toEqual({ built: true, warnings: undefined });
|
|
67
|
+
expect(getBuildContext(buildDirectory, configDirectory)).not.toBe(secondContext);
|
|
68
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('a failed page build counts toward the budget', async () => {
|
|
72
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ldf-context-budget-'));
|
|
73
|
+
const buildDirectory = path.join(root, 'server', 'build');
|
|
74
|
+
const configDirectory = path.join(root, 'config');
|
|
75
|
+
writeJson(path.join(buildDirectory, 'idCounter.json'), { prefix: 'cfg1_', counter: 10 });
|
|
76
|
+
writeJson(path.join(buildDirectory, 'installedPluginPackages.json'), ['@lowdefy/blocks-basic']);
|
|
77
|
+
writeJson(path.join(buildDirectory, 'theme.json'), {});
|
|
78
|
+
fs.mkdirSync(path.join(configDirectory, 'pages'), { recursive: true });
|
|
79
|
+
fs.writeFileSync(
|
|
80
|
+
path.join(configDirectory, 'pages', 'broken.yaml'),
|
|
81
|
+
'id: broken\ntype: Box\nblocks:\n - id: typo\n type: Buton\n'
|
|
82
|
+
);
|
|
83
|
+
writeJson(path.join(buildDirectory, 'pageRegistry.json'), {
|
|
84
|
+
broken: {
|
|
85
|
+
pageId: 'broken',
|
|
86
|
+
auth: { public: true },
|
|
87
|
+
refId: 'ref-broken',
|
|
88
|
+
refPath: 'pages/broken.yaml',
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
const request = (pageId) => buildPageIfNeeded({ pageId, buildDirectory, configDirectory });
|
|
92
|
+
|
|
93
|
+
await expect(request('broken')).rejects.toThrow('Buton');
|
|
94
|
+
const firstContext = getBuildContext(buildDirectory, configDirectory);
|
|
95
|
+
await expect(request('broken')).rejects.toThrow('Buton');
|
|
96
|
+
expect(getBuildContext(buildDirectory, configDirectory)).not.toBe(firstContext);
|
|
97
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
98
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
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 { makeId } from '@lowdefy/build/dev';
|
|
18
|
+
|
|
19
|
+
// JIT keys extend the config build's prefix with the dev server process's id, so
|
|
20
|
+
// they never repeat a key of that build, of an earlier config build, or of another
|
|
21
|
+
// process serving the same config build (a restarted server continues the build
|
|
22
|
+
// the one before it served). Within a process the counter only moves forward, so
|
|
23
|
+
// a recreated build context never repeats an earlier page build's key.
|
|
24
|
+
function continueJitKeys({ idCounter, childId }) {
|
|
25
|
+
makeId.continueFrom({ prefix: `${idCounter.prefix}${childId}_`, counter: 0 });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default continueJitKeys;
|
|
@@ -0,0 +1,43 @@
|
|
|
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 { makeId } from '@lowdefy/build/dev';
|
|
18
|
+
|
|
19
|
+
import continueJitKeys from './continueJitKeys.js';
|
|
20
|
+
|
|
21
|
+
test('two dev server processes serving one config build never hand out the same key', () => {
|
|
22
|
+
const idCounter = { prefix: 'a1b2_', counter: 40 };
|
|
23
|
+
|
|
24
|
+
continueJitKeys({ idCounter, childId: 'aaaaaa' });
|
|
25
|
+
const first = [makeId.next(), makeId.next()];
|
|
26
|
+
continueJitKeys({ idCounter, childId: 'bbbbbb' });
|
|
27
|
+
const second = [makeId.next(), makeId.next()];
|
|
28
|
+
|
|
29
|
+
expect(first).toEqual(['a1b2_aaaaaa_1', 'a1b2_aaaaaa_2']);
|
|
30
|
+
expect(second).toEqual(['a1b2_bbbbbb_1', 'a1b2_bbbbbb_2']);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('a recreated build context in the same process continues its keys', () => {
|
|
34
|
+
const idCounter = { prefix: 'c3d4_', counter: 40 };
|
|
35
|
+
|
|
36
|
+
continueJitKeys({ idCounter, childId: 'aaaaaa' });
|
|
37
|
+
const first = makeId.next();
|
|
38
|
+
continueJitKeys({ idCounter, childId: 'aaaaaa' });
|
|
39
|
+
const second = makeId.next();
|
|
40
|
+
|
|
41
|
+
expect(first).toBe('c3d4_aaaaaa_1');
|
|
42
|
+
expect(second).toBe('c3d4_aaaaaa_2');
|
|
43
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
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 { HTTPException } from 'hono/http-exception';
|
|
18
|
+
|
|
19
|
+
// A request whose verified data cookie names a session that has closed outlived its journey. The
|
|
20
|
+
// verified token proves it came from a journey, so it is answered 410 and never falls back to the
|
|
21
|
+
// app's own database. Thrown as an HTTPException, which the error handler sends as it is.
|
|
22
|
+
function createDataSessionEndedError({ id }) {
|
|
23
|
+
const message = `Data session ${id} has ended; this request outlived its journey.`;
|
|
24
|
+
return new HTTPException(410, {
|
|
25
|
+
message,
|
|
26
|
+
res: new Response(JSON.stringify({ name: 'DataSessionEnded', message }), {
|
|
27
|
+
status: 410,
|
|
28
|
+
headers: { 'content-type': 'application/json' },
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default createDataSessionEndedError;
|