@scalar/cli 2.0.1 → 2.5.1

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 (83) hide show
  1. package/README.md +68 -24
  2. package/chunks/action-37EV4UHW.js +125 -0
  3. package/chunks/action-4XI7XJR4.js +204 -0
  4. package/chunks/action-5IU77OII.js +60 -0
  5. package/chunks/action-B3KKREWQ.js +64 -0
  6. package/chunks/action-CH24QGTE.js +86 -0
  7. package/chunks/action-F3UX5E3M.js +522 -0
  8. package/chunks/action-FDB7NEOK.js +81 -0
  9. package/chunks/action-FIXBOJEW.js +244 -0
  10. package/chunks/action-G26LSVZ7.js +40 -0
  11. package/chunks/action-H3RTILLM.js +46 -0
  12. package/chunks/action-HGBBV353.js +86 -0
  13. package/chunks/action-IUE4IOWO.js +2142 -0
  14. package/chunks/action-JZLZ7ZAD.js +110 -0
  15. package/chunks/action-LA6KVAXQ.js +374 -0
  16. package/chunks/action-M7RQKBSB.js +169 -0
  17. package/chunks/action-MSLBC2SO.js +92 -0
  18. package/chunks/action-NVSZT2ZD.js +37 -0
  19. package/chunks/action-OGQSTRMX.js +37 -0
  20. package/chunks/action-PAGJ5PWC.js +60 -0
  21. package/chunks/action-QE2ZQQX7.js +250 -0
  22. package/chunks/action-QPUSPD5M.js +54 -0
  23. package/chunks/action-R7IMFHQ5.js +147 -0
  24. package/chunks/action-SH4UUXPL.js +60 -0
  25. package/chunks/action-SNLCIBQC.js +84 -0
  26. package/chunks/action-SQG3JAII.js +150 -0
  27. package/chunks/action-UZQJNYK4.js +18 -0
  28. package/chunks/action-VC4DCVST.js +68 -0
  29. package/chunks/action-VTVFY2MP.js +181 -0
  30. package/chunks/action-WFWYGY7O.js +67 -0
  31. package/chunks/action-XMNX5ZYT.js +197 -0
  32. package/chunks/agent-HCQRMHQ5.js +132 -0
  33. package/chunks/asyncapi-QM76O55R.js +105 -0
  34. package/chunks/build.action-P7FCIMYU.js +108 -0
  35. package/chunks/chunk-24WAOKGG.js +105 -0
  36. package/chunks/chunk-3L6DLIXJ.js +25530 -0
  37. package/chunks/chunk-3MZYUBJ6.js +49 -0
  38. package/chunks/chunk-3ZJYGGAA.js +30 -0
  39. package/chunks/chunk-4NHMAG6F.js +21 -0
  40. package/chunks/chunk-4ORL4MST.js +16 -0
  41. package/chunks/chunk-4ZDQXWBT.js +26 -0
  42. package/chunks/chunk-6ZMT63IV.js +19 -0
  43. package/chunks/chunk-7AGLC7WV.js +107 -0
  44. package/chunks/chunk-AEFPCC4U.js +16 -0
  45. package/chunks/chunk-AO3F5XWR.js +3147 -0
  46. package/chunks/chunk-B2MHTD3R.js +90 -0
  47. package/chunks/chunk-CISTON3A.js +153 -0
  48. package/chunks/chunk-COBPBRQF.js +25 -0
  49. package/chunks/chunk-F467BYYR.js +568 -0
  50. package/chunks/chunk-GSGZHE26.js +352 -0
  51. package/chunks/chunk-HCPN3KNF.js +637 -0
  52. package/chunks/chunk-HPL3ZZ2P.js +1726 -0
  53. package/chunks/chunk-IKT5F47M.js +17344 -0
  54. package/chunks/chunk-JFIXNSPP.js +26 -0
  55. package/chunks/chunk-K4DTP5TV.js +32 -0
  56. package/chunks/chunk-K74E42RV.js +7311 -0
  57. package/chunks/chunk-KHDYYVYF.js +16 -0
  58. package/chunks/chunk-LFU5ZUAP.js +350 -0
  59. package/chunks/chunk-M37TP6U2.js +445 -0
  60. package/chunks/chunk-OQKDBLOZ.js +741 -0
  61. package/chunks/chunk-P7H7GY5A.js +14 -0
  62. package/chunks/chunk-PBXZN65A.js +63911 -0
  63. package/chunks/chunk-PT5TI77I.js +34 -0
  64. package/chunks/chunk-Q7DOQHZN.js +404 -0
  65. package/chunks/chunk-T5HJUAWB.js +242 -0
  66. package/chunks/chunk-T7B6WNZC.js +18 -0
  67. package/chunks/chunk-UGGNHILG.js +38 -0
  68. package/chunks/chunk-VNYE4R7N.js +499 -0
  69. package/chunks/chunk-X5T526CE.js +23 -0
  70. package/chunks/chunk-XCSR4RIT.js +210 -0
  71. package/chunks/chunk-Z2KMGFE6.js +295 -0
  72. package/chunks/create.action-HDD2WUON.js +108 -0
  73. package/chunks/delete.action-7GOZY7ID.js +88 -0
  74. package/chunks/delete.action-VE66JFDS.js +96 -0
  75. package/chunks/get.action-2745EB4N.js +86 -0
  76. package/chunks/list.action-3VTXQJRA.js +116 -0
  77. package/chunks/list.action-4QDCZLSZ.js +95 -0
  78. package/chunks/publish.action-ULQLZKWU.js +190 -0
  79. package/chunks/update.action-6QEFP7NA.js +95 -0
  80. package/chunks/update.action-OROQSP2S.js +101 -0
  81. package/docs.html +352 -250
  82. package/index.js +664 -99064
  83. package/package.json +17 -11
