@openbkn/bkn-sdk 0.1.1-alpha.6 → 0.1.1-alpha.8

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.
@@ -4,11 +4,6 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
- // src/types.ts
8
- var DEFAULT_BUSINESS_DOMAIN = "bd_public";
9
- var DEFAULT_LIST_LIMIT = 30;
10
- var DEFAULT_QUERY_LIMIT = 50;
11
-
12
7
  // src/utils/errors.ts
13
8
  var HttpError = class extends Error {
14
9
  status;
@@ -77,189 +72,6 @@ function truncate(s, n) {
77
72
  return s.length > n ? `${s.slice(0, n)}\u2026` : s;
78
73
  }
79
74
 
80
- // src/config/store.ts
81
- import {
82
- chmodSync,
83
- existsSync,
84
- mkdirSync,
85
- readFileSync,
86
- readdirSync,
87
- rmSync,
88
- writeFileSync
89
- } from "fs";
90
- import { homedir } from "os";
91
- import { join } from "path";
92
-
93
- // src/auth/jwt.ts
94
- function decodeJwt(token) {
95
- const parts = token.split(".");
96
- if (parts.length < 2 || !parts[1]) return void 0;
97
- try {
98
- const json = Buffer.from(parts[1], "base64url").toString("utf8");
99
- return JSON.parse(json);
100
- } catch {
101
- return void 0;
102
- }
103
- }
104
- function isExpired(claims, nowMs = Date.now()) {
105
- return claims?.exp !== void 0 && claims.exp * 1e3 < nowMs;
106
- }
107
-
108
- // src/config/store.ts
109
- var PROFILE_RE = /^[A-Za-z0-9_-]{1,64}$/;
110
- var IS_WIN = process.platform === "win32";
111
- function configDir() {
112
- return process.env.BKN_CONFIG_DIR ?? join(homedir(), ".bkn");
113
- }
114
- function profileName() {
115
- const raw = process.env.BKN_PROFILE?.trim();
116
- if (!raw) return null;
117
- if (!PROFILE_RE.test(raw)) {
118
- throw new Error(`BKN_PROFILE='${raw}' is invalid. Use 1-64 chars from [A-Za-z0-9_-].`);
119
- }
120
- return raw;
121
- }
122
- function statePath() {
123
- const profile = profileName();
124
- return profile ? join(configDir(), "profiles", profile, "state.json") : join(configDir(), "state.json");
125
- }
126
- function encodeKey(baseUrl) {
127
- return Buffer.from(baseUrl, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
128
- }
129
- function platformDir(baseUrl) {
130
- return join(configDir(), "platforms", encodeKey(baseUrl));
131
- }
132
- function userDir(baseUrl, userId) {
133
- return join(platformDir(baseUrl), "users", userId);
134
- }
135
- function userIdFromToken(token) {
136
- return decodeJwt(token.idToken ?? "")?.sub ?? decodeJwt(token.accessToken)?.sub ?? "default";
137
- }
138
- function readState() {
139
- return readJson(statePath()) ?? {};
140
- }
141
- function writeState(state) {
142
- writeJson(statePath(), state);
143
- }
144
- function activePlatform() {
145
- return readState().currentPlatform;
146
- }
147
- function setActivePlatform(baseUrl) {
148
- writeState({ ...readState(), currentPlatform: baseUrl });
149
- }
150
- function activeUserId(baseUrl) {
151
- return readState().activeUsers?.[baseUrl];
152
- }
153
- function setActiveUser(baseUrl, userId) {
154
- const state = readState();
155
- writeState({ ...state, activeUsers: { ...state.activeUsers, [baseUrl]: userId } });
156
- }
157
- function readToken(baseUrl, userId = activeUserId(baseUrl)) {
158
- if (!userId) return void 0;
159
- return readJson(join(userDir(baseUrl, userId), "token.json")) ?? void 0;
160
- }
161
- function writeToken(baseUrl, token) {
162
- const userId = userIdFromToken(token);
163
- writeJson(join(userDir(baseUrl, userId), "token.json"), token, 384);
164
- setActiveUser(baseUrl, userId);
165
- return userId;
166
- }
167
- function deleteToken(baseUrl, userId = activeUserId(baseUrl)) {
168
- if (!userId) return false;
169
- const path = join(userDir(baseUrl, userId), "token.json");
170
- if (!existsSync(path)) return false;
171
- rmSync(path, { force: true });
172
- return true;
173
- }
174
- function readPlatformConfig(baseUrl, userId = activeUserId(baseUrl)) {
175
- if (!userId) return {};
176
- return readJson(join(userDir(baseUrl, userId), "config.json")) ?? {};
177
- }
178
- function writePlatformConfig(baseUrl, config) {
179
- const userId = activeUserId(baseUrl) ?? "default";
180
- writeJson(join(userDir(baseUrl, userId), "config.json"), config);
181
- }
182
- function listPlatforms() {
183
- const root = join(configDir(), "platforms");
184
- if (!existsSync(root)) return [];
185
- const state = readState();
186
- const out = [];
187
- for (const key of readdirSync(root)) {
188
- const baseUrl = decodeKey(key);
189
- if (!baseUrl) continue;
190
- const usersRoot = join(root, key, "users");
191
- if (!existsSync(usersRoot)) continue;
192
- const users = [];
193
- for (const userId of readdirSync(usersRoot)) {
194
- const token = readJson(join(usersRoot, userId, "token.json"));
195
- if (token) users.push({ userId, username: token.username, displayName: token.displayName });
196
- }
197
- if (users.length > 0) {
198
- out.push({ baseUrl, users, activeUserId: state.activeUsers?.[baseUrl] });
199
- }
200
- }
201
- return out;
202
- }
203
- function decodeKey(key) {
204
- try {
205
- const b64 = key.replace(/-/g, "+").replace(/_/g, "/");
206
- return Buffer.from(b64, "base64").toString("utf8");
207
- } catch {
208
- return null;
209
- }
210
- }
211
- function readJson(path) {
212
- if (!existsSync(path)) return void 0;
213
- try {
214
- return JSON.parse(readFileSync(path, "utf8"));
215
- } catch {
216
- return void 0;
217
- }
218
- }
219
- function writeJson(path, value, mode = 384) {
220
- const dir = path.slice(0, path.lastIndexOf("/")) || ".";
221
- mkdirSync(dir, { recursive: true, ...IS_WIN ? {} : { mode: 448 } });
222
- writeFileSync(path, `${JSON.stringify(value, null, 2)}
223
- `, IS_WIN ? {} : { mode });
224
- if (!IS_WIN) chmodSync(path, mode);
225
- }
226
-
227
- // src/config/resolve.ts
228
- function resolveContext(opts = {}) {
229
- const baseUrl = opts.baseUrl ?? process.env.BKN_BASE_URL ?? activePlatform();
230
- if (!baseUrl) {
231
- throw new InputError(
232
- "No base URL. Pass --base-url, set BKN_BASE_URL, or run `openbkn auth login`."
233
- );
234
- }
235
- const normalized = baseUrl.replace(/\/+$/, "");
236
- const stored = readToken(normalized);
237
- const explicit = opts.token ?? process.env.BKN_TOKEN;
238
- const token = explicit ?? stored?.accessToken ?? "";
239
- if (!token && !stored?.noAuth) {
240
- throw new InputError("No access token. Set BKN_TOKEN or run `openbkn auth login`.");
241
- }
242
- const insecure = opts.insecure ?? stored?.tlsInsecure ?? false;
243
- const refresh = !explicit && stored?.refreshToken ? {
244
- refreshToken: stored.refreshToken,
245
- persist: (t) => {
246
- writeToken(normalized, {
247
- ...stored,
248
- accessToken: t.accessToken,
249
- refreshToken: t.refreshToken ?? stored.refreshToken,
250
- idToken: t.idToken ?? stored.idToken
251
- });
252
- }
253
- } : void 0;
254
- return {
255
- baseUrl: normalized,
256
- token,
257
- businessDomain: opts.businessDomain ?? readPlatformConfig(normalized).businessDomain ?? DEFAULT_BUSINESS_DOMAIN,
258
- insecure,
259
- ...refresh ? { refresh } : {}
260
- };
261
- }
262
-
263
75
  // src/auth/oauth.ts
264
76
  import { spawn } from "child_process";
265
77
  function normalizeBaseUrl(value) {
@@ -520,6 +332,194 @@ async function tryRefresh(ctx) {
520
332
  }
521
333
  }
522
334
 
335
+ // src/types.ts
336
+ var DEFAULT_BUSINESS_DOMAIN = "bd_public";
337
+ var DEFAULT_LIST_LIMIT = 30;
338
+ var DEFAULT_QUERY_LIMIT = 50;
339
+
340
+ // src/config/store.ts
341
+ import {
342
+ chmodSync,
343
+ existsSync,
344
+ mkdirSync,
345
+ readFileSync,
346
+ readdirSync,
347
+ rmSync,
348
+ writeFileSync
349
+ } from "fs";
350
+ import { homedir } from "os";
351
+ import { join } from "path";
352
+
353
+ // src/auth/jwt.ts
354
+ function decodeJwt(token) {
355
+ const parts = token.split(".");
356
+ if (parts.length < 2 || !parts[1]) return void 0;
357
+ try {
358
+ const json = Buffer.from(parts[1], "base64url").toString("utf8");
359
+ return JSON.parse(json);
360
+ } catch {
361
+ return void 0;
362
+ }
363
+ }
364
+ function isExpired(claims, nowMs = Date.now()) {
365
+ return claims?.exp !== void 0 && claims.exp * 1e3 < nowMs;
366
+ }
367
+
368
+ // src/config/store.ts
369
+ var PROFILE_RE = /^[A-Za-z0-9_-]{1,64}$/;
370
+ var IS_WIN = process.platform === "win32";
371
+ function configDir() {
372
+ return process.env.BKN_CONFIG_DIR ?? join(homedir(), ".bkn");
373
+ }
374
+ function profileName() {
375
+ const raw = process.env.BKN_PROFILE?.trim();
376
+ if (!raw) return null;
377
+ if (!PROFILE_RE.test(raw)) {
378
+ throw new Error(`BKN_PROFILE='${raw}' is invalid. Use 1-64 chars from [A-Za-z0-9_-].`);
379
+ }
380
+ return raw;
381
+ }
382
+ function statePath() {
383
+ const profile = profileName();
384
+ return profile ? join(configDir(), "profiles", profile, "state.json") : join(configDir(), "state.json");
385
+ }
386
+ function encodeKey(baseUrl) {
387
+ return Buffer.from(baseUrl, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
388
+ }
389
+ function platformDir(baseUrl) {
390
+ return join(configDir(), "platforms", encodeKey(baseUrl));
391
+ }
392
+ function userDir(baseUrl, userId) {
393
+ return join(platformDir(baseUrl), "users", userId);
394
+ }
395
+ function userIdFromToken(token) {
396
+ return decodeJwt(token.idToken ?? "")?.sub ?? decodeJwt(token.accessToken)?.sub ?? "default";
397
+ }
398
+ function readState() {
399
+ return readJson(statePath()) ?? {};
400
+ }
401
+ function writeState(state) {
402
+ writeJson(statePath(), state);
403
+ }
404
+ function activePlatform() {
405
+ return readState().currentPlatform;
406
+ }
407
+ function setActivePlatform(baseUrl) {
408
+ writeState({ ...readState(), currentPlatform: baseUrl });
409
+ }
410
+ function activeUserId(baseUrl) {
411
+ return readState().activeUsers?.[baseUrl];
412
+ }
413
+ function setActiveUser(baseUrl, userId) {
414
+ const state = readState();
415
+ writeState({ ...state, activeUsers: { ...state.activeUsers, [baseUrl]: userId } });
416
+ }
417
+ function readToken(baseUrl, userId = activeUserId(baseUrl)) {
418
+ if (!userId) return void 0;
419
+ return readJson(join(userDir(baseUrl, userId), "token.json")) ?? void 0;
420
+ }
421
+ function writeToken(baseUrl, token) {
422
+ const userId = userIdFromToken(token);
423
+ writeJson(join(userDir(baseUrl, userId), "token.json"), token, 384);
424
+ setActiveUser(baseUrl, userId);
425
+ return userId;
426
+ }
427
+ function deleteToken(baseUrl, userId = activeUserId(baseUrl)) {
428
+ if (!userId) return false;
429
+ const path = join(userDir(baseUrl, userId), "token.json");
430
+ if (!existsSync(path)) return false;
431
+ rmSync(path, { force: true });
432
+ return true;
433
+ }
434
+ function readPlatformConfig(baseUrl, userId = activeUserId(baseUrl)) {
435
+ if (!userId) return {};
436
+ return readJson(join(userDir(baseUrl, userId), "config.json")) ?? {};
437
+ }
438
+ function writePlatformConfig(baseUrl, config) {
439
+ const userId = activeUserId(baseUrl) ?? "default";
440
+ writeJson(join(userDir(baseUrl, userId), "config.json"), config);
441
+ }
442
+ function listPlatforms() {
443
+ const root = join(configDir(), "platforms");
444
+ if (!existsSync(root)) return [];
445
+ const state = readState();
446
+ const out = [];
447
+ for (const key of readdirSync(root)) {
448
+ const baseUrl = decodeKey(key);
449
+ if (!baseUrl) continue;
450
+ const usersRoot = join(root, key, "users");
451
+ if (!existsSync(usersRoot)) continue;
452
+ const users = [];
453
+ for (const userId of readdirSync(usersRoot)) {
454
+ const token = readJson(join(usersRoot, userId, "token.json"));
455
+ if (token) users.push({ userId, username: token.username, displayName: token.displayName });
456
+ }
457
+ if (users.length > 0) {
458
+ out.push({ baseUrl, users, activeUserId: state.activeUsers?.[baseUrl] });
459
+ }
460
+ }
461
+ return out;
462
+ }
463
+ function decodeKey(key) {
464
+ try {
465
+ const b64 = key.replace(/-/g, "+").replace(/_/g, "/");
466
+ return Buffer.from(b64, "base64").toString("utf8");
467
+ } catch {
468
+ return null;
469
+ }
470
+ }
471
+ function readJson(path) {
472
+ if (!existsSync(path)) return void 0;
473
+ try {
474
+ return JSON.parse(readFileSync(path, "utf8"));
475
+ } catch {
476
+ return void 0;
477
+ }
478
+ }
479
+ function writeJson(path, value, mode = 384) {
480
+ const dir = path.slice(0, path.lastIndexOf("/")) || ".";
481
+ mkdirSync(dir, { recursive: true, ...IS_WIN ? {} : { mode: 448 } });
482
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}
483
+ `, IS_WIN ? {} : { mode });
484
+ if (!IS_WIN) chmodSync(path, mode);
485
+ }
486
+
487
+ // src/config/resolve.ts
488
+ function resolveContext(opts = {}) {
489
+ const baseUrl = opts.baseUrl ?? process.env.BKN_BASE_URL ?? activePlatform();
490
+ if (!baseUrl) {
491
+ throw new InputError(
492
+ "No base URL. Pass --base-url, set BKN_BASE_URL, or run `openbkn auth login`."
493
+ );
494
+ }
495
+ const normalized = baseUrl.replace(/\/+$/, "");
496
+ const stored = readToken(normalized);
497
+ const explicit = opts.token ?? process.env.BKN_TOKEN;
498
+ const token = explicit ?? stored?.accessToken ?? "";
499
+ if (!token && !stored?.noAuth) {
500
+ throw new InputError("No access token. Set BKN_TOKEN or run `openbkn auth login`.");
501
+ }
502
+ const insecure = opts.insecure ?? stored?.tlsInsecure ?? false;
503
+ const refresh = !explicit && stored?.refreshToken ? {
504
+ refreshToken: stored.refreshToken,
505
+ persist: (t) => {
506
+ writeToken(normalized, {
507
+ ...stored,
508
+ accessToken: t.accessToken,
509
+ refreshToken: t.refreshToken ?? stored.refreshToken,
510
+ idToken: t.idToken ?? stored.idToken
511
+ });
512
+ }
513
+ } : void 0;
514
+ return {
515
+ baseUrl: normalized,
516
+ token,
517
+ businessDomain: opts.businessDomain ?? readPlatformConfig(normalized).businessDomain ?? DEFAULT_BUSINESS_DOMAIN,
518
+ insecure,
519
+ ...refresh ? { refresh } : {}
520
+ };
521
+ }
522
+
523
523
  // src/api/safe.ts
524
524
  var ADMIN = "/api/safe/v1/admin";
525
525
  function notOnSafe(operation) {
@@ -4947,16 +4947,17 @@ async function rawCall(ctx, path, opts = {}) {
4947
4947
  if (!extra["content-type"]) extra["content-type"] = "application/json";
4948
4948
  }
4949
4949
  const method = opts.method ?? (body !== void 0 ? "POST" : "GET");
4950
- const headers2 = buildHeaders(
4951
- { ...ctx, businessDomain: opts.businessDomain ?? ctx.businessDomain },
4952
- extra
4953
- );
4950
+ const headersFor = () => buildHeaders({ ...ctx, businessDomain: opts.businessDomain ?? ctx.businessDomain }, extra);
4954
4951
  if (opts.verbose) process.stderr.write(`> ${method} ${url}
4955
4952
  `);
4956
4953
  const controller = new AbortController();
4957
4954
  const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 3e4);
4955
+ const send = () => fetch(url, { method, headers: headersFor(), body, signal: controller.signal });
4958
4956
  try {
4959
- const res = await fetch(url, { method, headers: headers2, body, signal: controller.signal });
4957
+ let res = await send();
4958
+ if (res.status === 401 && ctx.refresh && await tryRefresh(ctx)) {
4959
+ res = await send();
4960
+ }
4960
4961
  return { status: res.status, statusText: res.statusText, body: await res.text() };
4961
4962
  } finally {
4962
4963
  clearTimeout(timer);
@@ -4989,6 +4990,7 @@ __export(auth_exports, {
4989
4990
  attachNoAuth: () => attachNoAuth,
4990
4991
  attachToken: () => attachToken,
4991
4992
  currentToken: () => currentToken,
4993
+ currentTokenFresh: () => currentTokenFresh,
4992
4994
  deletePlatform: () => deletePlatform,
4993
4995
  exportCreds: () => exportCreds,
4994
4996
  hostOf: () => hostOf,
@@ -5055,6 +5057,30 @@ function currentToken() {
5055
5057
  if (!token) throw new InputError("Not logged in. Run `openbkn auth login <url> --token <t>`.");
5056
5058
  return token.accessToken;
5057
5059
  }
5060
+ async function currentTokenFresh() {
5061
+ const baseUrl = activePlatform();
5062
+ const token = baseUrl ? readToken(baseUrl) : void 0;
5063
+ if (!baseUrl || !token) {
5064
+ throw new InputError("Not logged in. Run `openbkn auth login <url> --token <t>`.");
5065
+ }
5066
+ const claims = decodeJwt(token.accessToken);
5067
+ const decodable = claims?.exp !== void 0;
5068
+ const needsRefresh = decodable ? isExpired(claims) : true;
5069
+ if (token.refreshToken && needsRefresh) {
5070
+ try {
5071
+ const t = await refreshAccessToken(baseUrl, token.refreshToken);
5072
+ writeToken(baseUrl, {
5073
+ ...token,
5074
+ accessToken: t.accessToken,
5075
+ refreshToken: t.refreshToken ?? token.refreshToken,
5076
+ idToken: t.idToken ?? token.idToken
5077
+ });
5078
+ return t.accessToken;
5079
+ } catch {
5080
+ }
5081
+ }
5082
+ return token.accessToken;
5083
+ }
5058
5084
  function whoami() {
5059
5085
  const baseUrl = activePlatform();
5060
5086
  const token = baseUrl ? readToken(baseUrl) : void 0;
@@ -5125,26 +5151,26 @@ function exportCreds() {
5125
5151
  }
5126
5152
 
5127
5153
  export {
5128
- rawCall,
5129
- DEFAULT_BUSINESS_DOMAIN,
5130
- DEFAULT_LIST_LIMIT,
5131
- DEFAULT_QUERY_LIMIT,
5132
5154
  HttpError,
5133
5155
  InputError,
5134
5156
  toExitCode,
5135
5157
  formatError,
5136
- decodeJwt,
5137
- activePlatform,
5138
- setActivePlatform,
5139
- readPlatformConfig,
5140
- writePlatformConfig,
5141
- resolveContext,
5142
5158
  isHeadless,
5143
5159
  openBrowser,
5144
5160
  fetchAuthStatus,
5145
5161
  deviceLogin,
5146
5162
  credentialDeviceLogin,
5147
5163
  request,
5164
+ rawCall,
5165
+ DEFAULT_BUSINESS_DOMAIN,
5166
+ DEFAULT_LIST_LIMIT,
5167
+ DEFAULT_QUERY_LIMIT,
5168
+ decodeJwt,
5169
+ activePlatform,
5170
+ setActivePlatform,
5171
+ readPlatformConfig,
5172
+ writePlatformConfig,
5173
+ resolveContext,
5148
5174
  getUserSafe,
5149
5175
  admin,
5150
5176
  agents,
@@ -5165,6 +5191,7 @@ export {
5165
5191
  attachNoAuth,
5166
5192
  status,
5167
5193
  currentToken,
5194
+ currentTokenFresh,
5168
5195
  whoami,
5169
5196
  listPlatforms2 as listPlatforms,
5170
5197
  use,
@@ -5174,4 +5201,4 @@ export {
5174
5201
  exportCreds,
5175
5202
  auth_exports
5176
5203
  };
5177
- //# sourceMappingURL=chunk-GAYXY7LP.js.map
5204
+ //# sourceMappingURL=chunk-DTU5DGJW.js.map