@fraqjs/fraq 0.4.0 → 0.5.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.mts CHANGED
@@ -5507,6 +5507,58 @@ type Pattern = Record<string, Parameter<any>>;
5507
5507
  type ParamsOf<P extends Pattern> = { [K in keyof P]: P[K] extends Parameter<infer T> ? T : never };
5508
5508
  type Handler<P extends Pattern> = (session: Session, params: ParamsOf<P>) => void | Promise<void>;
5509
5509
  type SessionPredicate = (session: Session) => boolean;
5510
+ interface Command {
5511
+ name: string;
5512
+ pattern: Pattern;
5513
+ handler: (session: Session, params: any) => void | Promise<void>;
5514
+ }
5515
+ interface RawPattern {
5516
+ pattern: Pattern;
5517
+ handler: (session: Session, params: any) => void | Promise<void>;
5518
+ }
5519
+ type RouteEntry =
5520
+ | {
5521
+ type: 'command';
5522
+ command: Command;
5523
+ }
5524
+ | {
5525
+ type: 'group';
5526
+ name: string;
5527
+ router: Router;
5528
+ }
5529
+ | {
5530
+ type: 'filter';
5531
+ predicate: SessionPredicate;
5532
+ router: Router;
5533
+ }
5534
+ | {
5535
+ type: 'rawPattern';
5536
+ rawPattern: RawPattern;
5537
+ };
5538
+ type RouteBranch =
5539
+ | {
5540
+ type: 'command';
5541
+ path: string[];
5542
+ command: Command;
5543
+ }
5544
+ | {
5545
+ type: 'rawPattern';
5546
+ path: string[];
5547
+ rawPattern: RawPattern;
5548
+ };
5549
+ type RouteMatchResult =
5550
+ | {
5551
+ type: 'command';
5552
+ path: string[];
5553
+ command: Command;
5554
+ params: any;
5555
+ }
5556
+ | {
5557
+ type: 'rawPattern';
5558
+ path: string[];
5559
+ rawPattern: RawPattern;
5560
+ params: any;
5561
+ };
5510
5562
  interface Session {
5511
5563
  raw: IncomingMessage;
5512
5564
  reply(segments: OutgoingSegment_ZodInput[]): Promise<void>;
@@ -5518,12 +5570,16 @@ declare class Router {
5518
5570
  rawPattern<P extends Pattern>(pattern: P, handler: Handler<P>): this;
5519
5571
  group(name: string): Router;
5520
5572
  filter(predicate: SessionPredicate): Router;
5573
+ routes(): RouteEntry[];
5574
+ branches(session: Session): RouteBranch[];
5575
+ match(session: Session, message: IncomingMessage): RouteMatchResult | undefined;
5521
5576
  dispatch(session: Session, message: IncomingMessage): Promise<boolean>;
5522
- private process;
5523
- private processEntry;
5524
- private processCommand;
5525
- private processGroup;
5526
- private processRawPattern;
5577
+ private matchFrom;
5578
+ private matchEntry;
5579
+ private matchCommand;
5580
+ private matchGroup;
5581
+ private matchRawPattern;
5582
+ private branchesFrom;
5527
5583
  private capturePattern;
5528
5584
  }
5529
5585
  //#endregion
@@ -5630,6 +5686,7 @@ declare class Context {
5630
5686
  tryResolve<T extends object>(service: ServiceClass<T>): T | undefined;
5631
5687
  isProvided<T extends object>(service: ServiceClass<T>): boolean;
5632
5688
  fork(name: string, filter?: Filter): Context;
5689
+ createSession(message: IncomingMessage): Session;
5633
5690
  start(): Promise<void>;
5634
5691
  private acceptsParentEvent;
5635
5692
  private applyPlugins;
@@ -5641,7 +5698,6 @@ declare class Context {
5641
5698
  private createUnresolvablePluginError;
5642
5699
  private createProxyContextForPlugin;
5643
5700
  private runEventStream;
5644
- private createSession;
5645
5701
  static fromUrl(baseUrl: string | URL, options?: ContextOptions & ContextUrlOptions): Context;
5646
5702
  static fromClient(client: MilkyClient, options?: ContextOptions): Context;
5647
5703
  }
@@ -5688,11 +5744,13 @@ declare namespace seg {
5688
5744
  //#endregion
5689
5745
  export {
5690
5746
  ApiEndpoints,
5747
+ Command,
5691
5748
  Context,
5692
5749
  ContextOptions,
5693
5750
  ContextUrlOptions,
5694
5751
  EventMap,
5695
5752
  Filter,
5753
+ Handler,
5696
5754
  Injection,
5697
5755
  LogHandler,
5698
5756
  LogLevel,
@@ -5702,10 +5760,17 @@ export {
5702
5760
  MilkyEventSubscription,
5703
5761
  Parameter,
5704
5762
  ParameterList,
5763
+ ParamsOf,
5764
+ Pattern,
5705
5765
  Plugin,
5766
+ RawPattern,
5767
+ RouteBranch,
5768
+ RouteEntry,
5769
+ RouteMatchResult,
5706
5770
  Router,
5707
5771
  type ServiceClass,
5708
5772
  Session,
5773
+ SessionPredicate,
5709
5774
  combineLogHandlers,
5710
5775
  createMilkyClient,
5711
5776
  definePlugin,
package/dist/index.mjs CHANGED
@@ -211,49 +211,102 @@ var Router = class Router {
211
211
  });
212
212
  return router;
213
213
  }
214
- async dispatch(session, message) {
214
+ routes() {
215
+ return this.entries;
216
+ }
217
+ branches(session) {
218
+ return this.branchesFrom(session, []);
219
+ }
220
+ match(session, message) {
215
221
  const tokenizer = new Tokenizer(message.segments);
216
- return await this.process(session, tokenizer);
222
+ return this.matchFrom(session, tokenizer, []);
217
223
  }
218
- async process(session, tokenizer) {
224
+ async dispatch(session, message) {
225
+ const match = this.match(session, message);
226
+ if (match === void 0) return false;
227
+ switch (match.type) {
228
+ case "command":
229
+ await match.command.handler(session, match.params);
230
+ break;
231
+ case "rawPattern":
232
+ await match.rawPattern.handler(session, match.params);
233
+ break;
234
+ }
235
+ return true;
236
+ }
237
+ matchFrom(session, tokenizer, path) {
219
238
  const initialState = tokenizer.getState();
220
239
  for (const entry of this.entries) {
221
240
  tokenizer.setState(initialState);
222
- if (await this.processEntry(entry, session, tokenizer)) return true;
241
+ const match = this.matchEntry(entry, session, tokenizer, path);
242
+ if (match !== void 0) return match;
223
243
  }
224
244
  tokenizer.setState(initialState);
225
- return false;
226
245
  }
227
- async processEntry(entry, session, tokenizer) {
246
+ matchEntry(entry, session, tokenizer, path) {
228
247
  switch (entry.type) {
229
- case "command": return await this.processCommand(entry.command, session, tokenizer);
230
- case "group": return await this.processGroup(entry.name, entry.router, session, tokenizer);
248
+ case "command": return this.matchCommand(entry.command, tokenizer, path);
249
+ case "group": return this.matchGroup(entry.name, entry.router, session, tokenizer, path);
231
250
  case "filter":
232
- if (entry.predicate(session) !== true) return false;
233
- return await entry.router.process(session, tokenizer);
234
- case "rawPattern": return await this.processRawPattern(entry.rawPattern, session, tokenizer);
251
+ if (entry.predicate(session) !== true) return;
252
+ return entry.router.matchFrom(session, tokenizer, path);
253
+ case "rawPattern": return this.matchRawPattern(entry.rawPattern, tokenizer, path);
235
254
  }
236
255
  }
237
- async processCommand(command, session, tokenizer) {
256
+ matchCommand(command, tokenizer, path) {
238
257
  const token = tokenizer.peek();
239
- if (typeof token !== "string" || token !== command.name) return false;
258
+ if (typeof token !== "string" || token !== command.name) return;
240
259
  tokenizer.next();
241
260
  const params = this.capturePattern(command.pattern, tokenizer);
242
- if (params === void 0 || tokenizer.hasNext()) return false;
243
- await command.handler(session, params);
244
- return true;
261
+ if (params === void 0 || tokenizer.hasNext()) return;
262
+ return {
263
+ type: "command",
264
+ path: [...path],
265
+ command,
266
+ params
267
+ };
245
268
  }
246
- async processGroup(name, router, session, tokenizer) {
269
+ matchGroup(name, router, session, tokenizer, path) {
247
270
  const token = tokenizer.peek();
248
- if (typeof token !== "string" || token !== name) return false;
271
+ if (typeof token !== "string" || token !== name) return;
249
272
  tokenizer.next();
250
- return await router.process(session, tokenizer);
273
+ return router.matchFrom(session, tokenizer, [...path, name]);
251
274
  }
252
- async processRawPattern(rawPattern, session, tokenizer) {
275
+ matchRawPattern(rawPattern, tokenizer, path) {
253
276
  const params = this.capturePattern(rawPattern.pattern, tokenizer);
254
- if (params === void 0 || tokenizer.hasNext()) return false;
255
- await rawPattern.handler(session, params);
256
- return true;
277
+ if (params === void 0 || tokenizer.hasNext()) return;
278
+ return {
279
+ type: "rawPattern",
280
+ path: [...path],
281
+ rawPattern,
282
+ params
283
+ };
284
+ }
285
+ branchesFrom(session, path) {
286
+ const branches = [];
287
+ for (const entry of this.entries) switch (entry.type) {
288
+ case "command":
289
+ branches.push({
290
+ type: "command",
291
+ path: [...path],
292
+ command: entry.command
293
+ });
294
+ break;
295
+ case "group":
296
+ branches.push(...entry.router.branchesFrom(session, [...path, entry.name]));
297
+ break;
298
+ case "filter":
299
+ if (entry.predicate(session) === true) branches.push(...entry.router.branchesFrom(session, path));
300
+ break;
301
+ case "rawPattern":
302
+ branches.push({
303
+ type: "rawPattern",
304
+ path: [...path],
305
+ rawPattern: entry.rawPattern
306
+ });
307
+ break;
308
+ }
309
+ return branches;
257
310
  }
258
311
  capturePattern(pattern, tokenizer) {
259
312
  const initialState = tokenizer.getState();
@@ -386,6 +439,31 @@ var Context = class Context {
386
439
  this.subContexts.push(subContext);
387
440
  return subContext;
388
441
  }
442
+ createSession(message) {
443
+ return {
444
+ raw: message,
445
+ reply: async (segments) => {
446
+ try {
447
+ switch (message.message_scene) {
448
+ case "friend":
449
+ await this.client.send_private_message({
450
+ user_id: message.peer_id,
451
+ message: segments
452
+ });
453
+ break;
454
+ case "group":
455
+ await this.client.send_group_message({
456
+ group_id: message.peer_id,
457
+ message: segments
458
+ });
459
+ break;
460
+ }
461
+ } catch (error) {
462
+ this.logger.error(`Error sending reply (source msg: scene=${message.message_scene} peer=${message.peer_id} sender=${message.sender_id} seq=${message.message_seq})`, error);
463
+ }
464
+ }
465
+ };
466
+ }
389
467
  async start() {
390
468
  if (this.isStarted) return;
391
469
  await this.applyPlugins();
@@ -509,31 +587,6 @@ var Context = class Context {
509
587
  reconnectAttempt += 1;
510
588
  }
511
589
  }
512
- createSession(message) {
513
- return {
514
- raw: message,
515
- reply: async (segments) => {
516
- try {
517
- switch (message.message_scene) {
518
- case "friend":
519
- await this.client.send_private_message({
520
- user_id: message.peer_id,
521
- message: segments
522
- });
523
- break;
524
- case "group":
525
- await this.client.send_group_message({
526
- group_id: message.peer_id,
527
- message: segments
528
- });
529
- break;
530
- }
531
- } catch (error) {
532
- this.logger.error(`Error sending reply (source msg: scene=${message.message_scene} peer=${message.peer_id} sender=${message.sender_id} seq=${message.message_seq})`, error);
533
- }
534
- }
535
- };
536
- }
537
590
  static fromUrl(baseUrl, options) {
538
591
  return new Context(createMilkyClient(baseUrl, { accessToken: options?.accessToken }), options);
539
592
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fraqjs/fraq",
3
3
  "type": "module",
4
- "version": "0.4.0",
4
+ "version": "0.5.1",
5
5
  "description": "Milky Bot framework",
6
6
  "files": [
7
7
  "dist"
@@ -19,6 +19,9 @@
19
19
  "dependencies": {
20
20
  "mitt": "^3.0.1"
21
21
  },
22
+ "devDependencies": {
23
+ "@fraqjs/mock": "^0.1.0"
24
+ },
22
25
  "engines": {
23
26
  "node": ">=22"
24
27
  },