@go-labs-sg/event-tech 0.9.0 → 0.10.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 (3) hide show
  1. package/README.md +11 -1
  2. package/dist/index.js +523 -232
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -41,6 +41,16 @@ bun add --global @go-labs-sg/event-tech
41
41
  et version
42
42
  ```
43
43
 
44
+ ## Secure credential storage
45
+
46
+ `GO_LABS_CLI_CREDENTIAL_ACCOUNT` selects the native credential-store account for this CLI. The default is `default`, preserving existing production logins. The downloadable staging launcher sets it to `staging` so a staging login does not replace the production login; keep the same account value for login and subsequent commands. The launcher also sets `GO_LABS_CLI_SKIP_DOTENV=1`, which skips the CLI's explicit current-directory `.env` load while leaving normal production behavior unchanged.
47
+
48
+ Browser sessions use `Bun.secrets`: macOS Keychain, Windows Credential Manager, or Linux Secret Service. Linux requires libsecret, a reachable user D-Bus session, and an unlocked Secret Service collection. SSH and containers must provide those native prerequisites themselves; `--no-browser` only lets approval happen on another device. Denied D-Bus access is a host permissions/session issue, not something the CLI bypasses.
49
+
50
+ Before requesting approval, login verifies write/read/delete capability with a unique non-secret probe. Native operations have a 10-second process deadline and sanitized errors. Issued credentials are read back and verified; failed persistence attempts remote revocation and reports local and remote cleanup separately. There is no plaintext fallback or external credential-helper configuration.
51
+
52
+ See the [shared authentication contract](../../cli-auth/README.md) for recovery and verification limits.
53
+
44
54
  ## Authentication
45
55
 
46
56
  ```sh
@@ -51,7 +61,7 @@ et auth whoami
51
61
 
52
62
  `et auth login` opens Event Tech in the system browser. Use the normal Event Tech Google-backed web login if needed, verify the displayed code and device, then click **Authorize CLI**. An existing browser session skips another Google login but never skips explicit CLI approval.
53
63
 
54
- The terminal polls automatically and stores only Event Tech-issued credentials through `Bun.secrets`. It does not store Google credentials and has no API-key or environment-variable authentication fallback. Use `et auth logout` to revoke the remote session and remove its local credential. For SSH and containers, pass `--no-browser` and open the printed URL elsewhere.
64
+ The terminal polls automatically and stores only Event Tech-issued credentials through `Bun.secrets`. It does not store Google credentials and has no raw API-key or token-environment authentication fallback. Use `et auth logout` to revoke the remote session and remove its local credential. For SSH and containers, pass `--no-browser` and open the printed URL elsewhere.
55
65
 
56
66
  Use `EVENT_TECH_API_URL` or `--api-url` to target another HTTPS deployment. Plain HTTP is allowed only for localhost development.
57
67
 
