@llamaduck/forgejo-ts 11.0.10 → 11.0.12

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/README.md CHANGED
@@ -16,141 +16,139 @@ pnpm add @llamaduck/forgejo-ts
16
16
 
17
17
  ## Usage
18
18
 
19
- ### Basic Configuration
19
+ ### Basic Usage
20
+
21
+ Create a client and start making API calls:
20
22
 
21
23
  ```typescript
22
- import { configure, RepositoryService, UserService } from '@llamaduck/forgejo-ts';
24
+ import { createClient, createConfig, getVersion, repoSearch } from '@llamaduck/forgejo-ts';
25
+
26
+ // Create a client
27
+ const client = createClient(createConfig({
28
+ baseUrl: 'https://codeberg.org/api/v1',
29
+ headers: { Authorization: 'token your-api-token' }
30
+ }));
23
31
 
24
- // Configure the client
25
- configure({
26
- baseUrl: 'https://your-forgejo-instance.com/api/v1',
27
- token: 'your-api-token', // Optional: for authenticated requests
28
- });
32
+ // Make API calls - pass the client in options
33
+ const version = await getVersion({ client });
34
+ console.log('Server version:', version.data?.version);
29
35
 
30
- // Now use any service
31
- const repos = await RepositoryService.repoSearch({ q: 'hello' });
32
- console.log(repos);
36
+ const repos = await repoSearch({ query: { q: 'typescript', limit: 10 } }, { client });
37
+ console.log('Found repos:', repos.data);
33
38
  ```
34
39
 
35
- ### Authentication Options
40
+ ### Multiple Clients
41
+
42
+ You can create multiple independent client instances:
36
43
 
37
44
  ```typescript
38
- import { configure } from '@llamaduck/forgejo-ts';
45
+ import { createClient, createConfig, repoSearch } from '@llamaduck/forgejo-ts';
39
46
 
40
- // Token authentication (recommended)
41
- configure({
42
- baseUrl: 'https://your-forgejo-instance.com/api/v1',
43
- token: 'your-personal-access-token',
44
- });
47
+ const clientA = createClient(createConfig({
48
+ baseUrl: 'https://codeberg.org/api/v1',
49
+ headers: { Authorization: 'token token-a' }
50
+ }));
45
51
 
46
- // Basic authentication
47
- configure({
48
- baseUrl: 'https://your-forgejo-instance.com/api/v1',
49
- username: 'your-username',
50
- password: 'your-password',
51
- });
52
- ```
52
+ const clientB = createClient(createConfig({
53
+ baseUrl: 'https://gitea.com/api/v1',
54
+ headers: { Authorization: 'token token-b' }
55
+ }));
53
56
 
54
- ### Direct OpenAPI Configuration
57
+ // Use different clients for different requests
58
+ const reposA = await repoSearch({ query: { q: 'test' } }, { client: clientA });
59
+ const reposB = await repoSearch({ query: { q: 'test' } }, { client: clientB });
60
+ ```
55
61
 
56
- For more control, you can configure the OpenAPI object directly:
62
+ ### Authentication
57
63
 
58
64
  ```typescript
59
- import { OpenAPI } from '@llamaduck/forgejo-ts';
65
+ import { createClient, createConfig } from '@llamaduck/forgejo-ts';
60
66
 
61
- OpenAPI.BASE = 'https://your-forgejo-instance.com/api/v1';
62
- OpenAPI.TOKEN = 'your-api-token';
67
+ // Token authentication (recommended)
68
+ const client = createClient(createConfig({
69
+ baseUrl: 'https://codeberg.org/api/v1',
70
+ headers: { Authorization: 'token your-personal-access-token' }
71
+ }));
63
72
 
64
- // Or use a function for dynamic token retrieval
65
- OpenAPI.TOKEN = async () => {
66
- return getTokenFromSomewhere();
67
- };
73
+ // Basic authentication
74
+ const auth = btoa('username:password');
75
+ const client = createClient(createConfig({
76
+ baseUrl: 'https://codeberg.org/api/v1',
77
+ headers: { Authorization: `Basic ${auth}` }
78
+ }));
68
79
  ```
69
80
 
70
- ### Using Services
81
+ ## API Reference
71
82
 
72
- All API endpoints are organized into services:
83
+ All API functions are exported directly from the package:
73
84
 
74
85
  ```typescript
