@lowdefy/server-dev 0.0.0-experimental-20260720072521 → 0.0.0-experimental-20260720135014
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/.eslintrc.yaml +1 -0
- package/lib/build/app.js +1 -8
- package/lib/build/appMeta.js +1 -8
- package/lib/build/auth.js +1 -8
- package/lib/build/config.js +1 -8
- package/lib/build/i18n.js +1 -8
- package/lib/build/logger.js +1 -8
- package/lib/build/theme.js +1 -8
- package/lib/client/App.js +80 -0
- package/{client/Page.jsx → lib/client/Page.js} +5 -5
- package/{client/Reload.jsx → lib/client/Reload.js} +7 -5
- package/lib/client/auth/{Auth.jsx → Auth.js} +5 -12
- package/lib/client/auth/AuthConfigured.js +61 -0
- package/lib/client/auth/AuthNotConfigured.js +2 -22
- package/lib/client/setPageId.js +5 -6
- package/lib/client/utils/useMutateCache.js +1 -14
- package/lib/client/utils/usePageConfig.js +11 -31
- package/lib/server/apiWrapper.js +116 -0
- package/lib/server/auth/{getStrategies.js → getAuthOptions.js} +9 -14
- package/lib/server/auth/{getMockUser.js → getMockSession.js} +19 -10
- package/{src/routes/docs/checkpointsRevert.js → lib/server/auth/getServerSession.js} +13 -11
- package/lib/server/compileCss.js +39 -0
- package/lib/server/jitPageBuilder.js +11 -36
- package/lib/server/log/logRequest.js +3 -1
- package/manager/getContext.mjs +7 -3
- package/manager/processes/compileCss.mjs +54 -0
- package/manager/processes/initialBuild.mjs +2 -0
- package/manager/processes/installPlugins.mjs +11 -19
- package/manager/processes/lowdefyBuild.mjs +7 -29
- package/manager/processes/nextBuild.mjs +50 -0
- package/manager/processes/readDotEnv.mjs +1 -13
- package/manager/processes/shutdownServer.mjs +6 -6
- package/manager/processes/startServer.mjs +7 -8
- package/manager/processes/startWatchers.mjs +2 -2
- package/manager/run.mjs +0 -41
- package/manager/utils/createCustomPluginMessagesMap.mjs +1 -8
- package/manager/utils/createCustomPluginTypesMap.mjs +2 -3
- package/manager/utils/{getViteBin.mjs → getNextBin.mjs} +10 -7
- package/manager/utils/updatePageTailwindCss.mjs +1 -7
- package/manager/watchers/lowdefyBuildWatcher.mjs +1 -0
- package/manager/watchers/moduleBuildWatcher.mjs +1 -0
- package/manager/watchers/{serverArtifactWatcher.mjs → nextBuildWatcher.mjs} +22 -18
- package/next.config.js +25 -0
- package/package.json +47 -63
- package/package.original.json +55 -66
- package/{src/routes/devTools.js → pages/404.js} +2 -4
- package/{src/routes/docs/appMap.js → pages/[[...pageId]].js} +2 -6
- package/{client/App.jsx → pages/_app.js} +33 -21
- package/pages/_document.js +107 -0
- package/pages/api/agent/[...path].js +86 -0
- package/pages/api/auth/[...nextauth].js +48 -0
- package/pages/api/client-error.js +45 -0
- package/{src/routes/docs/buildStatus.js → pages/api/dev-tools.js} +4 -5
- package/{lib/docs/clientErrorStore.js → pages/api/endpoints/[...endpointId].js} +11 -15
- package/{src/lib/serveBuildJs.js → pages/api/icons/dynamic.js} +12 -8
- package/{src/routes/jsEnv.js → pages/api/js/[env].js} +20 -8
- package/pages/api/page/[...pageId].js +74 -0
- package/{src/routes → pages/api}/ping.js +2 -4
- package/pages/api/reload.js +53 -0
- package/pages/api/request/[...path].js +41 -0
- package/{src/routes → pages/api}/root.js +4 -4
- package/client/Inspector.jsx +0 -206
- package/client/Routing.jsx +0 -106
- package/client/feedback/FeedbackMount.jsx +0 -83
- package/client/feedback/FeedbackOverlay.jsx +0 -901
- package/client/feedback/captureTabScreenshot.js +0 -84
- package/client/feedback/copyToClipboard.js +0 -45
- package/client/feedback/drawAnnotationsSvg.js +0 -119
- package/client/feedback/elementInspect.js +0 -99
- package/client/feedback/feedbackStyles.js +0 -301
- package/client/feedback/pinResponsiveImages.js +0 -59
- package/client/feedback/sendFeedback.js +0 -39
- package/client/feedback/useFeedbackToggle.js +0 -70
- package/client/main.jsx +0 -42
- package/client/openInEditor/OpenInEditorListener.jsx +0 -261
- package/client/openInEditor/findBlockLocation.js +0 -51
- package/lib/client/auth/AuthConfigured.jsx +0 -155
- package/lib/docs/captureAnnotatedScreenshot.js +0 -88
- package/lib/docs/checkpointPaths.js +0 -91
- package/lib/docs/checkpointStore.js +0 -234
- package/lib/docs/checkpointToMocks.js +0 -65
- package/lib/docs/configCheckpoints.test.mjs +0 -156
- package/lib/docs/createConfigCheckpoint.js +0 -92
- package/lib/docs/createDocsMcpServer.js +0 -506
- package/lib/docs/createDocsMcpServer.test.mjs +0 -123
- package/lib/docs/devMockRegistry.js +0 -68
- package/lib/docs/docs.test.mjs +0 -448
- package/lib/docs/enrichFeedback.js +0 -71
- package/lib/docs/evalOperator.js +0 -39
- package/lib/docs/evalOperator.test.mjs +0 -112
- package/lib/docs/evalOperatorHeadless.js +0 -87
- package/lib/docs/evalOperatorHeadless.test.mjs +0 -72
- package/lib/docs/evalOperatorInTab.js +0 -48
- package/lib/docs/findConfig.js +0 -260
- package/lib/docs/formatFeedback.js +0 -121
- package/lib/docs/formatFeedback.test.mjs +0 -204
- package/lib/docs/getAppMap.js +0 -180
- package/lib/docs/getBrowser.js +0 -115
- package/lib/docs/getBuildStatus.js +0 -37
- package/lib/docs/getCoreDoc.js +0 -63
- package/lib/docs/getDocsManifest.js +0 -40
- package/lib/docs/getExamples.js +0 -58
- package/lib/docs/getOverview.js +0 -115
- package/lib/docs/getPageConfig.js +0 -53
- package/lib/docs/getPluginDoc.js +0 -55
- package/lib/docs/getSchema.js +0 -65
- package/lib/docs/inspectState.js +0 -41
- package/lib/docs/inspectState.test.mjs +0 -91
- package/lib/docs/inspectStateFromTab.js +0 -40
- package/lib/docs/inspectStateHeadless.js +0 -84
- package/lib/docs/inspectStateHeadless.test.mjs +0 -60
- package/lib/docs/isWriteRequestsAllowed.js +0 -50
- package/lib/docs/listConfigCheckpoints.js +0 -55
- package/lib/docs/listPlugins.js +0 -80
- package/lib/docs/listTypes.js +0 -105
- package/lib/docs/loadState.js +0 -139
- package/lib/docs/mapPageBuildErrors.js +0 -28
- package/lib/docs/normalizeTypeKind.js +0 -40
- package/lib/docs/readBuildArtifact.js +0 -35
- package/lib/docs/readPageArtifact.js +0 -26
- package/lib/docs/resolvePluginDir.js +0 -49
- package/lib/docs/revertConfigCheckpoint.js +0 -73
- package/lib/docs/runRequest.js +0 -141
- package/lib/docs/saveAnnotatedScreenshot.js +0 -43
- package/lib/docs/scaffoldPage.js +0 -75
- package/lib/docs/scaffoldPage.test.mjs +0 -97
- package/lib/docs/screenshotPage.js +0 -109
- package/lib/docs/screenshotPage.test.mjs +0 -59
- package/lib/docs/screenshotPageClip.test.mjs +0 -102
- package/lib/docs/searchDocs.js +0 -67
- package/lib/docs/setupTestFixtures.mjs +0 -335
- package/lib/docs/snapshotState.js +0 -59
- package/lib/docs/stateCheckpoints.test.mjs +0 -348
- package/lib/docs/tabAvailable.js +0 -28
- package/lib/docs/tabChannel.js +0 -119
- package/lib/docs/tabChannel.test.mjs +0 -130
- package/lib/server/auth/createSystemContext.js +0 -70
- package/lib/server/auth/getAuth.js +0 -46
- package/lib/server/auth/getHeadlessUser.js +0 -39
- package/lib/server/auth/headlessUser.js +0 -30
- package/lib/server/createLowdefyContext.js +0 -133
- package/lib/server/loadDynamicJsMap.js +0 -47
- package/manager/processes/lowdefyBuild.test.mjs +0 -102
- package/manager/utils/formatNoticeBox.mjs +0 -30
- package/manager/utils/writeBuildStatus.mjs +0 -39
- package/manager/utils/writeBuildStatus.test.mjs +0 -76
- package/postcss.config.cjs +0 -1
- package/src/app.js +0 -188
- package/src/html/renderDevPage.js +0 -86
- package/src/lib/getPathSegments.js +0 -25
- package/src/lib/safeScriptJson.js +0 -38
- package/src/middleware/apiContext.js +0 -32
- package/src/middleware/errorHandler.js +0 -55
- package/src/routes/agent.js +0 -64
- package/src/routes/auth.js +0 -43
- package/src/routes/clientError.js +0 -57
- package/src/routes/cron.js +0 -44
- package/src/routes/detached.js +0 -51
- package/src/routes/devInspect.js +0 -94
- package/src/routes/docs/checkpointsCreate.js +0 -28
- package/src/routes/docs/checkpointsList.js +0 -23
- package/src/routes/docs/content.js +0 -31
- package/src/routes/docs/evalOperator.js +0 -46
- package/src/routes/docs/examples.js +0 -33
- package/src/routes/docs/find.js +0 -30
- package/src/routes/docs/index.js +0 -23
- package/src/routes/docs/inspectState.js +0 -34
- package/src/routes/docs/loadState.js +0 -38
- package/src/routes/docs/mcp.js +0 -30
- package/src/routes/docs/pageConfig.js +0 -36
- package/src/routes/docs/pluginDoc.js +0 -33
- package/src/routes/docs/plugins.js +0 -23
- package/src/routes/docs/runRequest.js +0 -34
- package/src/routes/docs/schema.js +0 -37
- package/src/routes/docs/screenshot.js +0 -66
- package/src/routes/docs/search.js +0 -27
- package/src/routes/docs/snapshotState.js +0 -36
- package/src/routes/docs/stateCheckpointsList.js +0 -26
- package/src/routes/docs/types.js +0 -33
- package/src/routes/endpoints.js +0 -76
- package/src/routes/feedback.js +0 -110
- package/src/routes/feedback.test.mjs +0 -204
- package/src/routes/iconsDynamic.js +0 -25
- package/src/routes/jitPage.js +0 -99
- package/src/routes/reload.js +0 -81
- package/src/routes/request.js +0 -66
- package/src/routes/usage.js +0 -46
- package/src/routes/user.js +0 -27
- package/src/routes/websocket.js +0 -33
- package/src/websocket/devWebSocket.js +0 -78
- package/vite.config.js +0 -111
- /package/lib/client/{BuildErrorPage.jsx → BuildErrorPage.js} +0 -0
- /package/lib/client/{BuildingPage.jsx → BuildingPage.js} +0 -0
- /package/lib/client/{ErrorBar.jsx → ErrorBar.js} +0 -0
- /package/lib/client/{InstallingPluginsPage.jsx → InstallingPluginsPage.js} +0 -0
- /package/lib/client/{RestartingPage.jsx → RestartingPage.js} +0 -0
|
@@ -1,59 +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
|
-
// html-to-image embeds img.src and clones srcset/<source> attributes as-is:
|
|
18
|
-
// the selection the browser actually displays (img.currentSrc) is ignored, so
|
|
19
|
-
// a <picture> rasterizes its fallback src stretched into the displayed box
|
|
20
|
-
// (e.g. the PageHeaderMenu square logo warped into the wordmark's slot), and
|
|
21
|
-
// remote srcset candidates can't load inside the sandboxed SVG rasterization
|
|
22
|
-
// anyway. Pin every responsive image to its currentSrc for the capture — the
|
|
23
|
-
// URL the tab already displays, so nothing changes visually — and return a
|
|
24
|
-
// restore function for the caller's finally block.
|
|
25
|
-
function pinResponsiveImages() {
|
|
26
|
-
const restores = [];
|
|
27
|
-
|
|
28
|
-
document.querySelectorAll('img').forEach((img) => {
|
|
29
|
-
const isResponsive =
|
|
30
|
-
img.hasAttribute('srcset') || (img.currentSrc && img.currentSrc !== img.src);
|
|
31
|
-
if (!img.currentSrc || !isResponsive) return;
|
|
32
|
-
const src = img.getAttribute('src');
|
|
33
|
-
const srcset = img.getAttribute('srcset');
|
|
34
|
-
restores.push(() => {
|
|
35
|
-
if (src === null) {
|
|
36
|
-
img.removeAttribute('src');
|
|
37
|
-
} else {
|
|
38
|
-
img.setAttribute('src', src);
|
|
39
|
-
}
|
|
40
|
-
if (srcset !== null) {
|
|
41
|
-
img.setAttribute('srcset', srcset);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
img.setAttribute('src', img.currentSrc);
|
|
45
|
-
img.removeAttribute('srcset');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
document.querySelectorAll('picture > source[srcset]').forEach((source) => {
|
|
49
|
-
const srcset = source.getAttribute('srcset');
|
|
50
|
-
restores.push(() => source.setAttribute('srcset', srcset));
|
|
51
|
-
source.removeAttribute('srcset');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return function restore() {
|
|
55
|
-
restores.forEach((fn) => fn());
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default pinResponsiveImages;
|
|
@@ -1,39 +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
|
-
// Sends the batch to the dev server for enrichment (blockId → yaml file:line
|
|
18
|
-
// via the build's keyMap) and gets back the formatted, agent-readable text.
|
|
19
|
-
// Best-effort, matching Inspector.jsx's postResult style — a dev-only feature
|
|
20
|
-
// must never throw into the app it rides along with. Returns the formatted
|
|
21
|
-
// string, or null on any failure.
|
|
22
|
-
async function sendFeedback({ basePath, batch }) {
|
|
23
|
-
try {
|
|
24
|
-
const response = await fetch(`${basePath}/lowdefy-feedback`, {
|
|
25
|
-
method: 'POST',
|
|
26
|
-
headers: { 'Content-Type': 'application/json' },
|
|
27
|
-
body: JSON.stringify(batch),
|
|
28
|
-
});
|
|
29
|
-
if (!response.ok) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
const data = await response.json();
|
|
33
|
-
return typeof data.formatted === 'string' ? data.formatted : null;
|
|
34
|
-
} catch {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export default sendFeedback;
|
|
@@ -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 { useEffect, useRef } from 'react';
|
|
18
|
-
|
|
19
|
-
import { tinykeys } from 'tinykeys';
|
|
20
|
-
|
|
21
|
-
// Binds the global Cmd/Ctrl+/ feedback toggle, matching the app's own
|
|
22
|
-
// shortcut convention (see createShortcutManager.js): tinykeys on window,
|
|
23
|
-
// "$mod" for the platform modifier. Registered at capture phase with
|
|
24
|
-
// stopImmediatePropagation so the app's own shortcut manager (or any block
|
|
25
|
-
// event bound to the same key) never also fires.
|
|
26
|
-
function useFeedbackToggle({ onToggle }) {
|
|
27
|
-
const onToggleRef = useRef(onToggle);
|
|
28
|
-
onToggleRef.current = onToggle;
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (typeof window === 'undefined') {
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let unsubscribe;
|
|
36
|
-
try {
|
|
37
|
-
unsubscribe = tinykeys(
|
|
38
|
-
window,
|
|
39
|
-
{
|
|
40
|
-
'$mod+Slash': (event) => {
|
|
41
|
-
try {
|
|
42
|
-
event.preventDefault();
|
|
43
|
-
event.stopImmediatePropagation();
|
|
44
|
-
if (onToggleRef.current) {
|
|
45
|
-
onToggleRef.current();
|
|
46
|
-
}
|
|
47
|
-
} catch {
|
|
48
|
-
// Never let the toggle handler crash the app.
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
{ capture: true }
|
|
53
|
-
);
|
|
54
|
-
} catch {
|
|
55
|
-
// tinykeys unavailable or binding failed — the feature just won't toggle.
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return () => {
|
|
59
|
-
try {
|
|
60
|
-
if (unsubscribe) {
|
|
61
|
-
unsubscribe();
|
|
62
|
-
}
|
|
63
|
-
} catch {
|
|
64
|
-
// no-op
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}, []);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export default useFeedbackToggle;
|
package/client/main.jsx
DELETED
|
@@ -1,42 +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
|
-
// CSS layer order — MUST be the first CSS import. This locks the cascade
|
|
18
|
-
// priority (antd > base/preflight) before antd's StyleProvider injects
|
|
19
|
-
// @layer antd {} at runtime. Vite's PostCSS pipeline compiles globals.css
|
|
20
|
-
// (Tailwind) on the fly and hot-replaces it — the old tailwind-jit.css
|
|
21
|
-
// side-channel is gone.
|
|
22
|
-
import '../build/layer-order.css';
|
|
23
|
-
|
|
24
|
-
import React from 'react';
|
|
25
|
-
import { createRoot } from 'react-dom/client';
|
|
26
|
-
import createRouter from '@lowdefy/client/adapters/createRouter.js';
|
|
27
|
-
|
|
28
|
-
import App from './App.jsx';
|
|
29
|
-
|
|
30
|
-
import '../build/globals.css';
|
|
31
|
-
|
|
32
|
-
const config = JSON.parse(document.getElementById('__LOWDEFY_CONFIG__').textContent);
|
|
33
|
-
const router = createRouter({ basePath: config.basePath ?? '', window });
|
|
34
|
-
const container = document.getElementById('root');
|
|
35
|
-
|
|
36
|
-
// Keep one React root across Vite HMR updates.
|
|
37
|
-
const root = import.meta.hot?.data.root ?? createRoot(container);
|
|
38
|
-
if (import.meta.hot) {
|
|
39
|
-
import.meta.hot.data.root = root;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
root.render(<App config={config} router={router} />);
|
|
@@ -1,261 +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 React, { useEffect, useRef, useState } from 'react';
|
|
18
|
-
import { createPortal } from 'react-dom';
|
|
19
|
-
|
|
20
|
-
import { blockAncestorChain, nearestBlock } from '../feedback/elementInspect.js';
|
|
21
|
-
import { highlightBox, labelChip, overlayContainer } from '../feedback/feedbackStyles.js';
|
|
22
|
-
import findBlockLocation from './findBlockLocation.js';
|
|
23
|
-
|
|
24
|
-
const STYLE_TAG_ID = 'lowdefy-open-in-editor-style-tag';
|
|
25
|
-
const BODY_CLASS = 'lowdefy-open-in-editor-target';
|
|
26
|
-
|
|
27
|
-
// Cursor over arbitrary app descendants can't be forced from inline styles —
|
|
28
|
-
// same trick as feedbackStyles' picking/drawing classes.
|
|
29
|
-
function injectStyleTag() {
|
|
30
|
-
if (typeof document === 'undefined' || document.getElementById(STYLE_TAG_ID)) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const style = document.createElement('style');
|
|
34
|
-
style.id = STYLE_TAG_ID;
|
|
35
|
-
style.textContent = `
|
|
36
|
-
.${BODY_CLASS}, .${BODY_CLASS} * {
|
|
37
|
-
cursor: pointer !important;
|
|
38
|
-
}
|
|
39
|
-
`;
|
|
40
|
-
document.head.appendChild(style);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function removeStyleTag() {
|
|
44
|
-
if (typeof document === 'undefined') {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
document.getElementById(STYLE_TAG_ID)?.remove();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// The feedback overlay owns clicks while it is open (its picking mode claims
|
|
51
|
-
// them) — the Cmd/Ctrl+click shortcut stays out of the way until it closes.
|
|
52
|
-
// :not() skips this component's own highlight portal, which carries
|
|
53
|
-
// data-lowdefy-feedback purely for screenshot/picking exclusion.
|
|
54
|
-
function feedbackOverlayOpen() {
|
|
55
|
-
return Boolean(
|
|
56
|
-
document.querySelector('[data-lowdefy-feedback]:not([data-lowdefy-open-in-editor])')
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Dev-only: Cmd/Ctrl+click any element to open the YAML that defines its
|
|
61
|
-
// block in VS Code (vscode://file deep link, at the exact line). While the
|
|
62
|
-
// modifier is held, the hovered block shows the same blue highlight box and
|
|
63
|
-
// blockId chip as the annotation overlay's picking mode, and the cursor
|
|
64
|
-
// switches to a pointer — so the developer sees exactly what a click will
|
|
65
|
-
// open. Mounted always-on from Routing.jsx alongside Inspector and
|
|
66
|
-
// FeedbackMount, and follows their resilience contract — every handler is
|
|
67
|
-
// try/caught so this can never take the app down with it.
|
|
68
|
-
//
|
|
69
|
-
// The click resolves the nearest block and, when that id is generated at
|
|
70
|
-
// runtime (list items, Dynamic endpoints), falls back through the ancestor
|
|
71
|
-
// block chain until an id resolves in config — the same strategy the
|
|
72
|
-
// feedback pipeline uses in enrichFeedback.js.
|
|
73
|
-
function OpenInEditorListener({ basePath, pageId }) {
|
|
74
|
-
const [hoverBlock, setHoverBlock] = useState(null); // { blockId, rect }
|
|
75
|
-
// Refs keep the freshest values without re-binding the capture listeners
|
|
76
|
-
// on every SPA navigation or hover change.
|
|
77
|
-
const pageIdRef = useRef(pageId);
|
|
78
|
-
pageIdRef.current = pageId;
|
|
79
|
-
const hoverRef = useRef(hoverBlock);
|
|
80
|
-
hoverRef.current = hoverBlock;
|
|
81
|
-
const lastPointerRef = useRef(null); // { x, y }
|
|
82
|
-
|
|
83
|
-
// Style tag lifecycle — the listener is always mounted, so this lives for
|
|
84
|
-
// the app's lifetime and only the body class toggles per hover.
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
injectStyleTag();
|
|
87
|
-
return () => removeStyleTag();
|
|
88
|
-
}, []);
|
|
89
|
-
|
|
90
|
-
// Pointer cursor only while a block is highlighted — over non-block areas
|
|
91
|
-
// the cursor stays native, signalling the click would do nothing.
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
try {
|
|
94
|
-
document.body.classList.toggle(BODY_CLASS, Boolean(hoverBlock));
|
|
95
|
-
} catch {
|
|
96
|
-
// no-op
|
|
97
|
-
}
|
|
98
|
-
return () => {
|
|
99
|
-
try {
|
|
100
|
-
document.body.classList.remove(BODY_CLASS);
|
|
101
|
-
} catch {
|
|
102
|
-
// no-op
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
}, [hoverBlock]);
|
|
106
|
-
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
function clearHover() {
|
|
109
|
-
if (hoverRef.current) {
|
|
110
|
-
setHoverBlock(null);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function resolveHover() {
|
|
115
|
-
try {
|
|
116
|
-
const point = lastPointerRef.current;
|
|
117
|
-
if (!point || feedbackOverlayOpen()) {
|
|
118
|
-
clearHover();
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const el = document.elementFromPoint(point.x, point.y);
|
|
122
|
-
const blockId = nearestBlock(el);
|
|
123
|
-
const blockEl = blockId ? document.getElementById(`bl-${blockId}`) : null;
|
|
124
|
-
if (!blockEl) {
|
|
125
|
-
clearHover();
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const rect = blockEl.getBoundingClientRect();
|
|
129
|
-
setHoverBlock({
|
|
130
|
-
blockId,
|
|
131
|
-
rect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },
|
|
132
|
-
});
|
|
133
|
-
} catch {
|
|
134
|
-
clearHover();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function onPointerMove(event) {
|
|
139
|
-
try {
|
|
140
|
-
lastPointerRef.current = { x: event.clientX, y: event.clientY };
|
|
141
|
-
if (event.metaKey || event.ctrlKey) {
|
|
142
|
-
resolveHover();
|
|
143
|
-
} else {
|
|
144
|
-
clearHover();
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// Best-effort hover tracking.
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Modifier pressed/released while the mouse is stationary — pointermove
|
|
152
|
-
// alone would leave the highlight stale.
|
|
153
|
-
function onKeyDown(event) {
|
|
154
|
-
if (event.key === 'Meta' || event.key === 'Control') {
|
|
155
|
-
resolveHover();
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function onKeyUp(event) {
|
|
160
|
-
if (event.key === 'Meta' || event.key === 'Control') {
|
|
161
|
-
clearHover();
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Cmd+Tab away releases the modifier without a keyup reaching the page.
|
|
166
|
-
function onBlur() {
|
|
167
|
-
clearHover();
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Keep the highlight glued to the block while the app scrolls under a
|
|
171
|
-
// stationary cursor.
|
|
172
|
-
function onScroll() {
|
|
173
|
-
if (hoverRef.current) {
|
|
174
|
-
resolveHover();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async function openBlockInEditor({ candidates }) {
|
|
179
|
-
for (const blockId of candidates) {
|
|
180
|
-
const location = await findBlockLocation({
|
|
181
|
-
basePath,
|
|
182
|
-
blockId,
|
|
183
|
-
pageId: pageIdRef.current,
|
|
184
|
-
});
|
|
185
|
-
if (location) {
|
|
186
|
-
window.location.assign(`vscode://file${location.file}:${location.line}`);
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
try {
|
|
191
|
-
// eslint-disable-next-line no-console
|
|
192
|
-
console.info(
|
|
193
|
-
`Lowdefy: no config location found for "${candidates[0]}" — the block is generated at runtime.`
|
|
194
|
-
);
|
|
195
|
-
} catch {
|
|
196
|
-
// no-op
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function onClickCapture(event) {
|
|
201
|
-
try {
|
|
202
|
-
if (!(event.metaKey || event.ctrlKey) || event.shiftKey || event.altKey) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
if (feedbackOverlayOpen()) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
const candidates = blockAncestorChain(event.target);
|
|
209
|
-
if (candidates.length === 0) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
// Only claim the click once a block is under the cursor — plain
|
|
213
|
-
// Cmd/Ctrl+clicks elsewhere keep their default behaviour.
|
|
214
|
-
event.preventDefault();
|
|
215
|
-
event.stopPropagation();
|
|
216
|
-
void openBlockInEditor({ candidates });
|
|
217
|
-
} catch {
|
|
218
|
-
// Never let the shortcut break the developer's app.
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
window.addEventListener('pointermove', onPointerMove);
|
|
223
|
-
window.addEventListener('keydown', onKeyDown);
|
|
224
|
-
window.addEventListener('keyup', onKeyUp);
|
|
225
|
-
window.addEventListener('blur', onBlur);
|
|
226
|
-
window.addEventListener('scroll', onScroll, true);
|
|
227
|
-
window.addEventListener('click', onClickCapture, { capture: true });
|
|
228
|
-
return () => {
|
|
229
|
-
window.removeEventListener('pointermove', onPointerMove);
|
|
230
|
-
window.removeEventListener('keydown', onKeyDown);
|
|
231
|
-
window.removeEventListener('keyup', onKeyUp);
|
|
232
|
-
window.removeEventListener('blur', onBlur);
|
|
233
|
-
window.removeEventListener('scroll', onScroll, true);
|
|
234
|
-
window.removeEventListener('click', onClickCapture, { capture: true });
|
|
235
|
-
};
|
|
236
|
-
}, [basePath]);
|
|
237
|
-
|
|
238
|
-
if (!hoverBlock || typeof document === 'undefined' || !document.body) {
|
|
239
|
-
return null;
|
|
240
|
-
}
|
|
241
|
-
// data-lowdefy-feedback keeps this out of the annotation overlay's element
|
|
242
|
-
// picking and out of tab-captured screenshots (both exclude that root).
|
|
243
|
-
return createPortal(
|
|
244
|
-
<div data-lowdefy-feedback data-lowdefy-open-in-editor style={overlayContainer}>
|
|
245
|
-
<div
|
|
246
|
-
style={{
|
|
247
|
-
...highlightBox,
|
|
248
|
-
top: hoverBlock.rect.top,
|
|
249
|
-
left: hoverBlock.rect.left,
|
|
250
|
-
width: hoverBlock.rect.width,
|
|
251
|
-
height: hoverBlock.rect.height,
|
|
252
|
-
}}
|
|
253
|
-
>
|
|
254
|
-
<span style={labelChip}>{hoverBlock.blockId}</span>
|
|
255
|
-
</div>
|
|
256
|
-
</div>,
|
|
257
|
-
document.body
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export default OpenInEditorListener;
|
|
@@ -1,51 +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
|
-
// Resolves a blockId to its YAML source via the dev server's existing
|
|
18
|
-
// GET /lowdefy-docs/find/{id}?pageId= route (which JIT-builds the page's
|
|
19
|
-
// keyMap on demand). Returns { file, line } with an absolute file path, or
|
|
20
|
-
// null when the id has no configured location. Best-effort, matching
|
|
21
|
-
// sendFeedback.js — a dev-only feature must never throw into the app.
|
|
22
|
-
async function findBlockLocation({ basePath, blockId, pageId }) {
|
|
23
|
-
try {
|
|
24
|
-
// Omit pageId when unknown — an empty ?pageId= reads as an unknown page
|
|
25
|
-
// on the server, while no param falls back to scanning all built pages.
|
|
26
|
-
const query = pageId ? `?pageId=${encodeURIComponent(pageId)}` : '';
|
|
27
|
-
const response = await fetch(
|
|
28
|
-
`${basePath}/lowdefy-docs/find/${encodeURIComponent(blockId)}${query}`
|
|
29
|
-
);
|
|
30
|
-
if (!response.ok) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
const data = await response.json();
|
|
34
|
-
const source = data.matches?.[0]?.location?.source;
|
|
35
|
-
if (typeof source !== 'string' || source.length === 0) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
// source is "<absolute path>" or "<absolute path>:<line>" — a numeric
|
|
39
|
-
// suffix after the last colon is the 1-based line number. Splitting on
|
|
40
|
-
// the last colon keeps Windows drive-letter colons intact.
|
|
41
|
-
const match = source.match(/^(.*):(\d+)$/);
|
|
42
|
-
if (match) {
|
|
43
|
-
return { file: match[1], line: Number(match[2]) };
|
|
44
|
-
}
|
|
45
|
-
return { file: source, line: 1 };
|
|
46
|
-
} catch {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export default findBlockLocation;
|
|
@@ -1,155 +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 React, { useEffect, useRef } from 'react';
|
|
18
|
-
import { createAuthClient } from 'better-auth/react';
|
|
19
|
-
import {
|
|
20
|
-
adminClient,
|
|
21
|
-
genericOAuthClient,
|
|
22
|
-
magicLinkClient,
|
|
23
|
-
organizationClient,
|
|
24
|
-
phoneNumberClient,
|
|
25
|
-
twoFactorClient,
|
|
26
|
-
} from 'better-auth/client/plugins';
|
|
27
|
-
import { passkeyClient } from '@better-auth/passkey/client';
|
|
28
|
-
|
|
29
|
-
import { serializer } from '@lowdefy/helpers';
|
|
30
|
-
|
|
31
|
-
import rawLowdefyConfig from '../../../build/config.json';
|
|
32
|
-
|
|
33
|
-
const lowdefyConfig = serializer.deserialize(rawLowdefyConfig);
|
|
34
|
-
|
|
35
|
-
const authClient = createAuthClient({
|
|
36
|
-
baseURL: `${window.location.origin}${lowdefyConfig.basePath ?? ''}/api/auth`,
|
|
37
|
-
plugins: [
|
|
38
|
-
adminClient(),
|
|
39
|
-
genericOAuthClient(),
|
|
40
|
-
magicLinkClient(),
|
|
41
|
-
organizationClient(),
|
|
42
|
-
passkeyClient(),
|
|
43
|
-
phoneNumberClient(),
|
|
44
|
-
twoFactorClient(),
|
|
45
|
-
],
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// The server resolves the caller per request and embeds it in the page
|
|
49
|
-
// config, so the first render never flashes unauthenticated. The BetterAuth
|
|
50
|
-
// client store takes over once its session fetch settles.
|
|
51
|
-
//
|
|
52
|
-
// Roles and merged attributes resolve server-side from the active member row
|
|
53
|
-
// - the base session carries neither. The last server-resolved caller is
|
|
54
|
-
// kept in a ref: while the session user is unchanged its roles and
|
|
55
|
-
// attributes stay authoritative, and UpdateSession refreshes the ref from
|
|
56
|
-
// /api/user after a change (e.g. SetActiveOrganization).
|
|
57
|
-
function Session({ children, reloadSuppressedRef, serverUser }) {
|
|
58
|
-
const { data: session, isPending } = authClient.useSession();
|
|
59
|
-
const resolvedUserRef = useRef(serverUser);
|
|
60
|
-
const wasAuthenticated = useRef(Boolean(serverUser));
|
|
61
|
-
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
if (session) {
|
|
64
|
-
wasAuthenticated.current = true;
|
|
65
|
-
}
|
|
66
|
-
// Reload after sign-out (or session revocation) so the server can apply
|
|
67
|
-
// the page auth fork - a protected page redirects to the login page.
|
|
68
|
-
// A logout with a callbackUrl suppresses the reload - its own navigation
|
|
69
|
-
// would otherwise race this one.
|
|
70
|
-
if (wasAuthenticated.current && !isPending && !session && !reloadSuppressedRef.current) {
|
|
71
|
-
window.location.reload();
|
|
72
|
-
}
|
|
73
|
-
}, [session, isPending]);
|
|
74
|
-
|
|
75
|
-
if (isPending) {
|
|
76
|
-
return children(resolvedUserRef.current, resolvedUserRef);
|
|
77
|
-
}
|
|
78
|
-
if (!session?.user) {
|
|
79
|
-
return children(null, resolvedUserRef);
|
|
80
|
-
}
|
|
81
|
-
const resolved = resolvedUserRef.current;
|
|
82
|
-
const user =
|
|
83
|
-
resolved && resolved.id === session.user.id
|
|
84
|
-
? { ...session.user, roles: resolved.roles, attributes: resolved.attributes }
|
|
85
|
-
: { roles: [], ...session.user };
|
|
86
|
-
return children(user, resolvedUserRef);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function AuthConfigured({ authConfig, children, serverUser }) {
|
|
90
|
-
const reloadSuppressedRef = useRef(false);
|
|
91
|
-
const auth = {
|
|
92
|
-
authConfig,
|
|
93
|
-
getSession: ({ disableCookieCache } = {}) =>
|
|
94
|
-
authClient.getSession(disableCookieCache ? { query: { disableCookieCache: true } } : {}),
|
|
95
|
-
// The server-resolved caller - roles from the active member row and the
|
|
96
|
-
// merged attributes bag - for re-syncing after session changes.
|
|
97
|
-
getResolvedUser: async () => {
|
|
98
|
-
const response = await fetch(`${lowdefyConfig.basePath ?? ''}/api/user`, {
|
|
99
|
-
credentials: 'same-origin',
|
|
100
|
-
});
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
// Throw instead of parsing an error page - a silent { user: undefined }
|
|
103
|
-
// would read as a client-side logout in updateSession.
|
|
104
|
-
throw new Error(`Failed to fetch the resolved user (HTTP ${response.status}).`);
|
|
105
|
-
}
|
|
106
|
-
return response.json();
|
|
107
|
-
},
|
|
108
|
-
suppressSignOutReload: () => {
|
|
109
|
-
reloadSuppressedRef.current = true;
|
|
110
|
-
},
|
|
111
|
-
acceptInvitation: (params) => authClient.organization.acceptInvitation(params),
|
|
112
|
-
// addPasskey runs the WebAuthn browser ceremony itself - options fetch,
|
|
113
|
-
// authenticator prompt, verification.
|
|
114
|
-
addPasskey: (params) => authClient.passkey.addPasskey(params),
|
|
115
|
-
changePassword: (params) => authClient.changePassword(params),
|
|
116
|
-
deletePasskey: (params) => authClient.passkey.deletePasskey(params),
|
|
117
|
-
impersonateUser: (params) => authClient.admin.impersonateUser(params),
|
|
118
|
-
phoneNumberRequestPasswordReset: (params) =>
|
|
119
|
-
authClient.phoneNumber.requestPasswordReset(params),
|
|
120
|
-
phoneNumberResetPassword: (params) => authClient.phoneNumber.resetPassword(params),
|
|
121
|
-
phoneNumberSendOtp: (params) => authClient.phoneNumber.sendOtp(params),
|
|
122
|
-
phoneNumberVerify: (params) => authClient.phoneNumber.verify(params),
|
|
123
|
-
requestPasswordReset: (params) => authClient.requestPasswordReset(params),
|
|
124
|
-
resetPassword: (params) => authClient.resetPassword(params),
|
|
125
|
-
revokeOtherSessions: () => authClient.revokeOtherSessions(),
|
|
126
|
-
sendVerificationEmail: (params) => authClient.sendVerificationEmail(params),
|
|
127
|
-
setActiveOrganization: (params) => authClient.organization.setActive(params),
|
|
128
|
-
signInEmail: (params) => authClient.signIn.email(params),
|
|
129
|
-
signInMagicLink: (params) => authClient.signIn.magicLink(params),
|
|
130
|
-
signInOauth2: (params) => authClient.signIn.oauth2(params),
|
|
131
|
-
signInPasskey: (params) => authClient.signIn.passkey(params),
|
|
132
|
-
signInPhoneNumber: (params) => authClient.signIn.phoneNumber(params),
|
|
133
|
-
signInSocial: (params) => authClient.signIn.social(params),
|
|
134
|
-
signOut: () => authClient.signOut(),
|
|
135
|
-
signUpEmail: (params) => authClient.signUp.email(params),
|
|
136
|
-
stopImpersonating: () => authClient.admin.stopImpersonating(),
|
|
137
|
-
twoFactorDisable: (params) => authClient.twoFactor.disable(params),
|
|
138
|
-
twoFactorEnable: (params) => authClient.twoFactor.enable(params),
|
|
139
|
-
twoFactorVerifyBackupCode: (params) => authClient.twoFactor.verifyBackupCode(params),
|
|
140
|
-
twoFactorVerifyTotp: (params) => authClient.twoFactor.verifyTotp(params),
|
|
141
|
-
};
|
|
142
|
-
return (
|
|
143
|
-
<Session reloadSuppressedRef={reloadSuppressedRef} serverUser={serverUser}>
|
|
144
|
-
{(user, resolvedUserRef) => {
|
|
145
|
-
auth.user = user;
|
|
146
|
-
auth.updateResolvedUser = (resolved) => {
|
|
147
|
-
resolvedUserRef.current = resolved;
|
|
148
|
-
};
|
|
149
|
-
return children(auth);
|
|
150
|
-
}}
|
|
151
|
-
</Session>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export default AuthConfigured;
|