@hot-updater/server 0.31.4 → 0.33.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.
Files changed (45) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/_virtual/_rolldown/runtime.mjs +1 -1
  3. package/dist/db/createBundleDiff.cjs +19 -13
  4. package/dist/db/createBundleDiff.mjs +15 -9
  5. package/dist/db/index.cjs +7 -10
  6. package/dist/db/index.mjs +7 -10
  7. package/dist/db/pluginCore.cjs +136 -96
  8. package/dist/db/pluginCore.mjs +137 -97
  9. package/dist/db/requestBundleIdentityMap.cjs +29 -0
  10. package/dist/db/requestBundleIdentityMap.mjs +29 -0
  11. package/dist/db/schemaEnhancements.cjs +1 -1
  12. package/dist/db/types.d.cts +2 -1
  13. package/dist/db/types.d.mts +2 -1
  14. package/dist/db/updateArtifacts.cjs +6 -6
  15. package/dist/db/updateArtifacts.mjs +6 -6
  16. package/dist/handler.cjs +18 -8
  17. package/dist/handler.d.cts +9 -10
  18. package/dist/handler.d.mts +9 -10
  19. package/dist/handler.mjs +17 -7
  20. package/dist/index.d.cts +1 -1
  21. package/dist/index.d.mts +1 -1
  22. package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index.d.cts +1 -1
  23. package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/index.d.mts +1 -1
  24. package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/query/index.d.cts +1 -1
  25. package/dist/node_modules/.pnpm/fumadb@0.2.2_drizzle-orm@0.44.7_@cloudflare_workers-types@4.20260313.1_@electric-sql_pg_c72c8c754becd21f6d6662e8fbd28e7f/node_modules/fumadb/dist/query/index.d.mts +1 -1
  26. package/dist/packages/server/package.cjs +1 -1
  27. package/dist/packages/server/package.mjs +1 -1
  28. package/dist/runtime.cjs +10 -12
  29. package/dist/runtime.mjs +10 -12
  30. package/package.json +7 -7
  31. package/src/db/createBundleDiff.spec.ts +3 -0
  32. package/src/db/createBundleDiff.ts +27 -21
  33. package/src/db/index.spec.ts +36 -0
  34. package/src/db/index.ts +6 -10
  35. package/src/db/pluginCore.spec.ts +443 -0
  36. package/src/db/pluginCore.ts +63 -7
  37. package/src/db/requestBundleIdentityMap.spec.ts +56 -0
  38. package/src/db/requestBundleIdentityMap.ts +61 -0
  39. package/src/db/types.ts +2 -0
  40. package/src/db/updateArtifacts.ts +8 -19
  41. package/src/handler-standalone.integration.spec.ts +12 -0
  42. package/src/handler.spec.ts +117 -19
  43. package/src/handler.ts +47 -21
  44. package/src/runtime.spec.ts +46 -4
  45. package/src/runtime.ts +10 -12
@@ -46,4 +46,4 @@ interface FumaDBFactory<Schemas extends AnySchema[]> {
46
46
  }
47
47
  type InferFumaDB<Factory extends FumaDBFactory<any>> = Factory extends FumaDBFactory<infer Schemas> ? FumaDB<Schemas> : never;
48
48
  //#endregion
49
- export type { FumaDBFactory, InferFumaDB };
49
+ export { type FumaDBFactory, type InferFumaDB };
@@ -153,4 +153,4 @@ interface AbstractQuery<S extends AnySchema> {
153
153
  }) => Promise<void>;
154
154
  }
155
155
  //#endregion
156
- export type { AbstractQuery };
156
+ export { type AbstractQuery };
@@ -153,4 +153,4 @@ interface AbstractQuery<S extends AnySchema> {
153
153
  }) => Promise<void>;
154
154
  }
155
155
  //#endregion
156
- export type { AbstractQuery };
156
+ export { type AbstractQuery };
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.31.4";
2
+ var version = "0.33.0";
3
3
  //#endregion
4
4
  Object.defineProperty(exports, "version", {
5
5
  enumerable: true,
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.31.4";
2
+ var version = "0.33.0";
3
3
  //#endregion
4
4
  export { version };
package/dist/runtime.cjs CHANGED
@@ -22,23 +22,21 @@ function createHotUpdater(options) {
22
22
  createMutationPlugin: () => database(),
23
23
  readStorageText
24
24
  } : { readStorageText });
25
- const api = {
26
- ...core.api,
27
- handler: require_handler.createHandler(core.api, {
28
- basePath,
29
- routes: options.routes
30
- }),
31
- adapterName: core.adapterName
32
- };
25
+ const internalHandler = require_handler.createHandler(core.api, {
26
+ basePath,
27
+ routes: options.routes
28
+ });
33
29
  const handler = (request, context, ...extraArgs) => {
34
- if (extraArgs.length > 0) return api.handler(request);
35
- return api.handler(request, context);
30
+ if (extraArgs.length > 0) return internalHandler(request);
31
+ return internalHandler(request, context);
36
32
  };
37
- return {
38
- ...api,
33
+ const api = {
39
34
  basePath,
35
+ adapterName: core.adapterName,
40
36
  handler
41
37
  };
38
+ Object.defineProperties(api, Object.getOwnPropertyDescriptors(core.api));
39
+ return api;
42
40
  }
43
41
  //#endregion
44
42
  exports.HOT_UPDATER_SERVER_VERSION = require_version.HOT_UPDATER_SERVER_VERSION;
package/dist/runtime.mjs CHANGED
@@ -20,23 +20,21 @@ function createHotUpdater(options) {
20
20
  createMutationPlugin: () => database(),
21
21
  readStorageText
22
22
  } : { readStorageText });
