@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.
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@picked/cli",
3
3
  "description": "Picked command-line interface for local development workflows",
4
- "version": "0.0.85-next.4",
4
+ "version": "0.0.85-next.5",
5
5
  "bin": {
6
6
  "picked": "dist/esm/cli.js"
7
7
  },
8
8
  "dependencies": {
9
- "@picked/admin-api-client": "0.0.85-next.4",
10
- "@picked/config": "0.0.85-next.4",
11
- "@picked/telemetry": "0.0.85-next.4",
12
- "@picked/typegen": "0.0.85-next.4"
9
+ "@picked/admin-api-client": "0.0.85-next.5",
10
+ "@picked/config": "0.0.85-next.5",
11
+ "@picked/telemetry": "0.0.85-next.5",
12
+ "@picked/typegen": "0.0.85-next.5"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@repo/eslint-config": "workspace:*",
@@ -51,6 +51,7 @@
51
51
  "ignoreDependencies": [
52
52
  "@picked/admin-api-client",
53
53
  "@picked/config",
54
+ "@picked/telemetry",
54
55
  "@picked/typegen",
55
56
  "@repo/eslint-config",
56
57
  "@repo/typescript-config",
@@ -1,48 +0,0 @@
1
- let e=require("@picked/typegen"),t=require("@picked/config"),n=require("node:http"),r=require("node:child_process"),i=require("node:fs"),a=require("node:fs/promises"),o=require("node:path"),s=require("node:crypto"),c=require("node:os"),l=require("@picked/admin-api-client"),u=require("node:readline");async function d(n){let r=n?.cwd??process.cwd(),i=await(0,t.loadResolvedPickedConfig)(r);if(!i)return console.error(`No picked.config.{ts,js,json} found in the current directory.`),1;try{let t=await(0,e.generate)({config:i,check:n?.check??!1,onWarn:e=>{console.warn(e)}});return n?.check?t.changed?(console.error(`Types are out of date: ${t.typesOutput}`),1):(console.log(`Types are up to date (${t.typesOutput}).`),0):(console.log(`Generated types at ${t.typesOutput}`),0)}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(t),1}}function f(e){return process.platform===`darwin`?{command:`open`,args:[e]}:process.platform===`win32`?{command:`cmd`,args:[`/c`,`start`,`""`,e]}:{command:`xdg-open`,args:[e]}}function p(e){let{command:t,args:n}=f(e);try{let e=(0,r.spawn)(t,n,{detached:!0,stdio:`ignore`});e.on(`error`,()=>void 0),e.unref()}catch{}return Promise.resolve()}var m=8;function ee(){return(0,o.join)((0,c.homedir)(),`.picked`)}function h(e){let n=(0,t.normalizeApiUrl)(e),{hostname:r,port:i}=new URL(n);return`${(i?`${r}-${i}`:r).replace(/[^a-z0-9.-]/gi,`_`)}-${(0,s.createHash)(`sha256`).update(n).digest(`hex`).slice(0,m)}`}function g(e){return(0,o.join)(ee(),`auth`,`${h(e)}.json`)}var _=384;function v(e){return typeof e==`object`&&!!e&&`clientId`in e&&typeof e.clientId==`string`&&`redirectUri`in e&&typeof e.redirectUri==`string`}function y(e){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))}function b(e){return!(typeof e!=`object`||!e||!(`apiUrl`in e)||typeof e.apiUrl!=`string`||`client`in e&&e.client!==void 0&&!v(e.client)||`session`in e&&e.session!==void 0&&!y(e.session))}async function x(e){let t=g(e);if(!(0,i.existsSync)(t))return null;try{let e=JSON.parse(await(0,a.readFile)(t,`utf8`));return b(e)?e:null}catch{return null}}async function S(e){let t=g(e.apiUrl);await(0,a.mkdir)((0,o.dirname)(t),{recursive:!0});let n=`${t}.${process.pid.toString()}.tmp`;await(0,a.writeFile)(n,`${JSON.stringify(e,null,2)}\n`,{encoding:`utf8`,mode:_}),await(0,a.chmod)(n,_),await(0,a.rename)(n,t)}async function C(e,n){let r=await x(e);await S({apiUrl:(0,t.normalizeApiUrl)(e),client:r?.client,session:r?.session,...n})}async function te(e,t){await C(e,{client:t})}async function w(e,t){await C(e,{session:t})}async function ne(e){await(0,a.rm)(g(e),{force:!0})}var re=32,ie=16;function T(e){return e.toString(`base64`).replaceAll(`+`,`-`).replaceAll(`/`,`_`).replaceAll(`=`,``)}function E(){return T((0,s.randomBytes)(re))}function D(e){return T((0,s.createHash)(`sha256`).update(e).digest())}function O(){return T((0,s.randomBytes)(ie))}var k=[8976,8977,8988],A=18e4,j=`openid profile email`;async function M(e){let t;try{t=await fetch(`${e}/.well-known/oauth-authorization-server`)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Failed to reach the Picked OAuth discovery endpoint: ${t}`)}if(!t.ok)throw Error(`OAuth discovery request failed (${t.status.toString()}).`);let n=await t.json();if(typeof n!=`object`||!n)throw Error(`Malformed OAuth discovery document.`);if(!(`authorization_endpoint`in n)||typeof n.authorization_endpoint!=`string`)throw Error(`OAuth discovery document is missing authorization_endpoint.`);if(!(`token_endpoint`in n)||typeof n.token_endpoint!=`string`)throw Error(`OAuth discovery document is missing token_endpoint.`);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;return{authorizationEndpoint:n.authorization_endpoint,tokenEndpoint:n.token_endpoint,registrationEndpoint:r,codeChallengeMethods:i}}async function N(e,t,n){if(!t.registrationEndpoint)throw Error(`OAuth client registration is not available for this Picked API.`);let r=await fetch(t.registrationEndpoint,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({client_name:`Picked CLI`,redirect_uris:[n],grant_types:[`authorization_code`,`refresh_token`],response_types:[`code`],token_endpoint_auth_method:`none`})});if(!r.ok)throw Error(`OAuth client registration failed (${r.status.toString()}).`);let i=await r.json();if(typeof i!=`object`||!i||!(`client_id`in i)||typeof i.client_id!=`string`)throw Error(`OAuth client registration returned an unexpected response.`);return await te(e,{clientId:i.client_id,redirectUri:n}),i.client_id}async function P(e,t,n){let r=(await x(e))?.client;return r?.redirectUri===n?r.clientId:N(e,t,n)}function F(e,t){return new Promise(n=>{let r=()=>{e.removeListener(`error`,r),n(!1)};e.once(`error`,r),e.listen(t,`127.0.0.1`,()=>{e.removeListener(`error`,r),n(!0)})})}async function I(e){for(let t of k)if(await F(e,t))return t;throw Error(`No loopback port available for the OAuth callback (tried ${k.join(`, `)}).`)}function L(e,t,n){return new Promise((r,i)=>{let a=()=>{clearTimeout(o),process.removeListener(`SIGINT`,s),e.close()},o=setTimeout(()=>{a(),i(Error(`Timed out waiting for the browser sign-in to complete.`))},n),s=()=>{a(),i(Error(`Sign-in cancelled.`))};process.once(`SIGINT`,s),e.on(`request`,(e,n)=>{let o=new URL(e.url??`/`,`http://127.0.0.1`);if(o.pathname!==`/callback`){n.writeHead(404),n.end();return}let s=o.searchParams.get(`error`);if(s){n.writeHead(200,{"content-type":`text/html`}),n.end(`<html><body>Sign-in failed. You can close this tab.</body></html>`),a(),i(Error(`Authorization failed: ${s}`));return}let c=o.searchParams.get(`code`),l=o.searchParams.get(`state`);if(!c||l!==t){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(Error(`Invalid OAuth callback: missing code or state mismatch.`));return}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})})})}async function R(e){let t;try{t=await e.json()}catch{return null}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;let n=`refresh_token`in t&&typeof t.refresh_token==`string`?t.refresh_token:void 0;return{accessToken:t.access_token,refreshToken:n,expiresIn:t.expires_in}}function z(e){let t=e.split(`.`),n=t[1];if(t.length!==3||!n)return{};try{let e=JSON.parse(Buffer.from(n,`base64url`).toString(`utf8`));return typeof e!=`object`||!e?{}:{id:`sub`in e&&typeof e.sub==`string`?e.sub:void 0,email:`email`in e&&typeof e.email==`string`?e.email:void 0}}catch{return{}}}async function B(e){let t=await M(e),r=(0,n.createServer)(),i=`http://127.0.0.1:${(await I(r)).toString()}/callback`,a=await P(e,t,i),o=E(),s=D(o),c=O(),l=new URL(t.authorizationEndpoint);l.searchParams.set(`response_type`,`code`),l.searchParams.set(`client_id`,a),l.searchParams.set(`redirect_uri`,i),l.searchParams.set(`code_challenge`,s),l.searchParams.set(`code_challenge_method`,`S256`),l.searchParams.set(`state`,c),l.searchParams.set(`scope`,j),console.log(`Opening your browser to sign in...\n${l.toString()}`),await p(l.toString());let{code:u}=await L(r,c,A),d=new URLSearchParams({grant_type:`authorization_code`,code:u,redirect_uri:i,client_id:a,code_verifier:o}),f=await fetch(t.tokenEndpoint,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:d.toString()});if(!f.ok)throw Error(`Token exchange failed (${f.status.toString()}).`);let m=await R(f);if(!m?.refreshToken)throw Error(`Token exchange did not return a refresh token.`);return{accessToken:m.accessToken,refreshToken:m.refreshToken,expiresAt:Date.now()+m.expiresIn*1e3,user:z(m.accessToken)}}async function ae(e){if(!e.client||!e.session)throw Error("Session expired. Run `picked login`.");let t=await M(e.apiUrl),n=new URLSearchParams({grant_type:`refresh_token`,refresh_token:e.session.refreshToken,client_id:e.client.clientId}),r;try{r=await fetch(t.tokenEndpoint,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:n.toString()})}catch{throw Error("Session expired. Run `picked login`.")}if(!r.ok)throw Error("Session expired. Run `picked login`.");let i=await R(r);if(!i)throw Error("Session expired. Run `picked login`.");return{accessToken:i.accessToken,refreshToken:i.refreshToken??e.session.refreshToken,expiresAt:Date.now()+i.expiresIn*1e3,user:e.session.user}}var V=`https://api.picked.app`;async function H(e=process.cwd()){let n=process.env.PICKED_API_URL;if(n)return(0,t.normalizeApiUrl)(n);let r=await(0,t.loadPickedConfig)(e);return(0,t.normalizeApiUrl)(r?.apiUrl??V)}async function U(e){let t=await H(e?.cwd);try{let e=await B(t);await w(t,e);let n=e.user?.email??e.user?.id??`unknown user`;return console.log(`Logged in as ${n} (${t})`),0}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(t),1}}async function W(e){let t=await H(e?.cwd);return await ne(t),console.log(`Logged out of ${t}.`),0}async function G(e){let n=e?.cwd??process.cwd(),r=await(0,t.loadPickedConfig)(n);if(!r)return console.error(`No picked.config.{ts,js,json} found in the current directory.`),1;let i=await H(n);console.log(`API: ${i}`),console.log(`Config default: project ${r.projectId} (source: ${r.source??`published`})`);let a=await(0,t.readActiveSelection)(n,i);if(!a)return console.log(`Active selection: none (using the config default).`),0;if(!a.workspace)return console.log(`Active selection: live (published) in project ${a.projectId}`),0;let{name:o,status:s,source:c}=a.workspace;return console.log(`Active selection: ${o} [${s}] in project ${a.projectId} (source: ${c})`),0}async function K(e){let t=await H(e?.cwd),n=await x(t);if(!n?.session)return console.error(`Not logged in to ${t}. Run \`picked login\`.`),1;let{user:r}=n.session,i=r?.email??r?.id??`unknown user`;return console.log(`${i} (${t})`),0}var q=6e4;async function J(e){let t=await x(e);if(!t?.session)throw Error(`Not logged in to ${e}. Run \`picked login\`.`);if(t.session.expiresAt-Date.now()>q)return t.session.accessToken;let n=await ae(t);return await w(e,n),n.accessToken}var oe=(0,l.graphql)(`
2
- query PickedWorkspaces {
3
- user {
4
- organizations(first: 50) {
5
- edges {
6
- node {
7
- id
8
- name
9
- slug
10
- projects(first: 100) {
11
- edges {
12
- node {
13
- id
14
- name
15
- liveWorkspace {
16
- id
17
- }
18
- liveWorkspaceVersion {
19
- id
20
- }
21
- workspaces(first: 100) {
22
- edges {
23
- node {
24
- id
25
- name
26
- status
27
- }
28
- }
29
- }
30
- }
31
- }
32
- }
33
- }
34
- }
35
- }
36
- }
37
- }
38
- `),se=(0,l.graphql)(`
39
- query PickedPreviewToken($id: ID!, $projectId: ID!) {
40
- workspace(id: $id, projectId: $projectId) {
41
- id
42
- name
43
- status
44
- previewToken
45
- }
46
- }
47
- `);async function Y(e,t){let n=await(0,l.createAdminApiClient)({apiUrl:e,token:t}).request(oe,{});if(!n.user)throw Error(`Not authenticated, or no organizations are visible to this account.`);return n.user.organizations.edges.map(e=>{let t=e.node;return{id:t.id,name:t.name,slug:t.slug??``,projects:t.projects.edges.map(e=>{let t=e.node;return{id:t.id,name:t.name,liveWorkspaceId:t.liveWorkspace?.id??null,liveVersionId:t.liveWorkspaceVersion?.id??null,workspaces:t.workspaces.edges.map(e=>({id:e.node.id,name:e.node.name,status:e.node.status}))}})}})}async function X(e,t,n,r){let i=(await(0,l.createAdminApiClient)({apiUrl:e,token:t}).request(se,{id:r,projectId:n})).workspace;if(!i)throw Error(`Workspace "${r}" was not found in project "${n}".`);return{status:i.status,name:i.name,previewToken:i.previewToken}}function ce(e){for(let t of e){console.log(`${t.name} (${t.slug})`);for(let e of t.projects){console.log(` ${e.name} [${e.id}]`);for(let t of e.workspaces){let n=t.status===`LIVE`||t.id===e.liveWorkspaceId?` (live)`:``;console.log(` ${t.name} [${t.status}]${n}`)}}}}async function Z(e){try{let t=await H(e?.cwd),n=await Y(t,await J(t));return e?.json?(console.log(JSON.stringify(n,null,2)),0):(ce(n),0)}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(t),1}}function le(e,t){return new Promise(n=>{e.question(t,n)})}async function Q(e,t){if(t.length===0)throw Error(`No choices available to select from.`);let n=(0,u.createInterface)({input:process.stdin,output:process.stderr});process.stderr.write(`${e}\n`),t.forEach((e,t)=>{process.stderr.write(` ${(t+1).toString()}. ${e.label}\n`)});try{for(;;){let e=await le(n,`Enter a number (1-${t.length.toString()}): `),r=Number.parseInt(e,10),i=Number.isInteger(r)?t[r-1]:void 0;if(i)return i.value;process.stderr.write(`Invalid choice, try again.
48
- `)}}finally{n.close()}}function $(e,t,n){return{projectId:e,workspace:{id:t,name:n.name,status:n.status,source:`preview`,previewToken:n.previewToken}}}async function ue(e,t,n,r){return r?$(n,r,await X(e,t,n,r)):{projectId:n}}async function de(e,t){let n=await Q(`Select a project`,(await Y(e,t)).flatMap(e=>e.projects.map(t=>({label:`${e.name} / ${t.name}`,value:t})))),r=n.workspaces.map(e=>({label:`${e.name} [${e.status}]`,value:e}));n.liveVersionId&&r.unshift({label:`Published (live version)`,value:null});let i=await Q(`Select a workspace`,r);if(!i)return{projectId:n.id};i.status===`ARCHIVED`&&console.error(`Warning: archived workspaces may fail to load via the delivery API.`);let a=await X(e,t,n.id,i.id);return $(n.id,i.id,a)}function fe(e){if(!e.workspace){console.log(`Active workspace: live (published) in project ${e.projectId}`);return}let{name:t,status:n,source:r}=e.workspace;console.log(`Active workspace: ${t} [${n}] in project ${e.projectId} (source: ${r})`)}async function pe(e){let n=e?.cwd??process.cwd();try{let r=await H(n),i=await J(r),a=e?.project?await ue(r,i,e.project,e.workspace):await de(r,i);return await(0,t.writeActiveSelection)(n,r,a),fe(a),e?.generate!==!1&&await d({cwd:n}),0}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(t),1}}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return G}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return Z}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return U}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return pe}});
@@ -1,521 +0,0 @@
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, readFile as d, rename as f, rm as p, writeFile as m } from "node:fs/promises";
7
- import { dirname as ee, join as h } from "node:path";
8
- import { createHash as g, randomBytes as _ } from "node:crypto";
9
- import { homedir as te } from "node:os";
10
- import { createAdminApiClient as v, graphql as y } from "@picked/admin-api-client";
11
- import { createInterface as b } from "node:readline";
12
- //#region src/commands/generate-types.ts
13
- async function x(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 ne(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 re(e) {
50
- let { command: t, args: n } = ne(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 S = 8;
63
- function C() {
64
- return h(te(), ".picked");
65
- }
66
- function w(e) {
67
- let t = r(e), { hostname: n, port: i } = new URL(t);
68
- return `${(i ? `${n}-${i}` : n).replace(/[^a-z0-9.-]/gi, "_")}-${g("sha256").update(t).digest("hex").slice(0, S)}`;
69
- }
70
- function T(e) {
71
- return h(C(), "auth", `${w(e)}.json`);
72
- }
73
- //#endregion
74
- //#region src/auth/token-store.ts
75
- var E = 384;
76
- function ie(e) {
77
- return typeof e == "object" && !!e && "clientId" in e && typeof e.clientId == "string" && "redirectUri" in e && typeof e.redirectUri == "string";
78
- }
79
- function ae(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 oe(e) {
83
- return !(typeof e != "object" || !e || !("apiUrl" in e) || typeof e.apiUrl != "string" || "client" in e && e.client !== void 0 && !ie(e.client) || "session" in e && e.session !== void 0 && !ae(e.session));
84
- }
85
- async function D(e) {
86
- let t = T(e);
87
- if (!c(t)) return null;
88
- try {
89
- let e = JSON.parse(await d(t, "utf8"));
90
- return oe(e) ? e : null;
91
- } catch {
92
- return null;
93
- }
94
- }
95
- async function se(e) {
96
- let t = T(e.apiUrl);
97
- await u(ee(t), { recursive: !0 });
98
- let n = `${t}.${process.pid.toString()}.tmp`;
99
- await m(n, `${JSON.stringify(e, null, 2)}\n`, {
100
- encoding: "utf8",
101
- mode: E
102
- }), await l(n, E), await f(n, t);
103
- }
104
- async function O(e, t) {
105
- let n = await D(e);
106
- await se({
107
- apiUrl: r(e),
108
- client: n?.client,
109
- session: n?.session,
110
- ...t
111
- });
112
- }
113
- async function k(e, t) {
114
- await O(e, { client: t });
115
- }
116
- async function A(e, t) {
117
- await O(e, { session: t });
118
- }
119
- async function j(e) {
120
- await p(T(e), { force: !0 });
121
- }
122
- //#endregion
123
- //#region src/auth/pkce.ts
124
- var M = 32, N = 16;
125
- function P(e) {
126
- return e.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
127
- }
128
- function F() {
129
- return P(_(M));
130
- }
131
- function I(e) {
132
- return P(g("sha256").update(e).digest());
133
- }
134
- function L() {
135
- return P(_(N));
136
- }
137
- //#endregion
138
- //#region src/auth/oauth.ts
139
- var R = [
140
- 8976,
141
- 8977,
142
- 8988
143
- ], z = 18e4, B = "openid profile email";
144
- async function V(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 H(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 k(e, {
182
- clientId: i.client_id,
183
- redirectUri: n
184
- }), i.client_id;
185
- }
186
- async function U(e, t, n) {
187
- let r = (await D(e))?.client;
188
- return r?.redirectUri === n ? r.clientId : H(e, t, n);
189
- }
190
- function W(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 G(e) {
201
- for (let t of R) if (await W(e, t)) return t;
202
- throw Error(`No loopback port available for the OAuth callback (tried ${R.join(", ")}).`);
203
- }
204
- function K(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 q(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 ce(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 le(e) {
262
- let t = await V(e), n = o(), r = `http://127.0.0.1:${(await G(n)).toString()}/callback`, i = await U(e, t, r), a = F(), s = I(a), c = L(), 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", B), console.log(`Opening your browser to sign in...\n${l.toString()}`), await re(l.toString());
264
- let { code: u } = await K(n, c, z), 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 q(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: ce(p.accessToken)
283
- };
284
- }
285
- async function ue(e) {
286
- if (!e.client || !e.session) throw Error("Session expired. Run `picked login`.");
287
- let t = await V(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 q(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/lib/api-url.ts
313
- var de = "https://api.picked.app";
314
- async function J(e = process.cwd()) {
315
- let n = process.env.PICKED_API_URL;
316
- if (n) return r(n);
317
- let i = await t(e);
318
- return r(i?.apiUrl ?? de);
319
- }
320
- //#endregion
321
- //#region src/commands/login.ts
322
- async function fe(e) {
323
- let t = await J(e?.cwd);
324
- try {
325
- let e = await le(t);
326
- await A(t, e);
327
- let n = e.user?.email ?? e.user?.id ?? "unknown user";
328
- return console.log(`Logged in as ${n} (${t})`), 0;
329
- } catch (e) {
330
- let t = e instanceof Error ? e.message : String(e);
331
- return console.error(t), 1;
332
- }
333
- }
334
- //#endregion
335
- //#region src/commands/logout.ts
336
- async function pe(e) {
337
- let t = await J(e?.cwd);
338
- return await j(t), console.log(`Logged out of ${t}.`), 0;
339
- }
340
- //#endregion
341
- //#region src/commands/status.ts
342
- async function me(e) {
343
- let n = e?.cwd ?? process.cwd(), r = await t(n);
344
- if (!r) return console.error("No picked.config.{ts,js,json} found in the current directory."), 1;
345
- let a = await J(n);
346
- console.log(`API: ${a}`), console.log(`Config default: project ${r.projectId} (source: ${r.source ?? "published"})`);
347
- let o = await i(n, a);
348
- if (!o) return console.log("Active selection: none (using the config default)."), 0;
349
- if (!o.workspace) return console.log(`Active selection: live (published) in project ${o.projectId}`), 0;
350
- let { name: s, status: c, source: l } = o.workspace;
351
- return console.log(`Active selection: ${s} [${c}] in project ${o.projectId} (source: ${l})`), 0;
352
- }
353
- //#endregion
354
- //#region src/commands/whoami.ts
355
- async function he(e) {
356
- let t = await J(e?.cwd), n = await D(t);
357
- if (!n?.session) return console.error(`Not logged in to ${t}. Run \`picked login\`.`), 1;
358
- let { user: r } = n.session, i = r?.email ?? r?.id ?? "unknown user";
359
- return console.log(`${i} (${t})`), 0;
360
- }
361
- //#endregion
362
- //#region src/auth/session.ts
363
- var ge = 6e4;
364
- async function Y(e) {
365
- let t = await D(e);
366
- if (!t?.session) throw Error(`Not logged in to ${e}. Run \`picked login\`.`);
367
- if (t.session.expiresAt - Date.now() > ge) return t.session.accessToken;
368
- let n = await ue(t);
369
- return await A(e, n), n.accessToken;
370
- }
371
- //#endregion
372
- //#region src/lib/workspaces.ts
373
- var _e = y("\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"), ve = y("\n query PickedPreviewToken($id: ID!, $projectId: ID!) {\n workspace(id: $id, projectId: $projectId) {\n id\n name\n status\n previewToken\n }\n }\n");
374
- async function X(e, t) {
375
- let n = await v({
376
- apiUrl: e,
377
- token: t
378
- }).request(_e, {});
379
- if (!n.user) throw Error("Not authenticated, or no organizations are visible to this account.");
380
- return n.user.organizations.edges.map((e) => {
381
- let t = e.node;
382
- return {
383
- id: t.id,
384
- name: t.name,
385
- slug: t.slug ?? "",
386
- projects: t.projects.edges.map((e) => {
387
- let t = e.node;
388
- return {
389
- id: t.id,
390
- name: t.name,
391
- liveWorkspaceId: t.liveWorkspace?.id ?? null,
392
- liveVersionId: t.liveWorkspaceVersion?.id ?? null,
393
- workspaces: t.workspaces.edges.map((e) => ({
394
- id: e.node.id,
395
- name: e.node.name,
396
- status: e.node.status
397
- }))
398
- };
399
- })
400
- };
401
- });
402
- }
403
- async function Z(e, t, n, r) {
404
- let i = (await v({
405
- apiUrl: e,
406
- token: t
407
- }).request(ve, {
408
- id: r,
409
- projectId: n
410
- })).workspace;
411
- if (!i) throw Error(`Workspace "${r}" was not found in project "${n}".`);
412
- return {
413
- status: i.status,
414
- name: i.name,
415
- previewToken: i.previewToken
416
- };
417
- }
418
- //#endregion
419
- //#region src/commands/workspace-list.ts
420
- function ye(e) {
421
- for (let t of e) {
422
- console.log(`${t.name} (${t.slug})`);
423
- for (let e of t.projects) {
424
- console.log(` ${e.name} [${e.id}]`);
425
- for (let t of e.workspaces) {
426
- let n = t.status === "LIVE" || t.id === e.liveWorkspaceId ? " (live)" : "";
427
- console.log(` ${t.name} [${t.status}]${n}`);
428
- }
429
- }
430
- }
431
- }
432
- async function be(e) {
433
- try {
434
- let t = await J(e?.cwd), n = await X(t, await Y(t));
435
- return e?.json ? (console.log(JSON.stringify(n, null, 2)), 0) : (ye(n), 0);
436
- } catch (e) {
437
- let t = e instanceof Error ? e.message : String(e);
438
- return console.error(t), 1;
439
- }
440
- }
441
- //#endregion
442
- //#region src/lib/prompt.ts
443
- function xe(e, t) {
444
- return new Promise((n) => {
445
- e.question(t, n);
446
- });
447
- }
448
- async function Q(e, t) {
449
- if (t.length === 0) throw Error("No choices available to select from.");
450
- let n = b({
451
- input: process.stdin,
452
- output: process.stderr
453
- });
454
- process.stderr.write(`${e}\n`), t.forEach((e, t) => {
455
- process.stderr.write(` ${(t + 1).toString()}. ${e.label}\n`);
456
- });
457
- try {
458
- for (;;) {
459
- let e = await xe(n, `Enter a number (1-${t.length.toString()}): `), r = Number.parseInt(e, 10), i = Number.isInteger(r) ? t[r - 1] : void 0;
460
- if (i) return i.value;
461
- process.stderr.write("Invalid choice, try again.\n");
462
- }
463
- } finally {
464
- n.close();
465
- }
466
- }
467
- //#endregion
468
- //#region src/commands/workspace-use.ts
469
- function $(e, t, n) {
470
- return {
471
- projectId: e,
472
- workspace: {
473
- id: t,
474
- name: n.name,
475
- status: n.status,
476
- source: "preview",
477
- previewToken: n.previewToken
478
- }
479
- };
480
- }
481
- async function Se(e, t, n, r) {
482
- return r ? $(n, r, await Z(e, t, n, r)) : { projectId: n };
483
- }
484
- async function Ce(e, t) {
485
- let n = await Q("Select a project", (await X(e, t)).flatMap((e) => e.projects.map((t) => ({
486
- label: `${e.name} / ${t.name}`,
487
- value: t
488
- })))), r = n.workspaces.map((e) => ({
489
- label: `${e.name} [${e.status}]`,
490
- value: e
491
- }));
492
- n.liveVersionId && r.unshift({
493
- label: "Published (live version)",
494
- value: null
495
- });
496
- let i = await Q("Select a workspace", r);
497
- if (!i) return { projectId: n.id };
498
- i.status === "ARCHIVED" && console.error("Warning: archived workspaces may fail to load via the delivery API.");
499
- let a = await Z(e, t, n.id, i.id);
500
- return $(n.id, i.id, a);
501
- }
502
- function we(e) {
503
- if (!e.workspace) {
504
- console.log(`Active workspace: live (published) in project ${e.projectId}`);
505
- return;
506
- }
507
- let { name: t, status: n, source: r } = e.workspace;
508
- console.log(`Active workspace: ${t} [${n}] in project ${e.projectId} (source: ${r})`);
509
- }
510
- async function Te(e) {
511
- let t = e?.cwd ?? process.cwd();
512
- try {
513
- let n = await J(t), r = await Y(n), i = e?.project ? await Se(n, r, e.project, e.workspace) : await Ce(n, r);
514
- return await a(t, n, i), we(i), e?.generate !== !1 && await x({ cwd: t }), 0;
515
- } catch (e) {
516
- let t = e instanceof Error ? e.message : String(e);
517
- return console.error(t), 1;
518
- }
519
- }
520
- //#endregion
521
- export { pe as a, me as i, be as n, fe as o, he as r, x as s, Te as t };