@cybermp/rpc-router 0.1.0-rc.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/LICENSE +21 -0
- package/dist/client/index.cjs +76 -0
- package/dist/client/index.d.cts +34 -0
- package/dist/client/index.d.mts +34 -0
- package/dist/client/index.d.ts +34 -0
- package/dist/client/index.mjs +74 -0
- package/dist/server/index.cjs +295 -0
- package/dist/server/index.d.cts +78 -0
- package/dist/server/index.d.mts +78 -0
- package/dist/server/index.d.ts +78 -0
- package/dist/server/index.mjs +285 -0
- package/dist/shared/rpc-router.Cu7hweRg.d.cts +157 -0
- package/dist/shared/rpc-router.Cu7hweRg.d.mts +157 -0
- package/dist/shared/rpc-router.Cu7hweRg.d.ts +157 -0
- package/package.json +36 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { A as AnySchema, P as ProcedureDef, S as Schema, I as InferSchemaInput, a as ProcedureHandler, b as InferSchemaOutput, c as Procedure, C as ContractDef, d as Contract, e as AnyContract, R as Router, f as ContractRouter } from '../shared/rpc-router.Cu7hweRg.mjs';
|
|
2
|
+
export { h as AnyProcedure, n as ContractProcedure, l as InferRouterInputs, m as InferRouterOutputs, g as ProcedureContext, k as RouterOrProcedure, i as isContract, j as isProcedure } from '../shared/rpc-router.Cu7hweRg.mjs';
|
|
3
|
+
import { RpcBase } from '@cybermp/rpc-core';
|
|
4
|
+
import { RpcContext, RpcApplyType } from '@cybermp/rpc-core/definitions';
|
|
5
|
+
|
|
6
|
+
type OverrideRpcContext<T extends RpcContext, D = any, M extends Record<string, any> = Record<string, any>> = Omit<T, 'data' | 'meta'> & {
|
|
7
|
+
data: D;
|
|
8
|
+
meta: M;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
interface ProcedureBuilderDef<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> extends Omit<ProcedureDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>, 'handler'> {
|
|
12
|
+
}
|
|
13
|
+
declare class ProcedureBuilder<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
14
|
+
'~crpc': ProcedureBuilderDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>;
|
|
15
|
+
constructor(def: ProcedureBuilderDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>);
|
|
16
|
+
context<UContext extends TCurrentContext>(): ProcedureBuilder<UContext, TInputSchema, TOutputSchema, TMethod>;
|
|
17
|
+
input<USchema extends AnySchema>(schema: USchema): ProcedureBuilder<TCurrentContext, USchema, TOutputSchema, TMethod>;
|
|
18
|
+
output<USchema extends AnySchema>(schema: USchema): ProcedureBuilder<TCurrentContext, TInputSchema, USchema, TMethod>;
|
|
19
|
+
method<UMethod extends RpcApplyType>(method: UMethod): ProcedureBuilder<TCurrentContext, TInputSchema, UMethod extends RpcApplyType.ON ? Schema<void> : TOutputSchema, UMethod>;
|
|
20
|
+
handler<UFuncOutput extends InferSchemaInput<TOutputSchema>>(...handler: ProcedureHandler<OverrideRpcContext<TCurrentContext, InferSchemaOutput<TInputSchema>>, UFuncOutput>[]): Procedure<TCurrentContext, TInputSchema, TOutputSchema extends {
|
|
21
|
+
initial?: true;
|
|
22
|
+
} ? Schema<UFuncOutput> : TOutputSchema, TMethod>;
|
|
23
|
+
}
|
|
24
|
+
declare const procedure: ProcedureBuilder<RpcContext<any, Record<string, any>>, Schema<unknown, unknown>, Schema<void>, RpcApplyType.ON>;
|
|
25
|
+
|
|
26
|
+
interface ContractBuilderDef<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> extends ContractDef<TInputSchema, TOutputSchema, TMethod> {
|
|
27
|
+
}
|
|
28
|
+
declare class ContractBuilder<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
29
|
+
'~crpc': ContractBuilderDef<TInputSchema, TOutputSchema, TMethod>;
|
|
30
|
+
constructor(def: ContractBuilderDef<TInputSchema, TOutputSchema, TMethod>);
|
|
31
|
+
input<USchema extends AnySchema>(schema: USchema): ContractBuilder<TCurrentContext, USchema, TOutputSchema, TMethod>;
|
|
32
|
+
output<USchema extends AnySchema>(schema: USchema): ContractBuilder<TCurrentContext, TInputSchema, USchema, TMethod>;
|
|
33
|
+
method<UMethod extends RpcApplyType>(method: UMethod): ContractBuilder<TCurrentContext, TInputSchema, UMethod extends RpcApplyType.ON ? Schema<void> : TOutputSchema, UMethod>;
|
|
34
|
+
build(): Contract<TInputSchema, TOutputSchema, TMethod>;
|
|
35
|
+
implement<UFuncOutput extends InferSchemaInput<TOutputSchema>>(...handler: ProcedureHandler<OverrideRpcContext<TCurrentContext, InferSchemaOutput<TInputSchema>>, UFuncOutput>[]): Procedure<TCurrentContext, TInputSchema, TOutputSchema extends {
|
|
36
|
+
initial?: true;
|
|
37
|
+
} ? Schema<UFuncOutput> : TOutputSchema, TMethod>;
|
|
38
|
+
}
|
|
39
|
+
declare const contract: ContractBuilder<RpcContext<any, Record<string, any>>, Schema<unknown, unknown>, Schema<void> & {
|
|
40
|
+
initial?: true;
|
|
41
|
+
}, RpcApplyType.ON>;
|
|
42
|
+
|
|
43
|
+
type RpcRouterOptions = {
|
|
44
|
+
validation?: boolean | {
|
|
45
|
+
input?: boolean;
|
|
46
|
+
output?: boolean;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
type InferImplementHandler<TContext extends RpcContext, TContract> = TContract extends AnyContract ? ProcedureHandler<OverrideRpcContext<TContext, InferSchemaOutput<TContract['~crpc']['inputSchema']>>, InferSchemaOutput<TContract['~crpc']['outputSchema']>> : TContract extends Record<string, any> ? {
|
|
50
|
+
[K in keyof TContract]: InferImplementHandler<TContext, TContract[K]>[] | InferImplementHandler<TContext, TContract[K]>;
|
|
51
|
+
} : never;
|
|
52
|
+
declare class RpcRouter<Context extends RpcContext> {
|
|
53
|
+
private readonly rpc;
|
|
54
|
+
private readonly options?;
|
|
55
|
+
readonly contract: ContractBuilder<Context, any, Schema<void>, RpcApplyType.ON>;
|
|
56
|
+
readonly procedure: ProcedureBuilder<Context, any, Schema<void>, RpcApplyType.ON>;
|
|
57
|
+
private store;
|
|
58
|
+
private contractProcedureMap;
|
|
59
|
+
constructor(rpc: RpcBase<any>, options?: RpcRouterOptions | undefined);
|
|
60
|
+
private validateSchema;
|
|
61
|
+
private shouldValidate;
|
|
62
|
+
private registerGlobalMiddleware;
|
|
63
|
+
apply(router: Router): void;
|
|
64
|
+
private findNameByProcedureOrContract;
|
|
65
|
+
implement<T extends AnyContract>(contract: T, ...handler: InferImplementHandler<Context, T>[]): void;
|
|
66
|
+
implement<T extends ContractRouter>(contractTree: T, handlerTree: InferImplementHandler<Context, T>): void;
|
|
67
|
+
private implementContract;
|
|
68
|
+
private implementContractTree;
|
|
69
|
+
unimplement(contract: AnyContract): void;
|
|
70
|
+
unimplement(contractTree: ContractRouter): void;
|
|
71
|
+
private unimplementContract;
|
|
72
|
+
private unimplementContractTree;
|
|
73
|
+
private removeProcedure;
|
|
74
|
+
private applyProcedure;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { AnyContract, Contract, ContractBuilder, ContractDef, ContractRouter, Procedure, ProcedureBuilder, ProcedureDef, ProcedureHandler, Router, RpcRouter, contract, procedure };
|
|
78
|
+
export type { ContractBuilderDef, InferImplementHandler, ProcedureBuilderDef, RpcRouterOptions };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { A as AnySchema, P as ProcedureDef, S as Schema, I as InferSchemaInput, a as ProcedureHandler, b as InferSchemaOutput, c as Procedure, C as ContractDef, d as Contract, e as AnyContract, R as Router, f as ContractRouter } from '../shared/rpc-router.Cu7hweRg.js';
|
|
2
|
+
export { h as AnyProcedure, n as ContractProcedure, l as InferRouterInputs, m as InferRouterOutputs, g as ProcedureContext, k as RouterOrProcedure, i as isContract, j as isProcedure } from '../shared/rpc-router.Cu7hweRg.js';
|
|
3
|
+
import { RpcBase } from '@cybermp/rpc-core';
|
|
4
|
+
import { RpcContext, RpcApplyType } from '@cybermp/rpc-core/definitions';
|
|
5
|
+
|
|
6
|
+
type OverrideRpcContext<T extends RpcContext, D = any, M extends Record<string, any> = Record<string, any>> = Omit<T, 'data' | 'meta'> & {
|
|
7
|
+
data: D;
|
|
8
|
+
meta: M;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
interface ProcedureBuilderDef<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> extends Omit<ProcedureDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>, 'handler'> {
|
|
12
|
+
}
|
|
13
|
+
declare class ProcedureBuilder<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
14
|
+
'~crpc': ProcedureBuilderDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>;
|
|
15
|
+
constructor(def: ProcedureBuilderDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>);
|
|
16
|
+
context<UContext extends TCurrentContext>(): ProcedureBuilder<UContext, TInputSchema, TOutputSchema, TMethod>;
|
|
17
|
+
input<USchema extends AnySchema>(schema: USchema): ProcedureBuilder<TCurrentContext, USchema, TOutputSchema, TMethod>;
|
|
18
|
+
output<USchema extends AnySchema>(schema: USchema): ProcedureBuilder<TCurrentContext, TInputSchema, USchema, TMethod>;
|
|
19
|
+
method<UMethod extends RpcApplyType>(method: UMethod): ProcedureBuilder<TCurrentContext, TInputSchema, UMethod extends RpcApplyType.ON ? Schema<void> : TOutputSchema, UMethod>;
|
|
20
|
+
handler<UFuncOutput extends InferSchemaInput<TOutputSchema>>(...handler: ProcedureHandler<OverrideRpcContext<TCurrentContext, InferSchemaOutput<TInputSchema>>, UFuncOutput>[]): Procedure<TCurrentContext, TInputSchema, TOutputSchema extends {
|
|
21
|
+
initial?: true;
|
|
22
|
+
} ? Schema<UFuncOutput> : TOutputSchema, TMethod>;
|
|
23
|
+
}
|
|
24
|
+
declare const procedure: ProcedureBuilder<RpcContext<any, Record<string, any>>, Schema<unknown, unknown>, Schema<void>, RpcApplyType.ON>;
|
|
25
|
+
|
|
26
|
+
interface ContractBuilderDef<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> extends ContractDef<TInputSchema, TOutputSchema, TMethod> {
|
|
27
|
+
}
|
|
28
|
+
declare class ContractBuilder<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
29
|
+
'~crpc': ContractBuilderDef<TInputSchema, TOutputSchema, TMethod>;
|
|
30
|
+
constructor(def: ContractBuilderDef<TInputSchema, TOutputSchema, TMethod>);
|
|
31
|
+
input<USchema extends AnySchema>(schema: USchema): ContractBuilder<TCurrentContext, USchema, TOutputSchema, TMethod>;
|
|
32
|
+
output<USchema extends AnySchema>(schema: USchema): ContractBuilder<TCurrentContext, TInputSchema, USchema, TMethod>;
|
|
33
|
+
method<UMethod extends RpcApplyType>(method: UMethod): ContractBuilder<TCurrentContext, TInputSchema, UMethod extends RpcApplyType.ON ? Schema<void> : TOutputSchema, UMethod>;
|
|
34
|
+
build(): Contract<TInputSchema, TOutputSchema, TMethod>;
|
|
35
|
+
implement<UFuncOutput extends InferSchemaInput<TOutputSchema>>(...handler: ProcedureHandler<OverrideRpcContext<TCurrentContext, InferSchemaOutput<TInputSchema>>, UFuncOutput>[]): Procedure<TCurrentContext, TInputSchema, TOutputSchema extends {
|
|
36
|
+
initial?: true;
|
|
37
|
+
} ? Schema<UFuncOutput> : TOutputSchema, TMethod>;
|
|
38
|
+
}
|
|
39
|
+
declare const contract: ContractBuilder<RpcContext<any, Record<string, any>>, Schema<unknown, unknown>, Schema<void> & {
|
|
40
|
+
initial?: true;
|
|
41
|
+
}, RpcApplyType.ON>;
|
|
42
|
+
|
|
43
|
+
type RpcRouterOptions = {
|
|
44
|
+
validation?: boolean | {
|
|
45
|
+
input?: boolean;
|
|
46
|
+
output?: boolean;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
type InferImplementHandler<TContext extends RpcContext, TContract> = TContract extends AnyContract ? ProcedureHandler<OverrideRpcContext<TContext, InferSchemaOutput<TContract['~crpc']['inputSchema']>>, InferSchemaOutput<TContract['~crpc']['outputSchema']>> : TContract extends Record<string, any> ? {
|
|
50
|
+
[K in keyof TContract]: InferImplementHandler<TContext, TContract[K]>[] | InferImplementHandler<TContext, TContract[K]>;
|
|
51
|
+
} : never;
|
|
52
|
+
declare class RpcRouter<Context extends RpcContext> {
|
|
53
|
+
private readonly rpc;
|
|
54
|
+
private readonly options?;
|
|
55
|
+
readonly contract: ContractBuilder<Context, any, Schema<void>, RpcApplyType.ON>;
|
|
56
|
+
readonly procedure: ProcedureBuilder<Context, any, Schema<void>, RpcApplyType.ON>;
|
|
57
|
+
private store;
|
|
58
|
+
private contractProcedureMap;
|
|
59
|
+
constructor(rpc: RpcBase<any>, options?: RpcRouterOptions | undefined);
|
|
60
|
+
private validateSchema;
|
|
61
|
+
private shouldValidate;
|
|
62
|
+
private registerGlobalMiddleware;
|
|
63
|
+
apply(router: Router): void;
|
|
64
|
+
private findNameByProcedureOrContract;
|
|
65
|
+
implement<T extends AnyContract>(contract: T, ...handler: InferImplementHandler<Context, T>[]): void;
|
|
66
|
+
implement<T extends ContractRouter>(contractTree: T, handlerTree: InferImplementHandler<Context, T>): void;
|
|
67
|
+
private implementContract;
|
|
68
|
+
private implementContractTree;
|
|
69
|
+
unimplement(contract: AnyContract): void;
|
|
70
|
+
unimplement(contractTree: ContractRouter): void;
|
|
71
|
+
private unimplementContract;
|
|
72
|
+
private unimplementContractTree;
|
|
73
|
+
private removeProcedure;
|
|
74
|
+
private applyProcedure;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { AnyContract, Contract, ContractBuilder, ContractDef, ContractRouter, Procedure, ProcedureBuilder, ProcedureDef, ProcedureHandler, Router, RpcRouter, contract, procedure };
|
|
78
|
+
export type { ContractBuilderDef, InferImplementHandler, ProcedureBuilderDef, RpcRouterOptions };
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { RpcApplyType, RpcError, RpcPacketType } from '@cybermp/rpc-core/definitions';
|
|
2
|
+
import { crush } from 'radash';
|
|
3
|
+
|
|
4
|
+
class ProcedureBuilder {
|
|
5
|
+
"~crpc";
|
|
6
|
+
constructor(def) {
|
|
7
|
+
this["~crpc"] = def;
|
|
8
|
+
}
|
|
9
|
+
context() {
|
|
10
|
+
return new ProcedureBuilder(
|
|
11
|
+
this["~crpc"]
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
input(schema) {
|
|
15
|
+
return new ProcedureBuilder({
|
|
16
|
+
...this["~crpc"],
|
|
17
|
+
inputSchema: schema
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
output(schema) {
|
|
21
|
+
return new ProcedureBuilder({
|
|
22
|
+
...this["~crpc"],
|
|
23
|
+
outputSchema: schema
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
method(method) {
|
|
27
|
+
return new ProcedureBuilder({
|
|
28
|
+
...this["~crpc"],
|
|
29
|
+
method
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
handler(...handler) {
|
|
33
|
+
return new Procedure({
|
|
34
|
+
...this["~crpc"],
|
|
35
|
+
handler
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const procedure = new ProcedureBuilder({ method: RpcApplyType.ON });
|
|
40
|
+
|
|
41
|
+
class Procedure {
|
|
42
|
+
"~crpc";
|
|
43
|
+
constructor(def) {
|
|
44
|
+
this["~crpc"] = def;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function isProcedure(item) {
|
|
48
|
+
if (item instanceof Procedure) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return (typeof item === "object" || typeof item === "function") && item !== null && "~crpc" in item && typeof item["~crpc"] === "object" && item["~crpc"] !== null && "handler" in item["~crpc"];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class ContractBuilder {
|
|
55
|
+
"~crpc";
|
|
56
|
+
constructor(def) {
|
|
57
|
+
this["~crpc"] = def;
|
|
58
|
+
}
|
|
59
|
+
input(schema) {
|
|
60
|
+
return new ContractBuilder({
|
|
61
|
+
...this["~crpc"],
|
|
62
|
+
inputSchema: schema
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
output(schema) {
|
|
66
|
+
return new ContractBuilder({
|
|
67
|
+
...this["~crpc"],
|
|
68
|
+
outputSchema: schema
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
method(method) {
|
|
72
|
+
return new ContractBuilder({
|
|
73
|
+
...this["~crpc"],
|
|
74
|
+
method
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
build() {
|
|
78
|
+
return new Contract(this["~crpc"]);
|
|
79
|
+
}
|
|
80
|
+
implement(...handler) {
|
|
81
|
+
return new Procedure({
|
|
82
|
+
...this["~crpc"],
|
|
83
|
+
handler
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const contract = new ContractBuilder({ method: RpcApplyType.ON });
|
|
88
|
+
|
|
89
|
+
class Contract {
|
|
90
|
+
"~crpc";
|
|
91
|
+
constructor(def) {
|
|
92
|
+
this["~crpc"] = def;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function isContract(item) {
|
|
96
|
+
if (item instanceof Contract) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return (typeof item === "object" || typeof item === "function") && item !== null && "~crpc" in item && typeof item["~crpc"] === "object" && item["~crpc"] !== null && !("handler" in item["~crpc"]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
class RpcRouter {
|
|
103
|
+
constructor(rpc, options) {
|
|
104
|
+
this.rpc = rpc;
|
|
105
|
+
this.options = options;
|
|
106
|
+
this.registerGlobalMiddleware();
|
|
107
|
+
}
|
|
108
|
+
contract = new ContractBuilder({
|
|
109
|
+
method: RpcApplyType.ON
|
|
110
|
+
});
|
|
111
|
+
procedure = new ProcedureBuilder({
|
|
112
|
+
method: RpcApplyType.ON
|
|
113
|
+
});
|
|
114
|
+
store = {};
|
|
115
|
+
contractProcedureMap = /* @__PURE__ */ new WeakMap();
|
|
116
|
+
async validateSchema(schema, value) {
|
|
117
|
+
const result = await schema["~standard"].validate(value);
|
|
118
|
+
if (result.issues) {
|
|
119
|
+
throw RpcError.invalidData({
|
|
120
|
+
message: `Validation failed at ${result.issues.map((i) => i.message).join(", ")}`,
|
|
121
|
+
data: {
|
|
122
|
+
issues: result.issues
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return result.value;
|
|
127
|
+
}
|
|
128
|
+
shouldValidate(key) {
|
|
129
|
+
const v = this.options?.validation;
|
|
130
|
+
if (typeof v === "boolean" && v) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if (typeof v === "object") {
|
|
134
|
+
return !!v?.[key];
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
registerGlobalMiddleware() {
|
|
139
|
+
this.rpc.use(async (ctx, next) => {
|
|
140
|
+
if (!ctx.meta.router) {
|
|
141
|
+
return next?.();
|
|
142
|
+
}
|
|
143
|
+
const procedureContext = ctx;
|
|
144
|
+
const procedure = this.store[ctx.packet.method];
|
|
145
|
+
if (!procedure || !isProcedure(procedure)) {
|
|
146
|
+
return next?.();
|
|
147
|
+
}
|
|
148
|
+
procedureContext.procedure = procedure;
|
|
149
|
+
const def = procedure["~crpc"];
|
|
150
|
+
if (def.inputSchema && this.shouldValidate("input")) {
|
|
151
|
+
procedureContext.data = await this.validateSchema(
|
|
152
|
+
def.inputSchema,
|
|
153
|
+
procedureContext.data
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
if (procedureContext.packet.type === RpcPacketType.TRIGGER) {
|
|
157
|
+
return next?.();
|
|
158
|
+
}
|
|
159
|
+
const result = await next?.();
|
|
160
|
+
if (def.outputSchema && this.shouldValidate("output")) {
|
|
161
|
+
const validatedResult = await this.validateSchema(
|
|
162
|
+
def.outputSchema,
|
|
163
|
+
result
|
|
164
|
+
);
|
|
165
|
+
return validatedResult;
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
apply(router) {
|
|
171
|
+
for (const [name, procedure] of Object.entries(this.store)) {
|
|
172
|
+
delete this.store[name];
|
|
173
|
+
if (isContract(procedure)) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
this.removeProcedure(name, procedure);
|
|
177
|
+
}
|
|
178
|
+
const flatRouter = crush(router);
|
|
179
|
+
for (const [name, procedure] of Object.entries(flatRouter)) {
|
|
180
|
+
this.store[name] = procedure;
|
|
181
|
+
if (isContract(procedure)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
this.applyProcedure(name, procedure);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
findNameByProcedureOrContract(c) {
|
|
188
|
+
for (const [key, value] of Object.entries(this.store)) {
|
|
189
|
+
if (value === c) {
|
|
190
|
+
return key;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
implement(contractOrTree, ...handlerOrTree) {
|
|
196
|
+
const [zeroHandler] = handlerOrTree;
|
|
197
|
+
if (isContract(contractOrTree) && typeof zeroHandler !== "object") {
|
|
198
|
+
this.implementContract(contractOrTree, ...handlerOrTree);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
this.implementContractTree(contractOrTree, zeroHandler);
|
|
202
|
+
}
|
|
203
|
+
implementContract(contract, ...handler) {
|
|
204
|
+
if (!isContract(contract)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const name = this.findNameByProcedureOrContract(contract);
|
|
208
|
+
if (!name) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const proc = new Procedure({
|
|
212
|
+
...contract["~crpc"],
|
|
213
|
+
handler
|
|
214
|
+
});
|
|
215
|
+
this.contractProcedureMap.set(contract, proc);
|
|
216
|
+
this.store[name] = proc;
|
|
217
|
+
this.applyProcedure(name, proc);
|
|
218
|
+
}
|
|
219
|
+
implementContractTree(contractTree, handlerTree) {
|
|
220
|
+
for (const [key, contract] of Object.entries(contractTree)) {
|
|
221
|
+
const handler = handlerTree[key];
|
|
222
|
+
if (!handler) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (isContract(contract) && (Array.isArray(handler) || typeof handler === "function")) {
|
|
226
|
+
this.implementContract(
|
|
227
|
+
contract,
|
|
228
|
+
...Array.isArray(handler) ? handler : [handler]
|
|
229
|
+
);
|
|
230
|
+
} else if (typeof contract === "object" && typeof handler === "object") {
|
|
231
|
+
this.implementContractTree(
|
|
232
|
+
contract,
|
|
233
|
+
handler
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
unimplement(contract) {
|
|
239
|
+
if (isContract(contract)) {
|
|
240
|
+
this.unimplementContract(contract);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
this.unimplementContractTree(contract);
|
|
244
|
+
}
|
|
245
|
+
unimplementContract(contract) {
|
|
246
|
+
const proc = this.contractProcedureMap.get(contract);
|
|
247
|
+
if (!proc) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const name = this.findNameByProcedureOrContract(proc);
|
|
251
|
+
if (!name) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this.store[name] = contract;
|
|
255
|
+
this.contractProcedureMap.delete(contract);
|
|
256
|
+
this.removeProcedure(name, proc);
|
|
257
|
+
}
|
|
258
|
+
unimplementContractTree(contractTree) {
|
|
259
|
+
for (const contract of Object.values(contractTree)) {
|
|
260
|
+
if (isContract(contract)) {
|
|
261
|
+
this.unimplementContract(contract);
|
|
262
|
+
} else {
|
|
263
|
+
this.unimplementContractTree(contract);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
removeProcedure(name, procedure) {
|
|
268
|
+
const def = procedure["~crpc"];
|
|
269
|
+
if (def.method === RpcApplyType.REGISTER) {
|
|
270
|
+
this.rpc.unregister(name);
|
|
271
|
+
} else if (def.method === RpcApplyType.ON) {
|
|
272
|
+
this.rpc.offAll(name);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
applyProcedure(name, procedure) {
|
|
276
|
+
const def = procedure["~crpc"];
|
|
277
|
+
if (def.method === RpcApplyType.REGISTER) {
|
|
278
|
+
this.rpc.register(name, ...def.handler);
|
|
279
|
+
} else if (def.method === RpcApplyType.ON) {
|
|
280
|
+
this.rpc.on(name, ...def.handler);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export { Contract, ContractBuilder, Procedure, ProcedureBuilder, RpcRouter, contract, isContract, isProcedure, procedure };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { RpcContext, RpcApplyType, RpcNext } from '@cybermp/rpc-core/definitions';
|
|
2
|
+
|
|
3
|
+
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
4
|
+
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
5
|
+
/** The Standard properties. */
|
|
6
|
+
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
7
|
+
}
|
|
8
|
+
declare namespace StandardTypedV1 {
|
|
9
|
+
/** The Standard Typed properties interface. */
|
|
10
|
+
interface Props<Input = unknown, Output = Input> {
|
|
11
|
+
/** The version number of the standard. */
|
|
12
|
+
readonly version: 1;
|
|
13
|
+
/** The vendor name of the schema library. */
|
|
14
|
+
readonly vendor: string;
|
|
15
|
+
/** Inferred types associated with the schema. */
|
|
16
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** The Standard Typed types interface. */
|
|
19
|
+
interface Types<Input = unknown, Output = Input> {
|
|
20
|
+
/** The input type of the schema. */
|
|
21
|
+
readonly input: Input;
|
|
22
|
+
/** The output type of the schema. */
|
|
23
|
+
readonly output: Output;
|
|
24
|
+
}
|
|
25
|
+
/** Infers the input type of a Standard Typed. */
|
|
26
|
+
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
27
|
+
/** Infers the output type of a Standard Typed. */
|
|
28
|
+
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
29
|
+
}
|
|
30
|
+
/** The Standard Schema interface. */
|
|
31
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
32
|
+
/** The Standard Schema properties. */
|
|
33
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
34
|
+
}
|
|
35
|
+
declare namespace StandardSchemaV1 {
|
|
36
|
+
/** The Standard Schema properties interface. */
|
|
37
|
+
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
38
|
+
/** Validates unknown input values. */
|
|
39
|
+
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
40
|
+
}
|
|
41
|
+
/** The result interface of the validate function. */
|
|
42
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
43
|
+
/** The result interface if validation succeeds. */
|
|
44
|
+
interface SuccessResult<Output> {
|
|
45
|
+
/** The typed output value. */
|
|
46
|
+
readonly value: Output;
|
|
47
|
+
/** A falsy value for `issues` indicates success. */
|
|
48
|
+
readonly issues?: undefined;
|
|
49
|
+
}
|
|
50
|
+
interface Options {
|
|
51
|
+
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
52
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
53
|
+
}
|
|
54
|
+
/** The result interface if validation fails. */
|
|
55
|
+
interface FailureResult {
|
|
56
|
+
/** The issues of failed validation. */
|
|
57
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
58
|
+
}
|
|
59
|
+
/** The issue interface of the failure output. */
|
|
60
|
+
interface Issue {
|
|
61
|
+
/** The error message of the issue. */
|
|
62
|
+
readonly message: string;
|
|
63
|
+
/** The path of the issue, if any. */
|
|
64
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
65
|
+
}
|
|
66
|
+
/** The path segment interface of the issue. */
|
|
67
|
+
interface PathSegment {
|
|
68
|
+
/** The key representing a path segment. */
|
|
69
|
+
readonly key: PropertyKey;
|
|
70
|
+
}
|
|
71
|
+
/** The Standard types interface. */
|
|
72
|
+
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {
|
|
73
|
+
}
|
|
74
|
+
/** Infers the input type of a Standard. */
|
|
75
|
+
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
76
|
+
/** Infers the output type of a Standard. */
|
|
77
|
+
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type Schema<I, O = I> = StandardSchemaV1<I, O>;
|
|
81
|
+
type AnySchema = Schema<any, any>;
|
|
82
|
+
type InferSchemaInput<T extends AnySchema> = T extends StandardSchemaV1<infer UInput, any> ? UInput : never;
|
|
83
|
+
type InferSchemaOutput<T extends AnySchema> = T extends StandardSchemaV1<any, infer UOutput> ? UOutput : never;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
Create a type that represents either the value or the value wrapped in `PromiseLike`.
|
|
87
|
+
|
|
88
|
+
Use-cases:
|
|
89
|
+
- A function accepts a callback that may either return a value synchronously or may return a promised value.
|
|
90
|
+
- This type could be the return type of `Promise#then()`, `Promise#catch()`, and `Promise#finally()` callbacks.
|
|
91
|
+
|
|
92
|
+
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31394) if you want to have this type as a built-in in TypeScript.
|
|
93
|
+
|
|
94
|
+
@example
|
|
95
|
+
```
|
|
96
|
+
import type {Promisable} from 'type-fest';
|
|
97
|
+
|
|
98
|
+
async function logger(getLogEntry: () => Promisable<string>): Promise<void> {
|
|
99
|
+
const entry = await getLogEntry();
|
|
100
|
+
console.log(entry);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await logger(() => 'foo');
|
|
104
|
+
await logger(() => Promise.resolve('bar'));
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
@category Async
|
|
108
|
+
*/
|
|
109
|
+
type Promisable<T> = T | PromiseLike<T>;
|
|
110
|
+
|
|
111
|
+
type ProcedureContext<TCurrentContext extends RpcContext> = TCurrentContext & {
|
|
112
|
+
procedure: AnyProcedure;
|
|
113
|
+
};
|
|
114
|
+
type ProcedureHandler<TCurrentContext extends RpcContext, THandlerOutput> = (ctx: ProcedureContext<TCurrentContext>, next: RpcNext) => Promisable<THandlerOutput>;
|
|
115
|
+
interface ProcedureDef<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
116
|
+
inputSchema?: TInputSchema;
|
|
117
|
+
outputSchema?: TOutputSchema;
|
|
118
|
+
method: TMethod;
|
|
119
|
+
handler: ProcedureHandler<TCurrentContext, any>[];
|
|
120
|
+
}
|
|
121
|
+
declare class Procedure<TCurrentContext extends RpcContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
122
|
+
'~crpc': ProcedureDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>;
|
|
123
|
+
constructor(def: ProcedureDef<TCurrentContext, TInputSchema, TOutputSchema, TMethod>);
|
|
124
|
+
}
|
|
125
|
+
type AnyProcedure = Procedure<any, any, any, RpcApplyType>;
|
|
126
|
+
declare function isProcedure(item: unknown): item is AnyProcedure;
|
|
127
|
+
|
|
128
|
+
interface ContractDef<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
129
|
+
inputSchema?: TInputSchema;
|
|
130
|
+
outputSchema?: TOutputSchema;
|
|
131
|
+
method: TMethod;
|
|
132
|
+
}
|
|
133
|
+
declare class Contract<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType> {
|
|
134
|
+
'~crpc': ContractDef<TInputSchema, TOutputSchema, TMethod>;
|
|
135
|
+
constructor(def: ContractDef<TInputSchema, TOutputSchema, TMethod>);
|
|
136
|
+
}
|
|
137
|
+
type AnyContract = Contract<any, any, RpcApplyType>;
|
|
138
|
+
declare function isContract(item: unknown): item is AnyContract;
|
|
139
|
+
|
|
140
|
+
type ContractProcedure<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TMethod extends RpcApplyType, TCurrentContext extends RpcContext = RpcContext> = Procedure<TCurrentContext, TInputSchema, TOutputSchema, TMethod> | Contract<TInputSchema, TOutputSchema, TMethod>;
|
|
141
|
+
|
|
142
|
+
type Router<C extends RpcContext = RpcContext> = {
|
|
143
|
+
[key: string]: (Procedure<C, any, any, RpcApplyType> | AnyContract) | Router<C>;
|
|
144
|
+
};
|
|
145
|
+
type RouterOrProcedure = Router | ContractProcedure<any, any, any>;
|
|
146
|
+
type ContractRouter = {
|
|
147
|
+
[k: string]: AnyContract | ContractRouter;
|
|
148
|
+
};
|
|
149
|
+
type InferRouterInputs<T extends RouterOrProcedure> = T extends ContractProcedure<infer UInputSchema, any, any> ? InferSchemaInput<UInputSchema> : {
|
|
150
|
+
[K in keyof T]: T[K] extends RouterOrProcedure ? InferRouterInputs<T[K]> : never;
|
|
151
|
+
};
|
|
152
|
+
type InferRouterOutputs<T extends RouterOrProcedure> = T extends ContractProcedure<any, infer UOutputSchema, any> ? InferSchemaOutput<UOutputSchema> : {
|
|
153
|
+
[K in keyof T]: T[K] extends RouterOrProcedure ? InferRouterOutputs<T[K]> : never;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export { Procedure as c, Contract as d, isContract as i, isProcedure as j };
|
|
157
|
+
export type { AnySchema as A, ContractDef as C, InferSchemaInput as I, ProcedureDef as P, Router as R, Schema as S, ProcedureHandler as a, InferSchemaOutput as b, AnyContract as e, ContractRouter as f, ProcedureContext as g, AnyProcedure as h, RouterOrProcedure as k, InferRouterInputs as l, InferRouterOutputs as m, ContractProcedure as n };
|