@tinycloud/cli 0.7.0-beta.8 → 0.7.0-beta.9

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/index.js CHANGED
@@ -816,12 +816,19 @@ function buildAuthUrl(did, options = {}) {
816
816
  if (options.host) {
817
817
  params.set("host", options.host);
818
818
  }
819
+ const reason = typeof options.reason === "string" ? options.reason.trim() : "";
819
820
  if (options.permissions?.length) {
820
821
  params.set(
821
822
  "permissions",
822
- Buffer.from(JSON.stringify({ permissions: options.permissions })).toString("base64url")
823
+ Buffer.from(JSON.stringify({
824
+ permissions: options.permissions,
825
+ ...reason ? { reason } : {}
826
+ })).toString("base64url")
823
827
  );
824
828
  }
829
+ if (reason) {
830
+ params.set("reason", reason);
831
+ }
825
832
  if (options.expiry !== void 0) {
826
833
  params.set("expiry", String(options.expiry));
827
834
  }
@@ -11391,6 +11398,10 @@ function registerAuthCommand(program2) {
11391
11398
  jwk: key,
11392
11399
  host: ctx.host,
11393
11400
  permissions: group,
11401
+ reason: permissionGrantReason(
11402
+ "Grant requested TinyCloud permissions from `tc auth request --grant`.",
11403
+ group
11404
+ ),
11394
11405
  openkeyHost,
11395
11406
  expiry: expiryOption,
11396
11407
  noPopup: options.popup === false
@@ -11535,6 +11546,7 @@ function registerAuthCommand(program2) {
11535
11546
  node,
11536
11547
  requested: parsed.requested,
11537
11548
  expiryOption: parsed.requestedExpiry,
11549
+ reason: "Grant permissions requested by a TinyCloud auth request artifact.",
11538
11550
  yes: options.yes === true
11539
11551
  });
11540
11552
  const grant = await grantAuthRequest(node, parsed);
@@ -11818,6 +11830,7 @@ async function ensureDelegationAuthority(params) {
11818
11830
  jwk: key,
11819
11831
  host: params.ctx.host,
11820
11832
  permissions: group,
11833
+ reason: permissionGrantReason(params.reason, group),
11821
11834
  openkeyHost,
11822
11835
  expiry: params.expiryOption
11823
11836
  });
@@ -11865,6 +11878,12 @@ async function ensureDelegationAuthority(params) {
11865
11878
  });
11866
11879
  }
11867
11880
  }
