@tinycloud/cli 0.7.0-beta.7 → 0.7.0-beta.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.
package/dist/index.js CHANGED
@@ -912,8 +912,8 @@ async function callbackFlow(did, options = {}) {
912
912
  }
913
913
  if (openBrowser) {
914
914
  try {
915
- const open = (await import("open")).default;
916
- await open(authUrl);
915
+ const open2 = (await import("open")).default;
916
+ await open2(authUrl);
917
917
  } catch {
918
918
  server.close();
919
919
  throw new Error("Failed to open browser");
@@ -14257,8 +14257,8 @@ function registerSecretsCommand(program2) {
14257
14257
  });
14258
14258
  secrets.command("manage").description("Open the TinyCloud Secrets Manager in your browser").action(async () => {
14259
14259
  try {
14260
- const open = (await import("open")).default;
14261
- await open("https://secrets.tinycloud.xyz");
14260
+ const open2 = (await import("open")).default;
14261
+ await open2("https://secrets.tinycloud.xyz");
14262
14262
  outputJson({ opened: "https://secrets.tinycloud.xyz" });
14263
14263
  } catch (error) {
14264
14264
  handleError(error);
@@ -15474,6 +15474,216 @@ function plural(count, label) {
15474
15474
  return `${count} ${label}${count === 1 ? "" : "s"}`;
15475
15475
  }
15476
15476
 
15477
+ // src/commands/account.ts
15478
+ import open from "open";
15479
+ import { readFile as readFile10 } from "fs/promises";
15480
+ var ACCOUNT_BILLING_URL = "https://account.tinycloud.xyz/billing";
15481
+ function registerAccountCommand(program2) {
15482
+ const account = program2.command("account").description("Account applications, delegations, and billing");
15483
+ account.command("status").description("Show account status").action(async (_options, cmd) => {
15484
+ try {
15485
+ const node = await authenticatedNode(cmd);
15486
+ const status = await node.account.status();
15487
+ assertOk(status);
15488
+ outputJson(status.data);
15489
+ } catch (error) {
15490
+ handleError(error);
15491
+ }
15492
+ });
15493
+ 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) => {
15495
+ try {
15496
+ const options = _options;
15497
+ const node = await authenticatedNode(cmd);
15498
+ const result = options.index ? await node.account.index.applications.list() : await node.account.applications.list();
15499
+ assertOk(result);
15500
+ const payload = { applications: result.data, count: result.data.length };
15501
+ if (shouldOutputJson()) {
15502
+ outputJson(payload);
15503
+ return;
15504
+ }
15505
+ if (result.data.length === 0) {
15506
+ process.stdout.write(theme.muted("No account applications registered.") + "\n");
15507
+ return;
15508
+ }
15509
+ process.stdout.write(
15510
+ formatTable(
15511
+ ["App ID", "Name", "Manifests", "Updated"],
15512
+ result.data.map((app) => [
15513
+ app.appId,
15514
+ app.name ?? "\u2014",
15515
+ String(app.manifests.length),
15516
+ app.updatedAt ?? "\u2014"
15517
+ ])
15518
+ ) + "\n"
15519
+ );
15520
+ } catch (error) {
15521
+ handleError(error);
15522
+ }
15523
+ });
15524
+ apps.command("info <app-id>").description("Show a registered account application").action(async (appId, _options, cmd) => {
15525
+ try {
15526
+ const node = await authenticatedNode(cmd);
15527
+ const result = await node.account.applications.get(appId);
15528
+ assertOk(result);
15529
+ outputJson(result.data);
15530
+ } catch (error) {
15531
+ handleError(error);
15532
+ }
15533
+ });
15534
+ apps.command("register <manifest>").description("Register an app manifest in account/applications").action(async (manifestSource, _options, cmd) => {
15535
+ try {
15536
+ const node = await authenticatedNode(cmd);
15537
+ const manifest = await loadManifestSource2(manifestSource);
15538
+ const result = await node.account.applications.register(manifest);
15539
+ assertOk(result);
15540
+ outputJson({ application: result.data, registered: true });
15541
+ } catch (error) {
15542
+ handleError(error);
15543
+ }
15544
+ });
15545
+ apps.command("remove <app-id>").alias("delete").description("Remove an application registry entry").action(async (appId, _options, cmd) => {
15546
+ try {
15547
+ const node = await authenticatedNode(cmd);
15548
+ const result = await node.account.applications.remove(appId);
15549
+ assertOk(result);
15550
+ outputJson({ appId, removed: true });
15551
+ } catch (error) {
15552
+ handleError(error);
15553
+ }
15554
+ });
15555
+ 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) => {
15557
+ try {
15558
+ if (options.granted && options.received) {
15559
+ throw new CLIError("USAGE_ERROR", "Use only one of --granted or --received.", ExitCode.USAGE_ERROR);
15560
+ }
15561
+ const node = await authenticatedNode(cmd);
15562
+ 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 });
15564
+ assertOk(result);
15565
+ const payload = { delegations: result.data.map(formatDelegation2), count: result.data.length };
15566
+ if (shouldOutputJson()) {
15567
+ outputJson(payload);
15568
+ return;
15569
+ }
15570
+ if (result.data.length === 0) {
15571
+ process.stdout.write(theme.muted("No delegations found.") + "\n");
15572
+ return;
15573
+ }
15574
+ process.stdout.write(
15575
+ formatTable(
15576
+ ["CID", "Direction", "Space", "Counterparty", "Status", "Expiry"],
15577
+ result.data.map((delegation) => [
15578
+ delegation.cid,
15579
+ delegation.direction,
15580
+ delegation.spaceName ?? delegation.spaceId,
15581
+ delegation.counterpartyDid,
15582
+ delegation.status,
15583
+ delegation.expiry.toISOString()
15584
+ ])
15585
+ ) + "\n"
15586
+ );
15587
+ } catch (error) {
15588
+ handleError(error);
15589
+ }
15590
+ });
15591
+ delegations.command("revoke <cid>").description("Revoke an active delegation granted by this account").requiredOption("--space <space>", "Space name or ID containing the delegation").action(async (cid, options, cmd) => {
15592
+ try {
15593
+ const node = await authenticatedNode(cmd);
15594
+ const result = await node.account.delegations.revoke({ cid, space: options.space });
15595
+ assertOk(result);
15596
+ outputJson({ cid, space: options.space, revoked: true });
15597
+ } catch (error) {
15598
+ handleError(error);
15599
+ }
15600
+ });
15601
+ const index = account.command("index").description("Manage the materialized account SQLite index");
15602
+ index.command("rebuild").description("Rebuild account SQLite index from canonical account data").action(async (_options, cmd) => {
15603
+ try {
15604
+ const node = await authenticatedNode(cmd);
15605
+ const result = await node.account.index.rebuild();
15606
+ assertOk(result);
15607
+ outputJson(result.data);
15608
+ } catch (error) {
15609
+ handleError(error);
15610
+ }
15611
+ });
15612
+ index.command("query <sql>").description("Query the materialized account SQLite index").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").action(async (sql, options, cmd) => {
15613
+ try {
15614
+ const node = await authenticatedNode(cmd);
15615
+ const params = parseParams(options.params);
15616
+ const result = await node.account.index.query(sql, params);
15617
+ assertOk(result);
15618
+ outputJson(result.data);
15619
+ } catch (error) {
15620
+ handleError(error);
15621
+ }
15622
+ });
15623
+ const billing = account.command("billing").description("Open account billing");
15624
+ for (const name of ["status", "checkout", "portal"]) {
15625
+ billing.command(name).description(`${name === "status" ? "Show" : "Open"} account billing page`).option("--open", "Open account.tinycloud.xyz in your browser").action(async (options) => {
15626
+ try {
15627
+ if (options.open) {
15628
+ await open(ACCOUNT_BILLING_URL);
15629
+ }
15630
+ outputJson({ url: ACCOUNT_BILLING_URL, opened: Boolean(options.open) });
15631
+ } catch (error) {
15632
+ handleError(error);
15633
+ }
15634
+ });
15635
+ }
15636
+ }
15637
+ async function authenticatedNode(cmd) {
15638
+ const globalOpts = cmd.optsWithGlobals();
15639
+ const ctx = await ProfileManager.resolveContext(globalOpts);
15640
+ return ensureAuthenticated(ctx);
15641
+ }
15642
+ function assertOk(result) {
15643
+ if (!result.ok) {
15644
+ throw new CLIError(result.error.code, result.error.message, ExitCode.ERROR);
15645
+ }
15646
+ }
15647
+ async function loadManifestSource2(source) {
15648
+ const raw = /^https?:\/\//i.test(source) ? await fetchManifest(source) : await readFile10(source, "utf8");
15649
+ return JSON.parse(raw);
15650
+ }
15651
+ async function fetchManifest(source) {
15652
+ const response = await fetch(source);
15653
+ if (!response.ok) {
15654
+ throw new CLIError(
15655
+ "MANIFEST_FETCH_FAILED",
15656
+ `Failed to fetch manifest from ${source}: ${response.status} ${response.statusText}`,
15657
+ ExitCode.NETWORK_ERROR
15658
+ );
15659
+ }
15660
+ return response.text();
15661
+ }
15662
+ function parseParams(input) {
15663
+ if (!input) return void 0;
15664
+ const parsed = JSON.parse(input);
15665
+ if (!Array.isArray(parsed)) {
15666
+ throw new CLIError("INVALID_PARAMS", "--params must be a JSON array.", ExitCode.USAGE_ERROR);
15667
+ }
15668
+ return parsed;
15669
+ }
15670
+ function formatDelegation2(delegation) {
15671
+ return {
15672
+ cid: delegation.cid,
15673
+ direction: delegation.direction,
15674
+ spaceId: delegation.spaceId,
15675
+ spaceName: delegation.spaceName,
15676
+ counterpartyDid: delegation.counterpartyDid,
15677
+ delegateDid: delegation.delegateDid,
15678
+ delegatorDid: delegation.delegatorDid,
15679
+ path: delegation.path,
15680
+ actions: delegation.actions,
15681
+ expiry: delegation.expiry.toISOString(),
15682
+ status: delegation.status,
15683
+ createdAt: delegation.createdAt?.toISOString()
15684
+ };
15685
+ }
15686
+
15477
15687
  // src/index.ts