@@ -0,0 +1,16 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+
3
+ // src/helpers/time.ts
4
+ async function measureTime(fn) {
5
+ const start = performance.now();
6
+ const result = await fn();
7
+ const end = performance.now();
8
+ return {
9
+ result,
10
+ executionTimeMs: end - start
11
+ };
12
+ }
13
+
14
+ export {
15
+ measureTime
16
+ };
@@ -0,0 +1,350 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+ import {
3
+ displayError
4
+ } from "./chunk-3ZJYGGAA.js";
5
+ import {
6
+ ISOLATE_DIR,
7
+ ISOLATE_EXTRACTION_DIR
8
+ } from "./chunk-X5T526CE.js";
9
+ import {
10
+ config
11
+ } from "./chunk-4ZDQXWBT.js";
12
+ import {
13
+ output
14
+ } from "./chunk-T5HJUAWB.js";
15
+
16
+ // src/domains/project/download-isolate/action.ts
17
+ import { execFile } from "node:child_process";
18
+ import fs from "node:fs/promises";
19
+ import path from "node:path";
20
+ import { Readable } from "node:stream";
21
+ import { pipeline } from "node:stream/promises";
22
+ import { promisify } from "node:util";
23
+ import zlib from "node:zlib";
24
+ import { nanoid } from "nanoid";
25
+ import tar from "tar-fs";
26
+
27
+ // src/domains/project/download-isolate/helpers.ts
28
+ var PLATFORM_TARBALL_TARGETS = /* @__PURE__ */ new Set([
29
+ "darwin-arm64",
30
+ "darwin-x64",
31
+ "linux-arm64",
32
+ "linux-x64",
33
+ "win32-arm64",
34
+ "win32-x64"
35
+ ]);
36
+ function getIsolateDownloadUrls(options) {
37
+ const baseUrl = `${options.cdnUrl}/isolates/${options.version}-isolate`;
38
+ const universalUrl = `${baseUrl}.tar.gz`;
39
+ const target = `${options.platform}-${options.arch}`;
40
+ if (!PLATFORM_TARBALL_TARGETS.has(target)) return [universalUrl];
41
+ return [`${baseUrl}-${target}.tar.gz`, universalUrl];
42
+ }
43
+
44
+ // src/domains/project/download-isolate/action.ts
45
+ var execFileAsync = promisify(execFile);
46
+ var IsolateDownloadError = class extends Error {
47
+ constructor(message, options) {
48
+ super(message, options);
49
+ this.name = "IsolateDownloadError";
50
+ }
51
+ };
52
+ var DOWNLOAD_TIMEOUT_MS = 10 * 60 * 1e3;
53
+ var EXTRACTION_ALLOWANCE_MS = 5 * 60 * 1e3;
54
+ async function getExistingIsolateVersion() {
55
+ try {
56
+ const packageJsonString = await fs.readFile(
57
+ path.join(ISOLATE_DIR, "package.json"),
58
+ "utf8"
59
+ );
60
+ const packageJson = JSON.parse(packageJsonString);
61
+ return packageJson.version;
62
+ } catch {
63
+ return void 0;
64
+ }
65
+ }
66
+ async function downloadWindowsIsolate(isolateUrl, destinationDir, timeoutMs) {
67
+ return new Promise((resolve, reject) => {
68
+ const timeoutSeconds = Math.ceil(timeoutMs / 1e3);
69
+ const psScript = `
70
+ $ErrorActionPreference = "Stop"
71
+
72
+ $targetDir = "${destinationDir}"
73
+ $tempFile = Join-Path $env:TEMP "scalar-isolate-download.tar.gz"
74
+
75
+ # Ensure target directory exists
76
+ New-Item -ItemType Directory -Force -Path $targetDir | Out-Null
77
+
78
+ # Download tarball. -TimeoutSec bounds the request so a stalled connection
79
+ # aborts instead of hanging indefinitely.
80
+ $ProgressPreference = 'SilentlyContinue'
81
+ Invoke-WebRequest -Uri "${isolateUrl}" -OutFile $tempFile -TimeoutSec ${timeoutSeconds}
82
+
83
+ # Extract (uses built-in tar on Windows)
84
+ tar -xzf $tempFile -C $targetDir
85
+
86
+ # Cleanup
87
+ Remove-Item $tempFile
88
+ `;
89
+ execFile(
90
+ "powershell.exe",
91
+ [
92
+ "-NoProfile",
93
+ "-NonInteractive",
94
+ "-ExecutionPolicy",
95
+ "Bypass",
96
+ "-Command",
97
+ psScript
98
+ ],
99
+ // Hard backstop: kill PowerShell if the whole run (download + extraction)
100
+ // overruns. `-TimeoutSec` only bounds the download, so the process budget
101
+ // adds an extraction allowance on top — a download that finishes near its
102
+ // own limit still has time to unpack, mirroring the unbounded extraction
103
+ // on Unix where the fetch timeout does not cover `tar`.
104
+ { windowsHide: true, timeout: timeoutMs + EXTRACTION_ALLOWANCE_MS },
105
+ (error, stdout, stderr) => {
106
+ if (error) {
107
+ error.stderr = stderr;
108
+ return reject(error);
109
+ }
110
+ resolve(stdout);
111
+ }
112
+ );
113
+ });
114
+ }
115
+ async function downloadAndExtract(url, destinationDir, options) {
116
+ if (process.platform === "win32") {
117
+ await downloadWindowsIsolate(url, destinationDir, options.timeoutMs);
118
+ return;
119
+ }
120
+ const response = await options.fetchImpl(url, {
121
+ signal: AbortSignal.timeout(options.timeoutMs)
122
+ });
123
+ if (!response.ok) {
124
+ throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
125
+ }
126
+ if (!response.body) {
127
+ throw new Error("Response had no body");
128
+ }
129
+ await pipeline(
130
+ Readable.fromWeb(response.body),
131
+ zlib.createGunzip(),
132
+ tar.extract(destinationDir)
133
+ );
134
+ }
135
+ async function assertIsolateLayout(destinationDir, url) {
136
+ try {
137
+ await fs.access(path.join(destinationDir, "isolate", "package.json"));
138
+ } catch {
139
+ throw new Error(
140
+ `The download from ${url} did not contain a valid docs preview server.`
141
+ );
142
+ }
143
+ }
144
+ var DISK_WRITE_ERROR_CODES = /* @__PURE__ */ new Set([
145
+ "ENOSPC",
146
+ // No space left on device
147
+ "EACCES",
148
+ // Permission denied
149
+ "EPERM",
150
+ // Operation not permitted
151
+ "EBUSY",
152
+ // Resource busy or locked
153
+ "EROFS",
154
+ // Read-only filesystem
155
+ "EDQUOT",
156
+ // Disk quota exceeded
157
+ "EMFILE",
158
+ // Too many open files
159
+ "ENFILE"
160
+ // File table overflow
161
+ ]);
162
+ var DISK_WRITE_ERROR_MESSAGES = [
163
+ "no space left on device",
164
+ // ENOSPC / bsdtar
165
+ "not enough space",
166
+ // Windows disk-full phrasing
167
+ "disk quota exceeded",
168
+ // EDQUOT
169
+ "permission denied",
170
+ // EACCES
171
+ "access is denied",
172
+ // Windows permission phrasing
173
+ "operation not permitted",
174
+ // EPERM
175
+ "read-only file system"
176
+ // EROFS
177
+ ];
178
+ function isDiskWriteError(error) {
179
+ if (!(error instanceof Error)) return false;
180
+ const code = error.code;
181
+ if (typeof code === "string" && DISK_WRITE_ERROR_CODES.has(code)) {
182
+ return true;
183
+ }
184
+ const details = `${error.message} ${error.stderr ?? ""}`.toLowerCase();
185
+ return DISK_WRITE_ERROR_MESSAGES.some((phrase) => details.includes(phrase));
186
+ }
187
+ async function downloadFirstAvailable(urls, destinationDir, options) {
188
+ const failures = [];
189
+ for (const url of urls) {
190
+ try {
191
+ await fs.rm(destinationDir, { recursive: true, force: true });
192
+ await downloadAndExtract(url, destinationDir, options);
193
+ await assertIsolateLayout(destinationDir, url);
194
+ return url;
195
+ } catch (error) {
196
+ if (isDiskWriteError(error)) throw error;
197
+ failures.push(
198
+ ` - ${url}: ${error instanceof Error ? error.message : String(error)}`
199
+ );
200
+ }
201
+ }
202
+ throw new IsolateDownloadError(
203
+ `Failed to download the docs preview server. Attempted:
204
+ ${failures.join("\n")}
205
+ Your existing preview server (if any) was left untouched. Check your network connection and try again.`
206
+ );
207
+ }
208
+ async function removeQuarantineAttributes(isolateDir) {
209
+ if (process.platform !== "darwin") return;
210
+ try {
211
+ await execFileAsync("xattr", ["-dr", "com.apple.quarantine", isolateDir]);
212
+ } catch {
213
+ }
214
+ }
215
+ async function swapIsolateDirectory(newIsolateDir, isolateDir) {
216
+ const backupDir = `${isolateDir}.old-${nanoid()}`;
217
+ let hasBackup = false;
218
+ try {
219
+ await fs.rename(isolateDir, backupDir);
220
+ hasBackup = true;
221
+ } catch (error) {
222
+ const isMissing = error instanceof Error && error.code === "ENOENT";
223
+ if (!isMissing) throw error;
224
+ }
225
+ try {
226
+ await fs.rename(newIsolateDir, isolateDir);
227
+ } catch (error) {
228
+ if (hasBackup) {
229
+ try {
230
+ await fs.rename(backupDir, isolateDir);
231
+ } catch {
232
+ throw new Error(
233
+ `Failed to install the new docs preview server and could not restore the previous one. Your previous preview server is preserved at ${backupDir} \u2014 rename it back to ${isolateDir} to recover.`,
234
+ { cause: error }
235
+ );
236
+ }
237
+ }
238
+ throw error;
239
+ }
240
+ if (hasBackup) {
241
+ await fs.rm(backupDir, { recursive: true, force: true }).catch(() => {
242
+ });
243
+ }
244
+ }
245
+ async function removeDirectoriesWithPrefixes(extractionDir, prefixes, minAgeMs = 0) {
246
+ try {
247
+ const entries = await fs.readdir(extractionDir);
248
+ const now = Date.now();
249
+ const matches = entries.filter(
250
+ (entry) => prefixes.some((prefix) => entry.startsWith(prefix))
251
+ );
252
+ await Promise.all(
253
+ matches.map(async (entry) => {
254
+ const entryPath = path.join(extractionDir, entry);
255
+ if (minAgeMs > 0) {
256
+ try {
257
+ const { mtimeMs } = await fs.stat(entryPath);
258
+ if (now - mtimeMs < minAgeMs) return;
259
+ } catch {
260
+ return;
261
+ }
262
+ }
263
+ await fs.rm(entryPath, { recursive: true, force: true });
264
+ })
265
+ );
266
+ } catch {
267
+ }
268
+ }
269
+ var STALE_WORKING_DIR_AGE_MS = 10 * 60 * 1e3;
270
+ async function cleanupStaleWorkingDirectories(extractionDir) {
271
+ const prefixes = ["isolate.tmp-"];
272
+ try {
273
+ const hasLiveIsolate = (await fs.readdir(extractionDir)).includes("isolate");
274
+ if (hasLiveIsolate) prefixes.push("isolate.old-");
275
+ } catch {
276
+ }
277
+ await removeDirectoriesWithPrefixes(
278
+ extractionDir,
279
+ prefixes,
280
+ STALE_WORKING_DIR_AGE_MS
281
+ );
282
+ }
283
+ async function updateIsolate(options) {
284
+ const {
285
+ urls,
286
+ extractionDir,
287
+ fetchImpl = fetch,
288
+ timeoutMs = DOWNLOAD_TIMEOUT_MS
289
+ } = options;
290
+ const isolateDir = path.join(extractionDir, "isolate");
291
+ await fs.mkdir(extractionDir, { recursive: true });
292
+ await cleanupStaleWorkingDirectories(extractionDir);
293
+ const temporaryDir = path.join(extractionDir, `isolate.tmp-${nanoid()}`);
294
+ try {
295
+ const usedUrl = await downloadFirstAvailable(urls, temporaryDir, {
296
+ fetchImpl,
297
+ timeoutMs
298
+ });
299
+ const downloadedIsolateDir = path.join(temporaryDir, "isolate");
300
+ await removeQuarantineAttributes(downloadedIsolateDir);
301
+ await swapIsolateDirectory(downloadedIsolateDir, isolateDir);
302
+ await removeDirectoriesWithPrefixes(
303
+ extractionDir,
304
+ ["isolate.old-"],
305
+ STALE_WORKING_DIR_AGE_MS
306
+ );
307
+ return usedUrl;
308
+ } finally {
309
+ await fs.rm(temporaryDir, { recursive: true, force: true }).catch(() => {
310
+ });
311
+ }
312
+ }
313
+ async function downloadIsolate() {
314
+ const existingIsolateVersion = await getExistingIsolateVersion();
315
+ if (config.ssgDocsIsolateVersion === existingIsolateVersion) return;
316
+ const logger = output.info({ animate: true }).loader("Downloading the docs preview server. This may take a minute...");
317
+ const urls = getIsolateDownloadUrls({
318
+ cdnUrl: config.cdnUrl,
319
+ version: config.ssgDocsIsolateVersion,
320
+ platform: process.platform,
321
+ arch: process.arch
322
+ });
323
+ try {
324
+ await updateIsolate({ urls, extractionDir: ISOLATE_EXTRACTION_DIR });
325
+ } catch (error) {
326
+ const isDownloadFailure = error instanceof IsolateDownloadError;
327
+ logger.update("loader", 0, {
328
+ content: isDownloadFailure ? "Download failed." : "Installation failed.",
329
+ status: "error"
330
+ });
331
+ logger.finish();
332
+ return output.error().title(
333
+ isDownloadFailure ? "Could not download the docs preview server" : "Could not install the docs preview server"
334
+ ).message(
335
+ [
336
+ displayError(error),
337
+ error instanceof Error && error.cause ? displayError(error.cause) : ""
338
+ ].filter(Boolean).join("\n\n")
339
+ ).exit("error");
340
+ }
341
+ logger.update("loader", 0, { content: "Download complete." });
342
+ logger.finish();
343
+ }
344
+
345
+ export {
346
+ IsolateDownloadError,
347
+ isDiskWriteError,
348
+ updateIsolate,
349
+ downloadIsolate
350
+ };