package/dist/index.js CHANGED
@@ -35,46 +35,46 @@ var __toESM = (mod, isNodeMode, target) => {
35
35
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
36
36
  var __require = import.meta.require;
37
37
 
38
- // ../../../node_modules/.bun/dotenv@18.0.1/node_modules/dotenv/dist/index.cjs
38
+ // ../../../node_modules/.bun/dotenv@18.0.5/node_modules/dotenv/dist/index.cjs
39
39
  var require_dist = __commonJS(function(exports, module) {
40
- var O = (e, o) => () => {
40
+ var I = (e, o) => () => {
41
41
  try {
42
42
  return o || e((o = { exports: {} }).exports, o), o.exports;
43
43
  } catch (t) {
44
44
  throw o = 0, t;
45
45
  }
46
46
  };
47
- var q = O((Ce, j) => {
48
- function I(e) {
47
+ var S = I((xe, U) => {
48
+ function G(e) {
49
49
  return typeof e == "string" ? !["false", "0", "no", "off", ""].includes(e.toLowerCase()) : !!e;
50
50
  }
51
- function B() {
52
- let e = {};
53
- for (let o of ["ENCODING", "PATH", "QUIET", "DEBUG", "OVERRIDE", "FAST"]) {
54
- let t = process.env[`DOTENV_${o}`] != null ? process.env[`DOTENV_${o}`] : process.env[`DOTENV_CONFIG_${o}`];
55
- t != null && (e[o.toLowerCase()] = o === "ENCODING" || o === "PATH" ? t : I(t));
51
+ function X(e = process.env) {
52
+ let o = {};
53
+ for (let t of ["ENCODING", "PATH", "QUIET", "DEBUG", "OVERRIDE", "FAST"]) {
54
+ let n = e[`DOTENV_${t}`] != null ? e[`DOTENV_${t}`] : e[`DOTENV_CONFIG_${t}`];
55
+ n != null && (o[t.toLowerCase()] = t === "ENCODING" || t === "PATH" ? n : G(n));
56
56
  }
57
- return e;
57
+ return o;
58
58
  }
59
- j.exports = { parseBoolean: I, optionsFromEnv: B };
59
+ U.exports = { parseBoolean: G, optionsFromEnv: X };
60
60
  });
61
- var y = O((we, C) => {
62
- var H = __require("fs"), x = __require("path"), L = __require("os"), { URL: M, fileURLToPath: W } = __require("url"), { parseBoolean: T, optionsFromEnv: Q } = q(), J = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg, v = new Uint8Array(256);
61
+ var N = I((ye, x) => {
62
+ var Y = __require("fs"), j = __require("path"), z = __require("os"), { URL: Z, fileURLToPath: ee } = __require("url"), { parseBoolean: k, optionsFromEnv: B } = S(), te = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg, b = new Uint8Array(256);
63
63
  for (let e = 48;e <= 57; e++)
64
- v[e] = 1;
64
+ b[e] = 1;
65
65
  for (let e = 65;e <= 90; e++)
66
- v[e] = 1;
66
+ b[e] = 1;
67
67
  for (let e = 97;e <= 122; e++)
68
- v[e] = 1;
69
- v[45] = 1;
70
- v[46] = 1;
71
- v[95] = 1;
72
- function K(e) {
68
+ b[e] = 1;
69
+ b[45] = 1;
70
+ b[46] = 1;
71
+ b[95] = 1;
72
+ function re(e) {
73
73
  let o = {}, t = e.toString();
74
74
  t = t.replace(/\r\n?/mg, `
75
75
  `);
76
76
  let n;
77
- for (;(n = J.exec(t)) != null; ) {
77
+ for (;(n = te.exec(t)) != null; ) {
78
78
  let r = n[1], s = n[2] || "";
79
79
  s = s.trim();
80
80
  let i = s[0];
@@ -83,192 +83,182 @@ var require_dist = __commonJS(function(exports, module) {
83
83
  }
84
84
  return o;
85
85
  }
86
- function X(e) {
86
+ function w(e) {
87
+ return e <= 32 ? e === 32 || e >= 9 && e <= 13 : e >= 160 && (e === 160 || e === 5760 || e >= 8192 && e <= 8202 || e === 8232 || e === 8233 || e === 8239 || e === 8287 || e === 12288 || e === 65279);
88
+ }
89
+ function O(e) {
90
+ return e === 10 || e === 8232 || e === 8233;
91
+ }
92
+ function oe(e) {
87
93
  let o = {}, t = typeof e == "string" ? e : e.toString();
88
94
  t.indexOf("\r") !== -1 && (t = t.replace(/\r\n?/g, `
89
95
  `));
90
96
  let n = t.length, r = 0;
91
97
  for (;r < n; ) {
92
98
  let s = t.charCodeAt(r);
93
- for (;r < n && (s === 32 || s === 9 || s === 10 || s === 65279); )
99
+ for (;r < n && w(s); )
94
100
  r++, s = t.charCodeAt(r);
95
101
  if (r >= n)
96
102
  break;
97
103
  if (s === 35) {
98
- for (;r < n && t.charCodeAt(r) !== 10; )
104
+ for (;r < n && !O(t.charCodeAt(r)); )
99
105
  r++;
100
106
  continue;
101
107
  }
108
+ let i = -1;
102
109
  if (s === 101 && r + 6 < n && t.charCodeAt(r + 1) === 120 && t.charCodeAt(r + 2) === 112 && t.charCodeAt(r + 3) === 111 && t.charCodeAt(r + 4) === 114 && t.charCodeAt(r + 5) === 116) {
103
- let f = t.charCodeAt(r + 6);
104
- if (f === 32 || f === 9)
105
- for (r += 7;r < n && ((s = t.charCodeAt(r)) === 32 || s === 9); )
106
- r++;
107
- else
110
+ let v = t.charCodeAt(r + 6);
111
+ if (w(v)) {
112
+ let u = r + 7;
113
+ for (;u < n && w(t.charCodeAt(u)); )
114
+ u++;
115
+ b[t.charCodeAt(u)] && (i = r + 6, r = u);
116
+ } else
108
117
  s = t.charCodeAt(r);
109
118
  }
110
- let i = r, l = 0;
111
- for (;r < n && (l = t.charCodeAt(r), v[l]); )
119
+ let l = r, d = 0;
120
+ for (;r < n && (d = t.charCodeAt(r), b[d]); )
112
121
  r++;
113
- if (r === i) {
114
- for (;r < n && t.charCodeAt(r) !== 10; )
122
+ if (r === l) {
123
+ for (;r < n && !O(t.charCodeAt(r)); )
115
124
  r++;
116
125
  continue;
117
126
  }
118
- let h = t.slice(i, r);
119
- if (r >= n && (l = 0), l === 32 || l === 9)
127
+ let p = t.slice(l, r), f = r;
128
+ if (r >= n && (d = 0), w(d))
120
129
  do
121
- r++, l = r < n ? t.charCodeAt(r) : 0;
122
- while (l === 32 || l === 9);
123
- if (l === 61)
124
- r++;
125
- else if (l === 58 && r + 1 < n && (t.charCodeAt(r + 1) === 32 || t.charCodeAt(r + 1) === 9))
130
+ r++, d = r < n ? t.charCodeAt(r) : 0;
131
+ while (w(d));
132
+ if (d === 61)
126
133
  r++;
134
+ else if (d === 58 && r === f && r + 1 < n && w(t.charCodeAt(r + 1)))
135
+ r += 2;
127
136
  else {
128
- for (;r < n && t.charCodeAt(r) !== 10; )
137
+ for (r = i === -1 ? f : i;r < n && !O(t.charCodeAt(r)); )
129
138
  r++;
130
139
  continue;
131
140
  }
132
- for (;r < n && ((s = t.charCodeAt(r)) === 32 || s === 9); )
133
- r++;
134
- let u;
135
- if (s = r < n ? t.charCodeAt(r) : 0, s === 39 || s === 34 || s === 96) {
136
- let f = s, c = r + 1, a = c;
137
- for (;a < n; ) {
138
- let d = t.charCodeAt(a);
139
- if (d === 92 && a + 1 < n) {
140
- let p = t.charCodeAt(a + 1);
141
- if (p === f || p === 92) {
142
- a += 2;
143
- continue;
144
- }
145
- }
146
- if (d === f)
141
+ let c = r, a = r;
142
+ for (;a < n && w(t.charCodeAt(a)); )
143
+ a++;
144
+ let g = t.charCodeAt(a), h, y = false;
145
+ if (g === 39 || g === 34 || g === 96) {
146
+ let v = t[a], u = t.indexOf(v, a + 1), m = -1, C = -1;
147
+ for (;u !== -1; ) {
148
+ let q = t.charCodeAt(u - 1) === 92, E = u + 1;
149
+ for (;E < n && !O(t.charCodeAt(E)) && w(t.charCodeAt(E)); )
150
+ E++;
151
+ if ((E === n || O(t.charCodeAt(E)) || t.charCodeAt(E) === 35) && (m = u, C = E), !q)
147
152
  break;
148
- a++;
153
+ u = t.indexOf(v, u + 1);
149
154
  }
150
- if (a >= n) {
151
- let d = r, p = r;
152
- for (;p < n; ) {
153
- let w = t.charCodeAt(p);
154
- if (w === 35 || w === 10)
155
- break;
156
- p++;
157
- }
158
- let m = p;
159
- for (;m > d; ) {
160
- let w = t.charCodeAt(m - 1);
161
- if (w === 32 || w === 9)
162
- m--;
163
- else
164
- break;
165
- }
166
- if (u = t.slice(d, m), r = p, r < n && t.charCodeAt(r) === 35)
167
- for (;r < n && t.charCodeAt(r) !== 10; )
168
- r++;
169
- } else {
170
- for (u = t.slice(c, a), r = a + 1, f === 34 && u.indexOf("\\") !== -1 && (u = u.replace(/\\n/g, `
171
- `).replace(/\\r/g, "\r"));r < n && ((s = t.charCodeAt(r)) === 32 || s === 9); )
172
- r++;
173
- if (r < n && t.charCodeAt(r) === 35)
174
- for (;r < n && t.charCodeAt(r) !== 10; )
155
+ if (m !== -1) {
156
+ if (h = t.slice(a + 1, m), r = C, t.charCodeAt(r) === 35)
157
+ for (;r < n && !O(t.charCodeAt(r)); )
175
158
  r++;
159
+ y = true;
176
160
  }
177
- } else {
178
- let f = r, c = t.indexOf(`
179
- `, r);
180
- c === -1 && (c = n);
181
- let a = t.indexOf("#", r);
182
- (a === -1 || a > c) && (a = c);
183
- let d = a;
184
- for (;d > f; ) {
185
- let p = t.charCodeAt(d - 1);
186
- if (p === 32 || p === 9)
187
- d--;
188
- else
189
- break;
190
- }
191
- u = f === d ? "" : t.slice(f, d), r = a === c ? a : c;
192
161
  }
193
- o[h] = u;
162
+ if (!y) {
163
+ let v = t.indexOf(`
164
+ `, c);
165
+ v === -1 && (v = n);
166
+ let u;
167
+ if (n < 4096)
168
+ u = t.indexOf("#", c), (u === -1 || u > v) && (u = v);
169
+ else
170
+ for (u = c;u < v && t.charCodeAt(u) !== 35; )
171
+ u++;
172
+ let m = c, C = u;
173
+ for (;m < C && w(t.charCodeAt(m)); )
174
+ m++;
175
+ for (;C > m && w(t.charCodeAt(C - 1)); )
176
+ C--;
177
+ let q = t.charCodeAt(m);
178
+ if (C - m >= 2 && (q === 39 || q === 34 || q === 96) && t.charCodeAt(C - 1) === q ? h = t.slice(m + 1, C - 1) : h = t.slice(m, C), r = u, u < v)
179
+ for (;r < n && !O(t.charCodeAt(r)); )
180
+ r++;
181
+ }
182
+ g === 34 && (y || a < r) && h.indexOf("\\") !== -1 && (h = h.replace(/\\n/g, `
183
+ `).replace(/\\r/g, "\r")), o[p] = h;
194
184
  }
195
185
  return o;
196
186
  }
197
- function Y(e, o) {
198
- return o && T(o.fast) ? X(e) : K(e);
187
+ function ne(e, o) {
188
+ return o && k(o.fast) ? oe(e) : re(e);
199
189
  }
200
- function b(e) {
190
+ function T(e) {
201
191
  console.log(`\u2506 ${e}`);
202
192
  }
203
- function z(e) {
193
+ function se(e) {
204
194
  console.error(`\u25C7 ${e}`);
205
195
  }
206
- function N(e) {
207
- return e[0] === "~" ? x.join(L.homedir(), e.slice(1)) : e;
196
+ function V(e) {
197
+ return e[0] === "~" ? j.join(z.homedir(), e.slice(1)) : e;
208
198
  }
209
- function Z(e = {}) {
210
- return { ...Q(), ...e };
199
+ function ie(e = {}) {
200
+ return { ...B(), ...e };
211
201
  }
212
- function ee(e) {
213
- e = Z(e);
214
- let o = x.resolve(process.cwd(), ".env"), t = "utf8", n = process.env;
202
+ function ce(e) {
203
+ e = ie(e);
204
+ let o = j.resolve(process.cwd(), ".env"), t = "utf8", n = process.env;
215
205
  e && e.processEnv != null && (n = e.processEnv);
216
- let r = T(e && e.debug), s = T(e && e.quiet);
217
- e && e.encoding ? t = e.encoding : r && b("no encoding is specified (UTF-8 is used by default)");
218
- let i = [o];
206
+ let r = k(e && e.debug);
207
+ e && e.encoding ? t = e.encoding : r && T("no encoding is specified (UTF-8 is used by default)");
208
+ let s = [o];
219
209
  if (e && e.path)
220
210
  if (!Array.isArray(e.path))
221
- i = [N(e.path)];
211
+ s = [V(e.path)];
222
212
  else {
223
- i = [];
213
+ s = [];
224
214
  for (let c of e.path)
225
- i.push(N(c));
215
+ s.push(V(c));
226
216
  }
227
- let l, h = {}, u = { fast: e.fast };
228
- for (let c of i)
217
+ let i, l = {}, d = { fast: e.fast };
218
+ for (let c of s)
229
219
  try {
230
- let a = g.parse(H.readFileSync(c, { encoding: t }), u);
231
- g.populate(h, a, e);
220
+ let a = A.parse(Y.readFileSync(c, { encoding: t }), d);
221
+ A.populate(l, a, e);
232
222
  } catch (a) {
233
- r && b(`failed to load ${c} ${a.message}`), l = a;
223
+ r && T(`failed to load ${c} ${a.message}`), i = a;
234
224
  }
235
- let f = g.populate(n, h, e);
236
- if (r || !s) {
237
- let c = Object.keys(f).length, a = [];
238
- for (let d of i)
225
+ let p = A.populate(n, l, e), f = k(Object.prototype.hasOwnProperty.call(e, "quiet") ? e.quiet : B(n).quiet);
226
+ if (r || !f) {
227
+ let c = Object.keys(p).length, a = [];
228
+ for (let g of s)
239
229
  try {
240
- let p = x.relative(process.cwd(), d instanceof M ? W(d) : d);
241
- a.push(p);
242
- } catch (p) {
243
- r && b(`failed to load ${d} ${p.message}`), l = p;
230
+ let h = j.relative(process.cwd(), g instanceof Z ? ee(g) : g);
231
+ a.push(h);
232
+ } catch (h) {
233
+ r && T(`failed to load ${g} ${h.message}`), i = h;
244
234
  }
245
- z(`injected env (${c}) from ${a.join(",")}`);
235
+ se(`injected env (${c}) from ${a.join(",")}`);
246
236
  }
247
- return l ? { parsed: h, error: l } : { parsed: h };
237
+ return i ? { parsed: l, error: i } : { parsed: l };
248
238
  }
249
- function te(e) {
250
- return g.configDotenv(e);
239
+ function ae(e) {
240
+ return A.configDotenv(e);
251
241
  }
252
- function re(e, o, t = {}) {
242
+ function le(e, o, t = {}) {
253
243
  let n = !!(t && t.debug), r = !!(t && t.override), s = {};
254
244
  if (e === null || typeof e != "object" || o === null || typeof o != "object") {
255
245
  let i = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
256
246
  throw i.code = "OBJECT_REQUIRED", i;
257
247
  }
258
248
  for (let i of Object.keys(o))
259
- Object.prototype.hasOwnProperty.call(e, i) ? (r === true && (e[i] = o[i], s[i] = o[i]), n && b(r === true ? `"${i}" is already defined and WAS overwritten` : `"${i}" is already defined and was NOT overwritten`)) : (e[i] = o[i], s[i] = o[i]);
249
+ Object.prototype.hasOwnProperty.call(e, i) ? (r === true && (e[i] = o[i], s[i] = o[i]), n && T(r === true ? `"${i}" is already defined and WAS overwritten` : `"${i}" is already defined and was NOT overwritten`)) : (e[i] = o[i], s[i] = o[i]);
260
250
  return s;
261
251
  }
262
- var g = { configDotenv: ee, config: te, parse: Y, populate: re };
263
- C.exports.configDotenv = g.configDotenv;
264
- C.exports.config = g.config;
265
- C.exports.parse = g.parse;
266
- C.exports.populate = g.populate;
267
- C.exports = g;
252
+ var A = { configDotenv: ce, config: ae, parse: ne, populate: le };
253
+ x.exports.configDotenv = A.configDotenv;
254
+ x.exports.config = A.config;
255
+ x.exports.parse = A.parse;
256
+ x.exports.populate = A.populate;
257
+ x.exports = A;
268
258
  });
269
- var F = O((be, R) => {
270
- var $ = __require("child_process"), oe = __require("fs"), P = __require("path");
271
- function ne(e) {
259
+ var M = I((Te, W) => {
260
+ var _ = __require("child_process"), fe = __require("fs"), L = __require("path");
261
+ function ue(e) {
272
262
  let o = ['"'], t = 0;
273
263
  for (let n of e) {
274
264
  if (n === "\\") {
@@ -279,7 +269,7 @@ var require_dist = __commonJS(function(exports, module) {
279
269
  }
280
270
  return o.push("\\".repeat(t * 2), '"'), o.join("");
281
271
  }
282
- function _(e, o = 1) {
272
+ function H(e, o = 1) {
283
273
  for (let t = 0;t < o; t++) {
284
274
  let n = [];
285
275
  for (let r of e) {
@@ -290,47 +280,47 @@ var require_dist = __commonJS(function(exports, module) {
290
280
  }
291
281
  return e;
292
282
  }
293
- function D(e, o) {
283
+ function P(e, o) {
294
284
  let t = Object.keys(e).reverse().find((n) => n.toUpperCase() === o);
295
285
  return t === undefined ? undefined : e[t];
296
286
  }
297
- function se(e, o, t) {
298
- let n = (D(o, "PATHEXT") || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean), s = n.some((l) => e.toLowerCase().endsWith(l.toLowerCase())) ? ["", ...n] : [...n, ""], i = /[\\/]/.test(e) ? [t] : [t, ...(D(o, "PATH") || "").split(";")];
287
+ function de(e, o, t) {
288
+ let n = (P(o, "PATHEXT") || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean), s = n.some((l) => e.toLowerCase().endsWith(l.toLowerCase())) ? ["", ...n] : [...n, ""], i = /[\\/]/.test(e) ? [t] : [t, ...(P(o, "PATH") || "").split(";")];
299
289
  for (let l of i)
300
- for (let h of s) {
301
- let u = P.resolve(t, l.replace(/^"|"$/g, ""), e + h);
290
+ for (let d of s) {
291
+ let p = L.resolve(t, l.replace(/^"|"$/g, ""), e + d);
302
292
  try {
303
- if (oe.statSync(u).isFile())
304
- return u;
293
+ if (fe.statSync(p).isFile())
294
+ return p;
305
295
  } catch {}
306
296
  }
307
297
  }
308
- function ie(e, o, t) {
298
+ function pe(e, o, t) {
309
299
  if (process.platform !== "win32")
310
- return $.spawn(e, o, t);
311
- let n = t.env || process.env, r = se(e, n, t.cwd || process.cwd());
300
+ return _.spawn(e, o, t);
301
+ let n = t.env || process.env, r = de(e, n, t.cwd || process.cwd());
312
302
  if (r && /\.(?:exe|com)$/i.test(r))
313
- return $.spawn(r, o, t);
314
- let s = /\.(?:bat|cmd)$/i.test(r || e), i = [_(P.normalize(r || e))];
315
- for (let h of o)
316
- i.push(_(ne(h), s ? 2 : 1));
303
+ return _.spawn(r, o, t);
304
+ let s = /\.(?:bat|cmd)$/i.test(r || e), i = [H(L.normalize(r || e))];
305
+ for (let d of o)
306
+ i.push(H(ue(d), s ? 2 : 1));
317
307
  let l = i.join(" ");
318
- return $.spawn(D(n, "COMSPEC") || "cmd.exe", ["/d", "/v:off", "/s", "/c", `"${l}"`], { ...t, windowsVerbatimArguments: true });
308
+ return _.spawn(P(n, "COMSPEC") || "cmd.exe", ["/d", "/v:off", "/s", "/c", `"${l}"`], { ...t, windowsVerbatimArguments: true });
319
309
  }
320
- R.exports = ie;
310
+ W.exports = pe;
321
311
  });
322
- var V = O((Ae, S) => {
323
- var ce = __require("fs"), ae = __require("os"), G = __require("path"), le = __require("child_process"), fe = F(), k = y(), { optionsFromEnv: ue } = q();
324
- function A() {
312
+ var K = I(($e, F) => {
313
+ var he = __require("fs"), ge = __require("os"), Q = __require("path"), me = __require("child_process"), ve = M(), R = N(), { optionsFromEnv: Ce } = S();
314
+ function $() {
325
315
  console.log(["Usage: dotenv run [--help] [-q|--quiet] [--debug] [--override] [--fast] [-f|--file <paths>] [--] <command> [args...]", "", "Run a command with environment variables from a .env file.", "Place dotenv options before the command; all following arguments go to the command.", "", "Options:", " -f, --file <paths> .env paths, comma-separated or repeated (default: .env)", " -q, --quiet suppress the injected env message", " --debug enable debug logging", " --override override existing environment variables", " --fast use the faster character-scanner parser", "", "Environment variables (DOTENV_CONFIG_* names remain as fallbacks):", " DOTENV_PATH, DOTENV_ENCODING, DOTENV_QUIET,", " DOTENV_DEBUG, DOTENV_OVERRIDE,", " DOTENV_FAST"].join(`
326
316
  `));
327
317
  }
328
- function de(e) {
318
+ function we(e) {
329
319
  let o = [], t = false, n, r, s, i, l = -1;
330
- for (let u = 0;u < e.length; u++) {
331
- let f = e[u];
320
+ for (let p = 0;p < e.length; p++) {
321
+ let f = e[p];
332
322
  if (f === "--") {
333
- l = u + 1;
323
+ l = p + 1;
334
324
  break;
335
325
  }
336
326
  if (f === "--help" || f === "-h")
@@ -352,70 +342,70 @@ var require_dist = __commonJS(function(exports, module) {
352
342
  continue;
353
343
  }
354
344
  if (f === "-f" || f === "--file" || f.startsWith("-f=") || f.startsWith("--file=")) {
355
- let c = f.indexOf("="), a = c === -1 ? f : f.slice(0, c), d = c === -1 ? e[++u] : f.slice(c + 1);
356
- if (!d || d === "--")
345
+ let c = f.indexOf("="), a = c === -1 ? f : f.slice(0, c), g = c === -1 ? e[++p] : f.slice(c + 1);
346
+ if (!g || g === "--")
357
347
  return { error: `${a} requires a path` };
358
- let p = d.split(",").map((m) => m.trim()).filter(Boolean);
359
- if (p.length === 0)
348
+ let h = g.split(",").map((y) => y.trim()).filter(Boolean);
349
+ if (h.length === 0)
360
350
  return { error: `${a} requires a path` };
361
- o.push(...p), t = true;
351
+ o.push(...h), t = true;
362
352
  continue;
363
353
  }
364
354
  if (f.startsWith("-"))
365
355
  return { error: `unknown option: ${f}` };
366
- l = u;
356
+ l = p;
367
357
  break;
368
358
  }
369
- let h = l === -1 ? [] : e.slice(l);
370
- return { paths: o, pathSet: t, quiet: n, debug: r, override: s, fast: i, command: h };
359
+ let d = l === -1 ? [] : e.slice(l);
360
+ return { paths: o, pathSet: t, quiet: n, debug: r, override: s, fast: i, command: d };
371
361
  }
372
- function pe(e) {
373
- return e[0] === "~" ? G.join(ae.homedir(), e.slice(1)) : e;
362
+ function Ae(e) {
363
+ return e[0] === "~" ? Q.join(ge.homedir(), e.slice(1)) : e;
374
364
  }
375
- function he(e) {
376
- let o = ue(), t = { encoding: o.encoding || "utf8", quiet: o.quiet === true, debug: o.debug === true, override: o.override === true, fast: o.fast === true, paths: [".env"], defaultPath: true };
365
+ function Ee(e) {
366
+ let o = Ce(), t = { encoding: o.encoding || "utf8", quiet: o.quiet === true, debug: o.debug === true, override: o.override === true, fast: o.fast === true, paths: [".env"], defaultPath: true };
377
367
  return o.path != null && (t.paths = [o.path], t.defaultPath = false), e.pathSet && (t.paths = e.paths, t.defaultPath = false), e.quiet != null && (t.quiet = e.quiet), e.debug != null && (t.debug = e.debug), e.override != null && (t.override = e.override), e.fast != null && (t.fast = e.fast), t;
378
368
  }
379
- function ge(e) {
369
+ function be(e) {
380
370
  let o = {}, t = [], n = { override: e.override, debug: e.debug };
381
371
  for (let s of e.paths) {
382
- let i = G.resolve(process.cwd(), pe(s));
372
+ let i = Q.resolve(process.cwd(), Ae(s));
383
373
  try {
384
- let l = k.parse(ce.readFileSync(i, { encoding: e.encoding }), { fast: e.fast });
385
- k.populate(o, l, n), t.push(s);
374
+ let l = R.parse(he.readFileSync(i, { encoding: e.encoding }), { fast: e.fast });
375
+ R.populate(o, l, n), t.push(s);
386
376
  } catch (l) {
387
377
  if (e.debug && console.log(`\u2506 failed to load ${s} ${l.message}`), !(e.defaultPath && l.code === "ENOENT"))
388
378
  throw l;
389
379
  }
390
380
  }
391
- return { injected: k.populate(process.env, o, n), loadedPaths: t };
381
+ return { injected: R.populate(process.env, o, n), loadedPaths: t };
392
382
  }
393
- function U(e) {
383
+ function J(e) {
394
384
  let o = e[0];
395
385
  if (o === "--help" || o === "-h") {
396
- A();
386
+ $();
397
387
  return;
398
388
  }
399
389
  if (o !== "run") {
400
- A(), process.exitCode = 1;
390
+ $(), process.exitCode = 1;
401
391
  return;
402
392
  }
403
- let t = de(e.slice(1));
393
+ let t = we(e.slice(1));
404
394
  if (t.help) {
405
- A();
395
+ $();
406
396
  return;
407
397
  }
408
398
  if (t.error) {
409
- console.error(`dotenv: ${t.error}`), A(), process.exitCode = 1;
399
+ console.error(`dotenv: ${t.error}`), $(), process.exitCode = 1;
410
400
  return;
411
401
  }
412
402
  if (t.command.length === 0) {
413
- A(), process.exitCode = 1;
403
+ $(), process.exitCode = 1;
414
404
  return;
415
405
  }
416
- let n = he(t);
406
+ let n = Ee(t);
417
407
  try {
418
- let c = ge(n);
408
+ let c = be(n);
419
409
  if (!n.quiet) {
420
410
  let a = `\u25C7 injected env (${Object.keys(c.injected).length})`;
421
411
  c.loadedPaths.length > 0 && (a += ` from ${c.loadedPaths.join(", ")}`), console.error(a);
@@ -424,11 +414,11 @@ var require_dist = __commonJS(function(exports, module) {
424
414
  console.error(`dotenv: ${c.message}`), process.exitCode = 1;
425
415
  return;
426
416
  }
427
- let r = !!process.stdin.isTTY, s = process.platform !== "win32" && !r, i = fe(t.command[0], t.command.slice(1), { stdio: "inherit", detached: s }), l = new Map, h = 0;
428
- function u(c) {
417
+ let r = !!process.stdin.isTTY, s = process.platform !== "win32" && !r, i = ve(t.command[0], t.command.slice(1), { stdio: "inherit", detached: s }), l = new Map, d = 0;
418
+ function p(c) {
429
419
  if (!(!i.pid || i.exitCode !== null || i.signalCode !== null)) {
430
420
  if (process.platform === "win32") {
431
- le.spawnSync("taskkill", ["/pid", String(i.pid), "/T", "/F"], { stdio: "ignore" });
421
+ me.spawnSync("taskkill", ["/pid", String(i.pid), "/T", "/F"], { stdio: "ignore" });
432
422
  return;
433
423
  }
434
424
  try {
@@ -446,14 +436,14 @@ var require_dist = __commonJS(function(exports, module) {
446
436
  for (let c of ["SIGINT", "SIGTERM", "SIGHUP", "SIGQUIT"]) {
447
437
  let a = () => {
448
438
  if (c === "SIGINT") {
449
- if (h++, r && process.platform !== "win32" && h === 1)
439
+ if (d++, r && process.platform !== "win32" && d === 1)
450
440
  return;
451
- if (h > 1) {
452
- u(h === 2 ? "SIGTERM" : "SIGKILL");
441
+ if (d > 1) {
442
+ p(d === 2 ? "SIGTERM" : "SIGKILL");
453
443
  return;
454
444
  }
455
445
  }
456
- u(c);
446
+ p(c);
457
447
  };
458
448
  l.set(c, a), process.on(c, a);
459
449
  }
@@ -463,22 +453,24 @@ var require_dist = __commonJS(function(exports, module) {
463
453
  f(), typeof c == "number" ? process.exit(c) : (setInterval(() => {}, 1000), process.kill(process.pid, a));
464
454
  });
465
455
  }
466
- S.exports = U;
467
- S === __require.main && U(process.argv.slice(2));
456
+ F.exports = J;
457
+ F === __require.main && J(process.argv.slice(2));
468
458
  });
469
- var E = y();
470
- var ve = V();
471
- module.exports = E;
472
- module.exports.config = E.config;
473
- module.exports.configDotenv = E.configDotenv;
474
- module.exports.parse = E.parse;
475
- module.exports.populate = E.populate;
459
+ var D = N();
460
+ var Oe = K();
461
+ module.exports = D;
462
+ module.exports.config = D.config;
463
+ module.exports.configDotenv = D.configDotenv;
464
+ module.exports.parse = D.parse;
465
+ module.exports.populate = D.populate;
476
466
  });
477
467
 
478
468
  // src/load-env.ts
479
469
  var import_dotenv = __toESM(require_dist(), 1);
480
470
  import path from "path";
481
- import_dotenv.config({ path: path.resolve(process.cwd(), ".env"), quiet: true });
471
+ if (process.env.GO_LABS_CLI_SKIP_DOTENV !== "1") {
472
+ import_dotenv.config({ path: path.resolve(process.cwd(), ".env"), quiet: true });
473
+ }
482
474
 
483
475
  // ../../cli-auth/src/client/credential-store.ts
484
476
  import { createHash as createHash2, randomUUID } from "crypto";
@@ -1493,6 +1485,8 @@ function datetime(args) {
1493
1485
  }
1494
1486
  var anyString = /^[\s\S]{0,}$/;
1495
1487
  var number = /^-?\d+(?:\.\d+)?$/;
1488
+ var boolean = /^(?:true|false)$/i;
1489
+ var _null = /^null$/i;
1496
1490
  var lowercase = /^[^A-Z]*$/;
1497
1491
  var uppercase = /^[^a-z]*$/;
1498
1492
 
@@ -2374,6 +2368,43 @@ var $ZodNumberFormat = /* @__PURE__ */ $constructor("$ZodNumberFormat", (inst, d
2374
2368
  $ZodCheckNumberFormat.init(inst, def);
2375
2369
  $ZodNumber.init(inst, def);
2376
2370
  });
2371
+ var $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
2372
+ $ZodType.init(inst, def);
2373
+ inst._zod.pattern = boolean;
2374
+ inst._zod.parse = (payload, _ctx) => {
2375
+ if (def.coerce)
2376
+ try {
2377
+ payload.value = Boolean(payload.value);
2378
+ } catch (_) {}
2379
+ const input = payload.value;
2380
+ if (typeof input === "boolean")
2381
+ return payload;
2382
+ payload.issues.push({
2383
+ expected: "boolean",
2384
+ code: "invalid_type",
2385
+ input,
2386
+ inst
2387
+ });
2388
+ return payload;
2389
+ };
2390
+ });
2391
+ var $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
2392
+ $ZodType.init(inst, def);
2393
+ inst._zod.pattern = _null;
2394
+ inst._zod.values = new Set([null]);
2395
+ inst._zod.parse = (payload, _ctx) => {
2396
+ const input = payload.value;
2397
+ if (input === null)
2398
+ return payload;
2399
+ payload.issues.push({
2400
+ expected: "null",
2401
+ code: "invalid_type",
2402
+ input,
2403
+ inst
2404
+ });
2405
+ return payload;
2406
+ };
2407
+ });
2377
2408
  var $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
2378
2409
  $ZodType.init(inst, def);
2379
2410
  inst._zod.parse = (payload) => payload;
@@ -3911,6 +3942,18 @@ function _int(Class, params) {
3911
3942
  ...normalizeParams(params)
3912
3943
  });
3913
3944
  }
3945
+ function _boolean(Class, params) {
3946
+ return new Class({
3947
+ type: "boolean",
3948
+ ...normalizeParams(params)
3949
+ });
3950
+ }
3951
+ function _null2(Class, params) {
3952
+ return new Class({
3953
+ type: "null",
3954
+ ...normalizeParams(params)
3955
+ });
3956
+ }
3914
3957
  function _unknown(Class) {
3915
3958
  return new Class({
3916
3959
  type: "unknown"
@@ -4793,6 +4836,18 @@ var numberProcessor = (schema, ctx, _json, params) => {
4793
4836
  json.allOf = [...json.allOf ?? [], ...rest.map((m) => ({ multipleOf: m }))];
4794
4837
  }
4795
4838
  };
4839
+ var booleanProcessor = (_schema, _ctx, json, _params) => {
4840
+ json.type = "boolean";
4841
+ };
4842
+ var nullProcessor = (_schema, ctx, json, _params) => {
4843
+ if (ctx.target === "openapi-3.0") {
4844
+ json.type = "string";
4845
+ json.nullable = true;
4846
+ json.enum = [null];
4847
+ } else {
4848
+ json.type = "null";
4849
+ }
4850
+ };
4796
4851
  var neverProcessor = (_schema, _ctx, json, _params) => {
4797
4852
  json.not = {};
4798
4853
  };
@@ -5587,6 +5642,22 @@ var ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, def
5587
5642
  function int(params) {
5588
5643
  return _int(ZodNumberFormat, params);
5589
5644
  }
5645
+ var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
5646
+ $ZodBoolean.init(inst, def);
5647
+ ZodType.init(inst, def);
5648
+ inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
5649
+ });
5650
+ function boolean2(params) {
5651
+ return _boolean(ZodBoolean, params);
5652
+ }
5653
+ var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
5654
+ $ZodNull.init(inst, def);
5655
+ ZodType.init(inst, def);
5656
+ inst._zod.processJSONSchema = (ctx, json, params) => nullProcessor(inst, ctx, json, params);
5657
+ });
5658
+ function _null3(params) {
5659
+ return _null2(ZodNull, params);
5660
+ }
5590
5661
  var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
5591
5662
  $ZodUnknown.init(inst, def);
5592
5663
  ZodType.init(inst, def);
@@ -6005,6 +6076,9 @@ var storedCliCredentialsSchema = object({
6005
6076
  session: cliSessionIdentitySchema
6006
6077
  }).strict();
6007
6078
  var cliProductSchema = _enum(cliProducts);
6079
+ // ../../cli-auth/src/client/secret-backend.ts
6080
+ import { execFile } from "child_process";
6081
+
6008
6082
  // ../../cli-auth/src/client/runtime.ts
6009
6083
  var MINIMUM_BUN_VERSION = [1, 4, 0];
6010
6084
  var parseBunVersion = (version) => {
@@ -6030,27 +6104,145 @@ var assertBunRuntime = (runtime = globalThis.Bun) => {
6030
6104
  }
6031
6105
  };
6032
6106
 
6033
- // ../../cli-auth/src/client/credential-store.ts
6107
+ // ../../cli-auth/src/client/storage-error.ts
6108
+ var guidance = {
6109
+ "missing-library": "Install the runtime's native credential-store library and ensure your own native keyring/session is accessible and unlocked; Linux desktop storage requires libsecret AND an accessible, unlocked Secret Service.",
6110
+ "bus-unavailable": "The Linux user D-Bus session is absent or unreachable. --no-browser does not provide storage. Start or repair your own user session and native keyring before retrying.",
6111
+ "bus-denied": "Access to the Linux user bus was denied. Fix your own native keyring/session permissions or host policy; do not change bus/socket permissions or borrow another user's bus.",
6112
+ "service-unavailable": "The user bus is reachable but your own Secret Service is unavailable. Start or repair your own native keyring session; do not expose another user's store.",
6113
+ locked: "Unlock your own native credential collection/session before retrying. The CLI will not wait indefinitely for an unlock prompt.",
6114
+ timeout: "The native credential backend did not finish within 10 seconds and its process was terminated. Fix or unlock your own native keyring/session outside the CLI; the CLI will not bypass host permissions.",
6115
+ "invalid-response": "The native credential backend returned an invalid response. Check your own keyring/session and configuration; no credential output was disclosed.",
6116
+ "read-failed": "The native credential backend could not read credentials. Check your own keyring/session availability and permissions; this is not evidence that you are logged out.",
6117
+ "write-failed": "The native credential backend could not persist credentials. Check your own keyring/session write permissions and availability; no plaintext fallback is used.",
6118
+ "delete-failed": "The native credential backend could not delete its entry. Check your own keyring/session permissions and remove any non-secret preflight probe through that backend if necessary."
6119
+ };
6120
+
6034
6121
  class CliCredentialStoreUnavailableError extends Error {
6035
6122
  code = "CLI_CREDENTIAL_STORE_UNAVAILABLE";
6036
- constructor(product, options) {
6037
- super(`Secure credential storage is unavailable for the ${product} CLI. Bun.secrets requires the operating system credential store, including Secret Service on Linux. Browser authentication cannot continue without a supported secure store.`, options);
6123
+ reason;
6124
+ constructor(product, reason = "read-failed") {
6125
+ super(`Secure credential storage is unavailable for the ${product} CLI [CLI_CREDENTIAL_STORE_UNAVAILABLE:${reason}]. ${guidance[reason]}`);
6038
6126
  this.name = "CliCredentialStoreUnavailableError";
6039
- }
6127
+ this.reason = reason;
6128
+ }
6129
+ }
6130
+ var classifyCredentialStoreFailure = (message, fallback) => {
6131
+ if (/libsecret.*(not found|not available|cannot open|load)|dlopen|shared (object|library).*not found/i.test(message))
6132
+ return "missing-library";
6133
+ if (/(d-?bus|user bus|session bus).*(denied|not permitted)|(?:denied|not permitted).*(d-?bus|user bus|session bus)/i.test(message))
6134
+ return "bus-denied";
6135
+ if (/locked|interaction.*not allowed|user.*cancel/i.test(message))
6136
+ return "locked";
6137
+ if (/ServiceUnknown|org\.freedesktop\.secrets.*(not provided|no owner|not available)|secret.?service.*(unavailable|not running)/i.test(message))
6138
+ return "service-unavailable";
6139
+ if (/d-?bus|user bus|session bus|autolaunch/i.test(message))
6140
+ return "bus-unavailable";
6141
+ return fallback;
6142
+ };
6143
+
6144
+ class CliCredentialPersistenceError extends Error {
6145
+ remoteRevoked;
6146
+ localRestored;
6147
+ phase;
6148
+ code = "CLI_CREDENTIAL_PERSISTENCE_FAILED";
6149
+ constructor(remoteRevoked, localRestored, phase) {
6150
+ super(`CLI credentials could not be saved after ${phase} [CLI_CREDENTIAL_PERSISTENCE_FAILED]. ${remoteRevoked ? "The newly issued session was revoked." : "Remote revocation could not be confirmed; revoke the session in the product's session management before retrying."} ${localRestored ? phase === "login" ? "The previous local credentials were preserved." : "The unusable rotated local credentials were removed; sign in again." : "Local cleanup could not be confirmed. Inspect your own native credential backend before retrying."}`);
6151
+ this.remoteRevoked = remoteRevoked;
6152
+ this.localRestored = localRestored;
6153
+ this.phase = phase;
6154
+ this.name = "CliCredentialPersistenceError";
6155
+ }
6156
+ }
6157
+ var getCliStorageError = (error) => {
6158
+ if (error instanceof CliCredentialStoreUnavailableError)
6159
+ return {
6160
+ code: error.code,
6161
+ message: error.message,
6162
+ details: { reason: error.reason }
6163
+ };
6164
+ if (error instanceof CliCredentialPersistenceError)
6165
+ return {
6166
+ code: error.code,
6167
+ message: error.message,
6168
+ details: {
6169
+ remoteRevoked: error.remoteRevoked,
6170
+ localRestored: error.localRestored,
6171
+ phase: error.phase
6172
+ }
6173
+ };
6174
+ return;
6175
+ };
6176
+
6177
+ // ../../cli-auth/src/client/secret-backend.ts
6178
+ var timeoutMs = 1e4;
6179
+ var maxBuffer = 64 * 1024;
6180
+ var runBackend = (product, executable, args, input, failure) => new Promise((resolve, reject) => {
6181
+ const child = execFile(executable, args, {
6182
+ timeout: timeoutMs,
6183
+ killSignal: "SIGKILL",
6184
+ maxBuffer,
6185
+ windowsHide: true
6186
+ }, (error, stdout, stderr) => {
6187
+ if (error) {
6188
+ const reason = error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ? "invalid-response" : error.killed ? "timeout" : classifyCredentialStoreFailure(`${stdout}
6189
+ ${stderr}`, failure);
6190
+ reject(new CliCredentialStoreUnavailableError(product, reason));
6191
+ return;
6192
+ }
6193
+ resolve(stdout);
6194
+ });
6195
+ child.stdin?.on("error", () => {});
6196
+ child.stdin?.end(input);
6197
+ });
6198
+ var nativeWorker = `
6199
+ try {
6200
+ const { operation, input } = JSON.parse(await Bun.stdin.text());
6201
+ const value = await Bun.secrets[operation](input);
6202
+ process.stdout.write(JSON.stringify({ value: value ?? null }));
6203
+ } catch (error) {
6204
+ const message = error instanceof Error ? error.message : "Credential backend failed";
6205
+ // libsecret's bus transport errors can omit the D-Bus context.
6206
+ const context = process.platform === "linux" && /^Could not connect:/i.test(message) ? "D-Bus: " : "";
6207
+ process.stderr.write(context + message);
6208
+ process.exitCode = 1;
6040
6209
  }
6041
- var useSecrets = async (product, operation) => {
6210
+ `;
6211
+ var nativeResponse = object({ value: union([string2(), boolean2(), _null3()]) }).strict();
6212
+ var createIsolatedBunSecrets = (product) => {
6213
+ const run = async (operation, input) => {
6214
+ assertBunRuntime();
6215
+ const output = await runBackend(product, process.execPath, ["--no-env-file", "--eval", nativeWorker], JSON.stringify({ operation, input }), operation === "set" ? "write-failed" : operation === "delete" ? "delete-failed" : "read-failed");
6216
+ try {
6217
+ return nativeResponse.parse(JSON.parse(output)).value;
6218
+ } catch {
6219
+ throw new CliCredentialStoreUnavailableError(product, "invalid-response");
6220
+ }
6221
+ };
6222
+ return {
6223
+ get: async (input) => {
6224
+ const value = await run("get", input);
6225
+ if (value === null || typeof value === "string")
6226
+ return value;
6227
+ throw new CliCredentialStoreUnavailableError(product, "invalid-response");
6228
+ },
6229
+ set: async (input) => {
6230
+ await run("set", input);
6231
+ },
6232
+ delete: async (input) => await run("delete", input) === true
6233
+ };
6234
+ };
6235
+
6236
+ // ../../cli-auth/src/client/credential-store.ts
6237
+ var runSecretOperation = async (product, operation, fallback = "read-failed") => {
6042
6238
  try {
6043
6239
  return await operation();
6044
6240
  } catch (cause) {
6045
6241
  if (cause instanceof CliCredentialStoreUnavailableError)
6046
6242
  throw cause;
6047
- throw new CliCredentialStoreUnavailableError(product, { cause });
6243
+ throw new CliCredentialStoreUnavailableError(product, classifyCredentialStoreFailure(cause instanceof Error ? cause.message : "", fallback));
6048
6244
  }
6049
6245
  };
6050
- var defaultSecrets = () => {
6051
- assertBunRuntime();
6052
- return Bun.secrets;
6053
- };
6054
6246
  var refreshLockTimeoutMs = 5 * 60 * 1000;
6055
6247
  var refreshLockRetryMs = 50;
6056
6248
  var getCredentialLockDirectoryPath = () => {
@@ -6122,18 +6314,38 @@ var acquireRefreshLock = async (path) => {
6122
6314
  }
6123
6315
  throw new Error("Timed out waiting for another CLI process to refresh credentials. Retry the command.");
6124
6316
  };
6317
+ var resolveCliCredentialAccount = (environment = process.env) => environment.GO_LABS_CLI_CREDENTIAL_ACCOUNT?.trim() || "default";
6125
6318
  var createBunCredentialStore = ({
6126
- account = "default",
6319
+ account = resolveCliCredentialAccount(),
6127
6320
  product,
6128
- secrets = defaultSecrets()
6321
+ secrets = createIsolatedBunSecrets(product)
6129
6322
  }) => {
6130
6323
  const service = `go-labs-cli:${product}`;
6131
6324
  return {
6325
+ preflight: async () => {
6326
+ const input = { name: `probe-${randomUUID()}`, service };
6327
+ const value = `go-labs-non-secret-probe:${randomUUID()}`;
6328
+ try {
6329
+ await runSecretOperation(product, () => secrets.set({ ...input, value }), "write-failed");
6330
+ if (await runSecretOperation(product, () => secrets.get(input)) !== value) {
6331
+ throw new CliCredentialStoreUnavailableError(product, "write-failed");
6332
+ }
6333
+ } catch (error) {
6334
+ await secrets.delete(input).catch(() => {
6335
+ return;
6336
+ });
6337
+ throw error;
6338
+ }
6339
+ await runSecretOperation(product, () => secrets.delete(input), "delete-failed");
6340
+ if (await runSecretOperation(product, () => secrets.get(input)) !== null) {
6341
+ throw new CliCredentialStoreUnavailableError(product, "delete-failed");
6342
+ }
6343
+ },
6132
6344
  delete: async () => {
6133
- await useSecrets(product, () => secrets.delete({ name: account, service }));
6345
+ await runSecretOperation(product, () => secrets.delete({ name: account, service }), "delete-failed");
6134
6346
  },
6135
6347
  get: async () => {
6136
- const value = await useSecrets(product, () => secrets.get({ name: account, service }));
6348
+ const value = await runSecretOperation(product, () => secrets.get({ name: account, service }));
6137
6349
  if (value === null)
6138
6350
  return null;
6139
6351
  try {
@@ -6144,11 +6356,11 @@ var createBunCredentialStore = ({
6144
6356
  },
6145
6357
  set: async (credentials) => {
6146
6358
  const parsed = storedCliCredentialsSchema.parse(credentials);
6147
- await useSecrets(product, () => secrets.set({
6359
+ await runSecretOperation(product, () => secrets.set({
6148
6360
  name: account,
6149
6361
  service,
6150
6362
  value: JSON.stringify(parsed)
6151
- }));
6363
+ }), "write-failed");
6152
6364
  },
6153
6365
  withCredentialLock: async (operation) => {
6154
6366
  const refreshLockPath = await getCredentialLockPath(product, account);
@@ -6169,6 +6381,7 @@ var createBunCredentialStore = ({
6169
6381
  };
6170
6382
  // ../../cli-auth/src/client/login.ts
6171
6383
  import { hostname } from "os";
6384
+ import { isDeepStrictEqual } from "util";
6172
6385
  var normalizeCliAuthIssuer = (value) => {
6173
6386
  const url = new URL(value);
6174
6387
  url.hash = "";
@@ -6231,12 +6444,15 @@ var openSystemBrowser = async (url) => {
6231
6444
  "-NoProfile",
6232
6445
  "-NonInteractive",
6233
6446
  "-Command",
6234
- "Start-Process -FilePath $args[0]",
6235
- url
6447
+ "Start-Process -FilePath $env:GO_LABS_CLI_VERIFICATION_URI -ErrorAction Stop"
6236
6448
  ] : ["xdg-open", url];
6237
6449
  try {
6238
- const process2 = Bun.spawn(command, { stderr: "ignore", stdout: "ignore" });
6239
- return await process2.exited === 0;
6450
+ const browserProcess = Bun.spawn(command, {
6451
+ env: process.platform === "win32" ? { ...process.env, GO_LABS_CLI_VERIFICATION_URI: url } : process.env,
6452
+ stderr: "ignore",
6453
+ stdout: "ignore"
6454
+ });
6455
+ return await browserProcess.exited === 0;
6240
6456
  } catch {
6241
6457
  return false;
6242
6458
  }
@@ -6254,6 +6470,8 @@ var loginWithBrowser = async ({
6254
6470
  store
6255
6471
  }) => {
6256
6472
  const baseUrl = normalizeCliAuthIssuer(apiBaseUrl);
6473
+ if (store.preflight)
6474
+ await withCredentialLock(store, () => store.preflight?.() ?? Promise.resolve());
6257
6475
  const pkce = createPkcePair();
6258
6476
  const beginResponse = await postJson(fetchImplementation, `${baseUrl}/api/cli-auth/device`, {
6259
6477
  clientName,
@@ -6281,7 +6499,19 @@ var loginWithBrowser = async ({
6281
6499
  if (response.ok) {
6282
6500
  const issued = tokenResponseSchema.parse(payload);
6283
6501
  const credentials = toStoredCredentials(issued, baseUrl, now());
6284
- await withCredentialLock(store, () => store.set(credentials));
6502
+ try {
6503
+ await withCredentialLock(store, () => persistIssuedCredentials({
6504
+ store,
6505
+ credentials,
6506
+ apiBaseUrl: baseUrl,
6507
+ fetch: fetchImplementation,
6508
+ phase: "login"
6509
+ }));
6510
+ } catch (error) {
6511
+ if (error instanceof CliCredentialPersistenceError)
6512
+ throw error;
6513
+ throw new CliCredentialPersistenceError(await revokeIssuedCredentials(fetchImplementation, baseUrl, credentials), false, "login");
6514
+ }
6285
6515
  return credentials;
6286
6516
  }
6287
6517
  const error = deviceTokenErrorSchema.safeParse(payload);
@@ -6301,6 +6531,55 @@ var loginWithBrowser = async ({
6301
6531
  }
6302
6532
  throw new Error("CLI authentication expired. Run auth login again.");
6303
6533
  };
6534
+ var revokeIssuedCredentials = async (fetchImplementation, apiBaseUrl, credentials) => {
6535
+ try {
6536
+ const response = await postJson(fetchImplementation, `${normalizeCliAuthIssuer(apiBaseUrl)}/api/cli-auth/revoke`, { refreshToken: credentials.refreshToken }, { signal: AbortSignal.timeout(refreshRequestTimeoutMs) });
6537
+ return response.ok;
6538
+ } catch {
6539
+ return false;
6540
+ }
6541
+ };
6542
+ var persistIssuedCredentials = async ({
6543
+ store,
6544
+ credentials,
6545
+ previous,
6546
+ apiBaseUrl,
6547
+ fetch: fetchImplementation,
6548
+ phase
6549
+ }) => {
6550
+ let prior = previous;
6551
+ try {
6552
+ if (phase === "login")
6553
+ prior = await store.get();
6554
+ await store.set(credentials);
6555
+ const saved = await store.get();
6556
+ if (!isDeepStrictEqual(saved, credentials))
6557
+ throw new Error("Credential write could not be verified");
6558
+ return;
6559
+ } catch {
6560
+ const remoteRevoked = await revokeIssuedCredentials(fetchImplementation, apiBaseUrl, credentials);
6561
+ let localRestored = false;
6562
+ try {
6563
+ const current = await store.get();
6564
+ if (phase === "login" && prior !== undefined) {
6565
+ if (isDeepStrictEqual(current, prior))
6566
+ localRestored = true;
6567
+ else if (current === null || current.refreshToken === credentials.refreshToken) {
6568
+ if (prior)
6569
+ await store.set(prior);
6570
+ else
6571
+ await store.delete();
6572
+ localRestored = isDeepStrictEqual(await store.get(), prior);
6573
+ }
6574
+ } else if (phase === "refresh" && (!current || current.refreshToken === credentials.refreshToken || current.refreshToken === prior?.refreshToken)) {
6575
+ if (current)
6576
+ await store.delete();
6577
+ localRestored = await store.get() === null;
6578
+ }
6579
+ } catch {}
6580
+ throw new CliCredentialPersistenceError(remoteRevoked, localRestored, phase);
6581
+ }
6582
+ };
6304
6583
  var refreshes = new WeakMap;
6305
6584
  var refreshRequestTimeoutMs = 30000;
6306
6585
  var isInvalidGrantResponse = (payload) => {
@@ -6355,7 +6634,14 @@ var refreshAccessToken = async ({
6355
6634
  throw new Error("Unable to refresh the CLI session because the API returned invalid credentials. Credentials were kept; retry the command.");
6356
6635
  }
6357
6636
  const stored = toStoredCredentials(issued, normalizeCliAuthIssuer(apiBaseUrl), now());
6358
- await store.set(stored);
6637
+ await persistIssuedCredentials({
6638
+ store,
6639
+ credentials: stored,
6640
+ previous: credentials,
6641
+ apiBaseUrl,
6642
+ fetch: fetchImplementation,
6643
+ phase: "refresh"
6644
+ });
6359
6645
  return stored.accessToken;
6360
6646
  };
6361
6647
  var refreshWithCurrentCredentials = async ({
@@ -6592,6 +6878,11 @@ var errorCode = (error) => {
6592
6878
  return "INTERNAL_ERROR";
6593
6879
  };
6594
6880
  var writeError = (runtime, error) => {
6881
+ const storageError = getCliStorageError(error);
6882
+ if (storageError) {
6883
+ runtime.stderr.write(serialize({ ok: false, error: storageError }));
6884
+ return;
6885
+ }
6595
6886
  const message = error instanceof Error ? sanitizeErrorMessage(error.message) : "Unknown error.";
6596
6887
  runtime.stderr.write(serialize({ ok: false, error: { code: errorCode(error), message } }));
6597
6888
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/event-tech",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Event Tech CLI for managing Event Tech resources through the Go Labs API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",