@hot-updater/plugin-core 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.
Files changed (161) hide show
  1. package/dist/assetStorageLayout.cjs +36 -18
  2. package/dist/assetStorageLayout.d.cts +21 -6
  3. package/dist/assetStorageLayout.d.mts +21 -6
  4. package/dist/assetStorageLayout.mjs +36 -18
  5. package/dist/bundleStorageLayout.cjs +2 -3
  6. package/dist/bundleStorageLayout.mjs +2 -3
  7. package/dist/contentAddressedAssets.cjs +5 -0
  8. package/dist/contentAddressedAssets.d.cts +2 -1
  9. package/dist/contentAddressedAssets.d.mts +2 -1
  10. package/dist/contentAddressedAssets.mjs +5 -1
  11. package/dist/createDatabasePlugin.cjs +775 -284
  12. package/dist/createDatabasePlugin.d.cts +20 -64
  13. package/dist/createDatabasePlugin.d.mts +20 -64
  14. package/dist/createDatabasePlugin.mjs +773 -284
  15. package/dist/createStorageKeyBuilder.cjs +9 -2
  16. package/dist/createStorageKeyBuilder.mjs +9 -2
  17. package/dist/createStoragePlugin.cjs +6 -145
  18. package/dist/createStoragePlugin.d.cts +7 -52
  19. package/dist/createStoragePlugin.d.mts +7 -52
  20. package/dist/createStoragePlugin.mjs +5 -143
  21. package/dist/databaseClient.cjs +112 -0
  22. package/dist/databaseClient.d.cts +33 -0
  23. package/dist/databaseClient.d.mts +33 -0
  24. package/dist/databaseClient.mjs +110 -0
  25. package/dist/databaseClientReads.cjs +113 -0
  26. package/dist/databaseClientReads.mjs +112 -0
  27. package/dist/databaseClientUpdates.cjs +39 -0
  28. package/dist/databaseClientUpdates.d.cts +11 -0
  29. package/dist/databaseClientUpdates.d.mts +11 -0
  30. package/dist/databaseClientUpdates.mjs +36 -0
  31. package/dist/databaseJsonValue.cjs +37 -0
  32. package/dist/databaseJsonValue.d.cts +5 -0
  33. package/dist/databaseJsonValue.d.mts +5 -0
  34. package/dist/databaseJsonValue.mjs +37 -0
  35. package/dist/databaseMetadata.cjs +13 -0
  36. package/dist/databaseMetadata.mjs +12 -0
  37. package/dist/databasePluginCrud.cjs +86 -0
  38. package/dist/databasePluginCrud.d.cts +1 -0
  39. package/dist/databasePluginCrud.d.mts +1 -0
  40. package/dist/databasePluginCrud.mjs +86 -0
  41. package/dist/databasePluginCrudValidation.d.cts +1 -0
  42. package/dist/databasePluginCrudValidation.d.mts +1 -0
  43. package/dist/databasePluginCrudValidationErrors.cjs +10 -0
  44. package/dist/databasePluginCrudValidationErrors.d.cts +9 -0
  45. package/dist/databasePluginCrudValidationErrors.d.mts +9 -0
  46. package/dist/databasePluginCrudValidationErrors.mjs +10 -0
  47. package/dist/databasePluginCrudValidationFields.cjs +291 -0
  48. package/dist/databasePluginCrudValidationFields.d.cts +1 -0
  49. package/dist/databasePluginCrudValidationFields.d.mts +1 -0
  50. package/dist/databasePluginCrudValidationFields.mjs +281 -0
  51. package/dist/databasePluginCrudValidationMutations.cjs +88 -0
  52. package/dist/databasePluginCrudValidationMutations.d.cts +1 -0
  53. package/dist/databasePluginCrudValidationMutations.d.mts +1 -0
  54. package/dist/databasePluginCrudValidationMutations.mjs +82 -0
  55. package/dist/databasePluginCrudValidationQueries.cjs +103 -0
  56. package/dist/databasePluginCrudValidationQueries.d.cts +1 -0
  57. package/dist/databasePluginCrudValidationQueries.d.mts +1 -0
  58. package/dist/databasePluginCrudValidationQueries.mjs +97 -0
  59. package/dist/databasePluginCrudValidationRows.cjs +55 -0
  60. package/dist/databasePluginCrudValidationRows.d.cts +1 -0
  61. package/dist/databasePluginCrudValidationRows.d.mts +1 -0
  62. package/dist/databasePluginCrudValidationRows.mjs +53 -0
  63. package/dist/databasePluginTransaction.cjs +7 -0
  64. package/dist/databasePluginTransaction.mjs +7 -0
  65. package/dist/databaseRows.cjs +149 -0
  66. package/dist/databaseRows.d.cts +34 -0
  67. package/dist/databaseRows.d.mts +34 -0
  68. package/dist/databaseRows.mjs +141 -0
  69. package/dist/index.cjs +76 -24
  70. package/dist/index.d.cts +22 -12
  71. package/dist/index.d.mts +22 -12
  72. package/dist/index.mjs +21 -14
  73. package/dist/internal.cjs +6 -0
  74. package/dist/internal.d.cts +9 -0
  75. package/dist/internal.d.mts +9 -0
  76. package/dist/internal.mjs +3 -0
  77. package/dist/node_modules/.pnpm/verkit@0.3.2/node_modules/verkit/dist/index.cjs +345 -0
  78. package/dist/node_modules/.pnpm/verkit@0.3.2/node_modules/verkit/dist/index.mjs +341 -0
  79. package/dist/paginateBundles.d.cts +6 -4
  80. package/dist/paginateBundles.d.mts +6 -4
  81. package/dist/parseStorageUri.cjs +46 -30
  82. package/dist/parseStorageUri.d.cts +20 -17
  83. package/dist/parseStorageUri.d.mts +20 -17
  84. package/dist/parseStorageUri.mjs +46 -30
  85. package/dist/queryBundles.cjs +1 -7
  86. package/dist/queryBundles.d.cts +3 -1
  87. package/dist/queryBundles.d.mts +3 -1
  88. package/dist/queryBundles.mjs +1 -7
  89. package/dist/releaseCatalogCompiler.cjs +391 -0
  90. package/dist/releaseCatalogCompiler.d.cts +55 -0
  91. package/dist/releaseCatalogCompiler.d.mts +55 -0
  92. package/dist/releaseCatalogCompiler.mjs +386 -0
  93. package/dist/releaseCatalogMutation.cjs +303 -0
  94. package/dist/releaseCatalogMutation.d.cts +86 -0
  95. package/dist/releaseCatalogMutation.d.mts +86 -0
  96. package/dist/releaseCatalogMutation.mjs +297 -0
  97. package/dist/releaseManagement.cjs +231 -0
  98. package/dist/releaseManagement.d.cts +48 -0
  99. package/dist/releaseManagement.d.mts +48 -0
  100. package/dist/releaseManagement.mjs +224 -0
  101. package/dist/remoteBundleSigning.cjs +296 -0
  102. package/dist/remoteBundleSigning.d.cts +43 -0
  103. package/dist/remoteBundleSigning.d.mts +43 -0
  104. package/dist/remoteBundleSigning.mjs +291 -0
  105. package/dist/requestBundleCache.cjs +22 -0
  106. package/dist/requestBundleCache.d.cts +9 -0
  107. package/dist/requestBundleCache.d.mts +9 -0
  108. package/dist/requestBundleCache.mjs +22 -0
  109. package/dist/semverSatisfies.cjs +3 -4
  110. package/dist/semverSatisfies.mjs +1 -1
  111. package/dist/storageDownloadPath.cjs +48 -0
  112. package/dist/storageDownloadPath.d.cts +15 -0
  113. package/dist/storageDownloadPath.d.mts +15 -0
  114. package/dist/storageDownloadPath.mjs +46 -0
  115. package/dist/types/database.d.cts +4 -0
  116. package/dist/types/database.d.mts +4 -0
  117. package/dist/types/databaseFields.cjs +92 -0
  118. package/dist/types/databaseFields.d.cts +12 -0
  119. package/dist/types/databaseFields.d.mts +12 -0
  120. package/dist/types/databaseFields.mjs +92 -0
  121. package/dist/types/databaseOperations.d.cts +173 -0
  122. package/dist/types/databaseOperations.d.mts +173 -0
  123. package/dist/types/databasePlugin.d.cts +240 -0
  124. package/dist/types/databasePlugin.d.mts +240 -0
  125. package/dist/types/databaseQuery.d.cts +47 -0
  126. package/dist/types/databaseQuery.d.mts +47 -0
  127. package/dist/types/databaseRows.d.cts +120 -0
  128. package/dist/types/databaseRows.d.mts +120 -0
  129. package/dist/types/index.d.cts +120 -162
  130. package/dist/types/index.d.mts +120 -162
  131. package/dist/types/internal.d.cts +7 -0
  132. package/dist/types/internal.d.mts +7 -0
  133. package/dist/types/public.d.cts +3 -0
  134. package/dist/types/public.d.mts +3 -0
  135. package/dist/uuidv7.cjs +9 -0
  136. package/dist/uuidv7.d.cts +4 -1
  137. package/dist/uuidv7.d.mts +4 -1
  138. package/dist/uuidv7.mjs +8 -1
  139. package/package.json +10 -5
  140. package/dist/bundleUnitOfWork.cjs +0 -158
  141. package/dist/bundleUnitOfWork.mjs +0 -158
  142. package/dist/bundleUnitOfWorkStore.cjs +0 -15
  143. package/dist/bundleUnitOfWorkStore.mjs +0 -15
  144. package/dist/createBlobDatabasePlugin.cjs +0 -382
  145. package/dist/createBlobDatabasePlugin.d.cts +0 -29
  146. package/dist/createBlobDatabasePlugin.d.mts +0 -29
  147. package/dist/createBlobDatabasePlugin.mjs +0 -381
  148. package/dist/legacyAssetStorageLayout.cjs +0 -12
  149. package/dist/legacyAssetStorageLayout.mjs +0 -12
  150. package/dist/requestUpdateBundleState.cjs +0 -26
  151. package/dist/requestUpdateBundleState.d.cts +0 -12
  152. package/dist/requestUpdateBundleState.d.mts +0 -12
  153. package/dist/requestUpdateBundleState.mjs +0 -24
  154. package/dist/resolveUpdateInfoFromBundles.cjs +0 -14
  155. package/dist/resolveUpdateInfoFromBundles.d.cts +0 -16
  156. package/dist/resolveUpdateInfoFromBundles.d.mts +0 -16
  157. package/dist/resolveUpdateInfoFromBundles.mjs +0 -13
  158. package/dist/storageProfile.cjs +0 -15
  159. package/dist/storageProfile.d.cts +0 -9
  160. package/dist/storageProfile.d.mts +0 -9
  161. package/dist/storageProfile.mjs +0 -12
