@xxxaz/json-rpc-schema-typing 0.10.30 → 0.11.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.
Files changed (168) hide show
  1. package/README.md +93 -4
  2. package/cjs/JsonRpcException.js +4 -5
  3. package/cjs/JsonRpcException.js.map +1 -1
  4. package/cjs/JsonRpcMethod.js +22 -8
  5. package/cjs/JsonRpcMethod.js.map +1 -1
  6. package/cjs/JsonRpcValidator.js +12 -4
  7. package/cjs/JsonRpcValidator.js.map +1 -1
  8. package/cjs/JsonSchemaValidator.js +12 -5
  9. package/cjs/JsonSchemaValidator.js.map +1 -1
  10. package/cjs/WebSocketWrapper.js +8 -3
  11. package/cjs/WebSocketWrapper.js.map +1 -1
  12. package/cjs/client/JsonRpcClient.js +77 -14
  13. package/cjs/client/JsonRpcClient.js.map +1 -1
  14. package/cjs/client/JsonRpcHttp2Client.js +8 -6
  15. package/cjs/client/JsonRpcHttp2Client.js.map +1 -1
  16. package/cjs/client/JsonRpcHttpClient.js +5 -5
  17. package/cjs/client/JsonRpcHttpClient.js.map +1 -1
  18. package/cjs/client/JsonRpcMessagePortClient.js +4 -5
  19. package/cjs/client/JsonRpcMessagePortClient.js.map +1 -1
  20. package/cjs/client/JsonRpcWebSocketClient.js +5 -6
  21. package/cjs/client/JsonRpcWebSocketClient.js.map +1 -1
  22. package/cjs/client/index.js +1 -1
  23. package/cjs/client/index.js.map +1 -1
  24. package/cjs/index.js +3 -3
  25. package/cjs/index.js.map +1 -1
  26. package/cjs/router/FileSystemRouter.js +3 -3
  27. package/cjs/router/FileSystemRouter.js.map +1 -1
  28. package/cjs/router/JsonRpcRouter.js.map +1 -1
  29. package/cjs/router/OpenRpc.js +141 -0
  30. package/cjs/router/OpenRpc.js.map +1 -0
  31. package/cjs/router/StaticRouter.js +41 -8
  32. package/cjs/router/StaticRouter.js.map +1 -1
  33. package/cjs/router/hashObject.js +7 -4
  34. package/cjs/router/hashObject.js.map +1 -1
  35. package/cjs/router/index.js +1 -0
  36. package/cjs/router/index.js.map +1 -1
  37. package/cjs/schemas/Complex.js +10 -13
  38. package/cjs/schemas/Complex.js.map +1 -1
  39. package/cjs/schemas/Primitive.js.map +1 -1
  40. package/cjs/schemas/Structure.js +5 -4
  41. package/cjs/schemas/Structure.js.map +1 -1
  42. package/cjs/schemas/index.js +1 -1
  43. package/cjs/schemas/index.js.map +1 -1
  44. package/cjs/server/JsonRpcHttpReceiver.js +11 -6
  45. package/cjs/server/JsonRpcHttpReceiver.js.map +1 -1
  46. package/cjs/server/JsonRpcMessagePortReceiver.js +3 -4
  47. package/cjs/server/JsonRpcMessagePortReceiver.js.map +1 -1
  48. package/cjs/server/JsonRpcServer.js +12 -6
  49. package/cjs/server/JsonRpcServer.js.map +1 -1
  50. package/cjs/server/JsonRpcWebSocketReceiver.js +3 -4
  51. package/cjs/server/JsonRpcWebSocketReceiver.js.map +1 -1
  52. package/cjs/server/index.js +1 -1
  53. package/cjs/server/index.js.map +1 -1
  54. package/cjs/utility.js +8 -14
  55. package/cjs/utility.js.map +1 -1
  56. package/esm/JsonRpcException.js +4 -5
  57. package/esm/JsonRpcException.js.map +1 -1
  58. package/esm/JsonRpcMethod.js +22 -8
  59. package/esm/JsonRpcMethod.js.map +1 -1
  60. package/esm/JsonRpcValidator.js +12 -4
  61. package/esm/JsonRpcValidator.js.map +1 -1
  62. package/esm/JsonSchemaValidator.js +13 -6
  63. package/esm/JsonSchemaValidator.js.map +1 -1
  64. package/esm/WebSocketWrapper.js +8 -3
  65. package/esm/WebSocketWrapper.js.map +1 -1
  66. package/esm/client/JsonRpcClient.js +78 -15
  67. package/esm/client/JsonRpcClient.js.map +1 -1
  68. package/esm/client/JsonRpcHttp2Client.js +10 -8
  69. package/esm/client/JsonRpcHttp2Client.js.map +1 -1
  70. package/esm/client/JsonRpcHttpClient.js +8 -8
  71. package/esm/client/JsonRpcHttpClient.js.map +1 -1
  72. package/esm/client/JsonRpcMessagePortClient.js +6 -7
  73. package/esm/client/JsonRpcMessagePortClient.js.map +1 -1
  74. package/esm/client/JsonRpcWebSocketClient.js +8 -9
  75. package/esm/client/JsonRpcWebSocketClient.js.map +1 -1
  76. package/esm/client/index.js +1 -1
  77. package/esm/client/index.js.map +1 -1
  78. package/esm/index.js +3 -3
  79. package/esm/index.js.map +1 -1
  80. package/esm/router/FileSystemRouter.js +5 -5
  81. package/esm/router/FileSystemRouter.js.map +1 -1
  82. package/esm/router/JsonRpcRouter.js +1 -1
  83. package/esm/router/JsonRpcRouter.js.map +1 -1
  84. package/esm/router/OpenRpc.js +138 -0
  85. package/esm/router/OpenRpc.js.map +1 -0
  86. package/esm/router/StaticRouter.js +42 -9
  87. package/esm/router/StaticRouter.js.map +1 -1
  88. package/esm/router/hashObject.js +7 -4
  89. package/esm/router/hashObject.js.map +1 -1
  90. package/esm/router/index.js +1 -0
  91. package/esm/router/index.js.map +1 -1
  92. package/esm/schemas/Complex.js +10 -13
  93. package/esm/schemas/Complex.js.map +1 -1
  94. package/esm/schemas/Primitive.js.map +1 -1
  95. package/esm/schemas/Structure.js +6 -5
  96. package/esm/schemas/Structure.js.map +1 -1
  97. package/esm/schemas/index.js +1 -1
  98. package/esm/schemas/index.js.map +1 -1
  99. package/esm/server/JsonRpcHttpReceiver.js +13 -8
  100. package/esm/server/JsonRpcHttpReceiver.js.map +1 -1
  101. package/esm/server/JsonRpcMessagePortReceiver.js +3 -4
  102. package/esm/server/JsonRpcMessagePortReceiver.js.map +1 -1
  103. package/esm/server/JsonRpcServer.js +15 -9
  104. package/esm/server/JsonRpcServer.js.map +1 -1
  105. package/esm/server/JsonRpcWebSocketReceiver.js +4 -5
  106. package/esm/server/JsonRpcWebSocketReceiver.js.map +1 -1
  107. package/esm/server/index.js +1 -1
  108. package/esm/server/index.js.map +1 -1
  109. package/esm/utility.js +8 -14
  110. package/esm/utility.js.map +1 -1
  111. package/package.json +4 -1
  112. package/src/JsonRpcException.ts +29 -26
  113. package/src/JsonRpcMethod.ts +173 -33
  114. package/src/JsonRpcValidator.ts +28 -15
  115. package/src/JsonSchemaValidator.ts +54 -25
  116. package/src/WebSocketWrapper.ts +36 -19
  117. package/src/client/JsonRpcClient.ts +188 -58
  118. package/src/client/JsonRpcHttp2Client.ts +55 -34
  119. package/src/client/JsonRpcHttpClient.ts +56 -30
  120. package/src/client/JsonRpcMessagePortClient.ts +36 -27
  121. package/src/client/JsonRpcWebSocketClient.ts +38 -21
  122. package/src/client/index.ts +1 -1
  123. package/src/index.ts +4 -7
  124. package/src/router/FileSystemRouter.ts +37 -21
  125. package/src/router/JsonRpcRouter.ts +50 -24
  126. package/src/router/OpenRpc.ts +262 -0
  127. package/src/router/StaticRouter.ts +115 -16
  128. package/src/router/hashObject.ts +11 -6
  129. package/src/router/index.ts +1 -0
  130. package/src/schemas/Complex.ts +33 -28
  131. package/src/schemas/Primitive.ts +0 -1
  132. package/src/schemas/Structure.ts +18 -9
  133. package/src/schemas/index.ts +1 -1
  134. package/src/server/JsonRpcHttpReceiver.ts +60 -28
  135. package/src/server/JsonRpcMessagePortReceiver.ts +27 -16
  136. package/src/server/JsonRpcServer.ts +59 -29
  137. package/src/server/JsonRpcWebSocketReceiver.ts +32 -25
  138. package/src/server/index.ts +1 -1
  139. package/src/types.ts +72 -43
  140. package/src/utility.ts +13 -19
  141. package/types/JsonRpcException.d.ts +2 -2
  142. package/types/JsonRpcMethod.d.ts +70 -3
  143. package/types/JsonRpcValidator.d.ts +3 -3
  144. package/types/JsonSchemaValidator.d.ts +2 -2
  145. package/types/WebSocketWrapper.d.ts +2 -2
  146. package/types/client/JsonRpcClient.d.ts +20 -9
  147. package/types/client/JsonRpcHttp2Client.d.ts +8 -6
  148. package/types/client/JsonRpcHttpClient.d.ts +7 -5
  149. package/types/client/JsonRpcMessagePortClient.d.ts +3 -3
  150. package/types/client/JsonRpcWebSocketClient.d.ts +4 -4
  151. package/types/client/index.d.ts +1 -1
  152. package/types/index.d.ts +3 -3
  153. package/types/router/FileSystemRouter.d.ts +3 -3
  154. package/types/router/JsonRpcRouter.d.ts +2 -2
  155. package/types/router/OpenRpc.d.ts +101 -0
  156. package/types/router/StaticRouter.d.ts +40 -4
  157. package/types/router/hashObject.d.ts +1 -1
  158. package/types/router/index.d.ts +1 -0
  159. package/types/schemas/Complex.d.ts +4 -4
  160. package/types/schemas/Structure.d.ts +5 -2
  161. package/types/schemas/index.d.ts +1 -1
  162. package/types/server/JsonRpcHttpReceiver.d.ts +2 -2
  163. package/types/server/JsonRpcMessagePortReceiver.d.ts +2 -2
  164. package/types/server/JsonRpcServer.d.ts +2 -2
  165. package/types/server/JsonRpcWebSocketReceiver.d.ts +1 -1
  166. package/types/server/index.d.ts +1 -1
  167. package/types/types.d.ts +12 -6
  168. package/types/utility.d.ts +2 -2