23
- const api = {
24
- ...core.api,
25
- handler: createHandler(core.api, {
26
- basePath,
27
- routes: options.routes
28
- }),
29
- adapterName: core.adapterName
30
- };
23
+ const internalHandler = createHandler(core.api, {
24
+ basePath,
25
+ routes: options.routes
26
+ });
31
27
  const handler = (request, context, ...extraArgs) => {
32
- if (extraArgs.length > 0) return api.handler(request);
33
- return api.handler(request, context);
28
+ if (extraArgs.length > 0) return internalHandler(request);
29
+ return internalHandler(request, context);
34
30
  };
35
- return {
36
- ...api,
31
+ const api = {
37
32
  basePath,
33
+ adapterName: core.adapterName,
38
34
  handler
39
35
  };
36
+ Object.defineProperties(api, Object.getOwnPropertyDescriptors(core.api));
37
+ return api;
40
38
  }
41
39
  //#endregion
42
40
  export { HOT_UPDATER_SERVER_VERSION, createHandler, createHotUpdater };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/server",
3
- "version": "0.31.4",
3
+ "version": "0.33.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
  "mongodb": "6.20.0",
56
56
  "rou3": "0.7.9",
57
57
  "semver": "^7.7.2",
58
- "@hot-updater/bsdiff": "0.31.4",
59
- "@hot-updater/plugin-core": "0.31.4",
60
- "@hot-updater/js": "0.31.4",
61
- "@hot-updater/core": "0.31.4"
58
+ "@hot-updater/core": "0.33.0",
59
+ "@hot-updater/bsdiff": "0.33.0",
60
+ "@hot-updater/plugin-core": "0.33.0",
61
+ "@hot-updater/js": "0.33.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@electric-sql/pglite": "0.2.17",
@@ -68,8 +68,8 @@
68
68
  "kysely-pglite-dialect": "1.2.0",
69
69
  "msw": "^2.7.0",
70
70
  "uuidv7": "^1.0.2",
71
- "@hot-updater/standalone": "0.31.4",
72
- "@hot-updater/test-utils": "0.31.4"
71
+ "@hot-updater/standalone": "0.33.0",
72
+ "@hot-updater/test-utils": "0.33.0"
73
73
  },
74
74
  "inlinedDependencies": {
75
75
  "@noble/hashes": "1.8.0",
@@ -93,6 +93,9 @@ const createStoragePlugin = (
93
93
  new Uint8Array(await response.arrayBuffer()),
94
94
  );
95
95
  },
96
+ async exists() {
97
+ return false;
98
+ },
96
99
  upload,
97
100
  },
98
101
  },
@@ -17,6 +17,7 @@ import type {
17
17
  DatabasePlugin,
18
18
  NodeStoragePlugin,
19
19
  } from "@hot-updater/plugin-core";
