@scalar/cli 2.0.1 → 2.1.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 (80) hide show
  1. package/README.md +40 -0
  2. package/chunks/action-45OGQB2M.js +138 -0
  3. package/chunks/action-5R5FDF6S.js +2097 -0
  4. package/chunks/action-ANU5HGC4.js +34 -0
  5. package/chunks/action-BMFXENMX.js +176 -0
  6. package/chunks/action-BNEGJBUH.js +38 -0
  7. package/chunks/action-BYZUBXVB.js +82 -0
  8. package/chunks/action-C5VB4ITT.js +132 -0
  9. package/chunks/action-CCW66QJN.js +72 -0
  10. package/chunks/action-CLSD7O2R.js +60 -0
  11. package/chunks/action-CQ56FVES.js +65 -0
  12. package/chunks/action-CYP4VDK3.js +148 -0
  13. package/chunks/action-DFKHSDFV.js +36 -0
  14. package/chunks/action-F4Y6Q2VB.js +92 -0
  15. package/chunks/action-GB6DM53B.js +70 -0
  16. package/chunks/action-GEBRPNRT.js +87 -0
  17. package/chunks/action-H5OHT2GV.js +56 -0
  18. package/chunks/action-HD2T6BFJ.js +54 -0
  19. package/chunks/action-HNKM3Q65.js +65 -0
  20. package/chunks/action-JOSVV6YA.js +71 -0
  21. package/chunks/action-MENXFJH3.js +204 -0
  22. package/chunks/action-P7LN6FGY.js +13 -0
  23. package/chunks/action-PVDDRIM6.js +130 -0
  24. package/chunks/action-Q5UJ32D6.js +46 -0
  25. package/chunks/action-R6ZZO26F.js +299 -0
  26. package/chunks/action-STIEAXOE.js +53 -0
  27. package/chunks/action-TPBKPHNS.js +110 -0
  28. package/chunks/action-TWFJNQ2R.js +95 -0
  29. package/chunks/action-TZ5KGAQT.js +64 -0
  30. package/chunks/action-UDZUUJSI.js +49 -0
  31. package/chunks/action-W5BATF4Q.js +197 -0
  32. package/chunks/agent-XGLOHXNA.js +112 -0
  33. package/chunks/build.action-LKOILPA6.js +108 -0
  34. package/chunks/chunk-23I5PKZZ.js +78 -0
  35. package/chunks/chunk-2BSG2QHO.js +455 -0
  36. package/chunks/chunk-3MZYUBJ6.js +49 -0
  37. package/chunks/chunk-47Y4L5IT.js +63361 -0
  38. package/chunks/chunk-4DGQIAJX.js +359 -0
  39. package/chunks/chunk-4QS7SJTG.js +138 -0
  40. package/chunks/chunk-5BISXQX4.js +447 -0
  41. package/chunks/chunk-5BPPGTUU.js +463 -0
  42. package/chunks/chunk-AEFPCC4U.js +16 -0
  43. package/chunks/chunk-AHWWJ3MD.js +32 -0
  44. package/chunks/chunk-ASMHW5AY.js +19 -0
  45. package/chunks/chunk-B6QZJWCQ.js +92 -0
  46. package/chunks/chunk-DOVIWNKQ.js +108 -0
  47. package/chunks/chunk-H2WRMLYY.js +13780 -0
  48. package/chunks/chunk-HQKBZOYU.js +34 -0
  49. package/chunks/chunk-ISGLWBXZ.js +4265 -0
  50. package/chunks/chunk-IX7LJ3AD.js +17 -0
  51. package/chunks/chunk-JFIXNSPP.js +26 -0
  52. package/chunks/chunk-K74E42RV.js +7311 -0
  53. package/chunks/chunk-KHDYYVYF.js +16 -0
  54. package/chunks/chunk-KWOL7A6J.js +23 -0
  55. package/chunks/chunk-NUXPNUSS.js +38 -0
  56. package/chunks/chunk-OAXFCOJV.js +25 -0
  57. package/chunks/chunk-P2VH7DOC.js +107 -0
  58. package/chunks/chunk-P646T2WH.js +1608 -0
  59. package/chunks/chunk-SHSHFGA7.js +297 -0
  60. package/chunks/chunk-SXYALPYK.js +2709 -0
  61. package/chunks/chunk-T7B6WNZC.js +18 -0
  62. package/chunks/chunk-T7MDADON.js +17 -0
  63. package/chunks/chunk-TLFMATXR.js +344 -0
  64. package/chunks/chunk-TQ5XC2E3.js +284 -0
  65. package/chunks/chunk-UPUTMFD4.js +465 -0
  66. package/chunks/chunk-VTYTPSXO.js +161 -0
  67. package/chunks/chunk-X4QLDBB5.js +221 -0
  68. package/chunks/chunk-ZTVWAKNJ.js +21 -0
  69. package/chunks/create.action-FFQLBSJH.js +108 -0
  70. package/chunks/delete.action-QNN3LC2F.js +96 -0
  71. package/chunks/delete.action-STHQHP4F.js +88 -0
  72. package/chunks/get.action-OTKYOP3Z.js +87 -0
  73. package/chunks/list.action-6I5EZAVB.js +95 -0
  74. package/chunks/list.action-KDM5RHEH.js +116 -0
  75. package/chunks/publish.action-PODTVRXS.js +182 -0
  76. package/chunks/update.action-4F6STTEQ.js +101 -0
  77. package/chunks/update.action-KMD4ZM75.js +95 -0
  78. package/docs.html +310 -209
  79. package/index.js +645 -99061
  80. package/package.json +13 -11
