@hot-updater/cloudflare 0.30.12 → 0.31.0

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.
@@ -10870,7 +10870,6 @@ function App() {
10870
10870
  export default HotUpdater.wrap({
10871
10871
  baseURL: "%%source%%",
10872
10872
  updateStrategy: "appVersion", // or "fingerprint"
10873
- updateMode: "auto",
10874
10873
  })(App);`;
10875
10874
  const deployWorker = async (oauth_token, accountId, { d1DatabaseId, d1DatabaseName, r2BucketName }) => {
10876
10875
  const cwd = (0, _hot_updater_cli_tools.getCwd)();
@@ -10862,7 +10862,6 @@ function App() {
10862
10862
  export default HotUpdater.wrap({
10863
10863
  baseURL: "%%source%%",
10864
10864
  updateStrategy: "appVersion", // or "fingerprint"
10865
- updateMode: "auto",
10866
10865
  })(App);`;
10867
10866
  const deployWorker = async (oauth_token, accountId, { d1DatabaseId, d1DatabaseName, r2BucketName }) => {
10868
10867
  const cwd = getCwd();
package/dist/index.cjs CHANGED
@@ -26,8 +26,10 @@ let _hot_updater_core = require("@hot-updater/core");
26
26
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
27
27
  let cloudflare = require("cloudflare");
28
28
  cloudflare = __toESM(cloudflare);
29
- let path = require("path");
30
- path = __toESM(path);
29
+ let node_fs_promises = require("node:fs/promises");
30
+ node_fs_promises = __toESM(node_fs_promises);
31
+ let node_path = require("node:path");
32
+ node_path = __toESM(node_path);
31
33
  let node_url = require("node:url");
32
34
  let node_child_process = require("node:child_process");
33
35
  let node_string_decoder = require("node:string_decoder");
@@ -36,8 +38,6 @@ let node_process = require("node:process");
36
38
  node_process = __toESM(node_process);
37
39
  let node_tty = require("node:tty");
38
40
  node_tty = __toESM(node_tty);
39
- let node_path = require("node:path");
40
- node_path = __toESM(node_path);
41
41
  let node_timers_promises = require("node:timers/promises");
42
42
  let node_os = require("node:os");
43
43
  let node_events = require("node:events");
@@ -357,7 +357,34 @@ function parseTargetCohorts(value) {
357
357
  }
358
358
  return null;
359
359
  }
360
- function transformRowToBundle(row) {
360
+ const parseMetadata = (value) => {
361
+ if (!value) return void 0;
362
+ if (typeof value === "string") try {
363
+ return parseMetadata(JSON.parse(value));
364
+ } catch {
365
+ return;
366
+ }
367
+ return typeof value === "object" && !Array.isArray(value) ? value : void 0;
368
+ };
369
+ const buildBundlePatchId = (bundleId, baseBundleId) => `${bundleId}:${baseBundleId}`;
370
+ const bundleToPatchRows = (bundle) => (0, _hot_updater_core.getBundlePatches)(bundle).map((patch, index) => ({
371
+ id: buildBundlePatchId(bundle.id, patch.baseBundleId),
372
+ bundle_id: bundle.id,
373
+ base_bundle_id: patch.baseBundleId,
374
+ base_file_hash: patch.baseFileHash,
375
+ patch_file_hash: patch.patchFileHash,
376
+ patch_storage_uri: patch.patchStorageUri,
377
+ order_index: index
378
+ }));
379
+ function transformRowToBundle(row, patchRows = []) {
380
+ const rawMetadata = parseMetadata(row.metadata);
381
+ const patches = patchRows.slice().sort((left, right) => (left.order_index ?? 0) - (right.order_index ?? 0) || left.base_bundle_id.localeCompare(right.base_bundle_id)).map((patch) => ({
382
+ baseBundleId: patch.base_bundle_id,
383
+ baseFileHash: patch.base_file_hash,
384
+ patchFileHash: patch.patch_file_hash,
385
+ patchStorageUri: patch.patch_storage_uri
386
+ }));
387
+ const primaryPatch = patches[0] ?? null;
361
388
  return {
362
389
  id: row.id,
363
390
  channel: row.channel,
@@ -370,7 +397,15 @@ function transformRowToBundle(row) {
370
397
  targetAppVersion: row.target_app_version,
371
398
  storageUri: row.storage_uri,
372
399
  fingerprintHash: row.fingerprint_hash,
373
- metadata: row?.metadata ? JSON.parse(row?.metadata) : {},
400
+ metadata: (0, _hot_updater_core.stripBundleArtifactMetadata)(rawMetadata),
401
+ manifestStorageUri: row.manifest_storage_uri ?? null,
402
+ manifestFileHash: row.manifest_file_hash ?? null,
403
+ assetBaseStorageUri: row.asset_base_storage_uri ?? null,
404
+ patches,
405
+ patchBaseBundleId: primaryPatch?.baseBundleId ?? null,
406
+ patchBaseFileHash: primaryPatch?.baseFileHash ?? null,
407
+ patchFileHash: primaryPatch?.patchFileHash ?? null,
408
+ patchStorageUri: primaryPatch?.patchStorageUri ?? null,
374
409
  rolloutCohortCount: row.rollout_cohort_count ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
375
410
  targetCohorts: parseTargetCohorts(row.target_cohorts)
376
411
  };
@@ -379,6 +414,27 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
379
414
  name: "d1Database",
380
415
  factory: (config) => {
381
416
  const cf = new cloudflare.default({ apiToken: config.cloudflareApiToken });
417
+ const getPatchMap = async (bundleIds) => {
418
+ const patchMap = /* @__PURE__ */ new Map();
419
+ if (bundleIds.length === 0) return patchMap;
420
+ const sql = (0, import_lib.default)(`
421
+ SELECT *
422
+ FROM bundle_patches
423
+ WHERE bundle_id IN (${bundleIds.map(() => "?").join(", ")})
424
+ ORDER BY order_index ASC, base_bundle_id ASC
425
+ `);
426
+ const rows = await resolvePage(await cf.d1.database.query(config.databaseId, {
427
+ account_id: config.accountId,
428
+ sql,
429
+ params: bundleIds
430
+ }));
431
+ for (const row of rows) {
432
+ const current = patchMap.get(row.bundle_id) ?? [];
433
+ current.push(row);
434
+ patchMap.set(row.bundle_id, current);
435
+ }
436
+ return patchMap;
437
+ };
382
438
  async function getTotalCount(conditions) {
383
439
  const { sql: whereClause, params } = buildWhereClause(conditions);
384
440
  const countSql = (0, import_lib.default)(`SELECT COUNT(*) as total FROM bundles${whereClause}`);
@@ -398,11 +454,13 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
398
454
  OFFSET ?
399
455
  `);
400
456
  params.push(limit, offset);
401
- return (await resolvePage(await cf.d1.database.query(config.databaseId, {
457
+ const rows = await resolvePage(await cf.d1.database.query(config.databaseId, {
402
458
  account_id: config.accountId,
403
459
  sql,
404
460
  params
405
- }))).map(transformRowToBundle);
461
+ }));
462
+ const patchMap = await getPatchMap(rows.map((row) => row.id));
463
+ return rows.map((row) => transformRowToBundle(row, patchMap.get(row.id)));
406
464
  }
407
465
  async function queryBundlesForUpdateInfo(conditions) {
408
466
  const { sql: whereClause, params } = buildWhereClause(conditions);
@@ -410,11 +468,13 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
410
468
  SELECT * FROM bundles
411
469
  ${whereClause}
412
470
  `);
413
- return (await resolvePage(await cf.d1.database.query(config.databaseId, {
471
+ const rows = await resolvePage(await cf.d1.database.query(config.databaseId, {
414
472
  account_id: config.accountId,
415
473
  sql,
416
474
  params
417
- }))).map(transformRowToBundle);
475
+ }));
476
+ const patchMap = await getPatchMap(rows.map((row) => row.id));
477
+ return rows.map((row) => transformRowToBundle(row, patchMap.get(row.id)));
418
478
  }
419
479
  async function getTargetAppVersionsForUpdateInfo({ platform, channel, minBundleId }) {
420
480
  const sql = (0, import_lib.default)(`
@@ -462,13 +522,14 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
462
522
  async getBundleById(bundleId) {
463
523
  const sql = (0, import_lib.default)(`
464
524
  SELECT * FROM bundles WHERE id = ? LIMIT 1`);
465
- const rows = await resolvePage(await cf.d1.database.query(config.databaseId, {
525
+ const [singlePage, patchMap] = await Promise.all([cf.d1.database.query(config.databaseId, {
466
526
  account_id: config.accountId,
467
527
  sql,
468
528
  params: [bundleId]
469
- }));
529
+ }), getPatchMap([bundleId])]);
530
+ const rows = await resolvePage(singlePage);
470
531
  if (rows.length === 0) return null;
471
- return transformRowToBundle(rows[0]);
532
+ return transformRowToBundle(rows[0], patchMap.get(bundleId));
472
533
  },
473
534
  async getBundles(options) {
474
535
  const { where = {}, limit, orderBy } = options;
@@ -497,7 +558,23 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
497
558
  for (const op of changedSets) if (op.operation === "delete") {
498
559
  const deleteSql = (0, import_lib.default)(`
499
560
  DELETE FROM bundles WHERE id = ?
561
+ `);
562
+ const deletePatchSql = (0, import_lib.default)(`
563
+ DELETE FROM bundle_patches WHERE bundle_id = ?
500
564
  `);
565
+ await cf.d1.database.query(config.databaseId, {
566
+ account_id: config.accountId,
567
+ sql: deletePatchSql,
568
+ params: [op.data.id]
569
+ });
570
+ const deleteBasePatchSql = (0, import_lib.default)(`
571
+ DELETE FROM bundle_patches WHERE base_bundle_id = ?
572
+ `);
573
+ await cf.d1.database.query(config.databaseId, {
574
+ account_id: config.accountId,
575
+ sql: deleteBasePatchSql,
576
+ params: [op.data.id]
577
+ });
501
578
  await cf.d1.database.query(config.databaseId, {
502
579
  account_id: config.accountId,
503
580
  sql: deleteSql,
@@ -519,10 +596,13 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
519
596
  storage_uri,
520
597
  fingerprint_hash,
521
598
  metadata,
599
+ manifest_storage_uri,
600
+ manifest_file_hash,
601
+ asset_base_storage_uri,
522
602
  rollout_cohort_count,
523
603
  target_cohorts
524
604
  )
525
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
605
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
526
606
  `);
527
607
  const params = [
528
608
  bundle.id,
@@ -536,7 +616,10 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
536
616
  bundle.targetAppVersion,
537
617
  bundle.storageUri,
538
618
  bundle.fingerprintHash,
539
- bundle.metadata ? JSON.stringify(bundle.metadata) : JSON.stringify({}),
619
+ JSON.stringify((0, _hot_updater_core.stripBundleArtifactMetadata)(bundle.metadata) ?? {}),
620
+ (0, _hot_updater_core.getManifestStorageUri)(bundle),
621
+ (0, _hot_updater_core.getManifestFileHash)(bundle),
622
+ (0, _hot_updater_core.getAssetBaseStorageUri)(bundle),
540
623
  bundle.rolloutCohortCount ?? _hot_updater_core.DEFAULT_ROLLOUT_COHORT_COUNT,
541
624
  bundle.targetCohorts ? JSON.stringify(bundle.targetCohorts) : null
542
625
  ];
@@ -545,6 +628,41 @@ const d1Database = (0, _hot_updater_plugin_core.createDatabasePlugin)({
545
628
  sql: upsertSql,
546
629
  params
547
630
  });
631
+ await cf.d1.database.query(config.databaseId, {
632
+ account_id: config.accountId,
633
+ sql: (0, import_lib.default)(`
634
+ DELETE FROM bundle_patches WHERE bundle_id = ?
635
+ `),
636
+ params: [bundle.id]
637
+ });
638
+ const patchRows = bundleToPatchRows(bundle);
639
+ if (patchRows.length > 0) {
640
+ const patchInsertSql = (0, import_lib.default)(`
641
+ INSERT OR REPLACE INTO bundle_patches (
642
+ id,
643
+ bundle_id,
644
+ base_bundle_id,
645
+ base_file_hash,
646
+ patch_file_hash,
647
+ patch_storage_uri,
648
+ order_index
649
+ )
650
+ VALUES (?, ?, ?, ?, ?, ?, ?)
651
+ `);
652
+ for (const patchRow of patchRows) await cf.d1.database.query(config.databaseId, {
653
+ account_id: config.accountId,
654
+ sql: patchInsertSql,
655
+ params: [
656
+ patchRow.id,
657
+ patchRow.bundle_id,
658
+ patchRow.base_bundle_id,
659
+ patchRow.base_file_hash,
660
+ patchRow.patch_file_hash,
661
+ patchRow.patch_storage_uri,
662
+ String(patchRow.order_index ?? 0)
663
+ ]
664
+ });
665
+ }
548
666
  }
549
667
  }
550
668
  };
@@ -1320,7 +1438,7 @@ const handleCommand = (filePath, rawArguments, rawOptions) => {
1320
1438
  var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1321
1439
  module.exports = isexe;
1322
1440
  isexe.sync = sync;
1323
- var fs$2 = require("fs");
1441
+ var fs$3 = require("fs");
1324
1442
  function checkPathExt(path, options) {
1325
1443
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
1326
1444
  if (!pathext) return true;
@@ -1337,12 +1455,12 @@ var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1337
1455
  return checkPathExt(path, options);
1338
1456
  }
1339
1457
  function isexe(path, options, cb) {
1340
- fs$2.stat(path, function(er, stat) {
1458
+ fs$3.stat(path, function(er, stat) {
1341
1459
  cb(er, er ? false : checkStat(stat, path, options));
1342
1460
  });
1343
1461
  }
1344
1462
  function sync(path, options) {
1345
- return checkStat(fs$2.statSync(path), path, options);
1463
+ return checkStat(fs$3.statSync(path), path, options);
1346
1464
  }
1347
1465
  }));
1348
1466
  //#endregion
@@ -1350,14 +1468,14 @@ var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1350
1468
  var require_mode = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1351
1469
  module.exports = isexe;
1352
1470
  isexe.sync = sync;
1353
- var fs$1 = require("fs");
1471
+ var fs$2 = require("fs");
1354
1472
  function isexe(path, options, cb) {
1355
- fs$1.stat(path, function(er, stat) {
1473
+ fs$2.stat(path, function(er, stat) {
1356
1474
  cb(er, er ? false : checkStat(stat, options));
1357
1475
  });
1358
1476
  }
1359
1477
  function sync(path, options) {
1360
- return checkStat(fs$1.statSync(path), options);
1478
+ return checkStat(fs$2.statSync(path), options);
1361
1479
  }
1362
1480
  function checkStat(stat, options) {
1363
1481
  return stat.isFile() && checkMode(stat, options);
@@ -1421,7 +1539,7 @@ var require_isexe = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1421
1539
  //#region ../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js
1422
1540
  var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1423
1541
  const isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
1424
- const path$9 = require("path");
1542
+ const path$8 = require("path");
1425
1543
  const COLON = isWindows ? ";" : ":";
1426
1544
  const isexe = require_isexe();
1427
1545
  const getNotFoundError = (cmd) => Object.assign(/* @__PURE__ */ new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -1451,7 +1569,7 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1451
1569
  if (i === pathEnv.length) return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
1452
1570
  const ppRaw = pathEnv[i];
1453
1571
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
1454
- const pCmd = path$9.join(pathPart, cmd);
1572
+ const pCmd = path$8.join(pathPart, cmd);
1455
1573
  resolve(subStep(!pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd, i, 0));
1456
1574
  });
1457
1575
  const subStep = (p, i, ii) => new Promise((resolve, reject) => {
@@ -1472,7 +1590,7 @@ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1472
1590
  for (let i = 0; i < pathEnv.length; i++) {
1473
1591
  const ppRaw = pathEnv[i];
1474
1592
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
1475
- const pCmd = path$9.join(pathPart, cmd);
1593
+ const pCmd = path$8.join(pathPart, cmd);
1476
1594
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
1477
1595
  for (let j = 0; j < pathExt.length; j++) {
1478
1596
  const cur = p + pathExt[j];
@@ -1503,7 +1621,7 @@ var require_path_key = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1503
1621
  //#endregion
1504
1622
  //#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
1505
1623
  var require_resolveCommand = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1506
- const path$8 = require("path");
1624
+ const path$7 = require("path");
1507
1625
  const which = require_which();
1508
1626
  const getPathKey = require_path_key();
1509
1627
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -1518,12 +1636,12 @@ var require_resolveCommand = /* @__PURE__ */ __commonJSMin(((exports, module) =>
1518
1636
  try {
1519
1637
  resolved = which.sync(parsed.command, {
1520
1638
  path: env[getPathKey({ env })],
1521
- pathExt: withoutPathExt ? path$8.delimiter : void 0
1639
+ pathExt: withoutPathExt ? path$7.delimiter : void 0
1522
1640
  });
1523
1641
  } catch (e) {} finally {
1524
1642
  if (shouldSwitchCwd) process.chdir(cwd);
1525
1643
  }
1526
- if (resolved) resolved = path$8.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
1644
+ if (resolved) resolved = path$7.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
1527
1645
  return resolved;
1528
1646
  }
1529
1647
  function resolveCommand(parsed) {
@@ -1572,16 +1690,16 @@ var require_shebang_command = /* @__PURE__ */ __commonJSMin(((exports, module) =
1572
1690
  //#endregion
1573
1691
  //#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
1574
1692
  var require_readShebang = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1575
- const fs = require("fs");
1693
+ const fs$1 = require("fs");
1576
1694
  const shebangCommand = require_shebang_command();
1577
1695
  function readShebang(command) {
1578
1696
  const size = 150;
1579
1697
  const buffer = Buffer.alloc(size);
1580
1698
  let fd;
1581
1699
  try {
1582
- fd = fs.openSync(command, "r");
1583
- fs.readSync(fd, buffer, 0, size, 0);
1584
- fs.closeSync(fd);
1700
+ fd = fs$1.openSync(command, "r");
1701
+ fs$1.readSync(fd, buffer, 0, size, 0);
1702
+ fs$1.closeSync(fd);
1585
1703
  } catch (e) {}
1586
1704
  return shebangCommand(buffer.toString());
1587
1705
  }
@@ -1590,7 +1708,7 @@ var require_readShebang = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1590
1708
  //#endregion
1591
1709
  //#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
1592
1710
  var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1593
- const path$7 = require("path");
1711
+ const path$6 = require("path");
1594
1712
  const resolveCommand = require_resolveCommand();
1595
1713
  const escape = require_escape();
1596
1714
  const readShebang = require_readShebang();
@@ -1613,7 +1731,7 @@ var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1613
1731
  const needsShell = !isExecutableRegExp.test(commandFile);
1614
1732
  if (parsed.options.forceShell || needsShell) {
1615
1733
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
1616
- parsed.command = path$7.normalize(parsed.command);
1734
+ parsed.command = path$6.normalize(parsed.command);
1617
1735
  parsed.command = escape.command(parsed.command);
1618
1736
  parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
1619
1737
  parsed.args = [
@@ -6727,28 +6845,8 @@ const createWrangler = ({ stdio, accountId, cloudflareApiToken, cwd }) => {
6727
6845
  //#region src/r2Storage.ts
6728
6846
  /**
6729
6847
  * Cloudflare R2 storage plugin for Hot Updater.
6730
- *
6731
- * Note: This plugin does not support `getDownloadUrl()`.
6732
- * If you need download URL generation, use `s3Storage` from `@hot-updater/aws` instead,
6733
- * which is fully compatible with Cloudflare R2.
6734
- *
6735
- * @example
6736
- * ```typescript
6737
- * // Using s3Storage with Cloudflare R2 for download URL support
6738
- * import { s3Storage } from "@hot-updater/aws";
6739
- *
6740
- * s3Storage({
6741
- * region: "auto",
6742
- * endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com",
6743
- * credentials: {
6744
- * accessKeyId: "YOUR_ACCESS_KEY_ID",
6745
- * secretAccessKey: "YOUR_SECRET_ACCESS_KEY",
6746
- * },
6747
- * bucketName: "YOUR_BUCKET_NAME",
6748
- * })
6749
- * ```
6750
6848
  */
6751
- const r2Storage = (0, _hot_updater_plugin_core.createStoragePlugin)({
6849
+ const r2Storage = (0, _hot_updater_plugin_core.createNodeStoragePlugin)({
6752
6850
  name: "r2Storage",
6753
6851
  supportedProtocol: "r2",
6754
6852
  factory: (config) => {
@@ -6771,7 +6869,7 @@ const r2Storage = (0, _hot_updater_plugin_core.createStoragePlugin)({
6771
6869
  },
6772
6870
  async upload(key, filePath) {
6773
6871
  const contentType = (0, _hot_updater_plugin_core.getContentType)(filePath);
6774
- const Key = getStorageKey(key, path.default.basename(filePath));
6872
+ const Key = getStorageKey(key, node_path.default.basename(filePath));
6775
6873
  try {
6776
6874
  const { stderr, exitCode } = await wrangler("r2", "object", "put", [bucketName, Key].join("/"), "--file", filePath, "--content-type", contentType, "--remote");
6777
6875
  if (exitCode !== 0 && stderr) throw new Error(stderr);
@@ -6781,8 +6879,17 @@ const r2Storage = (0, _hot_updater_plugin_core.createStoragePlugin)({
6781
6879
  }
6782
6880
  return { storageUri: `r2://${bucketName}/${Key}` };
6783
6881
  },
6784
- async getDownloadUrl() {
6785
- throw new Error("`r2Storage` does not support `getDownloadUrl()`. Use `s3Storage` from `@hot-updater/aws` instead (compatible with Cloudflare R2).\n\nExample:\ns3Storage({\n region: 'auto',\n endpoint: 'https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com',\n credentials: {\n accessKeyId: 'YOUR_ACCESS_KEY_ID',\n secretAccessKey: 'YOUR_SECRET_ACCESS_KEY',\n },\n bucketName: 'YOUR_BUCKET_NAME',\n})");
6882
+ async downloadFile(storageUri, filePath) {
6883
+ const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "r2");
6884
+ if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
6885
+ try {
6886
+ await node_fs_promises.default.mkdir(node_path.default.dirname(filePath), { recursive: true });
6887
+ const { stderr, exitCode } = await wrangler("r2", "object", "get", [bucketName, key].join("/"), "--file", filePath, "--remote");
6888
+ if (exitCode !== 0 && stderr) throw new Error(stderr);
6889
+ } catch (error) {
6890
+ if (error instanceof ExecaError) throw new Error(error.stderr || error.stdout);
6891
+ throw error;
6892
+ }
6786
6893
  }
6787
6894
  };
6788
6895
  }
package/dist/index.d.cts CHANGED
@@ -20,27 +20,7 @@ interface R2StorageConfig {
20
20
  }
21
21
  /**
22
22
  * Cloudflare R2 storage plugin for Hot Updater.
23
- *
24
- * Note: This plugin does not support `getDownloadUrl()`.
25
- * If you need download URL generation, use `s3Storage` from `@hot-updater/aws` instead,
26
- * which is fully compatible with Cloudflare R2.
27
- *
28
- * @example
29
- * ```typescript
30
- * // Using s3Storage with Cloudflare R2 for download URL support
31
- * import { s3Storage } from "@hot-updater/aws";
32
- *
33
- * s3Storage({
34
- * region: "auto",
35
- * endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com",
36
- * credentials: {
37
- * accessKeyId: "YOUR_ACCESS_KEY_ID",
38
- * secretAccessKey: "YOUR_SECRET_ACCESS_KEY",
39
- * },
40
- * bucketName: "YOUR_BUCKET_NAME",
41
- * })
42
- * ```
43
23
  */
44
- declare const r2Storage: (config: R2StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.StoragePlugin<unknown>;
24
+ declare const r2Storage: (config: R2StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.NodeStoragePlugin;
45
25
  //#endregion
46
26
  export { D1DatabaseConfig, R2StorageConfig, d1Database, r2Storage };
package/dist/index.d.mts CHANGED
@@ -20,27 +20,7 @@ interface R2StorageConfig {
20
20
  }
21
21
  /**
22
22
  * Cloudflare R2 storage plugin for Hot Updater.
23
- *
24
- * Note: This plugin does not support `getDownloadUrl()`.
25
- * If you need download URL generation, use `s3Storage` from `@hot-updater/aws` instead,
26
- * which is fully compatible with Cloudflare R2.
27
- *
28
- * @example
29
- * ```typescript
30
- * // Using s3Storage with Cloudflare R2 for download URL support
31
- * import { s3Storage } from "@hot-updater/aws";
32
- *
33
- * s3Storage({
34
- * region: "auto",
35
- * endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com",
36
- * credentials: {
37
- * accessKeyId: "YOUR_ACCESS_KEY_ID",
38
- * secretAccessKey: "YOUR_SECRET_ACCESS_KEY",
39
- * },
40
- * bucketName: "YOUR_BUCKET_NAME",
41
- * })
42
- * ```
43
23
  */
44
- declare const r2Storage: (config: R2StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.StoragePlugin<unknown>;
24
+ declare const r2Storage: (config: R2StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.NodeStoragePlugin;
45
25
  //#endregion
46
26
  export { D1DatabaseConfig, R2StorageConfig, d1Database, r2Storage };