@data-client/rest 0.7.4 → 0.7.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.
@@ -0,0 +1,659 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import type {
3
+ EndpointExtraOptions,
4
+ EndpointInstanceInterface,
5
+ Schema,
6
+ FetchFunction,
7
+ ResolveType,
8
+ } from '@data-client/endpoint';
9
+
10
+ import type { ExtractCollection } from './extractCollection.js';
11
+ import {
12
+ OptionsToBodyArgument,
13
+ OptionsToFunction,
14
+ } from './OptionsToFunction.js';
15
+ import { PathArgs } from './pathTypes.js';
16
+ import { EndpointUpdateFunction } from './RestEndpointTypeHelp.js';
17
+
18
+ export interface RestInstanceBase<
19
+ F extends FetchFunction = FetchFunction,
20
+ S extends Schema | undefined = any,
21
+ M extends true | undefined = true | undefined,
22
+ O extends {
23
+ path: string;
24
+ body?: any;
25
+ searchParams?: any;
26
+ method?: string;
27
+ } = { path: string },
28
+ > extends EndpointInstanceInterface<F, S, M> {
29
+ /** @see https://resthooks.io/rest/api/RestEndpoint#body */
30
+ readonly body?: 'body' extends keyof O ? O['body'] : any;
31
+ /** @see https://resthooks.io/rest/api/RestEndpoint#searchParams */
32
+ readonly searchParams?: 'searchParams' extends keyof O
33
+ ? O['searchParams']
34
+ : // unknown is identity with '&' type operator
35
+ unknown;
36
+
37
+ /** Pattern to construct url based on Url Parameters
38
+ * @see https://resthooks.io/rest/api/RestEndpoint#path
39
+ */
40
+ readonly path: O['path'];
41
+ /** Prepended to all urls
42
+ * @see https://resthooks.io/rest/api/RestEndpoint#urlPrefix
43
+ */
44
+ readonly urlPrefix: string;
45
+ readonly requestInit: RequestInit;
46
+ /** @see https://resthooks.io/rest/api/RestEndpoint#method */
47
+ readonly method: (O & { method: string })['method'];
48
+ readonly signal: AbortSignal | undefined;
49
+ readonly paginationField?: string;
50
+
51
+ /* fetch lifecycles */
52
+ /* before-fetch */
53
+ url(...args: Parameters<F>): string;
54
+ /** @see https://resthooks.io/rest/api/RestEndpoint#getRequestInit */
55
+ getRequestInit(
56
+ this: any,
57
+ body?: RequestInit['body'] | Record<string, unknown>,
58
+ ): Promise<RequestInit> | RequestInit;
59
+ /** @see https://resthooks.io/rest/api/RestEndpoint#getHeaders */
60
+ getHeaders(headers: HeadersInit): Promise<HeadersInit> | HeadersInit;
61
+ /* after-fetch */
62
+ /** @see https://resthooks.io/rest/api/RestEndpoint#fetchResponse */
63
+ fetchResponse(input: RequestInfo, init: RequestInit): Promise<Response>;
64
+ /** @see https://resthooks.io/rest/api/RestEndpoint#parseResponse */
65
+ parseResponse(response: Response): Promise<any>;
66
+ /** @see https://resthooks.io/rest/api/RestEndpoint#process */
67
+ process(value: any, ...args: Parameters<F>): ResolveType<F>;
68
+
69
+ /* utilities */
70
+ /** @see https://resthooks.io/rest/api/RestEndpoint#testKey */
71
+ testKey(key: string): boolean;
72
+
73
+ /* extenders */
74
+ // TODO: figure out better way than wrapping whole options in Readonly<> + making O extend from {}
75
+ // this is just a hack to handle when no members of PartialRestGenerics are present
76
+ // Note: Using overloading (like paginated did) struggles because typescript does not have a clear way of distinguishing one
77
+ // should be used from the other (due to same problem with every member being partial)
78
+ /** Creates a child endpoint that inherits from this while overriding provided `options`.
79
+ * @see https://dataclient.io/rest/api/RestEndpoint#extend
80
+ */
81
+ extend<
82
+ E extends RestInstanceBase,
83
+ ExtendOptions extends PartialRestGenerics | {},
84
+ >(
85
+ this: E,
86
+ options: Readonly<
87
+ RestEndpointExtendOptions<ExtendOptions, E, F> & ExtendOptions
88
+ >,
89
+ ): RestExtendedEndpoint<ExtendOptions, E>;
90
+ }
91
+
92
+ export interface RestInstance<
93
+ F extends FetchFunction = FetchFunction,
94
+ S extends Schema | undefined = any,
95
+ M extends true | undefined = true | undefined,
96
+ O extends {
97
+ path: string;
98
+ body?: any;
99
+ searchParams?: any;
100
+ method?: string;
101
+ paginationField?: string;
102
+ } = { path: string },
103
+ > extends RestInstanceBase<F, S, M, O> {
104
+ /** Creates an Endpoint to append the next page extending a list for pagination
105
+ * @see https://dataclient.io/rest/api/RestEndpoint#paginated
106
+ */
107
+ paginated<
108
+ E extends RestInstanceBase<FetchFunction, any, undefined>,
109
+ A extends any[],
110
+ >(
111
+ this: E,
112
+ removeCursor: (...args: A) => readonly [...Parameters<E>],
113
+ ): PaginationEndpoint<E, A>;
114
+ paginated<
115
+ E extends RestInstanceBase<FetchFunction, any, undefined>,
116
+ C extends string,
117
+ >(
118
+ this: E,
119
+ cursorField: C,
120
+ ): PaginationFieldEndpoint<E, C>;
121
+ /** Endpoint to append the next page extending a list for pagination
122
+ * @see https://dataclient.io/rest/api/RestEndpoint#getPage
123
+ */
124
+ getPage: 'paginationField' extends keyof O
125
+ ? O['paginationField'] extends string
126
+ ? PaginationFieldEndpoint<
127
+ F & { schema: S; sideEffect: M } & O,
128
+ O['paginationField']
129
+ >
130
+ : undefined
131
+ : undefined;
132
+ /** Endpoint that pushes (place at end) a newly created entity to this Collection
133
+ * @see https://dataclient.io/rest/api/RestEndpoint#push
134
+ */
135
+ push: AddEndpoint<
136
+ F,
137
+ ExtractCollection<S>['push'],
138
+ Exclude<O, 'body' | 'method'> & {
139
+ body:
140
+ | OptionsToAdderBodyArgument<O>
141
+ | OptionsToAdderBodyArgument<O>[]
142
+ | FormData;
143
+ }
144
+ >;
145
+ /** Endpoint that unshifts (place at start) a newly created entity to this Collection
146
+ * @see https://dataclient.io/rest/api/RestEndpoint#unshift
147
+ */
148
+ unshift: AddEndpoint<
149
+ F,
150
+ ExtractCollection<S>['unshift'],
151
+ Exclude<O, 'body' | 'method'> & {
152
+ body:
153
+ | OptionsToAdderBodyArgument<O>
154
+ | OptionsToAdderBodyArgument<O>[]
155
+ | FormData;
156
+ }
157
+ >;
158
+ /** Endpoint that assigns newly created entities to their respective keys in this Collection
159
+ * @see https://dataclient.io/rest/api/RestEndpoint#assign
160
+ */
161
+ assign: AddEndpoint<
162
+ F,
163
+ ExtractCollection<S>,
164
+ Exclude<O, 'body' | 'method'> & {
165
+ body: Record<string, OptionsToAdderBodyArgument<O>> | FormData;
166
+ }
167
+ >;
168
+ }
169
+
170
+ export type RestEndpointExtendOptions<
171
+ O extends PartialRestGenerics,
172
+ E extends { body?: any; path?: string; schema?: Schema; method?: string },
173
+ F extends FetchFunction,
174
+ > = RestEndpointOptions<
175
+ OptionsToFunction<O, E, F>,
176
+ 'schema' extends keyof O
177
+ ? Extract<O['schema'], Schema | undefined>
178
+ : E['schema']
179
+ > &
180
+ Partial<
181
+ Omit<
182
+ E,
183
+ KeyofRestEndpoint | keyof PartialRestGenerics | keyof RestEndpointOptions
184
+ >
185
+ >;
186
+
187
+ type OptionsToRestEndpoint<
188
+ O extends PartialRestGenerics,
189
+ E extends RestInstanceBase & { body?: any; paginationField?: string },
190
+ F extends FetchFunction,
191
+ > = 'path' extends keyof O
192
+ ? RestType<
193
+ 'searchParams' extends keyof O
194
+ ? O['searchParams'] extends undefined
195
+ ? PathArgs<Exclude<O['path'], undefined>>
196
+ : O['searchParams'] & PathArgs<Exclude<O['path'], undefined>>
197
+ : PathArgs<Exclude<O['path'], undefined>>,
198
+ OptionsToBodyArgument<
199
+ 'body' extends keyof O ? O : E,
200
+ 'method' extends keyof O ? O['method'] : E['method']
201
+ >,
202
+ 'schema' extends keyof O ? O['schema'] : E['schema'],
203
+ 'method' extends keyof O ? MethodToSide<O['method']> : E['sideEffect'],
204
+ O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>,
205
+ {
206
+ path: Exclude<O['path'], undefined>;
207
+ body: 'body' extends keyof O ? O['body'] : E['body'];
208
+ searchParams: 'searchParams' extends keyof O
209
+ ? O['searchParams']
210
+ : E['searchParams'];
211
+ method: 'method' extends keyof O ? O['method'] : E['method'];
212
+ paginationField: 'paginationField' extends keyof O
213
+ ? O['paginationField']
214
+ : E['paginationField'];
215
+ }
216
+ >
217
+ : 'body' extends keyof O
218
+ ? RestType<
219
+ 'searchParams' extends keyof O
220
+ ? O['searchParams'] extends undefined
221
+ ? PathArgs<Exclude<O['path'], undefined>>
222
+ : O['searchParams'] & PathArgs<Exclude<E['path'], undefined>>
223
+ : PathArgs<Exclude<E['path'], undefined>>,
224
+ OptionsToBodyArgument<
225
+ O,
226
+ 'method' extends keyof O ? O['method'] : E['method']
227
+ >,
228
+ 'schema' extends keyof O ? O['schema'] : E['schema'],
229
+ 'method' extends keyof O ? MethodToSide<O['method']> : E['sideEffect'],
230
+ O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>,
231
+ {
232
+ path: E['path'];
233
+ body: O['body'];
234
+ searchParams: 'searchParams' extends keyof O
235
+ ? O['searchParams']
236
+ : E['searchParams'];
237
+ method: 'method' extends keyof O ? O['method'] : E['method'];
238
+ paginationField: 'paginationField' extends keyof O
239
+ ? O['paginationField']
240
+ : Extract<E['paginationField'], string>;
241
+ }
242
+ >
243
+ : 'searchParams' extends keyof O
244
+ ? RestType<
245
+ O['searchParams'] extends undefined
246
+ ? PathArgs<Exclude<O['path'], undefined>>
247
+ : O['searchParams'] & PathArgs<Exclude<E['path'], undefined>>,
248
+ OptionsToBodyArgument<
249
+ E,
250
+ 'method' extends keyof O ? O['method'] : E['method']
251
+ >,
252
+ 'schema' extends keyof O ? O['schema'] : E['schema'],
253
+ 'method' extends keyof O ? MethodToSide<O['method']> : E['sideEffect'],
254
+ O['process'] extends {} ? ReturnType<O['process']> : ResolveType<F>,
255
+ {
256
+ path: E['path'];
257
+ body: E['body'];
258
+ searchParams: O['searchParams'];
259
+ method: 'method' extends keyof O ? O['method'] : E['method'];
260
+ paginationField: 'paginationField' extends keyof O
261
+ ? O['paginationField']
262
+ : Extract<E['paginationField'], string>;
263
+ }
264
+ >
265
+ : RestInstance<
266
+ F,
267
+ 'schema' extends keyof O ? O['schema'] : E['schema'],
268
+ 'method' extends keyof O ? MethodToSide<O['method']> : E['sideEffect'],
269
+ {
270
+ path: 'path' extends keyof O
271
+ ? Exclude<O['path'], undefined>
272
+ : E['path'];
273
+ body: 'body' extends keyof O ? O['body'] : E['body'];
274
+ searchParams: 'searchParams' extends keyof O
275
+ ? O['searchParams']
276
+ : E['searchParams'];
277
+ method: 'method' extends keyof O ? O['method'] : E['method'];
278
+ paginationField: 'paginationField' extends keyof O
279
+ ? O['paginationField']
280
+ : E['paginationField'];
281
+ }
282
+ >;
283
+
284
+ export type RestExtendedEndpoint<
285
+ O extends PartialRestGenerics,
286
+ E extends RestInstanceBase & { getPage?: unknown },
287
+ > = OptionsToRestEndpoint<
288
+ O,
289
+ E &
290
+ (E extends { getPage: { paginationField: string } }
291
+ ? { paginationField: E['getPage']['paginationField'] }
292
+ : unknown),
293
+ RestInstance<
294
+ (
295
+ ...args: Parameters<E>
296
+ ) => O['process'] extends {}
297
+ ? Promise<ReturnType<O['process']>>
298
+ : ReturnType<E>,
299
+ 'schema' extends keyof O ? O['schema'] : E['schema'],
300
+ 'method' extends keyof O ? MethodToSide<O['method']> : E['sideEffect']
301
+ >
302
+ > &
303
+ Omit<O, KeyofRestEndpoint> &
304
+ Omit<E, KeyofRestEndpoint | keyof O>;
305
+
306
+ export interface PartialRestGenerics {
307
+ /** @see https://resthooks.io/rest/api/RestEndpoint#path */
308
+ readonly path?: string;
309
+ /** @see https://resthooks.io/rest/api/RestEndpoint#schema */
310
+ readonly schema?: Schema | undefined;
311
+ /** @see https://resthooks.io/rest/api/RestEndpoint#method */
312
+ readonly method?: string;
313
+ /** Only used for types */
314
+ /** @see https://dataclient.io/rest/api/RestEndpoint#body */
315
+ body?: any;
316
+ /** Only used for types */
317
+ /** @see https://dataclient.io/rest/api/RestEndpoint#searchParams */
318
+ searchParams?: any;
319
+ /** @see https://dataclient.io/rest/api/RestEndpoint#paginationfield */
320
+ readonly paginationField?: string;
321
+ /** @see https://resthooks.io/rest/api/RestEndpoint#process */
322
+ process?(value: any, ...args: any): any;
323
+ }
324
+ export interface RestGenerics extends PartialRestGenerics {
325
+ readonly path: string;
326
+ }
327
+
328
+ export type PaginationEndpoint<
329
+ E extends FetchFunction & RestGenerics & { sideEffect?: true | undefined },
330
+ A extends any[],
331
+ > = RestInstanceBase<
332
+ ParamFetchNoBody<A[0], ResolveType<E>>,
333
+ E['schema'],
334
+ E['sideEffect'],
335
+ Pick<E, 'path' | 'searchParams' | 'body'> & {
336
+ searchParams: Omit<A[0], keyof PathArgs<E['path']>>;
337
+ }
338
+ >;
339
+ export type PaginationFieldEndpoint<
340
+ E extends FetchFunction & RestGenerics & { sideEffect?: true | undefined },
341
+ C extends string,
342
+ > = RestInstanceBase<
343
+ ParamFetchNoBody<
344
+ { [K in C]: string | number | boolean } & E['searchParams'] &
345
+ PathArgs<Exclude<E['path'], undefined>>,
346
+ ResolveType<E>
347
+ >,
348
+ E['schema'],
349
+ E['sideEffect'],
350
+ Pick<E, 'path' | 'searchParams' | 'body'> & {
351
+ searchParams: { [K in C]: string | number | boolean } & E['searchParams'];
352
+ }
353
+ > & { paginationField: C };
354
+ export type AddEndpoint<
355
+ F extends FetchFunction = FetchFunction,
356
+ S extends Schema | undefined = any,
357
+ O extends {
358
+ path: string;
359
+ body: any;
360
+ searchParams?: any;
361
+ } = { path: string; body: any },
362
+ > = RestInstanceBase<
363
+ RestFetch<
364
+ 'searchParams' extends keyof O
365
+ ? O['searchParams'] extends undefined
366
+ ? PathArgs<Exclude<O['path'], undefined>>
367
+ : O['searchParams'] & PathArgs<Exclude<O['path'], undefined>>
368
+ : PathArgs<Exclude<O['path'], undefined>>,
369
+ O['body'],
370
+ ResolveType<F>
371
+ >,
372
+ S,
373
+ true,
374
+ Omit<O, 'method'> & { method: 'POST' }
375
+ >;
376
+
377
+ type OptionsBodyDefault<O extends RestGenerics> = 'body' extends keyof O
378
+ ? O
379
+ : O['method'] extends 'POST' | 'PUT' | 'PATCH'
380
+ ? O & { body: any }
381
+ : O & { body: undefined };
382
+
383
+ type OptionsToAdderBodyArgument<O extends { body?: any }> =
384
+ 'body' extends keyof O ? O['body'] : any;
385
+
386
+ export interface RestEndpointOptions<
387
+ F extends FetchFunction = FetchFunction,
388
+ S extends Schema | undefined = undefined,
389
+ > extends EndpointExtraOptions<F> {
390
+ urlPrefix?: string;
391
+ requestInit?: RequestInit;
392
+ getHeaders?(headers: HeadersInit): Promise<HeadersInit> | HeadersInit;
393
+ getRequestInit?(body: any): Promise<RequestInit> | RequestInit;
394
+ fetchResponse?(input: RequestInfo, init: RequestInit): Promise<any>;
395
+ parseResponse?(response: Response): Promise<any>;
396
+
397
+ sideEffect?: true | undefined;
398
+ name?: string;
399
+ signal?: AbortSignal;
400
+ fetch?: F;
401
+ key?(...args: Parameters<F>): string;
402
+ url?(...args: Parameters<F>): string;
403
+ update?: EndpointUpdateFunction<F, S>;
404
+ }
405
+
406
+ export type RestEndpointConstructorOptions<O extends RestGenerics = any> =
407
+ RestEndpointOptions<
408
+ RestFetch<
409
+ 'searchParams' extends keyof O
410
+ ? O['searchParams'] extends undefined
411
+ ? PathArgs<O['path']>
412
+ : O['searchParams'] & PathArgs<O['path']>
413
+ : PathArgs<O['path']>,
414
+ OptionsToBodyArgument<
415
+ O,
416
+ 'method' extends keyof O
417
+ ? O['method']
418
+ : O extends { sideEffect: true }
419
+ ? 'POST'
420
+ : 'GET'
421
+ >,
422
+ O['process'] extends {}
423
+ ? ReturnType<O['process']>
424
+ : any /*Denormalize<O['schema']>*/
425
+ >,
426
+ O['schema']
427
+ >;
428
+
429
+ export interface RestEndpointConstructor {
430
+ new <O extends RestGenerics = any>({
431
+ method,
432
+ sideEffect,
433
+ name,
434
+ ...options
435
+ }: RestEndpointConstructorOptions<O> & Readonly<O>): RestInstance<
436
+ RestFetch<
437
+ 'searchParams' extends keyof O
438
+ ? O['searchParams'] extends undefined
439
+ ? PathArgs<O['path']>
440
+ : O['searchParams'] & PathArgs<O['path']>
441
+ : PathArgs<O['path']>,
442
+ OptionsToBodyArgument<
443
+ O,
444
+ 'method' extends keyof O
445
+ ? O['method']
446
+ : O extends { sideEffect: true }
447
+ ? 'POST'
448
+ : 'GET'
449
+ >,
450
+ O['process'] extends {}
451
+ ? ReturnType<O['process']>
452
+ : any /*Denormalize<O['schema']>*/
453
+ >,
454
+ 'schema' extends keyof O ? O['schema'] : undefined,
455
+ 'sideEffect' extends keyof O
456
+ ? Extract<O['sideEffect'], undefined | true>
457
+ : MethodToSide<O['method']>,
458
+ 'method' extends keyof O
459
+ ? O
460
+ : O & {
461
+ method: O extends { sideEffect: true } ? 'POST' : 'GET';
462
+ }
463
+ >;
464
+ readonly prototype: RestInstanceBase;
465
+ }
466
+
467
+ export type MethodToSide<M> = M extends string
468
+ ? M extends 'GET'
469
+ ? undefined
470
+ : true
471
+ : undefined;
472
+
473
+ /** RestEndpoint types simplified */
474
+ export type RestType<
475
+ UrlParams = any,
476
+ Body = any,
477
+ S extends Schema | undefined = Schema | undefined,
478
+ M extends true | undefined = true | undefined,
479
+ R = any,
480
+ O extends {
481
+ path: string;
482
+ body?: any;
483
+ searchParams?: any;
484
+ paginationField?: string;
485
+ } = { path: string; paginationField: string },
486
+ // eslint-disable-next-line @typescript-eslint/ban-types
487
+ > = IfTypeScriptLooseNull<
488
+ RestInstance<
489
+ keyof UrlParams extends never
490
+ ? (this: EndpointInstanceInterface, body?: Body) => Promise<R>
491
+ : // even with loose null, this will only be true when all members are optional
492
+ {} extends UrlParams
493
+ ?
494
+ | ((this: EndpointInstanceInterface, body?: Body) => Promise<R>)
495
+ | ((
496
+ this: EndpointInstanceInterface,
497
+ params: UrlParams,
498
+ body?: Body,
499
+ ) => Promise<R>)
500
+ : (
501
+ this: EndpointInstanceInterface,
502
+ params: UrlParams,
503
+ body?: Body,
504
+ ) => Promise<R>,
505
+ S,
506
+ M,
507
+ O
508
+ >,
509
+ Body extends {}
510
+ ? RestTypeWithBody<UrlParams, S, M, Body, R, O>
511
+ : RestTypeNoBody<UrlParams, S, M, R, O>
512
+ >;
513
+
514
+ export type RestTypeWithBody<
515
+ UrlParams = any,
516
+ S extends Schema | undefined = Schema | undefined,
517
+ M extends true | undefined = true | undefined,
518
+ Body = any,
519
+ R = any /*Denormalize<S>*/,
520
+ O extends {
521
+ path: string;
522
+ body?: any;
523
+ searchParams?: any;
524
+ } = { path: string; body: any },
525
+ > = RestInstance<ParamFetchWithBody<UrlParams, Body, R>, S, M, O>;
526
+
527
+ export type RestTypeNoBody<
528
+ UrlParams = any,
529
+ S extends Schema | undefined = Schema | undefined,
530
+ M extends true | undefined = true | undefined,
531
+ R = any /*Denormalize<S>*/,
532
+ O extends {
533
+ path: string;
534
+ body?: undefined;
535
+ searchParams?: any;
536
+ } = { path: string; body: undefined },
537
+ > = RestInstance<ParamFetchNoBody<UrlParams, R>, S, M, O>;
538
+
539
+ /** Simple parameters, and body fetch functions */
540
+ export type RestFetch<
541
+ UrlParams,
542
+ // eslint-disable-next-line @typescript-eslint/ban-types
543
+ Body = {},
544
+ Resolve = any,
545
+ > = IfTypeScriptLooseNull<
546
+ | ParamFetchNoBody<UrlParams, Resolve>
547
+ | ParamFetchWithBody<UrlParams, Body, Resolve>,
548
+ Body extends {}
549
+ ? ParamFetchWithBody<UrlParams, Body, Resolve>
550
+ : ParamFetchNoBody<UrlParams, Resolve>
551
+ >;
552
+
553
+ export type ParamFetchWithBody<P, B = {}, R = any> =
554
+ // we must always allow undefined in a union and give it a type without params
555
+ P extends undefined
556
+ ? (this: EndpointInstanceInterface, body: B) => Promise<R>
557
+ : // even with loose null, this will only be true when all members are optional
558
+ {} extends P
559
+ ? // this safely handles PathArgs with no members that results in a simple `unknown` type
560
+ keyof P extends never
561
+ ? (this: EndpointInstanceInterface, body: B) => Promise<R>
562
+ :
563
+ | ((
564
+ this: EndpointInstanceInterface,
565
+ params: P,
566
+ body: B,
567
+ ) => Promise<R>)
568
+ | ((this: EndpointInstanceInterface, body: B) => Promise<R>)
569
+ : (this: EndpointInstanceInterface, params: P, body: B) => Promise<R>;
570
+
571
+ export type ParamFetchNoBody<P, R = any> =
572
+ // we must always allow undefined in a union and give it a type without params
573
+ P extends undefined
574
+ ? (this: EndpointInstanceInterface) => Promise<R>
575
+ : // even with loose null, this will only be true when all members are optional
576
+ {} extends P
577
+ ? // this safely handles PathArgs with no members that results in a simple `unknown` type
578
+ keyof P extends never
579
+ ? (this: EndpointInstanceInterface) => Promise<R>
580
+ :
581
+ | ((this: EndpointInstanceInterface, params: P) => Promise<R>)
582
+ | ((this: EndpointInstanceInterface) => Promise<R>)
583
+ : (this: EndpointInstanceInterface, params: P) => Promise<R>;
584
+
585
+ type IfTypeScriptLooseNull<Y, N> = 1 | undefined extends 1 ? Y : N;
586
+
587
+ export type KeyofRestEndpoint = keyof RestInstance;
588
+
589
+ export type FromFallBack<K extends keyof E, O, E> = K extends keyof O
590
+ ? O[K]
591
+ : E[K];
592
+
593
+ export type FetchMutate<
594
+ A extends readonly any[] = // eslint-disable-next-line @typescript-eslint/ban-types
595
+ | [any, {}]
596
+ // eslint-disable-next-line @typescript-eslint/ban-types
597
+ | [{}],
598
+ R = any,
599
+ > = (this: RestInstance, ...args: A) => Promise<R>;
600
+
601
+ export type FetchGet<A extends readonly any[] = [any], R = any> = (
602
+ this: RestInstance,
603
+ ...args: A
604
+ ) => Promise<R>;
605
+
606
+ export type Defaults<O, D> = {
607
+ [K in keyof O | keyof D]: K extends keyof O
608
+ ? Exclude<O[K], undefined>
609
+ : D[Extract<K, keyof D>];
610
+ };
611
+
612
+ export type GetEndpoint<
613
+ O extends {
614
+ readonly path: string;
615
+ readonly schema: Schema;
616
+ /** Only used for types */
617
+ readonly searchParams?: any;
618
+ readonly paginationField?: string;
619
+ } = {
620
+ path: string;
621
+ schema: Schema;
622
+ },
623
+ > = RestTypeNoBody<
624
+ 'searchParams' extends keyof O
625
+ ? O['searchParams'] extends undefined
626
+ ? PathArgs<O['path']>
627
+ : O['searchParams'] & PathArgs<O['path']>
628
+ : PathArgs<O['path']>,
629
+ O['schema'],
630
+ undefined,
631
+ any,
632
+ O & { method: 'GET' }
633
+ >;
634
+
635
+ export type MutateEndpoint<
636
+ O extends {
637
+ readonly path: string;
638
+ readonly schema: Schema;
639
+ /** Only used for types */
640
+ readonly searchParams?: any;
641
+ /** Only used for types */
642
+ readonly body?: any;
643
+ } = {
644
+ path: string;
645
+ body: any;
646
+ schema: Schema;
647
+ },
648
+ > = RestTypeWithBody<
649
+ 'searchParams' extends keyof O
650
+ ? O['searchParams'] extends undefined
651
+ ? PathArgs<O['path']>
652
+ : O['searchParams'] & PathArgs<O['path']>
653
+ : PathArgs<O['path']>,
654
+ O['schema'],
655
+ true,
656
+ O['body'],
657
+ any,
658
+ O & { body: any; method: 'POST' | 'PUT' | 'PATCH' | 'DELETE' }
659
+ >;
@@ -138,7 +138,7 @@ export default function createResource<O extends ResourceGenerics>({
138
138
  function optimisticUpdate(snap: SnapshotInterface, params: any, body: any) {
139
139
  return {
140
140
  ...params,
141
- ...ensureBodyPojo(body),
141
+ ...ensurePojo(body),
142
142
  };
143
143
  }
144
144
  function optimisticPartial(
@@ -151,14 +151,14 @@ function optimisticPartial(
151
151
  ...params,
152
152
  ...data,
153
153
  // even tho we don't always have two arguments, the extra one will simply be undefined which spreads fine
154
- ...ensureBodyPojo(body),
154
+ ...ensurePojo(body),
155
155
  };
156
156
  };
157
157
  }
158
158
  function optimisticDelete(snap: SnapshotInterface, params: any) {
159
159
  return params;
160
160
  }
161
- function ensureBodyPojo(body: any) {
161
+ function ensurePojo(body: any) {
162
162
  return body instanceof FormData
163
163
  ? Object.fromEntries((body as any).entries())
164
164
  : body;
package/src/index.ts CHANGED
@@ -23,6 +23,12 @@ export type {
23
23
  export { default as createResource } from './createResource.js';
24
24
  export type { Resource } from './resourceTypes.js';
25
25
  export type { ResourceOptions, ResourceGenerics } from './resourceTypes.js';
26
+ export type {
27
+ ResourceExtension,
28
+ ResourceEndpointExtensions,
29
+ CustomResource,
30
+ ExtendedResource,
31
+ } from './resourceExtensionTypes.js';
26
32
  export { default as hookifyResource } from './hookifyResource.js';
27
33
  export type {
28
34
  HookResource,