@kibinrpc/client 0.0.2 → 0.0.3
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/dist/index.d.ts +38 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +98 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,53 @@
|
|
|
1
|
+
//#region src/errors.d.ts
|
|
2
|
+
declare class KibinError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
constructor(code: string, message: string);
|
|
5
|
+
}
|
|
6
|
+
declare function isKibinError(error: unknown): error is KibinError;
|
|
7
|
+
//#endregion
|
|
1
8
|
//#region src/types.d.ts
|
|
2
9
|
type AsyncifyMethod<T> = T extends ((...args: infer Args) => infer Return) ? (...args: Args) => Promise<Awaited<Return>> : never;
|
|
3
10
|
type ServiceClient<T> = { [K in keyof T as T[K] extends ((...args: never[]) => unknown) ? K : never]: AsyncifyMethod<T[K]> };
|
|
4
11
|
type ExtractServices<T> = T extends {
|
|
5
12
|
services: infer S;
|
|
6
13
|
} ? S : never;
|
|
7
|
-
type
|
|
14
|
+
type BatchFn = <T extends Array<() => Promise<unknown>>>(thunks: [...T]) => Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>> }>;
|
|
15
|
+
type KibinClient<Router> = { [K in keyof ExtractServices<Router>]: ServiceClient<ExtractServices<Router>[K]> } & {
|
|
16
|
+
$batch: BatchFn;
|
|
17
|
+
};
|
|
18
|
+
interface RequestCtx {
|
|
19
|
+
namespace: string;
|
|
20
|
+
method: string;
|
|
21
|
+
args: unknown[];
|
|
22
|
+
}
|
|
23
|
+
interface ResponseCtx extends RequestCtx {
|
|
24
|
+
data: unknown;
|
|
25
|
+
}
|
|
26
|
+
interface ErrorCtx extends RequestCtx {
|
|
27
|
+
error: KibinError;
|
|
28
|
+
}
|
|
29
|
+
interface ClientInterceptors {
|
|
30
|
+
request?: (ctx: RequestCtx) => RequestCtx | Promise<RequestCtx>;
|
|
31
|
+
response?: (ctx: ResponseCtx) => unknown | Promise<unknown>;
|
|
32
|
+
error?: (ctx: ErrorCtx) => unknown | Promise<unknown>;
|
|
33
|
+
}
|
|
34
|
+
interface RetryConfig {
|
|
35
|
+
/** Total number of attempts. Default: 3 */
|
|
36
|
+
attempts?: number;
|
|
37
|
+
/** Base delay in ms — doubles each retry (exponential backoff). Default: 300 */
|
|
38
|
+
delay?: number;
|
|
39
|
+
}
|
|
8
40
|
interface KibinClientConfig {
|
|
9
41
|
baseUrl: string;
|
|
42
|
+
/** Batch endpoint URL. Default: `${baseUrl}/batch` */
|
|
43
|
+
batchUrl?: string;
|
|
10
44
|
headers?: Record<string, string>;
|
|
45
|
+
retry?: RetryConfig;
|
|
46
|
+
interceptors?: ClientInterceptors;
|
|
11
47
|
}
|
|
12
48
|
//#endregion
|
|
13
49
|
//#region src/client.d.ts
|
|
14
50
|
declare function createKibinClient<Router>(config: KibinClientConfig): KibinClient<Router>;
|
|
15
51
|
//#endregion
|
|
16
|
-
|
|
17
|
-
declare class KibinError extends Error {
|
|
18
|
-
readonly code: string;
|
|
19
|
-
constructor(code: string, message: string);
|
|
20
|
-
}
|
|
21
|
-
declare function isKibinError(error: unknown): error is KibinError;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { type KibinClient, type KibinClientConfig, KibinError, createKibinClient, isKibinError };
|
|
52
|
+
export { type ClientInterceptors, type ErrorCtx, type KibinClient, type KibinClientConfig, KibinError, type RequestCtx, type ResponseCtx, type RetryConfig, createKibinClient, isKibinError };
|
|
24
53
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/
|
|
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,OAAA,cAAqB,KAAA,OAAY,OAAA,YAC5C,MAAA,MAAY,CAAA,MACR,OAAA,eAAsB,CAAA,GAAI,OAAA,CAAQ,UAAA,CAAW,CAAA,CAAE,CAAA;AAAA,KAExC,WAAA,yBACC,eAAA,CAAgB,MAAA,IAAU,aAAA,CAAc,eAAA,CAAgB,MAAA,EAAQ,CAAA;EACvE,MAAA,EAAQ,OAAA;AAAA;AAAA,UAEG,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;EArCY;EAuC5B,QAAA;EAxCwB;EA0CxB,KAAK;AAAA;AAAA,UAGW,iBAAA;EAChB,OAAA;EA7CY;EA+CZ,QAAA;EACA,OAAA,GAAU,MAAA;EACV,KAAA,GAAQ,WAAA;EACR,YAAA,GAAe,kBAAA;AAAA;;;iBC7CA,iBAAA,QAAA,CAA0B,MAAA,EAAQ,iBAAA,GAAoB,WAAA,CAAY,MAAA"}
|
package/dist/index.js
CHANGED
|
@@ -12,25 +12,111 @@ function isKibinError(error) {
|
|
|
12
12
|
}
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/client.ts
|
|
15
|
+
const RETRY_DEFAULTS = {
|
|
16
|
+
attempts: 3,
|
|
17
|
+
delay: 300
|
|
18
|
+
};
|
|
15
19
|
function createKibinClient(config) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
const maxAttempts = config.retry?.attempts ?? RETRY_DEFAULTS.attempts;
|
|
21
|
+
const baseDelay = config.retry?.delay ?? RETRY_DEFAULTS.delay;
|
|
22
|
+
const batchUrl = config.batchUrl ?? `${config.baseUrl}/batch`;
|
|
23
|
+
const { interceptors } = config;
|
|
24
|
+
let currentBatch = null;
|
|
25
|
+
async function rpcCall(namespace, method, args) {
|
|
26
|
+
let ctx = {
|
|
27
|
+
namespace,
|
|
28
|
+
method,
|
|
29
|
+
args
|
|
30
|
+
};
|
|
31
|
+
if (interceptors?.request) ctx = await interceptors.request(ctx);
|
|
32
|
+
if (currentBatch !== null) {
|
|
33
|
+
const batch = currentBatch;
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
batch.push({
|
|
36
|
+
ctx,
|
|
37
|
+
resolve,
|
|
38
|
+
reject
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
let lastError;
|
|
43
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
44
|
+
if (attempt > 0) await new Promise((resolve) => setTimeout(resolve, baseDelay * 2 ** (attempt - 1)));
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetch(config.baseUrl, {
|
|
20
47
|
method: "POST",
|
|
21
48
|
headers: {
|
|
22
49
|
"Content-Type": "application/json",
|
|
23
50
|
...config.headers
|
|
24
51
|
},
|
|
25
|
-
body: JSON.stringify(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
body: JSON.stringify(ctx)
|
|
53
|
+
});
|
|
54
|
+
const result = await response.json();
|
|
55
|
+
if (result.error) {
|
|
56
|
+
const err = new KibinError(result.error.code ?? "RPC_ERROR", result.error.message ?? "RPC Error");
|
|
57
|
+
if (response.status >= 500) {
|
|
58
|
+
lastError = err;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (interceptors?.error) return await interceptors.error({
|
|
62
|
+
...ctx,
|
|
63
|
+
error: err
|
|
64
|
+
});
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
if (interceptors?.response) return await interceptors.response({
|
|
68
|
+
...ctx,
|
|
69
|
+
data: result.data
|
|
70
|
+
});
|
|
32
71
|
return result.data;
|
|
33
|
-
}
|
|
72
|
+
} catch (err) {
|
|
73
|
+
if (err instanceof KibinError) throw err;
|
|
74
|
+
lastError = err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (lastError instanceof KibinError && interceptors?.error) return await interceptors.error({
|
|
78
|
+
...ctx,
|
|
79
|
+
error: lastError
|
|
80
|
+
});
|
|
81
|
+
throw lastError;
|
|
82
|
+
}
|
|
83
|
+
async function $batch(thunks) {
|
|
84
|
+
const queue = [];
|
|
85
|
+
currentBatch = queue;
|
|
86
|
+
const promises = thunks.map((thunk) => thunk());
|
|
87
|
+
currentBatch = null;
|
|
88
|
+
const results = await (await fetch(batchUrl, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: {
|
|
91
|
+
"Content-Type": "application/json",
|
|
92
|
+
...config.headers
|
|
93
|
+
},
|
|
94
|
+
body: JSON.stringify(queue.map((item) => item.ctx))
|
|
95
|
+
})).json();
|
|
96
|
+
for (let i = 0; i < queue.length; i++) {
|
|
97
|
+
const result = results[i];
|
|
98
|
+
if (result?.error) {
|
|
99
|
+
const err = new KibinError(result.error.code ?? "RPC_ERROR", result.error.message ?? "RPC Error");
|
|
100
|
+
if (interceptors?.error) queue[i].resolve(await interceptors.error({
|
|
101
|
+
...queue[i].ctx,
|
|
102
|
+
error: err
|
|
103
|
+
}));
|
|
104
|
+
else queue[i].reject(err);
|
|
105
|
+
} else {
|
|
106
|
+
const data = result?.data;
|
|
107
|
+
if (interceptors?.response) queue[i].resolve(await interceptors.response({
|
|
108
|
+
...queue[i].ctx,
|
|
109
|
+
data
|
|
110
|
+
}));
|
|
111
|
+
else queue[i].resolve(data);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return Promise.all(promises);
|
|
115
|
+
}
|
|
116
|
+
return new Proxy({}, { get(_, key) {
|
|
117
|
+
if (key === "$batch") return $batch;
|
|
118
|
+
return new Proxy({}, { get(_, method) {
|
|
119
|
+
return (...args) => rpcCall(key, method, args);
|
|
34
120
|
} });
|
|
35
121
|
} });
|
|
36
122
|
}
|
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 } from './types.js';\n\nexport function createKibinClient<Router>(config: KibinClientConfig): KibinClient<Router> {\n\
|
|
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 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 batchUrl = config.batchUrl ?? `${config.baseUrl}/batch`;\n\tconst { interceptors } = config;\n\n\tlet currentBatch: QueueItem[] | null = null;\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\tif (currentBatch !== null) {\n\t\t\tconst batch = currentBatch;\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tbatch.push({ ctx, resolve, reject });\n\t\t\t});\n\t\t}\n\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 0; attempt < maxAttempts; attempt++) {\n\t\t\tif (attempt > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => setTimeout(resolve, baseDelay * 2 ** (attempt - 1)));\n\t\t\t}\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(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 = new KibinError(\n\t\t\t\t\t\tresult.error.code ?? 'RPC_ERROR',\n\t\t\t\t\t\tresult.error.message ?? 'RPC Error',\n\t\t\t\t\t);\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\tif (interceptors?.error) {\n\t\t\t\t\t\treturn await interceptors.error({ ...ctx, error: err });\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tif (interceptors?.response) {\n\t\t\t\t\treturn await interceptors.response({ ...ctx, data: result.data });\n\t\t\t\t}\n\n\t\t\t\treturn result.data;\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof KibinError) throw err;\n\t\t\t\tlastError = err;\n\t\t\t}\n\t\t}\n\n\t\tif (lastError instanceof KibinError && interceptors?.error) {\n\t\t\treturn await interceptors.error({ ...ctx, error: lastError });\n\t\t}\n\n\t\tthrow lastError;\n\t}\n\n\tasync function $batch<T extends Array<() => Promise<unknown>>>(\n\t\tthunks: [...T],\n\t): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>> }> {\n\t\tconst queue: QueueItem[] = [];\n\t\tcurrentBatch = queue;\n\t\tconst promises = thunks.map((thunk) => thunk());\n\t\tcurrentBatch = null;\n\n\t\tconst response = await fetch(batchUrl, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json', ...config.headers },\n\t\t\tbody: JSON.stringify(queue.map((item) => item.ctx)),\n\t\t});\n\n\t\tconst results = (await response.json()) as RpcResult[];\n\n\t\tfor (let i = 0; i < queue.length; i++) {\n\t\t\tconst result = results[i];\n\t\t\tif (result?.error) {\n\t\t\t\tconst err = new KibinError(\n\t\t\t\t\tresult.error.code ?? 'RPC_ERROR',\n\t\t\t\t\tresult.error.message ?? 'RPC Error',\n\t\t\t\t);\n\t\t\t\tif (interceptors?.error) {\n\t\t\t\t\tqueue[i].resolve(await interceptors.error({ ...queue[i].ctx, error: err }));\n\t\t\t\t} else {\n\t\t\t\t\tqueue[i].reject(err);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst data = result?.data;\n\t\t\t\tif (interceptors?.response) {\n\t\t\t\t\tqueue[i].resolve(await interceptors.response({ ...queue[i].ctx, data }));\n\t\t\t\t} else {\n\t\t\t\t\tqueue[i].resolve(data);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all(promises) as Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>> }>;\n\t}\n\n\treturn new Proxy(\n\t\t{},\n\t\t{\n\t\t\tget(_, key: string) {\n\t\t\t\tif (key === '$batch') return $batch;\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: string) {\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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"}
|