@fraqjs/fraq 0.6.4 → 0.8.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/README.md +5 -5
- package/dist/index.d.mts +22 -16
- package/dist/index.mjs +52 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,15 +27,15 @@ const ctx = Context.fromUrl('<替换成你的 Milky 协议端地址>', {
|
|
|
27
27
|
// accessToken: '<如果你的 Milky 协议端配置了 token,请在这里添加>',
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
ctx.router.command(
|
|
31
|
-
'echo',
|
|
32
|
-
{
|
|
30
|
+
ctx.router.command({
|
|
31
|
+
name: 'echo',
|
|
32
|
+
pattern: {
|
|
33
33
|
content: param.greedy(),
|
|
34
34
|
},
|
|
35
|
-
(session, { content })
|
|
35
|
+
execute(session, { content }) {
|
|
36
36
|
session.reply(msg`You said: ${content}`);
|
|
37
37
|
},
|
|
38
|
-
);
|
|
38
|
+
});
|
|
39
39
|
|
|
40
40
|
ctx.start();
|
|
41
41
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -5505,21 +5505,21 @@ declare namespace param {
|
|
|
5505
5505
|
//#region src/routing/router.d.ts
|
|
5506
5506
|
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
|
-
type
|
|
5508
|
+
type Executor<P extends Pattern> = (session: Session, params: ParamsOf<P>) => void | Promise<void>;
|
|
5509
5509
|
type SessionPredicate = (session: Session) => boolean;
|
|
5510
|
-
interface Command {
|
|
5510
|
+
interface Command<P extends Pattern> {
|
|
5511
5511
|
name: string;
|
|
5512
|
-
pattern:
|
|
5513
|
-
|
|
5512
|
+
pattern: P;
|
|
5513
|
+
execute: Executor<P>;
|
|
5514
5514
|
}
|
|
5515
|
-
interface RawPattern {
|
|
5516
|
-
pattern:
|
|
5517
|
-
|
|
5515
|
+
interface RawPattern<P extends Pattern> {
|
|
5516
|
+
pattern: P;
|
|
5517
|
+
execute: Executor<P>;
|
|
5518
5518
|
}
|
|
5519
5519
|
type RouteEntry =
|
|
5520
5520
|
| {
|
|
5521
5521
|
type: 'command';
|
|
5522
|
-
command: Command
|
|
5522
|
+
command: Command<Pattern>;
|
|
5523
5523
|
}
|
|
5524
5524
|
| {
|
|
5525
5525
|
type: 'group';
|
|
@@ -5533,30 +5533,30 @@ type RouteEntry =
|
|
|
5533
5533
|
}
|
|
5534
5534
|
| {
|
|
5535
5535
|
type: 'rawPattern';
|
|
5536
|
-
rawPattern: RawPattern
|
|
5536
|
+
rawPattern: RawPattern<Pattern>;
|
|
5537
5537
|
};
|
|
5538
5538
|
type RouteBranch =
|
|
5539
5539
|
| {
|
|
5540
5540
|
type: 'command';
|
|
5541
5541
|
path: string[];
|
|
5542
|
-
command: Command
|
|
5542
|
+
command: Command<Pattern>;
|
|
5543
5543
|
}
|
|
5544
5544
|
| {
|
|
5545
5545
|
type: 'rawPattern';
|
|
5546
5546
|
path: string[];
|
|
5547
|
-
rawPattern: RawPattern
|
|
5547
|
+
rawPattern: RawPattern<Pattern>;
|
|
5548
5548
|
};
|
|
5549
5549
|
type RouteMatchResult =
|
|
5550
5550
|
| {
|
|
5551
5551
|
type: 'command';
|
|
5552
5552
|
path: string[];
|
|
5553
|
-
command: Command
|
|
5553
|
+
command: Command<Pattern>;
|
|
5554
5554
|
params: any;
|
|
5555
5555
|
}
|
|
5556
5556
|
| {
|
|
5557
5557
|
type: 'rawPattern';
|
|
5558
5558
|
path: string[];
|
|
5559
|
-
rawPattern: RawPattern
|
|
5559
|
+
rawPattern: RawPattern<Pattern>;
|
|
5560
5560
|
params: any;
|
|
5561
5561
|
};
|
|
5562
5562
|
interface Session {
|
|
@@ -5566,8 +5566,8 @@ interface Session {
|
|
|
5566
5566
|
declare class Router {
|
|
5567
5567
|
private readonly entries;
|
|
5568
5568
|
private readonly groups;
|
|
5569
|
-
command<P extends Pattern>(
|
|
5570
|
-
rawPattern<P extends Pattern>(
|
|
5569
|
+
command<P extends Pattern>(command: Command<P>): this;
|
|
5570
|
+
rawPattern<P extends Pattern>(rawPattern: RawPattern<P>): this;
|
|
5571
5571
|
group(name: string): Router;
|
|
5572
5572
|
filter(predicate: SessionPredicate): Router;
|
|
5573
5573
|
routes(): RouteEntry[];
|
|
@@ -5679,6 +5679,7 @@ declare class Context {
|
|
|
5679
5679
|
private readonly services;
|
|
5680
5680
|
private readonly subContexts;
|
|
5681
5681
|
private readonly parentEventForwarder?;
|
|
5682
|
+
private readonly timers;
|
|
5682
5683
|
private readonly initialReconnectDelayMs;
|
|
5683
5684
|
private readonly maxReconnectDelayMs;
|
|
5684
5685
|
private readonly logHandler?;
|
|
@@ -5700,12 +5701,17 @@ declare class Context {
|
|
|
5700
5701
|
tryResolve<T extends object>(service: ServiceClass<T>): T | undefined;
|
|
5701
5702
|
isProvided<T extends object>(service: ServiceClass<T>): boolean;
|
|
5702
5703
|
fork(name: string, filter?: Filter): Context;
|
|
5704
|
+
timeout(delayMs: number, callback: () => void | Promise<void>): NodeJS.Timeout;
|
|
5705
|
+
interval(intervalMs: number, callback: () => void | Promise<void>): NodeJS.Timeout;
|
|
5703
5706
|
createSession(message: IncomingMessage): Session;
|
|
5704
5707
|
start(): Promise<void>;
|
|
5705
5708
|
stop(): Promise<void>;
|
|
5706
5709
|
private startInternal;
|
|
5707
5710
|
private getState;
|
|
5708
5711
|
private stopInternal;
|
|
5712
|
+
private assertCanScheduleTimer;
|
|
5713
|
+
private runTimerCallback;
|
|
5714
|
+
private clearTimers;
|
|
5709
5715
|
private stopEventStream;
|
|
5710
5716
|
private acceptsParentEvent;
|
|
5711
5717
|
private applyPlugins;
|
|
@@ -5775,8 +5781,8 @@ export {
|
|
|
5775
5781
|
ContextUrlOptions,
|
|
5776
5782
|
Disposable,
|
|
5777
5783
|
EventMap,
|
|
5784
|
+
Executor,
|
|
5778
5785
|
Filter,
|
|
5779
|
-
Handler,
|
|
5780
5786
|
Injection,
|
|
5781
5787
|
LogHandler,
|
|
5782
5788
|
LogLevel,
|
package/dist/index.mjs
CHANGED
|
@@ -164,25 +164,17 @@ var Tokenizer = class {
|
|
|
164
164
|
var Router = class Router {
|
|
165
165
|
entries = [];
|
|
166
166
|
groups = /* @__PURE__ */ new Map();
|
|
167
|
-
command(
|
|
168
|
-
const command = {
|
|
169
|
-
name,
|
|
170
|
-
pattern,
|
|
171
|
-
handler
|
|
172
|
-
};
|
|
167
|
+
command(command) {
|
|
173
168
|
this.entries.push({
|
|
174
169
|
type: "command",
|
|
175
170
|
command
|
|
176
171
|
});
|
|
177
172
|
return this;
|
|
178
173
|
}
|
|
179
|
-
rawPattern(
|
|
180
|
-
if (Object.keys(pattern).length === 0) throw new Error("Raw pattern must have at least one parameter.");
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
pattern,
|
|
184
|
-
handler
|
|
185
|
-
};
|
|
174
|
+
rawPattern(rawPattern) {
|
|
175
|
+
if (Object.keys(rawPattern.pattern).length === 0) throw new Error("Raw pattern must have at least one parameter.");
|
|
176
|
+
const firstKey = Object.keys(rawPattern.pattern)[0];
|
|
177
|
+
if (rawPattern.pattern[firstKey].capturer.typeInstruction.type === "literal") throw new Error("The first parameter of a raw pattern cannot be a literal, as it would conflict with command patterns.");
|
|
186
178
|
this.entries.push({
|
|
187
179
|
type: "rawPattern",
|
|
188
180
|
rawPattern
|
|
@@ -226,10 +218,10 @@ var Router = class Router {
|
|
|
226
218
|
if (match === void 0) return false;
|
|
227
219
|
switch (match.type) {
|
|
228
220
|
case "command":
|
|
229
|
-
await match.command.
|
|
221
|
+
await match.command.execute(session, match.params);
|
|
230
222
|
break;
|
|
231
223
|
case "rawPattern":
|
|
232
|
-
await match.rawPattern.
|
|
224
|
+
await match.rawPattern.execute(session, match.params);
|
|
233
225
|
break;
|
|
234
226
|
}
|
|
235
227
|
return true;
|
|
@@ -382,6 +374,7 @@ var Context = class Context {
|
|
|
382
374
|
services = /* @__PURE__ */ new Map();
|
|
383
375
|
subContexts = [];
|
|
384
376
|
parentEventForwarder;
|
|
377
|
+
timers = /* @__PURE__ */ new Set();
|
|
385
378
|
initialReconnectDelayMs;
|
|
386
379
|
maxReconnectDelayMs;
|
|
387
380
|
logHandler;
|
|
@@ -466,6 +459,23 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
466
459
|
this.subContexts.push(subContext);
|
|
467
460
|
return subContext;
|
|
468
461
|
}
|
|
462
|
+
timeout(delayMs, callback) {
|
|
463
|
+
this.assertCanScheduleTimer();
|
|
464
|
+
const timeout = setTimeout(() => {
|
|
465
|
+
this.timers.delete(timeout);
|
|
466
|
+
this.runTimerCallback(callback);
|
|
467
|
+
}, delayMs);
|
|
468
|
+
this.timers.add(timeout);
|
|
469
|
+
return timeout;
|
|
470
|
+
}
|
|
471
|
+
interval(intervalMs, callback) {
|
|
472
|
+
this.assertCanScheduleTimer();
|
|
473
|
+
const interval = setInterval(() => {
|
|
474
|
+
this.runTimerCallback(callback);
|
|
475
|
+
}, intervalMs);
|
|
476
|
+
this.timers.add(interval);
|
|
477
|
+
return interval;
|
|
478
|
+
}
|
|
469
479
|
createSession(message) {
|
|
470
480
|
return {
|
|
471
481
|
raw: message,
|
|
@@ -508,10 +518,10 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
508
518
|
}
|
|
509
519
|
}
|
|
510
520
|
async stop() {
|
|
511
|
-
if (this.state === "idle" || this.state === "stopped") return;
|
|
521
|
+
if (this.state === "idle" && this.timers.size === 0 || this.state === "stopped") return;
|
|
512
522
|
if (this.state === "starting") await this.startPromise;
|
|
513
523
|
const stateAfterStart = this.getState();
|
|
514
|
-
if (stateAfterStart === "idle" || stateAfterStart === "stopped") return;
|
|
524
|
+
if (stateAfterStart === "idle" && this.timers.size === 0 || stateAfterStart === "stopped") return;
|
|
515
525
|
if (stateAfterStart === "stopping") {
|
|
516
526
|
await this.stopPromise;
|
|
517
527
|
return;
|
|
@@ -543,12 +553,13 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
543
553
|
}
|
|
544
554
|
async stopInternal() {
|
|
545
555
|
const errors = [];
|
|
546
|
-
|
|
556
|
+
this.clearTimers();
|
|
547
557
|
for (const subContext of [...this.subContexts].reverse()) try {
|
|
548
558
|
await subContext.stop();
|
|
549
559
|
} catch (error) {
|
|
550
560
|
errors.push(error);
|
|
551
561
|
}
|
|
562
|
+
await this.stopEventStream(errors);
|
|
552
563
|
if (this.parent && this.parentEventForwarder) this.parent.eventBus.off("*", this.parentEventForwarder);
|
|
553
564
|
for (const service of [...this.services.values()].reverse()) {
|
|
554
565
|
if (!isDisposable(service)) continue;
|
|
@@ -561,6 +572,22 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
561
572
|
if (errors.length === 1) throw errors[0];
|
|
562
573
|
if (errors.length > 1) throw new AggregateError(errors, `Context "${this.name}" failed to stop cleanly.`);
|
|
563
574
|
}
|
|
575
|
+
assertCanScheduleTimer() {
|
|
576
|
+
if (this.state === "stopping") throw new Error(`Context "${this.name}" cannot schedule timers while it is stopping.`);
|
|
577
|
+
if (this.state === "stopped") throw new Error(`Context "${this.name}" cannot schedule timers after it has stopped.`);
|
|
578
|
+
}
|
|
579
|
+
async runTimerCallback(callback) {
|
|
580
|
+
if (this.state === "stopping" || this.state === "stopped") return;
|
|
581
|
+
try {
|
|
582
|
+
await callback();
|
|
583
|
+
} catch (error) {
|
|
584
|
+
this.logger.error("Error handling timer callback", error);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
clearTimers() {
|
|
588
|
+
for (const timer of this.timers) clearTimeout(timer);
|
|
589
|
+
this.timers.clear();
|
|
590
|
+
}
|
|
564
591
|
async stopEventStream(errors) {
|
|
565
592
|
this.resolveReconnectDelay();
|
|
566
593
|
const subscription = this.eventSubscription;
|
|
@@ -685,6 +712,10 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
685
712
|
}
|
|
686
713
|
createProxyContextForPlugin(plugin) {
|
|
687
714
|
const proxyLogger = new Logger((message) => this.logHandler?.(message), plugin.name);
|
|
715
|
+
const proxyProvide = (service, instance) => {
|
|
716
|
+
this.provide(service, instance);
|
|
717
|
+
this.logger.debug(`Plugin ${plugin.name} provided ${service.name}`);
|
|
718
|
+
};
|
|
688
719
|
let proxyInjections;
|
|
689
720
|
if (plugin.inject) {
|
|
690
721
|
proxyInjections = {};
|
|
@@ -694,10 +725,11 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
694
725
|
proxyInjections ??= {};
|
|
695
726
|
for (const [key, service] of Object.entries(plugin.optionalInject)) proxyInjections[key] = this.tryResolve(service);
|
|
696
727
|
}
|
|
697
|
-
return new Proxy(this, { get(target, prop) {
|
|
728
|
+
return new Proxy(this, { get(target, prop, receiver) {
|
|
698
729
|
if (prop === "logger") return proxyLogger;
|
|
730
|
+
else if (prop === "provide") return proxyProvide;
|
|
699
731
|
else if (proxyInjections && prop in proxyInjections) return proxyInjections[prop];
|
|
700
|
-
else return target
|
|
732
|
+
else return Reflect.get(target, prop, receiver);
|
|
701
733
|
} });
|
|
702
734
|
}
|
|
703
735
|
async runEventStream() {
|