@hot-updater/server 0.29.4 → 0.29.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db/ormCore.cjs +105 -23
- package/dist/db/ormCore.mjs +105 -23
- package/dist/db/pluginCore.cjs +7 -4
- package/dist/db/pluginCore.mjs +7 -4
- package/dist/handler.cjs +13 -3
- package/dist/handler.mjs +13 -3
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.mts +2 -0
- package/package.json +6 -6
- package/src/db/ormCore.ts +194 -38
- package/src/db/pluginCore.spec.ts +172 -0
- package/src/db/pluginCore.ts +20 -3
- package/src/db/pluginUpdateCheck.bench.ts +10 -10
- package/src/handler-standalone.integration.spec.ts +1 -2
- package/src/handler.spec.ts +152 -2
- package/src/handler.ts +30 -2
- package/src/runtime.spec.ts +105 -0
- package/src/types/index.ts +2 -0
package/src/db/ormCore.ts
CHANGED
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
NIL_UUID,
|
|
14
14
|
} from "@hot-updater/core";
|
|
15
15
|
import type {
|
|
16
|
+
DatabaseBundleCursor,
|
|
17
|
+
DatabaseBundleIdFilter,
|
|
18
|
+
DatabaseBundleQueryOrder,
|
|
16
19
|
DatabaseBundleQueryOptions,
|
|
17
20
|
DatabaseBundleQueryWhere,
|
|
18
21
|
HotUpdaterContext,
|
|
@@ -53,6 +56,74 @@ const getLastItem = <T extends unknown[]>(
|
|
|
53
56
|
): T extends [...infer _, infer Last] ? Last : never =>
|
|
54
57
|
items.at(-1) as T extends [...infer _, infer Last] ? Last : never;
|
|
55
58
|
|
|
59
|
+
const DEFAULT_BUNDLE_ORDER = { field: "id", direction: "desc" } as const;
|
|
60
|
+
|
|
61
|
+
const mergeIdFilter = (
|
|
62
|
+
base: DatabaseBundleIdFilter | undefined,
|
|
63
|
+
patch: DatabaseBundleIdFilter,
|
|
64
|
+
): DatabaseBundleIdFilter => ({
|
|
65
|
+
...base,
|
|
66
|
+
...patch,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const mergeWhereWithIdFilter = (
|
|
70
|
+
where: DatabaseBundleQueryWhere | undefined,
|
|
71
|
+
idFilter: DatabaseBundleIdFilter,
|
|
72
|
+
): DatabaseBundleQueryWhere => ({
|
|
73
|
+
...where,
|
|
74
|
+
id: mergeIdFilter(where?.id, idFilter),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const buildCursorPageWhere = (
|
|
78
|
+
where: DatabaseBundleQueryWhere | undefined,
|
|
79
|
+
cursor: DatabaseBundleCursor,
|
|
80
|
+
orderBy: DatabaseBundleQueryOrder,
|
|
81
|
+
): {
|
|
82
|
+
reverseData: boolean;
|
|
83
|
+
where: DatabaseBundleQueryWhere;
|
|
84
|
+
orderBy: DatabaseBundleQueryOrder;
|
|
85
|
+
} => {
|
|
86
|
+
const direction = orderBy.direction;
|
|
87
|
+
|
|
88
|
+
if (cursor.after) {
|
|
89
|
+
return {
|
|
90
|
+
reverseData: false,
|
|
91
|
+
where: mergeWhereWithIdFilter(where, {
|
|
92
|
+
[direction === "desc" ? "lt" : "gt"]: cursor.after,
|
|
93
|
+
}),
|
|
94
|
+
orderBy,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (cursor.before) {
|
|
99
|
+
return {
|
|
100
|
+
reverseData: true,
|
|
101
|
+
where: mergeWhereWithIdFilter(where, {
|
|
102
|
+
[direction === "desc" ? "gt" : "lt"]: cursor.before,
|
|
103
|
+
}),
|
|
104
|
+
orderBy: {
|
|
105
|
+
field: orderBy.field,
|
|
106
|
+
direction: direction === "desc" ? "asc" : "desc",
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
reverseData: false,
|
|
113
|
+
where: where ?? {},
|
|
114
|
+
orderBy,
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const buildCountBeforeWhere = (
|
|
119
|
+
where: DatabaseBundleQueryWhere | undefined,
|
|
120
|
+
firstBundleId: string,
|
|
121
|
+
orderBy: DatabaseBundleQueryOrder,
|
|
122
|
+
): DatabaseBundleQueryWhere =>
|
|
123
|
+
mergeWhereWithIdFilter(where, {
|
|
124
|
+
[orderBy.direction === "desc" ? "gt" : "lt"]: firstBundleId,
|
|
125
|
+
});
|
|
126
|
+
|
|
56
127
|
export const HotUpdaterDB = fumadb({
|
|
57
128
|
namespace: "hot_updater",
|
|
58
129
|
schemas,
|
|
@@ -511,7 +582,12 @@ export function createOrmDatabaseCore<TContext = unknown>({
|
|
|
511
582
|
options: DatabaseBundleQueryOptions,
|
|
512
583
|
): Promise<Paginated<Bundle[]>> {
|
|
513
584
|
const orm = await ensureORM();
|
|
514
|
-
const { where, limit
|
|
585
|
+
const { where, limit } = options;
|
|
586
|
+
const orderBy = options.orderBy ?? DEFAULT_BUNDLE_ORDER;
|
|
587
|
+
const offset =
|
|
588
|
+
(("offset" in options ? options.offset : undefined) as
|
|
589
|
+
| number
|
|
590
|
+
| undefined) ?? 0;
|
|
515
591
|
|
|
516
592
|
const total = await orm.count("bundles", {
|
|
517
593
|
where: buildBundleWhere(where),
|
|
@@ -549,49 +625,129 @@ export function createOrmDatabaseCore<TContext = unknown>({
|
|
|
549
625
|
"target_cohorts",
|
|
550
626
|
];
|
|
551
627
|
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
628
|
+
const mapRowsToBundles = (rows: any[]): Bundle[] =>
|
|
629
|
+
rows.map(
|
|
630
|
+
(r): Bundle => ({
|
|
631
|
+
id: r.id,
|
|
632
|
+
platform: r.platform as Platform,
|
|
633
|
+
shouldForceUpdate: Boolean(r.should_force_update),
|
|
634
|
+
enabled: Boolean(r.enabled),
|
|
635
|
+
fileHash: r.file_hash,
|
|
636
|
+
gitCommitHash: r.git_commit_hash ?? null,
|
|
637
|
+
message: r.message ?? null,
|
|
638
|
+
channel: r.channel,
|
|
639
|
+
storageUri: r.storage_uri,
|
|
640
|
+
targetAppVersion: r.target_app_version ?? null,
|
|
641
|
+
fingerprintHash: r.fingerprint_hash ?? null,
|
|
642
|
+
rolloutCohortCount:
|
|
643
|
+
r.rollout_cohort_count ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
644
|
+
targetCohorts: parseTargetCohorts(r.target_cohorts),
|
|
645
|
+
}),
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
const findBundles = async ({
|
|
649
|
+
where,
|
|
650
|
+
orderBy,
|
|
651
|
+
limit,
|
|
652
|
+
offset,
|
|
653
|
+
}: {
|
|
654
|
+
where?: DatabaseBundleQueryWhere;
|
|
655
|
+
orderBy: DatabaseBundleQueryOrder;
|
|
656
|
+
limit: number;
|
|
657
|
+
offset: number;
|
|
658
|
+
}) => {
|
|
659
|
+
const rows = isMongoAdapter
|
|
660
|
+
? (
|
|
661
|
+
await orm.findMany("bundles", {
|
|
662
|
+
select: selectedColumns,
|
|
663
|
+
where: buildBundleWhere(where),
|
|
664
|
+
})
|
|
665
|
+
)
|
|
666
|
+
.sort((a, b) => {
|
|
667
|
+
const result = a.id.localeCompare(b.id);
|
|
668
|
+
return orderBy.direction === "asc" ? result : -result;
|
|
669
|
+
})
|
|
670
|
+
.slice(offset, offset + limit)
|
|
671
|
+
: await orm.findMany("bundles", {
|
|
555
672
|
select: selectedColumns,
|
|
556
673
|
where: buildBundleWhere(where),
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const result = a.id.localeCompare(b.id);
|
|
562
|
-
return direction === "asc" ? result : -result;
|
|
563
|
-
})
|
|
564
|
-
.slice(offset, offset + limit)
|
|
565
|
-
: await orm.findMany("bundles", {
|
|
566
|
-
select: selectedColumns,
|
|
567
|
-
where: buildBundleWhere(where),
|
|
568
|
-
orderBy: [[orderBy?.field ?? "id", orderBy?.direction ?? "desc"]],
|
|
569
|
-
limit,
|
|
570
|
-
offset,
|
|
571
|
-
});
|
|
674
|
+
orderBy: [[orderBy.field, orderBy.direction]],
|
|
675
|
+
limit,
|
|
676
|
+
offset,
|
|
677
|
+
});
|
|
572
678
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
679
|
+
return mapRowsToBundles(rows);
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
if (!options.cursor?.after && !options.cursor?.before) {
|
|
683
|
+
const data = await findBundles({
|
|
684
|
+
where,
|
|
685
|
+
orderBy,
|
|
686
|
+
limit,
|
|
687
|
+
offset,
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
return {
|
|
691
|
+
data,
|
|
692
|
+
pagination: {
|
|
693
|
+
...calculatePagination(total, { limit, offset }),
|
|
694
|
+
...(data.length > 0 && offset + data.length < total
|
|
695
|
+
? { nextCursor: data.at(-1)?.id }
|
|
696
|
+
: {}),
|
|
697
|
+
...(data.length > 0 && offset > 0
|
|
698
|
+
? { previousCursor: data[0]?.id }
|
|
699
|
+
: {}),
|
|
700
|
+
},
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const {
|
|
705
|
+
where: cursorWhere,
|
|
706
|
+
orderBy: cursorOrderBy,
|
|
707
|
+
reverseData,
|
|
708
|
+
} = buildCursorPageWhere(where, options.cursor, orderBy);
|
|
709
|
+
const cursorPage = await findBundles({
|
|
710
|
+
where: cursorWhere,
|
|
711
|
+
orderBy: cursorOrderBy,
|
|
712
|
+
limit,
|
|
713
|
+
offset: 0,
|
|
714
|
+
});
|
|
715
|
+
const data = reverseData ? cursorPage.slice().reverse() : cursorPage;
|
|
716
|
+
|
|
717
|
+
if (data.length === 0) {
|
|
718
|
+
const emptyStartIndex = options.cursor.after ? total : 0;
|
|
719
|
+
return {
|
|
720
|
+
data,
|
|
721
|
+
pagination: {
|
|
722
|
+
...calculatePagination(total, {
|
|
723
|
+
limit,
|
|
724
|
+
offset: emptyStartIndex,
|
|
725
|
+
}),
|
|
726
|
+
...(options.cursor.after
|
|
727
|
+
? { previousCursor: options.cursor.after }
|
|
728
|
+
: {}),
|
|
729
|
+
...(options.cursor.before
|
|
730
|
+
? { nextCursor: options.cursor.before }
|
|
731
|
+
: {}),
|
|
732
|
+
},
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const startIndex = await orm.count("bundles", {
|
|
737
|
+
where: buildBundleWhere(
|
|
738
|
+
buildCountBeforeWhere(where, data[0]!.id, orderBy),
|
|
739
|
+
),
|
|
740
|
+
});
|
|
591
741
|
|
|
592
742
|
return {
|
|
593
743
|
data,
|
|
594
|
-
pagination:
|
|
744
|
+
pagination: {
|
|
745
|
+
...calculatePagination(total, { limit, offset: startIndex }),
|
|
746
|
+
...(startIndex + data.length < total
|
|
747
|
+
? { nextCursor: data.at(-1)?.id }
|
|
748
|
+
: {}),
|
|
749
|
+
...(startIndex > 0 ? { previousCursor: data[0]?.id } : {}),
|
|
750
|
+
},
|
|
595
751
|
};
|
|
596
752
|
},
|
|
597
753
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Bundle, GetBundlesArgs, UpdateInfo } from "@hot-updater/core";
|
|
2
|
+
import { NIL_UUID } from "@hot-updater/core";
|
|
3
|
+
import type {
|
|
4
|
+
DatabasePlugin,
|
|
5
|
+
RequestEnvContext,
|
|
6
|
+
} from "@hot-updater/plugin-core";
|
|
7
|
+
import { describe, expect, it, vi } from "vitest";
|
|
8
|
+
|
|
9
|
+
import { createPluginDatabaseCore } from "./pluginCore";
|
|
10
|
+
|
|
11
|
+
const baseBundle: Bundle = {
|
|
12
|
+
id: "00000000-0000-0000-0000-000000000001",
|
|
13
|
+
channel: "production",
|
|
14
|
+
enabled: true,
|
|
15
|
+
fileHash: "hash-1",
|
|
16
|
+
fingerprintHash: null,
|
|
17
|
+
gitCommitHash: null,
|
|
18
|
+
message: "bundle",
|
|
19
|
+
platform: "ios",
|
|
20
|
+
shouldForceUpdate: false,
|
|
21
|
+
storageUri: "s3://bucket/bundle.zip",
|
|
22
|
+
targetAppVersion: "1.0.0",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const updateArgs: GetBundlesArgs = {
|
|
26
|
+
_updateStrategy: "appVersion",
|
|
27
|
+
appVersion: "1.0.0",
|
|
28
|
+
bundleId: NIL_UUID,
|
|
29
|
+
platform: "ios",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type TestContext = RequestEnvContext<{
|
|
33
|
+
assetHost: string;
|
|
34
|
+
}>;
|
|
35
|
+
|
|
36
|
+
describe("createPluginDatabaseCore", () => {
|
|
37
|
+
it("prefers plugin getUpdateInfo fast-path when provided", async () => {
|
|
38
|
+
const getBundles = vi.fn<DatabasePlugin<TestContext>["getBundles"]>();
|
|
39
|
+
const expected: UpdateInfo = {
|
|
40
|
+
fileHash: baseBundle.fileHash,
|
|
41
|
+
id: baseBundle.id,
|
|
42
|
+
message: baseBundle.message,
|
|
43
|
+
shouldForceUpdate: baseBundle.shouldForceUpdate,
|
|
44
|
+
status: "UPDATE",
|
|
45
|
+
storageUri: baseBundle.storageUri,
|
|
46
|
+
};
|
|
47
|
+
const getUpdateInfo = vi.fn<
|
|
48
|
+
NonNullable<DatabasePlugin<TestContext>["getUpdateInfo"]>
|
|
49
|
+
>(async () => expected);
|
|
50
|
+
|
|
51
|
+
const plugin: DatabasePlugin<TestContext> = {
|
|
52
|
+
name: "fast-path-plugin",
|
|
53
|
+
async appendBundle() {},
|
|
54
|
+
async commitBundle() {},
|
|
55
|
+
async deleteBundle() {},
|
|
56
|
+
async getBundleById() {
|
|
57
|
+
return null;
|
|
58
|
+
},
|
|
59
|
+
getBundles,
|
|
60
|
+
getUpdateInfo,
|
|
61
|
+
async getChannels() {
|
|
62
|
+
return ["production"];
|
|
63
|
+
},
|
|
64
|
+
async updateBundle() {},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const core = createPluginDatabaseCore(
|
|
68
|
+
() => plugin,
|
|
69
|
+
async () => null,
|
|
70
|
+
);
|
|
71
|
+
const context: TestContext = {
|
|
72
|
+
env: {
|
|
73
|
+
assetHost: "https://assets.example.com",
|
|
74
|
+
},
|
|
75
|
+
request: new Request("https://updates.example.com"),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
await expect(core.api.getUpdateInfo(updateArgs, context)).resolves.toEqual(
|
|
79
|
+
expected,
|
|
80
|
+
);
|
|
81
|
+
expect(getUpdateInfo).toHaveBeenCalledWith(updateArgs, context);
|
|
82
|
+
expect(getBundles).not.toHaveBeenCalled();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("does not fall back to scanning when plugin getUpdateInfo returns null", async () => {
|
|
86
|
+
const getBundles = vi.fn<DatabasePlugin["getBundles"]>(async () => ({
|
|
87
|
+
data: [baseBundle],
|
|
88
|
+
pagination: {
|
|
89
|
+
currentPage: 1,
|
|
90
|
+
hasNextPage: false,
|
|
91
|
+
hasPreviousPage: false,
|
|
92
|
+
total: 1,
|
|
93
|
+
totalPages: 1,
|
|
94
|
+
},
|
|
95
|
+
}));
|
|
96
|
+
const getUpdateInfo = vi.fn<NonNullable<DatabasePlugin["getUpdateInfo"]>>(
|
|
97
|
+
async () => null,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const plugin: DatabasePlugin = {
|
|
101
|
+
name: "null-fast-path-plugin",
|
|
102
|
+
async appendBundle() {},
|
|
103
|
+
async commitBundle() {},
|
|
104
|
+
async deleteBundle() {},
|
|
105
|
+
async getBundleById() {
|
|
106
|
+
return null;
|
|
107
|
+
},
|
|
108
|
+
getBundles,
|
|
109
|
+
getUpdateInfo,
|
|
110
|
+
async getChannels() {
|
|
111
|
+
return ["production"];
|
|
112
|
+
},
|
|
113
|
+
async updateBundle() {},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const core = createPluginDatabaseCore(
|
|
117
|
+
() => plugin,
|
|
118
|
+
async () => null,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
await expect(core.api.getUpdateInfo(updateArgs)).resolves.toBeNull();
|
|
122
|
+
expect(getUpdateInfo).toHaveBeenCalledWith(updateArgs);
|
|
123
|
+
expect(getBundles).not.toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("falls back to scanning when plugin getUpdateInfo is absent", async () => {
|
|
127
|
+
const latestBundle = {
|
|
128
|
+
...baseBundle,
|
|
129
|
+
id: "00000000-0000-0000-0000-000000000002",
|
|
130
|
+
};
|
|
131
|
+
const getBundles = vi.fn<DatabasePlugin["getBundles"]>(async () => ({
|
|
132
|
+
data: [latestBundle],
|
|
133
|
+
pagination: {
|
|
134
|
+
currentPage: 1,
|
|
135
|
+
hasNextPage: false,
|
|
136
|
+
hasPreviousPage: false,
|
|
137
|
+
total: 1,
|
|
138
|
+
totalPages: 1,
|
|
139
|
+
},
|
|
140
|
+
}));
|
|
141
|
+
|
|
142
|
+
const plugin: DatabasePlugin = {
|
|
143
|
+
name: "scan-plugin",
|
|
144
|
+
async appendBundle() {},
|
|
145
|
+
async commitBundle() {},
|
|
146
|
+
async deleteBundle() {},
|
|
147
|
+
async getBundleById() {
|
|
148
|
+
return null;
|
|
149
|
+
},
|
|
150
|
+
getBundles,
|
|
151
|
+
async getChannels() {
|
|
152
|
+
return ["production"];
|
|
153
|
+
},
|
|
154
|
+
async updateBundle() {},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const core = createPluginDatabaseCore(
|
|
158
|
+
() => plugin,
|
|
159
|
+
async () => null,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
await expect(core.api.getUpdateInfo(updateArgs)).resolves.toEqual({
|
|
163
|
+
fileHash: latestBundle.fileHash,
|
|
164
|
+
id: latestBundle.id,
|
|
165
|
+
message: latestBundle.message,
|
|
166
|
+
shouldForceUpdate: latestBundle.shouldForceUpdate,
|
|
167
|
+
status: "UPDATE",
|
|
168
|
+
storageUri: latestBundle.storageUri,
|
|
169
|
+
});
|
|
170
|
+
expect(getBundles).toHaveBeenCalledOnce();
|
|
171
|
+
});
|
|
172
|
+
});
|
package/src/db/pluginCore.ts
CHANGED
|
@@ -172,15 +172,21 @@ export function createPluginDatabaseCore<TContext = unknown>(
|
|
|
172
172
|
isCandidate: (bundle: Bundle) => boolean;
|
|
173
173
|
context?: HotUpdaterContext<TContext>;
|
|
174
174
|
}): Promise<UpdateInfo | null> => {
|
|
175
|
-
let
|
|
175
|
+
let after: string | undefined;
|
|
176
176
|
|
|
177
177
|
while (true) {
|
|
178
178
|
const { data, pagination } = await getSortedBundlePage(
|
|
179
179
|
{
|
|
180
180
|
where: queryWhere,
|
|
181
181
|
limit: PAGE_SIZE,
|
|
182
|
-
offset,
|
|
183
182
|
orderBy: DESC_ORDER,
|
|
183
|
+
...(after
|
|
184
|
+
? {
|
|
185
|
+
cursor: {
|
|
186
|
+
after,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
: {}),
|
|
184
190
|
},
|
|
185
191
|
context,
|
|
186
192
|
);
|
|
@@ -223,7 +229,10 @@ export function createPluginDatabaseCore<TContext = unknown>(
|
|
|
223
229
|
break;
|
|
224
230
|
}
|
|
225
231
|
|
|
226
|
-
|
|
232
|
+
after = data.at(-1)?.id;
|
|
233
|
+
if (!after) {
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
if (args.bundleId === NIL_UUID) {
|
|
@@ -269,6 +278,14 @@ export function createPluginDatabaseCore<TContext = unknown>(
|
|
|
269
278
|
args: GetBundlesArgs,
|
|
270
279
|
context?: HotUpdaterContext<TContext>,
|
|
271
280
|
): Promise<UpdateInfo | null> {
|
|
281
|
+
const plugin = getPlugin();
|
|
282
|
+
const directGetUpdateInfo = plugin.getUpdateInfo;
|
|
283
|
+
if (directGetUpdateInfo) {
|
|
284
|
+
return context === undefined
|
|
285
|
+
? await directGetUpdateInfo(args)
|
|
286
|
+
: await directGetUpdateInfo(args, context);
|
|
287
|
+
}
|
|
288
|
+
|
|
272
289
|
const channel = args.channel ?? "production";
|
|
273
290
|
const minBundleId = args.minBundleId ?? NIL_UUID;
|
|
274
291
|
const baseWhere = getBaseWhere({
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
DatabasePlugin,
|
|
7
7
|
} from "../../../../plugins/plugin-core/src";
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
paginateBundles,
|
|
10
10
|
semverSatisfies,
|
|
11
11
|
} from "../../../../plugins/plugin-core/src";
|
|
12
12
|
import type {
|
|
@@ -124,17 +124,19 @@ const createBenchPlugin = (bundles: Bundle[]): DatabasePlugin => {
|
|
|
124
124
|
return bundlesById.get(bundleId) ?? null;
|
|
125
125
|
},
|
|
126
126
|
async getBundles(options: DatabaseBundleQueryOptions) {
|
|
127
|
-
const { where, limit,
|
|
127
|
+
const { where, limit, cursor, orderBy } = options;
|
|
128
128
|
const source = sortByDirection(orderBy?.direction);
|
|
129
129
|
const matched = source.filter((bundle) =>
|
|
130
130
|
bundleMatchesWhere(bundle, where),
|
|
131
131
|
);
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
};
|
|
132
|
+
const paginated = paginateBundles({
|
|
133
|
+
bundles: matched.map(cloneBundle),
|
|
134
|
+
limit,
|
|
135
|
+
cursor,
|
|
136
|
+
orderBy,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return paginated;
|
|
138
140
|
},
|
|
139
141
|
async getChannels() {
|
|
140
142
|
return [...new Set(bundles.map((bundle) => bundle.channel))];
|
|
@@ -164,7 +166,6 @@ const oldPluginCoreGetUpdateInfo = async (
|
|
|
164
166
|
const { pagination } = await plugin.getBundles({
|
|
165
167
|
where,
|
|
166
168
|
limit: 1,
|
|
167
|
-
offset: 0,
|
|
168
169
|
});
|
|
169
170
|
|
|
170
171
|
if (pagination.total === 0) {
|
|
@@ -174,7 +175,6 @@ const oldPluginCoreGetUpdateInfo = async (
|
|
|
174
175
|
const { data } = await plugin.getBundles({
|
|
175
176
|
where,
|
|
176
177
|
limit: pagination.total,
|
|
177
|
-
offset: 0,
|
|
178
178
|
});
|
|
179
179
|
|
|
180
180
|
for (const bundle of data) {
|
|
@@ -234,7 +234,7 @@ describe("Handler <-> Standalone Repository Integration", () => {
|
|
|
234
234
|
})();
|
|
235
235
|
|
|
236
236
|
// Get all bundles
|
|
237
|
-
const result = await repo.getBundles({ limit: 50
|
|
237
|
+
const result = await repo.getBundles({ limit: 50 });
|
|
238
238
|
|
|
239
239
|
expect(result.data).toHaveLength(3);
|
|
240
240
|
expect(result.pagination.total).toBe(3);
|
|
@@ -243,7 +243,6 @@ describe("Handler <-> Standalone Repository Integration", () => {
|
|
|
243
243
|
const prodResult = await repo.getBundles({
|
|
244
244
|
where: { channel: "production" },
|
|
245
245
|
limit: 50,
|
|
246
|
-
offset: 0,
|
|
247
246
|
});
|
|
248
247
|
|
|
249
248
|
expect(prodResult.data).toHaveLength(2);
|