@mindexec/cli 0.2.477 → 0.2.478
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/README.md +323 -323
- package/codex-model-catalog.js +202 -202
- package/codex-runtime.js +1608 -1608
- package/desktop-workspace-state.cjs +120 -120
- package/electron/main.cjs +517 -517
- package/electron/preload.cjs +17 -17
- package/electron/recurring-update-owner-smoke.mjs +55 -55
- package/electron/recurring-update-owner.cjs +97 -97
- package/electron/source-smoke.mjs +108 -108
- package/electron/update-feed-resolver.cjs +79 -79
- package/electron/update-feed.json +10 -10
- package/electron/update-manager-smoke.mjs +146 -146
- package/electron/update-manager.cjs +297 -297
- package/electron/windows-package-smoke.mjs +156 -156
- package/launch-bridge.cjs +236 -236
- package/lzo1x.js +110 -110
- package/mode4-atlas-worker.js +440 -440
- package/mode4-atlas.js +130 -130
- package/package.json +1 -1
- package/port-guard.cjs +285 -285
- package/remote-fast/osx-arm64/MacScreenCaptureKitH264.swift +339 -339
- package/remote-fast/osx-arm64/MacSystemAudioCapture.swift +214 -214
- package/remote-fast/osx-arm64/UnixRawCaptureHelper.mjs +80 -80
- package/remote-fast/osx-arm64/livedesk-raw-capture-resampler.mjs +73 -73
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/MacScreenCaptureKitH264.swift +339 -339
- package/remote-fast/osx-x64/MacSystemAudioCapture.swift +214 -214
- package/remote-fast/osx-x64/UnixRawCaptureHelper.mjs +80 -80
- package/remote-fast/osx-x64/livedesk-raw-capture-resampler.mjs +73 -73
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/remote-hub.js +3698 -3698
- package/scripts/auth-session-smoke.mjs +262 -262
- package/scripts/board-render-ownership-smoke.mjs +85 -85
- package/scripts/codex-model-catalog-smoke.mjs +150 -150
- package/scripts/codex-runtime-home-smoke.mjs +58 -58
- package/scripts/codex-sdk-image-live-smoke.mjs +43 -43
- package/scripts/codex-sdk-image-runtime-smoke.mjs +122 -122
- package/scripts/codex-sdk-runtime-smoke.mjs +89 -89
- package/scripts/desktop-update-publisher-smoke.mjs +89 -89
- package/scripts/desktop-update-worker-smoke.mjs +72 -72
- package/scripts/desktop-workspace-state-smoke.mjs +81 -81
- package/scripts/drive-installed-update-smoke.mjs +67 -67
- package/scripts/npm-fresh-install-smoke.mjs +216 -216
- package/scripts/publish-mindexec-desktop-updates.mjs +224 -224
- package/scripts/remote-agent-managed-smoke.mjs +318 -318
- package/scripts/remote-agent-package-smoke.mjs +64 -64
- package/scripts/remote-agent-ws-smoke.mjs +269 -269
- package/scripts/remote-fast-live-rate-smoke.mjs +343 -343
- package/scripts/remote-fast-mdm-browser-smoke.mjs +453 -453
- package/scripts/remote-fleet-render-smoke.mjs +1350 -1350
- package/scripts/remote-frame-ws-smoke.mjs +234 -234
- package/scripts/remote-http-smoke.mjs +592 -592
- package/scripts/remote-hub-identity-smoke.mjs +146 -146
- package/scripts/remote-hub-scale-smoke.mjs +124 -124
- package/scripts/remote-hub-smoke.mjs +699 -699
- package/scripts/remote-input-ws-smoke.mjs +263 -263
- package/scripts/remote-registry-follower-smoke.mjs +815 -815
- package/scripts/setup-tree-sitter-grammars.mjs +59 -59
- package/server.js +7690 -7690
- package/start-bridge.bat +32 -32
- package/start-bridge.sh +81 -81
- package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -546
- package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -251
- package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -1
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +3789 -3789
- package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +27 -27
- package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1449 -1449
- package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -8316
- package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +338 -338
- package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -69
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-animated-image-preview.js +270 -270
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-automation-edge-motion.js +170 -170
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-board-render-ownership.js +81 -81
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +10506 -10506
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-hotpath.js +902 -902
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +24637 -24637
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -325
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1491 -1491
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +70 -70
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-image-policy.js +218 -218
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7065 -7065
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -160
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9956 -9956
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-video-placeholder.js +107 -107
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +1004 -1004
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1351 -1351
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +865 -865
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +554 -554
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4744 -4744
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-normal-boundary-optimizer.js +624 -624
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +241 -241
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2290 -2290
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-remote-codecs.js +202 -202
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +1971 -1971
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +93 -93
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2391 -2391
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-video-playback-controls.js +95 -95
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +895 -895
- package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +636 -636
- package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +45 -45
- package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +117 -117
- package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +114 -114
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +10 -10
- package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -6
- package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +7 -7
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +6 -6
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +2 -2
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +8 -8
- package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -30522
- package/wwwroot/_framework/{Google.Protobuf.9h59ukbel7.dll → Google.Protobuf.33g2gb5is0.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Core.ty1xewqp36.dll → MindExecution.Core.z100xo4mg0.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.h7rqjoo69o.dll → MindExecution.Kernel.i9cldrx8yc.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.wrfrcvhjde.dll → MindExecution.Plugins.Admin.48lzqddb0a.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.csbcyjurdh.dll → MindExecution.Plugins.Business.7m8u1q142p.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.buomiysqjn.dll → MindExecution.Plugins.Concept.cl5wmr53od.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.7k00i2v769.dll → MindExecution.Plugins.Directory.slipi39041.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.85i5ocraro.dll → MindExecution.Plugins.PlanMaster.qfge05l671.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.nbolrfakte.dll → MindExecution.Plugins.YouTube.tn7v29ut77.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.nqh4porv7x.dll → MindExecution.Shared.rjqlf0umjn.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.211q3bf4mr.dll → MindExecution.Web.rwawrxxk38.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +23 -23
- package/wwwroot/_headers +40 -40
- package/wwwroot/_redirects +1 -1
- package/wwwroot/index.html +772 -772
- package/wwwroot/js/marketing-tool.js +180 -180
- package/wwwroot/manifest.webmanifest +23 -23
- package/wwwroot/service-worker-assets.js +78 -106
- package/wwwroot/service-worker.js +33 -33
- package/tree-sitter-grammars/README.md +0 -18
- package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +0 -1059
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +0 -434
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +0 -372
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +0 -1258
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const LOCAL_HTTP_HOSTS = new Set(['127.0.0.1', 'localhost', '[::1]']);
|
|
4
|
-
const CHANNEL_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
5
|
-
const SEGMENT_PATTERN = /^[a-z0-9][a-z0-9/-]{0,127}$/;
|
|
6
|
-
|
|
7
|
-
function normalizeUrl(value) {
|
|
8
|
-
return String(value || '').trim().replace(/\/+$/, '');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function validateFeedUrl(value) {
|
|
12
|
-
const normalized = normalizeUrl(value);
|
|
13
|
-
if (!normalized) return { url: '', error: 'desktop-update-feed-not-configured' };
|
|
14
|
-
|
|
15
|
-
let parsed;
|
|
16
|
-
try {
|
|
17
|
-
parsed = new URL(normalized);
|
|
18
|
-
} catch {
|
|
19
|
-
return { url: '', error: 'desktop-update-feed-invalid' };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const localHttp = parsed.protocol === 'http:' && LOCAL_HTTP_HOSTS.has(parsed.hostname);
|
|
23
|
-
if (parsed.protocol !== 'https:' && !localHttp) {
|
|
24
|
-
return { url: '', error: 'desktop-update-feed-insecure' };
|
|
25
|
-
}
|
|
26
|
-
if (parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
27
|
-
return { url: '', error: 'desktop-update-feed-invalid' };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return { url: normalizeUrl(parsed.toString()), error: '' };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function resolveDesktopUpdateFeed({
|
|
34
|
-
config = {},
|
|
35
|
-
overrideUrl = '',
|
|
36
|
-
platform = process.platform,
|
|
37
|
-
arch = process.arch
|
|
38
|
-
} = {}) {
|
|
39
|
-
const exactOverride = validateFeedUrl(overrideUrl);
|
|
40
|
-
if (String(overrideUrl || '').trim()) {
|
|
41
|
-
return {
|
|
42
|
-
...exactOverride,
|
|
43
|
-
configured: Boolean(exactOverride.url),
|
|
44
|
-
platform,
|
|
45
|
-
arch,
|
|
46
|
-
channel: 'override'
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const channel = String(config?.channel || 'dev').trim().toLowerCase();
|
|
51
|
-
const pathSegment = String(config?.paths?.[platform]?.[arch] || '')
|
|
52
|
-
.trim()
|
|
53
|
-
.replace(/^\/+|\/+$/g, '');
|
|
54
|
-
if (!CHANNEL_PATTERN.test(channel)) {
|
|
55
|
-
return { url: '', configured: false, error: 'desktop-update-channel-invalid', platform, arch, channel };
|
|
56
|
-
}
|
|
57
|
-
if (!SEGMENT_PATTERN.test(pathSegment)) {
|
|
58
|
-
return { url: '', configured: false, error: 'desktop-update-platform-unsupported', platform, arch, channel };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const base = validateFeedUrl(config?.baseUrl);
|
|
62
|
-
if (!base.url) {
|
|
63
|
-
return { ...base, configured: false, platform, arch, channel };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
url: `${base.url}/${channel}/${pathSegment}`,
|
|
68
|
-
configured: true,
|
|
69
|
-
error: '',
|
|
70
|
-
platform,
|
|
71
|
-
arch,
|
|
72
|
-
channel
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = {
|
|
77
|
-
resolveDesktopUpdateFeed,
|
|
78
|
-
validateFeedUrl
|
|
79
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const LOCAL_HTTP_HOSTS = new Set(['127.0.0.1', 'localhost', '[::1]']);
|
|
4
|
+
const CHANNEL_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
5
|
+
const SEGMENT_PATTERN = /^[a-z0-9][a-z0-9/-]{0,127}$/;
|
|
6
|
+
|
|
7
|
+
function normalizeUrl(value) {
|
|
8
|
+
return String(value || '').trim().replace(/\/+$/, '');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function validateFeedUrl(value) {
|
|
12
|
+
const normalized = normalizeUrl(value);
|
|
13
|
+
if (!normalized) return { url: '', error: 'desktop-update-feed-not-configured' };
|
|
14
|
+
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = new URL(normalized);
|
|
18
|
+
} catch {
|
|
19
|
+
return { url: '', error: 'desktop-update-feed-invalid' };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const localHttp = parsed.protocol === 'http:' && LOCAL_HTTP_HOSTS.has(parsed.hostname);
|
|
23
|
+
if (parsed.protocol !== 'https:' && !localHttp) {
|
|
24
|
+
return { url: '', error: 'desktop-update-feed-insecure' };
|
|
25
|
+
}
|
|
26
|
+
if (parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
27
|
+
return { url: '', error: 'desktop-update-feed-invalid' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { url: normalizeUrl(parsed.toString()), error: '' };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolveDesktopUpdateFeed({
|
|
34
|
+
config = {},
|
|
35
|
+
overrideUrl = '',
|
|
36
|
+
platform = process.platform,
|
|
37
|
+
arch = process.arch
|
|
38
|
+
} = {}) {
|
|
39
|
+
const exactOverride = validateFeedUrl(overrideUrl);
|
|
40
|
+
if (String(overrideUrl || '').trim()) {
|
|
41
|
+
return {
|
|
42
|
+
...exactOverride,
|
|
43
|
+
configured: Boolean(exactOverride.url),
|
|
44
|
+
platform,
|
|
45
|
+
arch,
|
|
46
|
+
channel: 'override'
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const channel = String(config?.channel || 'dev').trim().toLowerCase();
|
|
51
|
+
const pathSegment = String(config?.paths?.[platform]?.[arch] || '')
|
|
52
|
+
.trim()
|
|
53
|
+
.replace(/^\/+|\/+$/g, '');
|
|
54
|
+
if (!CHANNEL_PATTERN.test(channel)) {
|
|
55
|
+
return { url: '', configured: false, error: 'desktop-update-channel-invalid', platform, arch, channel };
|
|
56
|
+
}
|
|
57
|
+
if (!SEGMENT_PATTERN.test(pathSegment)) {
|
|
58
|
+
return { url: '', configured: false, error: 'desktop-update-platform-unsupported', platform, arch, channel };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const base = validateFeedUrl(config?.baseUrl);
|
|
62
|
+
if (!base.url) {
|
|
63
|
+
return { ...base, configured: false, platform, arch, channel };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
url: `${base.url}/${channel}/${pathSegment}`,
|
|
68
|
+
configured: true,
|
|
69
|
+
error: '',
|
|
70
|
+
platform,
|
|
71
|
+
arch,
|
|
72
|
+
channel
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
resolveDesktopUpdateFeed,
|
|
78
|
+
validateFeedUrl
|
|
79
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
{
|
|
2
|
-
"provider": "generic",
|
|
3
|
-
"baseUrl": "https://mindexec.lovecrdm.workers.dev",
|
|
4
|
-
"channel": "dev",
|
|
5
|
-
"paths": {
|
|
6
|
-
"win32": {
|
|
7
|
-
"x64": "windows/x64"
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"provider": "generic",
|
|
3
|
+
"baseUrl": "https://mindexec.lovecrdm.workers.dev",
|
|
4
|
+
"channel": "dev",
|
|
5
|
+
"paths": {
|
|
6
|
+
"win32": {
|
|
7
|
+
"x64": "windows/x64"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
|
-
import test from 'node:test';
|
|
4
|
-
import updateManagerModule from './update-manager.cjs';
|
|
5
|
-
import updateFeedResolverModule from './update-feed-resolver.cjs';
|
|
6
|
-
|
|
7
|
-
const { createProductUpdateManager } = updateManagerModule;
|
|
8
|
-
const { resolveDesktopUpdateFeed } = updateFeedResolverModule;
|
|
9
|
-
|
|
10
|
-
const feedConfig = {
|
|
11
|
-
baseUrl: 'https://updates.example',
|
|
12
|
-
channel: 'dev',
|
|
13
|
-
paths: { win32: { x64: 'windows/x64' } }
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
class FakeUpdater extends EventEmitter {
|
|
17
|
-
checkCalls = 0;
|
|
18
|
-
downloadCalls = 0;
|
|
19
|
-
feed = null;
|
|
20
|
-
installStarted = false;
|
|
21
|
-
|
|
22
|
-
setFeedURL(feed) { this.feed = feed; }
|
|
23
|
-
|
|
24
|
-
async checkForUpdates() {
|
|
25
|
-
this.checkCalls += 1;
|
|
26
|
-
this.emit('checking-for-update');
|
|
27
|
-
await new Promise(resolve => setTimeout(resolve, 5));
|
|
28
|
-
this.emit('update-available', { version: '1.1.0' });
|
|
29
|
-
return { updateInfo: { version: '1.1.0' } };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async downloadUpdate() {
|
|
33
|
-
this.downloadCalls += 1;
|
|
34
|
-
this.emit('download-progress', { percent: 42 });
|
|
35
|
-
await new Promise(resolve => setTimeout(resolve, 5));
|
|
36
|
-
this.emit('update-downloaded', { version: '1.1.0' });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
quitAndInstall() { this.installStarted = true; }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function createManager(updater, hooks = {}) {
|
|
43
|
-
return createProductUpdateManager({
|
|
44
|
-
app: {
|
|
45
|
-
isPackaged: true,
|
|
46
|
-
getVersion: () => '1.0.0',
|
|
47
|
-
getAppPath: () => process.cwd()
|
|
48
|
-
},
|
|
49
|
-
updater,
|
|
50
|
-
platform: 'win32',
|
|
51
|
-
arch: 'x64',
|
|
52
|
-
installKind: 'installed',
|
|
53
|
-
updateFeedConfig: feedConfig,
|
|
54
|
-
overrideUrl: '',
|
|
55
|
-
...hooks
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
test('feed resolver pins Windows x64 to the exact development path and rejects insecure servers', () => {
|
|
60
|
-
assert.equal(
|
|
61
|
-
resolveDesktopUpdateFeed({ config: feedConfig, platform: 'win32', arch: 'x64' }).url,
|
|
62
|
-
'https://updates.example/dev/windows/x64'
|
|
63
|
-
);
|
|
64
|
-
assert.equal(
|
|
65
|
-
resolveDesktopUpdateFeed({ config: { ...feedConfig, baseUrl: 'http://updates.example' }, platform: 'win32', arch: 'x64' }).error,
|
|
66
|
-
'desktop-update-feed-insecure'
|
|
67
|
-
);
|
|
68
|
-
assert.equal(
|
|
69
|
-
resolveDesktopUpdateFeed({ config: feedConfig, platform: 'win32', arch: 'arm64' }).error,
|
|
70
|
-
'desktop-update-platform-unsupported'
|
|
71
|
-
);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('concurrent checks share one version request and one download', async () => {
|
|
75
|
-
const updater = new FakeUpdater();
|
|
76
|
-
const manager = createManager(updater);
|
|
77
|
-
const [first, second] = await Promise.all([manager.check(), manager.check()]);
|
|
78
|
-
assert.equal(first.state, 'downloaded');
|
|
79
|
-
assert.equal(second.state, 'downloaded');
|
|
80
|
-
assert.equal(updater.checkCalls, 1);
|
|
81
|
-
assert.equal(updater.downloadCalls, 1);
|
|
82
|
-
assert.deepEqual(updater.feed, { provider: 'generic', url: 'https://updates.example/dev/windows/x64' });
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('portable and unpacked executables never call electron-updater', async () => {
|
|
86
|
-
for (const installKind of ['portable', 'unpacked']) {
|
|
87
|
-
const updater = new FakeUpdater();
|
|
88
|
-
const manager = createManager(updater, { installKind });
|
|
89
|
-
const result = await manager.check();
|
|
90
|
-
assert.equal(result.state, 'unsupported');
|
|
91
|
-
assert.equal(result.updateSupported, false);
|
|
92
|
-
assert.equal(updater.checkCalls, 0);
|
|
93
|
-
assert.equal(updater.downloadCalls, 0);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('install starts only after the owned runtime and ports are released', async () => {
|
|
98
|
-
const order = [];
|
|
99
|
-
const updater = new FakeUpdater();
|
|
100
|
-
updater.quitAndInstall = () => { order.push('installer'); updater.installStarted = true; };
|
|
101
|
-
const manager = createManager(updater, {
|
|
102
|
-
beforeInstall: async () => { order.push('runtime-and-ports-zero'); }
|
|
103
|
-
});
|
|
104
|
-
await manager.check();
|
|
105
|
-
await manager.install();
|
|
106
|
-
assert.deepEqual(order, ['runtime-and-ports-zero', 'installer']);
|
|
107
|
-
assert.equal(updater.installStarted, true);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('a preparation or installer failure restores runtime ownership and allows retry', async () => {
|
|
111
|
-
const order = [];
|
|
112
|
-
const updater = new FakeUpdater();
|
|
113
|
-
let prepareAttempts = 0;
|
|
114
|
-
const manager = createManager(updater, {
|
|
115
|
-
beforeInstall: async () => {
|
|
116
|
-
prepareAttempts += 1;
|
|
117
|
-
order.push(`prepare-${prepareAttempts}`);
|
|
118
|
-
if (prepareAttempts === 1) throw new Error('runtime-release-failed');
|
|
119
|
-
},
|
|
120
|
-
onInstallError: async () => { order.push('runtime-restored'); }
|
|
121
|
-
});
|
|
122
|
-
await manager.check();
|
|
123
|
-
assert.equal((await manager.install()).state, 'error');
|
|
124
|
-
assert.equal((await manager.install()).state, 'installing');
|
|
125
|
-
assert.deepEqual(order, ['prepare-1', 'runtime-restored', 'prepare-2']);
|
|
126
|
-
assert.equal(updater.installStarted, true);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test('a slow update server never holds startup beyond its small budget', async () => {
|
|
130
|
-
const updater = new FakeUpdater();
|
|
131
|
-
updater.checkForUpdates = async () => {
|
|
132
|
-
updater.checkCalls += 1;
|
|
133
|
-
updater.emit('checking-for-update');
|
|
134
|
-
await new Promise(resolve => setTimeout(resolve, 80));
|
|
135
|
-
updater.emit('update-not-available');
|
|
136
|
-
return { updateInfo: { version: '1.0.0' } };
|
|
137
|
-
};
|
|
138
|
-
const manager = createManager(updater, { startupCheckTimeoutMs: 20 });
|
|
139
|
-
const startedAt = Date.now();
|
|
140
|
-
const status = await manager.checkAtStartup();
|
|
141
|
-
assert.ok(Date.now() - startedAt < 70, 'startup must continue while a slow check finishes in the background');
|
|
142
|
-
assert.equal(status.startupCheck, 'timed-out');
|
|
143
|
-
await new Promise(resolve => setTimeout(resolve, 90));
|
|
144
|
-
assert.equal(manager.getStatus().state, 'current');
|
|
145
|
-
assert.equal(manager.getStatus().startupCheck, 'complete');
|
|
146
|
-
});
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import test from 'node:test';
|
|
4
|
+
import updateManagerModule from './update-manager.cjs';
|
|
5
|
+
import updateFeedResolverModule from './update-feed-resolver.cjs';
|
|
6
|
+
|
|
7
|
+
const { createProductUpdateManager } = updateManagerModule;
|
|
8
|
+
const { resolveDesktopUpdateFeed } = updateFeedResolverModule;
|
|
9
|
+
|
|
10
|
+
const feedConfig = {
|
|
11
|
+
baseUrl: 'https://updates.example',
|
|
12
|
+
channel: 'dev',
|
|
13
|
+
paths: { win32: { x64: 'windows/x64' } }
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
class FakeUpdater extends EventEmitter {
|
|
17
|
+
checkCalls = 0;
|
|
18
|
+
downloadCalls = 0;
|
|
19
|
+
feed = null;
|
|
20
|
+
installStarted = false;
|
|
21
|
+
|
|
22
|
+
setFeedURL(feed) { this.feed = feed; }
|
|
23
|
+
|
|
24
|
+
async checkForUpdates() {
|
|
25
|
+
this.checkCalls += 1;
|
|
26
|
+
this.emit('checking-for-update');
|
|
27
|
+
await new Promise(resolve => setTimeout(resolve, 5));
|
|
28
|
+
this.emit('update-available', { version: '1.1.0' });
|
|
29
|
+
return { updateInfo: { version: '1.1.0' } };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async downloadUpdate() {
|
|
33
|
+
this.downloadCalls += 1;
|
|
34
|
+
this.emit('download-progress', { percent: 42 });
|
|
35
|
+
await new Promise(resolve => setTimeout(resolve, 5));
|
|
36
|
+
this.emit('update-downloaded', { version: '1.1.0' });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
quitAndInstall() { this.installStarted = true; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function createManager(updater, hooks = {}) {
|
|
43
|
+
return createProductUpdateManager({
|
|
44
|
+
app: {
|
|
45
|
+
isPackaged: true,
|
|
46
|
+
getVersion: () => '1.0.0',
|
|
47
|
+
getAppPath: () => process.cwd()
|
|
48
|
+
},
|
|
49
|
+
updater,
|
|
50
|
+
platform: 'win32',
|
|
51
|
+
arch: 'x64',
|
|
52
|
+
installKind: 'installed',
|
|
53
|
+
updateFeedConfig: feedConfig,
|
|
54
|
+
overrideUrl: '',
|
|
55
|
+
...hooks
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
test('feed resolver pins Windows x64 to the exact development path and rejects insecure servers', () => {
|
|
60
|
+
assert.equal(
|
|
61
|
+
resolveDesktopUpdateFeed({ config: feedConfig, platform: 'win32', arch: 'x64' }).url,
|
|
62
|
+
'https://updates.example/dev/windows/x64'
|
|
63
|
+
);
|
|
64
|
+
assert.equal(
|
|
65
|
+
resolveDesktopUpdateFeed({ config: { ...feedConfig, baseUrl: 'http://updates.example' }, platform: 'win32', arch: 'x64' }).error,
|
|
66
|
+
'desktop-update-feed-insecure'
|
|
67
|
+
);
|
|
68
|
+
assert.equal(
|
|
69
|
+
resolveDesktopUpdateFeed({ config: feedConfig, platform: 'win32', arch: 'arm64' }).error,
|
|
70
|
+
'desktop-update-platform-unsupported'
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('concurrent checks share one version request and one download', async () => {
|
|
75
|
+
const updater = new FakeUpdater();
|
|
76
|
+
const manager = createManager(updater);
|
|
77
|
+
const [first, second] = await Promise.all([manager.check(), manager.check()]);
|
|
78
|
+
assert.equal(first.state, 'downloaded');
|
|
79
|
+
assert.equal(second.state, 'downloaded');
|
|
80
|
+
assert.equal(updater.checkCalls, 1);
|
|
81
|
+
assert.equal(updater.downloadCalls, 1);
|
|
82
|
+
assert.deepEqual(updater.feed, { provider: 'generic', url: 'https://updates.example/dev/windows/x64' });
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('portable and unpacked executables never call electron-updater', async () => {
|
|
86
|
+
for (const installKind of ['portable', 'unpacked']) {
|
|
87
|
+
const updater = new FakeUpdater();
|
|
88
|
+
const manager = createManager(updater, { installKind });
|
|
89
|
+
const result = await manager.check();
|
|
90
|
+
assert.equal(result.state, 'unsupported');
|
|
91
|
+
assert.equal(result.updateSupported, false);
|
|
92
|
+
assert.equal(updater.checkCalls, 0);
|
|
93
|
+
assert.equal(updater.downloadCalls, 0);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('install starts only after the owned runtime and ports are released', async () => {
|
|
98
|
+
const order = [];
|
|
99
|
+
const updater = new FakeUpdater();
|
|
100
|
+
updater.quitAndInstall = () => { order.push('installer'); updater.installStarted = true; };
|
|
101
|
+
const manager = createManager(updater, {
|
|
102
|
+
beforeInstall: async () => { order.push('runtime-and-ports-zero'); }
|
|
103
|
+
});
|
|
104
|
+
await manager.check();
|
|
105
|
+
await manager.install();
|
|
106
|
+
assert.deepEqual(order, ['runtime-and-ports-zero', 'installer']);
|
|
107
|
+
assert.equal(updater.installStarted, true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('a preparation or installer failure restores runtime ownership and allows retry', async () => {
|
|
111
|
+
const order = [];
|
|
112
|
+
const updater = new FakeUpdater();
|
|
113
|
+
let prepareAttempts = 0;
|
|
114
|
+
const manager = createManager(updater, {
|
|
115
|
+
beforeInstall: async () => {
|
|
116
|
+
prepareAttempts += 1;
|
|
117
|
+
order.push(`prepare-${prepareAttempts}`);
|
|
118
|
+
if (prepareAttempts === 1) throw new Error('runtime-release-failed');
|
|
119
|
+
},
|
|
120
|
+
onInstallError: async () => { order.push('runtime-restored'); }
|
|
121
|
+
});
|
|
122
|
+
await manager.check();
|
|
123
|
+
assert.equal((await manager.install()).state, 'error');
|
|
124
|
+
assert.equal((await manager.install()).state, 'installing');
|
|
125
|
+
assert.deepEqual(order, ['prepare-1', 'runtime-restored', 'prepare-2']);
|
|
126
|
+
assert.equal(updater.installStarted, true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('a slow update server never holds startup beyond its small budget', async () => {
|
|
130
|
+
const updater = new FakeUpdater();
|
|
131
|
+
updater.checkForUpdates = async () => {
|
|
132
|
+
updater.checkCalls += 1;
|
|
133
|
+
updater.emit('checking-for-update');
|
|
134
|
+
await new Promise(resolve => setTimeout(resolve, 80));
|
|
135
|
+
updater.emit('update-not-available');
|
|
136
|
+
return { updateInfo: { version: '1.0.0' } };
|
|
137
|
+
};
|
|
138
|
+
const manager = createManager(updater, { startupCheckTimeoutMs: 20 });
|
|
139
|
+
const startedAt = Date.now();
|
|
140
|
+
const status = await manager.checkAtStartup();
|
|
141
|
+
assert.ok(Date.now() - startedAt < 70, 'startup must continue while a slow check finishes in the background');
|
|
142
|
+
assert.equal(status.startupCheck, 'timed-out');
|
|
143
|
+
await new Promise(resolve => setTimeout(resolve, 90));
|
|
144
|
+
assert.equal(manager.getStatus().state, 'current');
|
|
145
|
+
assert.equal(manager.getStatus().startupCheck, 'complete');
|
|
146
|
+
});
|