@hot-updater/server 0.35.12 → 0.36.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.
@@ -14,7 +14,6 @@ let node_zlib = require("node:zlib");
14
14
  let _hot_updater_bsdiff = require("@hot-updater/bsdiff");
15
15
  //#region src/db/createBundleDiff.ts
16
16
  const HBC_ASSET_PATH_RE = /\.bundle$/;
17
- const BR_COMPRESSED_ASSET_PATH_RE = /(^|\/)index\.[^/]+\.bundle$/;
18
17
  const HOT_UPDATER_DOWNLOAD_DIR_PREFIX = "downloads-";
19
18
  const decompressBrotli = (0, node_util.promisify)(node_zlib.brotliDecompress);
20
19
  const isBundleManifest = (value) => {
@@ -77,10 +76,11 @@ async function fetchAssetBytes(bundle, assetPath, manifest, storagePlugin) {
77
76
  if (!assetBaseStorageUri) throw new Error(`Bundle ${bundle.id} does not have asset storage metadata`);
78
77
  const asset = manifest.assets[assetPath];
79
78
  if (!asset) throw new Error(`Asset ${assetPath} is missing from manifest`);
80
- if (BR_COMPRESSED_ASSET_PATH_RE.test(assetPath)) {
79
+ const downloadPath = (0, _hot_updater_plugin_core.getManifestAssetDownloadPath)(assetPath);
80
+ if (downloadPath !== assetPath) {
81
81
  const compressedAssetStorageUri = (0, _hot_updater_plugin_core.resolveManifestAssetStorageUri)({
82
82
  assetBaseStorageUri,
83
- assetPath: `${assetPath}.br`,
83
+ assetPath: downloadPath,
84
84
  fileHash: asset.fileHash
85
85
  });
86
86
  let compressedBytes = null;
@@ -131,12 +131,7 @@ async function createBundleDiff({ baseBundleId, bundleId }, deps, options = {})
131
131
  const previousPatch = (0, _hot_updater_core.getBundlePatch)(targetBundle, baseBundle.id);
132
132
  try {
133
133
  await node_fs_promises.default.writeFile(patchPath, patchBytes);
134
- const uploadKey = [
135
- targetBundle.id,
136
- "patches",
137
- baseBundle.id,
138
- getRelativeStorageDir(targetAssetPath)
139
- ].filter(Boolean).join("/");
134
+ const uploadKey = (0, _hot_updater_plugin_core.createBundleStorageKey)(targetBundle.id, "patches", baseBundle.id, getRelativeStorageDir(targetAssetPath));
140
135
  const patchUpload = await deps.storagePlugin.profiles.node.upload(uploadKey, patchPath);
141
136
  const patchFileHash = await getFileHash(patchPath);
142
137
  const nextState = buildNextPatchState({
@@ -1,4 +1,4 @@
1
- import { resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
1
+ import { createBundleStorageKey, getManifestAssetDownloadPath, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
2
2
  import { getAssetBaseStorageUri, getBundlePatch, getBundlePatches, getManifestStorageUri } from "@hot-updater/core";
3
3
  import crypto, { randomUUID } from "node:crypto";
4
4
  import fs from "node:fs/promises";
@@ -9,7 +9,6 @@ import { brotliDecompress } from "node:zlib";
9
9
  import { hdiff } from "@hot-updater/bsdiff";
10
10
  //#region src/db/createBundleDiff.ts
11
11
  const HBC_ASSET_PATH_RE = /\.bundle$/;
12
- const BR_COMPRESSED_ASSET_PATH_RE = /(^|\/)index\.[^/]+\.bundle$/;
13
12
  const HOT_UPDATER_DOWNLOAD_DIR_PREFIX = "downloads-";
14
13
  const decompressBrotli = promisify(brotliDecompress);
15
14
  const isBundleManifest = (value) => {
@@ -72,10 +71,11 @@ async function fetchAssetBytes(bundle, assetPath, manifest, storagePlugin) {
72
71
  if (!assetBaseStorageUri) throw new Error(`Bundle ${bundle.id} does not have asset storage metadata`);
73
72
  const asset = manifest.assets[assetPath];
74
73
  if (!asset) throw new Error(`Asset ${assetPath} is missing from manifest`);
75
- if (BR_COMPRESSED_ASSET_PATH_RE.test(assetPath)) {
74
+ const downloadPath = getManifestAssetDownloadPath(assetPath);
75
+ if (downloadPath !== assetPath) {
76
76
  const compressedAssetStorageUri = resolveManifestAssetStorageUri({
77
77
  assetBaseStorageUri,
78
- assetPath: `${assetPath}.br`,
78
+ assetPath: downloadPath,
79
79
  fileHash: asset.fileHash
80
80
  });
81
81
  let compressedBytes = null;
@@ -126,12 +126,7 @@ async function createBundleDiff({ baseBundleId, bundleId }, deps, options = {})
126
126
  const previousPatch = getBundlePatch(targetBundle, baseBundle.id);
127
127
  try {
128
128
  await fs.writeFile(patchPath, patchBytes);
129
- const uploadKey = [
130
- targetBundle.id,
131
- "patches",
132
- baseBundle.id,
133
- getRelativeStorageDir(targetAssetPath)
134
- ].filter(Boolean).join("/");
129
+ const uploadKey = createBundleStorageKey(targetBundle.id, "patches", baseBundle.id, getRelativeStorageDir(targetAssetPath));
135
130
  const patchUpload = await deps.storagePlugin.profiles.node.upload(uploadKey, patchPath);
136
131
  const patchFileHash = await getFileHash(patchPath);
137
132
  const nextState = buildNextPatchState({
@@ -3,7 +3,6 @@ let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
3
3
  let _hot_updater_core = require("@hot-updater/core");
4
4
  //#region src/db/updateArtifacts.ts
5
5
  const HBC_ASSET_PATH_RE = /\.bundle$/;
6
- const BR_COMPRESSED_ASSET_PATH_RE = /(^|\/)index\.[^/]+\.bundle$/;
7
6
  const resolveUniqueHbcAssetPath = (manifest) => {
8
7
  const candidates = Object.keys(manifest.assets).sort((left, right) => left.localeCompare(right)).filter((candidate) => HBC_ASSET_PATH_RE.test(candidate));
9
8
  return candidates.length === 1 ? candidates[0] : null;
@@ -56,10 +55,11 @@ async function resolveChangedAssets({ assetBaseStorageUri, currentManifest, curr
56
55
  });
57
56
  const changedEntries = await Promise.all(Object.entries(targetManifest.assets).map(async ([assetPath, asset]) => {
58
57
  if ((currentManifest?.assets[assetPath])?.fileHash === asset.fileHash) return null;
59
- const usesBrotliAsset = BR_COMPRESSED_ASSET_PATH_RE.test(assetPath);
58
+ const downloadPath = (0, _hot_updater_plugin_core.getManifestAssetDownloadPath)(assetPath);
59
+ const usesBrotliAsset = downloadPath !== assetPath;
60
60
  const storageUri = (0, _hot_updater_plugin_core.resolveManifestAssetStorageUri)({
61
61
  assetBaseStorageUri,
62
- assetPath: usesBrotliAsset ? `${assetPath}.br` : assetPath,
62
+ assetPath: downloadPath,
63
63
  fileHash: asset.fileHash
64
64
  });
65
65
  const patch = patchDescriptor?.assetPath === assetPath ? patchDescriptor.patch : null;
@@ -1,8 +1,7 @@
1
- import { resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
1
+ import { getManifestAssetDownloadPath, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
2
2
  import { getAssetBaseStorageUri, getBundlePatch, getManifestFileHash, getManifestStorageUri, stripBundleArtifactMetadata } from "@hot-updater/core";
3
3
  //#region src/db/updateArtifacts.ts
4
4
  const HBC_ASSET_PATH_RE = /\.bundle$/;
5
- const BR_COMPRESSED_ASSET_PATH_RE = /(^|\/)index\.[^/]+\.bundle$/;
6
5
  const resolveUniqueHbcAssetPath = (manifest) => {
7
6
  const candidates = Object.keys(manifest.assets).sort((left, right) => left.localeCompare(right)).filter((candidate) => HBC_ASSET_PATH_RE.test(candidate));
8
7
  return candidates.length === 1 ? candidates[0] : null;
@@ -55,10 +54,11 @@ async function resolveChangedAssets({ assetBaseStorageUri, currentManifest, curr
55
54
  });
56
55
  const changedEntries = await Promise.all(Object.entries(targetManifest.assets).map(async ([assetPath, asset]) => {
57
56
  if ((currentManifest?.assets[assetPath])?.fileHash === asset.fileHash) return null;
58
- const usesBrotliAsset = BR_COMPRESSED_ASSET_PATH_RE.test(assetPath);
57
+ const downloadPath = getManifestAssetDownloadPath(assetPath);
58
+ const usesBrotliAsset = downloadPath !== assetPath;
59
59
  const storageUri = resolveManifestAssetStorageUri({
60
60
  assetBaseStorageUri,
61
- assetPath: usesBrotliAsset ? `${assetPath}.br` : assetPath,
61
+ assetPath: downloadPath,
62
62
  fileHash: asset.fileHash
63
63
  });
64
64
  const patch = patchDescriptor?.assetPath === assetPath ? patchDescriptor.patch : null;
package/dist/package.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.35.12";
2
+ var version = "0.36.0";
3
3
  //#endregion
4
4
  Object.defineProperty(exports, "version", {
5
5
  enumerable: true,
package/dist/package.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.35.12";
2
+ var version = "0.36.0";
3
3
  //#endregion
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/server",
3
- "version": "0.35.12",
3
+ "version": "0.36.0",
4
4
  "type": "module",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "sideEffects": false,
@@ -55,10 +55,10 @@
55
55
  "dependencies": {
56
56
  "rou3": "0.7.9",
57
57
  "verkit": "0.3.2",
58
- "@hot-updater/bsdiff": "0.35.12",
59
- "@hot-updater/core": "0.35.12",
60
- "@hot-updater/plugin-core": "0.35.12",
61
- "@hot-updater/js": "0.35.12"
58
+ "@hot-updater/js": "0.36.0",
59
+ "@hot-updater/bsdiff": "0.36.0",
60
+ "@hot-updater/plugin-core": "0.36.0",
61
+ "@hot-updater/core": "0.36.0"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "@prisma/client": "*",
@@ -90,8 +90,8 @@
90
90
  "mongodb": "6.20.0",
91
91
  "msw": "^2.7.0",
92
92
  "uuidv7": "^1.0.2",
93
- "@hot-updater/standalone": "0.35.12",
94
- "@hot-updater/test-utils": "0.35.12"
93
+ "@hot-updater/standalone": "0.36.0",
94
+ "@hot-updater/test-utils": "0.36.0"
95
95
  },
96
96
  "scripts": {
97
97
  "build": "tsdown",
@@ -193,7 +193,7 @@ describe("createBundleDiff", () => {
193
193
  });
194
194
  expect(updatedBundle.patchFileHash).toMatch(/[a-f0-9]{64}/);
195
195
  expect(updatedBundle.patchStorageUri).toContain(
196
- `${targetBundle.id}/patches/${baseBundle.id}`,
196
+ `bundles/${targetBundle.id}/patches/${baseBundle.id}`,
197
197
  );
198
198
  expect(updatedBundle.patches).toEqual([
199
199
  {
@@ -394,7 +394,7 @@ describe("createBundleDiff", () => {
394
394
  baseFileHash: "hash-secondary-old",
395
395
  patchFileHash: expect.any(String),
396
396
  patchStorageUri: expect.stringContaining(
397
- `${targetBundle.id}/patches/${secondaryBaseBundle.id}`,
397
+ `bundles/${targetBundle.id}/patches/${secondaryBaseBundle.id}`,
398
398
  ),
399
399
  },
400
400
  ]);
@@ -17,7 +17,11 @@ import type {
17
17
  DatabasePlugin,
18
18
  NodeStoragePlugin,
19
19
  } from "@hot-updater/plugin-core";
20
- import { resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
20
+ import {
21
+ createBundleStorageKey,
22
+ getManifestAssetDownloadPath,
23
+ resolveManifestAssetStorageUri,
24
+ } from "@hot-updater/plugin-core";
21
25
 
22
26
  type BundleManifest = {
23
27
  bundleId: string;
@@ -39,7 +43,6 @@ export interface CreateBundleDiffOptions {
39
43
  }
40
44
 
41
45
  const HBC_ASSET_PATH_RE = /\.bundle$/;
42
- const BR_COMPRESSED_ASSET_PATH_RE = /(^|\/)index\.[^/]+\.bundle$/;
43
46
  const HOT_UPDATER_DOWNLOAD_DIR_PREFIX = "downloads-";
44
47
  const decompressBrotli = promisify(brotliDecompress);
45
48
 
@@ -186,10 +189,11 @@ async function fetchAssetBytes(
186
189
  throw new Error(`Asset ${assetPath} is missing from manifest`);
187
190
  }
188
191
 
189
- if (BR_COMPRESSED_ASSET_PATH_RE.test(assetPath)) {
192
+ const downloadPath = getManifestAssetDownloadPath(assetPath);
193
+ if (downloadPath !== assetPath) {
190
194
  const compressedAssetStorageUri = resolveManifestAssetStorageUri({
191
195
  assetBaseStorageUri,
192
- assetPath: `${assetPath}.br`,
196
+ assetPath: downloadPath,
193
197
  fileHash: asset.fileHash,
194
198
  });
195
199
 
@@ -321,14 +325,12 @@ export async function createBundleDiff(
321
325
  try {
322
326
  await fs.writeFile(patchPath, patchBytes);
323
327
 
324
- const uploadKey = [
328
+ const uploadKey = createBundleStorageKey(
325
329
  targetBundle.id,
326
330
  "patches",
327
331
  baseBundle.id,
328
332
  getRelativeStorageDir(targetAssetPath),
329
- ]
330
- .filter(Boolean)
331
- .join("/");
333
+ );
332
334
  const patchUpload = await deps.storagePlugin.profiles.node.upload(
333
335
  uploadKey,
334
336
  patchPath,
@@ -9,6 +9,7 @@ import {
9
9
  type ChangedAsset,
10
10
  } from "@hot-updater/core";
11
11
  import {
12
+ getManifestAssetDownloadPath,
12
13
  resolveManifestAssetStorageUri,
13
14
  type HotUpdaterContext,
14
15
  } from "@hot-updater/plugin-core";
@@ -29,7 +30,6 @@ type ReadStorageText<TContext> = (
29
30
  ) => Promise<string | null>;
30
31
 
31
32
  const HBC_ASSET_PATH_RE = /\.bundle$/;
32
- const BR_COMPRESSED_ASSET_PATH_RE = /(^|\/)index\.[^/]+\.bundle$/;
33
33
 
34
34
  const resolveUniqueHbcAssetPath = (manifest: BundleManifest) => {
35
35
  const candidates = Object.keys(manifest.assets)
@@ -199,8 +199,8 @@ async function resolveChangedAssets<TContext>({
199
199
  return null;
200
200
  }
201
201
 
202
- const usesBrotliAsset = BR_COMPRESSED_ASSET_PATH_RE.test(assetPath);
203
- const downloadPath = usesBrotliAsset ? `${assetPath}.br` : assetPath;
202
+ const downloadPath = getManifestAssetDownloadPath(assetPath);
203
+ const usesBrotliAsset = downloadPath !== assetPath;
204
204
  const storageUri = resolveManifestAssetStorageUri({
205
205
  assetBaseStorageUri,
206
206
  assetPath: downloadPath,