@hot-updater/cli-tools 0.35.12 → 0.36.1

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.
Files changed (2) hide show
  1. package/dist/index.mjs +33 -20
  2. package/package.json +4 -4
package/dist/index.mjs CHANGED
@@ -36,7 +36,7 @@ import { parseSync } from "oxc-parser";
36
36
  import { loadConfig as loadConfig$1 } from "unconfig";
37
37
  import { brotliDecompressSync, createBrotliCompress as createBrotliCompress$1 } from "node:zlib";
38
38
  import { getManifestFileHash, stripBundleArtifactMetadata } from "@hot-updater/core";
39
- import { createUUIDv7, detectCompressionFormat } from "@hot-updater/plugin-core";
39
+ import { createBundleStorageKey, createStorageRootUriWithPath, createUUIDv7, detectCompressionFormat, getContentAddressedAssetStoragePath, getManifestAssetDownloadPath, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
40
40
  import { transformSync } from "oxc-transform";
41
41
  //#endregion
42
42
  //#region src/colors.ts
@@ -43875,7 +43875,6 @@ const getRelativeStorageDir = (relativePath) => {
43875
43875
  const dirname = path$1.posix.dirname(normalized);
43876
43876
  return dirname === "." ? "" : dirname;
43877
43877
  };
43878
- const isBundleAsset = (relativePath) => /(^|\/)[^/]+\.(ios|android)\.bundle$/.test(relativePath.replace(/\\/g, "/"));
43879
43878
  function resolvePreparedUploadPath(rootDir, assetPath) {
43880
43879
  const normalizedAssetPath = assetPath.replaceAll("\\", "/");
43881
43880
  const outputPath = path$1.resolve(rootDir, "upload-artifacts", `${normalizedAssetPath}.br`);
@@ -43884,19 +43883,20 @@ function resolvePreparedUploadPath(rootDir, assetPath) {
43884
43883
  return outputPath;
43885
43884
  }
43886
43885
  async function prepareManifestAssetUploadFile({ assetPath, sourcePath, workDir }) {
43887
- if (!isBundleAsset(assetPath)) return sourcePath;
43886
+ if (getManifestAssetDownloadPath(assetPath) === assetPath) return sourcePath;
43888
43887
  const uploadPath = resolvePreparedUploadPath(workDir, assetPath);
43889
43888
  await fs$3.mkdir(path$1.dirname(uploadPath), { recursive: true });
43890
43889
  await pipeline$1(createReadStream(sourcePath), createBrotliCompress$1(), createWriteStream$1(uploadPath));
43891
43890
  return uploadPath;
43892
43891
  }
43893
- const replaceStorageUriLeaf = (storageUri, nextLeaf) => {
43894
- const storageUrl = new URL(storageUri);
43895
- const normalizedPath = storageUrl.pathname.replace(/\/+$/, "");
43896
- const lastSlashIndex = normalizedPath.lastIndexOf("/");
43897
- storageUrl.pathname = `${lastSlashIndex >= 0 ? normalizedPath.slice(0, lastSlashIndex) : ""}/${nextLeaf}`;
43898
- return storageUrl.toString();
43899
- };
43892
+ async function prepareContentAddressedUploadFile({ sourcePath, storagePath, workDir }) {
43893
+ const filename = path$1.posix.basename(storagePath);
43894
+ if (path$1.basename(sourcePath) === filename) return sourcePath;
43895
+ const uploadPath = path$1.join(workDir, "upload-artifacts", "content-addressed", filename);
43896
+ await fs$3.mkdir(path$1.dirname(uploadPath), { recursive: true });
43897
+ await fs$3.copyFile(sourcePath, uploadPath);
43898
+ return uploadPath;
43899
+ }
43900
43900
  function resolveExtractedPath(rootDir, entryName) {
43901
43901
  const normalizedEntryName = entryName.replaceAll("\\", "/");
43902
43902
  const entryPath = path$1.resolve(rootDir, normalizedEntryName);
@@ -44037,26 +44037,39 @@ async function createCopiedBundleArchive({ bundle, config, nextBundleId, storage
44037
44037
  const signingKeyPath = config.signing?.enabled && config.signing.privateKeyPath ? config.signing.privateKeyPath : null;
44038
44038
  const nextFileHash = signingKeyPath ? await signFileHash(fileHash, signingKeyPath) : fileHash;
44039
44039
  const nextManifestFileHash = signingKeyPath ? await signFileHash(manifestHash, signingKeyPath) : manifestHash;
44040
- const archiveUpload = await storagePlugin.profiles.node.upload(nextBundleId, outputArchivePath);
44040
+ const archiveUpload = await storagePlugin.profiles.node.upload(createBundleStorageKey(nextBundleId), outputArchivePath);
44041
44041
  uploadedStorageUris.push(archiveUpload.storageUri);
44042
- const manifestUpload = await storagePlugin.profiles.node.upload(nextBundleId, manifestPath);
44042
+ const manifestUpload = await storagePlugin.profiles.node.upload(createBundleStorageKey(nextBundleId), manifestPath);
44043
44043
  uploadedStorageUris.push(manifestUpload.storageUri);
44044
+ const assetBaseStorageUri = createStorageRootUriWithPath(manifestUpload.storageUri, nextBundleId, "assets");
44044
44045
  const assetPaths = Object.keys(manifest.assets ?? {}).sort((left, right) => left.localeCompare(right));
44045
44046
  for (const assetPath of assetPaths) {
44046
- const uploadKey = [
44047
- nextBundleId,
44048
- "files",
44049
- getRelativeStorageDir(assetPath)
44050
- ].filter(Boolean).join("/");
44047
+ const asset = manifest.assets?.[assetPath];
44048
+ if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
44051
44049
  const uploadPath = await prepareManifestAssetUploadFile({
44052
44050
  assetPath,
44053
44051
  sourcePath: path$1.join(extractDir, assetPath),
44054
44052
  workDir
44055
44053
  });
44056
- const assetUpload = await storagePlugin.profiles.node.upload(uploadKey, uploadPath);
44057
- uploadedStorageUris.push(assetUpload.storageUri);
44054
+ const uploadName = getManifestAssetDownloadPath(assetPath);
44055
+ const storagePath = getContentAddressedAssetStoragePath({
44056
+ assetPath: uploadName,
44057
+ fileHash: asset.fileHash
44058
+ });
44059
+ const storageUri = resolveManifestAssetStorageUri({
44060
+ assetBaseStorageUri,
44061
+ assetPath: uploadName,
44062
+ fileHash: asset.fileHash
44063
+ });
44064
+ if (!await storagePlugin.profiles.node.exists(storageUri)) {
44065
+ const contentAddressedUploadPath = await prepareContentAddressedUploadFile({
44066
+ sourcePath: uploadPath,
44067
+ storagePath,
44068
+ workDir
44069
+ });
44070
+ await storagePlugin.profiles.node.upload(getRelativeStorageDir(storagePath) ? `assets/${getRelativeStorageDir(storagePath)}` : "assets", contentAddressedUploadPath);
44071
+ }
44058
44072
  }
44059
- const assetBaseStorageUri = replaceStorageUriLeaf(manifestUpload.storageUri, "files");
44060
44073
  return {
44061
44074
  bundle: {
44062
44075
  ...bundle,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/cli-tools",
3
- "version": "0.35.12",
3
+ "version": "0.36.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20.19.0"
@@ -49,8 +49,8 @@
49
49
  "oxc-parser": "0.141.0",
50
50
  "oxc-transform": "0.141.0",
51
51
  "unconfig": "7.5.0",
52
- "@hot-updater/core": "0.35.12",
53
- "@hot-updater/plugin-core": "0.35.12"
52
+ "@hot-updater/core": "0.36.1",
53
+ "@hot-updater/plugin-core": "0.36.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@clack/prompts": "1.7.0",
@@ -64,7 +64,7 @@
64
64
  "tar": "^7.5.16",
65
65
  "verkit": "0.3.2",
66
66
  "workspace-tools": "^0.41.7",
67
- "@hot-updater/test-utils": "0.35.12"
67
+ "@hot-updater/test-utils": "0.36.1"
68
68
  },
69
69
  "inlinedDependencies": {
70
70
  "@babel/code-frame": "7.29.0",