@kibinrpc/client 0.1.0 → 0.1.1

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 CHANGED
@@ -1,10 +1,5 @@
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
+ import { KibinError, isKibinError } from "@kibinrpc/shared";
2
+
8
3
  //#region src/types.d.ts
9
4
  type AsyncifyMethod<T> = T extends ((...args: infer Args) => infer Return) ? (...args: Args) => Promise<Awaited<Return>> : never;
10
5
  type ServiceClient<T> = { [K in keyof T as T[K] extends ((...args: never[]) => unknown) ? K : never]: AsyncifyMethod<T[K]> };
@@ -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;;;iBC9BA,iBAAA,QAAA,CAA0B,MAAA,EAAQ,iBAAA,GAAoB,WAAA,CAAY,MAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/client.ts"],"mappings":";;;KAEK,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;EA7BJ;EA+BZ,QAAA;EA/BmB;EAiCnB,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
@@ -1,16 +1,4 @@
1
- //#region src/errors.ts
2
- var KibinError = class extends Error {
3
- code;
4
- constructor(code, message) {
5
- super(message);
6
- this.name = "KibinError";
7
- this.code = code;
8
- }
9
- };
10
- function isKibinError(error) {
11
- return error instanceof KibinError;
12
- }
13
- //#endregion
1
+ import { KibinError, isKibinError } from "@kibinrpc/shared";
14
2
  //#region src/client.ts
15
3
  const RETRY_DEFAULTS = {
16
4
  attempts: 3,
@@ -129,25 +117,32 @@ function createKibinClient(config) {
129
117
  continue;
130
118
  }
131
119
  const retryItems = [];
120
+ const settlements = [];
132
121
  for (let i = 0; i < pending.length; i++) {
133
122
  const result = results[i];
134
123
  const item = pending[i];
135
- if (result?.error) {
124
+ if (!result) {
125
+ item.reject(new KibinError("BATCH_MISMATCH", "Server returned fewer results than expected"));
126
+ continue;
127
+ }
128
+ if (result.error) {
136
129
  const err = rpcError(result.error);
137
130
  if (result.status >= 500) {
138
131
  retryItems.push(item);
139
132
  lastErrors.set(item, err);
140
- } else await settleError(item, err);
141
- } else await settleSuccess(item, result?.data);
133
+ } else settlements.push(settleError(item, err));
134
+ } else settlements.push(settleSuccess(item, result.data));
142
135
  }
136
+ await Promise.all(settlements);
143
137
  pending = retryItems;
144
138
  if (pending.length === 0) break;
145
139
  }
146
- for (const item of pending) {
140
+ await Promise.all(pending.map((item) => {
147
141
  const err = lastErrors.get(item);
148
- if (err instanceof KibinError) await settleError(item, err);
149
- else item.reject(err);
150
- }
142
+ if (err instanceof KibinError) return settleError(item, err);
143
+ item.reject(err);
144
+ return Promise.resolve();
145
+ }));
151
146
  }
