@openbkn/bkn-sdk 0.1.1-alpha.18 → 0.1.1-alpha.19

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/dist/cli.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  HttpError,
7
7
  InputError,
8
8
  activePlatform,
9
- attachNoAuth,
10
9
  attachToken,
10
+ changePasswordSafe,
11
11
  createClient,
12
12
  credentialDeviceLogin,
13
13
  currentToken,
@@ -16,7 +16,6 @@ import {
16
16
  deletePlatform,
17
17
  deviceLogin,
18
18
  exportCreds,
19
- fetchAuthStatus,
20
19
  formatError,
21
20
  getUserSafe,
22
21
  isHeadless,
@@ -28,7 +27,6 @@ import {
28
27
  rawCall,
29
28
  readPlatformConfig,
30
29
  renderReportMarkdown,
31
- request,
32
30
  resolveContext,
33
31
  setActivePlatform,
34
32
  status,
@@ -37,7 +35,7 @@ import {
37
35
  use,
38
36
  whoami,
39
37
  writePlatformConfig
40
- } from "./chunk-LCOMMFH7.js";
38
+ } from "./chunk-ISJHU26W.js";
41
39
 
42
40
  // src/cli.ts
43
41
  import { Command as Command17 } from "commander";
@@ -45,10 +43,10 @@ import { Command as Command17 } from "commander";
45
43
  // package.json
46
44
  var package_default = {
47
45
  name: "@openbkn/bkn-sdk",
48
- version: "0.1.1-alpha.18",
46
+ version: "0.1.1-alpha.19",
49
47
  description: "Unified TypeScript SDK + CLI for the BKN (Business Knowledge Network) platform.",
50
48
  type: "module",
51
- license: "SEE LICENSE IN LICENSE",
49
+ license: "Apache-2.0",
52
50
  engines: {
53
51
  node: ">=18"
54
52
  },
@@ -63,7 +61,7 @@ var package_default = {
63
61
  import: "./dist/index.js"
64
62
  }
65
63
  },
66
- files: ["dist", "README.md", "README.zh.md", "LICENSE", "NOTICE"],
64
+ files: ["dist", "!dist/**/*.map", "README.md", "README.zh.md", "LICENSE", "NOTICE"],
67
65
  publishConfig: {
68
66
  access: "public"
69
67
  },
@@ -76,7 +74,8 @@ var package_default = {
76
74
  build: "tsup",
77
75
  dev: "tsup --watch",
78
76
  typecheck: "tsc --noEmit",
79
- lint: "biome check . && tsc --noEmit",
77
+ "check:deps": "node scripts/check-no-self-dep.mjs",
78
+ lint: "npm run check:deps && biome check . && tsc --noEmit",
80
79
  format: "biome format --write .",
81
80
  test: "vitest run",
82
81
  "test:cover": "vitest run --coverage",
@@ -85,12 +84,12 @@ var package_default = {
85
84
  },
86
85
  dependencies: {
87
86
  "@clack/prompts": "^0.9.1",
88
- "@openbkn/bkn-sdk": "^0.1.1-alpha.3",
89
87
  chalk: "^5.4.1",
90
88
  commander: "^13.1.0",
91
89
  "csv-parse": "^6.2.1",
92
90
  "js-yaml": "^4.2.0",
93
91
  jszip: "^3.10.1",
92
+ undici: "^8.7.0",
94
93
  zod: "^3.24.1"
95
94
  },
96
95
  devDependencies: {
@@ -353,25 +352,6 @@ function readBody(opts) {
353
352
 
354
353
  // src/commands/auth.ts
355
354
  import { Command } from "commander";
356
-
357
- // src/api/eacp-crypto.ts
358
- import {
359
- constants,
360
- createPrivateKey,
361
- createPublicKey,
362
- publicEncrypt
363
- } from "crypto";
364
-
365
- // src/api/admin.ts
366
- async function changePasswordSafe(ctx, account, oldPassword, newPassword) {
367
- await request(ctx, "/api/safe/v1/auth/change-password", {
368
- method: "POST",
369
- body: { account, old_password: oldPassword, new_password: newPassword }
370
- });
371
- return { ok: true };
372
- }
373
-
374
- // src/commands/auth.ts
375
355
  async function resolveAccount(baseUrl, accessToken, insecure, idToken) {
376
356
  const sub = decodeJwt(idToken ?? accessToken)?.sub;
377
357
  if (!sub) return void 0;
@@ -400,25 +380,17 @@ function renderSessions(items) {
400
380
  return lines.join("\n") || "(no saved sessions)";
401
381
  }
402
382
  function registerAuthLeaves(cmd) {
403
- cmd.command("login <url>").description("Log in to a platform (attach a token, or browser/password OAuth)").option("-u, --username <name>", "username for password signin").option("-p, --password <pwd>", "password for password signin").option("--token <token>", "provide a token directly (CI / headless)").option("--client-id <id>", "use a fixed OAuth2 client id (skip dynamic registration)").option("--client-secret <secret>", "OAuth2 client secret (omit for public/PKCE)").option(
404
- "--port <n>",
405
- "loopback redirect port for the auth_code flow",
406
- (v) => Number.parseInt(v, 10)
407
- ).option("--device", "headless device-code login (RFC 8628) \u2014 no callback server, no password").option("--audience <aud>", "device-code token audience", "bkn-safe").option(
383
+ cmd.command("login <url>").description("Log in to a platform (attach a token, or browser/password OAuth)").option("-u, --username <name>", "username for password signin").option("-p, --password <pwd>", "password for password signin").option("--token <token>", "provide a token directly (CI / headless)").option("--client-id <id>", "OAuth2 client id to authenticate as").option("--device", "headless device-code login (RFC 8628) \u2014 no callback server, no password").option("--audience <aud>", "device-code token audience", "bkn-safe").option(
408
384
  "--timeout <s>",
409
385
  "device-login wait before timing out",
410
386
  (v) => Number.parseInt(v, 10),
411
387
  120
412
- ).option("--no-browser", "(legacy) print the URL instead of opening a browser").option("--product <name>", "(legacy) ISF OAuth product query").option("--signin-public-key-file <path>", "(legacy) RSA public key for ISF /oauth2/signin").option("--no-auth", "register the platform with no authentication (no bkn-safe)").action(async (url, opts, cmd2) => {
388
+ ).option("--no-browser", "print the URL instead of opening a browser").action(async (url, opts, cmd2) => {
413
389
  const g = cmd2.optsWithGlobals();
414
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
415
390
  const out = outputOptions(cmd2);
416
391
  const report = (r) => {
417
392
  if (out.json || out.compact) {
418
393
  printJson({ loggedIn: true, ...r }, out);
419
- } else if (r.noAuth) {
420
- process.stdout.write(`Registered ${r.baseUrl ?? url} (no authentication)
421
- `);
422
394
  } else {
423
395
  process.stdout.write(`Logged in to ${r.baseUrl ?? url} as ${r.username ?? r.userId}
424
396
  `);
@@ -426,20 +398,7 @@ function registerAuthLeaves(cmd) {
426
398
  };
427
399
  const token = opts.token ?? g.token;
428
400
  if (token) {
429
- report(attachToken(url, token, { insecure: g.insecure }));
430
- return;
431
- }
432
- if (opts.auth === false) {
433
- report(attachNoAuth(url, { insecure: g.insecure }));
434
- return;
435
- }
436
- const authStatus = await fetchAuthStatus(url);
437
- if (authStatus && !authStatus.enabled) {
438
- process.stderr.write(
439
- `Platform auth is disabled (stack: ${authStatus.stack ?? "none"}) \u2014 registering without auth.
440
- `
441
- );
442
- report(attachNoAuth(url, { insecure: g.insecure }));
401
+ report(attachToken(url, token));
443
402
  return;
444
403
  }
445
404
  let tokens;
@@ -452,7 +411,8 @@ function registerAuthLeaves(cmd) {
452
411
  tokens = await credentialDeviceLogin(url, username, password, {
453
412
  clientId: opts.clientId,
454
413
  audience: opts.audience,
455
- timeoutMs: opts.timeout * 1e3
414
+ timeoutMs: opts.timeout * 1e3,
415
+ insecure: g.insecure
456
416
  });
457
417
  } else {
458
418
  const headless = isHeadless();
@@ -461,6 +421,7 @@ function registerAuthLeaves(cmd) {
461
421
  clientId: opts.clientId,
462
422
  audience: opts.audience,
463
423
  timeoutMs: opts.timeout * 1e3,
424
+ insecure: g.insecure,
464
425
  onPrompt: ({ userCode, verificationUri, verificationUriComplete }) => {
465
426
  const target = verificationUriComplete ?? verificationUri;
466
427
  process.stderr.write(
@@ -479,9 +440,9 @@ User code: ${userCode}
479
440
  }
480
441
  } catch (e) {
481
442
  if (e instanceof Error && /Device auth failed \(404\)/.test(e.message)) {
482
- process.stderr.write("No auth endpoint found \u2014 registering platform without auth.\n");
483
- report(attachNoAuth(url, { insecure: g.insecure }));
484
- return;
443
+ throw new InputError(
444
+ `No auth endpoint on ${url} \u2014 the platform has no bkn-safe auth stack. Deploy bkn-safe, or log in elsewhere and pass the token with \`--token\`.`
445
+ );
485
446
  }
486
447
  throw e;
487
448
  }
@@ -497,29 +458,28 @@ User code: ${userCode}
497
458
  attachToken(url, tokens.accessToken, {
498
459
  refreshToken: tokens.refreshToken,
499
460
  idToken: tokens.idToken,
500
- insecure: g.insecure,
501
461
  username: account
502
462
  })
503
463
  );
504
464
  });
505
- cmd.command("status").description("Show base URL and whether a token is configured").action((_opts, cmd2) => printJson(status(), outputOptions(cmd2)));
465
+ cmd.command("status").description("Show base URL and whether a token is configured").action(
466
+ (_opts, cmd2) => printJson(status({ user: cmd2.optsWithGlobals().user }), outputOptions(cmd2))
467
+ );
506
468
  cmd.command("token").description("Print the current access token, refreshing it if expired (keep secret)").option("--no-refresh", "print the stored token as-is, without refreshing").action(async (opts, cmd2) => {
507
469
  const g = cmd2.optsWithGlobals();
508
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
509
- const token = opts.refresh === false ? currentToken() : await currentTokenFresh();
470
+ const token = opts.refresh === false ? currentToken({ user: g.user }) : await currentTokenFresh({ insecure: g.insecure, user: g.user });
510
471
  process.stdout.write(`${token}
511
472
  `);
512
473
  });
513
474
  cmd.command("whoami [url]").description("Show current user identity (from the token)").option("--no-lookup", "skip the backend identity fallback (eacp/user/get)").action(async (_url, opts, cmd2) => {
514
475
  const g = cmd2.optsWithGlobals();
515
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
516
- const me = whoami();
476
+ const me = whoami({ user: g.user });
517
477
  if (opts.lookup !== false && me.baseUrl && me.sub) {
518
478
  try {
519
479
  const u = await getUserSafe(
520
480
  {
521
481
  baseUrl: me.baseUrl,
522
- token: currentToken(),
482
+ token: currentToken({ user: g.user }),
523
483
  businessDomain: DEFAULT_BUSINESS_DOMAIN,
524
484
  insecure: Boolean(g.insecure)
525
485
  },
@@ -584,9 +544,8 @@ User code: ${userCode}
584
544
  cmd.command("export").description("Export the active session's tokens (for a headless host)").action((_opts, cmd2) => {
585
545
  printJson(exportCreds(), outputOptions(cmd2));
586
546
  });
587
- cmd.command("change-password [url]").description("Change your account password (bkn-safe self-service; no browser)").option("-a, --account <name>", "account / login name (the login column, e.g. admin)").option("--old-password <pwd>", "current password").option("--new-password <pwd>", "new password").option("--public-key-file <path>", "(legacy) RSA public key for ISF password encryption").action(async (url, opts, cmd2) => {
547
+ cmd.command("change-password [url]").description("Change your account password (bkn-safe self-service; no browser)").option("-a, --account <name>", "account / login name (the login column, e.g. admin)").option("--old-password <pwd>", "current password").option("--new-password <pwd>", "new password").action(async (url, opts, cmd2) => {
588
548
  const g = cmd2.optsWithGlobals();
589
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
590
549
  const ctx = resolveContext({
591
550
  baseUrl: url ?? g.baseUrl,
592
551
  token: g.token,
package/dist/index.d.ts CHANGED
@@ -107,12 +107,16 @@ type LicenseImportResult = LicenseDetail | {
107
107
  };
108
108
 
109
109
  /**
110
- * Admin (operator) client — user-management + authorization.
111
- * Reads and writes (org/user create/update/delete +
112
- * reset-password) implemented; org/user detail and writes go through ISFWeb
113
- * thrift where the REST routes are RegisterPrivate. Passed through as JSON.
110
+ * Admin (operator) input shapes — the CLI-facing contract for the `admin`
111
+ * command group. `src/resources/admin.ts` maps each of these onto the bkn-safe
112
+ * client in `./safe.ts`, which is where the requests live.
113
+ *
114
+ * The ISF clients that used to back these types (`/api/user-management/v1`,
115
+ * `/api/authorization/v1`, `/isfweb/api/ShareMgnt`, `/api/eacp/v1`) were removed
116
+ * once ISF was retired — see docs/exec-plans/admin-bkn-safe-migration.md. Some
117
+ * fields here are wider than bkn-safe accepts and are dropped in the mapping;
118
+ * that lossiness is documented in the migration plan.
114
119
  */
115
-
116
120
  interface AdminListOptions {
117
121
  role?: string;
118
122
  offset?: number;
@@ -1225,16 +1229,20 @@ interface TokenConfig {
1225
1229
  refreshToken?: string;
1226
1230
  idToken?: string;
1227
1231
  expiresAt?: string;
1228
- /** Skip TLS verification for this platform (saved by `auth login -k`). */
1229
- tlsInsecure?: boolean;
1230
- /** Platform has no auth stack (no bkn-safe) — requests carry no token. */
1231
- noAuth?: boolean;
1232
1232
  /** Login name persisted at login time (fallback when JWT lacks claims). */
1233
1233
  username?: string;
1234
1234
  /** Human-readable name from userinfo. */
1235
1235
  displayName?: string;
1236
1236
  }
1237
- /** userId from the token's JWT `sub` (id_token first), else "default". */
1237
+ /**
1238
+ * userId from the token's JWT `sub` (id_token first), else "default".
1239
+ *
1240
+ * The `sub` is attacker-supplied — the JWT is never signature-checked — and it
1241
+ * becomes a path segment under `userDir`. An unconstrained one escapes the
1242
+ * store: `sub: "../../<other-platform>/users/default"` overwrites another
1243
+ * platform's saved token, so the victim's later commands there authenticate as
1244
+ * whoever issued this token. Constrain it the way BKN_PROFILE is constrained.
1245
+ */
1238
1246
  declare function userIdFromToken(token: TokenConfig): string;
1239
1247
  interface PlatformUser {
1240
1248
  userId: string;
@@ -1253,20 +1261,12 @@ declare function hostOf(baseUrl: string): string;
1253
1261
  declare function attachToken(baseUrl: string, accessToken: string, opts?: {
1254
1262
  refreshToken?: string;
1255
1263
  idToken?: string;
1256
- insecure?: boolean;
1257
1264
  username?: string;
1258
1265
  }): {
1259
1266
  baseUrl: string;
1260
1267
  userId: string;
1261
1268
  username?: string;
1262
1269
  };
1263
- /** Register a no-auth platform session (no token; the platform has no bkn-safe). */
1264
- declare function attachNoAuth(baseUrl: string, opts?: {
1265
- insecure?: boolean;
1266
- }): {
1267
- baseUrl: string;
1268
- noAuth: true;
1269
- };
1270
1270
  interface AuthStatus {
1271
1271
  baseUrl?: string;
1272
1272
  userId?: string;
@@ -1274,15 +1274,22 @@ interface AuthStatus {
1274
1274
  username?: string;
1275
1275
  expired?: boolean;
1276
1276
  }
1277
- declare function status(): AuthStatus;
1278
- declare function currentToken(): string;
1277
+ declare function status(opts?: {
1278
+ user?: string;
1279
+ }): AuthStatus;
1280
+ declare function currentToken(opts?: {
1281
+ user?: string;
1282
+ }): string;
1279
1283
  /**
1280
1284
  * Like {@link currentToken} but proactively refreshes an expired access token
1281
1285
  * when a refresh token is stored, persisting the result. API requests already
1282
1286
  * refresh on a 401 (see api/http.ts); this covers the `auth token` getter,
1283
1287
  * whose output is copied out and used elsewhere where no 401 retry can help.
1284
1288
  */
1285
- declare function currentTokenFresh(): Promise<string>;
1289
+ declare function currentTokenFresh(opts?: {
1290
+ insecure?: boolean;
1291
+ user?: string;
1292
+ }): Promise<string>;
1286
1293
  interface WhoamiResult extends JwtClaims {
1287
1294
  /** Platform the active session belongs to. */
1288
1295
  baseUrl?: string;
@@ -1291,7 +1298,9 @@ interface WhoamiResult extends JwtClaims {
1291
1298
  /** Resolved account/login name — what `auth login` looked up and stored. */
1292
1299
  username?: string;
1293
1300
  }
1294
- declare function whoami(): WhoamiResult;
1301
+ declare function whoami(opts?: {
1302
+ user?: string;
1303
+ }): WhoamiResult;
1295
1304
  interface PlatformListItem {
1296
1305
  baseUrl: string;
1297
1306
  userId: string;
@@ -1326,7 +1335,6 @@ declare function exportCreds(): {
1326
1335
  type auth_AuthStatus = AuthStatus;
1327
1336
  type auth_PlatformListItem = PlatformListItem;
1328
1337
  type auth_WhoamiResult = WhoamiResult;
1329
- declare const auth_attachNoAuth: typeof attachNoAuth;
1330
1338
  declare const auth_attachToken: typeof attachToken;
1331
1339
  declare const auth_currentToken: typeof currentToken;
1332
1340
  declare const auth_currentTokenFresh: typeof currentTokenFresh;
@@ -1342,7 +1350,7 @@ declare const auth_userIdFromToken: typeof userIdFromToken;
1342
1350
  declare const auth_usersOf: typeof usersOf;
1343
1351
  declare const auth_whoami: typeof whoami;
1344
1352
  declare namespace auth {
1345
- export { type auth_AuthStatus as AuthStatus, type auth_PlatformListItem as PlatformListItem, type auth_WhoamiResult as WhoamiResult, auth_attachNoAuth as attachNoAuth, auth_attachToken as attachToken, auth_currentToken as currentToken, auth_currentTokenFresh as currentTokenFresh, auth_deletePlatform as deletePlatform, auth_exportCreds as exportCreds, auth_hostOf as hostOf, auth_listPlatforms as listPlatforms, auth_logout as logout, auth_status as status, auth_switchUser as switchUser, auth_use as use, auth_userIdFromToken as userIdFromToken, auth_usersOf as usersOf, auth_whoami as whoami };
1353
+ export { type auth_AuthStatus as AuthStatus, type auth_PlatformListItem as PlatformListItem, type auth_WhoamiResult as WhoamiResult, auth_attachToken as attachToken, auth_currentToken as currentToken, auth_currentTokenFresh as currentTokenFresh, auth_deletePlatform as deletePlatform, auth_exportCreds as exportCreds, auth_hostOf as hostOf, auth_listPlatforms as listPlatforms, auth_logout as logout, auth_status as status, auth_switchUser as switchUser, auth_use as use, auth_userIdFromToken as userIdFromToken, auth_usersOf as usersOf, auth_whoami as whoami };
1346
1354
  }
1347
1355
 
1348
1356
  interface RequestInitEx {
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  toolboxes,
20
20
  trace,
21
21
  vega
22
- } from "./chunk-LCOMMFH7.js";
22
+ } from "./chunk-ISJHU26W.js";
23
23
  export {
24
24
  DEFAULT_BUSINESS_DOMAIN,
25
25
  DEFAULT_LIST_LIMIT,
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@openbkn/bkn-sdk",
3
- "version": "0.1.1-alpha.18",
3
+ "version": "0.1.1-alpha.19",
4
4
  "description": "Unified TypeScript SDK + CLI for the BKN (Business Knowledge Network) platform.",
5
5
  "type": "module",
6
- "license": "SEE LICENSE IN LICENSE",
6
+ "license": "Apache-2.0",
7
7
  "engines": {
8
8
  "node": ">=18"
9
9
  },
@@ -18,7 +18,7 @@
18
18
  "import": "./dist/index.js"
19
19
  }
20
20
  },
21
- "files": ["dist", "README.md", "README.zh.md", "LICENSE", "NOTICE"],
21
+ "files": ["dist", "!dist/**/*.map", "README.md", "README.zh.md", "LICENSE", "NOTICE"],
22
22
  "publishConfig": {
23
23
  "access": "public"
24
24
  },
@@ -31,7 +31,8 @@
31
31
  "build": "tsup",
32
32
  "dev": "tsup --watch",
33
33
  "typecheck": "tsc --noEmit",
34
- "lint": "biome check . && tsc --noEmit",
34
+ "check:deps": "node scripts/check-no-self-dep.mjs",
35
+ "lint": "npm run check:deps && biome check . && tsc --noEmit",
35
36
  "format": "biome format --write .",
36
37
  "test": "vitest run",
37
38
  "test:cover": "vitest run --coverage",
@@ -40,12 +41,12 @@
40
41
  },
41
42
  "dependencies": {
42
43
  "@clack/prompts": "^0.9.1",
43
- "@openbkn/bkn-sdk": "^0.1.1-alpha.3",
44
44
  "chalk": "^5.4.1",
45
45
  "commander": "^13.1.0",
46
46
  "csv-parse": "^6.2.1",
47
47
  "js-yaml": "^4.2.0",
48
48
  "jszip": "^3.10.1",
49
+ "undici": "^8.7.0",
49
50
  "zod": "^3.24.1"
50
51
  },
51
52
  "devDependencies": {