@@ -0,0 +1,110 @@
1
+ import { DatabaseAtomicCommitUnsupportedError, DatabaseRowReferencedError } from "./createDatabasePlugin.mjs";
2
+ import { bundleToPatchRows, bundleToRow } from "./databaseRows.mjs";
3
+ import { hydrateRows, responsePage } from "./databaseClientReads.mjs";
4
+ import { DatabasePatchUpdateUnsupportedError, bundleUpdateToPatchRows, bundleUpdateToRow } from "./databaseClientUpdates.mjs";
5
+ //#region src/databaseClient.ts
6
+ var DatabaseBundleNotFoundError = class extends Error {
7
+ name = "DatabaseBundleNotFoundError";
8
+ constructor(bundleId) {
9
+ super(`Bundle "${bundleId}" was not found.`);
10
+ this.bundleId = bundleId;
11
+ }
12
+ };
13
+ var DatabasePatchInsertUnsupportedError = class extends Error {
14
+ name = "DatabasePatchInsertUnsupportedError";
15
+ constructor(bundleId, pluginName) {
16
+ super(`Database plugin "${pluginName}" cannot atomically insert patches for bundle "${bundleId}".`);
17
+ this.bundleId = bundleId;
18
+ this.pluginName = pluginName;
19
+ }
20
+ };
21
+ const insertChanges = (bundle) => [{
22
+ model: "bundles",
23
+ operation: "insert",
24
+ row: bundleToRow(bundle)
25
+ }, ...bundleToPatchRows(bundle).map((row) => ({
26
+ model: "bundlePatches",
27
+ operation: "insert",
28
+ row
29
+ }))];
30
+ const updateChanges = (bundleId, update) => {
31
+ const rowUpdate = bundleUpdateToRow(update);
32
+ return [{
33
+ model: "bundles",
34
+ operation: "update",
35
+ where: { id: bundleId },
36
+ update: rowUpdate
37
+ }, ...Object.hasOwn(update, "patches") ? [{
38
+ model: "bundlePatches",
39
+ operation: "delete",
40
+ where: { bundleId }
41
+ }, ...bundleUpdateToPatchRows(bundleId, update).map((row) => ({
42
+ model: "bundlePatches",
43
+ operation: "insert",
44
+ row
45
+ }))] : []];
46
+ };
47
+ const deleteChanges = (bundleId) => [{
48
+ model: "bundles",
49
+ operation: "delete",
50
+ where: { id: bundleId }
51
+ }];
52
+ const createDatabaseClient = (plugin) => {
53
+ const getBundleById = async (id) => {
54
+ const row = await plugin.models.bundles.findById(id);
55
+ if (!row) return null;
56
+ return (await hydrateRows(plugin, [row]))[0] ?? null;
57
+ };
58
+ const insertChannel = (input) => plugin.models.channels.insert(input);
59
+ const createMutationClient = (commit) => ({
60
+ getBundleById,
61
+ getBundles: (options) => responsePage(plugin, options),
62
+ async getChannels() {
63
+ return (await plugin.models.channels.list({})).channels;
64
+ },
65
+ insertChannel,
66
+ async insertBundle(bundle) {
67
+ try {
68
+ await commit(insertChanges(bundle));
69
+ } catch (error) {
70
+ if (error instanceof DatabaseAtomicCommitUnsupportedError && bundleToPatchRows(bundle).length > 0) throw new DatabasePatchInsertUnsupportedError(bundle.id, plugin.name);
71
+ throw error;
72
+ }
73
+ },
74
+ async updateBundleById(bundleId, update) {
75
+ try {
76
+ if (!(await commit(updateChanges(bundleId, update))).committed) throw new DatabaseBundleNotFoundError(bundleId);
77
+ } catch (error) {
78
+ if (error instanceof DatabaseAtomicCommitUnsupportedError && Object.hasOwn(update, "patches")) throw new DatabasePatchUpdateUnsupportedError(bundleId, plugin.name);
79
+ throw error;
80
+ }
81
+ },
82
+ async deleteBundleById(bundleId) {
83
+ const result = await commit(deleteChanges(bundleId));
84
+ if (!result.committed && result.conflict.reason === "referenced") throw new DatabaseRowReferencedError();
85
+ }
86
+ });
87
+ const runMutation = async (operation) => {
88
+ const changes = [];
89
+ const result = await operation(createMutationClient(async (input) => {
90
+ changes.push(...input);
91
+ return { committed: true };
92
+ }));
93
+ if (changes.length === 0) return result;
94
+ const commitResult = await plugin.commit({ changes });
95
+ if (!commitResult.committed) {
96
+ const change = changes[commitResult.conflict.changeIndex];
97
+ if (commitResult.conflict.reason === "referenced" && change?.model === "bundles" && change.operation === "delete") throw new DatabaseRowReferencedError();
98
+ if (change?.model === "bundles" && change.operation === "update") throw new DatabaseBundleNotFoundError(change.where.id);
99
+ throw new Error(`Database plugin "${plugin.name}" rejected a commit.`);
100
+ }
101
+ return result;
102
+ };
103
+ return {
104
+ ...createMutationClient((changes) => plugin.commit({ changes })),
105
+ deleteChannel: (input) => plugin.models.channels.delete(input),
106
+ mutate: runMutation
107
+ };
108
+ };
109
+ //#endregion
110
+ export { DatabaseBundleNotFoundError, DatabasePatchInsertUnsupportedError, createDatabaseClient };
@@ -0,0 +1,113 @@
1
+ const require_calculatePagination = require("./calculatePagination.cjs");
2
+ const require_databasePluginCrudValidationErrors = require("./databasePluginCrudValidationErrors.cjs");
3
+ const require_databasePluginCrudValidationQueries = require("./databasePluginCrudValidationQueries.cjs");
4
+ const require_databaseRows = require("./databaseRows.cjs");
5
+ //#region src/databaseClientReads.ts
6
+ const PAGE_SIZE = 100;
7
+ const mergeIdFilter = (where, id) => ({
8
+ ...where,
9
+ id: {
10
+ ...where?.id,
11
+ ...id
12
+ }
13
+ });
14
+ const loadBundleRows = async (database, where) => {
15
+ const finiteIds = where?.id?.in;
16
+ if (finiteIds) {
17
+ if (finiteIds.length === 0) return [];
18
+ return [...await database.models.bundles.findMany({
19
+ where,
20
+ limit: finiteIds.length,
21
+ offset: 0,
22
+ orderBy: {
23
+ field: "id",
24
+ direction: "asc"
25
+ }
26
+ })];
27
+ }
28
+ const [cutoff] = await database.models.bundles.findMany({
29
+ where,
30
+ limit: 1,
31
+ offset: 0,
32
+ orderBy: {
33
+ field: "id",
34
+ direction: "desc"
35
+ }
36
+ });
37
+ if (!cutoff) return [];
38
+ const rows = [];
39
+ let after;
40
+ for (;;) {
41
+ const page = await database.models.bundles.findMany({
42
+ where: mergeIdFilter(where, {
43
+ lte: cutoff.id,
44
+ ...after ? { gt: after } : {}
45
+ }),
46
+ limit: PAGE_SIZE,
47
+ offset: 0,
48
+ orderBy: {
49
+ field: "id",
50
+ direction: "asc"
51
+ }
52
+ });
53
+ rows.push(...page);
54
+ if (page.length < PAGE_SIZE) return rows;
55
+ after = page.at(-1)?.id;
56
+ }
57
+ };
58
+ const hydrateRows = async (database, ownerRows) => {
59
+ const patchRows = await database.models.bundlePatches.findByBundleIds(ownerRows.map(({ id }) => id));
60
+ const ownerIds = new Set(ownerRows.map(({ id }) => id));
61
+ const referencedIds = [...new Set(patchRows.map(({ base_bundle_id }) => base_bundle_id).filter((id) => !ownerIds.has(id)))];
62
+ return require_databaseRows.rowsToBundles(ownerRows, patchRows, referencedIds.length === 0 ? [] : await loadBundleRows(database, { id: { in: referencedIds } }));
63
+ };
64
+ const cursorIdFilter = (cursor, direction) => {
65
+ if (cursor?.after) return { [direction === "desc" ? "lt" : "gt"]: cursor.after };
66
+ if (cursor?.before) return { [direction === "desc" ? "gt" : "lt"]: cursor.before };
67
+ };
68
+ const responsePage = async (database, options) => {
69
+ require_databasePluginCrudValidationQueries.validateBundlePagination(options);
70
+ const direction = options.orderBy?.direction ?? "desc";
71
+ const offset = options.page ? Math.max(0, options.page - 1) * options.limit : 0;
72
+ const cursor = options.page ? void 0 : options.cursor;
73
+ const queryLimit = cursor ? options.limit + 1 : options.limit;
74
+ if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(queryLimit) || !Number.isSafeInteger(offset + queryLimit)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-pagination");
75
+ const cursorFilter = cursorIdFilter(cursor, direction);
76
+ const where = cursorFilter ? mergeIdFilter(options.where, cursorFilter) : options.where;
77
+ const queryDirection = cursor?.before ? direction === "desc" ? "asc" : "desc" : direction;
78
+ const [queriedRows, total] = await Promise.all([database.models.bundles.findMany({
79
+ where,
80
+ limit: queryLimit,
81
+ offset,
82
+ orderBy: {
83
+ field: "id",
84
+ direction: queryDirection
85
+ }
86
+ }), database.models.bundles.count(options.where)]);
87
+ const hasMore = cursor ? queriedRows.length > options.limit : false;
88
+ const pageRows = cursor ? queriedRows.slice(0, options.limit) : queriedRows;
89
+ const ownerRows = cursor?.before ? pageRows.toReversed() : pageRows;
90
+ const pagination = require_calculatePagination.calculatePagination(total, {
91
+ limit: options.limit,
92
+ offset
93
+ });
94
+ const hasPreviousPage = cursor ? Boolean(cursor.after) || hasMore : pagination.hasPreviousPage;
95
+ const hasNextPage = cursor ? Boolean(cursor.before) || hasMore : pagination.hasNextPage;
96
+ const firstId = ownerRows[0]?.id;
97
+ const lastId = ownerRows.at(-1)?.id;
98
+ return {
99
+ data: await hydrateRows(database, ownerRows),
100
+ pagination: {
101
+ ...pagination,
102
+ hasNextPage,
103
+ hasPreviousPage,
104
+ ...hasNextPage && lastId ? { nextCursor: lastId } : {},
105
+ ...hasPreviousPage && firstId ? { previousCursor: firstId } : {},
106
+ ...!firstId && cursor?.after ? { previousCursor: cursor.after } : {},
107
+ ...!lastId && cursor?.before ? { nextCursor: cursor.before } : {}
108
+ }
109
+ };
110
+ };
111
+ //#endregion
112
+ exports.hydrateRows = hydrateRows;
113
+ exports.responsePage = responsePage;
@@ -0,0 +1,112 @@
1
+ import { calculatePagination } from "./calculatePagination.mjs";
2
+ import { DatabasePluginInputError } from "./databasePluginCrudValidationErrors.mjs";
3
+ import { validateBundlePagination } from "./databasePluginCrudValidationQueries.mjs";
4
+ import { rowsToBundles } from "./databaseRows.mjs";
5
+ //#region src/databaseClientReads.ts
6
+ const PAGE_SIZE = 100;
7
+ const mergeIdFilter = (where, id) => ({
8
+ ...where,
9
+ id: {
10
+ ...where?.id,
11
+ ...id
12
+ }
13
+ });
14
+ const loadBundleRows = async (database, where) => {
15
+ const finiteIds = where?.id?.in;
16
+ if (finiteIds) {
17
+ if (finiteIds.length === 0) return [];
18
+ return [...await database.models.bundles.findMany({
19
+ where,
20
+ limit: finiteIds.length,
21
+ offset: 0,
22
+ orderBy: {
23
+ field: "id",
24
+ direction: "asc"
25
+ }
26
+ })];
27
+ }
28
+ const [cutoff] = await database.models.bundles.findMany({
29
+ where,
30
+ limit: 1,
31
+ offset: 0,
32
+ orderBy: {
33
+ field: "id",
34
+ direction: "desc"
35
+ }
36
+ });
37
+ if (!cutoff) return [];
38
+ const rows = [];
39
+ let after;
40
+ for (;;) {
41
+ const page = await database.models.bundles.findMany({
42
+ where: mergeIdFilter(where, {
43
+ lte: cutoff.id,
44
+ ...after ? { gt: after } : {}
45
+ }),
46
+ limit: PAGE_SIZE,
47
+ offset: 0,
48
+ orderBy: {
49
+ field: "id",
50
+ direction: "asc"
51
+ }
52
+ });
53
+ rows.push(...page);
54
+ if (page.length < PAGE_SIZE) return rows;
55
+ after = page.at(-1)?.id;
56
+ }
57
+ };
58
+ const hydrateRows = async (database, ownerRows) => {
59
+ const patchRows = await database.models.bundlePatches.findByBundleIds(ownerRows.map(({ id }) => id));
60
+ const ownerIds = new Set(ownerRows.map(({ id }) => id));
61
+ const referencedIds = [...new Set(patchRows.map(({ base_bundle_id }) => base_bundle_id).filter((id) => !ownerIds.has(id)))];
62
+ return rowsToBundles(ownerRows, patchRows, referencedIds.length === 0 ? [] : await loadBundleRows(database, { id: { in: referencedIds } }));
63
+ };
64
+ const cursorIdFilter = (cursor, direction) => {
65
+ if (cursor?.after) return { [direction === "desc" ? "lt" : "gt"]: cursor.after };
66
+ if (cursor?.before) return { [direction === "desc" ? "gt" : "lt"]: cursor.before };
67
+ };
68
+ const responsePage = async (database, options) => {
69
+ validateBundlePagination(options);
70
+ const direction = options.orderBy?.direction ?? "desc";
71
+ const offset = options.page ? Math.max(0, options.page - 1) * options.limit : 0;
72
+ const cursor = options.page ? void 0 : options.cursor;
73
+ const queryLimit = cursor ? options.limit + 1 : options.limit;
74
+ if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(queryLimit) || !Number.isSafeInteger(offset + queryLimit)) throw new DatabasePluginInputError("invalid-pagination");
75
+ const cursorFilter = cursorIdFilter(cursor, direction);
76
+ const where = cursorFilter ? mergeIdFilter(options.where, cursorFilter) : options.where;
77
+ const queryDirection = cursor?.before ? direction === "desc" ? "asc" : "desc" : direction;
78
+ const [queriedRows, total] = await Promise.all([database.models.bundles.findMany({
79
+ where,
80
+ limit: queryLimit,
81
+ offset,
82
+ orderBy: {
83
+ field: "id",
84
+ direction: queryDirection
85
+ }
86
+ }), database.models.bundles.count(options.where)]);
87
+ const hasMore = cursor ? queriedRows.length > options.limit : false;
88
+ const pageRows = cursor ? queriedRows.slice(0, options.limit) : queriedRows;
89
+ const ownerRows = cursor?.before ? pageRows.toReversed() : pageRows;
90
+ const pagination = calculatePagination(total, {
91
+ limit: options.limit,
92
+ offset
93
+ });
94
+ const hasPreviousPage = cursor ? Boolean(cursor.after) || hasMore : pagination.hasPreviousPage;
95
+ const hasNextPage = cursor ? Boolean(cursor.before) || hasMore : pagination.hasNextPage;
96
+ const firstId = ownerRows[0]?.id;
97
+ const lastId = ownerRows.at(-1)?.id;
98
+ return {
99
+ data: await hydrateRows(database, ownerRows),
100
+ pagination: {
101
+ ...pagination,
102
+ hasNextPage,
103
+ hasPreviousPage,
104
+ ...hasNextPage && lastId ? { nextCursor: lastId } : {},
105
+ ...hasPreviousPage && firstId ? { previousCursor: firstId } : {},
106
+ ...!firstId && cursor?.after ? { previousCursor: cursor.after } : {},
107
+ ...!lastId && cursor?.before ? { nextCursor: cursor.before } : {}
108
+ }
109
+ };
110
+ };
111
+ //#endregion
112
+ export { hydrateRows, responsePage };
@@ -0,0 +1,39 @@
1
+ require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_databaseMetadata = require("./databaseMetadata.cjs");
3
+ let _hot_updater_core = require("@hot-updater/core");
4
+ //#region src/databaseClientUpdates.ts
5
+ var DatabasePatchUpdateUnsupportedError = class extends Error {
6
+ name = "DatabasePatchUpdateUnsupportedError";
7
+ constructor(bundleId, pluginName) {
8
+ super(`Database plugin "${pluginName}" cannot atomically replace patches for bundle "${bundleId}".`);
9
+ this.bundleId = bundleId;
10
+ this.pluginName = pluginName;
11
+ }
12
+ };
13
+ const bundleUpdateToRow = (update, _channelId) => {
14
+ return {
15
+ ...update.platform !== void 0 ? { platform: update.platform } : {},
16
+ ...update.fileHash !== void 0 ? { file_hash: update.fileHash } : {},
17
+ ...update.gitCommitHash !== void 0 ? { git_commit_hash: update.gitCommitHash } : {},
18
+ ...update.storageUri !== void 0 ? { storage_uri: update.storageUri } : {},
19
+ ...update.archiveByteSize !== void 0 ? { archive_byte_size: update.archiveByteSize } : {},
20
+ ...update.metadata !== void 0 ? { metadata: require_databaseMetadata.bundleMetadataToRow(update.metadata) } : {},
21
+ ...update.manifestStorageUri !== void 0 ? { manifest_storage_uri: update.manifestStorageUri } : {},
22
+ ...update.manifestFileHash !== void 0 ? { manifest_file_hash: update.manifestFileHash } : {},
23
+ ...update.assetBaseStorageUri !== void 0 ? { asset_base_storage_uri: update.assetBaseStorageUri } : {}
24
+ };
25
+ };
26
+ const bundleUpdateToPatchRows = (bundleId, update) => (0, _hot_updater_core.getBundlePatches)({ patches: update.patches }).map((patch, orderIndex) => ({
27
+ id: `${bundleId}:${patch.baseBundleId}`,
28
+ bundle_id: bundleId,
29
+ base_bundle_id: patch.baseBundleId,
30
+ base_file_hash: patch.baseFileHash,
31
+ patch_file_hash: patch.patchFileHash,
32
+ patch_storage_uri: patch.patchStorageUri,
33
+ byte_size: patch.byteSize,
34
+ order_index: orderIndex
35
+ }));
36
+ //#endregion
37
+ exports.DatabasePatchUpdateUnsupportedError = DatabasePatchUpdateUnsupportedError;
38
+ exports.bundleUpdateToPatchRows = bundleUpdateToPatchRows;
39
+ exports.bundleUpdateToRow = bundleUpdateToRow;
@@ -0,0 +1,11 @@
1
+ import { Bundle } from "@hot-updater/core";
2
+
3
+ //#region src/databaseClientUpdates.d.ts
4
+ declare class DatabasePatchUpdateUnsupportedError extends Error {
5
+ readonly bundleId: string;
6
+ readonly pluginName: string;
7
+ readonly name = "DatabasePatchUpdateUnsupportedError";
8
+ constructor(bundleId: string, pluginName: string);
9
+ }
10
+ //#endregion
11
+ export { DatabasePatchUpdateUnsupportedError };
@@ -0,0 +1,11 @@
1
+ import { Bundle } from "@hot-updater/core";
2
+
3
+ //#region src/databaseClientUpdates.d.ts
4
+ declare class DatabasePatchUpdateUnsupportedError extends Error {
5
+ readonly bundleId: string;
6
+ readonly pluginName: string;
7
+ readonly name = "DatabasePatchUpdateUnsupportedError";
8
+ constructor(bundleId: string, pluginName: string);
9
+ }
10
+ //#endregion
11
+ export { DatabasePatchUpdateUnsupportedError };
@@ -0,0 +1,36 @@
1
+ import { bundleMetadataToRow } from "./databaseMetadata.mjs";
2
+ import { getBundlePatches } from "@hot-updater/core";
3
+ //#region src/databaseClientUpdates.ts
4
+ var DatabasePatchUpdateUnsupportedError = class extends Error {
5
+ name = "DatabasePatchUpdateUnsupportedError";
6
+ constructor(bundleId, pluginName) {
7
+ super(`Database plugin "${pluginName}" cannot atomically replace patches for bundle "${bundleId}".`);
8
+ this.bundleId = bundleId;
9
+ this.pluginName = pluginName;
10
+ }
11
+ };
12
+ const bundleUpdateToRow = (update, _channelId) => {
13
+ return {
14
+ ...update.platform !== void 0 ? { platform: update.platform } : {},
15
+ ...update.fileHash !== void 0 ? { file_hash: update.fileHash } : {},
16
+ ...update.gitCommitHash !== void 0 ? { git_commit_hash: update.gitCommitHash } : {},
17
+ ...update.storageUri !== void 0 ? { storage_uri: update.storageUri } : {},
18
+ ...update.archiveByteSize !== void 0 ? { archive_byte_size: update.archiveByteSize } : {},
19
+ ...update.metadata !== void 0 ? { metadata: bundleMetadataToRow(update.metadata) } : {},
20
+ ...update.manifestStorageUri !== void 0 ? { manifest_storage_uri: update.manifestStorageUri } : {},
21
+ ...update.manifestFileHash !== void 0 ? { manifest_file_hash: update.manifestFileHash } : {},
22
+ ...update.assetBaseStorageUri !== void 0 ? { asset_base_storage_uri: update.assetBaseStorageUri } : {}
23
+ };
24
+ };
25
+ const bundleUpdateToPatchRows = (bundleId, update) => getBundlePatches({ patches: update.patches }).map((patch, orderIndex) => ({
26
+ id: `${bundleId}:${patch.baseBundleId}`,
27
+ bundle_id: bundleId,
28
+ base_bundle_id: patch.baseBundleId,
29
+ base_file_hash: patch.baseFileHash,
30
+ patch_file_hash: patch.patchFileHash,
31
+ patch_storage_uri: patch.patchStorageUri,
32
+ byte_size: patch.byteSize,
33
+ order_index: orderIndex
34
+ }));
35
+ //#endregion
36
+ export { DatabasePatchUpdateUnsupportedError, bundleUpdateToPatchRows, bundleUpdateToRow };
@@ -0,0 +1,37 @@
1
+ //#region src/databaseJsonValue.ts
2
+ const isDatabaseJsonValue = (value) => {
3
+ const ancestors = /* @__PURE__ */ new WeakSet();
4
+ const validate = (input) => {
5
+ if (input === null || typeof input === "string" || typeof input === "boolean") return true;
6
+ if (typeof input === "number") return Number.isFinite(input);
7
+ if (typeof input !== "object") return false;
8
+ if (ancestors.has(input)) return false;
9
+ ancestors.add(input);
10
+ try {
11
+ if (Array.isArray(input)) {
12
+ if (Object.getPrototypeOf(input) !== Array.prototype) return false;
13
+ if (Reflect.ownKeys(input).length !== input.length + 1) return false;
14
+ for (let index = 0; index < input.length; index += 1) {
15
+ const descriptor = Object.getOwnPropertyDescriptor(input, String(index));
16
+ if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor) || !validate(descriptor.value)) return false;
17
+ }
18
+ return true;
19
+ }
20
+ const prototype = Object.getPrototypeOf(input);
21
+ if (prototype !== Object.prototype && prototype !== null) return false;
22
+ for (const key of Reflect.ownKeys(input)) {
23
+ if (typeof key !== "string" || key === "__proto__") return false;
24
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
25
+ if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor) || !validate(descriptor.value)) return false;
26
+ }
27
+ return true;
28
+ } finally {
29
+ ancestors.delete(input);
30
+ }
31
+ };
32
+ return validate(value);
33
+ };
34
+ const isDatabaseJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && isDatabaseJsonValue(value);
35
+ const isDatabaseMetadataObject = (value) => isDatabaseJsonObject(value) && (!Object.hasOwn(value, "app_version") || typeof value["app_version"] === "string");
36
+ //#endregion
37
+ exports.isDatabaseMetadataObject = isDatabaseMetadataObject;
@@ -0,0 +1,5 @@
1
+ import { DatabaseBundleMetadata } from "./types/databaseRows.cjs";
2
+ //#region src/databaseJsonValue.d.ts
3
+ declare const isDatabaseMetadataObject: (value: unknown) => value is DatabaseBundleMetadata;
4
+ //#endregion
5
+ export { isDatabaseMetadataObject };
@@ -0,0 +1,5 @@
1
+ import { DatabaseBundleMetadata } from "./types/databaseRows.mjs";
2
+ //#region src/databaseJsonValue.d.ts
3
+ declare const isDatabaseMetadataObject: (value: unknown) => value is DatabaseBundleMetadata;
4
+ //#endregion
5
+ export { isDatabaseMetadataObject };
@@ -0,0 +1,37 @@
1
+ //#region src/databaseJsonValue.ts
2
+ const isDatabaseJsonValue = (value) => {
3
+ const ancestors = /* @__PURE__ */ new WeakSet();
4
+ const validate = (input) => {
5
+ if (input === null || typeof input === "string" || typeof input === "boolean") return true;
6
+ if (typeof input === "number") return Number.isFinite(input);
7
+ if (typeof input !== "object") return false;
8
+ if (ancestors.has(input)) return false;
9
+ ancestors.add(input);
10
+ try {
11
+ if (Array.isArray(input)) {
12
+ if (Object.getPrototypeOf(input) !== Array.prototype) return false;
13
+ if (Reflect.ownKeys(input).length !== input.length + 1) return false;
14
+ for (let index = 0; index < input.length; index += 1) {
15
+ const descriptor = Object.getOwnPropertyDescriptor(input, String(index));
16
+ if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor) || !validate(descriptor.value)) return false;
17
+ }
18
+ return true;
19
+ }
20
+ const prototype = Object.getPrototypeOf(input);
21
+ if (prototype !== Object.prototype && prototype !== null) return false;
22
+ for (const key of Reflect.ownKeys(input)) {
23
+ if (typeof key !== "string" || key === "__proto__") return false;
24
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
25
+ if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor) || !validate(descriptor.value)) return false;
26
+ }
27
+ return true;
28
+ } finally {
29
+ ancestors.delete(input);
30
+ }
31
+ };
32
+ return validate(value);
33
+ };
34
+ const isDatabaseJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && isDatabaseJsonValue(value);
35
+ const isDatabaseMetadataObject = (value) => isDatabaseJsonObject(value) && (!Object.hasOwn(value, "app_version") || typeof value["app_version"] === "string");
36
+ //#endregion
37
+ export { isDatabaseMetadataObject };
@@ -0,0 +1,13 @@
1
+ require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_databasePluginCrudValidationErrors = require("./databasePluginCrudValidationErrors.cjs");
3
+ const require_databaseJsonValue = require("./databaseJsonValue.cjs");
4
+ let _hot_updater_core = require("@hot-updater/core");
5
+ //#region src/databaseMetadata.ts
6
+ const bundleMetadataToRow = (metadata) => {
7
+ const value = (0, _hot_updater_core.stripBundleArtifactMetadata)(metadata);
8
+ if (value === void 0) return {};
9
+ if (!require_databaseJsonValue.isDatabaseMetadataObject(value)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
10
+ return value;
11
+ };
12
+ //#endregion
13
+ exports.bundleMetadataToRow = bundleMetadataToRow;
@@ -0,0 +1,12 @@
1
+ import { DatabasePluginInputError } from "./databasePluginCrudValidationErrors.mjs";
2
+ import { isDatabaseMetadataObject } from "./databaseJsonValue.mjs";
3
+ import { stripBundleArtifactMetadata } from "@hot-updater/core";
4
+ //#region src/databaseMetadata.ts
5
+ const bundleMetadataToRow = (metadata) => {
6
+ const value = stripBundleArtifactMetadata(metadata);
7
+ if (value === void 0) return {};
8
+ if (!isDatabaseMetadataObject(value)) throw new DatabasePluginInputError("invalid-data");
9
+ return value;
10
+ };
11
+ //#endregion
12
+ export { bundleMetadataToRow };
@@ -0,0 +1,86 @@
1
+ const require_databasePluginCrudValidationErrors = require("./databasePluginCrudValidationErrors.cjs");
2
+ const require_databasePluginCrudValidationFields = require("./databasePluginCrudValidationFields.cjs");
3
+ const require_databasePluginCrudValidationRows = require("./databasePluginCrudValidationRows.cjs");
4
+ const require_databasePluginCrudValidationMutations = require("./databasePluginCrudValidationMutations.cjs");
5
+ const require_databasePluginCrudValidationQueries = require("./databasePluginCrudValidationQueries.cjs");
6
+ //#region src/databasePluginCrud.ts
7
+ const createDatabasePluginCrud = (implementation) => {
8
+ async function create(input) {
9
+ require_databasePluginCrudValidationFields.validateModel(input.model);
10
+ require_databasePluginCrudValidationRows.validateCreateData(input.model, input.data);
11
+ if (input.onConflict !== void 0 && !(input.onConflict === "ignore" && (input.model === "channels" || input.model === "api_keys"))) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
12
+ require_databasePluginCrudValidationQueries.validateSelect(input.model, input.select);
13
+ const row = await implementation.create(input);
14
+ require_databasePluginCrudValidationRows.validateResult(input.model, row, input.select);
15
+ return require_databasePluginCrudValidationRows.selectRow(row, input);
16
+ }
17
+ async function update(input) {
18
+ require_databasePluginCrudValidationFields.validateModel(input.model);
19
+ require_databasePluginCrudValidationQueries.validateWhere(input.model, input.where);
20
+ require_databasePluginCrudValidationMutations.validateMutationWhere(input.where);
21
+ require_databasePluginCrudValidationMutations.validateUpdateWhere(input.model, input.where);
22
+ if (input.model === "bundles") require_databasePluginCrudValidationMutations.validateBundleUpdateData(input.update);
23
+ else if (input.model === "releases") require_databasePluginCrudValidationMutations.validateReleaseUpdateData(input.update);
24
+ else if (input.model === "release_catalogs") require_databasePluginCrudValidationMutations.validateReleaseCatalogUpdateData(input.update);
25
+ else if (input.model === "api_keys") require_databasePluginCrudValidationMutations.validateApiKeyUpdateData(input.update);
26
+ else throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
27
+ require_databasePluginCrudValidationQueries.validateSelect(input.model, input.select);
28
+ if (input.model === "bundles") {} else if (input.model === "releases") await require_databasePluginCrudValidationMutations.validateReleaseTargetUpdate(implementation, input);
29
+ const row = await implementation.update(input);
30
+ if (row === null) return null;
31
+ require_databasePluginCrudValidationRows.validateResult(input.model, row, input.select);
32
+ return require_databasePluginCrudValidationRows.selectRow(row, input);
33
+ }
34
+ async function deleteRows(input) {
35
+ require_databasePluginCrudValidationFields.validateModel(input.model);
36
+ if (input.model !== "bundles" && input.model !== "bundle_patches" && input.model !== "releases" && input.model !== "channels") throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
37
+ require_databasePluginCrudValidationQueries.validateWhere(input.model, input.where);
38
+ require_databasePluginCrudValidationMutations.validateMutationWhere(input.where);
39
+ await implementation.delete(input);
40
+ }
41
+ async function count(input) {
42
+ require_databasePluginCrudValidationFields.validateModel(input.model);
43
+ require_databasePluginCrudValidationQueries.validateWhere(input.model, input.where);
44
+ require_databasePluginCrudValidationQueries.validateDistinctFields(input.model, input.distinct);
45
+ const value = await implementation.count(input);
46
+ if (!Number.isSafeInteger(value) || value < 0) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-result");
47
+ return value;
48
+ }
49
+ async function findOne(input) {
50
+ require_databasePluginCrudValidationFields.validateModel(input.model);
51
+ require_databasePluginCrudValidationQueries.validateWhere(input.model, input.where);
52
+ require_databasePluginCrudValidationQueries.validateSelect(input.model, input.select);
53
+ const row = await implementation.findOne(input);
54
+ if (row === null) return null;
55
+ require_databasePluginCrudValidationRows.validateResult(input.model, row, input.select);
56
+ return require_databasePluginCrudValidationRows.selectRow(row, input);
57
+ }
58
+ async function findMany(input) {
59
+ require_databasePluginCrudValidationFields.validateModel(input.model);
60
+ require_databasePluginCrudValidationQueries.validateWhere(input.model, input.where);
61
+ require_databasePluginCrudValidationQueries.validatePagination(input.limit, input.offset);
62
+ require_databasePluginCrudValidationQueries.validateSelect(input.model, input.select);
63
+ const validatedOrderBy = require_databasePluginCrudValidationQueries.validateOrderBy(input.model, input.orderBy);
64
+ require_databasePluginCrudValidationQueries.validateDistinctOn(input.model, input.distinctOn, validatedOrderBy);
65
+ const normalizedInput = {
66
+ ...input,
67
+ orderBy: input.orderBy,
68
+ limit: input.limit ?? 100,
69
+ offset: input.offset ?? 0
70
+ };
71
+ const rows = await implementation.findMany(normalizedInput);
72
+ if (!Array.isArray(rows)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-result");
73
+ rows.forEach((row) => require_databasePluginCrudValidationRows.validateResult(input.model, row, input.select));
74
+ return rows.map((row) => require_databasePluginCrudValidationRows.selectRow(row, input));
75
+ }
76
+ return {
77
+ create,
78
+ update,
79
+ delete: deleteRows,
80
+ count,
81
+ findOne,
82
+ findMany
83
+ };
84
+ };
85
+ //#endregion
86
+ exports.createDatabasePluginCrud = createDatabasePluginCrud;
@@ -0,0 +1 @@
1
+ import { DatabasePluginInputError, DatabasePluginInputErrorCode } from "./databasePluginCrudValidationErrors.cjs";
@@ -0,0 +1 @@
1
+ import { DatabasePluginInputError, DatabasePluginInputErrorCode } from "./databasePluginCrudValidationErrors.mjs";