@tinycloud/cli 1.5.0-beta.20 → 1.5.0-beta.22

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.
@@ -2555,6 +2555,9 @@ function isRawEncryptionPermission(permission) {
2555
2555
  function isVerifiedRawEncryptionPermission(permission) {
2556
2556
  return isRawEncryptionPermission(permission) && (permission.space === void 0 || permission.space === "encryption");
2557
2557
  }
2558
+ function isDeviceDefaultDecrypt(permission) {
2559
+ return permission.service === ENCRYPTION_PERMISSION_SERVICE && permission.space === "default" && permission.path === "" && permission.actions.length === 1 && permission.actions[0] === "tinycloud.encryption/decrypt" && !permission.caveats?.length;
2560
+ }
2558
2561
  var init_raw_encryption = __esm({
2559
2562
  "src/lib/raw-encryption.ts"() {
2560
2563
  "use strict";
@@ -2625,7 +2628,7 @@ var init_caveat_refusal = __esm({
2625
2628
 
2626
2629
  // src/share/publishing-manifest.ts
2627
2630
  function sharePublishingPermissions() {
2628
- return SHARE_PUBLISHING_MANIFEST.permissions.map((permission) => ({
2631
+ return SHARE_PUBLISHING_MANIFEST.permissions.filter((permission) => permission.service !== "tinycloud.encryption").map((permission) => ({
2629
2632
  service: permission.service,
2630
2633
  space: SHARE_PUBLISHING_MANIFEST.space,
2631
2634
  path: permission.path,
@@ -2665,6 +2668,12 @@ var init_publishing_manifest = __esm({
2665
2668
  path: "artifacts/",
2666
2669
  skipPrefix: true,
2667
2670
  actions: ["tinycloud.kv/get", "tinycloud.kv/metadata", "tinycloud.kv/put", "tinycloud.kv/list"]
2671
+ },
2672
+ {
2673
+ service: "tinycloud.encryption",
2674
+ path: "",
2675
+ skipPrefix: true,
2676
+ actions: ["tinycloud.encryption/decrypt"]
2668
2677
  }
2669
2678
  ]
2670
2679
  };
@@ -2915,6 +2924,9 @@ async function loadPermissionRequest(source, profile) {
2915
2924
  async function loadManifestPermissions(source, profile, options = {}) {
2916
2925
  const raw = await loadManifestText(source);
2917
2926
  const manifest = JSON.parse(raw);
2927
+ if (options.device && source === SHARE_PUBLISHING_MANIFEST_REF && Array.isArray(manifest.permissions)) {
2928
+ manifest.permissions = manifest.permissions.filter((entry) => !(entry !== null && typeof entry === "object" && normalizeService(String(entry.service ?? "")) === "tinycloud.encryption"));
2929
+ }
2918
2930
  if (Array.isArray(manifest.permissions)) assertNoCaveatLimits(manifest.permissions);
2919
2931
  if (options.device && typeof manifest.app_id === "string" && (manifest.secrets !== void 0 || manifest.space === "secrets" || typeof manifest.space === "string" && manifest.space.endsWith(":secrets") || Array.isArray(manifest.permissions) && manifest.permissions.some((entry) => entry !== null && typeof entry === "object" && normalizeService(String(entry.service ?? "")) === "tinycloud.encryption"))) {
2920
2932
  throw new CLIError("DEVICE_AUTH_UNSUPPORTED_SCOPE", "--device cannot authorize tinycloud.encryption or the secrets space. Use browser or --paste login.", ExitCode.USAGE_ERROR);
@@ -3041,6 +3053,10 @@ async function resolvePermissionSpaces(entries, profile, options = {}) {
3041
3053
  resolved.push({ ...raw, service, space: ENCRYPTION_MANIFEST_SPACE, actions });
3042
3054
  continue;
3043
3055
  }
3056
+ if (isDeviceDefaultDecrypt({ ...entry, service, actions })) {
3057
+ resolved.push({ service, space: ENCRYPTION_MANIFEST_SPACE, path: await defaultSecretsNetworkId(profile, options.ownerDid), actions });
3058
+ continue;
3059
+ }
3044
3060
  let space;
3045
3061
  try {
3046
3062
  space = await resolveSpaceUri(entry.space, profile) ?? entry.space;
@@ -6568,20 +6584,20 @@ function effectiveAuthority2(input) {
6568
6584
  }
6569
6585
  function wrap(native) {
6570
6586
  const statements = /* @__PURE__ */ new Map();
6571
- const prepared = (sql) => {
6572
- let statement = statements.get(sql);
6587
+ const prepared = (sql2) => {
6588
+ let statement = statements.get(sql2);
6573
6589
  if (statement === void 0) {
6574
- statement = native.prepare(sql);
6575
- statements.set(sql, statement);
6590
+ statement = native.prepare(sql2);
6591
+ statements.set(sql2, statement);
6576
6592
  }
6577
6593
  return statement;
6578
6594
  };
6579
6595
  return {
6580
- exec: (sql) => native.exec(sql),
6581
- run: (sql, ...params) => void prepared(sql).run(...params),
6596
+ exec: (sql2) => native.exec(sql2),
6597
+ run: (sql2, ...params) => void prepared(sql2).run(...params),
6582
6598
  // bun:sqlite answers a missing row with null, node:sqlite with undefined.
6583
- get: (sql, ...params) => prepared(sql).get(...params) ?? void 0,
6584
- all: (sql, ...params) => prepared(sql).all(...params),
6599
+ get: (sql2, ...params) => prepared(sql2).get(...params) ?? void 0,
6600
+ all: (sql2, ...params) => prepared(sql2).all(...params),
6585
6601
  close: () => {
6586
6602
  let failure;
6587
6603
  try {
@@ -7274,11 +7290,11 @@ CREATE TABLE IF NOT EXISTS grant_install (
7274
7290
  "pending_grant_consent_anchor_at REAL",
7275
7291
  "pending_grant_consent_anchor_source TEXT"
7276
7292
  ];
7277
- normalizeSchema = (sql) => sql.replace(" IF NOT EXISTS", "").replace(/\s+/g, " ").trim();
7278
- SOURCE_SCHEMA = SCHEMA.trim().split(";").map((sql) => sql.trim()).filter(Boolean).map((sql) => {
7279
- const match = /^CREATE (TABLE|INDEX) IF NOT EXISTS ([a-z_]+)/.exec(sql);
7293
+ normalizeSchema = (sql2) => sql2.replace(" IF NOT EXISTS", "").replace(/\s+/g, " ").trim();
7294
+ SOURCE_SCHEMA = SCHEMA.trim().split(";").map((sql2) => sql2.trim()).filter(Boolean).map((sql2) => {
7295
+ const match = /^CREATE (TABLE|INDEX) IF NOT EXISTS ([a-z_]+)/.exec(sql2);
7280
7296
  if (match === null) throw new Error("Invalid source replica schema.");
7281
- return { type: match[1].toLowerCase(), name: match[2], sql: normalizeSchema(sql) };
7297
+ return { type: match[1].toLowerCase(), name: match[2], sql: normalizeSchema(sql2) };
7282
7298
  });
7283
7299
  V1_SCHEMA = SOURCE_SCHEMA.filter((entry) => entry.name !== "grant_install");
7284
7300
  POLICY_REPLICA = V1_SCHEMA.find((entry) => entry.name === "replica").sql.replace(/\) STRICT$/, `, ${POLICY_COLUMNS.join(", ")}) STRICT`);
@@ -16453,11 +16469,11 @@ function registerAccountCommand(program) {
16453
16469
  return handleError(error);
16454
16470
  }
16455
16471
  });
16456
- 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) => {
16472
+ index.command("query <sql>").description("Query the materialized account SQLite index").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").action(async (sql2, options, cmd) => {
16457
16473
  try {
16458
16474
  const node = await authenticatedNode(cmd);
16459
16475
  const params = parseParams(options.params);
16460
- const result = await node.account.index.query(sql, params);
16476
+ const result = await node.account.index.query(sql2, params);
16461
16477
  assertOk(result);
16462
16478
  outputJson(result.data);
16463
16479
  } catch (error) {
@@ -36959,14 +36975,14 @@ function verifyBytes(file, bytes) {
36959
36975
  throw new AppsInstallError("INTEGRITY_FAILED", `${file.path} does not match the pinned sha256 and size`);
36960
36976
  }
36961
36977
  }
36962
- function splitStatements(sql) {
36978
+ function splitStatements(sql2) {
36963
36979
  let stripped = "";
36964
36980
  let inQuote = false;
36965
- for (let i = 0; i < sql.length; i++) {
36966
- const ch = sql[i];
36981
+ for (let i = 0; i < sql2.length; i++) {
36982
+ const ch = sql2[i];
36967
36983
  if (ch === "'") inQuote = !inQuote;
36968
- if (!inQuote && ch === "-" && sql[i + 1] === "-") {
36969
- while (i < sql.length && sql[i] !== "\n") i++;
36984
+ if (!inQuote && ch === "-" && sql2[i + 1] === "-") {
36985
+ while (i < sql2.length && sql2[i] !== "\n") i++;
36970
36986
  stripped += "\n";
36971
36987
  continue;
36972
36988
  }
@@ -38146,11 +38162,15 @@ init_errors();
38146
38162
  init_formatter();
38147
38163
  var ONBOARD_EXPIRY = "30d";
38148
38164
  var kv = (actions) => actions.map((action) => `tinycloud.kv/${action}`);
38165
+ var sql = (actions) => actions.map((action) => `tinycloud.sql/${action}`);
38149
38166
  var ONBOARD_STEPS = [
38150
38167
  {
38151
38168
  space: "applications",
38152
38169
  asks: "Read and change your apps' data for 30 days.",
38153
- permissions: [{ service: "tinycloud.kv", space: "applications", path: "", actions: kv(["get", "list", "put", "del", "metadata"]) }]
38170
+ permissions: [
38171
+ { service: "tinycloud.kv", space: "applications", path: "", actions: kv(["get", "list", "put", "del", "metadata"]) },
38172
+ { service: "tinycloud.sql", space: "applications", path: "", actions: sql(["read", "write"]) }
38173
+ ]
38154
38174
  },
38155
38175
  {
38156
38176
  space: "account",
@@ -42753,12 +42773,7 @@ function shareCliError(error, operation = "publish") {
42753
42773
  return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
42754
42774
  }
42755
42775
  if (failure.kind === "decrypt-not-held") {
42756
- return new CLIError(
42757
- "PERMISSION_DENIED",
42758
- "this sign-in can't create email-addressed shares: it has no permission to decrypt with the account's key. Nothing was shared.",
42759
- 5,
42760
- { hint: "Share it from https://share.tinycloud.xyz while signed in as the account owner, or ask the owner to share it. A link anyone can open works from this sign-in: --to anyone." }
42761
- );
42776
+ return new CLIError("PERMISSION_DENIED", `Email shares need a paste sign-in: run ${CLI_NAME34} auth login --paste --manifest builtin:share-publishing`, 5);
42762
42777
  }
42763
42778
  if (failure.kind === "over-limit") {
42764
42779
  return new CLIError("MAX_BYTES_EXCEEDED", ADDRESSED_SHARE_TOO_LARGE_MESSAGE, 7, { hint: `What stays behind: ${failure.remaining.join("; ")}.` });
@@ -43393,8 +43408,8 @@ import { writeFile as writeFile5 } from "fs/promises";
43393
43408
  import { resolve as resolve8 } from "path";
43394
43409
  async function dbHandle(node, dbName, spaceInput, profileName2) {
43395
43410
  const spaceUri = await resolveSpaceUri(spaceInput, profileName2);
43396
- const sql = spaceUri ? node.sqlForSpace(spaceUri) : node.sql;
43397
- return { handle: sql.db(dbName), spaceUri };
43411
+ const sql2 = spaceUri ? node.sqlForSpace(spaceUri) : node.sql;
43412
+ return { handle: sql2.db(dbName), spaceUri };
43398
43413
  }
43399
43414
  async function throwSqlError(error, spaceUri, profileName2, prefix) {
43400
43415
  const storageFull = storageFullError(error, prefix);
@@ -43405,7 +43420,7 @@ async function throwSqlError(error, spaceUri, profileName2, prefix) {
43405
43420
  throw cliErrorFromService(error, message);
43406
43421
  }
43407
43422
  function registerSqlCommand(program) {
43408
- const sql = program.command("sql").description("SQLite database operations for your TinyCloud space").addHelpText("after", `
43423
+ const sql2 = program.command("sql").description("SQLite database operations for your TinyCloud space").addHelpText("after", `
43409
43424
 
43410
43425
  TinyCloud SQL gives each space isolated SQLite databases. Use the default
43411
43426
  database for simple apps, or pass --db to target a named database. Pass
@@ -43431,7 +43446,7 @@ Tips:
43431
43446
  - --space accepts a short name ("applications") or full URI ("tinycloud:pkh:eip155:1:0x...:applications").
43432
43447
  - Add --json for scripting-friendly output.
43433
43448
  `);
43434
- sql.command("query <sql>").description("Run a read-only SELECT query").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").addHelpText("after", `
43449
+ sql2.command("query <sql>").description("Run a read-only SELECT query").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").addHelpText("after", `
43435
43450
 
43436
43451
  Examples:
43437
43452
  $ ${CLI_NAME36} sql query "SELECT * FROM notes ORDER BY id"
@@ -43475,7 +43490,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
43475
43490
  return handleError(error);
43476
43491
  }
43477
43492
  });
43478
- sql.command("execute <sql>").description("Run a write or schema statement").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").addHelpText("after", `
43493
+ sql2.command("execute <sql>").description("Run a write or schema statement").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").addHelpText("after", `
43479
43494
 
43480
43495
  Examples:
43481
43496
  $ ${CLI_NAME36} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
@@ -43508,7 +43523,7 @@ Output:
43508
43523
  return handleError(error);
43509
43524
  }
43510
43525
  });
43511
- sql.command("export").description("Export a SQLite database as a binary .db file").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("-o, --output <file>", "Output file path", "export.db").addHelpText("after", `
43526
+ sql2.command("export").description("Export a SQLite database as a binary .db file").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("-o, --output <file>", "Output file path", "export.db").addHelpText("after", `
43512
43527
 
43513
43528
  Examples:
43514
43529
  $ ${CLI_NAME36} sql export
@@ -43543,7 +43558,7 @@ Output:
43543
43558
  return handleError(error);
43544
43559
  }
43545
43560
  });
43546
- sql.command("copy").description("Copy rows between SQL databases (optionally across spaces)").requiredOption("--from-db <name>", "Source database name").requiredOption("--to-db <name>", "Destination database name").option("--from-space <name|uri>", "Source space (defaults to primary)").option("--to-space <name|uri>", "Destination space (defaults to primary)").option("--table <name...>", "Restrict copy to specific tables (repeat or comma-separated)").option("--dry-run", "Print the plan without writing", false).addHelpText("after", `
43561
+ sql2.command("copy").description("Copy rows between SQL databases (optionally across spaces)").requiredOption("--from-db <name>", "Source database name").requiredOption("--to-db <name>", "Destination database name").option("--from-space <name|uri>", "Source space (defaults to primary)").option("--to-space <name|uri>", "Destination space (defaults to primary)").option("--table <name...>", "Restrict copy to specific tables (repeat or comma-separated)").option("--dry-run", "Print the plan without writing", false).addHelpText("after", `
43547
43562
 
43548
43563
  Examples:
43549
43564
  $ ${CLI_NAME36} sql copy --from-db com.tinycloud.conversation-sync/conversations \\