@hot-updater/aws 0.31.4 → 0.32.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.
@@ -6,7 +6,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
9
+ var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
10
10
  var __copyProps = (to, from, except, desc) => {
11
11
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
12
  key = keys[i];
@@ -29,13 +29,13 @@ let node_child_process = require("node:child_process");
29
29
  let node_string_decoder = require("node:string_decoder");
30
30
  let node_util = require("node:util");
31
31
  let node_process = require("node:process");
32
- node_process = __toESM(node_process, 1);
32
+ node_process = __toESM(node_process);
33
33
  let node_tty = require("node:tty");
34
- node_tty = __toESM(node_tty, 1);
34
+ node_tty = __toESM(node_tty);
35
35
  let node_path = require("node:path");
36
- node_path = __toESM(node_path, 1);
36
+ node_path = __toESM(node_path);
37
37
  let path = require("path");
38
- path = __toESM(path, 1);
38
+ path = __toESM(path);
39
39
  let node_timers_promises = require("node:timers/promises");
40
40
  let node_os = require("node:os");
41
41
  let node_events = require("node:events");
@@ -45,12 +45,12 @@ let node_stream_promises = require("node:stream/promises");
45
45
  let node_stream = require("node:stream");
46
46
  let node_buffer = require("node:buffer");
47
47
  let crypto = require("crypto");
48
- crypto = __toESM(crypto, 1);
48
+ crypto = __toESM(crypto);
49
49
  let _aws_sdk_client_cloudfront = require("@aws-sdk/client-cloudfront");
50
50
  let _aws_sdk_client_iam = require("@aws-sdk/client-iam");
51
51
  let _aws_sdk_client_sts = require("@aws-sdk/client-sts");
52
52
  let fs_promises = require("fs/promises");
53
- fs_promises = __toESM(fs_promises, 1);
53
+ fs_promises = __toESM(fs_promises);
54
54
  let _aws_sdk_client_lambda = require("@aws-sdk/client-lambda");
55
55
  let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
56
56
  let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
@@ -33,7 +33,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
33
33
  var __getOwnPropNames = Object.getOwnPropertyNames;
34
34
  var __getProtoOf = Object.getPrototypeOf;
35
35
  var __hasOwnProp = Object.prototype.hasOwnProperty;
36
- var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
36
+ var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
37
37
  var __copyProps = (to, from, except, desc) => {
38
38
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
39
39
  key = keys[i];
package/dist/index.cjs CHANGED
@@ -26,9 +26,9 @@ let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
26
26
  let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
27
27
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
28
28
  let fs_promises = require("fs/promises");
29
- fs_promises = __toESM(fs_promises, 1);
29
+ fs_promises = __toESM(fs_promises);
30
30
  let path = require("path");
31
- path = __toESM(path, 1);
31
+ path = __toESM(path);
32
32
  let _aws_sdk_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
33
33
  let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
34
34
  let _aws_sdk_cloudfront_signer = require("@aws-sdk/cloudfront-signer");
@@ -1578,6 +1578,20 @@ const s3Storage = (0, _hot_updater_plugin_core.createUniversalStoragePlugin)({
1578
1578
  if (!response.Bucket || !response.Key) throw new Error("Upload Failed");
1579
1579
  return { storageUri: `s3://${bucketName}/${Key}` };
1580
1580
  },
1581
+ async exists(storageUri) {
1582
+ const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1583
+ if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
1584
+ try {
1585
+ await client.send(new _aws_sdk_client_s3.HeadObjectCommand({
1586
+ Bucket: bucketName,
1587
+ Key: key
1588
+ }));
1589
+ return true;
1590
+ } catch (error) {
1591
+ if (error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchKey")) return false;
1592
+ throw error;
1593
+ }
1594
+ },
1581
1595
  async downloadFile(storageUri, filePath) {
1582
1596
  const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1583
1597
  if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
- import { S3ClientConfig } from "@aws-sdk/client-s3";
1
+ import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
2
2
  import { BlobDatabasePluginConfig, RuntimeStoragePlugin, StoragePluginHooks, StorageResolveContext } from "@hot-updater/plugin-core";
3
+ import { S3ClientConfig } from "@aws-sdk/client-s3";
3
4
 
4
5
  //#region src/s3Database.d.ts
5
6
  interface S3DatabaseConfig extends S3ClientConfig, BlobDatabasePluginConfig {
@@ -21,7 +22,7 @@ interface S3DatabaseConfig extends S3ClientConfig, BlobDatabasePluginConfig {
21
22
  shouldWaitForInvalidation?: boolean;
22
23
  apiBasePath?: string;
23
24
  }
24
- declare const s3Database: (config: S3DatabaseConfig, hooks?: import("@hot-updater/plugin-core").DatabasePluginHooks) => () => import("@hot-updater/plugin-core").DatabasePlugin<unknown>;
25
+ declare const s3Database: (config: S3DatabaseConfig, hooks?: _$_hot_updater_plugin_core0.DatabasePluginHooks) => () => _$_hot_updater_plugin_core0.DatabasePlugin<unknown>;
25
26
  //#endregion
26
27
  //#region src/s3Storage.d.ts
27
28
  interface S3StorageConfig extends S3ClientConfig {
@@ -31,7 +32,7 @@ interface S3StorageConfig extends S3ClientConfig {
31
32
  */
32
33
  basePath?: string;
33
34
  }
34
- declare const s3Storage: (config: S3StorageConfig, hooks?: import("@hot-updater/plugin-core").StoragePluginHooks) => () => import("@hot-updater/plugin-core").UniversalStoragePlugin<unknown>;
35
+ declare const s3Storage: (config: S3StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
35
36
  //#endregion
36
37
  //#region src/withCloudFrontSignedUrl.d.ts
37
38
  interface CloudFrontPrivateKeyFromGetter {
@@ -55,7 +56,7 @@ declare const withCloudFrontSignedUrl: <TContext = unknown, TStorage extends Run
55
56
  //#endregion
56
57
  //#region src/s3LambdaEdgeStorage.d.ts
57
58
  type AwsLambdaEdgeStorageConfig = S3StorageConfig & WithCloudFrontSignedUrlOptions;
58
- declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => import("@hot-updater/plugin-core").UniversalStoragePlugin<unknown>;
59
- declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => import("@hot-updater/plugin-core").UniversalStoragePlugin<unknown>;
59
+ declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
60
+ declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
60
61
  //#endregion
61
62
  export { AwsLambdaEdgeStorageConfig, CloudFrontSignedUrlConfig, PublicBaseUrlResolver, S3DatabaseConfig, S3StorageConfig, WithCloudFrontSignedUrlOptions, awsLambdaEdgeStorage, s3Database, s3LambdaEdgeStorage, s3Storage, withCloudFrontSignedUrl };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { S3ClientConfig } from "@aws-sdk/client-s3";
2
+ import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
2
3
  import { BlobDatabasePluginConfig, RuntimeStoragePlugin, StoragePluginHooks, StorageResolveContext } from "@hot-updater/plugin-core";
3
4
 
4
5
  //#region src/s3Database.d.ts
@@ -21,7 +22,7 @@ interface S3DatabaseConfig extends S3ClientConfig, BlobDatabasePluginConfig {
21
22
  shouldWaitForInvalidation?: boolean;
22
23
  apiBasePath?: string;
23
24
  }
24
- declare const s3Database: (config: S3DatabaseConfig, hooks?: import("@hot-updater/plugin-core").DatabasePluginHooks) => () => import("@hot-updater/plugin-core").DatabasePlugin<unknown>;
25
+ declare const s3Database: (config: S3DatabaseConfig, hooks?: _$_hot_updater_plugin_core0.DatabasePluginHooks) => () => _$_hot_updater_plugin_core0.DatabasePlugin<unknown>;
25
26
  //#endregion
26
27
  //#region src/s3Storage.d.ts
27
28
  interface S3StorageConfig extends S3ClientConfig {
@@ -31,7 +32,7 @@ interface S3StorageConfig extends S3ClientConfig {
31
32
  */
32
33
  basePath?: string;
33
34
  }
34
- declare const s3Storage: (config: S3StorageConfig, hooks?: import("@hot-updater/plugin-core").StoragePluginHooks) => () => import("@hot-updater/plugin-core").UniversalStoragePlugin<unknown>;
35
+ declare const s3Storage: (config: S3StorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
35
36
  //#endregion
36
37
  //#region src/withCloudFrontSignedUrl.d.ts
37
38
  interface CloudFrontPrivateKeyFromGetter {
@@ -55,7 +56,7 @@ declare const withCloudFrontSignedUrl: <TContext = unknown, TStorage extends Run
55
56
  //#endregion
56
57
  //#region src/s3LambdaEdgeStorage.d.ts
57
58
  type AwsLambdaEdgeStorageConfig = S3StorageConfig & WithCloudFrontSignedUrlOptions;
58
- declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => import("@hot-updater/plugin-core").UniversalStoragePlugin<unknown>;
59
- declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => import("@hot-updater/plugin-core").UniversalStoragePlugin<unknown>;
59
+ declare const awsLambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
60
+ declare const s3LambdaEdgeStorage: (config: AwsLambdaEdgeStorageConfig, hooks?: StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
60
61
  //#endregion
61
62
  export { AwsLambdaEdgeStorageConfig, CloudFrontSignedUrlConfig, PublicBaseUrlResolver, S3DatabaseConfig, S3StorageConfig, WithCloudFrontSignedUrlOptions, awsLambdaEdgeStorage, s3Database, s3LambdaEdgeStorage, s3Storage, withCloudFrontSignedUrl };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CloudFrontClient, CreateInvalidationCommand, GetInvalidationCommand } from "@aws-sdk/client-cloudfront";
2
- import { DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, ListObjectsV2Command, NoSuchKey, S3Client } from "@aws-sdk/client-s3";
2
+ import { DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, S3Client } from "@aws-sdk/client-s3";
3
3
  import { Upload } from "@aws-sdk/lib-storage";
4
4
  import { createBlobDatabasePlugin, createStorageKeyBuilder, createUniversalStoragePlugin, getContentType, parseStorageUri } from "@hot-updater/plugin-core";
5
5
  import fs from "fs/promises";
@@ -1553,6 +1553,20 @@ const s3Storage = createUniversalStoragePlugin({
1553
1553
  if (!response.Bucket || !response.Key) throw new Error("Upload Failed");
1554
1554
  return { storageUri: `s3://${bucketName}/${Key}` };
1555
1555
  },
1556
+ async exists(storageUri) {
1557
+ const { bucket, key } = parseStorageUri(storageUri, "s3");
1558
+ if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
1559
+ try {
1560
+ await client.send(new HeadObjectCommand({
1561
+ Bucket: bucketName,
1562
+ Key: key
1563
+ }));
1564
+ return true;
1565
+ } catch (error) {
1566
+ if (error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchKey")) return false;
1567
+ throw error;
1568
+ }
1569
+ },
1556
1570
  async downloadFile(storageUri, filePath) {
1557
1571
  const { bucket, key } = parseStorageUri(storageUri, "s3");
1558
1572
  if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
@@ -6,7 +6,7 @@ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames$1 = Object.getOwnPropertyNames;
7
7
  var __getProtoOf$1 = Object.getPrototypeOf;
8
8
  var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
9
- var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
9
+ var __commonJSMin$1 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
10
10
  var __copyProps$1 = (to, from, except, desc) => {
11
11
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
12
12
  key = keys[i];
@@ -23,16 +23,16 @@ var __toESM$1 = (mod, isNodeMode, target) => (target = mod != null ? __create$1(
23
23
  }) : target, mod));
24
24
  //#endregion
25
25
  let node_path = require("node:path");
26
- node_path = __toESM$1(node_path, 1);
26
+ node_path = __toESM$1(node_path);
27
27
  let node_crypto = require("node:crypto");
28
- node_crypto = __toESM$1(node_crypto, 1);
28
+ node_crypto = __toESM$1(node_crypto);
29
29
  let _aws_sdk_client_cloudfront = require("@aws-sdk/client-cloudfront");
30
30
  let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
31
31
  let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
32
32
  let fs_promises = require("fs/promises");
33
- fs_promises = __toESM$1(fs_promises, 1);
33
+ fs_promises = __toESM$1(fs_promises);
34
34
  let path = require("path");
35
- path = __toESM$1(path, 1);
35
+ path = __toESM$1(path);
36
36
  let _aws_sdk_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
37
37
  let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
38
38
  let _aws_sdk_cloudfront_signer = require("@aws-sdk/cloudfront-signer");
@@ -1440,6 +1440,49 @@ function getContentType(bundlePath) {
1440
1440
  return src_default.getType(bundlePath) ?? getCompressionMimeType(filename) ?? "application/octet-stream";
1441
1441
  }
1442
1442
  //#endregion
1443
+ //#region ../plugin-core/dist/contentAddressedAssets.mjs
1444
+ const getContentAddressedAssetStoragePath = ({ assetPath, fileHash }) => {
1445
+ const extension = assetPath.endsWith(".br") ? ".br" : assetPath.includes(".") ? `.${assetPath.split(".").pop()}` : "";
1446
+ return `sha256/${fileHash.slice(0, 2)}/${fileHash}${extension}`;
1447
+ };
1448
+ //#endregion
1449
+ //#region ../plugin-core/dist/legacyAssetStorageLayout.mjs
1450
+ /**
1451
+ * @internal
1452
+ *
1453
+ * Legacy manifest assets were stored below each bundle's `/files` directory
1454
+ * using their manifest-relative path. Keep all old-layout path decisions here
1455
+ * so support can be removed by deleting this module and the entrypoint branch
1456
+ * that imports it.
1457
+ */
1458
+ const getLegacyManifestAssetStoragePath = ({ assetPath }) => assetPath;
1459
+ //#endregion
1460
+ //#region ../plugin-core/dist/assetStorageLayout.mjs
1461
+ const createStorageUriWithRelativePath = ({ baseStorageUri, relativePath }) => {
1462
+ const storageUrl = new URL(baseStorageUri);
1463
+ storageUrl.pathname = `${storageUrl.pathname.replace(/\/+$/, "")}/${relativePath.replace(/\\/g, "/").split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/")}`;
1464
+ return storageUrl.toString();
1465
+ };
1466
+ const getAssetStorageLayout = (assetBaseStorageUri) => {
1467
+ const pathname = new URL(assetBaseStorageUri).pathname.replace(/\/+$/, "");
1468
+ return pathname.endsWith("/assets") || pathname === "/assets" ? "content-addressed" : "legacy-files";
1469
+ };
1470
+ const getManifestAssetStoragePath = ({ assetBaseStorageUri, assetPath, fileHash }) => {
1471
+ if (getAssetStorageLayout(assetBaseStorageUri) === "content-addressed") return getContentAddressedAssetStoragePath({
1472
+ assetPath,
1473
+ fileHash
1474
+ });
1475
+ return getLegacyManifestAssetStoragePath({ assetPath });
1476
+ };
1477
+ const resolveManifestAssetStorageUri = ({ assetBaseStorageUri, assetPath, fileHash }) => createStorageUriWithRelativePath({
1478
+ baseStorageUri: assetBaseStorageUri,
1479
+ relativePath: getManifestAssetStoragePath({
1480
+ assetBaseStorageUri,
1481
+ assetPath,
1482
+ fileHash
1483
+ })
1484
+ });
1485
+ //#endregion
1443
1486
  //#region ../../node_modules/.pnpm/es-toolkit@1.32.0/node_modules/es-toolkit/dist/_internal/compareValues.mjs
1444
1487
  function compareValues(a, b, order) {
1445
1488
  if (a < b) return order === "asc" ? -1 : 1;
@@ -2795,7 +2838,6 @@ var require_min_version$2 = /* @__PURE__ */ __commonJSMin$1(((exports, module) =
2795
2838
  break;
2796
2839
  case "<":
2797
2840
  case "<=": break;
2798
- /* istanbul ignore next */
2799
2841
  default: throw new Error(`Unexpected operation: ${comparator.operator}`);
2800
2842
  }
2801
2843
  });
@@ -3319,7 +3361,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3319
3361
  var __getOwnPropNames = Object.getOwnPropertyNames;
3320
3362
  var __getProtoOf = Object.getPrototypeOf;
3321
3363
  var __hasOwnProp = Object.prototype.hasOwnProperty;
3322
- var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
3364
+ var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
3323
3365
  var __copyProps = (to, from, except, desc) => {
3324
3366
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
3325
3367
  key = keys[i];
@@ -4308,7 +4350,6 @@ var require_min_version$1 = /* @__PURE__ */ __commonJSMin(((exports, module) =>
4308
4350
  break;
4309
4351
  case "<":
4310
4352
  case "<=": break;
4311
- /* istanbul ignore next */
4312
4353
  default: throw new Error(`Unexpected operation: ${comparator.operator}`);
4313
4354
  }
4314
4355
  });
@@ -5436,6 +5477,9 @@ const createProfiledStoragePlugin = ({ createProfiles, name, profileShape, suppo
5436
5477
  async downloadFile(storageUri, filePath) {
5437
5478
  return requireNodeProfile().downloadFile(storageUri, filePath);
5438
5479
  },
5480
+ async exists(storageUri) {
5481
+ return requireNodeProfile().exists(storageUri);
5482
+ },
5439
5483
  async upload(key, filePath) {
5440
5484
  return requireNodeProfile().upload(key, filePath);
5441
5485
  }
@@ -5554,11 +5598,6 @@ const isBundleManifest = (value) => {
5554
5598
  return typeof manifestAsset.fileHash === "string" && (manifestAsset.signature === void 0 || typeof manifestAsset.signature === "string");
5555
5599
  });
5556
5600
  };
5557
- const createChildStorageUri = (baseStorageUri, relativePath) => {
5558
- const baseUrl = new URL(baseStorageUri);
5559
- baseUrl.pathname = `${baseUrl.pathname.replace(/\/+$/, "")}/${relativePath.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/")}`;
5560
- return baseUrl.toString();
5561
- };
5562
5601
  async function fetchBundleManifest(storageUri, readStorageText, resolveFileUrl, context) {
5563
5602
  const [storageText, fileUrl] = await Promise.all([readStorageText(storageUri, context), resolveFileUrl(storageUri, context)]);
5564
5603
  if (storageText === null) return null;
@@ -5586,7 +5625,11 @@ async function resolveChangedAssets({ assetBaseStorageUri, currentManifest, curr
5586
5625
  const changedEntries = await Promise.all(Object.entries(targetManifest.assets).map(async ([assetPath, asset]) => {
5587
5626
  if ((currentManifest?.assets[assetPath])?.fileHash === asset.fileHash) return null;
5588
5627
  const usesBrotliAsset = BR_COMPRESSED_ASSET_PATH_RE.test(assetPath);
5589
- const storageUri = createChildStorageUri(assetBaseStorageUri, usesBrotliAsset ? `${assetPath}.br` : assetPath);
5628
+ const storageUri = resolveManifestAssetStorageUri({
5629
+ assetBaseStorageUri,
5630
+ assetPath: usesBrotliAsset ? `${assetPath}.br` : assetPath,
5631
+ fileHash: asset.fileHash
5632
+ });
5590
5633
  const patch = patchDescriptor?.assetPath === assetPath ? patchDescriptor.patch : null;
5591
5634
  let fileUrl = null;
5592
5635
  try {
@@ -6924,7 +6967,6 @@ var require_min_version = /* @__PURE__ */ __commonJSMin$1(((exports, module) =>
6924
6967
  break;
6925
6968
  case "<":
6926
6969
  case "<=": break;
6927
- /* istanbul ignore next */
6928
6970
  default: throw new Error(`Unexpected operation: ${comparator.operator}`);
6929
6971
  }
6930
6972
  });
@@ -7274,7 +7316,7 @@ function findRoute(router, method, path) {
7274
7316
  }
7275
7317
  //#endregion
7276
7318
  //#region ../../packages/server/src/version.ts
7277
- const HOT_UPDATER_SERVER_VERSION = "0.31.4";
7319
+ const HOT_UPDATER_SERVER_VERSION = "0.32.0";
7278
7320
  //#endregion
7279
7321
  //#region ../../packages/server/src/handler.ts
7280
7322
  var HandlerBadRequestError = class extends Error {
@@ -7285,6 +7327,8 @@ var HandlerBadRequestError = class extends Error {
7285
7327
  };
7286
7328
  const SDK_VERSION_HEADER = "Hot-Updater-SDK-Version";
7287
7329
  const EXPLICIT_NO_UPDATE_MIN_SDK_VERSION = "0.31.0";
7330
+ const DEFAULT_BUNDLE_LIST_LIMIT = 50;
7331
+ const MAX_BUNDLE_LIST_LIMIT = 100;
7288
7332
  const supportsExplicitNoUpdateResponse = (request) => {
7289
7333
  const sdkVersion = request.headers.get(SDK_VERSION_HEADER)?.trim();
7290
7334
  if (!sdkVersion) return false;
@@ -7334,6 +7378,13 @@ const parseStringArraySearchParam = (url, key) => {
7334
7378
  const values = url.searchParams.getAll(key);
7335
7379
  return values.length > 0 ? values : void 0;
7336
7380
  };
7381
+ const parsePositiveIntegerSearchParam = (url, key, defaultValue, maxValue) => {
7382
+ const value = url.searchParams.get(key);
7383
+ if (value === null) return defaultValue;
7384
+ const parsed = Number(value);
7385
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > maxValue) throw new HandlerBadRequestError(`The '${key}' query parameter must be a positive integer between 1 and ${maxValue}.`);
7386
+ return parsed;
7387
+ };
7337
7388
  const requirePlatformParam = (params) => {
7338
7389
  const platform = requireRouteParam(params, "platform");
7339
7390
  if (!isPlatform(platform)) throw new HandlerBadRequestError(`Invalid platform: ${platform}. Expected 'ios' or 'android'.`);
@@ -7402,7 +7453,7 @@ const handleGetBundles = async (_params, request, api, context) => {
7402
7453
  const url = new URL(request.url);
7403
7454
  const channel = url.searchParams.get("channel") ?? void 0;
7404
7455
  const platform = url.searchParams.get("platform");
7405
- const limit = Number(url.searchParams.get("limit")) || 50;
7456
+ const limit = parsePositiveIntegerSearchParam(url, "limit", DEFAULT_BUNDLE_LIST_LIMIT, MAX_BUNDLE_LIST_LIMIT);
7406
7457
  const pageParam = url.searchParams.get("page");
7407
7458
  const offset = url.searchParams.get("offset");
7408
7459
  const after = url.searchParams.get("after") ?? void 0;
@@ -7504,18 +7555,19 @@ const routes = {
7504
7555
  */
7505
7556
  function createHandler(api, options = {}) {
7506
7557
  const basePath = options.basePath ?? "/api";
7507
- const updateCheckEnabled = options.routes?.updateCheck ?? true;
7508
- const versionEnabled = options.routes?.version ?? true;
7509
- const bundlesEnabled = options.routes?.bundles ?? true;
7558
+ const routeOptions = {
7559
+ updateCheck: options.routes?.updateCheck ?? true,
7560
+ bundles: options.routes?.bundles ?? false
7561
+ };
7510
7562
  const router = createRouter();
7511
- if (versionEnabled) addRoute(router, "GET", "/version", "version");
7512
- if (updateCheckEnabled) {
7563
+ addRoute(router, "GET", "/version", "version");
7564
+ if (routeOptions.updateCheck) {
7513
7565
  addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId", "fingerprintUpdateWithCohort");
7514
7566
  addRoute(router, "GET", "/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId/:cohort", "fingerprintUpdateWithCohort");
7515
7567
  addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId", "appVersionUpdateWithCohort");
7516
7568
  addRoute(router, "GET", "/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId/:cohort", "appVersionUpdateWithCohort");
7517
7569
  }
7518
- if (bundlesEnabled) {
7570
+ if (routeOptions.bundles) {
7519
7571
  addRoute(router, "GET", "/api/bundles/channels", "getChannels");
7520
7572
  addRoute(router, "GET", "/api/bundles/:id", "getBundle");
7521
7573
  addRoute(router, "GET", "/api/bundles", "getBundles");
@@ -9696,6 +9748,20 @@ const s3Storage = createUniversalStoragePlugin({
9696
9748
  if (!response.Bucket || !response.Key) throw new Error("Upload Failed");
9697
9749
  return { storageUri: `s3://${bucketName}/${Key}` };
9698
9750
  },
9751
+ async exists(storageUri) {
9752
+ const { bucket, key } = parseStorageUri(storageUri, "s3");
9753
+ if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
9754
+ try {
9755
+ await client.send(new _aws_sdk_client_s3.HeadObjectCommand({
9756
+ Bucket: bucketName,
9757
+ Key: key
9758
+ }));
9759
+ return true;
9760
+ } catch (error) {
9761
+ if (error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchKey")) return false;
9762
+ throw error;
9763
+ }
9764
+ },
9699
9765
  async downloadFile(storageUri, filePath) {
9700
9766
  const { bucket, key } = parseStorageUri(storageUri, "s3");
9701
9767
  if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
@@ -9848,7 +9914,6 @@ const hotUpdater = createHotUpdater({
9848
9914
  basePath: HOT_UPDATER_BASE_PATH,
9849
9915
  routes: {
9850
9916
  updateCheck: true,
9851
- version: true,
9852
9917
  bundles: false
9853
9918
  }
9854
9919
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/aws",
3
3
  "type": "module",
4
- "version": "0.31.4",
4
+ "version": "0.32.0",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -42,10 +42,10 @@
42
42
  "es-toolkit": "^1.32.0",
43
43
  "execa": "9.5.2",
44
44
  "mime": "^4.0.4",
45
- "@hot-updater/core": "0.31.4",
46
- "@hot-updater/js": "0.31.4",
47
- "@hot-updater/mock": "0.31.4",
48
- "@hot-updater/test-utils": "0.31.4"
45
+ "@hot-updater/core": "0.32.0",
46
+ "@hot-updater/js": "0.32.0",
47
+ "@hot-updater/mock": "0.32.0",
48
+ "@hot-updater/test-utils": "0.32.0"
49
49
  },
50
50
  "dependencies": {
51
51
  "@aws-sdk/client-cloudfront": "3.1008.0",
@@ -60,9 +60,9 @@
60
60
  "@aws-sdk/lib-storage": "3.1008.0",
61
61
  "hono": "4.12.9",
62
62
  "aws-lambda": "1.0.7",
63
- "@hot-updater/cli-tools": "0.31.4",
64
- "@hot-updater/plugin-core": "0.31.4",
65
- "@hot-updater/server": "0.31.4"
63
+ "@hot-updater/cli-tools": "0.32.0",
64
+ "@hot-updater/server": "0.32.0",
65
+ "@hot-updater/plugin-core": "0.32.0"
66
66
  },
67
67
  "scripts": {
68
68
  "build": "tsdown",