20
+ import { resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
20
21
 
21
22
  type BundleManifest = {
22
23
  bundleId: string;
@@ -80,21 +81,6 @@ const isBundleManifest = (value: unknown): value is BundleManifest => {
80
81
  );
81
82
  };
82
83
 
83
- const createChildStorageUri = (
84
- baseStorageUri: string,
85
- relativePath: string,
86
- ) => {
87
- const baseUrl = new URL(baseStorageUri);
88
- const normalizedBasePath = baseUrl.pathname.replace(/\/+$/, "");
89
- const relativeSegments = relativePath
90
- .split("/")
91
- .filter(Boolean)
92
- .map((segment) => encodeURIComponent(segment));
93
-
94
- baseUrl.pathname = `${normalizedBasePath}/${relativeSegments.join("/")}`;
95
- return baseUrl.toString();
96
- };
97
-
98
84
  const getRelativeStorageDir = (relativePath: string) => {
99
85
  const normalized = relativePath.replace(/\\/g, "/");
100
86
  const dirname = path.posix.dirname(normalized);
@@ -188,18 +174,24 @@ function resolveHbcAssetPath(manifest: BundleManifest) {
188
174
  async function fetchAssetBytes(
189
175
  bundle: Bundle,
190
176
  assetPath: string,
177
+ manifest: BundleManifest,
191
178
  storagePlugin: NodeStoragePlugin | null,
192
179
  ) {
193
180
  const assetBaseStorageUri = getAssetBaseStorageUri(bundle);
194
181
  if (!assetBaseStorageUri) {
195
182
  throw new Error(`Bundle ${bundle.id} does not have asset storage metadata`);
196
183
  }
184
+ const asset = manifest.assets[assetPath];
185
+ if (!asset) {
186
+ throw new Error(`Asset ${assetPath} is missing from manifest`);
187
+ }
197
188
 
198
189
  if (BR_COMPRESSED_ASSET_PATH_RE.test(assetPath)) {
199
- const compressedAssetStorageUri = createChildStorageUri(
190
+ const compressedAssetStorageUri = resolveManifestAssetStorageUri({
200
191
  assetBaseStorageUri,
201
- `${assetPath}.br`,
202
- );
192
+ assetPath: `${assetPath}.br`,
193
+ fileHash: asset.fileHash,
194
+ });
203
195
 
204
196
  let compressedBytes: Uint8Array | null = null;
205
197
  try {
@@ -216,7 +208,11 @@ async function fetchAssetBytes(
216
208
  }
217
209
  }
218
210
 
219
- const assetStorageUri = createChildStorageUri(assetBaseStorageUri, assetPath);
211
+ const assetStorageUri = resolveManifestAssetStorageUri({
212
+ assetBaseStorageUri,
213
+ assetPath,
214
+ fileHash: asset.fileHash,
215
+ });
220
216
  return downloadStorageBytes(assetStorageUri, storagePlugin);
221
217
  }
222
218
 
@@ -300,8 +296,18 @@ export async function createBundleDiff(
300
296
  }
301
297
 
302
298
  const [baseBytes, targetBytes] = await Promise.all([
303
- fetchAssetBytes(baseBundle, baseAssetPath, deps.storagePlugin),
304
- fetchAssetBytes(targetBundle, targetAssetPath, deps.storagePlugin),
299
+ fetchAssetBytes(
300
+ baseBundle,
301
+ baseAssetPath,
302
+ baseManifest,
303
+ deps.storagePlugin,
304
+ ),
305
+ fetchAssetBytes(
306
+ targetBundle,
307
+ targetAssetPath,
308
+ targetManifest,
309
+ deps.storagePlugin,
310
+ ),
305
311
  ]);
306
312
 
307
313
  const patchBytes = await hdiff(baseBytes, targetBytes);
@@ -866,6 +866,42 @@ describe("server/db hotUpdater getUpdateInfo (PGlite + Kysely)", async () => {
866
866
  });
867
867
 
868
868
  describe("database plugin factories", () => {
869
+ it("keeps optional maintenance capabilities lazy", () => {
870
+ const factory = vi.fn(() => ({
871
+ async getBundleById() {
872
+ return null;
873
+ },
874
+ async getBundles() {
875
+ return {
876
+ data: [],
877
+ pagination: {
878
+ hasNextPage: false,
879
+ hasPreviousPage: false,
880
+ currentPage: 1,
881
+ totalPages: 1,
882
+ total: 0,
883
+ },
884
+ };
885
+ },
886
+ async getChannels() {
887
+ return [];
888
+ },
889
+ async commitBundle() {},
890
+ }));
891
+ const hotUpdater = createHotUpdater({
892
+ database: createDatabasePlugin({
893
+ name: "lazyPlugin",
894
+ factory,
895
+ })({}),
896
+ });
897
+
898
+ expect(factory).not.toHaveBeenCalled();
899
+ expect(hotUpdater.diagnostics).toBeUndefined();
900
+ expect(factory).not.toHaveBeenCalled();
901
+ expect(hotUpdater.diagnostics).toBeUndefined();
902
+ expect(factory).not.toHaveBeenCalled();
903
+ });
904
+
869
905
  it("isolates pending mutation state between overlapping writes", async () => {
870
906
  const committedBundleIds: string[][] = [];
871
907
  const onUnmount = vi.fn(async () => undefined);
package/src/db/index.ts CHANGED
@@ -104,19 +104,15 @@ export function createHotUpdater<TContext = unknown>(
104
104
  });
105
105
 
106
106
  const api = {
107
- ...core.api,
107
+ basePath,
108
+ adapterName: core.adapterName,
109
+ createMigrator: core.createMigrator,
110
+ generateSchema: core.generateSchema,
108
111
  handler: createHandler(core.api, {
109
112
  basePath,
110
113
  routes: options.routes,
111
114
  }),
112
- adapterName: core.adapterName,
113
- createMigrator: core.createMigrator,
114
- generateSchema: core.generateSchema,
115
- };
116
-
117
- return {
118
- ...api,
119
- basePath,
120
- handler: api.handler,
121
115
  };
116
+ Object.defineProperties(api, Object.getOwnPropertyDescriptors(core.api));
117
+ return api as HotUpdaterAPI<TContext>;
122
118
  }