@fraqjs/fraq 0.8.2 → 0.9.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/README.md +5 -8
- package/dist/index.d.mts +41 -6
- package/dist/index.mjs +90 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,15 +27,12 @@ const ctx = Context.fromUrl('<替换成你的 Milky 协议端地址>', {
|
|
|
27
27
|
// accessToken: '<如果你的 Milky 协议端配置了 token,请在这里添加>',
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
ctx.router
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
35
|
-
execute(session, { content }) {
|
|
30
|
+
ctx.router
|
|
31
|
+
.command('echo')
|
|
32
|
+
.arg('content', param.greedy())
|
|
33
|
+
.execute((session, { content }) => {
|
|
36
34
|
session.reply(msg`You said: ${content}`);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
35
|
+
});
|
|
39
36
|
|
|
40
37
|
ctx.start();
|
|
41
38
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -5506,20 +5506,54 @@ declare namespace param {
|
|
|
5506
5506
|
>;
|
|
5507
5507
|
}
|
|
5508
5508
|
//#endregion
|
|
5509
|
-
//#region src/routing/
|
|
5509
|
+
//#region src/routing/command.d.ts
|
|
5510
5510
|
type Pattern = Record<string, Parameter<any>>;
|
|
5511
5511
|
type ParamsOf<P extends Pattern> = { [K in keyof P]: P[K] extends Parameter<infer T> ? T : never };
|
|
5512
5512
|
type Executor<P extends Pattern> = (session: Session, params: ParamsOf<P>) => void | Promise<void>;
|
|
5513
|
-
type SessionPredicate = (session: Session) => boolean;
|
|
5514
5513
|
interface Command<P extends Pattern> {
|
|
5515
5514
|
name: string;
|
|
5516
5515
|
pattern: P;
|
|
5517
5516
|
execute: Executor<P>;
|
|
5517
|
+
description?: string;
|
|
5518
|
+
aliases?: string[];
|
|
5519
|
+
hidden?: boolean;
|
|
5518
5520
|
}
|
|
5519
5521
|
interface RawPattern<P extends Pattern> {
|
|
5520
5522
|
pattern: P;
|
|
5521
5523
|
execute: Executor<P>;
|
|
5522
5524
|
}
|
|
5525
|
+
interface Session {
|
|
5526
|
+
raw: IncomingMessage;
|
|
5527
|
+
reply(segments: OutgoingSegment_ZodInput[]): Promise<void>;
|
|
5528
|
+
}
|
|
5529
|
+
declare class CommandBuilder<P extends Pattern = {}, S = Command<P>> {
|
|
5530
|
+
readonly name: string;
|
|
5531
|
+
private readonly sink;
|
|
5532
|
+
private readonly pattern;
|
|
5533
|
+
private executor?;
|
|
5534
|
+
private description?;
|
|
5535
|
+
private aliases?;
|
|
5536
|
+
private hidden?;
|
|
5537
|
+
constructor(name: string, sink?: (command: Command<P>) => S);
|
|
5538
|
+
arg<K extends string, T>(
|
|
5539
|
+
key: K,
|
|
5540
|
+
parameter: Parameter<T>,
|
|
5541
|
+
): CommandBuilder<
|
|
5542
|
+
P & { [K2 in K]: Parameter<T> },
|
|
5543
|
+
S extends Command<P>
|
|
5544
|
+
? Command<P & { [K2 in K]: Parameter<T> }>
|
|
5545
|
+
: S extends RawPattern<P>
|
|
5546
|
+
? RawPattern<P & { [K2 in K]: Parameter<T> }>
|
|
5547
|
+
: S
|
|
5548
|
+
>;
|
|
5549
|
+
describe(description: string): CommandBuilder<P, S>;
|
|
5550
|
+
alias(...aliases: string[]): CommandBuilder<P, S>;
|
|
5551
|
+
hide(): CommandBuilder<P, S>;
|
|
5552
|
+
execute(executor: Executor<P>): S;
|
|
5553
|
+
}
|
|
5554
|
+
//#endregion
|
|
5555
|
+
//#region src/routing/router.d.ts
|
|
5556
|
+
type SessionPredicate = (session: Session) => boolean;
|
|
5523
5557
|
type RouteEntry =
|
|
5524
5558
|
| {
|
|
5525
5559
|
type: 'command';
|
|
@@ -5563,18 +5597,17 @@ type RouteMatchResult =
|
|
|
5563
5597
|
rawPattern: RawPattern<Pattern>;
|
|
5564
5598
|
params: any;
|
|
5565
5599
|
};
|
|
5566
|
-
interface Session {
|
|
5567
|
-
raw: IncomingMessage;
|
|
5568
|
-
reply(segments: OutgoingSegment_ZodInput[]): Promise<void>;
|
|
5569
|
-
}
|
|
5570
5600
|
declare class Router {
|
|
5571
5601
|
private readonly entries;
|
|
5572
5602
|
private readonly groups;
|
|
5603
|
+
command(name: string): CommandBuilder;
|
|
5573
5604
|
command<P extends Pattern>(command: Command<P>): this;
|
|
5605
|
+
rawPattern(): CommandBuilder<{}, RawPattern<{}>>;
|
|
5574
5606
|
rawPattern<P extends Pattern>(rawPattern: RawPattern<P>): this;
|
|
5575
5607
|
group(name: string): Router;
|
|
5576
5608
|
filter(predicate: SessionPredicate): Router;
|
|
5577
5609
|
routes(): RouteEntry[];
|
|
5610
|
+
aliasesOf(name: string): string[];
|
|
5578
5611
|
branches(session: Session): RouteBranch[];
|
|
5579
5612
|
match(session: Session, message: IncomingMessage): RouteMatchResult | undefined;
|
|
5580
5613
|
dispatch(session: Session, message: IncomingMessage): Promise<boolean>;
|
|
@@ -5584,6 +5617,7 @@ declare class Router {
|
|
|
5584
5617
|
private matchGroup;
|
|
5585
5618
|
private matchRawPattern;
|
|
5586
5619
|
private branchesFrom;
|
|
5620
|
+
private resolveAliasConflicts;
|
|
5587
5621
|
private validatePattern;
|
|
5588
5622
|
private capturePattern;
|
|
5589
5623
|
}
|
|
@@ -5784,6 +5818,7 @@ export {
|
|
|
5784
5818
|
ApiEndpoints,
|
|
5785
5819
|
Capturer,
|
|
5786
5820
|
Command,
|
|
5821
|
+
CommandBuilder,
|
|
5787
5822
|
Context,
|
|
5788
5823
|
ContextOptions,
|
|
5789
5824
|
ContextUrlOptions,
|
package/dist/index.mjs
CHANGED
|
@@ -64,6 +64,50 @@ function createMilkyClient(...params) {
|
|
|
64
64
|
} });
|
|
65
65
|
}
|
|
66
66
|
//#endregion
|
|
67
|
+
//#region src/routing/command.ts
|
|
68
|
+
var CommandBuilder = class {
|
|
69
|
+
name;
|
|
70
|
+
sink;
|
|
71
|
+
pattern = {};
|
|
72
|
+
executor;
|
|
73
|
+
description;
|
|
74
|
+
aliases;
|
|
75
|
+
hidden;
|
|
76
|
+
constructor(name, sink = (command) => command) {
|
|
77
|
+
this.name = name;
|
|
78
|
+
this.sink = sink;
|
|
79
|
+
}
|
|
80
|
+
arg(key, parameter) {
|
|
81
|
+
this.pattern[key] = parameter;
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
describe(description) {
|
|
85
|
+
this.description = description;
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
alias(...aliases) {
|
|
89
|
+
if (!this.aliases) this.aliases = [];
|
|
90
|
+
this.aliases.push(...aliases);
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
hide() {
|
|
94
|
+
this.hidden = true;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
execute(executor) {
|
|
98
|
+
this.executor = executor;
|
|
99
|
+
const command = {
|
|
100
|
+
name: this.name,
|
|
101
|
+
pattern: this.pattern,
|
|
102
|
+
execute: this.executor
|
|
103
|
+
};
|
|
104
|
+
if (this.description !== void 0) command.description = this.description;
|
|
105
|
+
if (this.aliases !== void 0) command.aliases = this.aliases;
|
|
106
|
+
if (this.hidden !== void 0) command.hidden = this.hidden;
|
|
107
|
+
return this.sink(command);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
//#endregion
|
|
67
111
|
//#region src/routing/tokenizer.ts
|
|
68
112
|
var Tokenizer = class {
|
|
69
113
|
segments;
|
|
@@ -192,7 +236,12 @@ var Router = class Router {
|
|
|
192
236
|
entries = [];
|
|
193
237
|
groups = /* @__PURE__ */ new Map();
|
|
194
238
|
command(command) {
|
|
239
|
+
if (typeof command === "string") return new CommandBuilder(command, (builtCommand) => {
|
|
240
|
+
this.command(builtCommand);
|
|
241
|
+
return builtCommand;
|
|
242
|
+
});
|
|
195
243
|
this.validatePattern(command.pattern);
|
|
244
|
+
this.resolveAliasConflicts(command);
|
|
196
245
|
this.entries.push({
|
|
197
246
|
type: "command",
|
|
198
247
|
command
|
|
@@ -200,6 +249,10 @@ var Router = class Router {
|
|
|
200
249
|
return this;
|
|
201
250
|
}
|
|
202
251
|
rawPattern(rawPattern) {
|
|
252
|
+
if (!rawPattern) return new CommandBuilder("", (builtCommand) => {
|
|
253
|
+
this.rawPattern(builtCommand);
|
|
254
|
+
return builtCommand;
|
|
255
|
+
});
|
|
203
256
|
this.validatePattern(rawPattern.pattern, { rawPattern: true });
|
|
204
257
|
this.entries.push({
|
|
205
258
|
type: "rawPattern",
|
|
@@ -232,6 +285,10 @@ var Router = class Router {
|
|
|
232
285
|
routes() {
|
|
233
286
|
return this.entries;
|
|
234
287
|
}
|
|
288
|
+
aliasesOf(name) {
|
|
289
|
+
for (const entry of this.entries) if (entry.type === "command" && entry.command.name === name) return entry.command.aliases ? [...entry.command.aliases] : [];
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
235
292
|
branches(session) {
|
|
236
293
|
return this.branchesFrom(session, []);
|
|
237
294
|
}
|
|
@@ -273,7 +330,7 @@ var Router = class Router {
|
|
|
273
330
|
}
|
|
274
331
|
matchCommand(command, tokenizer, path) {
|
|
275
332
|
const token = tokenizer.peek();
|
|
276
|
-
if (typeof token !== "string" || token !== command.name) return;
|
|
333
|
+
if (typeof token !== "string" || token !== command.name && !command.aliases?.includes(token)) return;
|
|
277
334
|
tokenizer.next();
|
|
278
335
|
const params = this.capturePattern(command.pattern, tokenizer);
|
|
279
336
|
if (params === void 0 || tokenizer.hasNext()) return;
|
|
@@ -304,7 +361,7 @@ var Router = class Router {
|
|
|
304
361
|
const branches = [];
|
|
305
362
|
for (const entry of this.entries) switch (entry.type) {
|
|
306
363
|
case "command":
|
|
307
|
-
branches.push({
|
|
364
|
+
if (!entry.command.hidden) branches.push({
|
|
308
365
|
type: "command",
|
|
309
366
|
path: [...path],
|
|
310
367
|
command: entry.command
|
|
@@ -326,6 +383,27 @@ var Router = class Router {
|
|
|
326
383
|
}
|
|
327
384
|
return branches;
|
|
328
385
|
}
|
|
386
|
+
resolveAliasConflicts(command) {
|
|
387
|
+
for (const entry of this.entries) {
|
|
388
|
+
if (entry.type !== "command") continue;
|
|
389
|
+
const existing = entry.command;
|
|
390
|
+
if (existing.aliases?.includes(command.name)) {
|
|
391
|
+
existing.aliases = existing.aliases.filter((a) => a !== command.name);
|
|
392
|
+
console.warn(`Command "${command.name}" conflicts with alias of existing command "${existing.name}". The alias "${command.name}" has been removed from "${existing.name}".`);
|
|
393
|
+
}
|
|
394
|
+
if (command.aliases) {
|
|
395
|
+
const dropped = [];
|
|
396
|
+
for (const alias of command.aliases) if (existing.name === alias) {
|
|
397
|
+
dropped.push(alias);
|
|
398
|
+
console.warn(`Alias "${alias}" of command "${command.name}" conflicts with existing command name "${existing.name}". The alias has been dropped.`);
|
|
399
|
+
} else if (existing.aliases?.includes(alias)) {
|
|
400
|
+
existing.aliases = existing.aliases.filter((a) => a !== alias);
|
|
401
|
+
console.warn(`Alias "${alias}" of command "${command.name}" conflicts with alias of existing command "${existing.name}". The alias has been removed from "${existing.name}".`);
|
|
402
|
+
}
|
|
403
|
+
if (dropped.length > 0) command.aliases = command.aliases.filter((a) => !dropped.includes(a));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
329
407
|
validatePattern(pattern, options) {
|
|
330
408
|
const entries = Object.entries(pattern);
|
|
331
409
|
if (options?.rawPattern && entries.length === 0) throw new Error("Raw pattern must have at least one parameter.");
|
|
@@ -648,7 +726,15 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
648
726
|
for (const installedPlugin of sortedPlugins) {
|
|
649
727
|
const { plugin, args } = installedPlugin;
|
|
650
728
|
const providedBeforeApply = new Set(this.services.keys());
|
|
651
|
-
|
|
729
|
+
let debugMessage = `Applying plugin ${plugin.name}`;
|
|
730
|
+
const requiredServices = [];
|
|
731
|
+
const providedServices = [];
|
|
732
|
+
if (plugin.requires) for (const service of plugin.requires) requiredServices.push(service.name);
|
|
733
|
+
if (plugin.optionalRequires) for (const service of plugin.optionalRequires) requiredServices.push(`${service.name}?`);
|
|
734
|
+
if (plugin.provides) for (const service of plugin.provides) providedServices.push(service.name);
|
|
735
|
+
if (requiredServices.length > 0) debugMessage += `, requires: [${requiredServices.join(", ")}]`;
|
|
736
|
+
if (providedServices.length > 0) debugMessage += `, provides: [${providedServices.join(", ")}]`;
|
|
737
|
+
this.logger.debug(debugMessage);
|
|
652
738
|
await plugin.apply(this.getPluginContext(installedPlugin), ...args);
|
|
653
739
|
for (const service of plugin.provides ?? []) if (!this.services.has(service) || providedBeforeApply.has(service)) throw new Error(`${plugin.name} declares service ${service.name} but did not provide it.`);
|
|
654
740
|
}
|
|
@@ -747,10 +833,6 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
747
833
|
}
|
|
748
834
|
createProxyContextForPlugin(plugin) {
|
|
749
835
|
const proxyLogger = new Logger((message) => this.logHandler?.(message), plugin.name);
|
|
750
|
-
const proxyProvide = (service, instance) => {
|
|
751
|
-
this.provide(service, instance);
|
|
752
|
-
this.logger.debug(`Plugin ${plugin.name} provided ${service.name}`);
|
|
753
|
-
};
|
|
754
836
|
let proxyInjections;
|
|
755
837
|
if (plugin.inject) {
|
|
756
838
|
proxyInjections = {};
|
|
@@ -762,7 +844,6 @@ and implement the dispose method to clean up resources when the context stops.
|
|
|
762
844
|
}
|
|
763
845
|
return new Proxy(this, { get(target, prop, receiver) {
|
|
764
846
|
if (prop === "logger") return proxyLogger;
|
|
765
|
-
else if (prop === "provide") return proxyProvide;
|
|
766
847
|
else if (proxyInjections && prop in proxyInjections) return proxyInjections[prop];
|
|
767
848
|
else return Reflect.get(target, prop, receiver);
|
|
768
849
|
} });
|
|
@@ -1230,4 +1311,4 @@ let param;
|
|
|
1230
1311
|
_param.segment = segment;
|
|
1231
1312
|
})(param || (param = {}));
|
|
1232
1313
|
//#endregion
|
|
1233
|
-
export { Context, Logger, Parameter, Router, combineLogHandlers, createMilkyClient, definePlugin, filter, implementsESNextDisposable, isDisposable, milkyPackageVersion, milkyVersion, msg, param, seg };
|
|
1314
|
+
export { CommandBuilder, Context, Logger, Parameter, Router, combineLogHandlers, createMilkyClient, definePlugin, filter, implementsESNextDisposable, isDisposable, milkyPackageVersion, milkyVersion, msg, param, seg };
|