Skip to content

Commit 1b93cdb

Browse files
committed
Re-add changes to packages/client that were left out when pushed to main
1 parent 8131b65 commit 1b93cdb

19 files changed

+808
-372
lines changed

packages/client/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@stl-api/client",
3-
"version": "0.0.1-alpha.32",
3+
"version": "0.0.1-alpha.38",
44
"description": "primary client package for stl-api",
55
"author": "[email protected]",
66
"license": "ISC",
@@ -29,7 +29,7 @@
2929
"dedent-js": "^1.0.1",
3030
"lodash": "^4.17.21",
3131
"prettier": "^3.3.3",
32-
"stainless": "github:stainless-api/stl-api#stainless-0.1.4",
32+
"stainless": "github:stainless-api/stl-api#stainless-0.1.3",
3333
"typescript": "^5.3.2",
3434
"zod-to-ts": "^1.2.0"
3535
},

packages/client/src/codegen/generate-types.ts

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -199,52 +199,47 @@ function makeActionType(
199199
const action = api.resources[resources[0]].actions[resources[1]];
200200
const types: string[] = [];
201201
const body = action.body ? `body: ${zodToString(action.body)}` : "";
202+
const query = action.query
203+
? `${body.length ? ", " : ""}query?: ${zodToString(action.query)}`
204+
: "";
202205
const returnType = action.response ? zodToString(action.response) : "void";
203206

204207
types.push(dedent`
205-
use${capitalize(camelCase(name))}(${body}): {
208+
use${capitalize(camelCase(name))}(${body}${query}): {
206209
queryFn(): Promise<${returnType}>;
207210
queryKey: string[];
208211
};`);
209212

210213
if (config.extensions) {
211-
if (action.body) {
212-
const input = zodToString(action.body);
213-
214-
types.push(dedent`
215-
${camelCase(name)}: {
216-
(${body}): Promise<${returnType}>;
217-
useQuery(
218-
body: ${input},
219-
opts?: UseQueryOptions
220-
): ReactQuery.UseQueryResult<${returnType}>;
221-
useSuspenseQuery(
222-
body: ${input},
223-
opts?: UseQueryOptions
224-
): ReactQuery.UseSuspenseQueryResult<${returnType}>;
225-
useMutation(
226-
opts?: UseMutationOptions
227-
): ReactQuery.UseMutationResult<${returnType}, unknown, ${input}>;
228-
getQueryKey(): string[];
229-
};`);
214+
const input = action.body ? zodToString(action.body) : undefined;
215+
const extensionMethds = dedent`
216+
useQuery(opts?: UseQueryOptions): ReactQuery.UseQueryResult<${returnType}>;
217+
useSuspenseQuery(opts?: UseSuspenseQueryOptions): ReactQuery.UseSuspenseQueryResult<${returnType}>;
218+
`;
219+
const extensionMutationMethod =
220+
input !== undefined
221+
? dedent`useMutation(opts?: UseMutationOptions<${returnType}, unknown, ${input}>): ReactQuery.UseMutationResult<${returnType}, unknown, ${input}>;`
222+
: dedent`useMutation(opts?: UseMutationOptions<${returnType}, unknown, void>): ReactQuery.UseMutationResult<${returnType}, unknown, void>;`;
223+
const extensionQueryKeyMethod = `getQueryKey(): string[];`;
224+
225+
if (body.length || query.length) {
226+
types.push(
227+
`${camelCase(name)}: {
228+
(${body}${query}): Promise<${returnType}> & {${extensionMethds}};
229+
${extensionMutationMethod}
230+
${extensionQueryKeyMethod}
231+
};`
232+
);
230233
} else {
231-
types.push(dedent`
232-
${camelCase(name)}: {
233-
(${body}): Promise<${returnType}>;
234-
useQuery(
235-
opts?: UseQueryOptions
236-
): ReactQuery.UseQueryResult<${returnType}>;
237-
useSuspenseQuery(
238-
opts?: UseQueryOptions
239-
): ReactQuery.UseSuspenseQueryResult<${returnType}>;
240-
useMutation(
241-
opts?: UseMutationOptions
242-
): ReactQuery.UseMutationResult<${returnType}, unknown, void>;
243-
getQueryKey(): string[];
244-
};`);
234+
types.push(dedent`${camelCase(name)}: {
235+
(): Promise<${returnType}>;
236+
${extensionMethds}
237+
${extensionMutationMethod}
238+
${extensionQueryKeyMethod}
239+
};`);
245240
}
246241
} else {
247-
types.push(`${camelCase(name)}(${body}): Promise<`);
242+
types.push(`${camelCase(name)}(${body}${query}): Promise<`);
248243
types.push(`${returnType}`);
249244
types.push(">;");
250245
}
@@ -300,8 +295,11 @@ function makeTypes(
300295
301296
type StlApiProvidedOpts = "queryFn" | "queryKey" | "mutationFn";
302297
type UseQueryOptions = Omit<ReactQuery.UseQueryOptions, StlApiProvidedOpts>;
303-
type UseMutationOptions = Omit<ReactQuery.UseMutationOptions, StlApiProvidedOpts>;
304-
298+
type UseSuspenseQueryOptions = Omit<ReactQuery.UseSuspenseQueryOptions, StlApiProvidedOpts>;
299+
type UseMutationOptions<TData = unknown, TError = Error, TVariables = void, TContext = unknown> = Omit<
300+
ReactQuery.UseMutationOptions<TData, TError, TVariables, TContext>,
301+
StlApiProvidedOpts
302+
>;
305303
`);
306304
}
307305

@@ -337,7 +335,6 @@ export async function generateOutput<API extends APIConfig>(
337335
);
338336

339337
return await prettier.format(output.flat().join("\n"), {
340-
semi: false,
341338
parser: "typescript",
342339
});
343340
}

packages/client/src/codegen/generated-api-client.test-d.ts

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, expectTypeOf, test } from "vitest";
22
import { makeClientWithExplicitTypes } from "../core/api-client";
33
import { Client } from "../test-util/generated-api-types";
4+
import { Color } from "../test-util/cat-api";
45

56
describe("Generated API Client", () => {
67
describe("single resource", () => {
@@ -17,20 +18,20 @@ describe("Generated API Client", () => {
1718
let updateOutput = client.cats("shiro").update({ color: "white" });
1819
let retrieveLitterOutput = client.cats("shiro").litter.retrieveLitter();
1920

20-
expectTypeOf(listOutput).toEqualTypeOf<
21-
Promise<{ name: string; color: string }[]>
21+
expectTypeOf(listOutput).toMatchTypeOf<
22+
Promise<{ name: string; color: Color }[]>
2223
>();
23-
expectTypeOf(createOutput).toEqualTypeOf<
24-
Promise<{ name: string; color: string }>
24+
expectTypeOf(createOutput).toMatchTypeOf<
25+
Promise<{ name: string; color: Color }>
2526
>();
2627
expectTypeOf(retrieveOutput).toEqualTypeOf<
27-
Promise<{ name: string; color: string }>
28+
Promise<{ name: string; color: Color }>
2829
>();
29-
expectTypeOf(updateOutput).toEqualTypeOf<
30-
Promise<{ name: string; color: string }>
30+
expectTypeOf(updateOutput).toMatchTypeOf<
31+
Promise<{ name: string; color: Color }>
3132
>();
3233
expectTypeOf(retrieveLitterOutput).toEqualTypeOf<
33-
Promise<{ name: string; color: string }[]>
34+
Promise<{ name: string; color: Color }[]>
3435
>();
3536
});
3637

@@ -48,23 +49,23 @@ describe("Generated API Client", () => {
4849

4950
expectTypeOf(listOutput).toEqualTypeOf<{
5051
queryKey: string[];
51-
queryFn: () => Promise<{ name: string; color: string }[]>;
52+
queryFn: () => Promise<{ name: string; color: Color }[]>;
5253
}>();
5354
expectTypeOf(createOutput).toEqualTypeOf<{
5455
queryKey: string[];
55-
queryFn: () => Promise<{ name: string; color: string }>;
56+
queryFn: () => Promise<{ name: string; color: Color }>;
5657
}>();
5758
expectTypeOf(retrieveOutput).toEqualTypeOf<{
5859
queryKey: string[];
59-
queryFn: () => Promise<{ name: string; color: string }>;
60+
queryFn: () => Promise<{ name: string; color: Color }>;
6061
}>();
6162
expectTypeOf(updateOutput).toEqualTypeOf<{
6263
queryKey: string[];
63-
queryFn: () => Promise<{ name: string; color: string }>;
64+
queryFn: () => Promise<{ name: string; color: Color }>;
6465
}>();
6566
expectTypeOf(retrieveLitterOutput).toEqualTypeOf<{
6667
queryKey: string[];
67-
queryFn: () => Promise<{ name: string; color: string }[]>;
68+
queryFn: () => Promise<{ name: string; color: Color }[]>;
6869
}>();
6970
});
7071
});
@@ -77,8 +78,8 @@ describe("Generated API Client", () => {
7778
let catListOutput = client.cats.list();
7879
let dogListOutput = client.dogs.list();
7980

80-
expectTypeOf(catListOutput).toEqualTypeOf<
81-
Promise<{ name: string; color: string }[]>
81+
expectTypeOf(catListOutput).toMatchTypeOf<
82+
Promise<{ name: string; color: Color }[]>
8283
>();
8384
expectTypeOf(dogListOutput).toEqualTypeOf<
8485
Promise<{ name: string; color: string }[]>
@@ -99,8 +100,19 @@ describe("Generated API Client", () => {
99100

100101
test("can handle native enums", () => {
101102
expectTypeOf(
102-
client.users("foo").update.useSuspenseQuery({}).data.accountType
103-
).toEqualTypeOf<"admin" | "free" | "paid">();
103+
client.users("foo").update({}).useSuspenseQuery().data.accountType
104+
).toMatchTypeOf<"admin" | "free" | "paid">();
105+
});
106+
});
107+
108+
describe("extensions", () => {
109+
const config = { basePath: "/api" as const };
110+
const client = makeClientWithExplicitTypes<Client>(config);
111+
112+
test("expects query params", () => {
113+
expectTypeOf(
114+
client.cats.list({ color: "black" }).useSuspenseQuery
115+
).toBeFunction();
104116
});
105117
});
106118
});

packages/client/src/codegen/generated-api-client.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ describe("Generated API Client", () => {
5757
expect(cats).toStrictEqual([{ name: "Shiro", color: "black" }]);
5858
});
5959

60+
it("can pass query params", async () => {
61+
const cats = await client.cats.list({ color: "black" });
62+
expect(mockFetch).toHaveBeenCalledWith("/api/cats?color=black", {
63+
method: "GET",
64+
});
65+
expect(cats).toStrictEqual([{ name: "Shiro", color: "black" }]);
66+
});
67+
6068
it("can send a request body", async () => {
6169
const update = await client.cats("shiro").update({ name: "Shiro!" });
6270
expect(update).toStrictEqual({ name: "Shiro!", color: "black" });
@@ -111,6 +119,19 @@ describe("Generated API Client", () => {
111119
expect(cats).toStrictEqual([{ name: "Shiro", color: "black" }]);
112120
});
113121

122+
it("can pass query params", async () => {
123+
const { queryFn, queryKey } = client.cats.useList({ color: "black" });
124+
125+
expect(queryKey).toEqual(["/api/cats"]);
126+
expect(queryFn).toBeTypeOf("function");
127+
128+
const cats = await queryFn();
129+
expect(mockFetch).toHaveBeenCalledWith("/api/cats?color=black", {
130+
method: "GET",
131+
});
132+
expect(cats).toStrictEqual([{ name: "Shiro", color: "black" }]);
133+
});
134+
114135
it("can send a request body", async () => {
115136
const { queryFn, queryKey } = client
116137
.cats("shiro")

packages/client/src/core/api-client-types.d.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,27 +57,48 @@ type CallableEndpoint<
5757
: never
5858
: /** Add types for API call method */ {
5959
[key in ActionName]: EndpointBodyInput<EPConfig> extends undefined
60-
? () => Promise<EndpointResponseOutput<EPConfig>>
60+
? (
61+
query?: z.input<EPConfig["query"]>
62+
) => Promise<EndpointResponseOutput<EPConfig>> &
63+
GetExtensions<
64+
Extensions,
65+
EndpointBodyInput<EPConfig>,
66+
EndpointQueryInput<EPConfig>,
67+
EndpointResponseOutput<EPConfig>
68+
>
6169
: (
62-
body: EndpointBodyInput<EPConfig>
63-
) => Promise<EndpointResponseOutput<EPConfig>>;
70+
body: EndpointBodyInput<EPConfig>,
71+
query?: z.input<EPConfig["query"]>
72+
) => Promise<EndpointResponseOutput<EPConfig>> &
73+
GetExtensions<
74+
Extensions,
75+
EndpointBodyInput<EPConfig>,
76+
EndpointQueryInput<EPConfig>,
77+
EndpointResponseOutput<EPConfig>
78+
>;
6479
} & {
6580
[key in ActionName as `use${Capitalize<key>}`]: EndpointBodyInput<EPConfig> extends undefined
66-
? () => {
81+
? (query?: z.input<EPConfig["query"]>) => {
6782
queryKey: string[];
6883
queryFn: () => Promise<EndpointResponseOutput<EPConfig>>;
6984
}
70-
: (body: EndpointBodyInput<EPConfig>) => {
85+
: (
86+
body: EndpointBodyInput<EPConfig>,
87+
query?: z.input<EPConfig["query"]>
88+
) => {
7189
queryKey: string[];
7290
queryFn: () => Promise<EndpointResponseOutput<EPConfig>>;
7391
};
7492
} & {
7593
[key in ActionName]: keyof Extensions extends string
76-
? GetExtensions<
77-
Extensions,
78-
EndpointBodyInput<EPConfig>,
79-
EndpointResponseOutput<EPConfig>
80-
>
94+
? EPConfig["query"] extends undefined
95+
? GetExtensions<
96+
Extensions,
97+
EndpointBodyInput<EPConfig>,
98+
EndpointQueryInput<EPConfig>,
99+
EndpointResponseOutput<EPConfig>
100+
>
101+
: "undefined"
81102
: "undefined";
82103
};
83104

packages/client/src/core/api-client.test-d.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ describe("API Client", () => {
3535
.cats<"retrieveLitter">("shiro")
3636
.litter.retrieveLitter();
3737

38-
expectTypeOf(listOutput).toEqualTypeOf<
38+
expectTypeOf(listOutput).toMatchTypeOf<
3939
Promise<{ name: string; color: string }[]>
4040
>();
41-
expectTypeOf(createOutput).toEqualTypeOf<
41+
expectTypeOf(createOutput).toMatchTypeOf<
4242
Promise<{ name: string; color: string }>
4343
>();
44-
expectTypeOf(retrieveOutput).toEqualTypeOf<
44+
expectTypeOf(retrieveOutput).toMatchTypeOf<
4545
Promise<{ name: string; color: string }>
4646
>();
47-
expectTypeOf(updateOutput).toEqualTypeOf<
47+
expectTypeOf(updateOutput).toMatchTypeOf<
4848
Promise<{ name: string; color: string }>
4949
>();
50-
expectTypeOf(retrieveLitterOutput).toEqualTypeOf<
50+
expectTypeOf(retrieveLitterOutput).toMatchTypeOf<
5151
Promise<{ name: string; color: string }[]>
5252
>();
5353
});
@@ -107,7 +107,7 @@ describe("API Client", () => {
107107
.cats<"retrieveLitter">("shiro")
108108
.litter.retrieveLitter();
109109

110-
expectTypeOf(retrieveLitterOutput).toEqualTypeOf<
110+
expectTypeOf(retrieveLitterOutput).toMatchTypeOf<
111111
Promise<{ name: string; color: string }[]>
112112
>();
113113
});
@@ -117,7 +117,7 @@ describe("API Client", () => {
117117
.cats({ catName: "shiro", discriminator: "retrieve" })
118118
.retrieve();
119119

120-
expectTypeOf(retrieveOutput).toEqualTypeOf<
120+
expectTypeOf(retrieveOutput).toMatchTypeOf<
121121
Promise<{ name: string; color: string }>
122122
>();
123123
});
@@ -142,10 +142,10 @@ describe("API Client", () => {
142142
let catListOutput = client.cats.list();
143143
let dogListOutput = client.dogs.list();
144144

145-
expectTypeOf(catListOutput).toEqualTypeOf<
145+
expectTypeOf(catListOutput).toMatchTypeOf<
146146
Promise<{ name: string; color: string }[]>
147147
>();
148-
expectTypeOf(dogListOutput).toEqualTypeOf<
148+
expectTypeOf(dogListOutput).toMatchTypeOf<
149149
Promise<{ name: string; color: string }[]>
150150
>();
151151
});
@@ -155,7 +155,7 @@ describe("API Client", () => {
155155
.dogs<"retrieveTreat">("fido")
156156
.dogTreats("treatId")
157157
.retrieveTreat();
158-
expectTypeOf(dogTreatOutput).toEqualTypeOf<Promise<{ yummy: boolean }>>();
158+
expectTypeOf(dogTreatOutput).toMatchTypeOf<Promise<{ yummy: boolean }>>();
159159
});
160160
});
161161
});

0 commit comments

Comments
 (0)