Harden auth/vault path sanitization and clean WeKnora docs
This commit is contained in:
@@ -293,6 +293,8 @@ import {
|
||||
};
|
||||
|
||||
const paneViewRegistry = new Map();
|
||||
/** 每 pane 导航世代:快速连点时丢弃过期 replacePaneDocument 结果,保证 last-click-wins。 */
|
||||
const paneReplaceGeneration = new Map();
|
||||
const currentWebShellWorkspaceId = () => {
|
||||
try {
|
||||
return currentUrl().searchParams.get('workspaceId') || '';
|
||||
@@ -709,6 +711,8 @@ import {
|
||||
};
|
||||
|
||||
const replacePaneDocument = async (paneRole, descriptor, options = {}) => {
|
||||
const generation = (paneReplaceGeneration.get(paneRole) || 0) + 1;
|
||||
paneReplaceGeneration.set(paneRole, generation);
|
||||
mindmapHost.unmountMindmapPane(paneRole);
|
||||
const root = paneRole === 'primary'
|
||||
? ensureLazyPrimaryPaneRoot()
|
||||
@@ -719,8 +723,12 @@ import {
|
||||
const aggregatePromise = options.aggregate
|
||||
? Promise.resolve(options.aggregate)
|
||||
: fetchPageAggregateForPane(descriptor);
|
||||
const previousView = paneViewRegistry.get(paneRole);
|
||||
const [runtime, aggregate] = await Promise.all([runtimePromise, aggregatePromise]);
|
||||
// 过期导航:丢弃结果,避免覆盖更新的 last-click View 并泄漏中间实例。
|
||||
if (paneReplaceGeneration.get(paneRole) !== generation) {
|
||||
return null;
|
||||
}
|
||||
const previousView = paneViewRegistry.get(paneRole);
|
||||
if (previousView) {
|
||||
unmountEditorViewBinding(previousView);
|
||||
paneViewRegistry.delete(paneRole);
|
||||
@@ -754,6 +762,13 @@ import {
|
||||
clearEmbeddedLocalDraft(runtimeDescriptor);
|
||||
try {
|
||||
const mountId = runtime.mount(runtimeDescriptor.root, mountOptions);
|
||||
if (paneReplaceGeneration.get(paneRole) !== generation) {
|
||||
try {
|
||||
if (typeof runtime.unmount === 'function') runtime.unmount(mountId);
|
||||
} catch (_) { /* ignore stale unmount */ }
|
||||
unmountEditorViewBinding(view);
|
||||
return null;
|
||||
}
|
||||
view.mountId = mountId;
|
||||
runtimeDescriptor.root.setAttribute('data-runtime-mount-id', String(mountId));
|
||||
runtimeDescriptor.root.setAttribute('data-editor-host-kind', 'leptos_tiptap_island');
|
||||
@@ -1181,7 +1196,9 @@ import {
|
||||
if (!id) return false;
|
||||
const descriptor = descriptorFromCurrentUrl('primary', id, { workspaceId, sourceKind, rootUri });
|
||||
descriptor.pageBlockNavigation = pageBlockNavigation === true;
|
||||
await replacePaneDocument('primary', descriptor);
|
||||
const view = await replacePaneDocument('primary', descriptor);
|
||||
// 过期导航(快速连点被 generation 丢弃)不得改 URL / 激活 tab。
|
||||
if (!view) return false;
|
||||
activateMainEditorTab('', 'primary');
|
||||
updatePrimaryUrl(descriptor, url instanceof URL ? url : null);
|
||||
return true;
|
||||
@@ -1202,7 +1219,8 @@ import {
|
||||
const id = typeof documentId === 'string' ? documentId.trim() : '';
|
||||
if (!id) return false;
|
||||
const descriptor = descriptorFromCurrentUrl('secondary', id, { workspaceId, sourceKind, rootUri });
|
||||
await replacePaneDocument('secondary', descriptor);
|
||||
const view = await replacePaneDocument('secondary', descriptor);
|
||||
if (!view) return false;
|
||||
activateMainEditorTab('', 'secondary');
|
||||
if (url instanceof URL) replaceUrlState(url);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user