@@ -1,6 +1,6 @@
1
- import { type JSONSchema, type FromSchema } from "./types.js";
2
1
  import { InvalidContext } from './JsonRpcException.js';
3
2
  import { $Object, $Tuple } from './schemas/Structure.js';
3
+ import type { FromSchema, JSONSchema } from './types.js';
4
4
 
5
5
  type ByPositionSchema = {
6
6
  readonly type: 'array';
@@ -13,36 +13,118 @@ type ByNameSchema = {
13
13
  readonly type: 'object';
14
14
  readonly properties: ObjectProperties;
15
15
  };
16
- export type ParameterSchema = ByPositionSchema|ByNameSchema|undefined;
16
+ export type ParameterSchema = ByPositionSchema | ByNameSchema | undefined;
17
17
 
18
- export interface JsonRpcMethodSchema<PrmSch extends ParameterSchema, RtnSch extends JSONSchema|undefined> {
18
+ export interface JsonRpcMethodSchema<
19
+ PrmSch extends ParameterSchema,
20
+ RtnSch extends JSONSchema | undefined,
21
+ > {
19
22
  readonly $params?: PrmSch;
20
23
  readonly $return?: RtnSch;
21
24
  }
22
25
 
23
- export type Params<Schema>
24
- = Schema extends ByPositionSchema
25
- ? FromSchema<Schema>
26
+ /**
27
+ * クライアント generic (`Schema`) の受け口となる leaf 型。
28
+ * - 素の method schema (`$params`/`$return`) … 従来の JsonRpcSchema 経路 (WS/MessagePort 等)
29
+ * - `JsonRpcMethodDefinition` … StaticRouter に直接埋めた定義
30
+ * - `() => Promise<...>` / `Promise<...>` … route thunk map (lazy import) 経路
31
+ */
32
+ type SchemaLeaf =
33
+ | JsonRpcMethodSchema<any, any>
34
+ | JsonRpcMethodDefinition<any, any, any>
35
+ | (() => Promise<unknown>)
36
+ | Promise<unknown>;
37
+
38
+ /**
39
+ * クライアント generic の**適合検証用の固定上限型**。
40
+ * 自己参照 (`Schema extends Conforms<Schema>`) や厳密な `RouteMap<Ctx>` は
41
+ * 巨大な route リテラルで TS2589 (instantiation too deep) を誘発するため、
42
+ * 「各 path が leaf か、さらに入れ子の schema 形」という**非自己参照の再帰上限**にして
43
+ * 適合検証を必ず通しつつ再帰爆発を避ける。primitive / 非 method 形の leaf は弾かれる。
44
+ */
45
+ export type AnySchemaShape = {
46
+ readonly [path: string]: SchemaLeaf | AnySchemaShape;
47
+ };
48
+
49
+ export type Params<Schema> = Schema extends ByPositionSchema
50
+ ? FromSchema<Schema>
26
51
  : Schema extends ByNameSchema
27
- ? [FromSchema<Schema>]
28
- : Schema extends undefined
52
+ ? [FromSchema<Schema>]
53
+ : Schema extends undefined
29
54
  ? []
30
- : never;
31
- export type Return<Schema>
32
- = Schema extends undefined
33
- ? void
55
+ : never;
56
+ export type Return<Schema> = Schema extends undefined
57
+ ? void
34
58
  : Schema extends JSONSchema
35
- ? FromSchema<Schema>
36
- : never;
37
-
38
- export type JsonRpcMethod<Context, PrmSch extends ParameterSchema, RtnSch extends JSONSchema|undefined>
39
- = (this: Context, ...params: Params<PrmSch>) => Promise<Return<RtnSch>>|Return<RtnSch>;
40
-
41
- type ContextClass<Ctx> = { new(...args: any[]): Ctx };
59
+ ? FromSchema<Schema>
60
+ : never;
61
+
62
+ export type JsonRpcMethod<
63
+ Context,
64
+ PrmSch extends ParameterSchema,
65
+ RtnSch extends JSONSchema | undefined,
66
+ > = (
67
+ this: Context,
68
+ ...params: Params<PrmSch>
69
+ ) => Promise<Return<RtnSch>> | Return<RtnSch>;
70
+
71
+ type ContextClass<Ctx> = { new (...args: any[]): Ctx };
42
72
  type Context<Cls, FB> = Cls extends ContextClass<infer Ctx> ? Ctx : FB;
43
73
 
74
+ /**
75
+ * OpenRPC 準拠のメソッドメタ情報。
76
+ * 型 (JsonRpcCaller 等) は $params/$return のみ参照するため、メタは呼び出し型に影響しない。
77
+ */
78
+ export type JsonRpcParameterMeta = {
79
+ readonly summary?: string;
80
+ readonly description?: string;
81
+ readonly required?: boolean;
82
+ readonly deprecated?: boolean;
83
+ };
84
+ export type JsonRpcResultMeta = {
85
+ readonly name: string;
86
+ readonly summary?: string;
87
+ readonly description?: string;
88
+ };
89
+ export type JsonRpcErrorMeta = {
90
+ readonly code: number;
91
+ readonly message: string;
92
+ readonly data?: unknown;
93
+ };
94
+ export type JsonRpcExampleMeta = {
95
+ readonly name: string;
96
+ readonly summary?: string;
97
+ readonly description?: string;
98
+ readonly params: readonly unknown[] | Readonly<Record<string, unknown>>;
99
+ readonly result?: unknown;
100
+ };
101
+ export type JsonRpcExternalDocsMeta = {
102
+ readonly url: string;
103
+ readonly description?: string;
104
+ };
105
+ export type JsonRpcMethodMeta = {
106
+ readonly summary?: string;
107
+ readonly description?: string;
108
+ readonly tags?: readonly string[];
109
+ readonly result?: JsonRpcResultMeta;
110
+ /**
111
+ * パラメータ別メタ。paramsByName の場合キーは $Object のプロパティ名。
112
+ * paramsByPosition の場合はキーの記述順が位置に対応する (キー名が param name になる)。
113
+ */
114
+ readonly params?: Readonly<Record<string, JsonRpcParameterMeta>>;
115
+ readonly errors?: readonly JsonRpcErrorMeta[];
116
+ readonly examples?: readonly JsonRpcExampleMeta[];
117
+ readonly deprecated?: boolean;
118
+ readonly externalDocs?: JsonRpcExternalDocsMeta;
119
+ };
120
+
44
121
  const methodKey = Symbol('JsonRpcMethodDefinition.method');
45
- export class JsonRpcMethodDefinition<Context, PrmSch extends ParameterSchema, RtnSch extends JSONSchema|undefined> implements JsonRpcMethodSchema<PrmSch, RtnSch> {
122
+ export class JsonRpcMethodDefinition<
123
+ Context,
124
+ PrmSch extends ParameterSchema,
125
+ RtnSch extends JSONSchema | undefined,
126
+ > implements JsonRpcMethodSchema<PrmSch, RtnSch>
127
+ {
46
128
  static readonly method: typeof methodKey = methodKey;
47
129
  readonly [methodKey]: JsonRpcMethod<Context, PrmSch, RtnSch>;
48
130
 
@@ -51,53 +133,111 @@ export class JsonRpcMethodDefinition<Context, PrmSch extends ParameterSchema, Rt
51
133
  readonly $params: PrmSch,
52
134
  readonly $return: RtnSch,
53
135
  readonly $contextClass?: ContextClass<Context>,
136
+ readonly $meta?: JsonRpcMethodMeta,
54
137
  ) {
55
138
  this[methodKey] = method;
56
139
  }
57
140
 
141
+ // instanceof はモジュール実体が二重ロードされた際に一致しないため、duck-typing でも判定する
142
+ static isDefinition(
143
+ obj: unknown,
144
+ ): obj is JsonRpcMethodDefinition<any, any, any> {
145
+ if (obj instanceof JsonRpcMethodDefinition) return true;
146
+ const key = (obj as any)?.constructor?.method;
147
+ return typeof key === 'symbol' && (obj as any)[key] instanceof Function;
148
+ }
149
+
58
150
  $apply(ctx: Context, params: any) {
59
- if(this.$contextClass && !(ctx instanceof this.$contextClass)) {
151
+ if (this.$contextClass && !(ctx instanceof this.$contextClass)) {
60
152
  const passedCtxType = (ctx as any)?.constructor?.name ?? typeof ctx;
61
- throw new InvalidContext(`Invalid context: expected ${this.$contextClass.name} but got ${passedCtxType}`);
153
+ throw new InvalidContext(
154
+ `Invalid context: expected ${this.$contextClass.name} but got ${passedCtxType}`,
155
+ );
62
156
  }
63
157
  if (this.$params?.type === 'object') params = [params];
64
158
  return this[methodKey].apply(ctx, params);
65
159
  }
66
160
 
67
- static get builder(){
161
+ static get builder() {
68
162
  return new DefinitionBuilder(undefined, undefined, undefined);
69
163
  }
70
164
  }
71
165
 
72
- class DefinitionBuilder<CtxCls extends ContextClass<any>|undefined, PrmSch extends ParameterSchema, RtnSch extends JSONSchema|undefined> implements JsonRpcMethodSchema<PrmSch, RtnSch> {
166
+ class DefinitionBuilder<
167
+ CtxCls extends ContextClass<any> | undefined,
168
+ PrmSch extends ParameterSchema,
169
+ RtnSch extends JSONSchema | undefined,
170
+ > implements JsonRpcMethodSchema<PrmSch, RtnSch>
171
+ {
73
172
  constructor(
74
173
  readonly $contextClass: CtxCls,
75
174
  readonly $params: PrmSch,
76
175
  readonly $return: RtnSch,
176
+ readonly $meta?: JsonRpcMethodMeta,
77
177
  ) {}
78
178
 
79
- define<Ctx = {}>(method: JsonRpcMethod<Context<CtxCls, Ctx>, PrmSch, RtnSch>) {
80
- return new JsonRpcMethodDefinition<Context<CtxCls, Ctx>, PrmSch, RtnSch>(method, this.$params, this.$return, this.$contextClass);
179
+ define<Ctx = {}>(
180
+ method: JsonRpcMethod<Context<CtxCls, Ctx>, PrmSch, RtnSch>,
181
+ ) {
182
+ return new JsonRpcMethodDefinition<
183
+ Context<CtxCls, Ctx>,
184
+ PrmSch,
185
+ RtnSch
186
+ >(method, this.$params, this.$return, this.$contextClass, this.$meta);
81
187
  }
82
188
 
83
189
  contextClass<CtxCls extends ContextClass<any>>(contextClass: CtxCls) {
84
- return new DefinitionBuilder(contextClass, this.$params, this.$return);
190
+ return new DefinitionBuilder(
191
+ contextClass,
192
+ this.$params,
193
+ this.$return,
194
+ this.$meta,
195
+ );
196
+ }
197
+
198
+ meta(meta: JsonRpcMethodMeta) {
199
+ return new DefinitionBuilder(
200
+ this.$contextClass,
201
+ this.$params,
202
+ this.$return,
203
+ meta,
204
+ );
85
205
  }
86
206
 
87
207
  params<NewPrm extends ParameterSchema>(params: NewPrm) {
88
- return new DefinitionBuilder(this.$contextClass, params, this.$return);
208
+ return new DefinitionBuilder(
209
+ this.$contextClass,
210
+ params,
211
+ this.$return,
212
+ this.$meta,
213
+ );
89
214
  }
90
215
 
91
216
  paramsByName<NewPrm extends ObjectProperties>(params: NewPrm) {
92
- return new DefinitionBuilder(this.$contextClass, $Object(params), this.$return);
217
+ return new DefinitionBuilder(
218
+ this.$contextClass,
219
+ $Object(params),
220
+ this.$return,
221
+ this.$meta,
222
+ );
93
223
  }
94
224
 
95
225
  paramsByPosition<NewPrm extends readonly JSONSchema[]>(...params: NewPrm) {
96
- return new DefinitionBuilder(this.$contextClass, $Tuple(...params), this.$return);
226
+ return new DefinitionBuilder(
227
+ this.$contextClass,
228
+ $Tuple(...params),
229
+ this.$return,
230
+ this.$meta,
231
+ );
97
232
  }
98
233
 
99
- return<NewRtn extends JSONSchema|undefined>(rtn: NewRtn) {
100
- return new DefinitionBuilder(this.$contextClass, this.$params, rtn);
234
+ return<NewRtn extends JSONSchema | undefined>(rtn: NewRtn) {
235
+ return new DefinitionBuilder(
236
+ this.$contextClass,
237
+ this.$params,
238
+ rtn,
239
+ this.$meta,
240
+ );
101
241
  }
102
242
 
103
243
  /** @deprecated paramsByPosition を使用してください */
@@ -105,7 +245,7 @@ class DefinitionBuilder<CtxCls extends ContextClass<any>|undefined, PrmSch exten
105
245
  return this.paramsByPosition(...params);
106
246
  }
107
247
  /** @deprecated return を使用してください */
108
- returnSchema<NewRtn extends JSONSchema|undefined>(rtn: NewRtn) {
248
+ returnSchema<NewRtn extends JSONSchema | undefined>(rtn: NewRtn) {
109
249
  return this.return(rtn);
110
250
  }
111
251
  }
@@ -1,41 +1,54 @@
1
- import { FromSchema } from 'json-schema-to-ts';
2
- import { JsonRpcMethodSchema, ParameterSchema } from "./JsonRpcMethod.js";
3
- import { JSONSchema } from "./types.js";
1
+ import type { FromSchema } from 'json-schema-to-ts';
4
2
  import { InvalidParams, InvalidReturn } from './JsonRpcException.js';
3
+ import type { JsonRpcMethodSchema, ParameterSchema } from './JsonRpcMethod.js';
5
4
  import { JsonSchemaValidator } from './JsonSchemaValidator.js';
5
+ import type { JSONSchema } from './types.js';
6
6
 
7
7
  type Valid<S> = S extends JSONSchema ? FromSchema<S> : never;
8
8
 
9
9
  export class JsonRpcValidator<
10
10
  P extends ParameterSchema,
11
11
  R extends JSONSchema | undefined,
12
- Sch extends JsonRpcMethodSchema<P, R>
12
+ Sch extends JsonRpcMethodSchema<P, R>,
13
13
  > {
14
14
  constructor(readonly schema: Sch) {
15
- this.#paramValidator = schema.$params ? new JsonSchemaValidator(schema.$params): null;
16
- this.#returnValidator = schema.$return ? new JsonSchemaValidator(schema.$return) : null;
15
+ this.#paramValidator = schema.$params
16
+ ? new JsonSchemaValidator(schema.$params)
17
+ : null;
18
+ this.#returnValidator = schema.$return
19
+ ? new JsonSchemaValidator(schema.$return)
20
+ : null;
17
21
  }
18
- #paramValidator:JsonSchemaValidator | null;
19
- #returnValidator:JsonSchemaValidator | null;
22
+ #paramValidator: JsonSchemaValidator | null;
23
+ #returnValidator: JsonSchemaValidator | null;
20
24
 
21
25
  validateParams(params: unknown): Valid<Sch['$params']> {
22
- if(!this.#paramValidator) return params as Valid<Sch['$params']>;
26
+ if (!this.#paramValidator) return params as Valid<Sch['$params']>;
23
27
  const validated = this.#paramValidator.validate(params);
24
- if(!validated.valid && validated.errors.length > 0) {
25
- const message = validated.errors.map(({ instancePath, message }) => `params${instancePath ?? ''}: ${message}`).join('\n');
28
+ if (!validated.valid && validated.errors.length > 0) {
29
+ const message = validated.errors
30
+ .map(
31
+ ({ instancePath, message }) =>
32
+ `params${instancePath ?? ''}: ${message}`,
33
+ )
34
+ .join('\n');
26
35
  throw new InvalidParams(message, validated.errors);
27
36
  }
28
37
  return params as Valid<Sch['$params']>;
29
38
  }
30
39
 
31
40
  validateReturn(result: unknown): Valid<Sch['$return']> {
32
- if(!this.#returnValidator) return result as Valid<Sch['$return']>;
41
+ if (!this.#returnValidator) return result as Valid<Sch['$return']>;
33
42
  const validated = this.#returnValidator.validate(result);
34
43
  if (!validated.valid && validated.errors.length > 0) {
35
- const message = validated.errors.map(({ instancePath, message }) => `return.${instancePath ?? ''}: ${message}`).join('\n');
44
+ const message = validated.errors
45
+ .map(
46
+ ({ instancePath, message }) =>
47
+ `return.${instancePath ?? ''}: ${message}`,
48
+ )
49
+ .join('\n');
36
50
  throw new InvalidReturn(message, validated.errors);
37
51
  }
38
52
  return result as Valid<Sch['$return']>;
39
53
  }
40
-
41
- }
54
+ }
@@ -1,5 +1,10 @@
1
- import { Ajv, Options as AjvOptions, ValidateFunction, ErrorObject } from 'ajv';
2
- import { type JSONSchema } from 'json-schema-to-ts';
1
+ import {
2
+ Ajv,
3
+ type Options as AjvOptions,
4
+ type ErrorObject,
5
+ type ValidateFunction,
6
+ } from 'ajv';
7
+ import type { JSONSchema } from 'json-schema-to-ts';
3
8
  import type { Worker as NodeWorker } from 'worker_threads';
4
9
 
5
10
  const isBrowser =
@@ -16,12 +21,14 @@ function currentFile() {
16
21
  return globalThis.__filename;
17
22
  }
18
23
  try {
19
- return Function("return import.meta.filename")();
24
+ return Function('return import.meta.filename')();
20
25
  } catch (err) {
21
26
  if (!(err instanceof SyntaxError)) throw err;
22
27
  }
23
28
 
24
- const script = globalThis.document?.currentScript as HTMLScriptElement | undefined;
29
+ const script = globalThis.document?.currentScript as
30
+ | HTMLScriptElement
31
+ | undefined;
25
32
  if (script?.src) {
26
33
  return script?.src;
27
34
  }
@@ -29,7 +36,6 @@ function currentFile() {
29
36
  return null;
30
37
  }
31
38
 
32
-
33
39
  type SerializedError = {
34
40
  propertyName?: string;
35
41
  message?: string;
@@ -39,26 +45,35 @@ type SerializedError = {
39
45
  schemaPath?: string;
40
46
  };
41
47
 
42
- function * serializeErrors(error?: ErrorObject[]|null) : Generator<SerializedError> {
43
- if(!error) return;
44
- for(const { propertyName, message, schemaPath, data, keyword, instancePath, params } of error) {
48
+ function* serializeErrors(
49
+ error?: ErrorObject[] | null,
50
+ ): Generator<SerializedError> {
51
+ if (!error) return;
52
+ for (const {
53
+ propertyName,
54
+ message,
55
+ schemaPath,
56
+ data,
57
+ keyword,
58
+ instancePath,
59
+ params,
60
+ } of error) {
45
61
  const err = {} as SerializedError;
46
- if(propertyName) err.propertyName = propertyName;
47
- if(message) err.message = message;
48
- if(data) err.data = data;
49
- if(keyword) err.keyword = keyword;
50
- if(instancePath) err.instancePath = instancePath;
51
- if(schemaPath) err.schemaPath = schemaPath;
62
+ if (propertyName) err.propertyName = propertyName;
63
+ if (message) err.message = message;
64
+ if (data) err.data = data;
65
+ if (keyword) err.keyword = keyword;
66
+ if (instancePath) err.instancePath = instancePath;
67
+ if (schemaPath) err.schemaPath = schemaPath;
52
68
  if (Object.keys(err).length > 0) {
53
69
  yield err;
54
70
  }
55
71
  if (params.errors) {
56
- yield * serializeErrors(params.errors);
72
+ yield* serializeErrors(params.errors);
57
73
  }
58
74
  }
59
75
  }
60
76
 
61
-
62
77
  type ValidationResult =
63
78
  | { valid: true }
64
79
  | {
@@ -72,7 +87,7 @@ const methodName = '@xxxaz/json-schema-typing.JsonSchemaValidator.validate';
72
87
  export class JsonSchemaValidator {
73
88
  constructor(
74
89
  readonly schema: JSONSchema & object,
75
- ajvOptions?: AjvOptions
90
+ ajvOptions?: AjvOptions,
76
91
  ) {
77
92
  this.#ajv = new Ajv(ajvOptions);
78
93
  this.#validate = this.#ajv.compile(this.schema);
@@ -106,13 +121,18 @@ export class JsonSchemaValidator {
106
121
  const id = crypto.randomUUID();
107
122
  const listener = Promise.withResolvers<ValidationResult>();
108
123
  listeners[id] = listener;
109
- worker.postMessage({ method: methodName, schema: this.schema, data, id });
124
+ worker.postMessage({
125
+ method: methodName,
126
+ schema: this.schema,
127
+ data,
128
+ id,
129
+ });
110
130
  return listener.promise;
111
131
  }
112
132
  }
113
133
 
114
134
  type WorkerType = NodeWorker | Worker;
115
- let workers: WeakMap<object, WorkerType> = new WeakMap();
135
+ const workers: WeakMap<object, WorkerType> = new WeakMap();
116
136
  let listeners: Record<string, PromiseWithResolvers<ValidationResult>> = {};
117
137
  async function getWorker(key: object): Promise<WorkerType | null> {
118
138
  if (workers.has(key)) return workers.get(key) ?? null;
@@ -138,7 +158,11 @@ async function getWorker(key: object): Promise<WorkerType | null> {
138
158
  workers.set(key, worker);
139
159
  return worker;
140
160
  }
141
- function onMessage(data: {id: string, result?: ValidationResult, error?: any}) {
161
+ function onMessage(data: {
162
+ id: string;
163
+ result?: ValidationResult;
164
+ error?: any;
165
+ }) {
142
166
  const listener = listeners[data.id];
143
167
  if (listener) {
144
168
  if (data.error) {
@@ -150,7 +174,9 @@ function onMessage(data: {id: string, result?: ValidationResult, error?: any}) {
150
174
  }
151
175
  }
152
176
  function onError(err: Error) {
153
- Object.values(listeners).forEach(({ reject }) => reject(err));
177
+ Object.values(listeners).forEach(({ reject }) => {
178
+ reject(err);
179
+ });
154
180
  listeners = {};
155
181
  }
156
182
  function onFaild(data: { id: string }) {
@@ -162,7 +188,12 @@ function onFaild(data: { id: string }) {
162
188
  }
163
189
 
164
190
  (async function kickValidateInWorker(): Promise<void> {
165
- type ReceiveMesg = { method: string; id: string; schema: JSONSchema & object; data: unknown };
191
+ type ReceiveMesg = {
192
+ method: string;
193
+ id: string;
194
+ schema: JSONSchema & object;
195
+ data: unknown;
196
+ };
166
197
  const onMessage = (msg: ReceiveMesg, callback: (result: {}) => void) => {
167
198
  const { id, schema, data } = msg;
168
199
  try {
@@ -180,7 +211,7 @@ function onFaild(data: { id: string }) {
180
211
  if (msg.method !== methodName) return;
181
212
  onMessage(msg, (result) => parentPort.postMessage(result));
182
213
  });
183
- }
214
+ }
184
215
  if (isWebWorker) {
185
216
  self.addEventListener('message', (ev) => {
186
217
  const msg = ev.data as ReceiveMesg;
@@ -191,5 +222,3 @@ function onFaild(data: { id: string }) {
191
222
  });
192
223
  }
193
224
  })();
194
-
195
-
@@ -1,12 +1,20 @@
1
- import { type WebSocket as NodeWebSocket, type RawData } from 'ws';
2
- import { type JsonSerializable } from "@xxxaz/stream-api-json";
3
-
4
- export type WrapableWebSocket = WebSocket|NodeWebSocket;
5
- export function wrapWebSocket(socket: WrapableWebSocket, listener: SocketListener, closedListener: ScokcetClosedListener) {
1
+ import type { JsonSerializable } from '@xxxaz/stream-api-json';
2
+ import type { WebSocket as NodeWebSocket, RawData } from 'ws';
3
+
4
+ export type WrapableWebSocket = WebSocket | NodeWebSocket;
5
+ export function wrapWebSocket(
6
+ socket: WrapableWebSocket,
7
+ listener: SocketListener,
8
+ closedListener: ScokcetClosedListener,
9
+ ) {
6
10
  if ('WebSocket' in globalThis && socket instanceof WebSocket) {
7
11
  return new BrowserWebSocketWrapper(socket, listener, closedListener);
8
12
  }
9
- return new NodeWebSocketWrapper(socket as NodeWebSocket, listener, closedListener);
13
+ return new NodeWebSocketWrapper(
14
+ socket as NodeWebSocket,
15
+ listener,
16
+ closedListener,
17
+ );
10
18
  }
11
19
 
12
20
  type ClosedData = {
@@ -19,10 +27,12 @@ type ClosedData = {
19
27
  type SocketListener = (data: JsonSerializable) => void;
20
28
  type ScokcetClosedListener = (data: ClosedData) => void;
21
29
 
22
- type ConnectionState = 'CONNECTING'|'OPEN'|'CLOSING'|'CLOSED';
30
+ type ConnectionState = 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED';
23
31
  export type WebSocketState = (typeof WebSocket)[ConnectionState];
24
32
 
25
- export interface WebSocketWrapper<Socket extends WrapableWebSocket = WrapableWebSocket> {
33
+ export interface WebSocketWrapper<
34
+ Socket extends WrapableWebSocket = WrapableWebSocket,
35
+ > {
26
36
  readonly socket: Socket;
27
37
  readonly listener: SocketListener;
28
38
  readonly readyState: WebSocketState;
@@ -35,7 +45,7 @@ export class NodeWebSocketWrapper implements WebSocketWrapper<NodeWebSocket> {
35
45
  constructor(
36
46
  readonly socket: NodeWebSocket,
37
47
  readonly listener: SocketListener,
38
- readonly closedListener: ScokcetClosedListener
48
+ readonly closedListener: ScokcetClosedListener,
39
49
  ) {
40
50
  socket.on('message', this.#onMessage);
41
51
  socket.on('close', (code, reasonBuffer) => {
@@ -67,14 +77,14 @@ export class NodeWebSocketWrapper implements WebSocketWrapper<NodeWebSocket> {
67
77
  this.listener(parsed);
68
78
  };
69
79
 
70
- async #parseMessage(data: RawData) : Promise<JsonSerializable> {
80
+ async #parseMessage(data: RawData): Promise<JsonSerializable> {
71
81
  if (data instanceof ArrayBuffer) {
72
82
  return JSON.parse(await new Blob([data]).text());
73
83
  }
74
- const json
75
- = data instanceof Array
76
- ? data.map(d=>JSON.parse(d.toString())).join('')
77
- : data.toString()
84
+ const json =
85
+ data instanceof Array
86
+ ? data.map((d) => JSON.parse(d.toString())).join('')
87
+ : data.toString();
78
88
  return JSON.parse(json);
79
89
  }
80
90
  }
@@ -83,11 +93,16 @@ export class BrowserWebSocketWrapper implements WebSocketWrapper<WebSocket> {
83
93
  constructor(
84
94
  readonly socket: WebSocket,
85
95
  readonly listener: SocketListener,
86
- readonly closedListener: ScokcetClosedListener
96
+ readonly closedListener: ScokcetClosedListener,
87
97
  ) {
88
98
  socket.addEventListener('message', this.#onMessage);
89
- socket.addEventListener('close', ev => {
90
- closedListener({ code: ev.code, reason: ev.reason, wasClean: ev.wasClean, wrapper: this });
99
+ socket.addEventListener('close', (ev) => {
100
+ closedListener({
101
+ code: ev.code,
102
+ reason: ev.reason,
103
+ wasClean: ev.wasClean,
104
+ wrapper: this,
105
+ });
91
106
  this.socket.removeEventListener('message', this.#onMessage);
92
107
  });
93
108
  }
@@ -101,7 +116,9 @@ export class BrowserWebSocketWrapper implements WebSocketWrapper<WebSocket> {
101
116
  this.listener(parsed);
102
117
  };
103
118
 
104
- async #parseMessage(data: ArrayBuffer|string|object) : Promise<JsonSerializable> {
119
+ async #parseMessage(
120
+ data: ArrayBuffer | string | object,
121
+ ): Promise<JsonSerializable> {
105
122
  if (data instanceof ArrayBuffer) {
106
123
  return JSON.parse(await new Blob([data]).text());
107
124
  }
@@ -127,4 +144,4 @@ export class BrowserWebSocketWrapper implements WebSocketWrapper<WebSocket> {
127
144
  this.detach();
128
145
  this.socket.close();
129
146
  }
130
- }
147
+ }