@lowdefy/server-dev 6.1.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +78 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +727 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/describeTargetKey.js +29 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +52 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +133 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +493 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +83 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +251 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sessionDatabaseName.js +32 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +36 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +225 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +12 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +81 -7
- package/lib/docs/getBuildStatus.test.mjs +229 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +92 -0
- package/lib/server/applyDataSetRedirect.test.mjs +446 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +207 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +134 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +331 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +115 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +25 -3
- package/manager/processes/initialBuild.mjs +17 -1
- package/manager/processes/initialBuild.test.mjs +104 -0
- package/manager/processes/lowdefyBuild.mjs +31 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +72 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,157 @@
|
|
|
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 { Hono } from 'hono';
|
|
18
|
+
import { jest } from '@jest/globals';
|
|
19
|
+
|
|
20
|
+
const mockCreateWebSocketConnection = jest.fn(() => ({
|
|
21
|
+
close: jest.fn(),
|
|
22
|
+
handleMessage: jest.fn(),
|
|
23
|
+
}));
|
|
24
|
+
// The route's origin rule has its own tests (src/routes/websocket.test.mjs);
|
|
25
|
+
// these requests carry no Origin, which it allows.
|
|
26
|
+
jest.unstable_mockModule('@lowdefy/api', () => ({
|
|
27
|
+
createChannelRegistry: jest.fn(() => ({})),
|
|
28
|
+
createWebSocketConnection: mockCreateWebSocketConnection,
|
|
29
|
+
isWebSocketOriginAllowed: () => true,
|
|
30
|
+
}));
|
|
31
|
+
const mockStrategies = [];
|
|
32
|
+
jest.unstable_mockModule('../../lib/server/auth/getStrategies.js', () => ({
|
|
33
|
+
default: () => mockStrategies,
|
|
34
|
+
}));
|
|
35
|
+
const mockLogger = { warn: jest.fn(), debug: jest.fn() };
|
|
36
|
+
jest.unstable_mockModule('../../lib/server/log/createLogger.js', () => ({
|
|
37
|
+
default: () => mockLogger,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const { handleWebSocketUpgrade } = await import('./devWebSocket.js');
|
|
41
|
+
const { default: websocketHandler } = await import('../routes/websocket.js');
|
|
42
|
+
|
|
43
|
+
// Mirrors the dev app: middleware builds the request context, then the
|
|
44
|
+
// websocket route runs. `status` stands in for the auth middleware refusing.
|
|
45
|
+
function createApp({ status } = {}) {
|
|
46
|
+
const app = new Hono();
|
|
47
|
+
app.use('/api/*', async (c, next) => {
|
|
48
|
+
if (status) {
|
|
49
|
+
return c.json({ message: 'Unauthorized.' }, status);
|
|
50
|
+
}
|
|
51
|
+
c.set('lowdefyContext', { rid: 'request-1', logger: mockLogger });
|
|
52
|
+
return next();
|
|
53
|
+
});
|
|
54
|
+
app.get('/api/websocket', websocketHandler);
|
|
55
|
+
return app;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createUpgrade() {
|
|
59
|
+
const socket = { end: jest.fn() };
|
|
60
|
+
const ws = { close: jest.fn(), on: jest.fn(), send: jest.fn() };
|
|
61
|
+
const wss = {
|
|
62
|
+
handleUpgrade: jest.fn((request, socket, head, callback) => {
|
|
63
|
+
callback(ws);
|
|
64
|
+
return ws;
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
const request = {
|
|
68
|
+
headers: { host: 'localhost:3000', cookie: 'session=1' },
|
|
69
|
+
url: '/api/websocket',
|
|
70
|
+
};
|
|
71
|
+
return { request, socket, wss, head: Buffer.alloc(0) };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
test('an upgrade hands the context the route built to the websocket connection', async () => {
|
|
75
|
+
const upgrade = createUpgrade();
|
|
76
|
+
|
|
77
|
+
await handleWebSocketUpgrade({ app: createApp(), ...upgrade });
|
|
78
|
+
|
|
79
|
+
expect(upgrade.wss.handleUpgrade).toHaveBeenCalledTimes(1);
|
|
80
|
+
expect(mockCreateWebSocketConnection.mock.calls[0][0]).toEqual({
|
|
81
|
+
rid: 'request-1',
|
|
82
|
+
logger: mockLogger,
|
|
83
|
+
});
|
|
84
|
+
expect(upgrade.socket.end).not.toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('an upgrade hands its headers and the auth strategies to the websocket connection', async () => {
|
|
88
|
+
const upgrade = createUpgrade();
|
|
89
|
+
|
|
90
|
+
await handleWebSocketUpgrade({ app: createApp(), ...upgrade });
|
|
91
|
+
|
|
92
|
+
const options = mockCreateWebSocketConnection.mock.calls[0][1];
|
|
93
|
+
expect(options.headers.get('cookie')).toBe('session=1');
|
|
94
|
+
expect(options.strategies).toBe(mockStrategies);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('the websocket connection closes its socket with the code and reason it is given', async () => {
|
|
98
|
+
const upgrade = createUpgrade();
|
|
99
|
+
|
|
100
|
+
await handleWebSocketUpgrade({ app: createApp(), ...upgrade });
|
|
101
|
+
|
|
102
|
+
const ws = upgrade.wss.handleUpgrade.mock.results[0].value;
|
|
103
|
+
const { closeSocket } = mockCreateWebSocketConnection.mock.calls[0][1];
|
|
104
|
+
closeSocket({ code: 4401, reason: 'caller-changed' });
|
|
105
|
+
expect(ws.close).toHaveBeenCalledWith(4401, 'caller-changed');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('concurrent upgrades through different app instances each get a connection', async () => {
|
|
109
|
+
const first = createUpgrade();
|
|
110
|
+
const second = createUpgrade();
|
|
111
|
+
|
|
112
|
+
await Promise.all([
|
|
113
|
+
handleWebSocketUpgrade({ app: createApp(), ...first }),
|
|
114
|
+
handleWebSocketUpgrade({ app: createApp(), ...second }),
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
expect(mockCreateWebSocketConnection).toHaveBeenCalledTimes(2);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('a refused upgrade answers with the route status and logs why', async () => {
|
|
121
|
+
const upgrade = createUpgrade();
|
|
122
|
+
|
|
123
|
+
await handleWebSocketUpgrade({ app: createApp({ status: 401 }), ...upgrade });
|
|
124
|
+
|
|
125
|
+
expect(upgrade.wss.handleUpgrade).not.toHaveBeenCalled();
|
|
126
|
+
expect(upgrade.socket.end).toHaveBeenCalledWith(
|
|
127
|
+
'HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n'
|
|
128
|
+
);
|
|
129
|
+
expect(mockLogger.warn).toHaveBeenCalledWith(
|
|
130
|
+
{ event: 'ws_upgrade_refused', status: 401 },
|
|
131
|
+
'WebSocket upgrade refused: /api/websocket answered 401. {"message":"Unauthorized."}'
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('the websocket route refuses a plain HTTP request', async () => {
|
|
136
|
+
const response = await createApp().request('/api/websocket');
|
|
137
|
+
|
|
138
|
+
expect(response.status).toBe(400);
|
|
139
|
+
expect(await response.json()).toEqual({ message: 'WebSocket upgrade required.' });
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('an upgrade answered 200 without a request context is refused and logged', async () => {
|
|
143
|
+
const upgrade = createUpgrade();
|
|
144
|
+
const app = new Hono();
|
|
145
|
+
app.get('/api/websocket', (c) => c.json({ ok: true }));
|
|
146
|
+
|
|
147
|
+
await handleWebSocketUpgrade({ app, ...upgrade });
|
|
148
|
+
|
|
149
|
+
expect(upgrade.wss.handleUpgrade).not.toHaveBeenCalled();
|
|
150
|
+
expect(upgrade.socket.end).toHaveBeenCalledWith(
|
|
151
|
+
'HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n'
|
|
152
|
+
);
|
|
153
|
+
expect(mockLogger.warn).toHaveBeenCalledWith(
|
|
154
|
+
{ event: 'ws_upgrade_refused', status: 200 },
|
|
155
|
+
'WebSocket upgrade refused: /api/websocket answered 200 without a request context; the websocket route did not run.'
|
|
156
|
+
);
|
|
157
|
+
});
|
package/vite.config.js
CHANGED
|
@@ -19,6 +19,17 @@ import { defineConfig } from 'vite';
|
|
|
19
19
|
import react from '@vitejs/plugin-react';
|
|
20
20
|
import devServer from '@hono/vite-dev-server';
|
|
21
21
|
import { WebSocketServer } from 'ws';
|
|
22
|
+
import watchOwner from '@lowdefy/node-utils/watchOwner.js';
|
|
23
|
+
|
|
24
|
+
import createDevServerExclude from './lib/vite/createDevServerExclude.js';
|
|
25
|
+
|
|
26
|
+
const devServerEntry = './src/app.js';
|
|
27
|
+
|
|
28
|
+
// The dev manager spawns this Vite process with a stdin pipe it holds and
|
|
29
|
+
// LOWDEFY_EXIT_ON_STDIN_CLOSE set, so a manager killed outright (SIGKILL, out
|
|
30
|
+
// of memory) does not leave Vite holding the internal port. process.exit runs
|
|
31
|
+
// Playwright's exit handler, which closes any browser this process launched.
|
|
32
|
+
watchOwner({ onExit: () => process.exit(0) });
|
|
22
33
|
|
|
23
34
|
// basePath from the Lowdefy build — assets and routes are served under it.
|
|
24
35
|
let basePath = '';
|
|
@@ -30,10 +41,11 @@ try {
|
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
// Vite owns the HTTP server in dev, so /api/websocket upgrades are handled
|
|
33
|
-
// here instead of @hono/node-server. The
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
44
|
+
// here instead of @hono/node-server. The Hono app is loaded from the same
|
|
45
|
+
// entry @hono/vite-dev-server serves, so the upgrade runs the app every other
|
|
46
|
+
// request runs, and the upgrade handler module is loaded through Vite's SSR
|
|
47
|
+
// graph so it shares the @lowdefy/api module instances with the dev server
|
|
48
|
+
// routes. Vite's own HMR websocket uses a different path and is untouched.
|
|
37
49
|
function lowdefyWebSocket() {
|
|
38
50
|
return {
|
|
39
51
|
name: 'lowdefy-websocket',
|
|
@@ -45,12 +57,13 @@ function lowdefyWebSocket() {
|
|
|
45
57
|
return;
|
|
46
58
|
}
|
|
47
59
|
try {
|
|
48
|
-
const { handleWebSocketUpgrade } = await
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
const [{ default: app }, { handleWebSocketUpgrade }] = await Promise.all([
|
|
61
|
+
server.ssrLoadModule(devServerEntry),
|
|
62
|
+
server.ssrLoadModule('./src/websocket/devWebSocket.js'),
|
|
63
|
+
]);
|
|
64
|
+
await handleWebSocketUpgrade({ app, request, socket, head, wss });
|
|
52
65
|
} catch (error) {
|
|
53
|
-
console.error(error);
|
|
66
|
+
console.error('WebSocket upgrade failed:', error);
|
|
54
67
|
socket.destroy();
|
|
55
68
|
}
|
|
56
69
|
});
|
|
@@ -58,23 +71,26 @@ function lowdefyWebSocket() {
|
|
|
58
71
|
};
|
|
59
72
|
}
|
|
60
73
|
|
|
74
|
+
// The @lowdefy packages this server depends on. A linked plugin pinned to
|
|
75
|
+
// another release brings its own copies, and the client would then mix
|
|
76
|
+
// versions: the dev server pre-bundles one copy per package for every
|
|
77
|
+
// importer (whichever its scan meets first, so the server's own code can get
|
|
78
|
+
// a plugin's older @lowdefy/helpers without an export it imports), and a
|
|
79
|
+
// production build bundles both, so blocks read module state the client never
|
|
80
|
+
// filled (the HTML enhancements it registers in @lowdefy/block-utils). The
|
|
81
|
+
// server's copies are the ones its client and blocks were released with.
|
|
82
|
+
const lowdefyDependencies = Object.keys(
|
|
83
|
+
JSON.parse(fs.readFileSync(new URL('./package.json', import.meta.url), 'utf8')).dependencies ?? {}
|
|
84
|
+
).filter((name) => name.startsWith('@lowdefy/'));
|
|
85
|
+
|
|
61
86
|
export default defineConfig(({ mode }) => ({
|
|
62
87
|
base: `${basePath}/`,
|
|
63
88
|
plugins: [
|
|
64
89
|
react(),
|
|
65
90
|
lowdefyWebSocket(),
|
|
66
91
|
devServer({
|
|
67
|
-
entry:
|
|
68
|
-
|
|
69
|
-
exclude: [
|
|
70
|
-
/^\/client\/.+/,
|
|
71
|
-
/^\/lib\/.+/,
|
|
72
|
-
/^\/build\/.+/,
|
|
73
|
-
/^\/@.+$/,
|
|
74
|
-
/^\/node_modules\/.*/,
|
|
75
|
-
/\?t=\d+$/,
|
|
76
|
-
/^\/favicon\.ico$/,
|
|
77
|
-
],
|
|
92
|
+
entry: devServerEntry,
|
|
93
|
+
exclude: createDevServerExclude({ basePath }),
|
|
78
94
|
}),
|
|
79
95
|
],
|
|
80
96
|
define: {
|
|
@@ -94,8 +110,20 @@ export default defineConfig(({ mode }) => ({
|
|
|
94
110
|
entries: ['client/main.jsx'],
|
|
95
111
|
},
|
|
96
112
|
resolve: {
|
|
97
|
-
//
|
|
98
|
-
|
|
113
|
+
// Linked plugin packages (pnpm link: / workspace) resolve their own copies of
|
|
114
|
+
// shared libraries. They must share one React, the antd/X/cssinjs copies
|
|
115
|
+
// whose context providers (App, ConfigProvider, StyleProvider) the client
|
|
116
|
+
// renders, the dayjs whose global locale the client sets, and the server's
|
|
117
|
+
// @lowdefy packages (see lowdefyDependencies).
|
|
118
|
+
dedupe: [
|
|
119
|
+
'react',
|
|
120
|
+
'react-dom',
|
|
121
|
+
'antd',
|
|
122
|
+
'@ant-design/x',
|
|
123
|
+
'@ant-design/cssinjs',
|
|
124
|
+
'dayjs',
|
|
125
|
+
...lowdefyDependencies,
|
|
126
|
+
],
|
|
99
127
|
},
|
|
100
128
|
server: {
|
|
101
129
|
watch: {
|
|
@@ -105,7 +133,9 @@ export default defineConfig(({ mode }) => ({
|
|
|
105
133
|
// not need these events: globals.css imports build/tailwind-candidates.css,
|
|
106
134
|
// which the JIT builder touches whenever tailwind content changes (the
|
|
107
135
|
// sole recompile trigger — see writeGlobalsCss in @lowdefy/build).
|
|
108
|
-
|
|
136
|
+
// The config build writes into build-staging and then moves each file
|
|
137
|
+
// into build, so only build is watched.
|
|
138
|
+
ignored: ['**/lowdefy-build/tailwind/**', '**/build-staging/**'],
|
|
109
139
|
},
|
|
110
140
|
},
|
|
111
141
|
}));
|
|
@@ -1,70 +0,0 @@
|
|
|
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 { createSessionCallback } from '@lowdefy/api';
|
|
18
|
-
|
|
19
|
-
import authJson from '../../build/auth.js';
|
|
20
|
-
import callbacks from '../../../build/plugins/auth/callbacks.js';
|
|
21
|
-
import getHeadlessUser from './getHeadlessUser.js';
|
|
22
|
-
import getMockUser from './getMockUser.js';
|
|
23
|
-
|
|
24
|
-
// THE single source of dev sessions (mock user, headless renderer). Two
|
|
25
|
-
// invariants live here, by construction rather than by convention:
|
|
26
|
-
//
|
|
27
|
-
// 1. Prod parity: the dev user runs through the identical Auth.js session
|
|
28
|
-
// callback a real sign-in uses (OIDC claim copy, userFields mapping,
|
|
29
|
-
// custom session-callback plugins, roles validation, hashed_id) — so what
|
|
30
|
-
// a mock or headless session sees is exactly what a real authenticated
|
|
31
|
-
// user would see in production, and dev validates prod behaviour.
|
|
32
|
-
// 2. Client/server parity: every consumer — the server request context
|
|
33
|
-
// (session.js) and the browser client's GET /api/auth/session
|
|
34
|
-
// (routes/auth.js) — obtains the session from this one function, so the
|
|
35
|
-
// two can never diverge.
|
|
36
|
-
//
|
|
37
|
-
// Auth.js sessions carry an expires timestamp (the client SessionProvider
|
|
38
|
-
// schedules refetches off it); dev sessions never expire while the server
|
|
39
|
-
// runs, a day keeps polling calm.
|
|
40
|
-
const DEV_SESSION_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
41
|
-
|
|
42
|
-
async function getDevSession(c) {
|
|
43
|
-
const user = getMockUser() ?? getHeadlessUser(c);
|
|
44
|
-
if (!user) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
// Without auth configured nothing is protected and there is no session
|
|
48
|
-
// callback pipeline to run — a dev session would not match any prod
|
|
49
|
-
// behaviour. (A configured mock user already threw in getMockUser.)
|
|
50
|
-
if (authJson.configured !== true) {
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const sessionCallback = createSessionCallback({
|
|
55
|
-
authConfig: authJson,
|
|
56
|
-
plugins: { callbacks },
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// The dev user acts as both token and user, exactly how a decoded JWT
|
|
60
|
-
// reaches the session callback on a real request.
|
|
61
|
-
const session = await sessionCallback({
|
|
62
|
-
session: { user: {} },
|
|
63
|
-
token: user,
|
|
64
|
-
user,
|
|
65
|
-
});
|
|
66
|
-
session.expires = new Date(Date.now() + DEV_SESSION_MAX_AGE_MS).toISOString();
|
|
67
|
-
return session;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export default getDevSession;
|
|
@@ -1,138 +0,0 @@
|
|
|
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
|
-
import { fileURLToPath } from 'url';
|
|
20
|
-
|
|
21
|
-
import { jest } from '@jest/globals';
|
|
22
|
-
|
|
23
|
-
// Only the auth build artifact is mocked — createSessionCallback is the REAL
|
|
24
|
-
// @lowdefy/api pipeline, because prod parity is exactly what these tests
|
|
25
|
-
// exist to prove: a dev session must be shaped by the same userFields
|
|
26
|
-
// mapping, roles validation, and hashed_id stamping as a real sign-in.
|
|
27
|
-
jest.unstable_mockModule('../../build/auth.js', () => ({
|
|
28
|
-
default: {
|
|
29
|
-
configured: true,
|
|
30
|
-
callbacks: [],
|
|
31
|
-
userFields: {
|
|
32
|
-
id: 'user.id',
|
|
33
|
-
roles: 'user.roles',
|
|
34
|
-
global_attributes: 'user.global_attributes',
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
|
-
// getDevSession statically imports the app build's auth callbacks module,
|
|
40
|
-
// which only exists in a built app (build/** is gitignored). Materialize an
|
|
41
|
-
// empty one — exactly what a build without custom auth callback plugins
|
|
42
|
-
// writes — so the import resolves; clean up only if this test created it.
|
|
43
|
-
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
44
|
-
const callbacksDir = path.resolve(dirname, '../../../build/plugins/auth');
|
|
45
|
-
const callbacksPath = path.join(callbacksDir, 'callbacks.js');
|
|
46
|
-
const createdCallbacksFixture = !fs.existsSync(callbacksPath);
|
|
47
|
-
if (createdCallbacksFixture) {
|
|
48
|
-
fs.mkdirSync(callbacksDir, { recursive: true });
|
|
49
|
-
fs.writeFileSync(callbacksPath, 'export default {};\n');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
afterAll(() => {
|
|
53
|
-
if (createdCallbacksFixture) {
|
|
54
|
-
fs.rmSync(callbacksPath, { force: true });
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const { default: getDevSession } = await import('./getDevSession.js');
|
|
59
|
-
const { HEADLESS_USER_COOKIE, headlessUser } = await import('./headlessUser.js');
|
|
60
|
-
|
|
61
|
-
function createContext({ cookie } = {}) {
|
|
62
|
-
return { req: { header: (name) => (name === 'cookie' ? (cookie ?? '') : undefined) } };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function headlessCookie(user = headlessUser) {
|
|
66
|
-
return `${HEADLESS_USER_COOKIE}=${Buffer.from(JSON.stringify(user)).toString('base64')}`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const originalDevUser = process.env.LOWDEFY_DEV_USER;
|
|
70
|
-
|
|
71
|
-
afterEach(() => {
|
|
72
|
-
if (originalDevUser === undefined) {
|
|
73
|
-
delete process.env.LOWDEFY_DEV_USER;
|
|
74
|
-
} else {
|
|
75
|
-
process.env.LOWDEFY_DEV_USER = originalDevUser;
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('getDevSession returns undefined with no mock user and no headless cookie', async () => {
|
|
80
|
-
delete process.env.LOWDEFY_DEV_USER;
|
|
81
|
-
expect(await getDevSession(createContext())).toBe(undefined);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('mock user session is built by the real session callback — userFields, hashed_id, expires', async () => {
|
|
85
|
-
// The claim shape a consuming app's tenant convention uses (e.g.
|
|
86
|
-
// global_attributes.company_ids) must survive to session.user on BOTH the
|
|
87
|
-
// server request path and the client session endpoint — this session is
|
|
88
|
-
// what both serve.
|
|
89
|
-
process.env.LOWDEFY_DEV_USER = JSON.stringify({
|
|
90
|
-
id: 'dev-user',
|
|
91
|
-
sub: 'dev-user',
|
|
92
|
-
name: 'Dev User',
|
|
93
|
-
roles: ['admin'],
|
|
94
|
-
global_attributes: { company_ids: ['C-1'] },
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const session = await getDevSession(createContext());
|
|
98
|
-
expect(session.user.id).toEqual('dev-user');
|
|
99
|
-
expect(session.user.name).toEqual('Dev User');
|
|
100
|
-
expect(session.user.roles).toEqual(['admin']);
|
|
101
|
-
expect(session.user.global_attributes).toEqual({ company_ids: ['C-1'] });
|
|
102
|
-
// Prod-session markers from the real pipeline:
|
|
103
|
-
expect(typeof session.hashed_id).toBe('string');
|
|
104
|
-
expect(session.hashed_id.length).toBeGreaterThan(0);
|
|
105
|
-
expect(new Date(session.expires).getTime()).toBeGreaterThan(Date.now());
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('headless cookie session runs through the same pipeline as a real sign-in', async () => {
|
|
109
|
-
delete process.env.LOWDEFY_DEV_USER;
|
|
110
|
-
|
|
111
|
-
const session = await getDevSession(createContext({ cookie: headlessCookie() }));
|
|
112
|
-
expect(session.user.id).toEqual(headlessUser.id);
|
|
113
|
-
expect(session.user.roles).toEqual([]);
|
|
114
|
-
expect(typeof session.hashed_id).toBe('string');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test('mock user takes precedence over the headless cookie', async () => {
|
|
118
|
-
process.env.LOWDEFY_DEV_USER = JSON.stringify({ id: 'mock-wins', roles: [] });
|
|
119
|
-
|
|
120
|
-
const session = await getDevSession(createContext({ cookie: headlessCookie() }));
|
|
121
|
-
expect(session.user.id).toEqual('mock-wins');
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
test('invalid roles are rejected by the real pipeline, exactly as in prod', async () => {
|
|
125
|
-
process.env.LOWDEFY_DEV_USER = JSON.stringify({ id: 'bad', roles: 'admin' });
|
|
126
|
-
|
|
127
|
-
await expect(getDevSession(createContext())).rejects.toThrow(
|
|
128
|
-
'session.user.roles must be an array of strings.'
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test('invalid JSON in LOWDEFY_DEV_USER throws a clear error', async () => {
|
|
133
|
-
process.env.LOWDEFY_DEV_USER = 'not json';
|
|
134
|
-
|
|
135
|
-
await expect(getDevSession(createContext())).rejects.toThrow(
|
|
136
|
-
'Invalid JSON in LOWDEFY_DEV_USER environment variable.'
|
|
137
|
-
);
|
|
138
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
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
|
-
// Auth.js derives the app origin from request headers (trustHost), so an unset
|
|
18
|
-
// AUTH_URL works on whatever port the dev server binds to. But when AUTH_URL (or
|
|
19
|
-
// the v4 fallback NEXTAUTH_URL) is set, @auth/core pins the origin to it verbatim
|
|
20
|
-
// — OAuth callbacks and sign-in redirects then target that URL. A pinned URL on a
|
|
21
|
-
// mismatched port is left untouched but warned about.
|
|
22
|
-
function warnAuthUrlPortMismatch({ context }) {
|
|
23
|
-
const { port } = context.options;
|
|
24
|
-
const name = process.env.AUTH_URL ? 'AUTH_URL' : 'NEXTAUTH_URL';
|
|
25
|
-
const current = process.env.AUTH_URL ?? process.env.NEXTAUTH_URL;
|
|
26
|
-
|
|
27
|
-
if (!current) return;
|
|
28
|
-
|
|
29
|
-
let currentPort;
|
|
30
|
-
try {
|
|
31
|
-
const url = new URL(current);
|
|
32
|
-
currentPort = url.port || (url.protocol === 'https:' ? '443' : '80');
|
|
33
|
-
} catch (_) {
|
|
34
|
-
context.logger.warn(`${name} (${current}) is not a valid URL.`);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (currentPort !== String(port)) {
|
|
39
|
-
context.logger.warn(
|
|
40
|
-
`${name} (${current}) does not match the dev server port ${port}. ` +
|
|
41
|
-
`Auth sign-in callbacks and redirects will target ${current}. ` +
|
|
42
|
-
`Update ${name} or unset it to derive the origin from the request.`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export default warnAuthUrlPortMismatch;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { jest } from '@jest/globals';
|
|
18
|
-
import warnAuthUrlPortMismatch from './warnAuthUrlPortMismatch.mjs';
|
|
19
|
-
|
|
20
|
-
const originalAuthUrl = process.env.AUTH_URL;
|
|
21
|
-
const originalNextAuthUrl = process.env.NEXTAUTH_URL;
|
|
22
|
-
|
|
23
|
-
function createContext(port) {
|
|
24
|
-
return {
|
|
25
|
-
options: { port },
|
|
26
|
-
logger: { warn: jest.fn() },
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function restoreEnv(name, value) {
|
|
31
|
-
if (value === undefined) {
|
|
32
|
-
delete process.env[name];
|
|
33
|
-
} else {
|
|
34
|
-
process.env[name] = value;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
delete process.env.AUTH_URL;
|
|
40
|
-
delete process.env.NEXTAUTH_URL;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterEach(() => {
|
|
44
|
-
restoreEnv('AUTH_URL', originalAuthUrl);
|
|
45
|
-
restoreEnv('NEXTAUTH_URL', originalNextAuthUrl);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('warnAuthUrlPortMismatch stays silent when no auth URL is set', () => {
|
|
49
|
-
const context = createContext(3001);
|
|
50
|
-
warnAuthUrlPortMismatch({ context });
|
|
51
|
-
expect(context.logger.warn).not.toHaveBeenCalled();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('warnAuthUrlPortMismatch stays silent when AUTH_URL matches the dev port', () => {
|
|
55
|
-
process.env.AUTH_URL = 'http://localhost:3000';
|
|
56
|
-
const context = createContext(3000);
|
|
57
|
-
warnAuthUrlPortMismatch({ context });
|
|
58
|
-
expect(context.logger.warn).not.toHaveBeenCalled();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('warnAuthUrlPortMismatch warns when AUTH_URL port does not match', () => {
|
|
62
|
-
process.env.AUTH_URL = 'http://localhost:3000';
|
|
63
|
-
const context = createContext(3001);
|
|
64
|
-
warnAuthUrlPortMismatch({ context });
|
|
65
|
-
expect(context.logger.warn).toHaveBeenCalledTimes(1);
|
|
66
|
-
expect(context.logger.warn.mock.calls[0][0]).toContain(
|
|
67
|
-
'AUTH_URL (http://localhost:3000) does not match the dev server port 3001'
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('warnAuthUrlPortMismatch falls back to NEXTAUTH_URL and names it in the warning', () => {
|
|
72
|
-
process.env.NEXTAUTH_URL = 'http://localhost:3000';
|
|
73
|
-
const context = createContext(3001);
|
|
74
|
-
warnAuthUrlPortMismatch({ context });
|
|
75
|
-
expect(context.logger.warn).toHaveBeenCalledTimes(1);
|
|
76
|
-
expect(context.logger.warn.mock.calls[0][0]).toContain('NEXTAUTH_URL (http://localhost:3000)');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('warnAuthUrlPortMismatch treats an https URL without a port as 443', () => {
|
|
80
|
-
process.env.AUTH_URL = 'https://example.com';
|
|
81
|
-
const context = createContext(3000);
|
|
82
|
-
warnAuthUrlPortMismatch({ context });
|
|
83
|
-
expect(context.logger.warn).toHaveBeenCalledTimes(1);
|
|
84
|
-
expect(context.logger.warn.mock.calls[0][0]).toContain('does not match the dev server port 3000');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('warnAuthUrlPortMismatch warns when the auth URL is not a valid URL', () => {
|
|
88
|
-
process.env.AUTH_URL = 'not-a-url';
|
|
89
|
-
const context = createContext(3000);
|
|
90
|
-
warnAuthUrlPortMismatch({ context });
|
|
91
|
-
expect(context.logger.warn).toHaveBeenCalledTimes(1);
|
|
92
|
-
expect(context.logger.warn.mock.calls[0][0]).toContain('is not a valid URL');
|
|
93
|
-
});
|