15478
15688
  var { version } = JSON.parse(
15479
15689
  readFileSync3(new URL("../package.json", import.meta.url), "utf-8")
@@ -15524,6 +15734,7 @@ registerDuckdbCommand(program);
15524
15734
  registerManifestCommand(program);
15525
15735
  registerUpgradeCommand(program);
15526
15736
  registerStatusCommand(program);
15737
+ registerAccountCommand(program);
15527
15738
  program.addHelpText("before", () => `${theme.label("Version:")} ${theme.value(version)}
15528
15739
  `);
15529
15740
  program.addHelpText("afterAll", () => {
@@ -15535,6 +15746,7 @@ ${theme.heading("Examples:")}
15535
15746
  ${theme.command('tc kv put greeting "Hello"')} ${theme.muted("Store a value")}
15536
15747
  ${theme.command("tc kv list")} ${theme.muted("List all keys")}
15537
15748
  ${theme.command("tc secrets network init")} ${theme.muted("Create the default secrets network")}
15749
+ ${theme.command("tc account apps list")} ${theme.muted("List registered account apps")}
15538
15750
  ${theme.command("tc delegation create --to did:pkh:...")} ${theme.muted("Grant access to another user")}
15539
15751
  ${theme.command("tc space list")} ${theme.muted("Show your spaces")}
15540
15752