11881
+ function permissionGrantReason(context, permissions) {
11882
+ const first = permissions[0];
11883
+ const summary = first ? compactPermission(first) : "no permissions";
11884
+ const more = permissions.length > 1 ? ` and ${permissions.length - 1} more permission${permissions.length === 2 ? "" : "s"}` : "";
11885
+ return `${context} Requested: ${summary}${more}.`;
11886
+ }
11868
11887
  function execCapturedCommand(command) {
11869
11888
  return new Promise((resolve3, reject) => {
11870
11889
  const child = spawn(process.execPath, [process.argv[1], ...command.argv], {
@@ -13541,12 +13560,17 @@ async function runSecretOperation(params) {
13541
13560
  node: params.node,
13542
13561
  requested,
13543
13562
  expiryOption: void 0,
13563
+ reason: secretPermissionReason(params.action, params.name),
13544
13564
  yes: true,
13545
13565
  force: true
13546
13566
  })
13547
13567
  );
13548
13568
  return runSecretOperationAttempt(params.label, params.operation);
13549
13569
  }
13570
+ function secretPermissionReason(action, name) {
13571
+ const target = name ? ` secret "${name}"` : " secrets";
13572
+ return `Allow \`tc secrets ${action}${name ? ` ${name}` : ""}\` to access${target} with the required TinyCloud permissions.`;
13573
+ }
13550
13574
  async function runSecretOperationAttempt(label, operation) {
13551
13575
  try {
13552
13576
  return await withSpinner(label, operation);
@@ -15479,7 +15503,7 @@ import open from "open";
15479
15503
  import { readFile as readFile10 } from "fs/promises";
15480
15504
  var ACCOUNT_BILLING_URL = "https://account.tinycloud.xyz/billing";
15481
15505
  function registerAccountCommand(program2) {
15482
- const account = program2.command("account").description("Account applications, delegations, and billing");
15506
+ const account = program2.command("account").description("Account applications, spaces, delegations, and billing");
15483
15507
  account.command("status").description("Show account status").action(async (_options, cmd) => {
15484
15508
  try {
15485
15509
  const node = await authenticatedNode(cmd);
@@ -15491,11 +15515,11 @@ function registerAccountCommand(program2) {
15491
15515
  }
15492
15516
  });
15493
15517
  const apps = account.command("apps").description("Manage account application registry");
15494
- apps.command("list").description("List applications registered under account/applications").option("--index", "Read from the materialized account SQLite index").action(async (_options, cmd) => {
15518
+ apps.command("list").description("List applications registered under account/applications").option("--live", "Read canonical account KV records instead of the SQLite index").action(async (_options, cmd) => {
15495
15519
  try {
15496
15520
  const options = _options;
15497
15521
  const node = await authenticatedNode(cmd);
15498
- const result = options.index ? await node.account.index.applications.list() : await node.account.applications.list();
15522
+ const result = options.live ? await node.account.applications.list() : await node.account.index.applications.list();
15499
15523
  assertOk(result);
15500
15524
  const payload = { applications: result.data, count: result.data.length };
15501
15525
  if (shouldOutputJson()) {
@@ -15521,6 +15545,84 @@ function registerAccountCommand(program2) {
15521
15545
  handleError(error);
15522
15546
  }
15523
15547
  });
15548
+ const spaces = account.command("spaces").description("Manage account space registry");
15549
+ spaces.command("list").description("List spaces registered under account/spaces").option("--live", "Read canonical account KV records instead of the SQLite index").action(async (options, cmd) => {
15550
+ try {
15551
+ const node = await authenticatedNode(cmd);
15552
+ const result = options.live ? await node.account.spaces.list() : await node.account.index.spaces.list();
15553
+ assertOk(result);
15554
+ const payload = { spaces: result.data.map(formatSpace), count: result.data.length };
15555
+ if (shouldOutputJson()) {
15556
+ outputJson(payload);
15557
+ return;
15558
+ }
15559
+ if (result.data.length === 0) {
15560
+ process.stdout.write(theme.muted("No account spaces registered.") + "\n");
15561
+ return;
15562
+ }
15563
+ process.stdout.write(
15564
+ formatTable(
15565
+ ["Space", "Type", "Owner", "Status", "Updated"],
15566
+ result.data.map((space) => [
15567
+ space.name,
15568
+ space.type,
15569
+ space.ownerDid,
15570
+ space.status,
15571
+ space.updatedAt ?? "\u2014"
15572
+ ])
15573
+ ) + "\n"
15574
+ );
15575
+ } catch (error) {
15576
+ handleError(error);
15577
+ }
15578
+ });
15579
+ spaces.command("info <space-id>").description("Show a registered account space").action(async (spaceId, _options, cmd) => {
15580
+ try {
15581
+ const node = await authenticatedNode(cmd);
15582
+ const result = await node.account.spaces.get(spaceId);
15583
+ assertOk(result);
15584
+ outputJson(formatSpace(result.data));
15585
+ } catch (error) {
15586
+ handleError(error);
15587
+ }
15588
+ });
15589
+ spaces.command("register <space-id>").description("Register a space in account/spaces").requiredOption("--name <name>", "Display name for the space").requiredOption("--owner <did>", "Owner DID for the space").option("--type <type>", "Space type: owned, delegated, or discovered", "discovered").option("--permission <permission...>", "Permission strings for the space").action(async (spaceId, options, cmd) => {
15590
+ try {
15591
+ const node = await authenticatedNode(cmd);
15592
+ const result = await node.account.spaces.register({
15593
+ spaceId,
15594
+ name: options.name,
15595
+ ownerDid: options.owner,
15596
+ type: options.type,
15597
+ permissions: options.permission ?? [],
15598
+ status: "active"
15599
+ });
15600
+ assertOk(result);
15601
+ outputJson({ space: formatSpace(result.data), registered: true });
15602
+ } catch (error) {
15603
+ handleError(error);
15604
+ }
15605
+ });
15606
+ spaces.command("sync").description("Register currently accessible spaces into account/spaces").action(async (_options, cmd) => {
15607
+ try {
15608
+ const node = await authenticatedNode(cmd);
15609
+ const result = await node.account.spaces.syncAccessible();
15610
+ assertOk(result);
15611
+ outputJson({ spaces: result.data.map(formatSpace), count: result.data.length, synced: true });
15612
+ } catch (error) {
15613
+ handleError(error);
15614
+ }
15615
+ });
15616
+ spaces.command("remove <space-id>").alias("delete").description("Remove a space registry entry").action(async (spaceId, _options, cmd) => {
15617
+ try {
15618
+ const node = await authenticatedNode(cmd);
15619
+ const result = await node.account.spaces.remove(spaceId);
15620
+ assertOk(result);
15621
+ outputJson({ spaceId, removed: true });
15622
+ } catch (error) {
15623
+ handleError(error);
15624
+ }
15625
+ });
15524
15626
  apps.command("info <app-id>").description("Show a registered account application").action(async (appId, _options, cmd) => {
15525
15627
  try {
15526
15628
  const node = await authenticatedNode(cmd);
@@ -15553,14 +15655,14 @@ function registerAccountCommand(program2) {
15553
15655
  }
15554
15656
  });
15555
15657
  const delegations = account.command("delegations").description("View and revoke account delegations");
15556
- delegations.command("list").description("List delegations granted by or to this account").option("--granted", "Show only delegations granted by this account").option("--received", "Show only delegations granted to this account").option("--space <space>", "Filter by space name or ID").option("--index", "Read from the materialized account SQLite index").action(async (options, cmd) => {
15658
+ delegations.command("list").description("List delegations granted by or to this account").option("--granted", "Show only delegations granted by this account").option("--received", "Show only delegations granted to this account").option("--space <space>", "Filter by space name or ID").option("--live", "Read live delegation services instead of the SQLite index").action(async (options, cmd) => {
15557
15659
  try {
15558
15660
  if (options.granted && options.received) {
15559
15661
  throw new CLIError("USAGE_ERROR", "Use only one of --granted or --received.", ExitCode.USAGE_ERROR);
15560
15662
  }
15561
15663
  const node = await authenticatedNode(cmd);
15562
15664
  const direction = options.granted ? "granted" : options.received ? "received" : "all";
15563
- const result = options.index ? await node.account.index.delegations.list({ direction, space: options.space }) : await node.account.delegations.list({ direction, space: options.space });
15665
+ const result = options.live ? await node.account.delegations.list({ direction, space: options.space }) : await node.account.index.delegations.list({ direction, space: options.space });
15564
15666
  assertOk(result);
15565
15667
  const payload = { delegations: result.data.map(formatDelegation2), count: result.data.length };
15566
15668
  if (shouldOutputJson()) {
@@ -15599,6 +15701,16 @@ function registerAccountCommand(program2) {
15599
15701
  }
15600
15702
  });
15601
15703
  const index = account.command("index").description("Manage the materialized account SQLite index");
15704
+ index.command("status").description("Show account SQLite index sync status").action(async (_options, cmd) => {
15705
+ try {
15706
+ const node = await authenticatedNode(cmd);
15707
+ const result = await node.account.index.status();
15708
+ assertOk(result);
15709
+ outputJson(result.data);
15710
+ } catch (error) {
15711
+ handleError(error);
15712
+ }
15713
+ });
15602
15714
  index.command("rebuild").description("Rebuild account SQLite index from canonical account data").action(async (_options, cmd) => {
15603
15715
  try {
15604
15716
  const node = await authenticatedNode(cmd);
@@ -15683,6 +15795,12 @@ function formatDelegation2(delegation) {
15683
15795
  createdAt: delegation.createdAt?.toISOString()
15684
15796
  };
15685
15797
  }
15798
+ function formatSpace(space) {
15799
+ return {
15800
+ ...space,
15801
+ expiresAt: space.expiresAt?.toISOString()
15802
+ };
15803
+ }
15686
15804
 
15687
15805
  // src/index.ts
15688
15806
  var { version } = JSON.parse(