@hot-updater/server 0.32.0 → 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.
- package/dist/db/index.cjs +7 -10
- package/dist/db/index.mjs +7 -10
- package/dist/db/pluginCore.cjs +136 -96
- package/dist/db/pluginCore.mjs +137 -97
- package/dist/db/requestBundleIdentityMap.cjs +29 -0
- package/dist/db/requestBundleIdentityMap.mjs +29 -0
- package/dist/db/types.d.cts +2 -1
- package/dist/db/types.d.mts +2 -1
- package/dist/packages/server/package.cjs +1 -1
- package/dist/packages/server/package.mjs +1 -1
- package/dist/runtime.cjs +10 -12
- package/dist/runtime.mjs +10 -12
- package/package.json +7 -7
- package/src/db/index.spec.ts +36 -0
- package/src/db/index.ts +6 -10
- package/src/db/pluginCore.spec.ts +334 -0
- package/src/db/pluginCore.ts +63 -7
- package/src/db/requestBundleIdentityMap.spec.ts +56 -0
- package/src/db/requestBundleIdentityMap.ts +61 -0
- package/src/db/types.ts +2 -0
- package/src/runtime.spec.ts +39 -0
- package/src/runtime.ts +10 -12
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Bundle } from "@hot-updater/core";
|
|
2
|
+
import type { HotUpdaterContext } from "@hot-updater/plugin-core";
|
|
3
|
+
|
|
4
|
+
type LoadBundleById<TContext> = (
|
|
5
|
+
bundleId: string,
|
|
6
|
+
context?: HotUpdaterContext<TContext>,
|
|
7
|
+
) => Promise<Bundle | null>;
|
|
8
|
+
|
|
9
|
+
type RequestBundleIdentityMapOptions<TContext> = {
|
|
10
|
+
readonly context?: HotUpdaterContext<TContext>;
|
|
11
|
+
readonly loadBundleById: LoadBundleById<TContext>;
|
|
12
|
+
readonly seeds: readonly (Bundle | null | undefined)[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const createRequestBundleIdentityMap = <TContext = unknown>({
|
|
16
|
+
context,
|
|
17
|
+
loadBundleById,
|
|
18
|
+
seeds,
|
|
19
|
+
}: RequestBundleIdentityMapOptions<TContext>) => {
|
|
20
|
+
const bundles = new Map<string, Bundle>();
|
|
21
|
+
const pendingBundles = new Map<string, Promise<Bundle | null>>();
|
|
22
|
+
|
|
23
|
+
for (const seed of seeds) {
|
|
24
|
+
if (seed) {
|
|
25
|
+
bundles.set(seed.id, seed);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const get = async (bundleId: string): Promise<Bundle | null> => {
|
|
30
|
+
const cachedBundle = bundles.get(bundleId);
|
|
31
|
+
if (cachedBundle) {
|
|
32
|
+
return cachedBundle;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const pendingBundle = pendingBundles.get(bundleId);
|
|
36
|
+
if (pendingBundle) {
|
|
37
|
+
return pendingBundle;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const lookup = loadBundleById(bundleId, context).then(
|
|
41
|
+
(bundle) => {
|
|
42
|
+
pendingBundles.delete(bundleId);
|
|
43
|
+
if (bundle) {
|
|
44
|
+
bundles.set(bundle.id, bundle);
|
|
45
|
+
}
|
|
46
|
+
return bundle;
|
|
47
|
+
},
|
|
48
|
+
(error: unknown) => {
|
|
49
|
+
pendingBundles.delete(bundleId);
|
|
50
|
+
throw error;
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
pendingBundles.set(bundleId, lookup);
|
|
54
|
+
return lookup;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const peek = (bundleId: string): Bundle | null =>
|
|
58
|
+
bundles.get(bundleId) ?? null;
|
|
59
|
+
|
|
60
|
+
return { get, peek };
|
|
61
|
+
};
|
package/src/db/types.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
UpdateInfo,
|
|
6
6
|
} from "@hot-updater/core";
|
|
7
7
|
import type {
|
|
8
|
+
DatabaseDiagnostics,
|
|
8
9
|
DatabaseBundleQueryOptions,
|
|
9
10
|
DatabasePlugin,
|
|
10
11
|
HotUpdaterContext,
|
|
@@ -108,6 +109,7 @@ export interface DatabaseAPI<TContext = unknown> {
|
|
|
108
109
|
bundleId: string,
|
|
109
110
|
context?: HotUpdaterContext<TContext>,
|
|
110
111
|
): Promise<void>;
|
|
112
|
+
diagnostics?: DatabaseDiagnostics<TContext>;
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
export type StoragePluginFactory<TContext = unknown> =
|
package/src/runtime.spec.ts
CHANGED
|
@@ -706,6 +706,45 @@ describe("runtime createHotUpdater", () => {
|
|
|
706
706
|
});
|
|
707
707
|
});
|
|
708
708
|
|
|
709
|
+
it("keeps optional maintenance capabilities lazy", () => {
|
|
710
|
+
const factory = vi.fn(() => ({
|
|
711
|
+
async getBundleById() {
|
|
712
|
+
return null;
|
|
713
|
+
},
|
|
714
|
+
async getBundles() {
|
|
715
|
+
return {
|
|
716
|
+
data: [],
|
|
717
|
+
pagination: {
|
|
718
|
+
hasNextPage: false,
|
|
719
|
+
hasPreviousPage: false,
|
|
720
|
+
currentPage: 1,
|
|
721
|
+
totalPages: 1,
|
|
722
|
+
total: 0,
|
|
723
|
+
},
|
|
724
|
+
};
|
|
725
|
+
},
|
|
726
|
+
async getChannels() {
|
|
727
|
+
return [];
|
|
728
|
+
},
|
|
729
|
+
async commitBundle() {},
|
|
730
|
+
}));
|
|
731
|
+
const database = createDatabasePlugin({
|
|
732
|
+
name: "lazyRuntimePlugin",
|
|
733
|
+
factory,
|
|
734
|
+
})({});
|
|
735
|
+
|
|
736
|
+
const hotUpdater = createHotUpdater({
|
|
737
|
+
database,
|
|
738
|
+
basePath: "/api/check-update",
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
expect(factory).not.toHaveBeenCalled();
|
|
742
|
+
expect(hotUpdater.diagnostics).toBeUndefined();
|
|
743
|
+
expect(factory).not.toHaveBeenCalled();
|
|
744
|
+
expect(hotUpdater.diagnostics).toBeUndefined();
|
|
745
|
+
expect(factory).not.toHaveBeenCalled();
|
|
746
|
+
});
|
|
747
|
+
|
|
709
748
|
it("clears pending plugin changes after a failed mutation commit", async () => {
|
|
710
749
|
const committedBundles = new Map<string, Bundle>();
|
|
711
750
|
let commitAttempt = 0;
|
package/src/runtime.ts
CHANGED
|
@@ -73,14 +73,10 @@ export function createHotUpdater<TContext = unknown>(
|
|
|
73
73
|
: { readStorageText },
|
|
74
74
|
);
|
|
75
75
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
routes: options.routes,
|
|
81
|
-
}),
|
|
82
|
-
adapterName: core.adapterName,
|
|
83
|
-
};
|
|
76
|
+
const internalHandler = createHandler(core.api, {
|
|
77
|
+
basePath,
|
|
78
|
+
routes: options.routes,
|
|
79
|
+
});
|
|
84
80
|
|
|
85
81
|
// Some framework adapters strip the mounted base path or pass extra
|
|
86
82
|
// bindings/execution context arguments. Ignore those extras here so the
|
|
@@ -91,17 +87,19 @@ export function createHotUpdater<TContext = unknown>(
|
|
|
91
87
|
...extraArgs: unknown[]
|
|
92
88
|
) => {
|
|
93
89
|
if (extraArgs.length > 0) {
|
|
94
|
-
return
|
|
90
|
+
return internalHandler(request);
|
|
95
91
|
}
|
|
96
92
|
|
|
97
|
-
return
|
|
93
|
+
return internalHandler(request, context);
|
|
98
94
|
};
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
...api,
|
|
96
|
+
const api = {
|
|
102
97
|
basePath,
|
|
98
|
+
adapterName: core.adapterName,
|
|
103
99
|
handler,
|
|
104
100
|
};
|
|
101
|
+
Object.defineProperties(api, Object.getOwnPropertyDescriptors(core.api));
|
|
102
|
+
return api as HotUpdaterAPI<TContext>;
|
|
105
103
|
}
|
|
106
104
|
|
|
107
105
|
export { createHandler };
|