@namzu/sandbox 24.0.0 → 25.0.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.
Files changed (158) hide show
  1. package/CHANGELOG.md +274 -0
  2. package/dist/backends/http-worker-client.d.ts +3 -1
  3. package/dist/backends/http-worker-client.d.ts.map +1 -1
  4. package/dist/backends/http-worker-client.js +15 -4
  5. package/dist/backends/http-worker-client.js.map +1 -1
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/local-virtual-computer/client.d.ts +21 -0
  11. package/dist/local-virtual-computer/client.d.ts.map +1 -0
  12. package/dist/local-virtual-computer/client.js +503 -0
  13. package/dist/local-virtual-computer/client.js.map +1 -0
  14. package/dist/local-virtual-computer/detached-process.d.ts +15 -0
  15. package/dist/local-virtual-computer/detached-process.d.ts.map +1 -0
  16. package/dist/local-virtual-computer/detached-process.js +111 -0
  17. package/dist/local-virtual-computer/detached-process.js.map +1 -0
  18. package/dist/local-virtual-computer/detached-worker.d.ts +11 -0
  19. package/dist/local-virtual-computer/detached-worker.d.ts.map +1 -0
  20. package/dist/local-virtual-computer/detached-worker.js +97 -0
  21. package/dist/local-virtual-computer/detached-worker.js.map +1 -0
  22. package/dist/local-virtual-computer/dialect.d.ts +26 -0
  23. package/dist/local-virtual-computer/dialect.d.ts.map +1 -0
  24. package/dist/local-virtual-computer/dialect.js +61 -0
  25. package/dist/local-virtual-computer/dialect.js.map +1 -0
  26. package/dist/local-virtual-computer/engine.d.ts +63 -0
  27. package/dist/local-virtual-computer/engine.d.ts.map +1 -0
  28. package/dist/local-virtual-computer/engine.js +125 -0
  29. package/dist/local-virtual-computer/engine.js.map +1 -0
  30. package/dist/local-virtual-computer/guest-stdio.d.ts +15 -0
  31. package/dist/local-virtual-computer/guest-stdio.d.ts.map +1 -0
  32. package/dist/local-virtual-computer/guest-stdio.js +330 -0
  33. package/dist/local-virtual-computer/guest-stdio.js.map +1 -0
  34. package/dist/local-virtual-computer/index.d.ts +36 -0
  35. package/dist/local-virtual-computer/index.d.ts.map +1 -0
  36. package/dist/local-virtual-computer/index.js +341 -0
  37. package/dist/local-virtual-computer/index.js.map +1 -0
  38. package/dist/local-virtual-computer/podman-machine.d.ts +17 -0
  39. package/dist/local-virtual-computer/podman-machine.d.ts.map +1 -0
  40. package/dist/local-virtual-computer/podman-machine.js +181 -0
  41. package/dist/local-virtual-computer/podman-machine.js.map +1 -0
  42. package/dist/local-virtual-computer/setup/contract.d.ts +360 -0
  43. package/dist/local-virtual-computer/setup/contract.d.ts.map +1 -0
  44. package/dist/local-virtual-computer/setup/contract.js +3 -0
  45. package/dist/local-virtual-computer/setup/contract.js.map +1 -0
  46. package/dist/local-virtual-computer/setup/elevated.d.ts +78 -0
  47. package/dist/local-virtual-computer/setup/elevated.d.ts.map +1 -0
  48. package/dist/local-virtual-computer/setup/elevated.js +548 -0
  49. package/dist/local-virtual-computer/setup/elevated.js.map +1 -0
  50. package/dist/local-virtual-computer/setup/host.d.ts +12 -0
  51. package/dist/local-virtual-computer/setup/host.d.ts.map +1 -0
  52. package/dist/local-virtual-computer/setup/host.js +93 -0
  53. package/dist/local-virtual-computer/setup/host.js.map +1 -0
  54. package/dist/local-virtual-computer/setup/idle.d.ts +18 -0
  55. package/dist/local-virtual-computer/setup/idle.d.ts.map +1 -0
  56. package/dist/local-virtual-computer/setup/idle.js +38 -0
  57. package/dist/local-virtual-computer/setup/idle.js.map +1 -0
  58. package/dist/local-virtual-computer/setup/image.d.ts +7 -0
  59. package/dist/local-virtual-computer/setup/image.d.ts.map +1 -0
  60. package/dist/local-virtual-computer/setup/image.js +124 -0
  61. package/dist/local-virtual-computer/setup/image.js.map +1 -0
  62. package/dist/local-virtual-computer/setup/index.d.ts +17 -0
  63. package/dist/local-virtual-computer/setup/index.d.ts.map +1 -0
  64. package/dist/local-virtual-computer/setup/index.js +17 -0
  65. package/dist/local-virtual-computer/setup/index.js.map +1 -0
  66. package/dist/local-virtual-computer/setup/limits.d.ts +30 -0
  67. package/dist/local-virtual-computer/setup/limits.d.ts.map +1 -0
  68. package/dist/local-virtual-computer/setup/limits.js +58 -0
  69. package/dist/local-virtual-computer/setup/limits.js.map +1 -0
  70. package/dist/local-virtual-computer/setup/plan.d.ts +8 -0
  71. package/dist/local-virtual-computer/setup/plan.d.ts.map +1 -0
  72. package/dist/local-virtual-computer/setup/plan.js +131 -0
  73. package/dist/local-virtual-computer/setup/plan.js.map +1 -0
  74. package/dist/local-virtual-computer/setup/readiness.d.ts +11 -0
  75. package/dist/local-virtual-computer/setup/readiness.d.ts.map +1 -0
  76. package/dist/local-virtual-computer/setup/readiness.js +320 -0
  77. package/dist/local-virtual-computer/setup/readiness.js.map +1 -0
  78. package/dist/local-virtual-computer/setup/registry.d.ts +18 -0
  79. package/dist/local-virtual-computer/setup/registry.d.ts.map +1 -0
  80. package/dist/local-virtual-computer/setup/registry.js +50 -0
  81. package/dist/local-virtual-computer/setup/registry.js.map +1 -0
  82. package/dist/local-virtual-computer/setup/restart.d.ts +8 -0
  83. package/dist/local-virtual-computer/setup/restart.d.ts.map +1 -0
  84. package/dist/local-virtual-computer/setup/restart.js +60 -0
  85. package/dist/local-virtual-computer/setup/restart.js.map +1 -0
  86. package/dist/local-virtual-computer/setup/resume.d.ts +14 -0
  87. package/dist/local-virtual-computer/setup/resume.d.ts.map +1 -0
  88. package/dist/local-virtual-computer/setup/resume.js +58 -0
  89. package/dist/local-virtual-computer/setup/resume.js.map +1 -0
  90. package/dist/local-virtual-computer/setup/run.d.ts +8 -0
  91. package/dist/local-virtual-computer/setup/run.d.ts.map +1 -0
  92. package/dist/local-virtual-computer/setup/run.js +200 -0
  93. package/dist/local-virtual-computer/setup/run.js.map +1 -0
  94. package/dist/local-virtual-computer/setup/windows-folder.d.ts +11 -0
  95. package/dist/local-virtual-computer/setup/windows-folder.d.ts.map +1 -0
  96. package/dist/local-virtual-computer/setup/windows-folder.js +14 -0
  97. package/dist/local-virtual-computer/setup/windows-folder.js.map +1 -0
  98. package/dist/local-virtual-computer/setup/wsl-package.d.ts +19 -0
  99. package/dist/local-virtual-computer/setup/wsl-package.d.ts.map +1 -0
  100. package/dist/local-virtual-computer/setup/wsl-package.js +242 -0
  101. package/dist/local-virtual-computer/setup/wsl-package.js.map +1 -0
  102. package/dist/local-virtual-computer/setup/wslc-shared.d.ts +27 -0
  103. package/dist/local-virtual-computer/setup/wslc-shared.d.ts.map +1 -0
  104. package/dist/local-virtual-computer/setup/wslc-shared.js +137 -0
  105. package/dist/local-virtual-computer/setup/wslc-shared.js.map +1 -0
  106. package/dist/local-virtual-computer/ssh-forward.d.ts +19 -0
  107. package/dist/local-virtual-computer/ssh-forward.d.ts.map +1 -0
  108. package/dist/local-virtual-computer/ssh-forward.js +179 -0
  109. package/dist/local-virtual-computer/ssh-forward.js.map +1 -0
  110. package/dist/local-virtual-computer/wslc-engine.d.ts +27 -0
  111. package/dist/local-virtual-computer/wslc-engine.d.ts.map +1 -0
  112. package/dist/local-virtual-computer/wslc-engine.js +98 -0
  113. package/dist/local-virtual-computer/wslc-engine.js.map +1 -0
  114. package/local-computer/Dockerfile +99 -0
  115. package/local-computer/app-catalog.cjs +240 -0
  116. package/local-computer/app-native-host.cjs +144 -0
  117. package/local-computer/browser-home.cjs +249 -0
  118. package/local-computer/build-image.mjs +310 -0
  119. package/local-computer/desktop-worker.cjs +477 -0
  120. package/local-computer/entrypoint.sh +161 -0
  121. package/local-computer/home.html +28 -0
  122. package/local-computer/new-tab/home.css +255 -0
  123. package/local-computer/new-tab/home.js +65 -0
  124. package/local-computer/new-tab/manifest.json +12 -0
  125. package/local-computer/new-tab/wordmark.svg +33 -0
  126. package/local-computer/openbox-rc.xml +41 -0
  127. package/local-computer/prepare-home.cjs +121 -0
  128. package/local-computer/tint2rc +44 -0
  129. package/package.json +13 -4
  130. package/src/backends/http-worker-client.ts +31 -3
  131. package/src/index.ts +13 -0
  132. package/src/local-virtual-computer/client.ts +573 -0
  133. package/src/local-virtual-computer/detached-process.ts +133 -0
  134. package/src/local-virtual-computer/detached-worker.ts +124 -0
  135. package/src/local-virtual-computer/dialect.ts +83 -0
  136. package/src/local-virtual-computer/engine.ts +197 -0
  137. package/src/local-virtual-computer/guest-stdio.ts +332 -0
  138. package/src/local-virtual-computer/index.ts +447 -0
  139. package/src/local-virtual-computer/podman-machine.ts +264 -0
  140. package/src/local-virtual-computer/setup/contract.ts +395 -0
  141. package/src/local-virtual-computer/setup/elevated.ts +655 -0
  142. package/src/local-virtual-computer/setup/host.ts +100 -0
  143. package/src/local-virtual-computer/setup/idle.ts +39 -0
  144. package/src/local-virtual-computer/setup/image.ts +159 -0
  145. package/src/local-virtual-computer/setup/index.ts +16 -0
  146. package/src/local-virtual-computer/setup/limits.ts +68 -0
  147. package/src/local-virtual-computer/setup/plan.ts +144 -0
  148. package/src/local-virtual-computer/setup/readiness.ts +386 -0
  149. package/src/local-virtual-computer/setup/registry.ts +50 -0
  150. package/src/local-virtual-computer/setup/restart.ts +64 -0
  151. package/src/local-virtual-computer/setup/resume.ts +65 -0
  152. package/src/local-virtual-computer/setup/run.ts +225 -0
  153. package/src/local-virtual-computer/setup/windows-folder.ts +13 -0
  154. package/src/local-virtual-computer/setup/wsl-package.ts +242 -0
  155. package/src/local-virtual-computer/setup/wslc-shared.ts +147 -0
  156. package/src/local-virtual-computer/ssh-forward.ts +195 -0
  157. package/src/local-virtual-computer/wslc-engine.ts +124 -0
  158. package/worker/server.js +1499 -0