@@ -0,0 +1,18 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+
3
+ // src/domains/project/resolve-project.ts
4
+ async function resolveProject(slug, apiClient) {
5
+ const githubResult = await apiClient.github.getProject(slug);
6
+ if (!githubResult.error) {
7
+ return { kind: "github", project: githubResult.data };
8
+ }
9
+ const docsResult = await apiClient.docsProject.getProject(slug);
10
+ if (!docsResult.error) {
11
+ return { kind: "docs", project: docsResult.data };
12
+ }
13
+ return { kind: "not-found" };
14
+ }
15
+
16
+ export {
17
+ resolveProject
18
+ };
@@ -0,0 +1,17 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+ import {
3
+ config
4
+ } from "./chunk-OAXFCOJV.js";
5
+
6
+ // src/domains/registry/helpers/links.ts
7
+ function registryUrl(path) {
8
+ return `${config.projects.registry}/${path}`;
9
+ }
10
+ function dashboardUrl(asset, uid) {
11
+ return `${config.projects.dashboard}/registry/${asset}/${uid}`;
12
+ }
13
+
14
+ export {
15
+ registryUrl,
16
+ dashboardUrl
17
+ };
@@ -0,0 +1,344 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+ import {
3
+ docVersionSchema,
4
+ namespaceSchema,
5
+ nanoidSchema,
6
+ slugSchema
7
+ } from "./chunk-ISGLWBXZ.js";
8
+ import {
9
+ external_exports,
10
+ zod_default
11
+ } from "./chunk-H2WRMLYY.js";
12
+
13
+ // ../../packages/entities/dist/agent/embed.js
14
+ var embedStatuses = ["pending", "success", "failed"];
15
+
16
+ // ../../packages/entities/dist/agent/docs.js
17
+ var docsProjectTypes = ["sync", "wysiwyg", "docs"];
18
+ var agentDocsProjectSchema = zod_default.object({
19
+ id: zod_default.string(),
20
+ uid: zod_default.string(),
21
+ name: zod_default.string(),
22
+ teamUid: zod_default.string(),
23
+ isPrivate: zod_default.boolean(),
24
+ type: zod_default.enum(docsProjectTypes),
25
+ activePublishId: zod_default.string().nullable(),
26
+ mcpServerId: zod_default.string().nullable(),
27
+ mcpInstallationId: zod_default.string().nullable(),
28
+ agentEnabled: zod_default.boolean(),
29
+ createdAt: zod_default.string(),
30
+ updatedAt: zod_default.string()
31
+ }).meta({ id: "agent-docs-project" });
32
+ var docsPublishSchema = zod_default.object({
33
+ id: zod_default.string(),
34
+ uid: zod_default.string(),
35
+ projectId: zod_default.string(),
36
+ domain: zod_default.string(),
37
+ embedStatus: zod_default.enum(embedStatuses),
38
+ createdAt: zod_default.string(),
39
+ updatedAt: zod_default.string()
40
+ }).meta({ id: "docs-publish" });
41
+ var docsPageSchema = zod_default.object({
42
+ id: zod_default.string(),
43
+ publishId: zod_default.string(),
44
+ title: zod_default.string(),
45
+ description: zod_default.string().nullable(),
46
+ to: zod_default.string(),
47
+ filepath: zod_default.string(),
48
+ contentHash: zod_default.string().nullable(),
49
+ searchToolEnabled: zod_default.boolean(),
50
+ executeRequestToolEnabled: zod_default.boolean(),
51
+ createdAt: zod_default.string()
52
+ }).meta({ id: "docs-page" });
53
+ var docsPageEmbeddingSchema = zod_default.object({
54
+ id: zod_default.string(),
55
+ pageId: zod_default.string(),
56
+ raw: zod_default.instanceof(Uint8Array),
57
+ embedding: zod_default.number().array(),
58
+ metadata: zod_default.record(zod_default.string(), zod_default.unknown()).nullable(),
59
+ createdAt: zod_default.string()
60
+ }).meta({ id: "docs-embedding" });
61
+
62
+ // ../../packages/entities/dist/agent/key.js
63
+ var agentKeySchema = zod_default.object({
64
+ id: zod_default.string(),
65
+ teamUid: zod_default.string(),
66
+ name: zod_default.string().max(50).default("My Agent Key"),
67
+ description: zod_default.string().max(200).default(""),
68
+ revoked: zod_default.boolean(),
69
+ expiresAt: zod_default.string(),
70
+ createdAt: zod_default.string(),
71
+ updatedAt: zod_default.string()
72
+ }).meta({ id: "agent-key" });
73
+ var agentTokenPayloadSchema = zod_default.object({
74
+ uid: zod_default.string(),
75
+ teamUid: nanoidSchema.optional(),
76
+ documentUids: nanoidSchema.array().optional(),
77
+ /** Ephemeral key minted for a registry API reference preview page. */
78
+ registryPreview: zod_default.boolean().optional(),
79
+ exp: zod_default.number().int()
80
+ }).meta({ id: "agent-token-payload" });
81
+ var SCALAR_AGENT_KEY_HEADER = "x-scalar-agent-key";
82
+
83
+ // ../../packages/entities/dist/agent/mcp.js
84
+ var mcpServerVersionChangeSources = [
85
+ "created",
86
+ "migration",
87
+ "user",
88
+ "docs-publish",
89
+ "track-latest",
90
+ "track-current",
91
+ "linked-resource-change"
92
+ ];
93
+ var mcpServerVersionStatuses = ["draft", "approved"];
94
+ var mcpDocumentTrackModes = [
95
+ "pinned",
96
+ "track-latest",
97
+ "track-current"
98
+ ];
99
+ var mcpDocsProjectTrackModes = [
100
+ "pinned",
101
+ "track-active-publish"
102
+ ];
103
+ var mcpServerToolModes = ["generic", "curated", "both"];
104
+ var mcpServerSchema = external_exports.object({
105
+ id: external_exports.string(),
106
+ teamUid: external_exports.string(),
107
+ name: external_exports.string(),
108
+ slug: slugSchema,
109
+ createdAt: external_exports.string(),
110
+ updatedAt: external_exports.string()
111
+ }).meta({ id: "mcp-server" });
112
+ var mcpServerVersionSchema = external_exports.object({
113
+ id: external_exports.string(),
114
+ mcpServerId: external_exports.string(),
115
+ semver: external_exports.string(),
116
+ parentVersionId: external_exports.string().nullable(),
117
+ changeSource: external_exports.enum(mcpServerVersionChangeSources),
118
+ changeNote: external_exports.string().nullable(),
119
+ newToolsSuggestionDismissed: external_exports.boolean(),
120
+ createdByUserId: external_exports.string().nullable(),
121
+ status: external_exports.enum(mcpServerVersionStatuses),
122
+ // Nullish input, null output: a dashboard bundle must keep parsing
123
+ // agent responses that predate these columns, whichever side deploys
124
+ // first — a missing key parses to null instead of failing.
125
+ approvalRequestedByUserId: external_exports.string().nullish().default(null),
126
+ approvalRequestedAt: external_exports.string().nullish().default(null),
127
+ approvedByUserId: external_exports.string().nullable(),
128
+ approvedAt: external_exports.string().nullable(),
129
+ createdAt: external_exports.string()
130
+ }).meta({ id: "mcp-server-version" });
131
+ var mcpServerOperationToolSchema = external_exports.object({
132
+ id: external_exports.string(),
133
+ mcpServerId: external_exports.string(),
134
+ mcpServerVersionId: external_exports.string(),
135
+ operationId: external_exports.string(),
136
+ searchToolEnabled: external_exports.boolean(),
137
+ executeRequestToolEnabled: external_exports.boolean(),
138
+ curatedToolEnabled: external_exports.boolean(),
139
+ name: external_exports.string().nullable(),
140
+ description: external_exports.string().nullable(),
141
+ createdAt: external_exports.string(),
142
+ updatedAt: external_exports.string()
143
+ }).meta({
144
+ id: "mcp-server-operation-tool"
145
+ });
146
+ var mcpServerDocsPageToolSchema = external_exports.object({
147
+ id: external_exports.string(),
148
+ mcpServerId: external_exports.string(),
149
+ mcpServerVersionId: external_exports.string(),
150
+ docsPageId: external_exports.string(),
151
+ searchToolEnabled: external_exports.boolean(),
152
+ executeRequestToolEnabled: external_exports.boolean(),
153
+ createdAt: external_exports.string(),
154
+ updatedAt: external_exports.string()
155
+ }).meta({
156
+ id: "mcp-server-docs-page-tool"
157
+ });
158
+ var mcpServerDocumentVersionSchema = external_exports.object({
159
+ id: external_exports.string(),
160
+ mcpServerId: external_exports.string(),
161
+ mcpServerVersionId: external_exports.string(),
162
+ versionId: external_exports.string(),
163
+ trackMode: external_exports.enum(mcpDocumentTrackModes),
164
+ toolMode: external_exports.enum(mcpServerToolModes),
165
+ createdAt: external_exports.string()
166
+ }).meta({
167
+ id: "mcp-server-document-version"
168
+ });
169
+ var mcpServerDocsPublishSchema = external_exports.object({
170
+ id: external_exports.string(),
171
+ mcpServerId: external_exports.string(),
172
+ mcpServerVersionId: external_exports.string(),
173
+ docsPublishId: external_exports.string(),
174
+ trackMode: external_exports.enum(mcpDocsProjectTrackModes),
175
+ createdAt: external_exports.string()
176
+ }).meta({
177
+ id: "mcp-server-docs-publish"
178
+ });
179
+ var mcpAuthModes = ["global", "passthrough"];
180
+ var PASSTHROUGH_NAME_REGEX = /^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$/;
181
+ var PASSTHROUGH_MAX_ENTRIES = 20;
182
+ var PASSTHROUGH_NAME_MAX_LENGTH = 128;
183
+ var PASSTHROUGH_HEADER_DENYLIST = [
184
+ "host",
185
+ "content-length",
186
+ "content-type",
187
+ "accept",
188
+ "accept-encoding",
189
+ "expect",
190
+ "connection",
191
+ "transfer-encoding",
192
+ "te",
193
+ "upgrade",
194
+ "trailer",
195
+ "keep-alive",
196
+ "proxy-authorization",
197
+ "proxy-authenticate",
198
+ "proxy-connection",
199
+ "mcp-session-id",
200
+ "mcp-protocol-version",
201
+ "x-scalar-agent-key",
202
+ "x-scalar-docs-agent-token",
203
+ "x-scalar-sdk-provider",
204
+ "forwarded",
205
+ "x-forwarded-for",
206
+ "x-forwarded-host",
207
+ "x-forwarded-proto"
208
+ ];
209
+ var passthroughAuthEntrySchema = external_exports.object({
210
+ in: external_exports.enum(["header", "query"]),
211
+ name: external_exports.string().min(1, "Name is required").max(PASSTHROUGH_NAME_MAX_LENGTH, "Name is too long").regex(PASSTHROUGH_NAME_REGEX, "Invalid character in name")
212
+ });
213
+ var passthroughAuthListSchema = external_exports.array(passthroughAuthEntrySchema).max(PASSTHROUGH_MAX_ENTRIES).superRefine((entries, ctx) => {
214
+ const seen = /* @__PURE__ */ new Set();
215
+ entries.forEach((entry, index) => {
216
+ const key = `${entry.in}:${entry.name.toLowerCase()}`;
217
+ if (seen.has(key))
218
+ ctx.addIssue({
219
+ code: "custom",
220
+ message: `"${entry.name}" is already in the list`,
221
+ path: [index, "name"]
222
+ });
223
+ seen.add(key);
224
+ if (entry.in === "header" && PASSTHROUGH_HEADER_DENYLIST.includes(entry.name.toLowerCase()))
225
+ ctx.addIssue({
226
+ code: "custom",
227
+ message: `The ${entry.name} header cannot be forwarded`,
228
+ path: [index, "name"]
229
+ });
230
+ });
231
+ });
232
+ var mcpVersionAuthSchema = external_exports.object({
233
+ mode: external_exports.enum(mcpAuthModes).default("global"),
234
+ passthrough: passthroughAuthListSchema.default([])
235
+ });
236
+ var mcpAuthConfigSchema = external_exports.record(external_exports.string(), mcpVersionAuthSchema);
237
+ var mcpInstallationSchema = external_exports.object({
238
+ id: external_exports.string(),
239
+ mcpServerId: external_exports.string(),
240
+ name: external_exports.string(),
241
+ slug: slugSchema,
242
+ documentAuth: external_exports.record(external_exports.string(), external_exports.unknown()),
243
+ isPrivate: external_exports.boolean(),
244
+ accessGroups: external_exports.array(external_exports.string()).default([]),
245
+ loginPortalUid: external_exports.string().nullable().default(null),
246
+ authConfig: mcpAuthConfigSchema.default({}),
247
+ mcpVersion: external_exports.string().nullable().default(null)
248
+ }).meta({ id: "mcp-installation" });
249
+
250
+ // ../../packages/entities/dist/agent/monthly-usage.js
251
+ var monthlyUsageSchema = zod_default.object({
252
+ identifier: zod_default.string(),
253
+ month: zod_default.date(),
254
+ type: zod_default.enum([
255
+ "public-user",
256
+ "web-team-user",
257
+ "agent-key",
258
+ "docs-project",
259
+ "mcp-installation",
260
+ "registry-preview"
261
+ ]),
262
+ teamUid: zod_default.string().nullable(),
263
+ inputTokens: zod_default.number(),
264
+ outputTokens: zod_default.number(),
265
+ messages: zod_default.number(),
266
+ toolCalls: zod_default.number(),
267
+ // bigint column: the pg driver returns int8 as a string, so coerce on read.
268
+ microCredits: zod_default.coerce.number()
269
+ }).meta({ id: "monthly-usage" });
270
+
271
+ // ../../node_modules/.pnpm/@scalar+helpers@0.9.2/node_modules/@scalar/helpers/dist/http/http-methods.js
272
+ var HTTP_METHODS = ["delete", "get", "head", "options", "patch", "post", "put", "trace"];
273
+ var httpMethods = Object.freeze(new Set(HTTP_METHODS));
274
+
275
+ // ../../packages/entities/dist/agent/operation.js
276
+ var methodSchema = zod_default.enum(HTTP_METHODS).meta({ id: "method" });
277
+ var operationSchema = zod_default.object({
278
+ id: zod_default.uuid(),
279
+ path: zod_default.string(),
280
+ method: methodSchema,
281
+ versionId: zod_default.uuid(),
282
+ embedding: zod_default.number().array(),
283
+ searchToolEnabled: zod_default.boolean(),
284
+ executeRequestToolEnabled: zod_default.boolean(),
285
+ operationId: zod_default.string().nullable(),
286
+ summary: zod_default.string().nullable(),
287
+ description: zod_default.string().nullable()
288
+ }).meta({ id: "operation" });
289
+
290
+ // ../../packages/entities/dist/agent/document.js
291
+ var documentSchema = zod_default.object({
292
+ id: zod_default.uuid(),
293
+ uid: nanoidSchema,
294
+ slug: slugSchema,
295
+ teamUid: nanoidSchema.nullable(),
296
+ namespace: namespaceSchema,
297
+ isPrivate: zod_default.boolean(),
298
+ title: zod_default.string(),
299
+ description: zod_default.string(),
300
+ logoUrl: zod_default.url().nullable(),
301
+ searchEnabled: zod_default.boolean(),
302
+ currentVersion: docVersionSchema,
303
+ latestVersion: docVersionSchema,
304
+ curated: zod_default.boolean(),
305
+ createdAt: zod_default.date(),
306
+ updatedAt: zod_default.date()
307
+ }).meta({ id: "document" });
308
+
309
+ // ../../packages/entities/dist/agent/key-documents.js
310
+ var keyDocumentSchema = zod_default.object({
311
+ keyId: zod_default.uuid(),
312
+ documentId: zod_default.uuid()
313
+ }).meta({ id: "key-documents" });
314
+
315
+ // ../../packages/entities/dist/agent/version.js
316
+ var versionSchema = zod_default.object({
317
+ id: zod_default.uuid(),
318
+ uid: nanoidSchema,
319
+ semver: docVersionSchema,
320
+ documentId: zod_default.uuid(),
321
+ raw: zod_default.instanceof(Uint8Array),
322
+ embedStatus: zod_default.enum(embedStatuses),
323
+ createdAt: zod_default.date(),
324
+ updatedAt: zod_default.date()
325
+ }).meta({ id: "version" });
326
+
327
+ export {
328
+ embedStatuses,
329
+ docsProjectTypes,
330
+ agentDocsProjectSchema,
331
+ agentKeySchema,
332
+ SCALAR_AGENT_KEY_HEADER,
333
+ mcpDocumentTrackModes,
334
+ mcpDocsProjectTrackModes,
335
+ mcpServerToolModes,
336
+ mcpServerSchema,
337
+ mcpServerVersionSchema,
338
+ mcpServerOperationToolSchema,
339
+ mcpServerDocsPageToolSchema,
340
+ mcpAuthConfigSchema,
341
+ mcpInstallationSchema,
342
+ monthlyUsageSchema,
343
+ methodSchema
344
+ };
@@ -0,0 +1,284 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+ import {
3
+ ISOLATE_DIR,
4
+ ISOLATE_EXTRACTION_DIR
5
+ } from "./chunk-KWOL7A6J.js";
6
+ import {
7
+ config
8
+ } from "./chunk-OAXFCOJV.js";
9
+ import {
10
+ output
11
+ } from "./chunk-X4QLDBB5.js";
12
+
13
+ // src/domains/project/download-isolate/action.ts
14
+ import { execFile } from "node:child_process";
15
+ import fs from "node:fs/promises";
16
+ import path from "node:path";
17
+ import { Readable } from "node:stream";
18
+ import { pipeline } from "node:stream/promises";
19
+ import { promisify } from "node:util";
20
+ import zlib from "node:zlib";
21
+ import { nanoid } from "nanoid";
22
+ import tar from "tar-fs";
23
+
24
+ // src/domains/project/download-isolate/helpers.ts
25
+ var PLATFORM_TARBALL_TARGETS = /* @__PURE__ */ new Set([
26
+ "darwin-arm64",
27
+ "darwin-x64",
28
+ "linux-arm64",
29
+ "linux-x64",
30
+ "win32-arm64",
31
+ "win32-x64"
32
+ ]);
33
+ function getIsolateDownloadUrls(options) {
34
+ const baseUrl = `${options.cdnUrl}/isolates/${options.version}-isolate`;
35
+ const universalUrl = `${baseUrl}.tar.gz`;
36
+ const target = `${options.platform}-${options.arch}`;
37
+ if (!PLATFORM_TARBALL_TARGETS.has(target)) return [universalUrl];
38
+ return [`${baseUrl}-${target}.tar.gz`, universalUrl];
39
+ }
40
+
41
+ // src/domains/project/download-isolate/action.ts
42
+ var execFileAsync = promisify(execFile);
43
+ var DOWNLOAD_TIMEOUT_MS = 10 * 60 * 1e3;
44
+ var EXTRACTION_ALLOWANCE_MS = 5 * 60 * 1e3;
45
+ async function getExistingIsolateVersion() {
46
+ try {
47
+ const packageJsonString = await fs.readFile(
48
+ path.join(ISOLATE_DIR, "package.json"),
49
+ "utf8"
50
+ );
51
+ const packageJson = JSON.parse(packageJsonString);
52
+ return packageJson.version;
53
+ } catch {
54
+ return void 0;
55
+ }
56
+ }
57
+ async function downloadWindowsIsolate(isolateUrl, destinationDir, timeoutMs) {
58
+ return new Promise((resolve, reject) => {
59
+ const timeoutSeconds = Math.ceil(timeoutMs / 1e3);
60
+ const psScript = `
61
+ $ErrorActionPreference = "Stop"
62
+
63
+ $targetDir = "${destinationDir}"
64
+ $tempFile = Join-Path $env:TEMP "scalar-isolate-download.tar.gz"
65
+
66
+ # Ensure target directory exists
67
+ New-Item -ItemType Directory -Force -Path $targetDir | Out-Null
68
+
69
+ # Download tarball. -TimeoutSec bounds the request so a stalled connection
70
+ # aborts instead of hanging indefinitely.
71
+ $ProgressPreference = 'SilentlyContinue'
72
+ Invoke-WebRequest -Uri "${isolateUrl}" -OutFile $tempFile -TimeoutSec ${timeoutSeconds}
73
+
74
+ # Extract (uses built-in tar on Windows)
75
+ tar -xzf $tempFile -C $targetDir
76
+
77
+ # Cleanup
78
+ Remove-Item $tempFile
79
+ `;
80
+ execFile(
81
+ "powershell.exe",
82
+ [
83
+ "-NoProfile",
84
+ "-NonInteractive",
85
+ "-ExecutionPolicy",
86
+ "Bypass",
87
+ "-Command",
88
+ psScript
89
+ ],
90
+ // Hard backstop: kill PowerShell if the whole run (download + extraction)
91
+ // overruns. `-TimeoutSec` only bounds the download, so the process budget
92
+ // adds an extraction allowance on top — a download that finishes near its
93
+ // own limit still has time to unpack, mirroring the unbounded extraction
94
+ // on Unix where the fetch timeout does not cover `tar`.
95
+ { windowsHide: true, timeout: timeoutMs + EXTRACTION_ALLOWANCE_MS },
96
+ (error, stdout, stderr) => {
97
+ if (error) {
98
+ error.stderr = stderr;
99
+ return reject(error);
100
+ }
101
+ resolve(stdout);
102
+ }
103
+ );
104
+ });
105
+ }
106
+ async function downloadAndExtract(url, destinationDir, options) {
107
+ if (process.platform === "win32") {
108
+ await downloadWindowsIsolate(url, destinationDir, options.timeoutMs);
109
+ return;
110
+ }
111
+ const response = await options.fetchImpl(url, {
112
+ signal: AbortSignal.timeout(options.timeoutMs)
113
+ });
114
+ if (!response.ok) {
115
+ throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
116
+ }
117
+ if (!response.body) {
118
+ throw new Error("Response had no body");
119
+ }
120
+ await pipeline(
121
+ Readable.fromWeb(response.body),
122
+ zlib.createGunzip(),
123
+ tar.extract(destinationDir)
124
+ );
125
+ }
126
+ async function assertIsolateLayout(destinationDir, url) {
127
+ try {
128
+ await fs.access(path.join(destinationDir, "isolate", "package.json"));
129
+ } catch {
130
+ throw new Error(
131
+ `The isolate tarball downloaded from ${url} did not contain an isolate directory.`
132
+ );
133
+ }
134
+ }
135
+ async function downloadFirstAvailable(urls, destinationDir, options) {
136
+ const failures = [];
137
+ for (const url of urls) {
138
+ try {
139
+ await fs.rm(destinationDir, { recursive: true, force: true });
140
+ await downloadAndExtract(url, destinationDir, options);
141
+ await assertIsolateLayout(destinationDir, url);
142
+ return url;
143
+ } catch (error) {
144
+ failures.push(
145
+ ` - ${url}: ${error instanceof Error ? error.message : String(error)}`
146
+ );
147
+ }
148
+ }
149
+ throw new Error(
150
+ `Failed to download the docs isolate. Attempted:
151
+ ${failures.join("\n")}
152
+ Your existing isolate (if any) was left untouched. Check your network connection and try again.`
153
+ );
154
+ }
155
+ async function removeQuarantineAttributes(isolateDir) {
156
+ if (process.platform !== "darwin") return;
157
+ try {
158
+ await execFileAsync("xattr", ["-dr", "com.apple.quarantine", isolateDir]);
159
+ } catch {
160
+ }
161
+ }
162
+ async function swapIsolateDirectory(newIsolateDir, isolateDir) {
163
+ const backupDir = `${isolateDir}.old-${nanoid()}`;
164
+ let hasBackup = false;
165
+ try {
166
+ await fs.rename(isolateDir, backupDir);
167
+ hasBackup = true;
168
+ } catch (error) {
169
+ const isMissing = error instanceof Error && error.code === "ENOENT";
170
+ if (!isMissing) throw error;
171
+ }
172
+ try {
173
+ await fs.rename(newIsolateDir, isolateDir);
174
+ } catch (error) {
175
+ if (hasBackup) {
176
+ try {
177
+ await fs.rename(backupDir, isolateDir);
178
+ } catch {
179
+ throw new Error(
180
+ `Failed to install the new isolate and could not restore the previous one. Your previous isolate is preserved at ${backupDir} \u2014 rename it back to ${isolateDir} to recover.`,
181
+ { cause: error }
182
+ );
183
+ }
184
+ }
185
+ throw error;
186
+ }
187
+ if (hasBackup) {
188
+ await fs.rm(backupDir, { recursive: true, force: true }).catch(() => {
189
+ });
190
+ }
191
+ }
192
+ async function removeDirectoriesWithPrefixes(extractionDir, prefixes, minAgeMs = 0) {
193
+ try {
194
+ const entries = await fs.readdir(extractionDir);
195
+ const now = Date.now();
196
+ const matches = entries.filter(
197
+ (entry) => prefixes.some((prefix) => entry.startsWith(prefix))
198
+ );
199
+ await Promise.all(
200
+ matches.map(async (entry) => {
201
+ const entryPath = path.join(extractionDir, entry);
202
+ if (minAgeMs > 0) {
203
+ try {
204
+ const { mtimeMs } = await fs.stat(entryPath);
205
+ if (now - mtimeMs < minAgeMs) return;
206
+ } catch {
207
+ return;
208
+ }
209
+ }
210
+ await fs.rm(entryPath, { recursive: true, force: true });
211
+ })
212
+ );
213
+ } catch {
214
+ }
215
+ }
216
+ var STALE_WORKING_DIR_AGE_MS = 10 * 60 * 1e3;
217
+ async function cleanupStaleWorkingDirectories(extractionDir) {
218
+ const prefixes = ["isolate.tmp-"];
219
+ try {
220
+ const hasLiveIsolate = (await fs.readdir(extractionDir)).includes("isolate");
221
+ if (hasLiveIsolate) prefixes.push("isolate.old-");
222
+ } catch {
223
+ }
224
+ await removeDirectoriesWithPrefixes(
225
+ extractionDir,
226
+ prefixes,
227
+ STALE_WORKING_DIR_AGE_MS
228
+ );
229
+ }
230
+ async function updateIsolate(options) {
231
+ const {
232
+ urls,
233
+ extractionDir,
234
+ fetchImpl = fetch,
235
+ timeoutMs = DOWNLOAD_TIMEOUT_MS
236
+ } = options;
237
+ const isolateDir = path.join(extractionDir, "isolate");
238
+ await fs.mkdir(extractionDir, { recursive: true });
239
+ await cleanupStaleWorkingDirectories(extractionDir);
240
+ const temporaryDir = path.join(extractionDir, `isolate.tmp-${nanoid()}`);
241
+ try {
242
+ const usedUrl = await downloadFirstAvailable(urls, temporaryDir, {
243
+ fetchImpl,
244
+ timeoutMs
245
+ });
246
+ const downloadedIsolateDir = path.join(temporaryDir, "isolate");
247
+ await removeQuarantineAttributes(downloadedIsolateDir);
248
+ await swapIsolateDirectory(downloadedIsolateDir, isolateDir);
249
+ await removeDirectoriesWithPrefixes(
250
+ extractionDir,
251
+ ["isolate.old-"],
252
+ STALE_WORKING_DIR_AGE_MS
253
+ );
254
+ return usedUrl;
255
+ } finally {
256
+ await fs.rm(temporaryDir, { recursive: true, force: true }).catch(() => {
257
+ });
258
+ }
259
+ }
260
+ async function downloadIsolate() {
261
+ const existingIsolateVersion = await getExistingIsolateVersion();
262
+ if (config.ssgDocsIsolateVersion === existingIsolateVersion) return;
263
+ const logger = output.info({ animate: true }).loader("Downloading docs isolate. This may take a minute...");
264
+ const urls = getIsolateDownloadUrls({
265
+ cdnUrl: config.cdnUrl,
266
+ version: config.ssgDocsIsolateVersion,
267
+ platform: process.platform,
268
+ arch: process.arch
269
+ });
270
+ try {
271
+ await updateIsolate({ urls, extractionDir: ISOLATE_EXTRACTION_DIR });
272
+ } catch (error) {
273
+ logger.update("loader", 0, { content: "Download failed." });
274
+ logger.finish();
275
+ throw error;
276
+ }
277
+ logger.update("loader", 0, { content: "Download complete." });
278
+ logger.finish();
279
+ }
280
+
281
+ export {
282
+ updateIsolate,
283
+ downloadIsolate
284
+ };