@kibinrpc/server 0.1.1 → 0.2.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/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +17 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/decorator.ts","../src/fn.ts","../src/types.ts","../src/router.ts"],"mappings":";;;iBAEgB,YAAA,CAAA,0CAEd,MAAA,GAAS,IAAA,EAAM,IAAA,KAAS,IAAA,EAAM,IAAA,KAAS,MAAA,EACvC,OAAA,EAAS,2BAAA,CAA4B,IAAA,GAAO,IAAA,EAAM,IAAA,KAAS,IAAA,EAAM,IAAA,KAAS,MAAA,OAAO,IAAA,EADlE,IAAA,KAAI,IAAA,EAAW,IAAA,KAAS,MAAA;;;iBCFzB,YAAA,eAA2B,IAAA,sBAAA,CAA2B,EAAA,EAAI,CAAA,GAAI,CAAC;AAAA,iBAK/D,aAAA,WAAwB,MAAA,aAAmB,IAAA,uBAAA,CAC1D,OAAA,EAAS,CAAA,GACP,CAAA;;;UCTc,UAAA;EAChB,SAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,UAGgB,WAAA;EAChB,IAAA,GAAO,CAAC;EACR,KAAA;IAAU,IAAA;IAAc,OAAA;EAAA;AAAA;AAAA,UAGR,oBAAA,SAA6B,WAAW;EACxD,MAAM;AAAA;AAAA,UAGU,SAAA;EAChB,SAAA;EACA,MAAA;EACA,IAAA;EACA,OAAA,EAAS,OAAO;AAAA;AAAA,UAGA,cAAA,SAAuB,SAAS;EAChD,MAAM;AAAA;AAAA,UAGU,cAAA,SAAuB,SAAS;EAChD,KAAK;AAAA;AAAA,UAGW,kBAAA;EAChB,YAAA,IAAgB,GAAA,EAAK,SAAA,YAAqB,OAAA;EAC1C,WAAA,IAAe,GAAA,EAAK,cAAA,eAA6B,OAAA;EACjD,OAAA,IAAW,GAAA,EAAK,cAAA,YAA0B,OAAA;AAAA;;;KC7BtC,QAAA,GAAW,MAAM;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/decorator.ts","../src/fn.ts","../src/types.ts","../src/router.ts"],"mappings":";;;iBAEgB,YAAA,CAAA,0CAEd,MAAA,GAAS,IAAA,EAAM,IAAA,KAAS,IAAA,EAAM,IAAA,KAAS,MAAA,EACvC,OAAA,EAAS,2BAAA,CAA4B,IAAA,GAAO,IAAA,EAAM,IAAA,KAAS,IAAA,EAAM,IAAA,KAAS,MAAA,OAAO,IAAA,EADlE,IAAA,KAAI,IAAA,EAAW,IAAA,KAAS,MAAA;;;iBCFzB,YAAA,eAA2B,IAAA,sBAAA,CAA2B,EAAA,EAAI,CAAA,GAAI,CAAC;AAAA,iBAK/D,aAAA,WAAwB,MAAA,aAAmB,IAAA,uBAAA,CAC1D,OAAA,EAAS,CAAA,GACP,CAAA;;;UCTc,UAAA;EAChB,SAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,UAGgB,WAAA;EAChB,IAAA,GAAO,CAAC;EACR,KAAA;IAAU,IAAA;IAAc,OAAA;EAAA;AAAA;AAAA,UAGR,oBAAA,SAA6B,WAAW;EACxD,MAAM;AAAA;AAAA,UAGU,SAAA;EAChB,SAAA;EACA,MAAA;EACA,IAAA;EACA,OAAA,EAAS,OAAO;AAAA;AAAA,UAGA,cAAA,SAAuB,SAAS;EAChD,MAAM;AAAA;AAAA,UAGU,cAAA,SAAuB,SAAS;EAChD,KAAK;AAAA;AAAA,UAGW,kBAAA;EAChB,YAAA,IAAgB,GAAA,EAAK,SAAA,YAAqB,OAAA;EAC1C,WAAA,IAAe,GAAA,EAAK,cAAA,eAA6B,OAAA;EACjD,OAAA,IAAW,GAAA,EAAK,cAAA,YAA0B,OAAA;AAAA;;;KC7BtC,QAAA,GAAW,MAAM;AAAA,iBAkFN,YAAA,WAAuB,QAAA,CAAA,CACtC,QAAA,EAAU,CAAA,EACV,YAAA,GAAe,kBAAA;EACb;AAAA;EAA2C,YAAA;AAAA;;qBAEb,OAAA,KAAU,OAAA,CAAQ,QAAA;AAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -2,8 +2,17 @@ import { KibinError } from "@kibinrpc/shared";
|
|
|
2
2
|
//#region src/registry.ts
|
|
3
3
|
const SERVER_ACTIONS_KEY = Symbol("serverActions");
|
|
4
4
|
const FUNCTION_ACTION_KEY = Symbol("functionAction");
|
|
5
|
+
const EMPTY_SET = /* @__PURE__ */ new Set();
|
|
5
6
|
function getRegisteredActions(instance) {
|
|
6
|
-
return Reflect.get(instance, SERVER_ACTIONS_KEY) ??
|
|
7
|
+
return Reflect.get(instance, SERVER_ACTIONS_KEY) ?? EMPTY_SET;
|
|
8
|
+
}
|
|
9
|
+
function ensureActionsSet(instance) {
|
|
10
|
+
let set = Reflect.get(instance, SERVER_ACTIONS_KEY);
|
|
11
|
+
if (!set) {
|
|
12
|
+
set = /* @__PURE__ */ new Set();
|
|
13
|
+
Reflect.set(instance, SERVER_ACTIONS_KEY, set);
|
|
14
|
+
}
|
|
15
|
+
return set;
|
|
7
16
|
}
|
|
8
17
|
function isBrandedAction(fn) {
|
|
9
18
|
return typeof fn === "function" && Reflect.get(fn, FUNCTION_ACTION_KEY) === true;
|
|
@@ -14,8 +23,7 @@ function ServerAction() {
|
|
|
14
23
|
return (target, context) => {
|
|
15
24
|
context.addInitializer(function() {
|
|
16
25
|
if (typeof context.name === "symbol") return;
|
|
17
|
-
|
|
18
|
-
Reflect.get(this, SERVER_ACTIONS_KEY).add(context.name);
|
|
26
|
+
ensureActionsSet(this).add(context.name);
|
|
19
27
|
});
|
|
20
28
|
return target;
|
|
21
29
|
};
|
|
@@ -38,11 +46,14 @@ function jsonResponse(body, status) {
|
|
|
38
46
|
headers: { "Content-Type": "application/json" }
|
|
39
47
|
});
|
|
40
48
|
}
|
|
49
|
+
const ERROR_STATUS = {
|
|
50
|
+
NOT_FOUND: 404,
|
|
51
|
+
METHOD_NOT_FOUND: 404,
|
|
52
|
+
BAD_REQUEST: 400
|
|
53
|
+
};
|
|
41
54
|
function statusFromResponse(result) {
|
|
42
55
|
if (!result.error) return 200;
|
|
43
|
-
|
|
44
|
-
if (result.error.code === "BAD_REQUEST") return 400;
|
|
45
|
-
return 500;
|
|
56
|
+
return ERROR_STATUS[result.error.code ?? ""] ?? 500;
|
|
46
57
|
}
|
|
47
58
|
async function executeRpcCall(body, request, services, interceptors) {
|
|
48
59
|
const { namespace, method, args } = body;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/registry.ts","../src/decorator.ts","../src/fn.ts","../src/router.ts"],"sourcesContent":["export const SERVER_ACTIONS_KEY = Symbol('serverActions');\nexport const FUNCTION_ACTION_KEY = Symbol('functionAction');\n\nexport function getRegisteredActions(instance: object):
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/registry.ts","../src/decorator.ts","../src/fn.ts","../src/router.ts"],"sourcesContent":["export const SERVER_ACTIONS_KEY = Symbol('serverActions');\nexport const FUNCTION_ACTION_KEY = Symbol('functionAction');\n\nconst EMPTY_SET: ReadonlySet<string> = new Set();\n\nexport function getRegisteredActions(instance: object): ReadonlySet<string> {\n\treturn (Reflect.get(instance, SERVER_ACTIONS_KEY) as Set<string> | undefined) ?? EMPTY_SET;\n}\n\nexport function ensureActionsSet(instance: object): Set<string> {\n\tlet set = Reflect.get(instance, SERVER_ACTIONS_KEY) as Set<string> | undefined;\n\tif (!set) {\n\t\tset = new Set<string>();\n\t\tReflect.set(instance, SERVER_ACTIONS_KEY, set);\n\t}\n\treturn set;\n}\n\nexport function isBrandedAction(fn: unknown): boolean {\n\treturn typeof fn === 'function' && Reflect.get(fn, FUNCTION_ACTION_KEY) === true;\n}\n","import { ensureActionsSet } from './registry.js';\n\nexport function ServerAction() {\n\treturn <This, Args extends unknown[], Return>(\n\t\ttarget: (this: This, ...args: Args) => Return,\n\t\tcontext: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>,\n\t) => {\n\t\tcontext.addInitializer(function (this: This) {\n\t\t\tif (typeof context.name === 'symbol') return;\n\t\t\tensureActionsSet(this as object).add(context.name);\n\t\t});\n\t\treturn target;\n\t};\n}\n","import { FUNCTION_ACTION_KEY } from './registry.js';\n\nexport function serverAction<T extends (...args: never[]) => unknown>(fn: T): T {\n\tReflect.set(fn, FUNCTION_ACTION_KEY, true);\n\treturn fn;\n}\n\nexport function defineActions<T extends Record<string, (...args: never[]) => unknown>>(\n\tactions: T,\n): T {\n\tfor (const key of Object.keys(actions)) {\n\t\tserverAction(actions[key]);\n\t}\n\treturn actions;\n}\n","import { KibinError } from './errors.js';\nimport { getRegisteredActions, isBrandedAction } from './registry.js';\nimport type { RouterInterceptors, RpcBatchItemResponse, RpcRequest, RpcResponse } from './types.js';\n\ntype Services = Record<string, object>;\n\nfunction jsonResponse(body: RpcResponse | RpcBatchItemResponse[], status: number): Response {\n\treturn new Response(JSON.stringify(body), {\n\t\tstatus,\n\t\theaders: { 'Content-Type': 'application/json' },\n\t});\n}\n\nconst ERROR_STATUS: Record<string, number> = {\n\tNOT_FOUND: 404,\n\tMETHOD_NOT_FOUND: 404,\n\tBAD_REQUEST: 400,\n};\n\nfunction statusFromResponse(result: RpcResponse): number {\n\tif (!result.error) return 200;\n\treturn ERROR_STATUS[result.error.code ?? ''] ?? 500;\n}\n\nasync function executeRpcCall(\n\tbody: RpcRequest,\n\trequest: Request,\n\tservices: Services,\n\tinterceptors: RouterInterceptors | undefined,\n): Promise<RpcResponse> {\n\tconst { namespace, method, args } = body;\n\n\tconst service = services[namespace];\n\tif (!service) {\n\t\treturn { error: { code: 'NOT_FOUND', message: `Namespace \"${namespace}\" not found` } };\n\t}\n\n\tconst fn = (service as Record<string, unknown>)[method];\n\tif (typeof fn !== 'function') {\n\t\treturn { error: { code: 'METHOD_NOT_FOUND', message: `Method \"${method}\" not found` } };\n\t}\n\n\tconst isAllowed = getRegisteredActions(service).has(method) || isBrandedAction(fn);\n\tif (!isAllowed) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\tcode: 'METHOD_NOT_FOUND',\n\t\t\t\tmessage: `\"${method}\" is not a registered server action`,\n\t\t\t},\n\t\t};\n\t}\n\n\tconst ctx = { namespace, method, args, request };\n\n\ttry {\n\t\tif (interceptors?.beforeAction) {\n\t\t\tawait interceptors.beforeAction(ctx);\n\t\t}\n\n\t\tconst result = await fn.apply(service, args);\n\n\t\tlet finalResult = result;\n\t\tif (interceptors?.afterAction) {\n\t\t\tconst transformed = await interceptors.afterAction({ ...ctx, result });\n\t\t\tif (transformed !== undefined) finalResult = transformed;\n\t\t}\n\n\t\treturn { data: finalResult };\n\t} catch (error) {\n\t\tif (interceptors?.onError) {\n\t\t\ttry {\n\t\t\t\tawait interceptors.onError({ ...ctx, error });\n\t\t\t} catch {\n\t\t\t\t// onError hook errors are silently ignored to protect the response path\n\t\t\t}\n\t\t}\n\n\t\tif (error instanceof KibinError) {\n\t\t\treturn { error: { code: error.code, message: error.message } };\n\t\t}\n\t\treturn { error: { code: 'INTERNAL_ERROR', message: 'Internal server error' } };\n\t}\n}\n\nconst DEFAULT_MAX_BATCH_SIZE = 50;\n\nexport function createRouter<T extends Services>(\n\tservices: T,\n\tinterceptors?: RouterInterceptors,\n\t{ maxBatchSize = DEFAULT_MAX_BATCH_SIZE }: { maxBatchSize?: number } = {},\n) {\n\tasync function handler(request: Request): Promise<Response> {\n\t\tlet body: RpcRequest | RpcRequest[];\n\t\ttry {\n\t\t\tbody = (await request.json()) as RpcRequest | RpcRequest[];\n\t\t} catch {\n\t\t\treturn jsonResponse({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);\n\t\t}\n\n\t\tif (Array.isArray(body)) {\n\t\t\tif (body.length > maxBatchSize) {\n\t\t\t\treturn jsonResponse(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: { code: 'BAD_REQUEST', message: `Batch size exceeds limit of ${maxBatchSize}` },\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst results = await Promise.all(\n\t\t\t\tbody.map((b) => executeRpcCall(b, request, services, interceptors)),\n\t\t\t);\n\t\t\tconst responses: RpcBatchItemResponse[] = results.map((r) => ({\n\t\t\t\t...r,\n\t\t\t\tstatus: statusFromResponse(r),\n\t\t\t}));\n\t\t\tconst httpStatus = responses.every((r) => r.status === 200) ? 200 : 207;\n\t\t\treturn jsonResponse(responses, httpStatus);\n\t\t}\n\n\t\tconst result = await executeRpcCall(body, request, services, interceptors);\n\t\treturn jsonResponse(result, statusFromResponse(result));\n\t}\n\n\treturn { services, handler };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kibinrpc/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Devloper-friendly RPC server router with full type inference",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ixexel661",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@kibinrpc/shared": "0.
|
|
34
|
+
"@kibinrpc/shared": "0.2.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|