@hot-updater/server 0.36.7 → 1.0.0-rc.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/adapters/databaseConstraintErrors.cjs +23 -0
- package/dist/adapters/databaseConstraintErrors.mjs +21 -0
- package/dist/adapters/databasePluginUtils.cjs +117 -0
- package/dist/adapters/databasePluginUtils.mjs +106 -0
- package/dist/adapters/drizzle.cjs +53 -176
- package/dist/adapters/drizzle.d.cts +6 -4
- package/dist/adapters/drizzle.d.mts +6 -4
- package/dist/adapters/drizzle.mjs +54 -177
- package/dist/adapters/drizzleCrud.cjs +250 -0
- package/dist/adapters/drizzleCrud.mjs +249 -0
- package/dist/adapters/drizzleLazyDB.cjs +84 -36
- package/dist/adapters/drizzleLazyDB.mjs +84 -36
- package/dist/adapters/drizzleQuery.cjs +68 -0
- package/dist/adapters/drizzleQuery.mjs +67 -0
- package/dist/adapters/kysely.cjs +18 -138
- package/dist/adapters/kysely.d.cts +3 -12
- package/dist/adapters/kysely.d.mts +3 -12
- package/dist/adapters/kysely.mjs +19 -139
- package/dist/adapters/kyselyCrud.cjs +254 -0
- package/dist/adapters/kyselyCrud.mjs +253 -0
- package/dist/adapters/kyselyQuery.cjs +56 -0
- package/dist/adapters/kyselyQuery.mjs +55 -0
- package/dist/adapters/mongodb.cjs +21 -174
- package/dist/adapters/mongodb.d.cts +3 -2
- package/dist/adapters/mongodb.d.mts +3 -2
- package/dist/adapters/mongodb.mjs +21 -174
- package/dist/adapters/mongodbCollections.cjs +36 -0
- package/dist/adapters/mongodbCollections.mjs +30 -0
- package/dist/adapters/mongodbQuery.cjs +77 -0
- package/dist/adapters/mongodbQuery.mjs +70 -0
- package/dist/adapters/mongodbReads.cjs +148 -0
- package/dist/adapters/mongodbReads.mjs +147 -0
- package/dist/adapters/mongodbWrites.cjs +134 -0
- package/dist/adapters/mongodbWrites.mjs +133 -0
- package/dist/adapters/prisma.cjs +205 -180
- package/dist/adapters/prisma.d.cts +3 -3
- package/dist/adapters/prisma.d.mts +3 -3
- package/dist/adapters/prisma.mjs +206 -181
- package/dist/adapters/prismaQuery.cjs +58 -0
- package/dist/adapters/prismaQuery.mjs +56 -0
- package/dist/adapters/prismaRows.cjs +198 -0
- package/dist/adapters/prismaRows.mjs +188 -0
- package/dist/analytics/bounded/activeOverview.cjs +87 -0
- package/dist/analytics/bounded/activeOverview.mjs +85 -0
- package/dist/analytics/bounded/installationSearch.cjs +42 -0
- package/dist/analytics/bounded/installationSearch.mjs +42 -0
- package/dist/analytics/bounded/persistence.cjs +39 -0
- package/dist/analytics/bounded/persistence.mjs +38 -0
- package/dist/analytics/bounded/provider.cjs +170 -0
- package/dist/analytics/bounded/provider.d.cts +7 -0
- package/dist/analytics/bounded/provider.d.mts +7 -0
- package/dist/analytics/bounded/provider.mjs +170 -0
- package/dist/analytics/bounded/scan.cjs +144 -0
- package/dist/analytics/bounded/scan.mjs +138 -0
- package/dist/analytics/domain.d.cts +121 -0
- package/dist/analytics/domain.d.mts +121 -0
- package/dist/analytics/errors.cjs +22 -0
- package/dist/analytics/errors.mjs +20 -0
- package/dist/analytics/eventInput.cjs +111 -0
- package/dist/analytics/eventInput.mjs +111 -0
- package/dist/analytics/persistence.d.cts +6 -0
- package/dist/analytics/persistence.d.mts +6 -0
- package/dist/analytics/queryInput.cjs +58 -0
- package/dist/analytics/queryInput.mjs +55 -0
- package/dist/analytics/routes.cjs +63 -0
- package/dist/analytics/routes.mjs +61 -0
- package/dist/analytics/types.d.cts +17 -0
- package/dist/analytics/types.d.mts +17 -0
- package/dist/apiKeys.cjs +139 -0
- package/dist/apiKeys.d.cts +50 -0
- package/dist/apiKeys.d.mts +50 -0
- package/dist/apiKeys.mjs +133 -0
- package/dist/createHotUpdaterCore.cjs +48 -26
- package/dist/createHotUpdaterCore.d.cts +49 -17
- package/dist/createHotUpdaterCore.d.mts +49 -17
- package/dist/createHotUpdaterCore.mjs +51 -29
- package/dist/db/createBundleDiff.cjs +45 -68
- package/dist/db/createBundleDiff.d.cts +3 -3
- package/dist/db/createBundleDiff.d.mts +3 -3
- package/dist/db/createBundleDiff.mjs +47 -68
- package/dist/db/databasePluginCore.cjs +138 -0
- package/dist/db/databasePluginCore.mjs +137 -0
- package/dist/db/fixedMigrator.cjs +36 -93
- package/dist/db/fixedMigrator.mjs +36 -93
- package/dist/db/fixedMigratorMongo.cjs +319 -0
- package/dist/db/fixedMigratorMongo.mjs +319 -0
- package/dist/db/fixedMigratorShared.cjs +23 -0
- package/dist/db/fixedMigratorShared.mjs +18 -0
- package/dist/db/mongoMigrationExecution.cjs +11 -0
- package/dist/db/mongoMigrationExecution.mjs +11 -0
- package/dist/db/releaseCatalog.cjs +66 -0
- package/dist/db/releaseCatalog.d.cts +17 -0
- package/dist/db/releaseCatalog.d.mts +17 -0
- package/dist/db/releaseCatalog.mjs +64 -0
- package/dist/db/schema/mongodb.cjs +14 -6
- package/dist/db/schema/mongodb.mjs +14 -6
- package/dist/db/schema/registry.cjs +0 -2
- package/dist/db/schema/registry.mjs +1 -2
- package/dist/db/schema/sql.cjs +31 -14
- package/dist/db/schema/sql.mjs +32 -13
- package/dist/db/schema/sqlOperations.cjs +4 -4
- package/dist/db/schema/sqlOperations.mjs +5 -5
- package/dist/db/schemaGenerators.cjs +52 -18
- package/dist/db/schemaGenerators.mjs +52 -18
- package/dist/db/schemaReadiness.cjs +4 -3
- package/dist/db/schemaReadiness.mjs +4 -3
- package/dist/db/sqlMigrationExecution.cjs +67 -0
- package/dist/db/sqlMigrationExecution.mjs +66 -0
- package/dist/db/types.cjs +2 -6
- package/dist/db/types.d.cts +60 -16
- package/dist/db/types.d.mts +60 -16
- package/dist/db/types.mjs +3 -6
- package/dist/db/updateArtifacts.cjs +114 -60
- package/dist/db/updateArtifacts.mjs +117 -62
- package/dist/handler.cjs +108 -282
- package/dist/handler.d.cts +3 -46
- package/dist/handler.d.mts +3 -46
- package/dist/handler.mjs +107 -281
- package/dist/handlerBundleRoutes.cjs +155 -0
- package/dist/handlerBundleRoutes.mjs +155 -0
- package/dist/handlerErrors.cjs +9 -0
- package/dist/handlerErrors.mjs +9 -0
- package/dist/handlerParameters.cjs +39 -0
- package/dist/handlerParameters.mjs +34 -0
- package/dist/handlerReleaseCatalogRoutes.cjs +111 -0
- package/dist/handlerReleaseCatalogRoutes.mjs +110 -0
- package/dist/handlerReleaseManagementRoutes.cjs +125 -0
- package/dist/handlerReleaseManagementRoutes.mjs +124 -0
- package/dist/handlerTypes.d.cts +63 -0
- package/dist/handlerTypes.d.mts +63 -0
- package/dist/handlerVersionRoutes.cjs +10 -0
- package/dist/handlerVersionRoutes.d.cts +4 -0
- package/dist/handlerVersionRoutes.d.mts +4 -0
- package/dist/handlerVersionRoutes.mjs +9 -0
- package/dist/index.cjs +10 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.mts +9 -3
- package/dist/index.mjs +5 -2
- package/dist/node.cjs +19 -12
- package/dist/node.d.cts +15 -10
- package/dist/node.d.mts +15 -10
- package/dist/node.mjs +19 -13
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/schema/dsl.cjs +19 -2
- package/dist/schema/dsl.mjs +17 -3
- package/dist/schema/index.cjs +1 -8
- package/dist/schema/index.mjs +2 -8
- package/dist/schema/types.cjs +3 -1
- package/dist/schema/types.mjs +3 -2
- package/dist/schema/v1_0_0.cjs +364 -0
- package/dist/schema/v1_0_0.mjs +357 -0
- package/dist/storageAccess.cjs +69 -25
- package/dist/storageAccess.mjs +68 -25
- package/dist/types/index.d.cts +4 -3
- package/dist/types/index.d.mts +5 -4
- package/package.json +8 -7
- package/src/adapters/databaseConstraintErrors.ts +25 -0
- package/src/adapters/databasePluginTestDatabase.ts +106 -0
- package/src/adapters/databasePluginUtils.spec.ts +29 -0
- package/src/adapters/databasePluginUtils.ts +214 -0
- package/src/adapters/drizzle.spec.ts +208 -47
- package/src/adapters/drizzle.ts +106 -293
- package/src/adapters/drizzleCrud.ts +419 -0
- package/src/adapters/drizzleLazyDB.ts +206 -100
- package/src/adapters/drizzleQuery.ts +164 -0
- package/src/adapters/kysely.spec.ts +126 -88
- package/src/adapters/kysely.ts +76 -334
- package/src/adapters/kyselyCrud.ts +588 -0
- package/src/adapters/kyselyQuery.ts +128 -0
- package/src/adapters/mongodb.spec.ts +141 -0
- package/src/adapters/mongodb.ts +60 -288
- package/src/adapters/mongodbCollections.ts +62 -0
- package/src/adapters/mongodbQuery.ts +226 -0
- package/src/adapters/mongodbReads.ts +311 -0
- package/src/adapters/mongodbRows.spec.ts +64 -0
- package/src/adapters/mongodbRows.ts +118 -0
- package/src/adapters/mongodbTestClient.ts +342 -0
- package/src/adapters/mongodbTestFilter.ts +166 -0
- package/src/adapters/mongodbWrites.ts +260 -0
- package/src/adapters/prisma.spec.ts +196 -0
- package/src/adapters/prisma.ts +417 -292
- package/src/adapters/prismaQuery.ts +129 -0
- package/src/adapters/prismaRows.spec.ts +98 -0
- package/src/adapters/prismaRows.ts +301 -0
- package/src/adapters/prismaTestClient.ts +396 -0
- package/src/analytics/analytics.integration.spec.ts +144 -0
- package/src/analytics/bounded/activeOverview.spec.ts +189 -0
- package/src/analytics/bounded/activeOverview.ts +148 -0
- package/src/analytics/bounded/installationSearch.spec.ts +130 -0
- package/src/analytics/bounded/installationSearch.ts +69 -0
- package/src/analytics/bounded/persistence.ts +43 -0
- package/src/analytics/bounded/provider.spec.ts +219 -0
- package/src/analytics/bounded/provider.ts +229 -0
- package/src/analytics/bounded/scan.ts +235 -0
- package/src/analytics/domain.ts +139 -0
- package/src/analytics/errors.ts +18 -0
- package/src/analytics/eventInput.ts +168 -0
- package/src/analytics/persistence.ts +10 -0
- package/src/analytics/queryInput.ts +102 -0
- package/src/analytics/routes.ts +123 -0
- package/src/analytics/types.ts +44 -0
- package/src/apiKeys.integration.spec.ts +192 -0
- package/src/apiKeys.spec.ts +162 -0
- package/src/apiKeys.ts +220 -0
- package/src/createHotUpdaterCore.ts +164 -100
- package/src/db/bundleRows.spec.ts +164 -0
- package/src/db/bundleRows.ts +10 -140
- package/src/db/createBundleDiff.spec.ts +172 -127
- package/src/db/createBundleDiff.ts +91 -110
- package/src/db/databasePluginCore.spec.ts +62 -0
- package/src/db/databasePluginCore.testFixtures.ts +76 -0
- package/src/db/databasePluginCore.ts +185 -0
- package/src/db/databasePluginUpdateCheck.bench.ts +107 -0
- package/src/db/fixedMigrator.spec.ts +184 -42
- package/src/db/fixedMigrator.ts +64 -205
- package/src/db/fixedMigratorMongo.spec.ts +192 -0
- package/src/db/fixedMigratorMongo.ts +425 -0
- package/src/db/fixedMigratorShared.ts +36 -0
- package/src/db/hotUpdaterSchema.ts +0 -1
- package/src/db/index.spec.ts +333 -1025
- package/src/db/mongoMigrationExecution.ts +23 -0
- package/src/db/node-sqlite.d.ts +25 -0
- package/src/db/releaseCatalog.ts +148 -0
- package/src/db/schema/mongodb.ts +20 -6
- package/src/db/schema/sql.ts +52 -11
- package/src/db/schema/sqlOperations.ts +5 -4
- package/src/db/schemaGenerators.ts +107 -23
- package/src/db/schemaReadiness.ts +2 -1
- package/src/db/sqlMigrationExecution.spec.ts +65 -0
- package/src/db/sqlMigrationExecution.ts +108 -0
- package/src/db/types.spec.ts +55 -0
- package/src/db/types.ts +129 -65
- package/src/db/updateArtifacts.spec.ts +359 -0
- package/src/db/updateArtifacts.ts +290 -126
- package/src/handler-standalone.integration.spec.ts +401 -364
- package/src/handler.spec.ts +137 -582
- package/src/handler.testFixtures.ts +30 -0
- package/src/handler.ts +218 -616
- package/src/handlerAuth.integration.spec.ts +33 -0
- package/src/handlerBundleRoutes.ts +259 -0
- package/src/handlerErrors.ts +7 -0
- package/src/handlerManagement.spec.ts +262 -0
- package/src/handlerParameters.ts +105 -0
- package/src/handlerReleaseCatalogRoutes.ts +154 -0
- package/src/handlerReleaseManagementRoutes.ts +213 -0
- package/src/handlerTypes.ts +96 -0
- package/src/handlerVersionRoutes.ts +12 -0
- package/src/index.ts +22 -2
- package/src/node.spec.ts +79 -10
- package/src/node.ts +20 -17
- package/src/releaseCatalogRoutes.integration.spec.ts +238 -0
- package/src/runtime.spec.ts +126 -959
- package/src/runtime.testFixtures.ts +71 -0
- package/src/schema/dsl-all-versions.spec.ts +26 -17
- package/src/schema/dsl.ts +41 -2
- package/src/schema/index.ts +3 -9
- package/src/schema/types.ts +9 -3
- package/src/schema/v1_0_0.spec.ts +146 -0
- package/src/schema/v1_0_0.ts +465 -0
- package/src/storageAccess.spec.ts +127 -32
- package/src/storageAccess.ts +106 -55
- package/src/types/index.ts +2 -1
- package/dist/db/bundleRows.cjs +0 -82
- package/dist/db/bundleRows.d.cts +0 -33
- package/dist/db/bundleRows.d.mts +0 -33
- package/dist/db/bundleRows.mjs +0 -79
- package/dist/db/pluginCore.cjs +0 -242
- package/dist/db/pluginCore.mjs +0 -241
- package/dist/db/schema/sqlMigrations.cjs +0 -74
- package/dist/db/schema/sqlMigrations.mjs +0 -73
- package/dist/db/schemaEnhancements.cjs +0 -20
- package/dist/db/schemaEnhancements.mjs +0 -19
- package/dist/route.cjs +0 -7
- package/dist/route.mjs +0 -7
- package/dist/schema/v0_21_0.cjs +0 -38
- package/dist/schema/v0_21_0.mjs +0 -37
- package/dist/schema/v0_29_0.cjs +0 -45
- package/dist/schema/v0_29_0.mjs +0 -44
- package/dist/schema/v0_31_0.cjs +0 -82
- package/dist/schema/v0_31_0.mjs +0 -80
- package/src/db/pluginCore.spec.ts +0 -1095
- package/src/db/pluginCore.ts +0 -475
- package/src/db/pluginUpdateCheck.bench.ts +0 -254
- package/src/db/schema/sqlMigrations.ts +0 -219
- package/src/db/schemaEnhancements.ts +0 -55
- package/src/route.ts +0 -7
- package/src/schema/v0_21_0.ts +0 -52
- package/src/schema/v0_29_0.ts +0 -62
- package/src/schema/v0_31_0.spec.ts +0 -73
- package/src/schema/v0_31_0.ts +0 -120
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import crypto
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
1
|
+
import crypto from "node:crypto";
|
|
4
2
|
import path from "node:path";
|
|
5
3
|
import { promisify } from "node:util";
|
|
6
4
|
import { brotliDecompress } from "node:zlib";
|
|
@@ -14,18 +12,27 @@ import {
|
|
|
14
12
|
} from "@hot-updater/core";
|
|
15
13
|
import type {
|
|
16
14
|
Bundle,
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
BundleRepository,
|
|
16
|
+
StoragePluginWith,
|
|
19
17
|
} from "@hot-updater/plugin-core";
|
|
20
18
|
import {
|
|
21
19
|
createBundleStorageKey,
|
|
20
|
+
createDatabaseClient,
|
|
22
21
|
getManifestAssetDownloadPath,
|
|
23
22
|
resolveManifestAssetStorageUri,
|
|
24
23
|
} from "@hot-updater/plugin-core";
|
|
25
24
|
|
|
26
25
|
type BundleManifest = {
|
|
27
26
|
bundleId: string;
|
|
28
|
-
assets: Record<
|
|
27
|
+
assets: Record<
|
|
28
|
+
string,
|
|
29
|
+
{
|
|
30
|
+
downloadByteSize?: unknown;
|
|
31
|
+
downloadFileHash?: unknown;
|
|
32
|
+
fileHash: string;
|
|
33
|
+
signature?: string;
|
|
34
|
+
}
|
|
35
|
+
>;
|
|
29
36
|
};
|
|
30
37
|
|
|
31
38
|
export interface CreateBundleDiffInput {
|
|
@@ -34,8 +41,8 @@ export interface CreateBundleDiffInput {
|
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
export interface CreateBundleDiffDependencies {
|
|
37
|
-
databasePlugin:
|
|
38
|
-
storagePlugin:
|
|
44
|
+
databasePlugin: BundleRepository;
|
|
45
|
+
storagePlugin: StoragePluginWith<"get" | "put" | "delete"> | null;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
export interface CreateBundleDiffOptions {
|
|
@@ -43,7 +50,6 @@ export interface CreateBundleDiffOptions {
|
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
const HBC_ASSET_PATH_RE = /\.bundle$/;
|
|
46
|
-
const HOT_UPDATER_DOWNLOAD_DIR_PREFIX = "downloads-";
|
|
47
53
|
const decompressBrotli = promisify(brotliDecompress);
|
|
48
54
|
|
|
49
55
|
const isBundleManifest = (value: unknown): value is BundleManifest => {
|
|
@@ -101,41 +107,30 @@ async function downloadFromUrl(url: string) {
|
|
|
101
107
|
|
|
102
108
|
async function downloadStorageBytes(
|
|
103
109
|
storageUri: string,
|
|
104
|
-
storagePlugin:
|
|
110
|
+
storagePlugin: StoragePluginWith<"get" | "put" | "delete"> | null,
|
|
105
111
|
) {
|
|
106
112
|
const protocol = new URL(storageUri).protocol.replace(":", "");
|
|
107
113
|
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (storagePlugin.supportedProtocol !== protocol) {
|
|
114
|
+
if (!storagePlugin || storagePlugin.protocol !== protocol) {
|
|
115
|
+
if (protocol === "http" || protocol === "https") {
|
|
116
|
+
return downloadFromUrl(storageUri);
|
|
117
|
+
}
|
|
118
|
+
if (!storagePlugin) {
|
|
119
|
+
throw new Error("Storage plugin is not configured");
|
|
120
|
+
}
|
|
117
121
|
throw new Error(`No storage plugin for protocol: ${protocol}`);
|
|
118
122
|
}
|
|
119
123
|
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
path.join(downloadRoot, HOT_UPDATER_DOWNLOAD_DIR_PREFIX),
|
|
124
|
-
);
|
|
125
|
-
const filename = path.basename(new URL(storageUri).pathname) || randomUUID();
|
|
126
|
-
const filePath = path.join(workDir, filename);
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
await storagePlugin.profiles.node.downloadFile(storageUri, filePath);
|
|
130
|
-
return new Uint8Array(await fs.readFile(filePath));
|
|
131
|
-
} finally {
|
|
132
|
-
await fs.rm(workDir, { force: true, recursive: true });
|
|
124
|
+
const { response } = await storagePlugin.get({ storageUri });
|
|
125
|
+
if (response === null) {
|
|
126
|
+
throw new Error(`Storage object not found: ${storageUri}`);
|
|
133
127
|
}
|
|
128
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
134
129
|
}
|
|
135
130
|
|
|
136
131
|
async function fetchManifest(
|
|
137
132
|
bundle: Bundle,
|
|
138
|
-
storagePlugin:
|
|
133
|
+
storagePlugin: StoragePluginWith<"get" | "put" | "delete"> | null,
|
|
139
134
|
): Promise<BundleManifest> {
|
|
140
135
|
const manifestStorageUri = getManifestStorageUri(bundle);
|
|
141
136
|
if (!manifestStorageUri) {
|
|
@@ -147,9 +142,7 @@ async function fetchManifest(
|
|
|
147
142
|
storagePlugin,
|
|
148
143
|
);
|
|
149
144
|
|
|
150
|
-
const payload = JSON.parse(
|
|
151
|
-
new TextDecoder().decode(manifestBytes),
|
|
152
|
-
) as unknown;
|
|
145
|
+
const payload: unknown = JSON.parse(new TextDecoder().decode(manifestBytes));
|
|
153
146
|
if (!isBundleManifest(payload)) {
|
|
154
147
|
throw new Error(`Invalid manifest payload for bundle ${bundle.id}`);
|
|
155
148
|
}
|
|
@@ -178,7 +171,7 @@ async function fetchAssetBytes(
|
|
|
178
171
|
bundle: Bundle,
|
|
179
172
|
assetPath: string,
|
|
180
173
|
manifest: BundleManifest,
|
|
181
|
-
storagePlugin:
|
|
174
|
+
storagePlugin: StoragePluginWith<"get" | "put" | "delete"> | null,
|
|
182
175
|
) {
|
|
183
176
|
const assetBaseStorageUri = getAssetBaseStorageUri(bundle);
|
|
184
177
|
if (!assetBaseStorageUri) {
|
|
@@ -194,6 +187,7 @@ async function fetchAssetBytes(
|
|
|
194
187
|
const compressedAssetStorageUri = resolveManifestAssetStorageUri({
|
|
195
188
|
assetBaseStorageUri,
|
|
196
189
|
assetPath: downloadPath,
|
|
190
|
+
downloadFileHash: asset.downloadFileHash,
|
|
197
191
|
fileHash: asset.fileHash,
|
|
198
192
|
});
|
|
199
193
|
|
|
@@ -203,8 +197,9 @@ async function fetchAssetBytes(
|
|
|
203
197
|
compressedAssetStorageUri,
|
|
204
198
|
storagePlugin,
|
|
205
199
|
);
|
|
206
|
-
} catch {
|
|
207
|
-
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (!(error instanceof Error)) throw error;
|
|
202
|
+
compressedBytes = null;
|
|
208
203
|
}
|
|
209
204
|
|
|
210
205
|
if (compressedBytes) {
|
|
@@ -220,11 +215,6 @@ async function fetchAssetBytes(
|
|
|
220
215
|
return downloadStorageBytes(assetStorageUri, storagePlugin);
|
|
221
216
|
}
|
|
222
217
|
|
|
223
|
-
async function getFileHash(filePath: string) {
|
|
224
|
-
const file = await fs.readFile(filePath);
|
|
225
|
-
return crypto.createHash("sha256").update(file).digest("hex");
|
|
226
|
-
}
|
|
227
|
-
|
|
228
218
|
function buildNextPatchState({
|
|
229
219
|
currentBundle,
|
|
230
220
|
nextPatch,
|
|
@@ -240,12 +230,8 @@ function buildNextPatchState({
|
|
|
240
230
|
const orderedPatches = makePrimary
|
|
241
231
|
? [nextPatch, ...existingPatches]
|
|
242
232
|
: [...existingPatches, nextPatch];
|
|
243
|
-
const primaryPatch = orderedPatches[0] ?? nextPatch;
|
|
244
233
|
|
|
245
|
-
return
|
|
246
|
-
patches: orderedPatches,
|
|
247
|
-
primaryPatch,
|
|
248
|
-
};
|
|
234
|
+
return orderedPatches;
|
|
249
235
|
}
|
|
250
236
|
|
|
251
237
|
export async function createBundleDiff(
|
|
@@ -253,6 +239,8 @@ export async function createBundleDiff(
|
|
|
253
239
|
deps: CreateBundleDiffDependencies,
|
|
254
240
|
options: CreateBundleDiffOptions = {},
|
|
255
241
|
) {
|
|
242
|
+
const database = createDatabaseClient(deps.databasePlugin);
|
|
243
|
+
|
|
256
244
|
if (!deps.storagePlugin) {
|
|
257
245
|
throw new Error("Storage plugin is not configured");
|
|
258
246
|
}
|
|
@@ -261,8 +249,8 @@ export async function createBundleDiff(
|
|
|
261
249
|
throw new Error("Base bundle must be different from the target bundle");
|
|
262
250
|
}
|
|
263
251
|
|
|
264
|
-
const baseBundle = await
|
|
265
|
-
const targetBundle = await
|
|
252
|
+
const baseBundle = await database.getBundleById(baseBundleId);
|
|
253
|
+
const targetBundle = await database.getBundleById(bundleId);
|
|
266
254
|
|
|
267
255
|
if (!baseBundle || !targetBundle) {
|
|
268
256
|
throw new Error("Bundle not found");
|
|
@@ -315,69 +303,62 @@ export async function createBundleDiff(
|
|
|
315
303
|
]);
|
|
316
304
|
|
|
317
305
|
const patchBytes = await hdiff(baseBytes, targetBytes);
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
306
|
+
const patchFileHash = crypto
|
|
307
|
+
.createHash("sha256")
|
|
308
|
+
.update(patchBytes)
|
|
309
|
+
.digest("hex");
|
|
321
310
|
const patchFilename = `${path.posix.basename(targetAssetPath)}.bsdiff`;
|
|
322
|
-
const patchPath = path.join(workDir, patchFilename);
|
|
323
311
|
const previousPatch = getBundlePatch(targetBundle, baseBundle.id);
|
|
324
312
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
patchStorageUri: patchUpload.storageUri,
|
|
345
|
-
};
|
|
346
|
-
const nextState = buildNextPatchState({
|
|
347
|
-
currentBundle: targetBundle,
|
|
348
|
-
nextPatch,
|
|
349
|
-
makePrimary: options.makePrimary ?? true,
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
await deps.databasePlugin.updateBundle(targetBundle.id, {
|
|
353
|
-
patches: nextState.patches,
|
|
354
|
-
patchBaseBundleId: nextState.primaryPatch.baseBundleId,
|
|
355
|
-
patchBaseFileHash: nextState.primaryPatch.baseFileHash,
|
|
356
|
-
patchFileHash: nextState.primaryPatch.patchFileHash,
|
|
357
|
-
patchStorageUri: nextState.primaryPatch.patchStorageUri,
|
|
358
|
-
});
|
|
359
|
-
await deps.databasePlugin.commitBundle();
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
previousPatch?.patchStorageUri &&
|
|
363
|
-
previousPatch.patchStorageUri !== patchUpload.storageUri
|
|
364
|
-
) {
|
|
365
|
-
await deps.storagePlugin.profiles.node
|
|
366
|
-
.delete(previousPatch.patchStorageUri)
|
|
367
|
-
.catch(() => {
|
|
368
|
-
return;
|
|
369
|
-
});
|
|
370
|
-
}
|
|
313
|
+
const uploadKey = createBundleStorageKey(
|
|
314
|
+
targetBundle.id,
|
|
315
|
+
"patches",
|
|
316
|
+
baseBundle.id,
|
|
317
|
+
patchFileHash,
|
|
318
|
+
getRelativeStorageDir(targetAssetPath),
|
|
319
|
+
patchFilename,
|
|
320
|
+
);
|
|
321
|
+
const patchUpload = await deps.storagePlugin.put({
|
|
322
|
+
key: uploadKey,
|
|
323
|
+
body: new ReadableStream<Uint8Array>({
|
|
324
|
+
start(controller) {
|
|
325
|
+
controller.enqueue(patchBytes);
|
|
326
|
+
controller.close();
|
|
327
|
+
},
|
|
328
|
+
}),
|
|
329
|
+
contentLength: patchBytes.byteLength,
|
|
330
|
+
contentType: "application/octet-stream",
|
|
331
|
+
});
|
|
371
332
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
333
|
+
const nextPatch = {
|
|
334
|
+
baseBundleId: baseBundle.id,
|
|
335
|
+
baseFileHash: baseAssetHash,
|
|
336
|
+
byteSize: patchBytes.byteLength,
|
|
337
|
+
patchFileHash,
|
|
338
|
+
patchStorageUri: patchUpload.storageUri,
|
|
339
|
+
};
|
|
340
|
+
const patches = buildNextPatchState({
|
|
341
|
+
currentBundle: targetBundle,
|
|
342
|
+
nextPatch,
|
|
343
|
+
makePrimary: options.makePrimary ?? true,
|
|
344
|
+
});
|
|
378
345
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
346
|
+
const updatedBundle: Bundle = {
|
|
347
|
+
...targetBundle,
|
|
348
|
+
patches,
|
|
349
|
+
};
|
|
350
|
+
await database.updateBundleById(targetBundle.id, updatedBundle);
|
|
351
|
+
|
|
352
|
+
if (
|
|
353
|
+
previousPatch?.patchStorageUri &&
|
|
354
|
+
previousPatch.patchStorageUri !== patchUpload.storageUri
|
|
355
|
+
) {
|
|
356
|
+
await deps.storagePlugin
|
|
357
|
+
.delete({ storageUri: previousPatch.patchStorageUri })
|
|
358
|
+
.catch(() => {
|
|
359
|
+
return;
|
|
360
|
+
});
|
|
382
361
|
}
|
|
362
|
+
|
|
363
|
+
return updatedBundle;
|
|
383
364
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type DatabasePlugin } from "@hot-updater/plugin-core";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { createInMemoryDatabasePlugin } from "../../../test-utils/test/inMemoryDatabasePlugin";
|
|
5
|
+
import { createDatabasePluginCore } from "./databasePluginCore";
|
|
6
|
+
import {
|
|
7
|
+
currentBundle,
|
|
8
|
+
resolveFileUrl,
|
|
9
|
+
} from "./databasePluginCore.testFixtures";
|
|
10
|
+
|
|
11
|
+
describe("createDatabasePluginCore", () => {
|
|
12
|
+
it("runs the schema readiness guard before a low plugin operation", async () => {
|
|
13
|
+
const plugin: DatabasePlugin = createInMemoryDatabasePlugin();
|
|
14
|
+
const beforeOperation = vi.fn(async () => {});
|
|
15
|
+
const core = createDatabasePluginCore(plugin, resolveFileUrl, {
|
|
16
|
+
beforeOperation,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
await core.api.getChannels();
|
|
20
|
+
|
|
21
|
+
expect(beforeOperation).toHaveBeenCalledOnce();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("inserts an artifact without synthesizing a Release", async () => {
|
|
25
|
+
const plugin: DatabasePlugin = createInMemoryDatabasePlugin();
|
|
26
|
+
const core = createDatabasePluginCore(plugin, resolveFileUrl);
|
|
27
|
+
|
|
28
|
+
await core.api.insertBundle(currentBundle);
|
|
29
|
+
|
|
30
|
+
await expect(
|
|
31
|
+
core.api.getBundleById(currentBundle.id),
|
|
32
|
+
).resolves.toMatchObject(currentBundle);
|
|
33
|
+
await expect(
|
|
34
|
+
plugin.models.releases.findMany({
|
|
35
|
+
bundleId: currentBundle.id,
|
|
36
|
+
limit: 10,
|
|
37
|
+
}),
|
|
38
|
+
).resolves.toEqual([]);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("updates an artifact without requiring or mutating a Release", async () => {
|
|
42
|
+
const plugin: DatabasePlugin = createInMemoryDatabasePlugin();
|
|
43
|
+
const core = createDatabasePluginCore(plugin, resolveFileUrl);
|
|
44
|
+
await core.api.insertBundle(currentBundle);
|
|
45
|
+
await core.api.updateBundleById(currentBundle.id, {
|
|
46
|
+
storageUri: `r2://bucket/bundles/${currentBundle.id}/updated.zip`,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await expect(
|
|
50
|
+
core.api.getBundleById(currentBundle.id),
|
|
51
|
+
).resolves.toMatchObject({
|
|
52
|
+
id: currentBundle.id,
|
|
53
|
+
storageUri: `r2://bucket/bundles/${currentBundle.id}/updated.zip`,
|
|
54
|
+
});
|
|
55
|
+
await expect(
|
|
56
|
+
plugin.models.releases.findMany({
|
|
57
|
+
bundleId: currentBundle.id,
|
|
58
|
+
limit: 10,
|
|
59
|
+
}),
|
|
60
|
+
).resolves.toEqual([]);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Bundle } from "@hot-updater/core";
|
|
2
|
+
import {
|
|
3
|
+
createDatabaseClient,
|
|
4
|
+
type DatabasePlugin,
|
|
5
|
+
} from "@hot-updater/plugin-core";
|
|
6
|
+
|
|
7
|
+
export const currentBundle: Bundle = {
|
|
8
|
+
id: "00000000-0000-0000-0000-000000000001",
|
|
9
|
+
fileHash: "current-archive-hash",
|
|
10
|
+
gitCommitHash: null,
|
|
11
|
+
platform: "ios",
|
|
12
|
+
storageUri:
|
|
13
|
+
"r2://bucket/bundles/00000000-0000-0000-0000-000000000001/archive.zip",
|
|
14
|
+
archiveByteSize: 3_000_000_001,
|
|
15
|
+
manifestStorageUri:
|
|
16
|
+
"r2://bucket/bundles/00000000-0000-0000-0000-000000000001/manifest.json",
|
|
17
|
+
manifestFileHash: "sig:current-manifest",
|
|
18
|
+
assetBaseStorageUri: "r2://bucket/assets",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const targetBundle: Bundle = {
|
|
22
|
+
...currentBundle,
|
|
23
|
+
id: "00000000-0000-0000-0000-000000000002",
|
|
24
|
+
fileHash: "target-archive-hash",
|
|
25
|
+
storageUri:
|
|
26
|
+
"r2://bucket/bundles/00000000-0000-0000-0000-000000000002/archive.zip",
|
|
27
|
+
manifestStorageUri:
|
|
28
|
+
"r2://bucket/bundles/00000000-0000-0000-0000-000000000002/manifest.json",
|
|
29
|
+
manifestFileHash: "sig:target-manifest",
|
|
30
|
+
assetBaseStorageUri: "r2://bucket/assets",
|
|
31
|
+
patches: [
|
|
32
|
+
{
|
|
33
|
+
baseBundleId: currentBundle.id,
|
|
34
|
+
baseFileHash: "current-bundle-hash",
|
|
35
|
+
patchFileHash: "patch-hash",
|
|
36
|
+
patchStorageUri:
|
|
37
|
+
"r2://bucket/bundles/00000000-0000-0000-0000-000000000002/patches/00000000-0000-0000-0000-000000000001/index.ios.bundle.bsdiff",
|
|
38
|
+
byteSize: 3_000_000_002,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const resolveFileUrl = async (storageUri: string | null) => {
|
|
44
|
+
if (!storageUri) return null;
|
|
45
|
+
const url = new URL(storageUri);
|
|
46
|
+
return `https://assets.example.com/${url.host}${url.pathname}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const seedBundles = async (plugin: DatabasePlugin): Promise<void> => {
|
|
50
|
+
const client = createDatabaseClient(plugin);
|
|
51
|
+
await client.insertBundle(currentBundle);
|
|
52
|
+
await client.insertBundle(targetBundle);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const manifests = new Map<string, string>([
|
|
56
|
+
[
|
|
57
|
+
currentBundle.manifestStorageUri ?? "",
|
|
58
|
+
JSON.stringify({
|
|
59
|
+
bundleId: currentBundle.id,
|
|
60
|
+
assets: {
|
|
61
|
+
"index.ios.bundle": { fileHash: "current-bundle-hash" },
|
|
62
|
+
"shared.png": { fileHash: "shared-hash" },
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
targetBundle.manifestStorageUri ?? "",
|
|
68
|
+
JSON.stringify({
|
|
69
|
+
bundleId: targetBundle.id,
|
|
70
|
+
assets: {
|
|
71
|
+
"index.ios.bundle": { fileHash: "target-bundle-hash" },
|
|
72
|
+
"shared.png": { fileHash: "shared-hash" },
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
],
|
|
76
|
+
]);
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import type { Bundle } from "@hot-updater/core";
|
|
2
|
+
import { decodeChannelKey } from "@hot-updater/core";
|
|
3
|
+
import {
|
|
4
|
+
type ChannelRow,
|
|
5
|
+
createDatabaseClient,
|
|
6
|
+
deleteRelease as deleteReleasePolicy,
|
|
7
|
+
preflightReleasePolicy as preflightReleasePolicyMutation,
|
|
8
|
+
rebuildReleaseCatalog as rebuildReleaseCatalogProjection,
|
|
9
|
+
updateReleasePolicy as updateReleasePolicyMutation,
|
|
10
|
+
} from "@hot-updater/plugin-core";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
createArtifactResolver,
|
|
14
|
+
createReleaseCatalogReader,
|
|
15
|
+
} from "./releaseCatalog";
|
|
16
|
+
import type { DatabaseAPI, DatabasePlugin } from "./types";
|
|
17
|
+
|
|
18
|
+
export function createDatabasePluginCore(
|
|
19
|
+
database: DatabasePlugin,
|
|
20
|
+
resolveFileUrl: (storageUri: string | null) => Promise<string | null>,
|
|
21
|
+
options?: {
|
|
22
|
+
beforeOperation?: () => Promise<void>;
|
|
23
|
+
readStorageText?: (storageUri: string) => Promise<string | null>;
|
|
24
|
+
},
|
|
25
|
+
): {
|
|
26
|
+
api: DatabaseAPI;
|
|
27
|
+
adapterName: string;
|
|
28
|
+
createMigrator: () => never;
|
|
29
|
+
generateSchema: () => never;
|
|
30
|
+
} {
|
|
31
|
+
const client = createDatabaseClient(database);
|
|
32
|
+
const beforeOperation = options?.beforeOperation;
|
|
33
|
+
const getReleaseCatalog = createReleaseCatalogReader(database);
|
|
34
|
+
const getArtifact = createArtifactResolver({
|
|
35
|
+
database,
|
|
36
|
+
readStorageText: options?.readStorageText,
|
|
37
|
+
resolveFileUrl,
|
|
38
|
+
});
|
|
39
|
+
const api: DatabaseAPI = {
|
|
40
|
+
async getBundleById(id: string): Promise<Bundle | null> {
|
|
41
|
+
await beforeOperation?.();
|
|
42
|
+
return client.getBundleById(id);
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
async getReleaseCatalog(input) {
|
|
46
|
+
await beforeOperation?.();
|
|
47
|
+
return getReleaseCatalog(input);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
async getArtifactInfo(targetBundleId, currentBundleId) {
|
|
51
|
+
await beforeOperation?.();
|
|
52
|
+
return getArtifact(targetBundleId, currentBundleId);
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
async getReleaseById(id) {
|
|
56
|
+
await beforeOperation?.();
|
|
57
|
+
return database.models.releases.findById(id);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
async getReleasesByScope(input) {
|
|
61
|
+
await beforeOperation?.();
|
|
62
|
+
return database.models.releases.findManyByScope({
|
|
63
|
+
...input,
|
|
64
|
+
consistency: "strong",
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
async getReleases(input) {
|
|
69
|
+
await beforeOperation?.();
|
|
70
|
+
return database.models.releases.findMany(input);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
async getReleaseCatalogByScopeKey(scopeKey) {
|
|
74
|
+
await beforeOperation?.();
|
|
75
|
+
return database.models.releaseCatalogs.findByScopeKey(scopeKey);
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
async getReleaseCatalogs(input) {
|
|
79
|
+
await beforeOperation?.();
|
|
80
|
+
return database.models.releaseCatalogs.findMany(input);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async updateReleasePolicy(input) {
|
|
84
|
+
await beforeOperation?.();
|
|
85
|
+
return updateReleasePolicyMutation({ database, ...input });
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async preflightReleasePolicy(input) {
|
|
89
|
+
await beforeOperation?.();
|
|
90
|
+
return preflightReleasePolicyMutation({ database, ...input });
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
async deleteRelease(input) {
|
|
94
|
+
await beforeOperation?.();
|
|
95
|
+
return deleteReleasePolicy({ database, ...input });
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
async rebuildReleaseCatalog(scopeKey) {
|
|
99
|
+
await beforeOperation?.();
|
|
100
|
+
const catalog =
|
|
101
|
+
await database.models.releaseCatalogs.findByScopeKey(scopeKey);
|
|
102
|
+
if (catalog === null) {
|
|
103
|
+
throw new Error(`Release catalog "${scopeKey}" was not found.`);
|
|
104
|
+
}
|
|
105
|
+
return rebuildReleaseCatalogProjection({
|
|
106
|
+
database,
|
|
107
|
+
scope: {
|
|
108
|
+
channelId: catalog.channel_id,
|
|
109
|
+
channelName: decodeChannelKey(catalog.channel_key),
|
|
110
|
+
fingerprintHash: catalog.fingerprint_hash,
|
|
111
|
+
platform: catalog.platform,
|
|
112
|
+
scopeKey: catalog.scope_key,
|
|
113
|
+
strategy: catalog.strategy,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
async commitDatabase(input) {
|
|
119
|
+
await beforeOperation?.();
|
|
120
|
+
return database.commit(input);
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
async getChannels(): Promise<readonly ChannelRow[]> {
|
|
124
|
+
await beforeOperation?.();
|
|
125
|
+
return client.getChannels();
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
async insertChannel(input) {
|
|
129
|
+
await beforeOperation?.();
|
|
130
|
+
return database.models.channels.insert(input);
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
async deleteChannel(input) {
|
|
134
|
+
await beforeOperation?.();
|
|
135
|
+
return database.models.channels.delete(input);
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
async getBundles(options) {
|
|
139
|
+
await beforeOperation?.();
|
|
140
|
+
return client.getBundles(options);
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
async insertBundle(bundle: Bundle): Promise<void> {
|
|
144
|
+
await beforeOperation?.();
|
|
145
|
+
await client.insertBundle(bundle);
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
async insertBundles(bundles: readonly Bundle[]): Promise<void> {
|
|
149
|
+
await beforeOperation?.();
|
|
150
|
+
await client.mutate(async (transaction) => {
|
|
151
|
+
for (const bundle of bundles) {
|
|
152
|
+
await transaction.insertBundle(bundle);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
async updateBundleById(
|
|
158
|
+
bundleId: string,
|
|
159
|
+
update: Partial<Bundle>,
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
await beforeOperation?.();
|
|
162
|
+
await client.updateBundleById(bundleId, update);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
async deleteBundleById(bundleId: string): Promise<void> {
|
|
166
|
+
await beforeOperation?.();
|
|
167
|
+
await client.deleteBundleById(bundleId);
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
api,
|
|
173
|
+
adapterName: database.name,
|
|
174
|
+
createMigrator: () => {
|
|
175
|
+
throw new Error(
|
|
176
|
+
"createMigrator is only available for Kysely/MongoDB database plugins.",
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
generateSchema: () => {
|
|
180
|
+
throw new Error(
|
|
181
|
+
"generateSchema is only available for Drizzle/Prisma database plugins.",
|
|
182
|
+
);
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|