75
86
  import {
76
- RepositoryService,
77
- UserService,
78
- OrganizationService,
79
- IssueService,
80
- AdminService,
81
- // ... and more
87
+ // Repositories
88
+ repoSearch,
89
+ repoGet,
90
+ userListRepos,
91
+
92
+ // Users
93
+ userGetCurrent,
94
+ userGet,
95
+
96
+ // Issues
97
+ issueSearch,
98
+ issueCreateIssue,
99
+
100
+ // Organizations
101
+ orgGet,
102
+
103
+ // And many more...
82
104
  } from '@llamaduck/forgejo-ts';
83
-
84
- // Get current user
85
- const user = await UserService.userGetCurrent();
86
-
87
- // List repositories
88
- const repos = await RepositoryService.repoSearch({
89
- q: 'typescript',
90
- limit: 10,
91
- });
92
-
93
- // Create an issue
94
- const issue = await IssueService.issueCreateIssue({
95
- owner: 'username',
96
- repo: 'repo-name',
97
- body: {
98
- title: 'Bug report',
99
- body: 'Description of the bug',
100
- },
101
- });
102
105
  ```
103
106
 
104
- ### Error Handling
107
+ Each function accepts:
108
+ 1. **Data/params** - The request data (path params, query params, body)
109
+ 2. **Options** (optional) - Request options including the `client` instance
105
110
 
111
+ Example:
106
112
  ```typescript
107
- import { ApiError, RepositoryService } from '@llamaduck/forgejo-ts';
113
+ // Search repositories
114
+ const repos = await repoSearch(
115
+ { query: { q: 'typescript', limit: 10 } },
116
+ { client }
117
+ );
118
+
119
+ // Get a specific repository
120
+ const repo = await repoGet(
121
+ { path: { owner: 'forgejo', repo: 'forgejo' } },
122
+ { client }
123
+ );
108
124
 
109
- try {
110
- const repo = await RepositoryService.repoGet({
111
- owner: 'user',
112
- repo: 'nonexistent',
113
- });
114
- } catch (error) {
115
- if (error instanceof ApiError) {
116
- console.error('API Error:', error.status, error.message);
117
- console.error('Response body:', error.body);
118
- }
119
- }
125
+ // Create an issue
126
+ const issue = await issueCreateIssue(
127
+ { path: { owner: 'user', repo: 'repo' } },
128
+ { body: { title: 'Bug report', body: 'Description' } },
129
+ { client }
130
+ );
120
131
  ```
121
132
 
122
- ### Canceling Requests
133
+ ### Error Handling
123
134
 
124
135
  ```typescript
125
- import { RepositoryService, CancelError } from '@llamaduck/forgejo-ts';
126
-
127
- const request = RepositoryService.repoSearch({ q: 'test' });
128
-
129
- // Cancel the request
130
- request.cancel();
136
+ import { repoGet } from '@llamaduck/forgejo-ts';
131
137
 
