noteconnection 1.6.8 → 1.8.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/LICENSE +674 -21
- package/README.md +258 -64
- package/dist/src/agent_workspace.contract.parity.test.js +475 -0
- package/dist/src/agent_workspace.frontend.test.js +9989 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/PathBridge.js +28 -3
- package/dist/src/export/WorkspaceExportBundle.js +1130 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +406 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
- package/dist/src/frontend/README.md +258 -64
- package/dist/src/frontend/agent_workspace.js +5353 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +3597 -141
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +641 -266
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/locales/en.json +721 -5
- package/dist/src/frontend/locales/zh.json +721 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +107 -0
- package/dist/src/frontend/path_app.js +2189 -150
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +522 -27
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/simulationWorker.js +241 -6
- package/dist/src/frontend/source_manager.js +190 -21
- package/dist/src/frontend/styles.css +2853 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10168 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/indexing/IndexLifecycle.js +195 -0
- package/dist/src/indexing/IndexLifecycle.test.js +49 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +170 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
- package/dist/src/learning/answerReleaseReview.js +4319 -0
- package/dist/src/learning/answerReleaseReview.test.js +2888 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1480 -0
- package/dist/src/learning/conversationComposer.test.js +1817 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1176 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphContextAssembler.js +870 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/index.js +28 -0
- package/dist/src/learning/queryBackend.js +1898 -0
- package/dist/src/learning/queryBackend.test.js +955 -0
- package/dist/src/learning/ragContextPack.js +257 -0
- package/dist/src/learning/ragContextPack.test.js +160 -0
- package/dist/src/learning/ragPublicText.js +38 -0
- package/dist/src/learning/ragSufficiencyJudge.js +161 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
- package/dist/src/learning/requestNormalization.js +198 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1240 -0
- package/dist/src/learning/store.test.js +1126 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +66 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/auth.js +17 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +21 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +498 -13
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +143 -35
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +16 -2
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +58 -0
- package/dist/src/platform/PlatformCapabilities.js +45 -0
- package/dist/src/platform/PlatformCapabilities.test.js +30 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +73 -0
- package/dist/src/resources/ResourceRegistry.js +223 -0
- package/dist/src/resources/ResourceRegistry.test.js +61 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/data.js +267 -0
- package/dist/src/routes/diagnostics.js +51 -0
- package/dist/src/routes/index.js +23 -0
- package/dist/src/routes/knowledge.js +968 -0
- package/dist/src/routes/markdown.js +287 -0
- package/dist/src/routes/notemd.js +565 -0
- package/dist/src/routes/registry.contract.test.js +130 -0
- package/dist/src/routes/render.js +285 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +11090 -1549
- package/dist/src/server.migration.test.js +193 -21
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/tauri.frontend.build.contract.test.js +60 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/utils/RuntimePaths.js +4 -13
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +122 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +61 -10
|
@@ -373,75 +373,88 @@
|
|
|
373
373
|
});
|
|
374
374
|
}
|
|
375
375
|
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
return
|
|
376
|
+
function dispatchRuntimeReadyEvent() {
|
|
377
|
+
if (typeof window.dispatchEvent !== 'function' || typeof window.CustomEvent !== 'function') {
|
|
378
|
+
return;
|
|
379
379
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
window.dispatchEvent(new CustomEvent('noteconnection:runtime-ready', {
|
|
381
|
+
detail: {
|
|
382
|
+
runtime: syncGlobalState(),
|
|
383
|
+
caps: window.__NC_RUNTIME_CAPS || null,
|
|
384
|
+
appConfig: syncGlobalAppState()
|
|
385
385
|
}
|
|
386
|
+
}));
|
|
387
|
+
}
|
|
386
388
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
);
|
|
393
|
-
if (caps && typeof caps === 'object') {
|
|
394
|
-
window.__NC_RUNTIME_CAPS = {
|
|
395
|
-
...(window.__NC_RUNTIME_CAPS || {}),
|
|
396
|
-
...caps
|
|
397
|
-
};
|
|
398
|
-
}
|
|
389
|
+
async function syncRuntimeFromTauri() {
|
|
390
|
+
const invoke = getTauriInvoke();
|
|
391
|
+
if (!invoke) {
|
|
392
|
+
return syncGlobalState();
|
|
393
|
+
}
|
|
399
394
|
|
|
400
|
-
|
|
401
|
-
|
|
395
|
+
try {
|
|
396
|
+
const caps = await invokeTauriWithTimeout(
|
|
397
|
+
() => invoke('get_runtime_capabilities'),
|
|
398
|
+
'get_runtime_capabilities',
|
|
399
|
+
TAURI_RUNTIME_HYDRATE_TIMEOUT_MS
|
|
400
|
+
);
|
|
401
|
+
if (caps && typeof caps === 'object') {
|
|
402
|
+
window.__NC_RUNTIME_CAPS = {
|
|
403
|
+
...(window.__NC_RUNTIME_CAPS || {}),
|
|
404
|
+
...caps
|
|
405
|
+
};
|
|
402
406
|
}
|
|
403
407
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const runtimeConfig = await invokeTauriWithTimeout(
|
|
408
|
-
() => invoke('get_sidecar_runtime_config'),
|
|
409
|
-
'get_sidecar_runtime_config',
|
|
410
|
-
TAURI_RUNTIME_HYDRATE_TIMEOUT_MS
|
|
411
|
-
);
|
|
412
|
-
setRuntimeConfig(runtimeConfig);
|
|
413
|
-
}
|
|
414
|
-
} catch (error) {
|
|
415
|
-
console.warn('[RuntimeBridge] Failed to hydrate sidecar runtime config from Tauri. Using runtime bridge defaults.', error);
|
|
416
|
-
}
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.warn('[RuntimeBridge] Failed to hydrate runtime capabilities from Tauri. Using runtime bridge defaults.', error);
|
|
410
|
+
}
|
|
417
411
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
412
|
+
try {
|
|
413
|
+
const runtimeCaps = window.__NC_RUNTIME_CAPS || {};
|
|
414
|
+
if (runtimeCaps.supports_sidecar) {
|
|
415
|
+
const runtimeConfig = await invokeTauriWithTimeout(
|
|
416
|
+
() => invoke('get_sidecar_runtime_config'),
|
|
417
|
+
'get_sidecar_runtime_config',
|
|
422
418
|
TAURI_RUNTIME_HYDRATE_TIMEOUT_MS
|
|
423
419
|
);
|
|
424
|
-
|
|
425
|
-
} catch (error) {
|
|
426
|
-
console.warn('[RuntimeBridge] Failed to hydrate app runtime config from Tauri. Using runtime defaults.', error);
|
|
420
|
+
setRuntimeConfig(runtimeConfig);
|
|
427
421
|
}
|
|
422
|
+
} catch (error) {
|
|
423
|
+
console.warn('[RuntimeBridge] Failed to hydrate sidecar runtime config from Tauri. Using runtime bridge defaults.', error);
|
|
424
|
+
}
|
|
428
425
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
426
|
+
try {
|
|
427
|
+
const appConfig = await invokeTauriWithTimeout(
|
|
428
|
+
() => invoke('get_app_runtime_config'),
|
|
429
|
+
'get_app_runtime_config',
|
|
430
|
+
TAURI_RUNTIME_HYDRATE_TIMEOUT_MS
|
|
431
|
+
);
|
|
432
|
+
setAppRuntimeConfig(appConfig);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
console.warn('[RuntimeBridge] Failed to hydrate app runtime config from Tauri. Using runtime defaults.', error);
|
|
435
|
+
}
|
|
438
436
|
|
|
439
|
-
|
|
440
|
-
|
|
437
|
+
dispatchRuntimeReadyEvent();
|
|
438
|
+
return syncGlobalState();
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function hydrateRuntimeFromTauri() {
|
|
442
|
+
if (!runtimeHydrationPromise) {
|
|
443
|
+
runtimeHydrationPromise = syncRuntimeFromTauri().then(() => {
|
|
444
|
+
finalizeRuntimeReady();
|
|
445
|
+
return syncGlobalState();
|
|
446
|
+
});
|
|
447
|
+
}
|
|
441
448
|
|
|
442
449
|
return runtimeHydrationPromise;
|
|
443
450
|
}
|
|
444
451
|
|
|
452
|
+
async function refreshRuntimeFromTauri() {
|
|
453
|
+
await syncRuntimeFromTauri();
|
|
454
|
+
finalizeRuntimeReady();
|
|
455
|
+
return syncGlobalState();
|
|
456
|
+
}
|
|
457
|
+
|
|
445
458
|
function whenReady() {
|
|
446
459
|
if (!runtimeHydrationPromise) {
|
|
447
460
|
void hydrateRuntimeFromTauri();
|
|
@@ -463,7 +476,7 @@
|
|
|
463
476
|
parseBridgeEnvelope,
|
|
464
477
|
sendBridgeMessage,
|
|
465
478
|
whenReady,
|
|
466
|
-
refreshFromTauri:
|
|
479
|
+
refreshFromTauri: refreshRuntimeFromTauri,
|
|
467
480
|
getBaseUrl: function () {
|
|
468
481
|
return state.baseUrl;
|
|
469
482
|
},
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* runtime_bridge.mjs - ES Module version.
|
|
3
|
+
* Unified RPC bridge over HTTP + WebSocket, with Tauri IPC fallback.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const DEFAULT_BASE_URL = 'http://127.0.0.1:3000';
|
|
7
|
+
const DEFAULT_BRIDGE_WS_URL = 'ws://127.0.0.1:9876';
|
|
8
|
+
const BRIDGE_RPC_VERSION = '2.0';
|
|
9
|
+
const BRIDGE_RPC_METHOD_PREFIX = 'noteconnection.';
|
|
10
|
+
const TAURI_RUNTIME_HYDRATE_TIMEOUT_MS = 2000;
|
|
11
|
+
|
|
12
|
+
function isPlainObject(value) {
|
|
13
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeBridgeMessageType(rawType) {
|
|
17
|
+
return String(rawType || '').trim().replace(/^[/.]+/, '');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function toBridgeEnvelope(type, payload, meta) {
|
|
21
|
+
const normalizedType = normalizeBridgeMessageType(type);
|
|
22
|
+
if (!normalizedType) throw new Error('Bridge message type is required.');
|
|
23
|
+
const envelope = {
|
|
24
|
+
type: normalizedType,
|
|
25
|
+
payload: payload === undefined ? null : payload,
|
|
26
|
+
jsonrpc: BRIDGE_RPC_VERSION,
|
|
27
|
+
method: `${BRIDGE_RPC_METHOD_PREFIX}${normalizedType}`,
|
|
28
|
+
params: payload === undefined ? null : payload,
|
|
29
|
+
};
|
|
30
|
+
if (meta && Object.prototype.hasOwnProperty.call(meta, 'id')) {
|
|
31
|
+
envelope.id = meta.id;
|
|
32
|
+
}
|
|
33
|
+
return envelope;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseBridgeEnvelope(rawMessage) {
|
|
37
|
+
let decoded = rawMessage;
|
|
38
|
+
if (typeof decoded === 'string') decoded = JSON.parse(decoded);
|
|
39
|
+
if (!isPlainObject(decoded)) return null;
|
|
40
|
+
let type = normalizeBridgeMessageType(decoded.type);
|
|
41
|
+
let payload = Object.prototype.hasOwnProperty.call(decoded, 'payload') ? decoded.payload : undefined;
|
|
42
|
+
if (!type && typeof decoded.method === 'string' && decoded.method.startsWith(BRIDGE_RPC_METHOD_PREFIX)) {
|
|
43
|
+
type = normalizeBridgeMessageType(decoded.method.slice(BRIDGE_RPC_METHOD_PREFIX.length));
|
|
44
|
+
if (payload === undefined) payload = decoded.params;
|
|
45
|
+
}
|
|
46
|
+
if (!type) return null;
|
|
47
|
+
if (payload === undefined && Object.prototype.hasOwnProperty.call(decoded, 'params')) {
|
|
48
|
+
payload = decoded.params;
|
|
49
|
+
}
|
|
50
|
+
return { type, payload: payload === undefined ? null : payload, id: Object.prototype.hasOwnProperty.call(decoded, 'id') ? decoded.id : null, jsonrpc: decoded.jsonrpc === BRIDGE_RPC_VERSION, raw: decoded };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function sendBridgeMessage(socket, type, payload, meta) {
|
|
54
|
+
if (!socket || socket.readyState !== WebSocket.OPEN) return false;
|
|
55
|
+
socket.send(JSON.stringify(toBridgeEnvelope(type, payload, meta)));
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function normalizeBaseUrl(rawUrl) {
|
|
60
|
+
const value = String(rawUrl || '').trim();
|
|
61
|
+
return value ? value.replace(/\/+$/, '') : DEFAULT_BASE_URL;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeBridgeWsUrl(rawUrl) {
|
|
65
|
+
const value = String(rawUrl || '').trim();
|
|
66
|
+
return value ? value.replace(/\/+$/, '') : DEFAULT_BRIDGE_WS_URL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeLanguageCode(rawValue) {
|
|
70
|
+
return String(rawValue || '').trim().toLowerCase().startsWith('zh') ? 'zh' : 'en';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function normalizeBoolean(value, fallback) {
|
|
74
|
+
return typeof value === 'boolean' ? value : fallback;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getDefaultAppRuntimeConfig() {
|
|
78
|
+
return {
|
|
79
|
+
language: 'en',
|
|
80
|
+
multiWindow: {
|
|
81
|
+
singleWindowMode: true,
|
|
82
|
+
hideTauriWhenPathmodeOpens: true,
|
|
83
|
+
restoreTauriWhenPathmodeExits: true,
|
|
84
|
+
confirmBeforeFullShutdownFromGodot: true,
|
|
85
|
+
syncLanguage: true,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const state = {
|
|
91
|
+
baseUrl: normalizeBaseUrl(window.__NC_SIDECAR_RUNTIME?.baseUrl),
|
|
92
|
+
bridgeWsUrl: normalizeBridgeWsUrl(window.__NC_SIDECAR_RUNTIME?.bridgeWsUrl),
|
|
93
|
+
authToken: String(window.__NC_SIDECAR_RUNTIME?.authToken || '').trim(),
|
|
94
|
+
host: String(window.__NC_SIDECAR_RUNTIME?.host || '127.0.0.1'),
|
|
95
|
+
port: Number(window.__NC_SIDECAR_RUNTIME?.port || 3000),
|
|
96
|
+
bridgePort: Number(window.__NC_SIDECAR_RUNTIME?.bridgePort || 9876),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const appState = getDefaultAppRuntimeConfig();
|
|
100
|
+
if (window.__NC_APP_CONFIG && typeof window.__NC_APP_CONFIG === 'object') {
|
|
101
|
+
const boot = window.__NC_APP_CONFIG;
|
|
102
|
+
appState.language = normalizeLanguageCode(boot.language || appState.language);
|
|
103
|
+
if (boot.multiWindow && typeof boot.multiWindow === 'object') {
|
|
104
|
+
const mw = boot.multiWindow;
|
|
105
|
+
appState.multiWindow.singleWindowMode = normalizeBoolean(mw.singleWindowMode, appState.multiWindow.singleWindowMode);
|
|
106
|
+
appState.multiWindow.hideTauriWhenPathmodeOpens = normalizeBoolean(mw.hideTauriWhenPathmodeOpens, appState.multiWindow.hideTauriWhenPathmodeOpens);
|
|
107
|
+
appState.multiWindow.restoreTauriWhenPathmodeExits = normalizeBoolean(mw.restoreTauriWhenPathmodeExits, appState.multiWindow.restoreTauriWhenPathmodeExits);
|
|
108
|
+
appState.multiWindow.confirmBeforeFullShutdownFromGodot = normalizeBoolean(mw.confirmBeforeFullShutdownFromGodot, appState.multiWindow.confirmBeforeFullShutdownFromGodot);
|
|
109
|
+
appState.multiWindow.syncLanguage = normalizeBoolean(mw.syncLanguage, appState.multiWindow.syncLanguage);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let runtimeReadyResolved = false;
|
|
114
|
+
let runtimeHydrationPromise = null;
|
|
115
|
+
let resolveRuntimeReady;
|
|
116
|
+
const runtimeReadyPromise = new Promise((resolve) => { resolveRuntimeReady = resolve; });
|
|
117
|
+
|
|
118
|
+
function syncGlobalState() {
|
|
119
|
+
window.__NC_SIDECAR_RUNTIME = { host: state.host, port: state.port, bridgePort: state.bridgePort, baseUrl: state.baseUrl, bridgeWsUrl: state.bridgeWsUrl, authToken: state.authToken };
|
|
120
|
+
return window.__NC_SIDECAR_RUNTIME;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function syncGlobalAppState() {
|
|
124
|
+
window.__NC_APP_CONFIG = { language: appState.language, multiWindow: { ...appState.multiWindow } };
|
|
125
|
+
return window.__NC_APP_CONFIG;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function finalizeRuntimeReady() {
|
|
129
|
+
if (runtimeReadyResolved) return runtimeReadyPromise;
|
|
130
|
+
runtimeReadyResolved = true;
|
|
131
|
+
resolveRuntimeReady(syncGlobalState());
|
|
132
|
+
return runtimeReadyPromise;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function setRuntimeConfig(nextConfig) {
|
|
136
|
+
if (!nextConfig || typeof nextConfig !== 'object') return syncGlobalState();
|
|
137
|
+
if (typeof nextConfig.host === 'string' && nextConfig.host.trim()) state.host = nextConfig.host.trim();
|
|
138
|
+
if (typeof nextConfig.port === 'number' && Number.isFinite(nextConfig.port) && nextConfig.port > 0) state.port = nextConfig.port;
|
|
139
|
+
if (typeof nextConfig.bridgePort === 'number' && Number.isFinite(nextConfig.bridgePort) && nextConfig.bridgePort > 0) state.bridgePort = nextConfig.bridgePort;
|
|
140
|
+
state.baseUrl = typeof nextConfig.baseUrl === 'string' ? normalizeBaseUrl(nextConfig.baseUrl) : normalizeBaseUrl(`http://${state.host}:${state.port}`);
|
|
141
|
+
state.bridgeWsUrl = typeof nextConfig.bridgeWsUrl === 'string' ? normalizeBridgeWsUrl(nextConfig.bridgeWsUrl) : normalizeBridgeWsUrl(`ws://${state.host}:${state.bridgePort}`);
|
|
142
|
+
if (typeof nextConfig.authToken === 'string') state.authToken = nextConfig.authToken.trim();
|
|
143
|
+
return syncGlobalState();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function getRuntimeConfig() { return syncGlobalState(); }
|
|
147
|
+
function setAppRuntimeConfig(nextConfig) { /* same logic as original */ return syncGlobalAppState(); }
|
|
148
|
+
function getAppRuntimeConfig() { return syncGlobalAppState(); }
|
|
149
|
+
|
|
150
|
+
function buildUrl(resourcePath, query) {
|
|
151
|
+
const normalizedPath = String(resourcePath || '').replace(/^\/+/, '');
|
|
152
|
+
const url = new URL(normalizedPath, `${state.baseUrl}/`);
|
|
153
|
+
if (query && typeof query === 'object') {
|
|
154
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
155
|
+
if (value === undefined || value === null || value === '') return;
|
|
156
|
+
url.searchParams.set(key, String(value));
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return url.toString();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function createAuthHeaders(extraHeaders) {
|
|
163
|
+
const headers = new Headers(extraHeaders || {});
|
|
164
|
+
if (state.authToken && !headers.has('X-NoteConnection-Token') && !headers.has('Authorization')) {
|
|
165
|
+
headers.set('X-NoteConnection-Token', state.authToken);
|
|
166
|
+
}
|
|
167
|
+
return headers;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function buildFetchOptions(init) {
|
|
171
|
+
const nextInit = { ...(init || {}) };
|
|
172
|
+
nextInit.headers = createAuthHeaders(nextInit.headers);
|
|
173
|
+
return nextInit;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getBridgeWsUrl(clientTag) {
|
|
177
|
+
const rawWsUrl = String(state.bridgeWsUrl || '').trim();
|
|
178
|
+
if (!rawWsUrl) return '';
|
|
179
|
+
try {
|
|
180
|
+
const url = new URL(rawWsUrl);
|
|
181
|
+
const tag = String(clientTag || '').trim();
|
|
182
|
+
if (tag) url.searchParams.set('client', tag);
|
|
183
|
+
if (state.authToken) url.searchParams.set('token', state.authToken);
|
|
184
|
+
return url.toString();
|
|
185
|
+
} catch (_) { return rawWsUrl; }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function openBridgeSocket(clientTag, protocols) {
|
|
189
|
+
const wsUrl = getBridgeWsUrl(clientTag);
|
|
190
|
+
if (!wsUrl) return null;
|
|
191
|
+
return protocols ? new WebSocket(wsUrl, protocols) : new WebSocket(wsUrl);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getTauriInvoke() {
|
|
195
|
+
return window.__TAURI__?.core?.invoke && typeof window.__TAURI__.core.invoke === 'function'
|
|
196
|
+
? window.__TAURI__.core.invoke : null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function invokeTauriWithTimeout(invokeCall, commandLabel, timeoutMs) {
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
let settled = false;
|
|
202
|
+
const timer = setTimeout(() => { if (!settled) { settled = true; reject(new Error(`Tauri invoke timed out (${commandLabel}).`)); } }, timeoutMs);
|
|
203
|
+
Promise.resolve(invokeCall()).then((result) => { if (!settled) { settled = true; clearTimeout(timer); resolve(result); } }).catch((error) => { if (!settled) { settled = true; clearTimeout(timer); reject(error); } });
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function dispatchRuntimeReadyEvent() {
|
|
208
|
+
if (typeof window.dispatchEvent === 'function') {
|
|
209
|
+
window.dispatchEvent(new CustomEvent('noteconnection:runtime-ready', { detail: { runtime: syncGlobalState(), caps: window.__NC_RUNTIME_CAPS || null, appConfig: syncGlobalAppState() } }));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function syncRuntimeFromTauri() {
|
|
214
|
+
const invoke = getTauriInvoke();
|
|
215
|
+
if (!invoke) return syncGlobalState();
|
|
216
|
+
try {
|
|
217
|
+
const caps = await invokeTauriWithTimeout(() => invoke('get_runtime_capabilities'), 'get_runtime_capabilities', TAURI_RUNTIME_HYDRATE_TIMEOUT_MS);
|
|
218
|
+
if (caps && typeof caps === 'object') window.__NC_RUNTIME_CAPS = { ...(window.__NC_RUNTIME_CAPS || {}), ...caps };
|
|
219
|
+
} catch (error) { console.warn('[RuntimeBridge] Tauri caps hydrate failed.', error); }
|
|
220
|
+
try {
|
|
221
|
+
if ((window.__NC_RUNTIME_CAPS || {}).supports_sidecar) {
|
|
222
|
+
const config = await invokeTauriWithTimeout(() => invoke('get_sidecar_runtime_config'), 'get_sidecar_runtime_config', TAURI_RUNTIME_HYDRATE_TIMEOUT_MS);
|
|
223
|
+
setRuntimeConfig(config);
|
|
224
|
+
}
|
|
225
|
+
} catch (error) { console.warn('[RuntimeBridge] Sidecar config hydrate failed.', error); }
|
|
226
|
+
try {
|
|
227
|
+
const appConfig = await invokeTauriWithTimeout(() => invoke('get_app_runtime_config'), 'get_app_runtime_config', TAURI_RUNTIME_HYDRATE_TIMEOUT_MS);
|
|
228
|
+
setAppRuntimeConfig(appConfig);
|
|
229
|
+
} catch (error) { console.warn('[RuntimeBridge] App config hydrate failed.', error); }
|
|
230
|
+
dispatchRuntimeReadyEvent();
|
|
231
|
+
return syncGlobalState();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function hydrateRuntimeFromTauri() {
|
|
235
|
+
if (!runtimeHydrationPromise) {
|
|
236
|
+
runtimeHydrationPromise = syncRuntimeFromTauri().then(() => {
|
|
237
|
+
finalizeRuntimeReady();
|
|
238
|
+
return syncGlobalState();
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return runtimeHydrationPromise;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function refreshRuntimeFromTauri() {
|
|
245
|
+
await syncRuntimeFromTauri();
|
|
246
|
+
finalizeRuntimeReady();
|
|
247
|
+
return syncGlobalState();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function whenReady() {
|
|
251
|
+
if (!runtimeHydrationPromise) void hydrateRuntimeFromTauri();
|
|
252
|
+
return runtimeReadyPromise;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Build the runtime object
|
|
256
|
+
const NoteConnectionRuntime = {
|
|
257
|
+
setRuntimeConfig, getRuntimeConfig,
|
|
258
|
+
setAppRuntimeConfig, getAppRuntimeConfig,
|
|
259
|
+
buildUrl, buildFetchOptions, createAuthHeaders,
|
|
260
|
+
getBridgeWsUrl, openBridgeSocket,
|
|
261
|
+
toBridgeEnvelope, parseBridgeEnvelope, sendBridgeMessage,
|
|
262
|
+
whenReady, refreshFromTauri: refreshRuntimeFromTauri,
|
|
263
|
+
getBaseUrl: () => state.baseUrl,
|
|
264
|
+
getAuthToken: () => state.authToken,
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Backward compatibility
|
|
268
|
+
window.NoteConnectionRuntime = NoteConnectionRuntime;
|
|
269
|
+
syncGlobalState();
|
|
270
|
+
syncGlobalAppState();
|
|
271
|
+
|
|
272
|
+
if (document.readyState === 'loading') {
|
|
273
|
+
document.addEventListener('DOMContentLoaded', () => { void hydrateRuntimeFromTauri(); }, { once: true });
|
|
274
|
+
} else {
|
|
275
|
+
void hydrateRuntimeFromTauri();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export { NoteConnectionRuntime, setRuntimeConfig, getRuntimeConfig, buildUrl, buildFetchOptions, createAuthHeaders, getBridgeWsUrl, openBridgeSocket, toBridgeEnvelope, parseBridgeEnvelope, sendBridgeMessage, whenReady, hydrateRuntimeFromTauri };
|
|
279
|
+
export default NoteConnectionRuntime;
|
|
@@ -9,6 +9,7 @@ const SETTINGS_STORAGE_KEY = "nc_settings";
|
|
|
9
9
|
const FRONTEND_SETTINGS_ENDPOINT = "/api/frontend/settings";
|
|
10
10
|
const RUNTIME_READY_TIMEOUT_MS = 2000;
|
|
11
11
|
const REMOTE_SYNC_DEBOUNCE_MS = 200;
|
|
12
|
+
const RUNTIME_REQUEST_RETRY_DELAY_MS = 180;
|
|
12
13
|
|
|
13
14
|
const defaultSettings = {
|
|
14
15
|
physics: {
|
|
@@ -57,6 +58,86 @@ function clampNumber(value, minValue, maxValue, fallback) {
|
|
|
57
58
|
return Math.max(minValue, Math.min(maxValue, numeric));
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
function sleep(ms) {
|
|
62
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function hasExplicitRuntimeBackendBootstrap() {
|
|
66
|
+
if (typeof window === "undefined" || !window.__NC_SIDECAR_RUNTIME) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const currentOrigin = String((window.location && window.location.origin) || "").trim().replace(/\/+$/, "");
|
|
70
|
+
const runtimeBaseUrl = String(window.__NC_SIDECAR_RUNTIME.baseUrl || "").trim().replace(/\/+$/, "");
|
|
71
|
+
return Boolean(currentOrigin && runtimeBaseUrl && currentOrigin === runtimeBaseUrl);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isDetachedTauriCliPreviewPage() {
|
|
75
|
+
if (typeof window === "undefined" || window.__TAURI__) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return Array.from(document.scripts || []).some((script) =>
|
|
79
|
+
/__tauri_cli/.test(String(script && (script.text || script.textContent) || ""))
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getRuntimeBaseOrigin() {
|
|
84
|
+
if (
|
|
85
|
+
!window.NoteConnectionRuntime ||
|
|
86
|
+
typeof window.NoteConnectionRuntime.getBaseUrl !== "function"
|
|
87
|
+
) {
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
const baseUrl = String(window.NoteConnectionRuntime.getBaseUrl() || "").trim();
|
|
91
|
+
if (!baseUrl) {
|
|
92
|
+
return "";
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
return new URL(baseUrl).origin;
|
|
96
|
+
} catch (_error) {
|
|
97
|
+
return "";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isCapacitorNativeRuntime() {
|
|
102
|
+
if (typeof window === "undefined" || window.__TAURI__ || !window.Capacitor) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
if (typeof window.Capacitor.getPlatform === "function") {
|
|
107
|
+
const platform = window.Capacitor.getPlatform();
|
|
108
|
+
if (platform && platform !== "web") {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (typeof window.Capacitor.isNativePlatform === "function") {
|
|
113
|
+
return Boolean(window.Capacitor.isNativePlatform());
|
|
114
|
+
}
|
|
115
|
+
} catch (_error) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function shouldEnableRuntimeSync() {
|
|
122
|
+
if (typeof window === "undefined") {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
if (window.__TAURI__) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (isDetachedTauriCliPreviewPage() && window.location.origin !== getRuntimeBaseOrigin()) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (isCapacitorNativeRuntime()) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
if (hasExplicitRuntimeBackendBootstrap()) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
const origin = String((window.location && window.location.origin) || "").trim().toLowerCase();
|
|
138
|
+
return /^https?:\/\/(?:127\.0\.0\.1|localhost):3000$/.test(origin);
|
|
139
|
+
}
|
|
140
|
+
|
|
60
141
|
function normalizeDegreeMode(value) {
|
|
61
142
|
return String(value || "").trim().toLowerCase() === "total" ? "total" : "visible";
|
|
62
143
|
}
|
|
@@ -187,7 +268,12 @@ class SettingsManager {
|
|
|
187
268
|
this.remoteSyncDeferred = false;
|
|
188
269
|
this.isHydrationComplete = false;
|
|
189
270
|
this.preHydrationPatches = [];
|
|
271
|
+
this.runtimeSyncEnabled = shouldEnableRuntimeSync();
|
|
190
272
|
this.settings = this.loadLocalSnapshot();
|
|
273
|
+
if (!this.runtimeSyncEnabled) {
|
|
274
|
+
this.isHydrationComplete = true;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
191
277
|
this.hydrateFromRuntime().catch((error) => {
|
|
192
278
|
console.warn("[Settings] Runtime settings hydration failed; using local snapshot.", error);
|
|
193
279
|
}).finally(() => {
|
|
@@ -290,20 +376,49 @@ class SettingsManager {
|
|
|
290
376
|
});
|
|
291
377
|
}
|
|
292
378
|
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
379
|
+
const maxAttempts = (window.__TAURI__ && method === "GET") ? 12 : ((window.__TAURI__ && method === "POST") ? 8 : 1);
|
|
380
|
+
let lastError = null;
|
|
381
|
+
|
|
382
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
383
|
+
try {
|
|
384
|
+
const response = await fetch(
|
|
385
|
+
this.buildUrl(FRONTEND_SETTINGS_ENDPOINT),
|
|
386
|
+
this.buildFetchOptions(requestInit)
|
|
387
|
+
);
|
|
388
|
+
if (!response.ok) {
|
|
389
|
+
const message = await response.text().catch(() => "");
|
|
390
|
+
const error = new Error(message || `Frontend settings request failed (${method} ${response.status}).`);
|
|
391
|
+
error.status = response.status;
|
|
392
|
+
throw error;
|
|
393
|
+
}
|
|
301
394
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
395
|
+
const payload = await response.json().catch(() => null);
|
|
396
|
+
if (!payload || payload.success !== true || !isObjectLike(payload.settings)) {
|
|
397
|
+
throw new Error("Invalid frontend settings API response.");
|
|
398
|
+
}
|
|
399
|
+
return normalizeSettings(payload.settings);
|
|
400
|
+
} catch (error) {
|
|
401
|
+
lastError = error;
|
|
402
|
+
const status = Number(error && error.status);
|
|
403
|
+
const shouldRetry = Boolean(
|
|
404
|
+
window.__TAURI__
|
|
405
|
+
&& attempt < maxAttempts
|
|
406
|
+
&& (
|
|
407
|
+
!Number.isFinite(status)
|
|
408
|
+
|| status === 404
|
|
409
|
+
|| status === 502
|
|
410
|
+
|| status === 503
|
|
411
|
+
|| status === 504
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
if (!shouldRetry) {
|
|
415
|
+
throw error;
|
|
416
|
+
}
|
|
417
|
+
await sleep(Math.min(1000, RUNTIME_REQUEST_RETRY_DELAY_MS * attempt));
|
|
418
|
+
}
|
|
305
419
|
}
|
|
306
|
-
|
|
420
|
+
|
|
421
|
+
throw lastError || new Error("Frontend settings request failed.");
|
|
307
422
|
}
|
|
308
423
|
|
|
309
424
|
async hydrateFromRuntime() {
|
|
@@ -359,6 +474,9 @@ class SettingsManager {
|
|
|
359
474
|
}
|
|
360
475
|
|
|
361
476
|
scheduleRuntimePersist() {
|
|
477
|
+
if (!this.runtimeSyncEnabled) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
362
480
|
if (!this.isHydrationComplete) {
|
|
363
481
|
this.remoteSyncDeferred = true;
|
|
364
482
|
return;
|