File tree Expand file tree Collapse file tree 4 files changed +97
-17
lines changed Expand file tree Collapse file tree 4 files changed +97
-17
lines changed Original file line number Diff line number Diff line change @@ -2,4 +2,5 @@ node_modules
2
2
browser
3
3
* .js
4
4
* .js.map
5
- * .d.ts
5
+ * .d.ts
6
+ ! index.d.ts
Original file line number Diff line number Diff line change @@ -20,13 +20,25 @@ export const makeApi = <Data extends ApiData>({
20
20
Object . keys ( headers ) . forEach ( key => fetchHeaders . set ( key , headers [ key ] ) ) ;
21
21
}
22
22
}
23
- return ( action , payload ) =>
24
- fetch ( endpoint , {
25
- method : "POST" ,
26
- headers : fetchHeaders ,
27
- body : JSON . stringify ( {
28
- action,
29
- payload
30
- } )
31
- } ) . then ( r => r . json ( ) ) ;
23
+ return ( action , payload ) => {
24
+ try {
25
+ const controller = new AbortController ( ) ;
26
+ const signal = controller . signal ;
27
+ const promise = fetch ( endpoint , {
28
+ signal,
29
+ method : "POST" ,
30
+ headers : fetchHeaders ,
31
+ body : JSON . stringify ( {
32
+ action,
33
+ payload
34
+ } )
35
+ } ) . then ( r => r . json ( ) ) ;
36
+ Object . defineProperty ( promise , "abort" , {
37
+ value : ( ) => controller . abort ( )
38
+ } ) ;
39
+ return promise ;
40
+ } catch ( err ) {
41
+ return Promise . reject ( err ) ;
42
+ }
43
+ } ;
32
44
} ;
Original file line number Diff line number Diff line change
1
+ export type ActionFunction < Payload = any , Output = any , Context = any > = (
2
+ payload : Payload ,
3
+ context : Context
4
+ ) => Promise < Output > ;
5
+
6
+ export type Unpacked < T > = T extends Promise < infer U > ? U : T ;
7
+
8
+ export type Payload < T extends ActionFunction > = T extends (
9
+ p : infer P ,
10
+ c : any
11
+ ) => any
12
+ ? P
13
+ : never ;
14
+
15
+ export type Output < T extends ActionFunction > = T extends (
16
+ p : any ,
17
+ c : any
18
+ ) => infer R
19
+ ? R
20
+ : never ;
21
+
22
+ export type ApiData = { [ key : string ] : ActionFunction } ;
23
+
24
+ export type PromiseA < T > = Promise < T > & {
25
+ abort ?: ( ) => void ;
26
+ } ;
27
+
28
+ export type ApiResolver < D extends ApiData > = < N extends keyof D > (
29
+ name : N ,
30
+ payload : Payload < D [ N ] >
31
+ ) => PromiseA < Unpacked < Output < D [ N ] > > > ;
Original file line number Diff line number Diff line change 1
- import { ApiResolver , ApiData } from "@webcarrot/api" ;
1
+ import {
2
+ ApiResolver ,
3
+ ApiData ,
4
+ Payload ,
5
+ PromiseA ,
6
+ Unpacked ,
7
+ Output
8
+ } from "@webcarrot/api" ;
9
+
10
+ const makeError = ( ) => {
11
+ const error = new Error ( "Action aborted" ) ;
12
+ error . name === "AbortError" ;
13
+ return error ;
14
+ } ;
2
15
3
16
export const makeApi = < Data extends ApiData , Context > ( {
4
17
actions,
5
18
context
6
19
} : {
7
20
actions : Data ;
8
21
context : Context ;
9
- } ) : ApiResolver < Data > => async ( action , payload ) => {
10
- if ( action in actions ) {
11
- return await actions [ action ] ( payload , context ) ;
12
- } else {
13
- throw new Error ( `Unknown action ${ action } ` ) ;
14
- }
22
+ } ) : ApiResolver < Data > => < N extends keyof Data > (
23
+ action : N ,
24
+ payload : Payload < Data [ N ] >
25
+ ) : PromiseA < Unpacked < Output < Data [ N ] > > > => {
26
+ let aborted = false ;
27
+ const promise = new Promise < Unpacked < Output < Data [ N ] > > > ( ( resolve , reject ) => {
28
+ if ( aborted ) {
29
+ reject ( makeError ( ) ) ;
30
+ } else if ( action in actions ) {
31
+ actions [ action ] ( payload , context ) . then (
32
+ data => {
33
+ if ( ! aborted ) {
34
+ resolve ( data ) ;
35
+ } else {
36
+ reject ( makeError ( ) ) ;
37
+ }
38
+ } ,
39
+ err => reject ( aborted ? makeError ( ) : err )
40
+ ) ;
41
+ } else {
42
+ reject ( new Error ( `Unknown action ${ action } ` ) ) ;
43
+ }
44
+ } ) ;
45
+ Object . defineProperty ( promise , "abort" , {
46
+ value : ( ) => {
47
+ aborted = true ;
48
+ }
49
+ } ) ;
50
+ return promise ;
15
51
} ;
You can’t perform that action at this time.
0 commit comments