132
138
  try {
133
- await request;
139
+ const repo = await repoGet(
140
+ { path: { owner: 'user', repo: 'nonexistent' } },
141
+ { client }
142
+ );
134
143
  } catch (error) {
135
- if (error instanceof CancelError) {
136
- console.log('Request was canceled');
144
+ if (error.status === 404) {
145
+ console.error('Repository not found');
146
+ } else {
147
+ console.error('API Error:', error);
137
148
  }
138
149
  }
139
150
  ```
140
151
 
141
- ## Available Services
142
-
143
- - `ActivitypubService` - ActivityPub federation endpoints
144
- - `AdminService` - Administration endpoints (requires admin access)
145
- - `IssueService` - Issues and pull requests
146
- - `MiscellaneousService` - Miscellaneous endpoints (version, settings, etc.)
147
- - `NotificationService` - User notifications
148
- - `OrganizationService` - Organizations and teams
149
- - `PackageService` - Package registry
150
- - `RepositoryService` - Repositories, branches, commits, files
151
- - `SettingsService` - Instance settings
152
- - `UserService` - Users, followers, tokens, keys
153
-
154
152
  ## Version Information
155
153
 
156
154
  ```typescript
@@ -189,8 +187,6 @@ FORGEJO_VERSION=14.0.2 npm run generate
189
187
  npm run build
190
188
  ```
191
189
 
192
- The script fetches the Swagger spec directly from Codeberg.
193
-
194
190
  ## Configuration
195
191
 
196
192
  The `config.json` file specifies which major versions to track:
@@ -206,7 +202,7 @@ When Forgejo releases a new major version (e.g., v15), update this file to chang
206
202
 
207
203
  ## Contributing
208
204
 
209
- Contributions are welcome! Please note that the `src/generated/` directory is auto-generated and should not be manually edited.
205
+ Contributions are welcome! Please note that the `src/` directory is auto-generated and should not be manually edited.
210
206
 
211
207
  ## License
212
208
 
package/client.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./dist/client/index";
package/client.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require("./dist/client/index.js");
package/client.mjs ADDED
@@ -0,0 +1 @@
1
+ export * from "./dist/client/index.mjs";
@@ -0,0 +1,339 @@
1
+ import { CreateAxiosDefaults, AxiosStatic, AxiosInstance, AxiosRequestHeaders, AxiosResponse, AxiosError } from 'axios';
2
+
3
+ type AuthToken = string | undefined;
4
+ interface Auth {
5
+ /**
6
+ * Which part of the request do we use to send the auth?
7
+ *
8
+ * @default 'header'
9
+ */
10
+ in?: 'header' | 'query' | 'cookie';
11
+ /**
12
+ * Header or query parameter name.
13
+ *
14
+ * @default 'Authorization'
15
+ */
16
+ name?: string;
17
+ scheme?: 'basic' | 'bearer';
18
+ type: 'apiKey' | 'http';
19
+ }
20
+
21
+ interface SerializerOptions<T> {
22
+ /**
23
+ * @default true
24
+ */
25
+ explode: boolean;
26
+ style: T;
27
+ }
28
+ type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
29
+ type ObjectStyle = 'form' | 'deepObject';
30
+
31
+ type QuerySerializer = (query: Record<string, unknown>) => string;
32
+ type BodySerializer = (body: any) => any;
33
+ type QuerySerializerOptionsObject = {
34
+ allowReserved?: boolean;
35
+ array?: Partial<SerializerOptions<ArrayStyle>>;
36
+ object?: Partial<SerializerOptions<ObjectStyle>>;
37
+ };
38
+ type QuerySerializerOptions = QuerySerializerOptionsObject & {
39
+ /**
40
+ * Per-parameter serialization overrides. When provided, these settings
41
+ * override the global array/object settings for specific parameter names.
42
+ */
43
+ parameters?: Record<string, QuerySerializerOptionsObject>;
44
+ };
45
+ declare const formDataBodySerializer: {
46
+ bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T) => FormData;
47
+ };
48
+ declare const jsonBodySerializer: {
49
+ bodySerializer: <T>(body: T) => string;
50
+ };
51
+ declare const urlSearchParamsBodySerializer: {
52
+ bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T) => string;
53
+ };
54
+
55
+ type Slot = 'body' | 'headers' | 'path' | 'query';
56
+ type Field = {
57
+ in: Exclude<Slot, 'body'>;
58
+ /**
59
+ * Field name. This is the name we want the user to see and use.
60
+ */
61
+ key: string;
62
+ /**
63
+ * Field mapped name. This is the name we want to use in the request.
64
+ * If omitted, we use the same value as `key`.
65
+ */
66
+ map?: string;
67
+ } | {
68
+ in: Extract<Slot, 'body'>;
69
+ /**
70
+ * Key isn't required for bodies.
71
+ */
72
+ key?: string;
73
+ map?: string;
74
+ } | {
75
+ /**
76
+ * Field name. This is the name we want the user to see and use.
77
+ */
78
+ key: string;
79
+ /**
80
+ * Field mapped name. This is the name we want to use in the request.
81
+ * If `in` is omitted, `map` aliases `key` to the transport layer.
82
+ */
83
+ map: Slot;
84
+ };
85
+ interface Fields {
86
+ allowExtra?: Partial<Record<Slot, boolean>>;
87
+ args?: ReadonlyArray<Field>;
88
+ }
89
+ type FieldsConfig = ReadonlyArray<Field | Fields>;
90
+ interface Params {
91
+ body: unknown;
92
+ headers: Record<string, unknown>;
93
+ path: Record<string, unknown>;
94
+ query: Record<string, unknown>;
95
+ }
96
+ declare const buildClientParams: (args: ReadonlyArray<unknown>, fields: FieldsConfig) => Params;
97
+
98
+ /**
99
+ * JSON-friendly union that mirrors what Pinia Colada can hash.
100
+ */
101
+ type JsonValue = null | string | number | boolean | JsonValue[] | {
102
+ [key: string]: JsonValue;
103
+ };
104
+ /**
105
+ * Normalizes any accepted value into a JSON-friendly shape for query keys.
106
+ */
107
+ declare const serializeQueryKeyValue: (value: unknown) => JsonValue | undefined;
108
+
109
+ type HttpMethod = 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace';
110
+ type Client$1<RequestFn = never, Config = unknown, MethodFn = never, BuildUrlFn = never, SseFn = never> = {
111
+ /**
112
+ * Returns the final request URL.
113
+ */
114
+ buildUrl: BuildUrlFn;
115
+ getConfig: () => Config;
116
+ request: RequestFn;
117
+ setConfig: (config: Config) => Config;
118
+ } & {
119
+ [K in HttpMethod]: MethodFn;
120
+ } & ([SseFn] extends [never] ? {
121
+ sse?: never;
122
+ } : {
123
+ sse: {
124
+ [K in HttpMethod]: SseFn;
125
+ };
126
+ });
127
+ interface Config$1 {
128
+ /**
129
+ * Auth token or a function returning auth token. The resolved value will be
130
+ * added to the request payload as defined by its `security` array.
131
+ */
132
+ auth?: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken;
133
+ /**
134
+ * A function for serializing request body parameter. By default,
135
+ * {@link JSON.stringify()} will be used.
136
+ */
137
+ bodySerializer?: BodySerializer | null;
138
+ /**
139
+ * An object containing any HTTP headers that you want to pre-populate your
140
+ * `Headers` object with.
141
+ *
142
+ * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
143
+ */
144
+ headers?: RequestInit['headers'] | Record<string, string | number | boolean | (string | number | boolean)[] | null | undefined | unknown>;
145
+ /**
146
+ * The request method.
147
+ *
148
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more}
149
+ */
150
+ method?: Uppercase<HttpMethod>;
151
+ /**
152
+ * A function for serializing request query parameters. By default, arrays
153
+ * will be exploded in form style, objects will be exploded in deepObject
154
+ * style, and reserved characters are percent-encoded.
155
+ *
156
+ * This method will have no effect if the native `paramsSerializer()` Axios
157
+ * API function is used.
158
+ *
159
+ * {@link https://swagger.io/docs/specification/serialization/#query View examples}
160
+ */
161
+ querySerializer?: QuerySerializer | QuerySerializerOptions;
162
+ /**
163
+ * A function validating request data. This is useful if you want to ensure
164
+ * the request conforms to the desired shape, so it can be safely sent to
165
+ * the server.
166
+ */
167
+ requestValidator?: (data: unknown) => Promise<unknown>;
168
+ /**
169
+ * A function transforming response data before it's returned. This is useful
170
+ * for post-processing data, e.g. converting ISO strings into Date objects.
171
+ */
172
+ responseTransformer?: (data: unknown) => Promise<unknown>;
173
+ /**
174
+ * A function validating response data. This is useful if you want to ensure
175
+ * the response conforms to the desired shape, so it can be safely passed to
176
+ * the transformers and returned to the user.
177
+ */
178
+ responseValidator?: (data: unknown) => Promise<unknown>;
179
+ }
180
+
181
+ type ServerSentEventsOptions<TData = unknown> = Omit<RequestInit, 'method'> & Pick<Config$1, 'method' | 'responseTransformer' | 'responseValidator'> & {
182
+ /**
183
+ * Fetch API implementation. You can use this option to provide a custom
184
+ * fetch instance.
185
+ *
186
+ * @default globalThis.fetch
187
+ */
188
+ fetch?: typeof fetch;
189
+ /**
190
+ * Implementing clients can call request interceptors inside this hook.
191
+ */
192
+ onRequest?: (url: string, init: RequestInit) => Promise<Request>;
193
+ /**
194
+ * Callback invoked when a network or parsing error occurs during streaming.
195
+ *
196
+ * This option applies only if the endpoint returns a stream of events.
197
+ *
198
+ * @param error The error that occurred.
199
+ */
200
+ onSseError?: (error: unknown) => void;
201
+ /**
202
+ * Callback invoked when an event is streamed from the server.
203
+ *
204
+ * This option applies only if the endpoint returns a stream of events.
205
+ *
206
+ * @param event Event streamed from the server.
207
+ * @returns Nothing (void).
208
+ */
209
+ onSseEvent?: (event: StreamEvent<TData>) => void;
210
+ serializedBody?: RequestInit['body'];
211
+ /**
212
+ * Default retry delay in milliseconds.
213
+ *
214
+ * This option applies only if the endpoint returns a stream of events.
215
+ *
216
+ * @default 3000
217
+ */
218
+ sseDefaultRetryDelay?: number;
219
+ /**
220
+ * Maximum number of retry attempts before giving up.
221
+ */
222
+ sseMaxRetryAttempts?: number;
223
+ /**
224
+ * Maximum retry delay in milliseconds.
225
+ *
226
+ * Applies only when exponential backoff is used.
227
+ *
228
+ * This option applies only if the endpoint returns a stream of events.
229
+ *
230
+ * @default 30000
231
+ */
232
+ sseMaxRetryDelay?: number;
233
+ /**
234
+ * Optional sleep function for retry backoff.
235
+ *
236
+ * Defaults to using `setTimeout`.
237
+ */
238
+ sseSleepFn?: (ms: number) => Promise<void>;
239
+ url: string;
240
+ };
241
+ interface StreamEvent<TData = unknown> {
242
+ data: TData;
243
+ event?: string;
244
+ id?: string;
245
+ retry?: number;
246
+ }
247
+ type ServerSentEventsResult<TData = unknown, TReturn = void, TNext = unknown> = {
248
+ stream: AsyncGenerator<TData extends Record<string, unknown> ? TData[keyof TData] : TData, TReturn, TNext>;
249
+ };
250
+
251
+ interface Config<T extends ClientOptions = ClientOptions> extends Omit<CreateAxiosDefaults, 'auth' | 'baseURL' | 'headers' | 'method'>, Config$1 {
252
+ /**
253
+ * Axios implementation. You can use this option to provide either an
254
+ * `AxiosStatic` or an `AxiosInstance`.
255
+ *
256
+ * @default axios
257
+ */
258
+ axios?: AxiosStatic | AxiosInstance;
259
+ /**
260
+ * Base URL for all requests made by this client.
261
+ */
262
+ baseURL?: T['baseURL'];
263
+ /**
264
+ * An object containing any HTTP headers that you want to pre-populate your
265
+ * `Headers` object with.
266
+ *
267
+ * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
268
+ */
269
+ headers?: AxiosRequestHeaders | Record<string, string | number | boolean | (string | number | boolean)[] | null | undefined | unknown>;
270
+ /**
271
+ * Throw an error instead of returning it in the response?
272
+ *
273
+ * @default false
274
+ */
275
+ throwOnError?: T['throwOnError'];
276
+ }
277
+ interface RequestOptions<TData = unknown, ThrowOnError extends boolean = boolean, Url extends string = string> extends Config<{
278
+ throwOnError: ThrowOnError;
279
+ }>, Pick<ServerSentEventsOptions<TData>, 'onSseError' | 'onSseEvent' | 'sseDefaultRetryDelay' | 'sseMaxRetryAttempts' | 'sseMaxRetryDelay'> {
280
+ /**
281
+ * Any body that you want to add to your request.
282
+ *
283
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
284
+ */
285
+ body?: unknown;
286
+ path?: Record<string, unknown>;
287
+ query?: Record<string, unknown>;
288
+ /**
289
+ * Security mechanism(s) to use for the request.
290
+ */
291
+ security?: ReadonlyArray<Auth>;
292
+ url: Url;
293
+ }
294
+ interface ClientOptions {
295
+ baseURL?: string;
296
+ throwOnError?: boolean;
297
+ }
298
+ type RequestResult<TData = unknown, TError = unknown, ThrowOnError extends boolean = boolean> = ThrowOnError extends true ? Promise<AxiosResponse<TData extends Record<string, unknown> ? TData[keyof TData] : TData>> : Promise<(AxiosResponse<TData extends Record<string, unknown> ? TData[keyof TData] : TData> & {
299
+ error: undefined;
300
+ }) | (AxiosError<TError extends Record<string, unknown> ? TError[keyof TError] : TError> & {
301
+ data: undefined;
302
+ error: TError extends Record<string, unknown> ? TError[keyof TError] : TError;
303
+ })>;
304
+ type MethodFn = <TData = unknown, TError = unknown, ThrowOnError extends boolean = false>(options: Omit<RequestOptions<TData, ThrowOnError>, 'method'>) => RequestResult<TData, TError, ThrowOnError>;
305
+ type SseFn = <TData = unknown, TError = unknown, ThrowOnError extends boolean = false>(options: Omit<RequestOptions<TData, ThrowOnError>, 'method'>) => Promise<ServerSentEventsResult<TData, TError>>;
306
+ type RequestFn = <TData = unknown, TError = unknown, ThrowOnError extends boolean = false>(options: Omit<RequestOptions<TData, ThrowOnError>, 'method'> & Pick<Required<RequestOptions<TData, ThrowOnError>>, 'method'>) => RequestResult<TData, TError, ThrowOnError>;
307
+ type BuildUrlFn = <TData extends {
308
+ body?: unknown;
309
+ path?: Record<string, unknown>;
310
+ query?: Record<string, unknown>;
311
+ url: string;
312
+ }>(options: TData & Options<TData>) => string;
313
+ type Client = Client$1<RequestFn, Config, MethodFn, BuildUrlFn, SseFn> & {
314
+ instance: AxiosInstance;
315
+ };
316
+ /**
317
+ * The `createClientConfig()` function will be called on client initialization
318
+ * and the returned object will become the client's initial configuration.
319
+ *
320
+ * You may want to initialize your client this way instead of calling
321
+ * `setConfig()`. This is useful for example if you're using Next.js
322
+ * to ensure your client always has the correct values.
323
+ */
324
+ type CreateClientConfig<T extends ClientOptions = ClientOptions> = (override?: Config<ClientOptions & T>) => Config<Required<ClientOptions> & T>;
325
+ interface TDataShape {
326
+ body?: unknown;
327
+ headers?: unknown;
328
+ path?: unknown;
329
+ query?: unknown;
330
+ url: string;
331
+ }
332
+ type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
333
+ type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = OmitKeys<RequestOptions<TResponse, ThrowOnError>, 'body' | 'path' | 'query' | 'url'> & ([TData] extends [never] ? unknown : Omit<TData, 'url'>);
334
+
335
+ declare const createClient: (config?: Config) => Client;
336
+
337
+ declare const createConfig: <T extends ClientOptions = ClientOptions>(override?: Config<Omit<ClientOptions, keyof T> & T>) => Config<Omit<ClientOptions, keyof T> & T>;
338
+
339
+ export { type Auth, type Client, type ClientOptions, type Config, type CreateClientConfig, type Options, type QuerySerializerOptions, type RequestOptions, type RequestResult, type TDataShape, buildClientParams, createClient, createConfig, formDataBodySerializer, jsonBodySerializer, serializeQueryKeyValue, urlSearchParamsBodySerializer };