@@ -0,0 +1,200 @@
1
+ import { runElevatedWslcSteps } from './elevated.js';
2
+ import { createWslcSetupHost } from './host.js';
3
+ import { loadWslcImage } from './image.js';
4
+ import { planWslcSetup } from './plan.js';
5
+ import { inspectWslcReadiness } from './readiness.js';
6
+ import { clearRestartMarker, readRestartMarker, writeRestartMarker } from './restart.js';
7
+ import { clearResumeAtSignIn, registerResumeAtSignIn } from './resume.js';
8
+ import { PINNED_WSL_PACKAGE, downloadWslPackage } from './wsl-package.js';
9
+ import { readManifest, writeImageRecord } from './wslc-shared.js';
10
+ const isElevated = (kind) => kind === 'enable-windows-features' || kind === 'install-wsl';
11
+ const ELEVATED_WORDS = {
12
+ 'enable-windows-features': 'Turning on Windows features',
13
+ 'install-wsl': 'Installing Linux support',
14
+ };
15
+ const elevatedFailureDetail = (step, exitCode) => {
16
+ const words = isElevated(step) ? ELEVATED_WORDS[step] : 'This step';
17
+ return exitCode === undefined
18
+ ? `${words} did not finish.`
19
+ : `${words} stopped with exit code ${exitCode}.`;
20
+ };
21
+ /**
22
+ * Run the plan the person agreed to. Inspects again first, with the session
23
+ * probe, and refuses with `plan-changed` when the plan it would run is not the
24
+ * one named by the consent.
25
+ */
26
+ export const runWslcSetup = async (consent, options) => {
27
+ const host = createWslcSetupHost(options.host);
28
+ const { signal } = options;
29
+ const pinned = options.wslPackage ?? PINNED_WSL_PACKAGE;
30
+ const inspectOptions = { ...options, host, probeSession: true };
31
+ const markerBefore = await readRestartMarker(host);
32
+ const readiness = await inspectWslcReadiness(inspectOptions);
33
+ let manifest;
34
+ if (readiness.image.bundled) {
35
+ try {
36
+ manifest = await readManifest(readiness.image.bundled.manifestPath);
37
+ }
38
+ catch {
39
+ manifest = undefined;
40
+ }
41
+ }
42
+ const plan = planWslcSetup(readiness, { wslPackage: options.wslPackage, manifest });
43
+ if (plan.id !== consent.planId) {
44
+ // The PC is already ready (for example the image was loaded before Namzu kept a record of
45
+ // it): nothing is left to do, but the next quiet status must say so, so record it now.
46
+ if (readiness.state === 'ready' && manifest) {
47
+ await writeImageRecord(host, {
48
+ imageRef: manifest.imageRef,
49
+ imageId: manifest.imageId,
50
+ loadedAt: host.now().toISOString(),
51
+ });
52
+ return { outcome: 'ready' };
53
+ }
54
+ return { outcome: 'plan-changed', plan };
55
+ }
56
+ if (plan.blocked)
57
+ return { outcome: 'blocked', blocked: plan.blocked };
58
+ // Each step reports started and finished once, whoever emits it.
59
+ const announced = new Set();
60
+ const emit = (progress) => {
61
+ if (progress.phase !== 'progress') {
62
+ const key = `${progress.step}:${progress.phase}`;
63
+ if (announced.has(key))
64
+ return;
65
+ announced.add(key);
66
+ }
67
+ options.onProgress?.(progress);
68
+ };
69
+ const started = (step) => emit({ step, phase: 'started' });
70
+ const finished = (step, result) => emit({ step, phase: 'finished', result });
71
+ const failed = (step, code, detail, exitCode) => ({
72
+ outcome: 'failed',
73
+ step,
74
+ code,
75
+ ...(detail ? { detail } : {}),
76
+ ...(exitCode === undefined ? {} : { exitCode }),
77
+ });
78
+ const kinds = plan.steps.map((step) => step.kind);
79
+ let packagePath;
80
+ let elevatedOk = false;
81
+ for (const step of plan.steps) {
82
+ if (step.kind === 'restart') {
83
+ // Windows said the elevated steps need no restart: nothing to wait for.
84
+ if (elevatedOk)
85
+ continue;
86
+ return { outcome: 'restart-required' };
87
+ }
88
+ if (step.kind === 'download-wsl') {
89
+ started('download-wsl');
90
+ const downloaded = await downloadWslPackage({
91
+ pinned,
92
+ directory: host.stateDirectory,
93
+ onProgress: emit,
94
+ signal,
95
+ });
96
+ if (downloaded.outcome === 'failed')
97
+ return failed('download-wsl', downloaded.code, downloaded.detail);
98
+ packagePath = downloaded.path;
99
+ finished('download-wsl', 'ok');
100
+ }
101
+ if (isElevated(step.kind)) {
102
+ // All elevated steps share one call, made at the first of them.
103
+ if (step.kind !== kinds.find(isElevated))
104
+ continue;
105
+ const elevated = kinds.filter(isElevated);
106
+ // Only the first step is announced now; the tail of the elevated progress file announces
107
+ // each later one when the script reaches it, so a failure never shows a step that did not start.
108
+ started(elevated[0]);
109
+ const outcome = await (options.runElevated ?? runElevatedWslcSteps)({
110
+ steps: elevated,
111
+ ...(elevated.includes('install-wsl') && packagePath
112
+ ? { wslPackage: { path: packagePath, sha256: pinned.sha256 } }
113
+ : {}),
114
+ host,
115
+ onProgress: emit,
116
+ signal,
117
+ });
118
+ switch (outcome.outcome) {
119
+ case 'cancelled':
120
+ return { outcome: 'cancelled' };
121
+ case 'needs-administrator':
122
+ return { outcome: 'needs-administrator' };
123
+ case 'failed': {
124
+ // The steps before the failing one finished, and the failing one started, whether or
125
+ // not the progress tail saw it; the later steps never began.
126
+ const at = elevated.indexOf(outcome.step);
127
+ if (at >= 0) {
128
+ for (const kind of elevated.slice(0, at)) {
129
+ started(kind);
130
+ finished(kind, 'ok');
131
+ }
132
+ started(elevated[at]);
133
+ }
134
+ return failed(outcome.step, outcome.code, elevatedFailureDetail(outcome.step, outcome.exitCode), outcome.exitCode);
135
+ }
136
+ case 'restart-required': {
137
+ const last = elevated[elevated.length - 1];
138
+ for (const kind of elevated) {
139
+ started(kind);
140
+ finished(kind, kind === last ? 'restart-required' : 'ok');
141
+ }
142
+ const after = kinds.slice(kinds.lastIndexOf(last) + 1);
143
+ await writeRestartMarker(host, {
144
+ recordedAt: host.now().toISOString(),
145
+ planId: plan.id,
146
+ remaining: after.filter((kind) => kind !== 'restart'),
147
+ });
148
+ if (options.resumeCommand)
149
+ await registerResumeAtSignIn(host, options.resumeCommand);
150
+ return { outcome: 'restart-required' };
151
+ }
152
+ case 'ok':
153
+ for (const kind of elevated) {
154
+ started(kind);
155
+ finished(kind, 'ok');
156
+ }
157
+ elevatedOk = true;
158
+ break;
159
+ }
160
+ }
161
+ if (step.kind === 'load-image') {
162
+ if (!readiness.image.bundled)
163
+ return { outcome: 'blocked', blocked: 'image-unavailable' };
164
+ started('load-image');
165
+ const loaded = await loadWslcImage({
166
+ manifestPath: readiness.image.bundled.manifestPath,
167
+ host,
168
+ onProgress: emit,
169
+ signal,
170
+ });
171
+ if (loaded.outcome === 'failed')
172
+ return failed('load-image', loaded.code, loaded.detail);
173
+ finished('load-image', 'ok');
174
+ }
175
+ }
176
+ const after = await inspectWslcReadiness(inspectOptions);
177
+ switch (after.state) {
178
+ case 'ready':
179
+ if (markerBefore !== undefined) {
180
+ await clearRestartMarker(host);
181
+ try {
182
+ await clearResumeAtSignIn(host);
183
+ }
184
+ catch {
185
+ // The resume entry is a convenience; a leftover one is harmless.
186
+ }
187
+ }
188
+ return { outcome: 'ready' };
189
+ case 'restart-pending':
190
+ return { outcome: 'restart-required' };
191
+ case 'virtualization-off':
192
+ case 'sdk-mismatch':
193
+ case 'blocked-by-policy':
194
+ case 'unsupported':
195
+ return { outcome: 'blocked', blocked: after.state };
196
+ default:
197
+ return failed(plan.steps[plan.steps.length - 1]?.kind ?? 'load-image', 'engine-failed', 'Setup finished, but the Pal computer is still not ready on this PC.');
198
+ }
199
+ };
200
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/local-virtual-computer/setup/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The Windows folder as a path setup code may run programs from.
3
+ *
4
+ * The environment is only a claim, so a value is accepted when it is a drive
5
+ * root followed by `Windows` or `WINNT`; anything else becomes `C:\Windows`.
6
+ * A PC whose Windows folder has another name therefore cannot be set up by
7
+ * this code: the launch fails (reported as `elevation-failed`) rather than
8
+ * running a program from a folder the environment picked.
9
+ */
10
+ export declare function trustedWindowsDirectory(env: NodeJS.ProcessEnv): string;
11
+ //# sourceMappingURL=windows-folder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-folder.d.ts","sourceRoot":"","sources":["../../../src/local-virtual-computer/setup/windows-folder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAGtE"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The Windows folder as a path setup code may run programs from.
3
+ *
4
+ * The environment is only a claim, so a value is accepted when it is a drive
5
+ * root followed by `Windows` or `WINNT`; anything else becomes `C:\Windows`.
6
+ * A PC whose Windows folder has another name therefore cannot be set up by
7
+ * this code: the launch fails (reported as `elevation-failed`) rather than
8
+ * running a program from a folder the environment picked.
9
+ */
10
+ export function trustedWindowsDirectory(env) {
11
+ const claimed = (env.SystemRoot ?? env.windir ?? '').replace(/[\\/]+$/, '');
12
+ return /^[A-Za-z]:\\(Windows|WINNT)$/i.test(claimed) ? claimed : 'C:\\Windows';
13
+ }
14
+ //# sourceMappingURL=windows-folder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-folder.js","sourceRoot":"","sources":["../../../src/local-virtual-computer/setup/windows-folder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAsB;IAC7D,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAC3E,OAAO,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAA;AAC/E,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { DownloadWslPackage, PinnedWslPackage } from './contract.js';
2
+ /**
3
+ * The WSL release setup installs: Microsoft's per-machine MSI for x64 from
4
+ * https://github.com/microsoft/WSL/releases/tag/3.0.1. The size and digest are
5
+ * the ones the release API reports for the asset, and were recomputed from a
6
+ * download of the file.
7
+ */
8
+ export declare const PINNED_WSL_PACKAGE: PinnedWslPackage;
9
+ /**
10
+ * Fetch the pinned package into `directory/<file name>.part` (resuming it with
11
+ * a Range request when a partial file exists), check the SHA-256, and
12
+ * rename it to `directory/<file name>`. A file that fails the check is
13
+ * deleted. Network trouble and 5xx answers retry with exponential backoff; a
14
+ * 4xx answer fails at once. Emits only `progress` events; the caller owns
15
+ * `started` and `finished`. An aborted signal rejects with the signal's reason
16
+ * and leaves the partial file for the next run.
17
+ */
18
+ export declare const downloadWslPackage: DownloadWslPackage;
19
+ //# sourceMappingURL=wsl-package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsl-package.d.ts","sourceRoot":"","sources":["../../../src/local-virtual-computer/setup/wsl-package.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAqB,MAAM,eAAe,CAAA;AAE5F;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAMhC,CAAA;AA+JD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,kBAuDhC,CAAA"}
@@ -0,0 +1,242 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { createReadStream } from 'node:fs';
3
+ import { mkdir, open, rename, rm, stat } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ /**
6
+ * The WSL release setup installs: Microsoft's per-machine MSI for x64 from
7
+ * https://github.com/microsoft/WSL/releases/tag/3.0.1. The size and digest are
8
+ * the ones the release API reports for the asset, and were recomputed from a
9
+ * download of the file.
10
+ */
11
+ export const PINNED_WSL_PACKAGE = {
12
+ version: '3.0.1.0',
13
+ architecture: 'x64',
14
+ url: 'https://github.com/microsoft/WSL/releases/download/3.0.1/wsl.3.0.1.0.x64.msi',
15
+ sha256: '28b1a0d013640a2ac95898ea705fa186e5b4ff767a1c1b49257161bc106599c6',
16
+ sizeBytes: 367669248,
17
+ };
18
+ /** Attempts before a download gives up, counting the first. */
19
+ const MAX_ATTEMPTS = 5;
20
+ /** Backoff before attempt n+1 is `BASE_DELAY_MS * 2 ** n`. */
21
+ const BASE_DELAY_MS = 1000;
22
+ /** Report progress at most once per this many bytes (and at the end). */
23
+ const PROGRESS_STEP_BYTES = 512 * 1024;
24
+ class RetryableError extends Error {
25
+ }
26
+ class FatalError extends Error {
27
+ }
28
+ function fileNameOf(url) {
29
+ const name = new URL(url).pathname.split('/').pop() ?? '';
30
+ if (!/^[A-Za-z0-9._-]+$/.test(name) || name.startsWith('.')) {
31
+ throw new FatalError('The package address has no usable file name.');
32
+ }
33
+ return name;
34
+ }
35
+ function sleep(ms, signal) {
36
+ return new Promise((resolve, reject) => {
37
+ if (signal?.aborted) {
38
+ reject(signal.reason);
39
+ return;
40
+ }
41
+ const onAbort = () => {
42
+ clearTimeout(timer);
43
+ reject(signal?.reason);
44
+ };
45
+ const timer = setTimeout(() => {
46
+ signal?.removeEventListener('abort', onAbort);
47
+ resolve();
48
+ }, ms);
49
+ signal?.addEventListener('abort', onAbort, { once: true });
50
+ });
51
+ }
52
+ async function sizeOf(path) {
53
+ try {
54
+ return (await stat(path)).size;
55
+ }
56
+ catch {
57
+ return undefined;
58
+ }
59
+ }
60
+ function sha256Of(path, signal) {
61
+ return new Promise((resolve, reject) => {
62
+ const hash = createHash('sha256');
63
+ const stream = createReadStream(path, { signal });
64
+ stream.on('data', (chunk) => hash.update(chunk));
65
+ stream.on('error', reject);
66
+ stream.on('end', () => resolve(hash.digest('hex')));
67
+ });
68
+ }
69
+ /** Like {@link sha256Of}, but an abort rejects with the signal's reason, as everywhere else here. */
70
+ async function hashOrAbort(path, signal) {
71
+ try {
72
+ return await sha256Of(path, signal);
73
+ }
74
+ catch (error) {
75
+ if (signal?.aborted)
76
+ throw signal.reason;
77
+ throw error;
78
+ }
79
+ }
80
+ /**
81
+ * One attempt: continue `part` from its current size when the server honours
82
+ * the range, or start over when it does not. Resolves when `part` holds
83
+ * `sizeBytes`.
84
+ */
85
+ async function attempt(pinned, part, fetchImpl, onProgress, signal) {
86
+ let have = (await sizeOf(part)) ?? 0;
87
+ if (have > pinned.sizeBytes) {
88
+ await rm(part, { force: true });
89
+ have = 0;
90
+ }
91
+ if (have === pinned.sizeBytes)
92
+ return;
93
+ let response;
94
+ try {
95
+ response = await fetchImpl(pinned.url, {
96
+ headers: have > 0 ? { Range: `bytes=${have}-` } : {},
97
+ redirect: 'follow',
98
+ signal,
99
+ });
100
+ }
101
+ catch (error) {
102
+ if (signal?.aborted)
103
+ throw signal.reason;
104
+ throw new RetryableError(error instanceof Error ? error.message : 'The request failed.');
105
+ }
106
+ if (response.status === 416) {
107
+ // The partial file does not fit what the server has; start over.
108
+ await rm(part, { force: true });
109
+ throw new RetryableError('The server refused the resume range.');
110
+ }
111
+ if (response.status !== 200 && response.status !== 206) {
112
+ const message = `The server answered ${response.status}.`;
113
+ if (response.status === 429 || response.status >= 500)
114
+ throw new RetryableError(message);
115
+ throw new FatalError(message);
116
+ }
117
+ if (!response.body)
118
+ throw new RetryableError('The server sent no data.');
119
+ let resumed = response.status === 206 && have > 0;
120
+ if (resumed) {
121
+ // A 206 for another offset would append misaligned bytes: drop the
122
+ // partial file and fetch again from zero.
123
+ const start = /^bytes (\d+)-/.exec(response.headers.get('content-range') ?? '')?.[1];
124
+ if (start === undefined || Number(start) !== have) {
125
+ await response.body.cancel().catch(() => undefined);
126
+ await rm(part, { force: true });
127
+ throw new RetryableError('The server answered for a different part of the file.');
128
+ }
129
+ }
130
+ else {
131
+ resumed = false;
132
+ have = 0;
133
+ }
134
+ const handle = await open(part, resumed ? 'a' : 'w');
135
+ let done = have;
136
+ let reported = have;
137
+ try {
138
+ const reader = response.body.getReader();
139
+ try {
140
+ for (;;) {
141
+ const { value, done: finished } = await reader.read();
142
+ if (finished)
143
+ break;
144
+ await handle.write(value);
145
+ done += value.byteLength;
146
+ if (done - reported >= PROGRESS_STEP_BYTES) {
147
+ reported = done;
148
+ onProgress?.({
149
+ step: 'download-wsl',
150
+ phase: 'progress',
151
+ done,
152
+ total: pinned.sizeBytes,
153
+ unit: 'bytes',
154
+ });
155
+ }
156
+ }
157
+ }
158
+ catch (error) {
159
+ if (signal?.aborted)
160
+ throw signal.reason;
161
+ throw new RetryableError(error instanceof Error ? error.message : 'The download broke off.');
162
+ }
163
+ }
164
+ finally {
165
+ await handle.close();
166
+ }
167
+ onProgress?.({
168
+ step: 'download-wsl',
169
+ phase: 'progress',
170
+ done,
171
+ total: pinned.sizeBytes,
172
+ unit: 'bytes',
173
+ });
174
+ if (done < pinned.sizeBytes)
175
+ throw new RetryableError('The download ended early.');
176
+ }
177
+ /**
178
+ * Fetch the pinned package into `directory/<file name>.part` (resuming it with
179
+ * a Range request when a partial file exists), check the SHA-256, and
180
+ * rename it to `directory/<file name>`. A file that fails the check is
181
+ * deleted. Network trouble and 5xx answers retry with exponential backoff; a
182
+ * 4xx answer fails at once. Emits only `progress` events; the caller owns
183
+ * `started` and `finished`. An aborted signal rejects with the signal's reason
184
+ * and leaves the partial file for the next run.
185
+ */
186
+ export const downloadWslPackage = async (options) => {
187
+ const { pinned, directory, signal, onProgress } = options;
188
+ const fetchImpl = options.fetch ?? fetch;
189
+ let target;
190
+ try {
191
+ target = join(directory, fileNameOf(pinned.url));
192
+ }
193
+ catch (error) {
194
+ return { outcome: 'failed', code: 'download-failed', detail: error.message };
195
+ }
196
+ const part = `${target}.part`;
197
+ await mkdir(directory, { recursive: true });
198
+ // A previous run may have left a finished, verified file.
199
+ if ((await sizeOf(target)) === pinned.sizeBytes &&
200
+ (await hashOrAbort(target, signal)) === pinned.sha256) {
201
+ return { outcome: 'ok', path: target };
202
+ }
203
+ await rm(target, { force: true });
204
+ let lastError = 'The download failed.';
205
+ for (let n = 0; n < MAX_ATTEMPTS; n++) {
206
+ signal?.throwIfAborted();
207
+ if (n > 0)
208
+ await sleep(BASE_DELAY_MS * 2 ** (n - 1), signal);
209
+ try {
210
+ await attempt(pinned, part, fetchImpl, onProgress, signal);
211
+ }
212
+ catch (error) {
213
+ if (signal?.aborted)
214
+ throw signal.reason;
215
+ if (error instanceof FatalError) {
216
+ return { outcome: 'failed', code: 'download-failed', detail: error.message };
217
+ }
218
+ if (error instanceof RetryableError) {
219
+ lastError = error.message;
220
+ continue;
221
+ }
222
+ return {
223
+ outcome: 'failed',
224
+ code: 'download-failed',
225
+ detail: 'The package could not be written to disk.',
226
+ };
227
+ }
228
+ // The digest decides; a file of the wrong length cannot have the right one.
229
+ if ((await hashOrAbort(part, signal)) !== pinned.sha256) {
230
+ await rm(part, { force: true });
231
+ return {
232
+ outcome: 'failed',
233
+ code: 'download-corrupt',
234
+ detail: 'The downloaded package does not match the release Namzu expects.',
235
+ };
236
+ }
237
+ await rename(part, target);
238
+ return { outcome: 'ok', path: target };
239
+ }
240
+ return { outcome: 'failed', code: 'download-failed', detail: lastError };
241
+ };
242
+ //# sourceMappingURL=wsl-package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsl-package.js","sourceRoot":"","sources":["../../../src/local-virtual-computer/setup/wsl-package.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { WslcImageManifest, WslcSetupHost } from './contract.js';
2
+ /** The label every Pal computer image carries; it names the guest protocol. */
3
+ export declare const PROTOCOL_LABEL = "org.namzu.local-computer.protocol";
4
+ /** Where the WSL package puts wslc. */
5
+ export declare function wslcBinaryOf(host: Pick<WslcSetupHost, 'env'>): string;
6
+ /** Why a manifest was refused, in words safe to show. */
7
+ export declare class ManifestError extends Error {
8
+ readonly name = "ManifestError";
9
+ }
10
+ /** Validate a parsed manifest. Throws {@link ManifestError}. */
11
+ export declare function validateManifest(value: unknown): WslcImageManifest;
12
+ export declare function readManifest(manifestPath: string): Promise<WslcImageManifest>;
13
+ /** The archive lies beside its manifest. */
14
+ export declare function archivePathOf(manifestPath: string, manifest: WslcImageManifest): string;
15
+ /** `[{ Id, Config: { Labels } }]` from `wslc image inspect -f json`. */
16
+ export declare function parseImageInspect(output: string): {
17
+ id: string;
18
+ protocol: string | undefined;
19
+ } | undefined;
20
+ export interface WslcImageRecord {
21
+ readonly imageRef: string;
22
+ readonly imageId: string;
23
+ readonly loadedAt: string;
24
+ }
25
+ export declare function readImageRecord(host: Pick<WslcSetupHost, 'stateDirectory'>): Promise<WslcImageRecord | undefined>;
26
+ export declare function writeImageRecord(host: Pick<WslcSetupHost, 'stateDirectory'>, record: WslcImageRecord): Promise<void>;
27
+ //# sourceMappingURL=wslc-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wslc-shared.d.ts","sourceRoot":"","sources":["../../../src/local-virtual-computer/setup/wslc-shared.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAErE,+EAA+E;AAC/E,eAAO,MAAM,cAAc,sCAAsC,CAAA;AAEjE,uCAAuC;AACvC,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,MAAM,CAIrE;AAED,yDAAyD;AACzD,qBAAa,aAAc,SAAQ,KAAK;IACvC,SAAkB,IAAI,mBAAkB;CACxC;AAQD,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CA0ClE;AAED,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAcnF;AAED,4CAA4C;AAC5C,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAEvF;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,GACZ;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAa1D;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CACzB;AAMD,wBAAsB,eAAe,CACpC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,GACzC,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAStC;AAED,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,EAC3C,MAAM,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAWf"}