@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
@@ -1,308 +1,799 @@
1
- require("./_virtual/_rolldown/runtime.cjs");
2
- const require_calculatePagination = require("./calculatePagination.cjs");
3
- const require_bundleUnitOfWork = require("./bundleUnitOfWork.cjs");
4
- const require_bundleUnitOfWorkStore = require("./bundleUnitOfWorkStore.cjs");
5
- let es_toolkit = require("es-toolkit");
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_databasePluginCrud = require("./databasePluginCrud.cjs");
6
+ const require_databasePluginTransaction = require("./databasePluginTransaction.cjs");
6
7
  //#region src/createDatabasePlugin.ts
7
- const REPLACE_ON_UPDATE_KEYS = ["patches", "targetCohorts"];
8
- const DEFAULT_DESC_ORDER = {
9
- field: "id",
10
- direction: "desc"
8
+ const PAGE_SIZE = 100;
9
+ const compareChannelRows = (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0;
10
+ var DatabaseAtomicCommitUnsupportedError = class extends Error {
11
+ name = "DatabaseAtomicCommitUnsupportedError";
12
+ constructor(pluginName) {
13
+ super(`Database plugin "${pluginName}" cannot atomically commit changes across models.`);
14
+ this.pluginName = pluginName;
15
+ }
11
16
  };
12
- function normalizePage(value) {
13
- if (!Number.isInteger(value) || value === void 0 || value < 1) return;
14
- return value;
15
- }
16
- function mergeBundleUpdate(baseBundle, patch) {
17
- return (0, es_toolkit.mergeWith)({ ...baseBundle }, patch, (_targetValue, sourceValue, key) => {
18
- if (REPLACE_ON_UPDATE_KEYS.includes(key)) return sourceValue;
17
+ /**
18
+ * Internal provider signal for a delete rejected by a live reference.
19
+ *
20
+ * Provider implementations throw this after translating their native
21
+ * foreign-key or reference-condition error. The public database contract
22
+ * observes only the indexed `referenced` commit conflict.
23
+ */
24
+ var DatabaseRowReferencedError = class extends Error {
25
+ name = "DatabaseRowReferencedError";
26
+ constructor() {
27
+ super("The database row is still referenced.");
28
+ }
29
+ };
30
+ var DatabaseCommitConflictError = class extends Error {
31
+ name = "DatabaseCommitConflictError";
32
+ constructor(result) {
33
+ super("Database commit precondition failed.");
34
+ this.result = result;
35
+ }
36
+ };
37
+ const toBundleWhere = (where) => {
38
+ if (!where) return [];
39
+ const filters = [];
40
+ if (where.platform !== void 0) filters.push({
41
+ field: "platform",
42
+ value: where.platform
19
43
  });
20
- }
21
- function mergeIdFilter(base, patch) {
22
- return {
23
- ...base,
24
- ...patch
25
- };
26
- }
27
- function mergeWhereWithIdFilter(where, idFilter) {
28
- return {
29
- ...where,
30
- id: mergeIdFilter(where?.id, idFilter)
31
- };
32
- }
33
- function buildCursorPageQuery(where, cursor, orderBy) {
34
- const direction = orderBy.direction;
35
- if (cursor.after) return {
36
- reverseData: false,
37
- where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "lt" : "gt"]: cursor.after }),
38
- orderBy
39
- };
40
- if (cursor.before) return {
41
- reverseData: true,
42
- where: mergeWhereWithIdFilter(where, { [direction === "desc" ? "gt" : "lt"]: cursor.before }),
43
- orderBy: {
44
- field: orderBy.field,
45
- direction: direction === "desc" ? "asc" : "desc"
44
+ if (where.id?.eq !== void 0) filters.push({
45
+ field: "id",
46
+ value: where.id.eq
47
+ });
48
+ if (where.id?.gt !== void 0) filters.push({
49
+ field: "id",
50
+ operator: "gt",
51
+ value: where.id.gt
52
+ });
53
+ if (where.id?.gte !== void 0) filters.push({
54
+ field: "id",
55
+ operator: "gte",
56
+ value: where.id.gte
57
+ });
58
+ if (where.id?.lt !== void 0) filters.push({
59
+ field: "id",
60
+ operator: "lt",
61
+ value: where.id.lt
62
+ });
63
+ if (where.id?.lte !== void 0) filters.push({
64
+ field: "id",
65
+ operator: "lte",
66
+ value: where.id.lte
67
+ });
68
+ if (where.id?.in !== void 0) filters.push({
69
+ field: "id",
70
+ operator: "in",
71
+ value: where.id.in
72
+ });
73
+ return filters;
74
+ };
75
+ const assertReleaseReferences = async (database, row) => {
76
+ if (await database.findOne({
77
+ model: "channels",
78
+ where: [{
79
+ field: "id",
80
+ value: row.channel_id
81
+ }]
82
+ }) === null) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
83
+ if (row.bundle_id !== null) {
84
+ const bundle = await database.findOne({
85
+ model: "bundles",
86
+ where: [{
87
+ field: "id",
88
+ value: row.bundle_id
89
+ }]
90
+ });
91
+ if (bundle === null || bundle.platform !== row.platform) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
92
+ }
93
+ };
94
+ const applyChange = async (database, change, changeIndex) => {
95
+ switch (change.model) {
96
+ case "bundles": switch (change.operation) {
97
+ case "insert":
98
+ await database.create({
99
+ model: "bundles",
100
+ data: change.row
101
+ });
102
+ return;
103
+ case "update":
104
+ if (await database.update({
105
+ model: "bundles",
106
+ where: [{
107
+ field: "id",
108
+ value: change.where.id
109
+ }],
110
+ update: change.update
111
+ }) === null) throw new DatabaseCommitConflictError({
112
+ committed: false,
113
+ conflict: {
114
+ changeIndex,
115
+ reason: "not_found"
116
+ }
117
+ });
118
+ return;
119
+ case "delete":
120
+ if (await database.count({
121
+ model: "releases",
122
+ where: [{
123
+ field: "bundle_id",
124
+ value: change.where.id
125
+ }]
126
+ }) > 0) throw new DatabaseCommitConflictError({
127
+ committed: false,
128
+ conflict: {
129
+ changeIndex,
130
+ reason: "referenced"
131
+ }
132
+ });
133
+ await database.delete({
134
+ model: "bundles",
135
+ where: [{
136
+ field: "id",
137
+ value: change.where.id
138
+ }]
139
+ });
140
+ return;
46
141
  }
47
- };
48
- return {
49
- reverseData: false,
50
- where: where ?? {},
51
- orderBy
52
- };
53
- }
54
- function buildCountBeforeWhere(where, firstBundleId, orderBy) {
55
- return mergeWhereWithIdFilter(where, { [orderBy.direction === "desc" ? "gt" : "lt"]: firstBundleId });
142
+ case "releases": switch (change.operation) {
143
+ case "insert":
144
+ await assertReleaseReferences(database, change.row);
145
+ await database.create({
146
+ model: "releases",
147
+ data: change.row
148
+ });
149
+ return;
150
+ case "update":
151
+ if (await database.update({
152
+ model: "releases",
153
+ where: [{
154
+ field: "id",
155
+ value: change.where.id
156
+ }],
157
+ update: change.update
158
+ }) === null) throw new DatabaseCommitConflictError({
159
+ committed: false,
160
+ conflict: {
161
+ changeIndex,
162
+ reason: "not_found"
163
+ }
164
+ });
165
+ return;
166
+ case "delete":
167
+ await database.delete({
168
+ model: "releases",
169
+ where: [{
170
+ field: "id",
171
+ value: change.where.id
172
+ }]
173
+ });
174
+ return;
175
+ }
176
+ case "releaseCatalogs":
177
+ if (await database.findOne({
178
+ model: "release_catalogs",
179
+ where: [{
180
+ field: "scope_key",
181
+ value: change.row.scope_key
182
+ }]
183
+ }) === null) await database.create({
184
+ model: "release_catalogs",
185
+ data: change.row
186
+ });
187
+ else {
188
+ const { scope_key: _scopeKey, ...update } = change.row;
189
+ await database.update({
190
+ model: "release_catalogs",
191
+ where: [{
192
+ field: "scope_key",
193
+ value: change.row.scope_key
194
+ }],
195
+ update
196
+ });
197
+ }
198
+ return;
199
+ case "bundlePatches": switch (change.operation) {
200
+ case "insert":
201
+ await database.create({
202
+ model: "bundle_patches",
203
+ data: change.row
204
+ });
205
+ return;
206
+ case "delete":
207
+ await database.delete({
208
+ model: "bundle_patches",
209
+ where: [{
210
+ field: "bundle_id",
211
+ value: change.where.bundleId
212
+ }]
213
+ });
214
+ return;
215
+ }
216
+ case "channels": switch (change.operation) {
217
+ case "insert":
218
+ await database.create({
219
+ model: "channels",
220
+ data: change.row,
221
+ onConflict: change.onConflict
222
+ });
223
+ return;
224
+ case "delete":
225
+ if (await database.count({
226
+ model: "releases",
227
+ where: [{
228
+ field: "channel_id",
229
+ value: change.where.id
230
+ }]
231
+ }) > 0) throw new DatabaseCommitConflictError({
232
+ committed: false,
233
+ conflict: {
234
+ changeIndex,
235
+ reason: "referenced"
236
+ }
237
+ });
238
+ try {
239
+ await database.delete({
240
+ model: "channels",
241
+ where: [{
242
+ field: "id",
243
+ value: change.where.id
244
+ }]
245
+ });
246
+ } catch (error) {
247
+ if (error instanceof DatabaseRowReferencedError) throw new DatabaseCommitConflictError({
248
+ committed: false,
249
+ conflict: {
250
+ changeIndex,
251
+ reason: "referenced"
252
+ }
253
+ });
254
+ throw error;
255
+ }
256
+ return;
257
+ }
258
+ case "analytics":
259
+ await database.create({
260
+ model: "bundle_events",
261
+ data: change.row
262
+ });
263
+ return;
264
+ case "apiKeys": switch (change.operation) {
265
+ case "insert":
266
+ await database.create({
267
+ model: "api_keys",
268
+ data: change.row,
269
+ onConflict: change.onConflict
270
+ });
271
+ return;
272
+ case "update":
273
+ if (await database.update({
274
+ model: "api_keys",
275
+ where: [{
276
+ field: "id",
277
+ value: change.where.id
278
+ }],
279
+ update: { revoked_at_ms: change.update.revokedAtMs }
280
+ }) === null) throw new DatabaseCommitConflictError({
281
+ committed: false,
282
+ conflict: {
283
+ changeIndex,
284
+ reason: "not_found"
285
+ }
286
+ });
287
+ return;
288
+ }
289
+ }
290
+ };
291
+ const expectationVersion = async (database, expectation) => {
292
+ if (expectation.model === "releases") return (await database.findOne({
293
+ model: "releases",
294
+ where: [{
295
+ field: "id",
296
+ value: expectation.id
297
+ }],
298
+ select: ["revision"]
299
+ }))?.revision ?? null;
300
+ return (await database.findOne({
301
+ model: "release_catalogs",
302
+ where: [{
303
+ field: "scope_key",
304
+ value: expectation.scopeKey
305
+ }],
306
+ select: ["generation"]
307
+ }))?.generation ?? null;
308
+ };
309
+ const applyExpectations = async (database, expectations) => {
310
+ for (const expectation of expectations) {
311
+ const expectedVersion = expectation.model === "releases" ? expectation.revision : expectation.generation;
312
+ const actualVersion = await expectationVersion(database, expectation);
313
+ if (actualVersion !== expectedVersion) throw new DatabaseCommitConflictError({
314
+ committed: false,
315
+ conflict: {
316
+ actualVersion,
317
+ changeIndex: -1,
318
+ expectedVersion,
319
+ key: expectation.model === "releases" ? expectation.id : expectation.scopeKey,
320
+ model: expectation.model,
321
+ reason: "version_conflict"
322
+ }
323
+ });
324
+ }
325
+ };
326
+ const applyChanges = async (database, input) => {
327
+ await applyExpectations(database, input.expectations ?? []);
328
+ for (const [changeIndex, change] of input.changes.entries()) await applyChange(database, change, changeIndex);
329
+ return { committed: true };
330
+ };
331
+ const hasOnlyKeys = (value, keys) => {
332
+ return Reflect.ownKeys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
333
+ };
334
+ const validateWhere = (where, field, validateValue = (value) => typeof value === "string") => {
335
+ if (!require_databasePluginCrudValidationFields.isRecord(where) || !hasOnlyKeys(where, [field]) || !validateValue(Reflect.get(where, field))) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
336
+ };
337
+ const validateDatabaseChange = (change) => {
338
+ if (!require_databasePluginCrudValidationFields.isRecord(change)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
339
+ switch (change.model) {
340
+ case "bundles": switch (change.operation) {
341
+ case "insert":
342
+ if (!hasOnlyKeys(change, [
343
+ "model",
344
+ "operation",
345
+ "row"
346
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
347
+ require_databasePluginCrudValidationRows.validateCreateData("bundles", change.row);
348
+ return;
349
+ case "update":
350
+ if (!hasOnlyKeys(change, [
351
+ "model",
352
+ "operation",
353
+ "where",
354
+ "update"
355
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
356
+ validateWhere(change.where, "id");
357
+ require_databasePluginCrudValidationMutations.validateBundleUpdateData(change.update);
358
+ return;
359
+ case "delete":
360
+ if (!hasOnlyKeys(change, [
361
+ "model",
362
+ "operation",
363
+ "where"
364
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
365
+ validateWhere(change.where, "id");
366
+ return;
367
+ default: throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
368
+ }
369
+ case "bundlePatches": switch (change.operation) {
370
+ case "insert":
371
+ if (!hasOnlyKeys(change, [
372
+ "model",
373
+ "operation",
374
+ "row"
375
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
376
+ require_databasePluginCrudValidationRows.validateCreateData("bundle_patches", change.row);
377
+ return;
378
+ case "delete":
379
+ if (!hasOnlyKeys(change, [
380
+ "model",
381
+ "operation",
382
+ "where"
383
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
384
+ validateWhere(change.where, "bundleId");
385
+ return;
386
+ default: throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
387
+ }
388
+ case "releases": switch (change.operation) {
389
+ case "insert":
390
+ if (!hasOnlyKeys(change, [
391
+ "model",
392
+ "operation",
393
+ "row"
394
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
395
+ require_databasePluginCrudValidationRows.validateCreateData("releases", change.row);
396
+ return;
397
+ case "update":
398
+ if (!hasOnlyKeys(change, [
399
+ "model",
400
+ "operation",
401
+ "where",
402
+ "update"
403
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
404
+ validateWhere(change.where, "id");
405
+ require_databasePluginCrudValidationMutations.validateReleaseUpdateData(change.update);
406
+ return;
407
+ case "delete":
408
+ if (!hasOnlyKeys(change, [
409
+ "model",
410
+ "operation",
411
+ "where"
412
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
413
+ validateWhere(change.where, "id");
414
+ return;
415
+ default: throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
416
+ }
417
+ case "releaseCatalogs":
418
+ if (change.operation !== "put" || !hasOnlyKeys(change, [
419
+ "model",
420
+ "operation",
421
+ "row"
422
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
423
+ require_databasePluginCrudValidationRows.validateCreateData("release_catalogs", change.row);
424
+ return;
425
+ case "channels": switch (change.operation) {
426
+ case "insert":
427
+ if (!hasOnlyKeys(change, [
428
+ "model",
429
+ "operation",
430
+ "row",
431
+ "onConflict"
432
+ ]) || change.onConflict !== "ignore") throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
433
+ require_databasePluginCrudValidationRows.validateCreateData("channels", change.row);
434
+ return;
435
+ case "delete":
436
+ if (!hasOnlyKeys(change, [
437
+ "model",
438
+ "operation",
439
+ "where"
440
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
441
+ validateWhere(change.where, "id", require_databasePluginCrudValidationFields.isChannelText);
442
+ return;
443
+ default: throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
444
+ }
445
+ case "analytics":
446
+ if (change.operation !== "insert" || !hasOnlyKeys(change, [
447
+ "model",
448
+ "operation",
449
+ "row"
450
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
451
+ require_databasePluginCrudValidationRows.validateCreateData("bundle_events", change.row);
452
+ return;
453
+ case "apiKeys": switch (change.operation) {
454
+ case "insert":
455
+ if (!hasOnlyKeys(change, [
456
+ "model",
457
+ "operation",
458
+ "row",
459
+ "onConflict"
460
+ ]) || change.onConflict !== "ignore") throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
461
+ require_databasePluginCrudValidationRows.validateCreateData("api_keys", change.row);
462
+ return;
463
+ case "update":
464
+ if (!hasOnlyKeys(change, [
465
+ "model",
466
+ "operation",
467
+ "where",
468
+ "update"
469
+ ])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
470
+ validateWhere(change.where, "id");
471
+ if (!require_databasePluginCrudValidationFields.isRecord(change.update)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
472
+ if (!hasOnlyKeys(change.update, ["revokedAtMs"])) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
473
+ require_databasePluginCrudValidationMutations.validateApiKeyUpdateData({ revoked_at_ms: change.update.revokedAtMs });
474
+ return;
475
+ default: throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
476
+ }
477
+ default: throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-model");
478
+ }
479
+ };
480
+ const validateDatabaseCommitExpectation = (expectation) => {
481
+ if (!require_databasePluginCrudValidationFields.isRecord(expectation)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
482
+ if (expectation.model === "releases") {
483
+ if (!hasOnlyKeys(expectation, [
484
+ "model",
485
+ "id",
486
+ "revision"
487
+ ]) || typeof expectation.id !== "string" || !(expectation.revision === null || typeof expectation.revision === "number" && Number.isSafeInteger(expectation.revision) && expectation.revision >= 1)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
488
+ return;
489
+ }
490
+ if (expectation.model === "releaseCatalogs") {
491
+ if (!hasOnlyKeys(expectation, [
492
+ "model",
493
+ "scopeKey",
494
+ "generation"
495
+ ]) || typeof expectation.scopeKey !== "string" || !(expectation.generation === null || typeof expectation.generation === "number" && Number.isSafeInteger(expectation.generation) && expectation.generation >= 1)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
496
+ return;
497
+ }
498
+ throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-model");
499
+ };
500
+ function validateDatabaseCommit(input) {
501
+ if (!require_databasePluginCrudValidationFields.isRecord(input) || !Array.isArray(input.changes) || (Object.hasOwn(input, "expectations") ? !hasOnlyKeys(input, ["changes", "expectations"]) || !Array.isArray(input.expectations) : !hasOnlyKeys(input, ["changes"]))) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
502
+ input.changes.forEach(validateDatabaseChange);
503
+ if (Array.isArray(input.expectations)) input.expectations.forEach(validateDatabaseCommitExpectation);
56
504
  }
57
- function createPaginatedResult(total, limit, startIndex, data) {
58
- const pagination = require_calculatePagination.calculatePagination(total, {
59
- limit,
60
- offset: startIndex
61
- });
62
- const nextCursor = data.length > 0 && startIndex + data.length < total ? data.at(-1)?.id : void 0;
63
- const previousCursor = data.length > 0 && startIndex > 0 ? data[0]?.id : void 0;
64
- return {
65
- data,
66
- pagination: {
67
- ...pagination,
68
- ...nextCursor ? { nextCursor } : {},
69
- ...previousCursor ? { previousCursor } : {}
505
+ const validateChannelInsertResult = (input, result) => {
506
+ require_databasePluginCrudValidationRows.validateResult("channels", result.row, void 0);
507
+ if (typeof result.inserted !== "boolean" || result.row.name !== input.row.name || result.inserted && result.row.id !== input.row.id) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-result");
508
+ };
509
+ const validateChannelDeleteResult = (result) => {
510
+ if (result.deleted) return;
511
+ if (result.reason !== "not_found" && result.reason !== "not_empty") throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-result");
512
+ };
513
+ const createDatabasePluginAdapter = (name, implementation) => {
514
+ const crud = require_databasePluginCrud.createDatabasePluginCrud(implementation);
515
+ const transaction = implementation.transaction;
516
+ const executeCommit = implementation.commit ? implementation.commit : async (input) => {
517
+ if (transaction) try {
518
+ return await transaction((database) => applyChanges(require_databasePluginTransaction.createTransactionDatabasePlugin(database), input));
519
+ } catch (error) {
520
+ if (error instanceof DatabaseCommitConflictError) return error.result;
521
+ throw error;
522
+ }
523
+ if ((input.expectations?.length ?? 0) > 0 || input.changes.length > 1 || input.changes.some((change) => change.model === "channels" && change.operation === "delete")) throw new DatabaseAtomicCommitUnsupportedError(name);
524
+ try {
525
+ return await applyChanges(crud, input);
526
+ } catch (error) {
527
+ if (error instanceof DatabaseCommitConflictError) return error.result;
528
+ throw error;
70
529
  }
71
530
  };
72
- }
73
- function expandLimitForUnitOfWork(options, unitOfWork) {
74
- const extraLimit = unitOfWork.listFetchExtraCount();
75
- if (extraLimit === 0) return options;
76
- return {
77
- ...options,
78
- limit: options.limit + extraLimit
531
+ const commit = async (input) => {
532
+ validateDatabaseCommit(input);
533
+ return executeCommit(input);
79
534
  };
80
- }
81
- function adjustPaginationTotal(pagination, options) {
82
- if (options.totalDelta === 0) return pagination;
83
- const total = Math.max(0, pagination.total + options.totalDelta);
84
- const hasPreviousPage = pagination.currentPage > 1;
85
- const hasNextPage = pagination.currentPage * options.limit < total;
535
+ const findApiKeyByHash = (database, hash) => database.findOne({
536
+ model: "api_keys",
537
+ where: [{
538
+ field: "hash",
539
+ value: hash
540
+ }]
541
+ });
86
542
  return {
87
- ...pagination,
88
- total,
89
- hasNextPage,
90
- hasPreviousPage,
91
- totalPages: total === 0 ? 0 : Math.ceil(total / options.limit)
92
- };
93
- }
94
- /**
95
- * Creates a database plugin with lazy initialization and automatic hook execution.
96
- *
97
- * This factory function abstracts the double currying pattern used by all database plugins,
98
- * ensuring consistent lazy initialization behavior across different database providers.
99
- * Hooks are automatically executed at appropriate times without requiring manual invocation.
100
- *
101
- * @param options - Configuration options for the database plugin
102
- * @returns A double-curried function that lazily initializes the database plugin
103
- *
104
- * @example
105
- * ```typescript
106
- * export const postgres = createDatabasePlugin<PostgresConfig>({
107
- * name: "postgres",
108
- * factory: (config) => {
109
- * const db = new Kysely(config);
110
- * return {
111
- * async getBundleById(bundleId) { ... },
112
- * async getBundles(options) { ... },
113
- * async getChannels() { ... },
114
- * async commitBundle({ changedSets }) { ... }
115
- * };
116
- * }
117
- * });
118
- * ```
119
- */
120
- function createDatabasePlugin(options) {
121
- return (config, hooks) => {
122
- let cachedMethods = null;
123
- const getMethods = () => {
124
- if (!cachedMethods) cachedMethods = options.factory(config);
125
- return cachedMethods;
126
- };
127
- return () => {
128
- const instanceMutationUnitOfWork = new require_bundleUnitOfWork.BundleUnitOfWork();
129
- const getRequestUnitOfWork = (context) => {
130
- return require_bundleUnitOfWorkStore.getRequestBundleUnitOfWork(context);
131
- };
132
- const getMutationUnitOfWork = (context) => {
133
- return getRequestUnitOfWork(context) ?? instanceMutationUnitOfWork;
134
- };
135
- const runGetBundles = async (options, context) => {
136
- if (context === void 0) return getMethods().getBundles(options);
137
- return getMethods().getBundles(options, context);
138
- };
139
- const getBundlesWithLegacyCursorFallback = async (options, context) => {
140
- const orderBy = options.orderBy ?? DEFAULT_DESC_ORDER;
141
- const baseWhere = options.where;
142
- const total = (await runGetBundles({
143
- where: baseWhere,
144
- limit: 1,
145
- offset: 0,
146
- orderBy
147
- }, context)).pagination.total;
148
- if (!options.cursor?.after && !options.cursor?.before) {
149
- const firstPage = await runGetBundles({
150
- where: baseWhere,
151
- limit: options.limit,
543
+ models: {
544
+ bundles: {
545
+ findById: (id) => crud.findOne({
546
+ model: "bundles",
547
+ where: [{
548
+ field: "id",
549
+ value: id
550
+ }]
551
+ }),
552
+ findMany: (query) => crud.findMany({
553
+ model: "bundles",
554
+ where: toBundleWhere(query.where),
555
+ limit: query.limit,
556
+ offset: query.offset,
557
+ orderBy: [query.orderBy]
558
+ }),
559
+ count: (where) => crud.count({
560
+ model: "bundles",
561
+ where: toBundleWhere(where)
562
+ })
563
+ },
564
+ bundlePatches: { async findByBundleIds(bundleIds) {
565
+ if (bundleIds.length === 0) return [];
566
+ const rows = [];
567
+ for (let offset = 0;; offset += PAGE_SIZE) {
568
+ const page = await crud.findMany({
569
+ model: "bundle_patches",
570
+ where: [{
571
+ field: "bundle_id",
572
+ operator: "in",
573
+ value: bundleIds
574
+ }],
575
+ limit: PAGE_SIZE,
576
+ offset,
577
+ orderBy: [{
578
+ field: "id",
579
+ direction: "asc"
580
+ }]
581
+ });
582
+ rows.push(...page);
583
+ if (page.length < PAGE_SIZE) return rows;
584
+ }
585
+ } },
586
+ releases: {
587
+ findById: (id) => crud.findOne({
588
+ model: "releases",
589
+ where: [{
590
+ field: "id",
591
+ value: id
592
+ }]
593
+ }),
594
+ findMany(input) {
595
+ if (!Number.isSafeInteger(input.limit) || input.limit <= 0 || input.afterReleaseId !== void 0 && input.beforeReleaseId !== void 0) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-query");
596
+ const query = crud.findMany({
597
+ model: "releases",
598
+ where: [
599
+ ...input.afterReleaseId === void 0 ? [] : [{
600
+ field: "id",
601
+ operator: "gt",
602
+ value: input.afterReleaseId
603
+ }],
604
+ ...input.beforeReleaseId === void 0 ? [] : [{
605
+ field: "id",
606
+ operator: "lt",
607
+ value: input.beforeReleaseId
608
+ }],
609
+ ...input.bundleId === void 0 ? [] : [{
610
+ field: "bundle_id",
611
+ value: input.bundleId
612
+ }],
613
+ ...input.channelId === void 0 ? [] : [{
614
+ field: "channel_id",
615
+ value: input.channelId
616
+ }],
617
+ ...input.enabled === void 0 ? [] : [{
618
+ field: "enabled",
619
+ value: input.enabled
620
+ }],
621
+ ...input.platform === void 0 ? [] : [{
622
+ field: "platform",
623
+ value: input.platform
624
+ }],
625
+ ...input.targetAppVersion === void 0 ? [] : [{
626
+ field: "target_app_version",
627
+ value: input.targetAppVersion
628
+ }]
629
+ ],
630
+ limit: input.limit,
152
631
  offset: 0,
153
- orderBy
154
- }, context);
155
- return createPaginatedResult(total, options.limit, 0, firstPage.data);
632
+ orderBy: [{
633
+ field: "id",
634
+ direction: input.afterReleaseId === void 0 ? "desc" : "asc"
635
+ }]
636
+ });
637
+ return input.afterReleaseId === void 0 ? query : query.then((rows) => [...rows].reverse());
638
+ },
639
+ findManyByScope(input) {
640
+ if (input.consistency !== "strong" || !Number.isSafeInteger(input.limit) || input.limit <= 0) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-query");
641
+ return crud.findMany({
642
+ model: "releases",
643
+ where: [{
644
+ field: "scope_key",
645
+ value: input.scopeKey
646
+ }, ...input.afterReleaseId === void 0 ? [] : [{
647
+ field: "id",
648
+ operator: "gt",
649
+ value: input.afterReleaseId
650
+ }]],
651
+ limit: input.limit,
652
+ offset: 0,
653
+ orderBy: [{
654
+ field: "id",
655
+ direction: "asc"
656
+ }]
657
+ });
156
658
  }
157
- const { where, orderBy: queryOrderBy, reverseData } = buildCursorPageQuery(baseWhere, options.cursor, orderBy);
158
- const cursorPage = await runGetBundles({
159
- where,
160
- limit: options.limit,
161
- offset: 0,
162
- orderBy: queryOrderBy
163
- }, context);
164
- const data = reverseData ? cursorPage.data.slice().reverse() : cursorPage.data;
165
- if (data.length === 0) {
166
- const emptyStartIndex = options.cursor.after ? total : 0;
167
- return {
168
- data,
169
- pagination: {
170
- ...require_calculatePagination.calculatePagination(total, {
171
- limit: options.limit,
172
- offset: emptyStartIndex
173
- }),
174
- ...options.cursor.after ? { previousCursor: options.cursor.after } : {},
175
- ...options.cursor.before ? { nextCursor: options.cursor.before } : {}
176
- }
177
- };
659
+ },
660
+ releaseCatalogs: {
661
+ findByScopeKey: (scopeKey) => crud.findOne({
662
+ model: "release_catalogs",
663
+ where: [{
664
+ field: "scope_key",
665
+ value: scopeKey
666
+ }]
667
+ }),
668
+ findMany(input) {
669
+ if (!Number.isSafeInteger(input.limit) || input.limit <= 0) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-query");
670
+ return crud.findMany({
671
+ model: "release_catalogs",
672
+ where: input.afterScopeKey === void 0 ? [] : [{
673
+ field: "scope_key",
674
+ operator: "gt",
675
+ value: input.afterScopeKey
676
+ }],
677
+ limit: input.limit,
678
+ offset: 0,
679
+ orderBy: [{
680
+ field: "scope_key",
681
+ direction: "asc"
682
+ }]
683
+ });
178
684
  }
179
- const firstBundleId = data[0].id;
180
- const countBeforeResult = await runGetBundles({
181
- where: buildCountBeforeWhere(baseWhere, firstBundleId, orderBy),
182
- limit: 1,
183
- offset: 0,
184
- orderBy
185
- }, context);
186
- return createPaginatedResult(total, options.limit, countBeforeResult.pagination.total, data);
187
- };
188
- const plugin = {
189
- name: options.name,
190
- async getBundleById(bundleId, context) {
191
- const requestUnitOfWork = getRequestUnitOfWork(context);
192
- if (requestUnitOfWork) return requestUnitOfWork.getById(bundleId, () => getMethods().getBundleById(bundleId, context));
193
- const pendingMutation = instanceMutationUnitOfWork.peekChanged(bundleId);
194
- if (pendingMutation.found) return pendingMutation.value;
195
- return getMethods().getBundleById(bundleId);
685
+ },
686
+ channels: {
687
+ async insert(input) {
688
+ if (input.onConflict !== "returnExisting") throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-operation");
689
+ require_databasePluginCrudValidationRows.validateCreateData("channels", input.row);
690
+ const result = await implementation.insertChannel(input);
691
+ validateChannelInsertResult(input, result);
692
+ return result;
196
693
  },
197
- async getBundles(options, context) {
198
- if (typeof options === "object" && options !== null && "offset" in options && options.offset !== void 0) throw new Error("Bundle offset pagination has been removed. Use cursor.after or cursor.before instead.");
199
- const methods = getMethods();
200
- const requestUnitOfWork = getRequestUnitOfWork(context);
201
- const unitOfWork = requestUnitOfWork ?? instanceMutationUnitOfWork;
202
- const shouldOverlay = requestUnitOfWork !== null || instanceMutationUnitOfWork.hasChanges();
203
- const normalizedOptions = {
204
- ...options,
205
- page: normalizePage(options.page),
206
- orderBy: options.orderBy ?? DEFAULT_DESC_ORDER
207
- };
208
- const overlayResult = (result) => ({
209
- ...result,
210
- data: unitOfWork.overlayList(result.data, {
211
- limit: normalizedOptions.limit,
212
- orderBy: normalizedOptions.orderBy,
213
- where: normalizedOptions.where
214
- }),
215
- pagination: adjustPaginationTotal(result.pagination, {
216
- limit: normalizedOptions.limit,
217
- totalDelta: unitOfWork.totalDelta(normalizedOptions.where)
218
- })
219
- });
220
- if (normalizedOptions.page !== void 0) {
221
- const { page, ...pageOptions } = normalizedOptions;
222
- const requestedOffset = (page - 1) * normalizedOptions.limit;
223
- const fetchPageOptions = expandLimitForUnitOfWork(pageOptions, unitOfWork);
224
- let pageResult = await runGetBundles({
225
- ...fetchPageOptions,
226
- offset: requestedOffset
227
- }, context);
228
- const total = pageResult.pagination.total;
229
- const totalPages = total === 0 ? 0 : Math.ceil(total / normalizedOptions.limit);
230
- const maxOffset = totalPages === 0 ? 0 : (Math.max(1, totalPages) - 1) * normalizedOptions.limit;
231
- const resolvedOffset = Math.min(requestedOffset, maxOffset);
232
- if (resolvedOffset !== requestedOffset) pageResult = await runGetBundles({
233
- ...fetchPageOptions,
234
- offset: resolvedOffset
235
- }, context);
236
- const result = { ...createPaginatedResult(total, normalizedOptions.limit, resolvedOffset, pageResult.data) };
237
- return shouldOverlay ? overlayResult(result) : result;
238
- }
239
- if (methods.supportsCursorPagination) {
240
- const fetchOptions = expandLimitForUnitOfWork(normalizedOptions, unitOfWork);
241
- const result = context === void 0 ? await methods.getBundles(fetchOptions) : await methods.getBundles(fetchOptions, context);
242
- return shouldOverlay ? overlayResult(result) : result;
694
+ async list(_input) {
695
+ const channels = [];
696
+ for (let offset = 0;; offset += PAGE_SIZE) {
697
+ const page = await crud.findMany({
698
+ model: "channels",
699
+ orderBy: [{
700
+ field: "name",
701
+ direction: "asc"
702
+ }],
703
+ limit: PAGE_SIZE,
704
+ offset
705
+ });
706
+ channels.push(...page);
707
+ if (page.length < PAGE_SIZE) {
708
+ channels.sort(compareChannelRows);
709
+ return { channels };
710
+ }
243
711
  }
244
- const result = await getBundlesWithLegacyCursorFallback(shouldOverlay ? expandLimitForUnitOfWork(normalizedOptions, unitOfWork) : normalizedOptions, context);
245
- return shouldOverlay ? overlayResult(result) : result;
246
- },
247
- async getChannels(context) {
248
- if (context === void 0) return getMethods().getChannels();
249
- return getMethods().getChannels(context);
250
712
  },
251
- async onUnmount() {
252
- const methods = getMethods();
253
- if (methods.onUnmount) return methods.onUnmount();
254
- },
255
- async commitBundle(context) {
256
- const methods = getMethods();
257
- const unitOfWork = getMutationUnitOfWork(context);
258
- const params = { changedSets: unitOfWork.changedSets() };
259
- if (context === void 0) await methods.commitBundle(params);
260
- else await methods.commitBundle(params, context);
261
- unitOfWork.clear();
262
- await hooks?.onDatabaseUpdated?.();
263
- },
264
- async updateBundle(targetBundleId, newBundle, context) {
265
- const unitOfWork = getMutationUnitOfWork(context);
266
- const currentBundle = await unitOfWork.getById(targetBundleId, () => context === void 0 ? getMethods().getBundleById(targetBundleId) : getMethods().getBundleById(targetBundleId, context));
267
- if (!currentBundle) throw new Error("targetBundleId not found");
268
- const updatedBundle = mergeBundleUpdate(currentBundle, newBundle);
269
- unitOfWork.markUpdate(updatedBundle);
270
- },
271
- async appendBundle(inputBundle, context) {
272
- getMutationUnitOfWork(context).markInsert(inputBundle);
273
- },
274
- async deleteBundle(deleteBundle, context) {
275
- getMutationUnitOfWork(context).markDelete(deleteBundle);
713
+ async delete(input) {
714
+ if (!require_databasePluginCrudValidationFields.isChannelText(input.id)) throw new require_databasePluginCrudValidationErrors.DatabasePluginInputError("invalid-data");
715
+ const result = await implementation.deleteChannel(input);
716
+ validateChannelDeleteResult(result);
717
+ return result;
276
718
  }
277
- };
278
- Object.defineProperty(plugin, "getUpdateInfo", {
279
- configurable: true,
280
- enumerable: true,
281
- get() {
282
- const directGetUpdateInfo = getMethods().getUpdateInfo;
283
- if (!directGetUpdateInfo) {
284
- Object.defineProperty(plugin, "getUpdateInfo", {
285
- configurable: true,
286
- enumerable: true,
287
- value: void 0
719
+ },
720
+ analytics: {
721
+ async append(row) {
722
+ await crud.create({
723
+ model: "bundle_events",
724
+ data: row
725
+ });
726
+ },
727
+ async scan(input) {
728
+ const rows = [];
729
+ for (let offset = 0; rows.length < input.limit; offset += PAGE_SIZE) {
730
+ const page = await crud.findMany({
731
+ model: "bundle_events",
732
+ where: [{
733
+ field: "received_at_ms",
734
+ operator: "lt",
735
+ value: input.beforeReceivedAtMs
736
+ }],
737
+ orderBy: [{
738
+ field: "received_at_ms",
739
+ direction: "asc"
740
+ }, {
741
+ field: "id",
742
+ direction: "asc"
743
+ }],
744
+ limit: PAGE_SIZE,
745
+ offset
288
746
  });
289
- return;
747
+ rows.push(...page.filter((row) => input.after === void 0 || row.received_at_ms > input.after.receivedAtMs || row.received_at_ms === input.after.receivedAtMs && row.id > input.after.id));
748
+ if (page.length < PAGE_SIZE) break;
290
749
  }
291
- const wrappedGetUpdateInfo = async (args, context) => {
292
- if (context === void 0) return directGetUpdateInfo(args);
293
- return directGetUpdateInfo(args, context);
750
+ return rows.slice(0, input.limit);
751
+ }
752
+ },
753
+ apiKeys: {
754
+ async create(row) {
755
+ const run = async (database) => {
756
+ if (await findApiKeyByHash(database, row.hash) !== null) return "existing";
757
+ await database.create({
758
+ model: "api_keys",
759
+ data: row
760
+ });
761
+ return "created";
294
762
  };
295
- Object.defineProperty(plugin, "getUpdateInfo", {
296
- configurable: true,
297
- enumerable: true,
298
- value: wrappedGetUpdateInfo
763
+ return transaction ? transaction((database) => run(require_databasePluginTransaction.createTransactionDatabasePlugin(database))) : run(crud);
764
+ },
765
+ findByHash: (hash) => findApiKeyByHash(crud, hash),
766
+ list: () => crud.findMany({
767
+ model: "api_keys",
768
+ orderBy: [{
769
+ field: "created_at_ms",
770
+ direction: "desc"
771
+ }, {
772
+ field: "id",
773
+ direction: "asc"
774
+ }],
775
+ limit: Number.MAX_SAFE_INTEGER,
776
+ offset: 0
777
+ }),
778
+ async revoke({ id, revokedAtMs }) {
779
+ return crud.update({
780
+ model: "api_keys",
781
+ where: [{
782
+ field: "id",
783
+ value: id
784
+ }],
785
+ update: { revoked_at_ms: revokedAtMs }
299
786
  });
300
- return wrappedGetUpdateInfo;
301
787
  }
302
- });
303
- return plugin;
304
- };
788
+ }
789
+ },
790
+ commit,
791
+ ...implementation.dispose ? { dispose: implementation.dispose } : {}
305
792
  };
306
- }
793
+ };
794
+ const createDatabasePlugin = (options) => ({ ...options });
307
795
  //#endregion
796
+ exports.DatabaseAtomicCommitUnsupportedError = DatabaseAtomicCommitUnsupportedError;
797
+ exports.DatabaseRowReferencedError = DatabaseRowReferencedError;
308
798
  exports.createDatabasePlugin = createDatabasePlugin;
799
+ exports.createDatabasePluginAdapter = createDatabasePluginAdapter;