152
147
  return new Proxy({}, { get(_, key) {
153
148
  if (typeof key !== "string") return void 0;
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\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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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["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\t\t\tconst settlements: Promise<void>[] = [];\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) {\n\t\t\t\t\titem.reject(\n\t\t\t\t\t\tnew KibinError('BATCH_MISMATCH', 'Server returned fewer results than expected'),\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\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\tsettlements.push(settleError(item, err));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tsettlements.push(settleSuccess(item, result.data));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait Promise.all(settlements);\n\t\t\tpending = retryItems;\n\t\t\tif (pending.length === 0) break;\n\t\t}\n\n\t\tawait Promise.all(\n\t\t\tpending.map((item) => {\n\t\t\t\tconst err = lastErrors.get(item);\n\t\t\t\tif (err instanceof KibinError) return settleError(item, err);\n\t\t\t\titem.reject(err);\n\t\t\t\treturn Promise.resolve();\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":";;AAGA,MAAM,iBAAiB;CAAE,UAAU;CAAG,OAAO;AAAI;AAMjD,SAAS,SAAS,OAAwD;CACzE,OAAO,IAAI,WAAW,MAAM,QAAQ,aAAa,MAAM,WAAW,WAAW;AAC9E;AAEA,SAAS,MAAM,SAAiB,WAAkC;CACjE,OAAO,IAAI,SAAe,MAAM,WAAW,GAAG,YAAY,MAAM,UAAU,EAAE,CAAC;AAC9E;AAEA,SAAgB,kBAA0B,QAAgD;CACzF,MAAM,cAAc,OAAO,OAAO,YAAY,eAAe;CAC7D,MAAM,YAAY,OAAO,OAAO,SAAS,eAAe;CACxD,MAAM,EAAE,iBAAiB;CAEzB,IAAI,eAA4B,CAAC;CACjC,IAAI,iBAAiB;CAErB,eAAe,YAAY,MAAiB,KAAgC;EAC3E,IAAI,cAAc,OACjB,IAAI;GACH,KAAK,QAAQ,MAAM,aAAa,MAAM;IAAE,GAAG,KAAK;IAAK,OAAO;GAAI,CAAC,CAAC;EACnE,SAAS,kBAAkB;GAC1B,KAAK,OAAO,gBAAgB;EAC7B;OAEA,KAAK,OAAO,GAAG;CAEjB;CAEA,eAAe,cAAc,MAAiB,MAA8B;EAC3E,IAAI,cAAc,UACjB,IAAI;GACH,KAAK,QAAQ,MAAM,aAAa,SAAS;IAAE,GAAG,KAAK;IAAK;GAAK,CAAC,CAAC;EAChE,SAAS,kBAAkB;GAC1B,KAAK,OAAO,gBAAgB;EAC7B;OAEA,KAAK,QAAQ,IAAI;CAEnB;CAEA,eAAe,QAAQ,WAAmB,QAAgB,MAAmC;EAC5F,IAAI,MAAkB;GAAE;GAAW;GAAQ;EAAK;EAEhD,IAAI,cAAc,SACjB,MAAM,MAAM,aAAa,QAAQ,GAAG;EAGrC,OAAO,IAAI,SAAkB,SAAS,WAAW;GAChD,aAAa,KAAK;IAAE;IAAK;IAAS;GAAO,CAAC;GAC1C,IAAI,CAAC,gBAAgB;IACpB,iBAAiB;IACjB,eAAe,KAAK;GACrB;EACD,CAAC;CACF;CAEA,SAAS,QAAQ;EAChB,MAAM,QAAQ;EACd,eAAe,CAAC;EAChB,iBAAiB;EAEjB,IAAI,MAAM,WAAW,GAAG;EACxB,IAAI,MAAM,WAAW,GACpB,YAAY,MAAM,EAAE;OAEpB,WAAW,KAAK;CAElB;CAEA,eAAe,YAAY,MAAiB;EAC3C,IAAI;EAEJ,KAAK,IAAI,UAAU,GAAG,UAAU,aAAa,WAAW;GACvD,IAAI,UAAU,GAAG,MAAM,MAAM,SAAS,SAAS;GAE/C,IAAI;IACH,MAAM,WAAW,MAAM,MAAM,OAAO,SAAS;KAC5C,QAAQ;KACR,SAAS;MAAE,gBAAgB;MAAoB,GAAG,OAAO;KAAQ;KACjE,MAAM,KAAK,UAAU,KAAK,GAAG;IAC9B,CAAC;IAED,MAAM,SAAU,MAAM,SAAS,KAAK;IAEpC,IAAI,OAAO,OAAO;KACjB,MAAM,MAAM,SAAS,OAAO,KAAK;KACjC,IAAI,SAAS,UAAU,KAAK;MAC3B,YAAY;MACZ;KACD;KACA,MAAM,YAAY,MAAM,GAAG;KAC3B;IACD;IAEA,MAAM,cAAc,MAAM,OAAO,IAAI;IACrC;GACD,SAAS,KAAK;IACb,YAAY;GACb;EACD;EAEA,IAAI,qBAAqB,YACxB,MAAM,YAAY,MAAM,SAAS;OAEjC,KAAK,OAAO,SAAS;CAEvB;CAEA,eAAe,WAAW,OAAoB;EAC7C,IAAI,UAAU,CAAC,GAAG,KAAK;EACvB,MAAM,6BAAa,IAAI,IAAwB;EAE/C,KAAK,IAAI,UAAU,GAAG,UAAU,aAAa,WAAW;GACvD,IAAI,UAAU,GAAG,MAAM,MAAM,SAAS,SAAS;GAE/C,IAAI;GACJ,IAAI;IAMH,UAAW,OAAM,MALM,MAAM,OAAO,SAAS;KAC5C,QAAQ;KACR,SAAS;MAAE,gBAAgB;MAAoB,GAAG,OAAO;KAAQ;KACjE,MAAM,KAAK,UAAU,QAAQ,KAAK,SAAS,KAAK,GAAG,CAAC;IACrD,CAAC,GACyB,KAAK;GAChC,SAAS,KAAK;IACb,KAAK,MAAM,QAAQ,SAAS,WAAW,IAAI,MAAM,GAAG;IACpD;GACD;GAEA,MAAM,aAA0B,CAAC;GACjC,MAAM,cAA+B,CAAC;GAEtC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;IACxC,MAAM,SAAS,QAAQ;IACvB,MAAM,OAAO,QAAQ;IAErB,IAAI,CAAC,QAAQ;KACZ,KAAK,OACJ,IAAI,WAAW,kBAAkB,6CAA6C,CAC/E;KACA;IACD;IAEA,IAAI,OAAO,OAAO;KACjB,MAAM,MAAM,SAAS,OAAO,KAAK;KACjC,IAAI,OAAO,UAAU,KAAK;MACzB,WAAW,KAAK,IAAI;MACpB,WAAW,IAAI,MAAM,GAAG;KACzB,OACC,YAAY,KAAK,YAAY,MAAM,GAAG,CAAC;IAEzC,OACC,YAAY,KAAK,cAAc,MAAM,OAAO,IAAI,CAAC;GAEnD;GAEA,MAAM,QAAQ,IAAI,WAAW;GAC7B,UAAU;GACV,IAAI,QAAQ,WAAW,GAAG;EAC3B;EAEA,MAAM,QAAQ,IACb,QAAQ,KAAK,SAAS;GACrB,MAAM,MAAM,WAAW,IAAI,IAAI;GAC/B,IAAI,eAAe,YAAY,OAAO,YAAY,MAAM,GAAG;GAC3D,KAAK,OAAO,GAAG;GACf,OAAO,QAAQ,QAAQ;EACxB,CAAC,CACF;CACD;CAEA,OAAO,IAAI,MACV,CAAC,GACD,EACC,IAAI,GAAG,KAAK;EACX,IAAI,OAAO,QAAQ,UAAU,OAAO,KAAA;EACpC,OAAO,IAAI,MACV,CAAC,GACD,EACC,IAAI,GAAG,QAAQ;GACd,IAAI,OAAO,WAAW,UAAU,OAAO,KAAA;GACvC,QAAQ,GAAG,SAAoB,QAAQ,KAAK,QAAQ,IAAI;EACzD,EACD,CACD;CACD,EACD,CACD;AACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kibinrpc/client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Type-safe and developer-friendly RPC client with end-to-end type inference",
5
5
  "license": "MIT",
6
6
  "author": "ixexel661",
@@ -28,6 +28,9 @@
28
28
  "files": [
29
29
  "dist"
30
30
  ],
31
+ "dependencies": {
32
+ "@kibinrpc/shared": "0.1.1"
33
+ },
31
34
  "publishConfig": {
32
35
  "access": "public"
33
36
  },