@scalar/cli 2.0.0 → 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 +42 -2
  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 +393 -230
  79. package/index.js +645 -98865
  80. package/package.json +16 -14
@@ -0,0 +1,447 @@
1
+ import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
2
+ import {
3
+ config
4
+ } from "./chunk-OAXFCOJV.js";
5
+ import {
6
+ roleSchema
7
+ } from "./chunk-4DGQIAJX.js";
8
+ import {
9
+ emailSchema,
10
+ entitySchema,
11
+ nanoidSchema,
12
+ timestampSchema
13
+ } from "./chunk-ISGLWBXZ.js";
14
+ import {
15
+ external_exports,
16
+ zod_default
17
+ } from "./chunk-H2WRMLYY.js";
18
+ import {
19
+ isUrl
20
+ } from "./chunk-IX7LJ3AD.js";
21
+ import {
22
+ output
23
+ } from "./chunk-X4QLDBB5.js";
24
+
25
+ // src/helpers/node-version.ts
26
+ import semver from "semver";
27
+ function checkNodeVersion() {
28
+ const currentVersion = process.version;
29
+ if (!semver.satisfies(currentVersion, ">=24")) {
30
+ output.error().title("Node.js version incompatible").message(
31
+ `Current Node.js version: ${currentVersion}
32
+ Minimum required version: ${">=24"}
33
+ Please upgrade your Node.js version and try again.
34
+ Visit https://nodejs.org to download the latest version.`
35
+ ).exit("error");
36
+ }
37
+ }
38
+
39
+ // ../../packages/entities/dist/token/token.js
40
+ var accessTokenPayloadSchema = external_exports.object({
41
+ userIndex: external_exports.string(),
42
+ userUid: external_exports.string().brand(),
43
+ // Brand only — `.brand()` keeps the runtime `z.string()` validation (no
44
+ // `.min()`), so parsed tokens stay byte-identical while gaining the Team brand.
45
+ teamUid: external_exports.string().brand(),
46
+ email: emailSchema.nullable(),
47
+ role: roleSchema.optional(),
48
+ exp: external_exports.number().int()
49
+ }).meta({ id: "access-token-payload" });
50
+ var healthTokenPayloadSchema = external_exports.object({
51
+ svc: external_exports.string().optional(),
52
+ iat: external_exports.number().int().optional(),
53
+ exp: external_exports.number().int()
54
+ }).meta({ id: "health-token-payload" });
55
+ var edgeCacheSyncTokenPayloadSchema = external_exports.object({
56
+ svc: external_exports.literal("watcher-edge-cache-sync"),
57
+ iat: external_exports.number().int().optional(),
58
+ exp: external_exports.number().int()
59
+ }).meta({
60
+ id: "edge-cache-sync-token-payload"
61
+ });
62
+ var refreshTokenPayloadSchema = external_exports.object({
63
+ uid: external_exports.string(),
64
+ teamUid: external_exports.string().nullable(),
65
+ type: external_exports.string(),
66
+ familyId: external_exports.string(),
67
+ userIndex: external_exports.string(),
68
+ exp: external_exports.number()
69
+ }).meta({ id: "refresh-token-payload" });
70
+ var personalTokenPayloadSchema = external_exports.object({
71
+ uid: external_exports.string(),
72
+ teamUid: external_exports.string(),
73
+ userIndex: external_exports.string(),
74
+ iat: external_exports.number(),
75
+ exp: external_exports.number()
76
+ }).meta({ id: "personal-token-payload" });
77
+ var exchangeTokenSchema = external_exports.object({
78
+ uid: external_exports.string(),
79
+ accessToken: external_exports.string(),
80
+ refreshToken: external_exports.string(),
81
+ expiry: external_exports.number(),
82
+ teamUid: external_exports.string()
83
+ }).meta({ id: "exchange-token" });
84
+ var socialOauthProviderSchema = external_exports.enum(["google", "microsoft"]).meta({ id: "social-oauth-provider" });
85
+ var hostingExchangeTokenSchema = external_exports.object({
86
+ email: emailSchema,
87
+ aud: external_exports.url(),
88
+ /** Identity provider uid, present when minted from a SAML assertion */
89
+ idp: nanoidSchema.optional(),
90
+ /**
91
+ * The social provider that authenticated the email, present only for
92
+ * OAuth logins. Absent means SAML, where the team's IdP is the authority.
93
+ * OAuth proves email ownership only, so the consumer must re-check the
94
+ * resource's email allowlists and that this provider is enabled before
95
+ * creating a session.
96
+ */
97
+ provider: socialOauthProviderSchema.optional(),
98
+ teamUid: nanoidSchema,
99
+ exp: external_exports.number()
100
+ }).meta({ id: "hosting-exchange-token" });
101
+ var hostingLoginTokenSchema = entitySchema.extend({
102
+ email: emailSchema,
103
+ host: external_exports.string(),
104
+ redirect: external_exports.string().optional(),
105
+ loginPortalUid: external_exports.string().optional(),
106
+ exp: timestampSchema
107
+ }).meta({ id: "hosting-login-token" });
108
+ var docsAgentTokenSchema = external_exports.object({
109
+ uid: external_exports.string(),
110
+ publishUid: external_exports.string(),
111
+ projectUid: external_exports.string(),
112
+ teamUid: external_exports.string(),
113
+ mcpServerId: external_exports.string(),
114
+ mcpInstallationId: external_exports.string(),
115
+ iat: external_exports.number(),
116
+ exp: external_exports.number()
117
+ }).meta({ id: "docs-agent-token" });
118
+
119
+ // ../../packages/entities/dist/token/payload.js
120
+ var tokenResponseSchema = external_exports.object({
121
+ refreshToken: external_exports.string(),
122
+ accessToken: external_exports.string()
123
+ }).meta({ id: "token-response" });
124
+
125
+ // ../../packages/entities/dist/token/refresh.js
126
+ var refreshTokenRecordSchema = external_exports.object({
127
+ uid: external_exports.string(),
128
+ /** Associate a refresh token with a team */
129
+ teamUid: external_exports.string().nullable(),
130
+ /** Token expiry in unix milliseconds */
131
+ expiry: external_exports.number().int(),
132
+ /** Tracks if a token has been used. No refresh token should be reused */
133
+ used: external_exports.boolean(),
134
+ /**
135
+ * When the token was consumed by a rotation, in unix milliseconds.
136
+ * Reuse within a short grace window after this moment is treated as a
137
+ * benign client race (parallel tabs); reuse after it revokes the family.
138
+ */
139
+ usedAt: external_exports.number().int().optional(),
140
+ /** family id is used to remove all tokens for a family in the event of a reuse */
141
+ familyId: external_exports.string(),
142
+ /** Unique lookup for the user */
143
+ userIndex: external_exports.string()
144
+ }).meta({ id: "refresh-token-record" });
145
+
146
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/runtime/base64url.js
147
+ import { Buffer as Buffer2 } from "node:buffer";
148
+
149
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/lib/buffer_utils.js
150
+ var encoder = new TextEncoder();
151
+ var decoder = new TextDecoder();
152
+ var MAX_INT32 = 2 ** 32;
153
+
154
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/runtime/base64url.js
155
+ function normalize(input) {
156
+ let encoded = input;
157
+ if (encoded instanceof Uint8Array) {
158
+ encoded = decoder.decode(encoded);
159
+ }
160
+ return encoded;
161
+ }
162
+ var decode = (input) => new Uint8Array(Buffer2.from(normalize(input), "base64url"));
163
+
164
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/util/errors.js
165
+ var JOSEError = class extends Error {
166
+ static code = "ERR_JOSE_GENERIC";
167
+ code = "ERR_JOSE_GENERIC";
168
+ constructor(message, options) {
169
+ super(message, options);
170
+ this.name = this.constructor.name;
171
+ Error.captureStackTrace?.(this, this.constructor);
172
+ }
173
+ };
174
+ var JWTInvalid = class extends JOSEError {
175
+ static code = "ERR_JWT_INVALID";
176
+ code = "ERR_JWT_INVALID";
177
+ };
178
+
179
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/lib/is_object.js
180
+ function isObjectLike(value) {
181
+ return typeof value === "object" && value !== null;
182
+ }
183
+ function isObject(input) {
184
+ if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
185
+ return false;
186
+ }
187
+ if (Object.getPrototypeOf(input) === null) {
188
+ return true;
189
+ }
190
+ let proto = input;
191
+ while (Object.getPrototypeOf(proto) !== null) {
192
+ proto = Object.getPrototypeOf(proto);
193
+ }
194
+ return Object.getPrototypeOf(input) === proto;
195
+ }
196
+
197
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/util/base64url.js
198
+ var decode2 = decode;
199
+
200
+ // ../../node_modules/.pnpm/jose@5.9.6/node_modules/jose/dist/node/esm/util/decode_jwt.js
201
+ function decodeJwt(jwt) {
202
+ if (typeof jwt !== "string")
203
+ throw new JWTInvalid("JWTs must use Compact JWS serialization, JWT must be a string");
204
+ const { 1: payload, length } = jwt.split(".");
205
+ if (length === 5)
206
+ throw new JWTInvalid("Only JWTs using Compact JWS serialization can be decoded");
207
+ if (length !== 3)
208
+ throw new JWTInvalid("Invalid JWT");
209
+ if (!payload)
210
+ throw new JWTInvalid("JWTs must contain a payload");
211
+ let decoded;
212
+ try {
213
+ decoded = decode2(payload);
214
+ } catch {
215
+ throw new JWTInvalid("Failed to base64url decode the payload");
216
+ }
217
+ let result;
218
+ try {
219
+ result = JSON.parse(decoder.decode(decoded));
220
+ } catch {
221
+ throw new JWTInvalid("Failed to parse the decoded payload as JSON");
222
+ }
223
+ if (!isObject(result))
224
+ throw new JWTInvalid("Invalid JWT Claims Set");
225
+ return result;
226
+ }
227
+
228
+ // ../../packages/tokens/dist/error.js
229
+ function TokenError(msg, code) {
230
+ const err = new Error(msg);
231
+ err.code = code;
232
+ return err;
233
+ }
234
+
235
+ // ../../packages/tokens/dist/index.js
236
+ function validatePayload(data, schema) {
237
+ const result = schema.safeParse(data);
238
+ if (!result.success) {
239
+ console.error("Invalid token payload:");
240
+ console.error(result.error.issues);
241
+ throw TokenError("Invalid token payload", "invalid-payload");
242
+ }
243
+ return result.data;
244
+ }
245
+ function decode3(token, schema = external_exports.any()) {
246
+ return validatePayload(decodeJwt(token), schema);
247
+ }
248
+
249
+ // src/helpers/metadata.ts
250
+ import fs from "node:fs/promises";
251
+ import os from "node:os";
252
+ import path from "node:path";
253
+ var SCALAR_METADATA_FILE_NAME = ".scalar-config";
254
+ var METADATA_FILE_PATH = path.join(
255
+ os.homedir(),
256
+ SCALAR_METADATA_FILE_NAME
257
+ );
258
+ var authSchema = external_exports.union([
259
+ external_exports.object({
260
+ accessToken: external_exports.string(),
261
+ refreshToken: external_exports.string()
262
+ }),
263
+ external_exports.object({
264
+ accessToken: external_exports.string(),
265
+ personalToken: external_exports.string()
266
+ })
267
+ ]);
268
+ var metadataSchema = external_exports.object({
269
+ lastUpdateCheck: external_exports.number(),
270
+ lastKnownVersion: external_exports.string(),
271
+ auth: authSchema.nullable().default(null)
272
+ });
273
+ var metadataCache = null;
274
+ var getMetadataMtimeMs = async () => (await fs.stat(METADATA_FILE_PATH).catch(() => null))?.mtimeMs ?? null;
275
+ var writeQueue = Promise.resolve();
276
+ var setMetadata = async (metadata) => {
277
+ const write = writeQueue.then(async () => {
278
+ const currentMetadata = await getMetadata();
279
+ const updatedMetadata = { ...currentMetadata, ...metadata };
280
+ const tmpPath = `${METADATA_FILE_PATH}.${process.pid}.tmp`;
281
+ await fs.writeFile(tmpPath, JSON.stringify(updatedMetadata));
282
+ await fs.rename(tmpPath, METADATA_FILE_PATH);
283
+ metadataCache = {
284
+ mtimeMs: await getMetadataMtimeMs(),
285
+ data: updatedMetadata
286
+ };
287
+ });
288
+ writeQueue = write.catch(() => {
289
+ });
290
+ return write;
291
+ };
292
+ var fileExists = async (path3) => !!await fs.stat(path3).catch(() => false);
293
+ var readMetadataFile = async () => {
294
+ const metadata = await fileExists(METADATA_FILE_PATH) ? await fs.readFile(METADATA_FILE_PATH, { encoding: "utf-8" }) : "{}";
295
+ try {
296
+ return metadataSchema.partial().parse(JSON.parse(metadata));
297
+ } catch {
298
+ return {};
299
+ }
300
+ };
301
+ var getMetadata = async () => {
302
+ const mtimeMs = await getMetadataMtimeMs();
303
+ if (metadataCache && metadataCache.mtimeMs === mtimeMs) {
304
+ return metadataCache.data;
305
+ }
306
+ const data = await readMetadataFile();
307
+ metadataCache = { mtimeMs, data };
308
+ return data;
309
+ };
310
+
311
+ // src/helpers/auth.ts
312
+ var eventListeners = [];
313
+ var addEventListener = (callback) => {
314
+ eventListeners.push(callback);
315
+ };
316
+ var fireCallbacks = (auth) => eventListeners.forEach((callback) => callback(auth));
317
+ var setAuthData = async (authData) => {
318
+ await setMetadata({ auth: authData });
319
+ fireCallbacks(authData);
320
+ };
321
+ var getAuthData = async (opts) => {
322
+ const { noExit } = opts ?? {};
323
+ const { auth } = await getMetadata();
324
+ if (!auth) {
325
+ if (noExit) throw new Error("Authorization required");
326
+ return output.error().title("Authorization required").message("Please login before running this command.").exit("error");
327
+ }
328
+ const { email, role, teamUid, exp } = decode3(
329
+ auth.accessToken,
330
+ accessTokenPayloadSchema
331
+ );
332
+ const isExpired = exp * 1e3 < Date.now();
333
+ if (!isExpired) {
334
+ return { ...auth, email, role, teamUid, addEventListener };
335
+ }
336
+ try {
337
+ if ("refreshToken" in auth) {
338
+ const updatedAuth2 = await refreshToken(auth.refreshToken);
339
+ return { ...updatedAuth2, email, role, teamUid, addEventListener };
340
+ }
341
+ const updatedAuth = await generateAccessByPersonalToken({
342
+ personalToken: auth.personalToken
343
+ });
344
+ return { ...updatedAuth, email, role, teamUid, addEventListener };
345
+ } catch {
346
+ if (noExit) throw new Error("Session expired, please login again.");
347
+ return output.error().title("Expired session").message("Session expired, please login again.").exit("error");
348
+ }
349
+ };
350
+ var clearAuthData = async () => {
351
+ await setMetadata({ auth: null });
352
+ };
353
+ var refreshTokenResponseSchema = zod_default.object({
354
+ accessToken: zod_default.string(),
355
+ refreshToken: zod_default.string()
356
+ });
357
+ var refreshToken = async (token, teamUid) => {
358
+ const result = await fetch(`${config.services.api}/core/login/refresh`, {
359
+ method: "POST",
360
+ headers: {
361
+ "Content-Type": "application/json"
362
+ },
363
+ credentials: "include",
364
+ body: JSON.stringify({
365
+ refreshToken: token,
366
+ teamUid
367
+ }),
368
+ // Fail fast instead of hanging every authed command on a slow network
369
+ signal: AbortSignal.timeout(1e4)
370
+ });
371
+ if (result.ok) {
372
+ const { accessToken, refreshToken: refreshToken2 } = refreshTokenResponseSchema.parse(
373
+ await result.json()
374
+ );
375
+ await setAuthData({ accessToken, refreshToken: refreshToken2 });
376
+ return { accessToken, refreshToken: refreshToken2 };
377
+ }
378
+ throw Error("Could not refresh token");
379
+ };
380
+
381
+ // src/helpers/watch-file.ts
382
+ import fs2 from "node:fs";
383
+ import path2 from "node:path";
384
+ import chokidar from "chokidar";
385
+ var watchFile = async (file, callback, options) => {
386
+ if (isUrl(file)) {
387
+ setInterval(callback, 5e3);
388
+ return;
389
+ }
390
+ const absoluteFilePath = path2.join(process.cwd(), file);
391
+ if (!fs2.existsSync(absoluteFilePath)) {
392
+ throw new Error(`File ${absoluteFilePath} does not exist`);
393
+ }
394
+ output.info().title(`Watch ${file}`).print();
395
+ const watcher = chokidar.watch(file, { persistent: true });
396
+ watcher.on("change", () => {
397
+ callback();
398
+ });
399
+ if (options?.immediate) {
400
+ callback();
401
+ }
402
+ return {
403
+ unsubscribe: () => watcher.close()
404
+ };
405
+ };
406
+
407
+ // src/domains/auth/login/helpers/personal-token-generate-access.ts
408
+ var generateAccessByPersonalToken = async ({
409
+ personalToken
410
+ }) => {
411
+ const result = await fetch(
412
+ `${config.services.api}/core/login/personal-token/access`,
413
+ {
414
+ method: "POST",
415
+ headers: {
416
+ "Content-Type": "application/json"
417
+ },
418
+ body: JSON.stringify({
419
+ personalToken
420
+ })
421
+ }
422
+ );
423
+ if (!result.ok) {
424
+ const data = await result.json();
425
+ throw new Error(
426
+ data.message ?? "Could not generate an access token from the provided personal token"
427
+ );
428
+ }
429
+ const { accessToken } = external_exports.object({ accessToken: external_exports.string() }).parse(await result.json());
430
+ await setAuthData({ accessToken, personalToken });
431
+ return { accessToken, personalToken };
432
+ };
433
+
434
+ export {
435
+ checkNodeVersion,
436
+ tokenResponseSchema,
437
+ accessTokenPayloadSchema,
438
+ decode3 as decode,
439
+ generateAccessByPersonalToken,
440
+ setMetadata,
441
+ getMetadata,
442
+ setAuthData,
443
+ getAuthData,
444
+ clearAuthData,
445
+ refreshToken,
446
+ watchFile
447
+ };