Skip to content

Commit 5cbc516

Browse files
committed
feat: add (client-side) filtering by status to API#listInstallations
1 parent b7fe53c commit 5cbc516

2 files changed

Lines changed: 48 additions & 38 deletions

File tree

.changeset/twenty-socks-train.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@badrap/libapp": patch
3+
---
4+
5+
Add (client-side) filtering by status to API#listInstallations

src/api/index.ts

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,26 @@ export class UpdateFailed extends Error {
1313
}
1414
}
1515

16+
type InstallationStatus = "active" | "paused" | "uninstalled";
17+
const InstallationStatus: v.Type<InstallationStatus> = v.union(
18+
v.literal("active"),
19+
v.literal("paused"),
20+
v.literal("uninstalled"),
21+
);
22+
23+
type InstallationOwner =
24+
| { type: "team"; name: string }
25+
| { type: "user"; email: string };
26+
const InstallationOwner: v.Type<InstallationOwner> = v.union(
27+
v.object({ type: v.literal("team"), name: v.string() }),
28+
v.object({ type: v.literal("user"), email: v.string() }),
29+
);
30+
1631
export type Installation<State extends Record<string, unknown>> = {
1732
id: string;
1833
state: State;
19-
owner?: { type: "team"; name: string } | { type: "user"; email: string };
20-
status: "active" | "paused" | "uninstalled";
34+
owner?: InstallationOwner;
35+
status: InstallationStatus;
2136
};
2237

2338
export type Asset = Readonly<{
@@ -75,31 +90,39 @@ export class API<
7590
};
7691
}
7792

78-
async *listInstallations(): AsyncIterable<{
93+
async *listInstallations({
94+
status,
95+
}: {
96+
status?: InstallationStatus | InstallationStatus[];
97+
}): AsyncIterable<{
7998
id: string;
8099
owner?: { type: "team"; name: string } | { type: "user"; email: string };
81-
status: "active" | "paused" | "uninstalled";
100+
status: InstallationStatus;
82101
}> {
83-
yield* await this.#client.request({
102+
const list = await this.#client.request({
84103
method: "GET",
85104
path: ["installations"],
86105
responseType: v.array(
87106
v.object({
88107
id: v.string(),
89-
owner: v
90-
.union(
91-
v.object({ type: v.literal("team"), name: v.string() }),
92-
v.object({ type: v.literal("user"), email: v.string() }),
93-
)
94-
.optional(),
95-
status: v.union(
96-
v.literal("active"),
97-
v.literal("paused"),
98-
v.literal("uninstalled"),
99-
),
108+
owner: InstallationOwner.optional(),
109+
status: InstallationStatus,
100110
}),
101111
),
102112
});
113+
114+
const statusSet =
115+
status === undefined
116+
? undefined
117+
: typeof status === "string"
118+
? new Set([status])
119+
: new Set(status);
120+
121+
for (const installation of list) {
122+
if (!statusSet || statusSet.has(installation.status)) {
123+
yield installation;
124+
}
125+
}
103126
}
104127

105128
async createInstallationCallback(
@@ -131,17 +154,8 @@ export class API<
131154
responseType: v.object({
132155
id: v.string(),
133156
state: this.#stateType,
134-
owner: v
135-
.union(
136-
v.object({ type: v.literal("team"), name: v.string() }),
137-
v.object({ type: v.literal("user"), email: v.string() }),
138-
)
139-
.optional(),
140-
status: v.union(
141-
v.literal("active"),
142-
v.literal("paused"),
143-
v.literal("uninstalled"),
144-
),
157+
owner: InstallationOwner.optional(),
158+
status: InstallationStatus,
145159
}),
146160
});
147161
}
@@ -166,17 +180,8 @@ export class API<
166180
responseType: v.object({
167181
id: v.string(),
168182
state: this.#stateType,
169-
owner: v
170-
.union(
171-
v.object({ type: v.literal("team"), name: v.string() }),
172-
v.object({ type: v.literal("user"), email: v.string() }),
173-
)
174-
.optional(),
175-
status: v.union(
176-
v.literal("active"),
177-
v.literal("paused"),
178-
v.literal("uninstalled"),
179-
),
183+
owner: InstallationOwner.optional(),
184+
status: InstallationStatus,
180185
}),
181186
});
182187

0 commit comments

Comments
 (0)