@kibinrpc/client 0.0.4 → 0.1.0
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 +17 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -38
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -11,15 +11,15 @@ npm install @kibinrpc/client
|
|
|
11
11
|
## Quick start
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import { createKibinClient } from
|
|
15
|
-
import type { AppRouter } from
|
|
14
|
+
import { createKibinClient } from "@kibinrpc/client"
|
|
15
|
+
import type { AppRouter } from "./server/router"
|
|
16
16
|
|
|
17
17
|
const client = createKibinClient<AppRouter>({
|
|
18
|
-
baseUrl:
|
|
18
|
+
baseUrl: "/api/rpc",
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
// Return types are inferred from the server — no manual annotations
|
|
22
|
-
const user = await client.user.getUser(
|
|
22
|
+
const user = await client.user.getUser("1")
|
|
23
23
|
const posts = await client.post.listPosts()
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -35,7 +35,7 @@ const [users, posts] = await Promise.all([
|
|
|
35
35
|
])
|
|
36
36
|
|
|
37
37
|
// Sequential calls → two separate requests
|
|
38
|
-
const user = await client.user.getUser(
|
|
38
|
+
const user = await client.user.getUser("1")
|
|
39
39
|
const posts = await client.post.listPosts()
|
|
40
40
|
```
|
|
41
41
|
|
|
@@ -45,11 +45,11 @@ No configuration required. The server receives either a single object or an arra
|
|
|
45
45
|
|
|
46
46
|
```ts
|
|
47
47
|
const client = createKibinClient<AppRouter>({
|
|
48
|
-
baseUrl:
|
|
48
|
+
baseUrl: "/api/rpc",
|
|
49
49
|
|
|
50
50
|
// Static headers sent with every request
|
|
51
51
|
headers: {
|
|
52
|
-
|
|
52
|
+
"X-App-Version": "1.0.0",
|
|
53
53
|
},
|
|
54
54
|
|
|
55
55
|
// Retry on network errors and 5xx responses
|
|
@@ -100,8 +100,8 @@ Runs on every failed call (after retries are exhausted). Return a fallback value
|
|
|
100
100
|
```ts
|
|
101
101
|
interceptors: {
|
|
102
102
|
error({ error }) {
|
|
103
|
-
if (error.code ===
|
|
104
|
-
window.location.href =
|
|
103
|
+
if (error.code === "UNAUTHORIZED") {
|
|
104
|
+
window.location.href = "/login"
|
|
105
105
|
}
|
|
106
106
|
throw error
|
|
107
107
|
},
|
|
@@ -111,14 +111,14 @@ interceptors: {
|
|
|
111
111
|
## Error handling
|
|
112
112
|
|
|
113
113
|
```ts
|
|
114
|
-
import { isKibinError } from
|
|
114
|
+
import { isKibinError } from "@kibinrpc/client"
|
|
115
115
|
|
|
116
116
|
try {
|
|
117
|
-
await client.user.getUser(
|
|
117
|
+
await client.user.getUser("999")
|
|
118
118
|
} catch (err) {
|
|
119
119
|
if (isKibinError(err)) {
|
|
120
|
-
console.log(err.code) // e.g.
|
|
121
|
-
console.log(err.message) // e.g.
|
|
120
|
+
console.log(err.code) // e.g. "NOT_FOUND"
|
|
121
|
+
console.log(err.message) // e.g. "User not found"
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
```
|
|
@@ -138,9 +138,9 @@ try {
|
|
|
138
138
|
Returns a typed proxy. Every namespace from your router becomes a property, every registered action becomes an async method.
|
|
139
139
|
|
|
140
140
|
```ts
|
|
141
|
-
const client = createKibinClient<AppRouter>({ baseUrl:
|
|
141
|
+
const client = createKibinClient<AppRouter>({ baseUrl: "/api/rpc" })
|
|
142
142
|
|
|
143
|
-
client.user.getUser(
|
|
143
|
+
client.user.getUser("1") // Promise<User>
|
|
144
144
|
client.post.listPosts() // Promise<Post[]>
|
|
145
145
|
```
|
|
146
146
|
|
|
@@ -149,7 +149,7 @@ client.post.listPosts() // Promise<Post[]>
|
|
|
149
149
|
Type guard for `KibinError`:
|
|
150
150
|
|
|
151
151
|
```ts
|
|
152
|
-
import { isKibinError, KibinError } from
|
|
152
|
+
import { isKibinError, KibinError } from "@kibinrpc/client"
|
|
153
153
|
|
|
154
154
|
isKibinError(err) // err is KibinError
|
|
155
155
|
err.code // string
|
|
@@ -167,5 +167,5 @@ import type {
|
|
|
167
167
|
ResponseCtx,
|
|
168
168
|
ErrorCtx,
|
|
169
169
|
RetryConfig,
|
|
170
|
-
} from
|
|
170
|
+
} from "@kibinrpc/client"
|
|
171
171
|
```
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/client.ts"],"mappings":";cAAa,UAAA,SAAmB,KAAK;EAAA,SAC3B,IAAA;cAEG,IAAA,UAAc,OAAA;AAAA;AAAA,iBAOX,YAAA,CAAa,KAAA,YAAiB,KAAA,IAAS,UAAU;;;KCR5D,cAAA,MAAoB,CAAA,cAAc,IAAA,qCAChC,IAAA,EAAM,IAAA,KAAS,OAAA,CAAQ,OAAA,CAAQ,MAAA;AAAA,KAGjC,aAAA,oBACQ,CAAA,IAAK,CAAA,CAAE,CAAA,eAAe,IAAA,yBAA4B,CAAA,WAAY,cAAA,CAAe,CAAA,CAAE,CAAA;AAAA,KAGvF,eAAA,MAAqB,CAAC;EAAW,QAAA;AAAA,IAAsB,CAAA;AAAA,KAEhD,WAAA,yBACC,eAAA,CAAgB,MAAA,IAAU,aAAA,CAAc,eAAA,CAAgB,MAAA,EAAQ,CAAA;AAAA,UAG5D,UAAA;EAChB,SAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,UAGgB,WAAA,SAAoB,UAAU;EAC9C,IAAI;AAAA;AAAA,UAGY,QAAA,SAAiB,UAAU;EAC3C,KAAA,EAAO,UAAA;AAAA;AAAA,UAGS,kBAAA;EAChB,OAAA,IAAW,GAAA,EAAK,UAAA,KAAe,UAAA,GAAa,OAAA,CAAQ,UAAA;EACpD,QAAA,IAAY,GAAA,EAAK,WAAA,eAA0B,OAAA;EAC3C,KAAA,IAAS,GAAA,EAAK,QAAA,eAAuB,OAAA;AAAA;AAAA,UAGrB,WAAA;EAjCJ;EAmCZ,QAAA;EAnC6B;EAqC7B,KAAK;AAAA;AAAA,UAGW,iBAAA;EAChB,OAAA;EACA,OAAA,GAAU,MAAA;EACV,KAAA,GAAQ,WAAA;EACR,YAAA,GAAe,kBAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/client.ts"],"mappings":";cAAa,UAAA,SAAmB,KAAK;EAAA,SAC3B,IAAA;cAEG,IAAA,UAAc,OAAA;AAAA;AAAA,iBAOX,YAAA,CAAa,KAAA,YAAiB,KAAA,IAAS,UAAU;;;KCR5D,cAAA,MAAoB,CAAA,cAAc,IAAA,qCAChC,IAAA,EAAM,IAAA,KAAS,OAAA,CAAQ,OAAA,CAAQ,MAAA;AAAA,KAGjC,aAAA,oBACQ,CAAA,IAAK,CAAA,CAAE,CAAA,eAAe,IAAA,yBAA4B,CAAA,WAAY,cAAA,CAAe,CAAA,CAAE,CAAA;AAAA,KAGvF,eAAA,MAAqB,CAAC;EAAW,QAAA;AAAA,IAAsB,CAAA;AAAA,KAEhD,WAAA,yBACC,eAAA,CAAgB,MAAA,IAAU,aAAA,CAAc,eAAA,CAAgB,MAAA,EAAQ,CAAA;AAAA,UAG5D,UAAA;EAChB,SAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,UAGgB,WAAA,SAAoB,UAAU;EAC9C,IAAI;AAAA;AAAA,UAGY,QAAA,SAAiB,UAAU;EAC3C,KAAA,EAAO,UAAA;AAAA;AAAA,UAGS,kBAAA;EAChB,OAAA,IAAW,GAAA,EAAK,UAAA,KAAe,UAAA,GAAa,OAAA,CAAQ,UAAA;EACpD,QAAA,IAAY,GAAA,EAAK,WAAA,eAA0B,OAAA;EAC3C,KAAA,IAAS,GAAA,EAAK,QAAA,eAAuB,OAAA;AAAA;AAAA,UAGrB,WAAA;EAjCJ;EAmCZ,QAAA;EAnC6B;EAqC7B,KAAK;AAAA;AAAA,UAGW,iBAAA;EAChB,OAAA;EACA,OAAA,GAAU,MAAA;EACV,KAAA,GAAQ,WAAA;EACR,YAAA,GAAe,kBAAA;AAAA;;;iBC9BA,iBAAA,QAAA,CAA0B,MAAA,EAAQ,iBAAA,GAAoB,WAAA,CAAY,MAAA"}
|
package/dist/index.js
CHANGED
|
@@ -16,12 +16,40 @@ const RETRY_DEFAULTS = {
|
|
|
16
16
|
attempts: 3,
|
|
17
17
|
delay: 300
|
|
18
18
|
};
|
|
19
|
+
function rpcError(error) {
|
|
20
|
+
return new KibinError(error.code ?? "RPC_ERROR", error.message ?? "RPC Error");
|
|
21
|
+
}
|
|
22
|
+
function sleep(attempt, baseDelay) {
|
|
23
|
+
return new Promise((r) => setTimeout(r, baseDelay * 2 ** (attempt - 1)));
|
|
24
|
+
}
|
|
19
25
|
function createKibinClient(config) {
|
|
20
26
|
const maxAttempts = config.retry?.attempts ?? RETRY_DEFAULTS.attempts;
|
|
21
27
|
const baseDelay = config.retry?.delay ?? RETRY_DEFAULTS.delay;
|
|
22
28
|
const { interceptors } = config;
|
|
23
29
|
let pendingBatch = [];
|
|
24
30
|
let flushScheduled = false;
|
|
31
|
+
async function settleError(item, err) {
|
|
32
|
+
if (interceptors?.error) try {
|
|
33
|
+
item.resolve(await interceptors.error({
|
|
34
|
+
...item.ctx,
|
|
35
|
+
error: err
|
|
36
|
+
}));
|
|
37
|
+
} catch (interceptorError) {
|
|
38
|
+
item.reject(interceptorError);
|
|
39
|
+
}
|
|
40
|
+
else item.reject(err);
|
|
41
|
+
}
|
|
42
|
+
async function settleSuccess(item, data) {
|
|
43
|
+
if (interceptors?.response) try {
|
|
44
|
+
item.resolve(await interceptors.response({
|
|
45
|
+
...item.ctx,
|
|
46
|
+
data
|
|
47
|
+
}));
|
|
48
|
+
} catch (interceptorError) {
|
|
49
|
+
item.reject(interceptorError);
|
|
50
|
+
}
|
|
51
|
+
else item.resolve(data);
|
|
52
|
+
}
|
|
25
53
|
async function rpcCall(namespace, method, args) {
|
|
26
54
|
let ctx = {
|
|
27
55
|
namespace,
|
|
@@ -50,10 +78,9 @@ function createKibinClient(config) {
|
|
|
50
78
|
else flushBatch(batch);
|
|
51
79
|
}
|
|
52
80
|
async function flushSingle(item) {
|
|
53
|
-
const { ctx } = item;
|
|
54
81
|
let lastError;
|
|
55
82
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
56
|
-
if (attempt > 0) await
|
|
83
|
+
if (attempt > 0) await sleep(attempt, baseDelay);
|
|
57
84
|
try {
|
|
58
85
|
const response = await fetch(config.baseUrl, {
|
|
59
86
|
method: "POST",
|
|
@@ -61,47 +88,32 @@ function createKibinClient(config) {
|
|
|
61
88
|
"Content-Type": "application/json",
|
|
62
89
|
...config.headers
|
|
63
90
|
},
|
|
64
|
-
body: JSON.stringify(ctx)
|
|
91
|
+
body: JSON.stringify(item.ctx)
|
|
65
92
|
});
|
|
66
93
|
const result = await response.json();
|
|
67
94
|
if (result.error) {
|
|
68
|
-
const err =
|
|
95
|
+
const err = rpcError(result.error);
|
|
69
96
|
if (response.status >= 500) {
|
|
70
97
|
lastError = err;
|
|
71
98
|
continue;
|
|
72
99
|
}
|
|
73
|
-
|
|
74
|
-
...ctx,
|
|
75
|
-
error: err
|
|
76
|
-
}));
|
|
77
|
-
else item.reject(err);
|
|
100
|
+
await settleError(item, err);
|
|
78
101
|
return;
|
|
79
102
|
}
|
|
80
|
-
|
|
81
|
-
...ctx,
|
|
82
|
-
data: result.data
|
|
83
|
-
}));
|
|
84
|
-
else item.resolve(result.data);
|
|
103
|
+
await settleSuccess(item, result.data);
|
|
85
104
|
return;
|
|
86
105
|
} catch (err) {
|
|
87
|
-
if (err instanceof KibinError) {
|
|
88
|
-
item.reject(err);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
106
|
lastError = err;
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
|
-
if (lastError instanceof KibinError
|
|
95
|
-
...ctx,
|
|
96
|
-
error: lastError
|
|
97
|
-
}));
|
|
109
|
+
if (lastError instanceof KibinError) await settleError(item, lastError);
|
|
98
110
|
else item.reject(lastError);
|
|
99
111
|
}
|
|
100
112
|
async function flushBatch(batch) {
|
|
101
113
|
let pending = [...batch];
|
|
102
114
|
const lastErrors = /* @__PURE__ */ new Map();
|
|
103
115
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
104
|
-
if (attempt > 0) await
|
|
116
|
+
if (attempt > 0) await sleep(attempt, baseDelay);
|
|
105
117
|
let results;
|
|
106
118
|
try {
|
|
107
119
|
results = await (await fetch(config.baseUrl, {
|
|
@@ -121,35 +133,26 @@ function createKibinClient(config) {
|
|
|
121
133
|
const result = results[i];
|
|
122
134
|
const item = pending[i];
|
|
123
135
|
if (result?.error) {
|
|
124
|
-
const err =
|
|
136
|
+
const err = rpcError(result.error);
|
|
125
137
|
if (result.status >= 500) {
|
|
126
138
|
retryItems.push(item);
|
|
127
139
|
lastErrors.set(item, err);
|
|
128
|
-
} else
|
|
129
|
-
|
|
130
|
-
error: err
|
|
131
|
-
}));
|
|
132
|
-
else item.reject(err);
|
|
133
|
-
} else if (interceptors?.response) item.resolve(await interceptors.response({
|
|
134
|
-
...item.ctx,
|
|
135
|
-
data: result?.data
|
|
136
|
-
}));
|
|
137
|
-
else item.resolve(result?.data);
|
|
140
|
+
} else await settleError(item, err);
|
|
141
|
+
} else await settleSuccess(item, result?.data);
|
|
138
142
|
}
|
|
139
143
|
pending = retryItems;
|
|
140
144
|
if (pending.length === 0) break;
|
|
141
145
|
}
|
|
142
146
|
for (const item of pending) {
|
|
143
147
|
const err = lastErrors.get(item);
|
|
144
|
-
if (err instanceof KibinError
|
|
145
|
-
...item.ctx,
|
|
146
|
-
error: err
|
|
147
|
-
}));
|
|
148
|
+
if (err instanceof KibinError) await settleError(item, err);
|
|
148
149
|
else item.reject(err);
|
|
149
150
|
}
|
|
150
151
|
}
|
|
151
152
|
return new Proxy({}, { get(_, key) {
|
|
153
|
+
if (typeof key !== "string") return void 0;
|
|
152
154
|
return new Proxy({}, { get(_, method) {
|
|
155
|
+
if (typeof method !== "string") return void 0;
|
|
153
156
|
return (...args) => rpcCall(key, method, args);
|
|
154
157
|
} });
|
|
155
158
|
} });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["export class KibinError extends Error {\n\treadonly code: string;\n\n\tconstructor(code: string, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'KibinError';\n\t\tthis.code = code;\n\t}\n}\n\nexport function isKibinError(error: unknown): error is KibinError {\n\treturn error instanceof KibinError;\n}\n","import { KibinError } from './errors.js';\nimport type { KibinClient, KibinClientConfig, RequestCtx } from './types.js';\n\nconst RETRY_DEFAULTS = { attempts: 3, delay: 300 };\n\ntype RpcResult = { data?: unknown; error?: { code?: string; message?: string } };\ntype BatchRpcResult = RpcResult & { status: number };\ntype QueueItem = { ctx: RequestCtx; resolve: (v: unknown) => void; reject: (e: unknown) => void };\n\nexport function createKibinClient<Router>(config: KibinClientConfig): KibinClient<Router> {\n\tconst maxAttempts = config.retry?.attempts ?? RETRY_DEFAULTS.attempts;\n\tconst baseDelay = config.retry?.delay ?? RETRY_DEFAULTS.delay;\n\tconst { interceptors } = config;\n\n\tlet pendingBatch: QueueItem[] = [];\n\tlet flushScheduled = false;\n\n\tasync function rpcCall(namespace: string, method: string, args: unknown[]): Promise<unknown> {\n\t\tlet ctx: RequestCtx = { namespace, method, args };\n\n\t\tif (interceptors?.request) {\n\t\t\tctx = await interceptors.request(ctx);\n\t\t}\n\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tpendingBatch.push({ ctx, resolve, reject });\n\t\t\tif (!flushScheduled) {\n\t\t\t\tflushScheduled = true;\n\t\t\t\tqueueMicrotask(flush);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction flush() {\n\t\tconst batch = pendingBatch;\n\t\tpendingBatch = [];\n\t\tflushScheduled = false;\n\n\t\tif (batch.length === 0) return;\n\t\tif (batch.length === 1) {\n\t\t\tflushSingle(batch[0]);\n\t\t} else {\n\t\t\tflushBatch(batch);\n\t\t}\n\t}\n\n\tasync function flushSingle(item: QueueItem) {\n\t\
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["export class KibinError extends Error {\n\treadonly code: string;\n\n\tconstructor(code: string, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'KibinError';\n\t\tthis.code = code;\n\t}\n}\n\nexport function isKibinError(error: unknown): error is KibinError {\n\treturn error instanceof KibinError;\n}\n","import { KibinError } from './errors.js';\nimport type { KibinClient, KibinClientConfig, RequestCtx } from './types.js';\n\nconst RETRY_DEFAULTS = { attempts: 3, delay: 300 };\n\ntype RpcResult = { data?: unknown; error?: { code?: string; message?: string } };\ntype BatchRpcResult = RpcResult & { status: number };\ntype QueueItem = { ctx: RequestCtx; resolve: (v: unknown) => void; reject: (e: unknown) => void };\n\nfunction rpcError(error: { code?: string; message?: string }): KibinError {\n\treturn new KibinError(error.code ?? 'RPC_ERROR', error.message ?? 'RPC Error');\n}\n\nfunction sleep(attempt: number, baseDelay: number): Promise<void> {\n\treturn new Promise<void>((r) => setTimeout(r, baseDelay * 2 ** (attempt - 1)));\n}\n\nexport function createKibinClient<Router>(config: KibinClientConfig): KibinClient<Router> {\n\tconst maxAttempts = config.retry?.attempts ?? RETRY_DEFAULTS.attempts;\n\tconst baseDelay = config.retry?.delay ?? RETRY_DEFAULTS.delay;\n\tconst { interceptors } = config;\n\n\tlet pendingBatch: QueueItem[] = [];\n\tlet flushScheduled = false;\n\n\tasync function settleError(item: QueueItem, err: KibinError): Promise<void> {\n\t\tif (interceptors?.error) {\n\t\t\ttry {\n\t\t\t\titem.resolve(await interceptors.error({ ...item.ctx, error: err }));\n\t\t\t} catch (interceptorError) {\n\t\t\t\titem.reject(interceptorError);\n\t\t\t}\n\t\t} else {\n\t\t\titem.reject(err);\n\t\t}\n\t}\n\n\tasync function settleSuccess(item: QueueItem, data: unknown): Promise<void> {\n\t\tif (interceptors?.response) {\n\t\t\ttry {\n\t\t\t\titem.resolve(await interceptors.response({ ...item.ctx, data }));\n\t\t\t} catch (interceptorError) {\n\t\t\t\titem.reject(interceptorError);\n\t\t\t}\n\t\t} else {\n\t\t\titem.resolve(data);\n\t\t}\n\t}\n\n\tasync function rpcCall(namespace: string, method: string, args: unknown[]): Promise<unknown> {\n\t\tlet ctx: RequestCtx = { namespace, method, args };\n\n\t\tif (interceptors?.request) {\n\t\t\tctx = await interceptors.request(ctx);\n\t\t}\n\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tpendingBatch.push({ ctx, resolve, reject });\n\t\t\tif (!flushScheduled) {\n\t\t\t\tflushScheduled = true;\n\t\t\t\tqueueMicrotask(flush);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction flush() {\n\t\tconst batch = pendingBatch;\n\t\tpendingBatch = [];\n\t\tflushScheduled = false;\n\n\t\tif (batch.length === 0) return;\n\t\tif (batch.length === 1) {\n\t\t\tflushSingle(batch[0]);\n\t\t} else {\n\t\t\tflushBatch(batch);\n\t\t}\n\t}\n\n\tasync function flushSingle(item: QueueItem) {\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 0; attempt < maxAttempts; attempt++) {\n\t\t\tif (attempt > 0) await sleep(attempt, baseDelay);\n\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(config.baseUrl, {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'Content-Type': 'application/json', ...config.headers },\n\t\t\t\t\tbody: JSON.stringify(item.ctx),\n\t\t\t\t});\n\n\t\t\t\tconst result = (await response.json()) as RpcResult;\n\n\t\t\t\tif (result.error) {\n\t\t\t\t\tconst err = rpcError(result.error);\n\t\t\t\t\tif (response.status >= 500) {\n\t\t\t\t\t\tlastError = err;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tawait settleError(item, err);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tawait settleSuccess(item, result.data);\n\t\t\t\treturn;\n\t\t\t} catch (err) {\n\t\t\t\tlastError = err;\n\t\t\t}\n\t\t}\n\n\t\tif (lastError instanceof KibinError) {\n\t\t\tawait settleError(item, lastError);\n\t\t} else {\n\t\t\titem.reject(lastError);\n\t\t}\n\t}\n\n\tasync function flushBatch(batch: QueueItem[]) {\n\t\tlet pending = [...batch];\n\t\tconst lastErrors = new Map<QueueItem, unknown>();\n\n\t\tfor (let attempt = 0; attempt < maxAttempts; attempt++) {\n\t\t\tif (attempt > 0) await sleep(attempt, baseDelay);\n\n\t\t\tlet results: BatchRpcResult[];\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(config.baseUrl, {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'Content-Type': 'application/json', ...config.headers },\n\t\t\t\t\tbody: JSON.stringify(pending.map((item) => item.ctx)),\n\t\t\t\t});\n\t\t\t\tresults = (await response.json()) as BatchRpcResult[];\n\t\t\t} catch (err) {\n\t\t\t\tfor (const item of pending) lastErrors.set(item, err);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst retryItems: QueueItem[] = [];\n\n\t\t\tfor (let i = 0; i < pending.length; i++) {\n\t\t\t\tconst result = results[i];\n\t\t\t\tconst item = pending[i];\n\n\t\t\t\tif (result?.error) {\n\t\t\t\t\tconst err = rpcError(result.error);\n\t\t\t\t\tif (result.status >= 500) {\n\t\t\t\t\t\tretryItems.push(item);\n\t\t\t\t\t\tlastErrors.set(item, err);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait settleError(item, err);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tawait settleSuccess(item, result?.data);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpending = retryItems;\n\t\t\tif (pending.length === 0) break;\n\t\t}\n\n\t\tfor (const item of pending) {\n\t\t\tconst err = lastErrors.get(item);\n\t\t\tif (err instanceof KibinError) {\n\t\t\t\tawait settleError(item, err);\n\t\t\t} else {\n\t\t\t\titem.reject(err);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn new Proxy(\n\t\t{},\n\t\t{\n\t\t\tget(_, key) {\n\t\t\t\tif (typeof key !== 'string') return undefined;\n\t\t\t\treturn new Proxy(\n\t\t\t\t\t{},\n\t\t\t\t\t{\n\t\t\t\t\t\tget(_, method) {\n\t\t\t\t\t\t\tif (typeof method !== 'string') return undefined;\n\t\t\t\t\t\t\treturn (...args: unknown[]) => rpcCall(key, method, args);\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t},\n\t\t},\n\t) as unknown as KibinClient<Router>;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kibinrpc/client",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Type-safe and developer-friendly RPC client with end-to-end type inference",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ixexel661",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsdown",
|
|
36
|
-
"dev": "tsdown --watch"
|
|
36
|
+
"dev": "tsdown --watch",
|
|
37
|
+
"test": "vitest run"
|
|
37
38
|
}
|
|
38
39
|
}
|