@picked/cli 0.0.85-next.4 → 0.0.85-next.5

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.
@@ -0,0 +1,839 @@
1
+ import { generate as e } from "@picked/typegen";
2
+ import { loadPickedConfig as t, loadResolvedPickedConfig as n, normalizeApiUrl as r, readActiveSelection as i, writeActiveSelection as a } from "@picked/config";
3
+ import { createServer as o } from "node:http";
4
+ import { spawn as s } from "node:child_process";
5
+ import { existsSync as c } from "node:fs";
6
+ import { chmod as l, mkdir as u, mkdtemp as d, readFile as f, readdir as p, rename as m, rm as h, rmdir as ee, writeFile as g } from "node:fs/promises";
7
+ import { basename as te, dirname as _, join as v, resolve as y, sep as b } from "node:path";
8
+ import { createHash as x, randomBytes as S } from "node:crypto";
9
+ import { homedir as ne } from "node:os";
10
+ import { AdminApiResponseError as re, AssetCommitDocument as ie, AssetDeleteDocument as ae, AssetUploadInitDocument as oe, ProjectLiveVersionDocument as se, WorkspaceExportDocument as ce, WorkspaceImportDocument as le, WorkspacePublishDocument as ue, createAdminApiClient as C, graphql as w } from "@picked/admin-api-client";
11
+ import { createInterface as de } from "node:readline";
12
+ //#region src/commands/generate-types.ts
13
+ async function T(t) {
14
+ let r = t?.cwd ?? process.cwd(), i = await n(r);
15
+ if (!i) return console.error("No picked.config.{ts,js,json} found in the current directory."), 1;
16
+ try {
17
+ let n = await e({
18
+ config: i,
19
+ check: t?.check ?? !1,
20
+ onWarn: (e) => {
21
+ console.warn(e);
22
+ }
23
+ });
24
+ return t?.check ? n.changed ? (console.error(`Types are out of date: ${n.typesOutput}`), 1) : (console.log(`Types are up to date (${n.typesOutput}).`), 0) : (console.log(`Generated types at ${n.typesOutput}`), 0);
25
+ } catch (e) {
26
+ let t = e instanceof Error ? e.message : String(e);
27
+ return console.error(t), 1;
28
+ }
29
+ }
30
+ //#endregion
31
+ //#region src/lib/browser.ts
32
+ function fe(e) {
33
+ return process.platform === "darwin" ? {
34
+ command: "open",
35
+ args: [e]
36
+ } : process.platform === "win32" ? {
37
+ command: "cmd",
38
+ args: [
39
+ "/c",
40
+ "start",
41
+ "\"\"",
42
+ e
43
+ ]
44
+ } : {
45
+ command: "xdg-open",
46
+ args: [e]
47
+ };
48
+ }
49
+ function pe(e) {
50
+ let { command: t, args: n } = fe(e);
51
+ try {
52
+ let e = s(t, n, {
53
+ detached: !0,
54
+ stdio: "ignore"
55
+ });
56
+ e.on("error", () => void 0), e.unref();
57
+ } catch {}
58
+ return Promise.resolve();
59
+ }
60
+ //#endregion
61
+ //#region src/lib/paths.ts
62
+ var me = 8;
63
+ function he() {
64
+ return v(ne(), ".picked");
65
+ }
66
+ function ge(e) {
67
+ let t = r(e), { hostname: n, port: i } = new URL(t);
68
+ return `${(i ? `${n}-${i}` : n).replace(/[^a-z0-9.-]/gi, "_")}-${x("sha256").update(t).digest("hex").slice(0, me)}`;
69
+ }
70
+ function E(e) {
71
+ return v(he(), "auth", `${ge(e)}.json`);
72
+ }
73
+ //#endregion
74
+ //#region src/auth/token-store.ts
75
+ var D = 384;
76
+ function _e(e) {
77
+ return typeof e == "object" && !!e && "clientId" in e && typeof e.clientId == "string" && "redirectUri" in e && typeof e.redirectUri == "string";
78
+ }
79
+ function ve(e) {
80
+ return !(typeof e != "object" || !e || !("accessToken" in e) || typeof e.accessToken != "string" || !("refreshToken" in e) || typeof e.refreshToken != "string" || !("expiresAt" in e) || typeof e.expiresAt != "number" || "user" in e && e.user !== void 0 && (typeof e.user != "object" || e.user === null));
81
+ }
82
+ function ye(e) {
83
+ return !(typeof e != "object" || !e || !("apiUrl" in e) || typeof e.apiUrl != "string" || "client" in e && e.client !== void 0 && !_e(e.client) || "session" in e && e.session !== void 0 && !ve(e.session));
84
+ }
85
+ async function O(e) {
86
+ let t = E(e);
87
+ if (!c(t)) return null;
88
+ try {
89
+ let e = JSON.parse(await f(t, "utf8"));
90
+ return ye(e) ? e : null;
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
95
+ async function be(e) {
96
+ let t = E(e.apiUrl);
97
+ await u(_(t), { recursive: !0 });
98
+ let n = `${t}.${process.pid.toString()}.tmp`;
99
+ await g(n, `${JSON.stringify(e, null, 2)}\n`, {
100
+ encoding: "utf8",
101
+ mode: D
102
+ }), await l(n, D), await m(n, t);
103
+ }
104
+ async function k(e, t) {
105
+ let n = await O(e);
106
+ await be({
107
+ apiUrl: r(e),
108
+ client: n?.client,
109
+ session: n?.session,
110
+ ...t
111
+ });
112
+ }
113
+ async function xe(e, t) {
114
+ await k(e, { client: t });
115
+ }
116
+ async function A(e, t) {
117
+ await k(e, { session: t });
118
+ }
119
+ async function Se(e) {
120
+ await h(E(e), { force: !0 });
121
+ }
122
+ //#endregion
123
+ //#region src/auth/pkce.ts
124
+ var Ce = 32, we = 16;
125
+ function j(e) {
126
+ return e.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
127
+ }
128
+ function Te() {
129
+ return j(S(Ce));
130
+ }
131
+ function Ee(e) {
132
+ return j(x("sha256").update(e).digest());
133
+ }
134
+ function De() {
135
+ return j(S(we));
136
+ }
137
+ //#endregion
138
+ //#region src/auth/oauth.ts
139
+ var M = [
140
+ 8976,
141
+ 8977,
142
+ 8988
143
+ ], Oe = 18e4, ke = "openid profile email";
144
+ async function N(e) {
145
+ let t;
146
+ try {
147
+ t = await fetch(`${e}/.well-known/oauth-authorization-server`);
148
+ } catch (e) {
149
+ let t = e instanceof Error ? e.message : String(e);
150
+ throw Error(`Failed to reach the Picked OAuth discovery endpoint: ${t}`);
151
+ }
152
+ if (!t.ok) throw Error(`OAuth discovery request failed (${t.status.toString()}).`);
153
+ let n = await t.json();
154
+ if (typeof n != "object" || !n) throw Error("Malformed OAuth discovery document.");
155
+ if (!("authorization_endpoint" in n) || typeof n.authorization_endpoint != "string") throw Error("OAuth discovery document is missing authorization_endpoint.");
156
+ if (!("token_endpoint" in n) || typeof n.token_endpoint != "string") throw Error("OAuth discovery document is missing token_endpoint.");
157
+ let r = "registration_endpoint" in n && typeof n.registration_endpoint == "string" ? n.registration_endpoint : void 0, i = "code_challenge_methods_supported" in n && Array.isArray(n.code_challenge_methods_supported) ? n.code_challenge_methods_supported.filter((e) => typeof e == "string") : void 0;
158
+ return {
159
+ authorizationEndpoint: n.authorization_endpoint,
160
+ tokenEndpoint: n.token_endpoint,
161
+ registrationEndpoint: r,
162
+ codeChallengeMethods: i
163
+ };
164
+ }
165
+ async function Ae(e, t, n) {
166
+ if (!t.registrationEndpoint) throw Error("OAuth client registration is not available for this Picked API.");
167
+ let r = await fetch(t.registrationEndpoint, {
168
+ method: "POST",
169
+ headers: { "content-type": "application/json" },
170
+ body: JSON.stringify({
171
+ client_name: "Picked CLI",
172
+ redirect_uris: [n],
173
+ grant_types: ["authorization_code", "refresh_token"],
174
+ response_types: ["code"],
175
+ token_endpoint_auth_method: "none"
176
+ })
177
+ });
178
+ if (!r.ok) throw Error(`OAuth client registration failed (${r.status.toString()}).`);
179
+ let i = await r.json();
180
+ if (typeof i != "object" || !i || !("client_id" in i) || typeof i.client_id != "string") throw Error("OAuth client registration returned an unexpected response.");
181
+ return await xe(e, {
182
+ clientId: i.client_id,
183
+ redirectUri: n
184
+ }), i.client_id;
185
+ }
186
+ async function je(e, t, n) {
187
+ let r = (await O(e))?.client;
188
+ return r?.redirectUri === n ? r.clientId : Ae(e, t, n);
189
+ }
190
+ function Me(e, t) {
191
+ return new Promise((n) => {
192
+ let r = () => {
193
+ e.removeListener("error", r), n(!1);
194
+ };
195
+ e.once("error", r), e.listen(t, "127.0.0.1", () => {
196
+ e.removeListener("error", r), n(!0);
197
+ });
198
+ });
199
+ }
200
+ async function Ne(e) {
201
+ for (let t of M) if (await Me(e, t)) return t;
202
+ throw Error(`No loopback port available for the OAuth callback (tried ${M.join(", ")}).`);
203
+ }
204
+ function Pe(e, t, n) {
205
+ return new Promise((r, i) => {
206
+ let a = () => {
207
+ clearTimeout(o), process.removeListener("SIGINT", s), e.close();
208
+ }, o = setTimeout(() => {
209
+ a(), i(/* @__PURE__ */ Error("Timed out waiting for the browser sign-in to complete."));
210
+ }, n), s = () => {
211
+ a(), i(/* @__PURE__ */ Error("Sign-in cancelled."));
212
+ };
213
+ process.once("SIGINT", s), e.on("request", (e, n) => {
214
+ let o = new URL(e.url ?? "/", "http://127.0.0.1");
215
+ if (o.pathname !== "/callback") {
216
+ n.writeHead(404), n.end();
217
+ return;
218
+ }
219
+ let s = o.searchParams.get("error");
220
+ if (s) {
221
+ n.writeHead(200, { "content-type": "text/html" }), n.end("<html><body>Sign-in failed. You can close this tab.</body></html>"), a(), i(/* @__PURE__ */ Error(`Authorization failed: ${s}`));
222
+ return;
223
+ }
224
+ let c = o.searchParams.get("code"), l = o.searchParams.get("state");
225
+ if (!c || l !== t) {
226
+ n.writeHead(400, { "content-type": "text/html" }), n.end("<html><body>Invalid sign-in response. Close this tab and try again.</body></html>"), a(), i(/* @__PURE__ */ Error("Invalid OAuth callback: missing code or state mismatch."));
227
+ return;
228
+ }
229
+ n.writeHead(200, { "content-type": "text/html" }), n.end("<html><body>Signed in. You can close this tab and return to the terminal.</body></html>"), a(), r({ code: c });
230
+ });
231
+ });
232
+ }
233
+ async function P(e) {
234
+ let t;
235
+ try {
236
+ t = await e.json();
237
+ } catch {
238
+ return null;
239
+ }
240
+ if (typeof t != "object" || !t || !("access_token" in t) || typeof t.access_token != "string" || !("expires_in" in t) || typeof t.expires_in != "number") return null;
241
+ let n = "refresh_token" in t && typeof t.refresh_token == "string" ? t.refresh_token : void 0;
242
+ return {
243
+ accessToken: t.access_token,
244
+ refreshToken: n,
245
+ expiresIn: t.expires_in
246
+ };
247
+ }
248
+ function Fe(e) {
249
+ let t = e.split("."), n = t[1];
250
+ if (t.length !== 3 || !n) return {};
251
+ try {
252
+ let e = JSON.parse(Buffer.from(n, "base64url").toString("utf8"));
253
+ return typeof e != "object" || !e ? {} : {
254
+ id: "sub" in e && typeof e.sub == "string" ? e.sub : void 0,
255
+ email: "email" in e && typeof e.email == "string" ? e.email : void 0
256
+ };
257
+ } catch {
258
+ return {};
259
+ }
260
+ }
261
+ async function Ie(e) {
262
+ let t = await N(e), n = o(), r = `http://127.0.0.1:${(await Ne(n)).toString()}/callback`, i = await je(e, t, r), a = Te(), s = Ee(a), c = De(), l = new URL(t.authorizationEndpoint);
263
+ l.searchParams.set("response_type", "code"), l.searchParams.set("client_id", i), l.searchParams.set("redirect_uri", r), l.searchParams.set("code_challenge", s), l.searchParams.set("code_challenge_method", "S256"), l.searchParams.set("state", c), l.searchParams.set("scope", ke), console.log(`Opening your browser to sign in...\n${l.toString()}`), await pe(l.toString());
264
+ let { code: u } = await Pe(n, c, Oe), d = new URLSearchParams({
265
+ grant_type: "authorization_code",
266
+ code: u,
267
+ redirect_uri: r,
268
+ client_id: i,
269
+ code_verifier: a
270
+ }), f = await fetch(t.tokenEndpoint, {
271
+ method: "POST",
272
+ headers: { "content-type": "application/x-www-form-urlencoded" },
273
+ body: d.toString()
274
+ });
275
+ if (!f.ok) throw Error(`Token exchange failed (${f.status.toString()}).`);
276
+ let p = await P(f);
277
+ if (!p?.refreshToken) throw Error("Token exchange did not return a refresh token.");
278
+ return {
279
+ accessToken: p.accessToken,
280
+ refreshToken: p.refreshToken,
281
+ expiresAt: Date.now() + p.expiresIn * 1e3,
282
+ user: Fe(p.accessToken)
283
+ };
284
+ }
285
+ async function Le(e) {
286
+ if (!e.client || !e.session) throw Error("Session expired. Run `picked login`.");
287
+ let t = await N(e.apiUrl), n = new URLSearchParams({
288
+ grant_type: "refresh_token",
289
+ refresh_token: e.session.refreshToken,
290
+ client_id: e.client.clientId
291
+ }), r;
292
+ try {
293
+ r = await fetch(t.tokenEndpoint, {
294
+ method: "POST",
295
+ headers: { "content-type": "application/x-www-form-urlencoded" },
296
+ body: n.toString()
297
+ });
298
+ } catch {
299
+ throw Error("Session expired. Run `picked login`.");
300
+ }
301
+ if (!r.ok) throw Error("Session expired. Run `picked login`.");
302
+ let i = await P(r);
303
+ if (!i) throw Error("Session expired. Run `picked login`.");
304
+ return {
305
+ accessToken: i.accessToken,
306
+ refreshToken: i.refreshToken ?? e.session.refreshToken,
307
+ expiresAt: Date.now() + i.expiresIn * 1e3,
308
+ user: e.session.user
309
+ };
310
+ }
311
+ //#endregion
312
+ //#region src/auth/session.ts
313
+ var Re = 6e4;
314
+ async function F(e) {
315
+ let t = await O(e);
316
+ if (!t?.session) throw Error(`Not logged in to ${e}. Run \`picked login\`.`);
317
+ if (t.session.expiresAt - Date.now() > Re) return t.session.accessToken;
318
+ let n = await Le(t);
319
+ return await A(e, n), n.accessToken;
320
+ }
321
+ //#endregion
322
+ //#region src/lib/admin-client.ts
323
+ function I() {
324
+ let e = process.env.PICKED_API_KEY?.trim();
325
+ return e === "" ? void 0 : e;
326
+ }
327
+ async function L(e) {
328
+ let t = I();
329
+ return t ? C({
330
+ apiUrl: e,
331
+ apiKey: t
332
+ }) : (await F(e), C({
333
+ apiUrl: e,
334
+ token: () => F(e)
335
+ }));
336
+ }
337
+ //#endregion
338
+ //#region src/lib/api-url.ts
339
+ var ze = "https://api.picked.app";
340
+ async function R(e = process.cwd()) {
341
+ let n = process.env.PICKED_API_URL;
342
+ if (n) return r(n);
343
+ let i = await t(e);
344
+ return r(i?.apiUrl ?? ze);
345
+ }
346
+ //#endregion
347
+ //#region src/commands/login.ts
348
+ async function Be(e) {
349
+ let t = await R(e?.cwd);
350
+ if (I()) return console.error(`\`picked login\` does not apply while PICKED_API_KEY is set: every command authenticates to ${t} with that API key. Unset PICKED_API_KEY to sign in as a user.`), 1;
351
+ try {
352
+ let e = await Ie(t);
353
+ await A(t, e);
354
+ let n = e.user?.email ?? e.user?.id ?? "unknown user";
355
+ return console.log(`Logged in as ${n} (${t})`), 0;
356
+ } catch (e) {
357
+ let t = e instanceof Error ? e.message : String(e);
358
+ return console.error(t), 1;
359
+ }
360
+ }
361
+ //#endregion
362
+ //#region src/commands/logout.ts
363
+ async function Ve(e) {
364
+ let t = await R(e?.cwd);
365
+ return await Se(t), console.log(`Logged out of ${t}.`), 0;
366
+ }
367
+ //#endregion
368
+ //#region src/commands/status.ts
369
+ async function He(e) {
370
+ let n = e?.cwd ?? process.cwd(), r = await t(n);
371
+ if (!r) return console.error("No picked.config.{ts,js,json} found in the current directory."), 1;
372
+ let a = await R(n);
373
+ console.log(`API: ${a}`), console.log(`Config default: project ${r.projectId} (source: ${r.source ?? "published"})`);
374
+ let o = await i(n, a);
375
+ if (!o) return console.log("Active selection: none (using the config default)."), 0;
376
+ if (!o.workspace) return console.log(`Active selection: live (published) in project ${o.projectId}`), 0;
377
+ let { name: s, status: c, source: l } = o.workspace;
378
+ return console.log(`Active selection: ${s} [${c}] in project ${o.projectId} (source: ${l})`), 0;
379
+ }
380
+ //#endregion
381
+ //#region src/commands/whoami.ts
382
+ async function Ue(e) {
383
+ let t = await R(e?.cwd);
384
+ if (I()) return console.error(`\`picked whoami\` does not apply while PICKED_API_KEY is set: an API key authenticates to ${t} as a project or organization, not as a user.`), 1;
385
+ let n = await O(t);
386
+ if (!n?.session) return console.error(`Not logged in to ${t}. Run \`picked login\`.`), 1;
387
+ let { user: r } = n.session, i = r?.email ?? r?.id ?? "unknown user";
388
+ return console.log(`${i} (${t})`), 0;
389
+ }
390
+ //#endregion
391
+ //#region src/lib/bundle.ts
392
+ var z = "bundle.json", B = "assets", We = /^[0-9a-f]{64}$/;
393
+ function V(e, t, n) {
394
+ let r = y(e), i = y(r, t);
395
+ if (!i.startsWith(r.endsWith(b) ? r : r + b)) throw Error(`${n} ${t} must name a directory inside ${r}.`);
396
+ return i;
397
+ }
398
+ function H(e) {
399
+ return typeof e == "object" && !!e && !Array.isArray(e);
400
+ }
401
+ function Ge(e) {
402
+ return x("sha256").update(e).digest("hex");
403
+ }
404
+ function U(e, t) {
405
+ return v(e, B, t);
406
+ }
407
+ function Ke(e, t) {
408
+ let n = `bundle assets[${String(t)}]`;
409
+ if (!H(e)) throw Error(`${n} is not an object.`);
410
+ let { versionId: r, fileName: i, mimeType: a, sizeBytes: o, sha256: s, downloadUrl: c } = e;
411
+ if (typeof r != "string" || typeof i != "string" || typeof a != "string" || typeof c != "string" || typeof o != "number" || !Number.isInteger(o) || o < 0) throw Error(`${n} needs a string versionId, fileName, mimeType and downloadUrl, and an integer sizeBytes.`);
412
+ if (s === null) return {
413
+ versionId: r,
414
+ fileName: i,
415
+ mimeType: a,
416
+ sizeBytes: o,
417
+ sha256: s,
418
+ downloadUrl: c
419
+ };
420
+ let l = typeof s == "string" ? s.toLowerCase() : "";
421
+ if (!We.test(l)) throw Error(`${n} (${i}) has a sha256 that is not a hex SHA-256 digest.`);
422
+ return {
423
+ versionId: r,
424
+ fileName: i,
425
+ mimeType: a,
426
+ sizeBytes: o,
427
+ sha256: l,
428
+ downloadUrl: c
429
+ };
430
+ }
431
+ function W(e) {
432
+ let { assets: t } = e;
433
+ if (!Array.isArray(t)) throw Error("The bundle has no assets array.");
434
+ return t.map((e, t) => Ke(e, t));
435
+ }
436
+ function G(e, t, n) {
437
+ if (t.byteLength !== e.sizeBytes) throw Error(`${e.fileName} (${n}) has size ${String(t.byteLength)} bytes; the manifest says ${String(e.sizeBytes)}.`);
438
+ let r = Ge(t);
439
+ if (e.sha256 !== null && r !== e.sha256) throw Error(`${e.fileName} (${n}) has SHA-256 ${r}; the manifest says ${e.sha256}.`);
440
+ return r;
441
+ }
442
+ function qe(e, t) {
443
+ let n = Array.isArray(e.assets) ? e.assets : [];
444
+ return {
445
+ ...e,
446
+ assets: n.map((e, n) => H(e) ? {
447
+ ...e,
448
+ sha256: t[n]
449
+ } : e)
450
+ };
451
+ }
452
+ //#endregion
453
+ //#region src/lib/workspace-transfer.ts
454
+ var Je = 12e4, Ye = 3e5, K = class extends Error {
455
+ name = "PayloadUserErrorsError";
456
+ };
457
+ function q(e, t) {
458
+ if (t.length !== 0) throw new K(`${e} failed:\n${t.map((e) => {
459
+ let t = e.field?.length ? ` (${e.field.join(".")})` : "";
460
+ return ` ${e.code}: ${e.message}${t}`;
461
+ }).join("\n")}`);
462
+ }
463
+ async function Xe(e, t) {
464
+ let { project: n } = await e.request(se, { input: { id: t } });
465
+ if (!n) throw Error(`Project ${t} was not found.`);
466
+ let r = n.liveWorkspaceVersion;
467
+ if (!r) throw Error(`Project ${t} has no published version.`);
468
+ if (!r.snapshotWorkspaceId) throw Error(`The live version ${r.id} of project ${t} has no snapshot workspace to export. Publish the project again.`);
469
+ return r.snapshotWorkspaceId;
470
+ }
471
+ async function Ze(e, t) {
472
+ let { workspaceExport: n } = await e.request(ce, { input: { workspaceId: t } });
473
+ if (q(`Export of workspace ${t}`, n.userErrors), !H(n.bundle)) throw Error(`Export of workspace ${t} returned no bundle.`);
474
+ return n.bundle;
475
+ }
476
+ async function Qe(e, t) {
477
+ let { projectId: n, fileName: r, mimeType: i, sha256: a, bytes: o } = t, { assetUploadInit: s } = await e.request(oe, { input: {
478
+ projectId: n,
479
+ fileName: r,
480
+ contentType: i,
481
+ sha256: a
482
+ } });
483
+ if (s.deduplicated) return {
484
+ assetId: s.assetId,
485
+ versionId: s.versionId,
486
+ deduplicated: !0
487
+ };
488
+ if (!s.uploadUrl) throw Error(`The API returned no upload URL for ${r}.`);
489
+ let c = await fetch(s.uploadUrl, {
490
+ method: "PUT",
491
+ headers: { "Content-Type": i },
492
+ body: o,
493
+ signal: AbortSignal.timeout(Je)
494
+ });
495
+ if (!c.ok) throw Error(`Upload of ${r} failed with status ${String(c.status)}: ${await c.text()}`);
496
+ let { assetCommit: l } = await e.request(ie, { input: {
497
+ projectId: n,
498
+ assetId: s.assetId,
499
+ versionId: s.versionId,
500
+ fileName: r,
501
+ storagePath: s.storagePath,
502
+ sha256: a
503
+ } });
504
+ return q(`Commit of ${r}`, l.userErrors), {
505
+ assetId: s.assetId,
506
+ versionId: s.versionId,
507
+ deduplicated: !1
508
+ };
509
+ }
510
+ async function $e(e, t) {
511
+ await e.request(ae, { input: { id: t } });
512
+ }
513
+ async function et(e, t) {
514
+ let { workspaceImport: n } = await e.request(le, { input: t }, { timeoutMs: Ye });
515
+ if (q(`Import into project ${t.projectId}`, n.userErrors), !n.workspace) throw Error(`Import into project ${t.projectId} returned no workspace.`);
516
+ return n.workspace;
517
+ }
518
+ async function tt(e, t) {
519
+ let { workspacePublish: n } = await e.request(ue, { input: { workspaceId: t } });
520
+ q(`Publish of workspace ${t}`, n.userErrors);
521
+ }
522
+ //#endregion
523
+ //#region src/commands/workspace-export.ts
524
+ var nt = 12e4;
525
+ function rt(e, t) {
526
+ if (!e.project) throw Error("Missing --project <id>.");
527
+ if (e.workspace && e.live) throw Error("Pass --workspace <id> or --live, not both.");
528
+ if (!e.workspace && !e.live) throw Error("Pass --workspace <id> or --live.");
529
+ if (!e.out) throw Error("Missing --out <dir>.");
530
+ return {
531
+ projectId: e.project,
532
+ workspaceId: e.workspace ?? null,
533
+ outDir: V(t, e.out, "--out")
534
+ };
535
+ }
536
+ async function it(e) {
537
+ if ((await p(e).catch((e) => {
538
+ if (H(e) && e.code === "ENOENT") return [];
539
+ throw e;
540
+ })).length > 0) throw Error(`${e} is not empty. Export into a new or empty directory.`);
541
+ }
542
+ async function at(e) {
543
+ let t = await fetch(e.downloadUrl, { signal: AbortSignal.timeout(nt) });
544
+ if (!t.ok) throw Error(`Download of ${e.fileName} from ${e.downloadUrl} failed with status ${String(t.status)}.`);
545
+ let n = new Uint8Array(await t.arrayBuffer());
546
+ return {
547
+ bytes: n,
548
+ sha256: G(e, n, e.downloadUrl)
549
+ };
550
+ }
551
+ async function ot(e, t, n) {
552
+ await u(v(e, B));
553
+ let r = [];
554
+ for (let t of n) {
555
+ let { bytes: n, sha256: i } = await at(t);
556
+ await g(U(e, i), n), r.push(i);
557
+ }
558
+ let i = qe(t, r);
559
+ await g(v(e, z), `${JSON.stringify(i, null, 2)}\n`);
560
+ }
561
+ async function st(e, t, n) {
562
+ await u(_(e), { recursive: !0 });
563
+ let r = await d(v(_(e), `.${te(e)}.partial-`));
564
+ try {
565
+ await ot(r, t, n), await ee(e).catch((e) => {
566
+ if (!(H(e) && e.code === "ENOENT")) throw e;
567
+ }), await m(r, e);
568
+ } catch (e) {
569
+ throw await h(r, {
570
+ recursive: !0,
571
+ force: !0
572
+ }), e;
573
+ }
574
+ }
575
+ async function ct(e, t) {
576
+ let n = t.workspaceId ?? await Xe(e, t.projectId), r = await Ze(e, n), i = H(r.source) ? r.source.projectId : void 0;
577
+ if (i !== t.projectId) throw Error(`Workspace ${n} belongs to project ${String(i)}, not ${t.projectId}.`);
578
+ return r;
579
+ }
580
+ async function lt(e) {
581
+ try {
582
+ let t = rt(e, e.cwd ?? process.cwd());
583
+ await it(t.outDir);
584
+ let n = await ct(await L(await R(e.cwd)), t), r = W(n);
585
+ await st(t.outDir, n, r);
586
+ let i = H(n.workspace) ? String(n.workspace.name) : "";
587
+ return console.log(`Exported workspace "${i}" with ${String(r.length)} assets to ${t.outDir}`), 0;
588
+ } catch (e) {
589
+ let t = e instanceof Error ? e.message : String(e);
590
+ return console.error(t), 1;
591
+ }
592
+ }
593
+ //#endregion
594
+ //#region src/commands/workspace-import.ts
595
+ async function ut(e) {
596
+ let t = v(e, z), n = await f(t, "utf8").catch((e) => {
597
+ throw Error(`Cannot read ${t}. Pass the directory \`picked workspace export\` wrote.`, { cause: e });
598
+ }), r = JSON.parse(n);
599
+ if (!H(r)) throw Error(`${t} is not a JSON object.`);
600
+ return r;
601
+ }
602
+ async function dt(e, t) {
603
+ let n = [];
604
+ for (let r of t) {
605
+ if (r.sha256 === null) throw Error(`The manifest item for ${r.fileName} has no SHA-256. Export the bundle with \`picked workspace export\`.`);
606
+ let t = U(e, r.sha256), i = new Uint8Array(await f(t));
607
+ n.push({
608
+ asset: r,
609
+ sha256: G(r, i, t),
610
+ bytes: i
611
+ });
612
+ }
613
+ return n;
614
+ }
615
+ async function ft(e, t, n, r) {
616
+ let i = [];
617
+ for (let { asset: a, sha256: o, bytes: s } of n) {
618
+ let n = await Qe(e, {
619
+ projectId: t,
620
+ fileName: a.fileName,
621
+ mimeType: a.mimeType,
622
+ sha256: o,
623
+ bytes: s
624
+ });
625
+ n.deduplicated || r.push(n.assetId), i.push({
626
+ sourceVersionId: a.versionId,
627
+ assetId: n.assetId,
628
+ versionId: n.versionId
629
+ });
630
+ }
631
+ return i;
632
+ }
633
+ async function J(e, t) {
634
+ let n = [], r = [];
635
+ for (let i of t) try {
636
+ await $e(e, i), n.push(i);
637
+ } catch (e) {
638
+ let t = e instanceof Error ? e.message : String(e);
639
+ r.push(`Could not delete asset ${i} (${t}); delete it from the project by hand.`);
640
+ }
641
+ return [...n.length > 0 ? [`Deleted the ${String(n.length)} asset${n.length === 1 ? "" : "s"} this run uploaded: ${n.join(", ")}.`] : [], ...r].join("\n");
642
+ }
643
+ function Y(e, t) {
644
+ let n = e instanceof Error ? e.message : String(e);
645
+ return Error(t ? `${n}\n${t}` : n, { cause: e });
646
+ }
647
+ function pt(e) {
648
+ let t = ["The outcome of the import is unknown: the API may have created the workspace. Check the project for it before you import again."];
649
+ return e.length > 0 && t.push(`Kept the ${String(e.length)} asset${e.length === 1 ? "" : "s"} this run uploaded: ${e.join(", ")}. If the project has no new workspace, delete them from the project.`), t.join("\n");
650
+ }
651
+ var mt = /* @__PURE__ */ new Set([
652
+ "FORBIDDEN",
653
+ "UNAUTHENTICATED",
654
+ "BAD_USER_INPUT",
655
+ "GRAPHQL_VALIDATION_FAILED"
656
+ ]);
657
+ function ht(e) {
658
+ return e instanceof K || e instanceof re && e.codes.length > 0 && e.codes.every((e) => e !== void 0 && mt.has(e));
659
+ }
660
+ async function gt(e, t) {
661
+ let n = [], r = await ft(e, t.projectId, t.assets, n).catch(async (t) => {
662
+ throw Y(t, await J(e, n));
663
+ });
664
+ return {
665
+ workspace: await et(e, {
666
+ projectId: t.projectId,
667
+ name: t.name,
668
+ bundle: t.bundle,
669
+ assetMap: r
670
+ }).catch(async (t) => {
671
+ throw Y(t, ht(t) ? await J(e, n) : pt(n));
672
+ }),
673
+ uploaded: n.length
674
+ };
675
+ }
676
+ async function _t(e) {
677
+ try {
678
+ if (!e.project) throw Error("Missing --project <id>.");
679
+ if (!e.in) throw Error("Missing --in <dir>.");
680
+ let t = e.project, n = V(e.cwd ?? process.cwd(), e.in, "--in"), r = await ut(n), i = await dt(n, W(r)), a = await L(await R(e.cwd)), { workspace: o, uploaded: s } = await gt(a, {
681
+ projectId: t,
682
+ name: e.name,
683
+ bundle: r,
684
+ assets: i
685
+ });
686
+ return console.log(`Imported workspace "${o.name}" as ${o.id} into project ${t} (assets: ${String(s)} uploaded, ${String(i.length - s)} already in the project).`), e.publish && (await tt(a, o.id).catch((e) => {
687
+ let t = e instanceof Error ? e.message : String(e);
688
+ throw Error(`Workspace ${o.id} was imported, but not published. ${t}`, { cause: e });
689
+ }), console.log(`Published workspace ${o.id}.`)), 0;
690
+ } catch (e) {
691
+ let t = e instanceof Error ? e.message : String(e);
692
+ return console.error(t), 1;
693
+ }
694
+ }
695
+ //#endregion
696
+ //#region src/lib/workspaces.ts
697
+ var vt = w("\n query PickedWorkspaces {\n user {\n organizations(first: 50) {\n edges {\n node {\n id\n name\n slug\n projects(first: 100) {\n edges {\n node {\n id\n name\n liveWorkspace {\n id\n }\n liveWorkspaceVersion {\n id\n }\n workspaces(first: 100) {\n edges {\n node {\n id\n name\n status\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"), yt = w("\n query PickedPreviewToken($id: ID!, $projectId: ID!) {\n workspace(id: $id, projectId: $projectId) {\n id\n name\n status\n previewToken\n }\n }\n");
698
+ async function X(e) {
699
+ let t = await e.request(vt, {});
700
+ if (!t.user) throw Error("Not signed in as a user, or no organizations are visible to this account. An API key has no organization list.");
701
+ return t.user.organizations.edges.map((e) => {
702
+ let t = e.node;
703
+ return {
704
+ id: t.id,
705
+ name: t.name,
706
+ slug: t.slug ?? "",
707
+ projects: t.projects.edges.map((e) => {
708
+ let t = e.node;
709
+ return {
710
+ id: t.id,
711
+ name: t.name,
712
+ liveWorkspaceId: t.liveWorkspace?.id ?? null,
713
+ liveVersionId: t.liveWorkspaceVersion?.id ?? null,
714
+ workspaces: t.workspaces.edges.map((e) => ({
715
+ id: e.node.id,
716
+ name: e.node.name,
717
+ status: e.node.status
718
+ }))
719
+ };
720
+ })
721
+ };
722
+ });
723
+ }
724
+ async function Z(e, t, n) {
725
+ let r = (await e.request(yt, {
726
+ id: n,
727
+ projectId: t
728
+ })).workspace;
729
+ if (!r) throw Error(`Workspace "${n}" was not found in project "${t}".`);
730
+ return {
731
+ status: r.status,
732
+ name: r.name,
733
+ previewToken: r.previewToken
734
+ };
735
+ }
736
+ //#endregion
737
+ //#region src/commands/workspace-list.ts
738
+ function bt(e) {
739
+ for (let t of e) {
740
+ console.log(`${t.name} (${t.slug})`);
741
+ for (let e of t.projects) {
742
+ console.log(` ${e.name} [${e.id}]`);
743
+ for (let t of e.workspaces) {
744
+ let n = t.status === "LIVE" || t.id === e.liveWorkspaceId ? " (live)" : "";
745
+ console.log(` ${t.name} [${t.status}]${n}`);
746
+ }
747
+ }
748
+ }
749
+ }
750
+ async function xt(e) {
751
+ try {
752
+ let t = await X(await L(await R(e?.cwd)));
753
+ return e?.json ? (console.log(JSON.stringify(t, null, 2)), 0) : (bt(t), 0);
754
+ } catch (e) {
755
+ let t = e instanceof Error ? e.message : String(e);
756
+ return console.error(t), 1;
757
+ }
758
+ }
759
+ //#endregion
760
+ //#region src/lib/prompt.ts
761
+ function St(e, t) {
762
+ return new Promise((n) => {
763
+ e.question(t, n);
764
+ });
765
+ }
766
+ async function Q(e, t) {
767
+ if (t.length === 0) throw Error("No choices available to select from.");
768
+ let n = de({
769
+ input: process.stdin,
770
+ output: process.stderr
771
+ });
772
+ process.stderr.write(`${e}\n`), t.forEach((e, t) => {
773
+ process.stderr.write(` ${(t + 1).toString()}. ${e.label}\n`);
774
+ });
775
+ try {
776
+ for (;;) {
777
+ let e = await St(n, `Enter a number (1-${t.length.toString()}): `), r = Number.parseInt(e, 10), i = Number.isInteger(r) ? t[r - 1] : void 0;
778
+ if (i) return i.value;
779
+ process.stderr.write("Invalid choice, try again.\n");
780
+ }
781
+ } finally {
782
+ n.close();
783
+ }
784
+ }
785
+ //#endregion
786
+ //#region src/commands/workspace-use.ts
787
+ function $(e, t, n) {
788
+ return {
789
+ projectId: e,
790
+ workspace: {
791
+ id: t,
792
+ name: n.name,
793
+ status: n.status,
794
+ source: "preview",
795
+ previewToken: n.previewToken
796
+ }
797
+ };
798
+ }
799
+ async function Ct(e, t, n) {
800
+ return n ? $(t, n, await Z(e, t, n)) : { projectId: t };
801
+ }
802
+ async function wt(e) {
803
+ let t = await Q("Select a project", (await X(e)).flatMap((e) => e.projects.map((t) => ({
804
+ label: `${e.name} / ${t.name}`,
805
+ value: t
806
+ })))), n = t.workspaces.map((e) => ({
807
+ label: `${e.name} [${e.status}]`,
808
+ value: e
809
+ }));
810
+ t.liveVersionId && n.unshift({
811
+ label: "Published (live version)",
812
+ value: null
813
+ });
814
+ let r = await Q("Select a workspace", n);
815
+ if (!r) return { projectId: t.id };
816
+ r.status === "ARCHIVED" && console.error("Warning: archived workspaces may fail to load via the delivery API.");
817
+ let i = await Z(e, t.id, r.id);
818
+ return $(t.id, r.id, i);
819
+ }
820
+ function Tt(e) {
821
+ if (!e.workspace) {
822
+ console.log(`Active workspace: live (published) in project ${e.projectId}`);
823
+ return;
824
+ }
825
+ let { name: t, status: n, source: r } = e.workspace;
826
+ console.log(`Active workspace: ${t} [${n}] in project ${e.projectId} (source: ${r})`);
827
+ }
828
+ async function Et(e) {
829
+ let t = e?.cwd ?? process.cwd();
830
+ try {
831
+ let n = await R(t), r = await L(n), i = e?.project ? await Ct(r, e.project, e.workspace) : await wt(r);
832
+ return await a(t, n, i), Tt(i), e?.generate !== !1 && await T({ cwd: t }), 0;
833
+ } catch (e) {
834
+ let t = e instanceof Error ? e.message : String(e);
835
+ return console.error(t), 1;
836
+ }
837
+ }
838
+ //#endregion
839
+ export { Ue as a, Be as c, lt as i, T as l, xt as n, He as o, _t as r, Ve as s, Et as t };