@fraqjs/fraq 0.13.3 → 0.14.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/dist/index.d.mts +87 -126
- package/dist/index.mjs +212 -276
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5377,6 +5377,86 @@ interface ApiEndpoints$1 {
|
|
|
5377
5377
|
};
|
|
5378
5378
|
}
|
|
5379
5379
|
//#endregion
|
|
5380
|
+
//#region src/protocol/endpoint.d.ts
|
|
5381
|
+
type ApiEndpointName = keyof ApiEndpoints$1;
|
|
5382
|
+
type RequiredKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? never : K }[keyof T];
|
|
5383
|
+
type AllOptional<T> = RequiredKeys<T> extends never ? true : false;
|
|
5384
|
+
type RawApiEndpoint<E extends ApiEndpointName> = {
|
|
5385
|
+
request: ApiEndpoints$1[E]['request_ZodInput'] extends null ? null : ApiEndpoints$1[E]['request_ZodInput'];
|
|
5386
|
+
response: ApiEndpoints$1[E]['response'] extends null ? null : ApiEndpoints$1[E]['response'];
|
|
5387
|
+
};
|
|
5388
|
+
type ApiRequest<E extends ApiEndpointName> = RawApiEndpoint<E>['request'];
|
|
5389
|
+
type ApiParams<E extends ApiEndpointName> = RawApiEndpoint<E>['request'] extends null
|
|
5390
|
+
? undefined
|
|
5391
|
+
: AllOptional<RawApiEndpoint<E>['request']> extends true
|
|
5392
|
+
? RawApiEndpoint<E>['request'] | undefined
|
|
5393
|
+
: RawApiEndpoint<E>['request'];
|
|
5394
|
+
type ApiResponse<E extends ApiEndpointName> = RawApiEndpoint<E>['response'];
|
|
5395
|
+
interface ApiCall<E extends ApiEndpointName = ApiEndpointName> {
|
|
5396
|
+
endpoint: E;
|
|
5397
|
+
params: ApiParams<E>;
|
|
5398
|
+
}
|
|
5399
|
+
type ApiNext<E extends ApiEndpointName> =
|
|
5400
|
+
undefined extends ApiParams<E>
|
|
5401
|
+
? (params?: ApiParams<E>) => Promise<ApiResponse<E>>
|
|
5402
|
+
: (params: ApiParams<E>) => Promise<ApiResponse<E>>;
|
|
5403
|
+
type ApiHook<E extends ApiEndpointName> = (
|
|
5404
|
+
params: ApiParams<E>,
|
|
5405
|
+
next: ApiNext<E>,
|
|
5406
|
+
call: ApiCall<E>,
|
|
5407
|
+
) => ApiResponse<E> | Promise<ApiResponse<E>>;
|
|
5408
|
+
type AnyApiCall = { [E in ApiEndpointName]: ApiCall<E> }[ApiEndpointName];
|
|
5409
|
+
type AnyApiNext = (params?: unknown) => Promise<unknown>;
|
|
5410
|
+
type AnyApiHook = (call: AnyApiCall, next: AnyApiNext) => unknown | Promise<unknown>;
|
|
5411
|
+
type ApiEndpointFunction<E extends ApiEndpointName> = RawApiEndpoint<E>['request'] extends null
|
|
5412
|
+
? () => Promise<ApiResponse<E>>
|
|
5413
|
+
: AllOptional<RawApiEndpoint<E>['request']> extends true
|
|
5414
|
+
? (params?: RawApiEndpoint<E>['request']) => Promise<ApiResponse<E>>
|
|
5415
|
+
: (params: RawApiEndpoint<E>['request']) => Promise<ApiResponse<E>>;
|
|
5416
|
+
type ApiEndpoints = { [E in ApiEndpointName]: ApiEndpointFunction<E> };
|
|
5417
|
+
type EventMap = {
|
|
5418
|
+
[K in Event['event_type']]: Extract<
|
|
5419
|
+
Event,
|
|
5420
|
+
{
|
|
5421
|
+
event_type: K;
|
|
5422
|
+
}
|
|
5423
|
+
>;
|
|
5424
|
+
};
|
|
5425
|
+
//#endregion
|
|
5426
|
+
//#region src/protocol/client.d.ts
|
|
5427
|
+
interface MilkyClient extends ApiEndpoints {}
|
|
5428
|
+
declare class MilkyClientBase {
|
|
5429
|
+
readonly baseUrl: string;
|
|
5430
|
+
readonly wsBaseUrl: string;
|
|
5431
|
+
private readonly accessToken?;
|
|
5432
|
+
private readonly baseHeaders;
|
|
5433
|
+
constructor(
|
|
5434
|
+
baseUrl: string | URL,
|
|
5435
|
+
options?: {
|
|
5436
|
+
accessToken?: string;
|
|
5437
|
+
},
|
|
5438
|
+
);
|
|
5439
|
+
callApi(endpoint: string, params?: unknown): Promise<unknown>;
|
|
5440
|
+
}
|
|
5441
|
+
declare function createMilkyClient(...params: ConstructorParameters<typeof MilkyClientBase>): MilkyClient;
|
|
5442
|
+
//#endregion
|
|
5443
|
+
//#region src/protocol/event.d.ts
|
|
5444
|
+
interface MilkyEventSubscription {
|
|
5445
|
+
closed: Promise<void>;
|
|
5446
|
+
stop(): void | Promise<void>;
|
|
5447
|
+
}
|
|
5448
|
+
interface MilkyEventSource {
|
|
5449
|
+
readonly name?: string;
|
|
5450
|
+
start(onEvent: (event: Event) => void | Promise<void>): Promise<MilkyEventSubscription>;
|
|
5451
|
+
}
|
|
5452
|
+
interface MilkyWebSocketEventSourceOptions {
|
|
5453
|
+
accessToken?: string;
|
|
5454
|
+
}
|
|
5455
|
+
declare function createMilkyWebSocketEventSource(
|
|
5456
|
+
baseUrl: string | URL,
|
|
5457
|
+
options?: MilkyWebSocketEventSourceOptions,
|
|
5458
|
+
): MilkyEventSource;
|
|
5459
|
+
//#endregion
|
|
5380
5460
|
//#region src/routing/tokenizer.d.ts
|
|
5381
5461
|
type Token =
|
|
5382
5462
|
| string
|
|
@@ -5548,21 +5628,20 @@ type RouteActivation =
|
|
|
5548
5628
|
type: 'prefix';
|
|
5549
5629
|
prefix: string;
|
|
5550
5630
|
};
|
|
5551
|
-
type RouteActivationInput = RouteActivation | readonly RouteActivation[];
|
|
5552
5631
|
type RouteDescriptor =
|
|
5553
5632
|
| {
|
|
5554
5633
|
type: 'command';
|
|
5555
|
-
path:
|
|
5634
|
+
path: string[];
|
|
5556
5635
|
name: string;
|
|
5557
|
-
aliases?:
|
|
5636
|
+
aliases?: string[];
|
|
5558
5637
|
meta?: RouteMeta;
|
|
5559
5638
|
}
|
|
5560
5639
|
| {
|
|
5561
5640
|
type: 'rawPattern';
|
|
5562
|
-
path:
|
|
5641
|
+
path: string[];
|
|
5563
5642
|
meta?: RouteMeta;
|
|
5564
5643
|
};
|
|
5565
|
-
type RouteActivationResolver = (route: RouteDescriptor, session: Session) =>
|
|
5644
|
+
type RouteActivationResolver = (route: RouteDescriptor, session: Session) => RouteActivation[];
|
|
5566
5645
|
declare const defaultRouteActivationResolver: RouteActivationResolver;
|
|
5567
5646
|
type RouteEntry =
|
|
5568
5647
|
| {
|
|
@@ -5642,118 +5721,6 @@ declare class Router {
|
|
|
5642
5721
|
private capturePattern;
|
|
5643
5722
|
}
|
|
5644
5723
|
//#endregion
|
|
5645
|
-
//#region src/core/activation.d.ts
|
|
5646
|
-
type ContextRouteActivationByScene = Partial<
|
|
5647
|
-
Record<IncomingMessage['message_scene'] | 'default', RouteActivationInput>
|
|
5648
|
-
>;
|
|
5649
|
-
type ContextRouteActivation = RouteActivationInput | ContextRouteActivationByScene;
|
|
5650
|
-
interface ContextRouteActivationMatcher {
|
|
5651
|
-
type?: RouteDescriptor['type'] | readonly RouteDescriptor['type'][];
|
|
5652
|
-
plugin?: string | readonly string[];
|
|
5653
|
-
context?: string | readonly string[];
|
|
5654
|
-
tag?: string | readonly string[];
|
|
5655
|
-
command?: string | readonly string[];
|
|
5656
|
-
path?: readonly string[];
|
|
5657
|
-
route?: readonly string[];
|
|
5658
|
-
predicate?: (route: RouteDescriptor, session: Session) => boolean;
|
|
5659
|
-
}
|
|
5660
|
-
interface ContextRouteActivationRule {
|
|
5661
|
-
match?: ContextRouteActivationMatcher;
|
|
5662
|
-
activation: ContextRouteActivation;
|
|
5663
|
-
}
|
|
5664
|
-
interface ContextRouteActivationConfig {
|
|
5665
|
-
default?: ContextRouteActivation;
|
|
5666
|
-
rules?: ContextRouteActivationRule | readonly ContextRouteActivationRule[];
|
|
5667
|
-
}
|
|
5668
|
-
interface ContextRoutingOptions {
|
|
5669
|
-
activation?: ContextRouteActivationConfig;
|
|
5670
|
-
activationResolver?: RouteActivationResolver;
|
|
5671
|
-
}
|
|
5672
|
-
declare function createContextRouteActivationResolver(
|
|
5673
|
-
routing: ContextRoutingOptions | undefined,
|
|
5674
|
-
fallback?: RouteActivationResolver,
|
|
5675
|
-
): RouteActivationResolver;
|
|
5676
|
-
//#endregion
|
|
5677
|
-
//#region src/protocol/endpoint.d.ts
|
|
5678
|
-
type ApiEndpointName = keyof ApiEndpoints$1;
|
|
5679
|
-
type RequiredKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? never : K }[keyof T];
|
|
5680
|
-
type AllOptional<T> = RequiredKeys<T> extends never ? true : false;
|
|
5681
|
-
type RawApiEndpoint<E extends ApiEndpointName> = {
|
|
5682
|
-
request: ApiEndpoints$1[E]['request_ZodInput'] extends null ? null : ApiEndpoints$1[E]['request_ZodInput'];
|
|
5683
|
-
response: ApiEndpoints$1[E]['response'] extends null ? null : ApiEndpoints$1[E]['response'];
|
|
5684
|
-
};
|
|
5685
|
-
type ApiRequest<E extends ApiEndpointName> = RawApiEndpoint<E>['request'];
|
|
5686
|
-
type ApiParams<E extends ApiEndpointName> = RawApiEndpoint<E>['request'] extends null
|
|
5687
|
-
? undefined
|
|
5688
|
-
: AllOptional<RawApiEndpoint<E>['request']> extends true
|
|
5689
|
-
? RawApiEndpoint<E>['request'] | undefined
|
|
5690
|
-
: RawApiEndpoint<E>['request'];
|
|
5691
|
-
type ApiResponse<E extends ApiEndpointName> = RawApiEndpoint<E>['response'];
|
|
5692
|
-
interface ApiCall<E extends ApiEndpointName = ApiEndpointName> {
|
|
5693
|
-
endpoint: E;
|
|
5694
|
-
params: ApiParams<E>;
|
|
5695
|
-
}
|
|
5696
|
-
type ApiNext<E extends ApiEndpointName> =
|
|
5697
|
-
undefined extends ApiParams<E>
|
|
5698
|
-
? (params?: ApiParams<E>) => Promise<ApiResponse<E>>
|
|
5699
|
-
: (params: ApiParams<E>) => Promise<ApiResponse<E>>;
|
|
5700
|
-
type ApiHook<E extends ApiEndpointName> = (
|
|
5701
|
-
params: ApiParams<E>,
|
|
5702
|
-
next: ApiNext<E>,
|
|
5703
|
-
call: ApiCall<E>,
|
|
5704
|
-
) => ApiResponse<E> | Promise<ApiResponse<E>>;
|
|
5705
|
-
type AnyApiCall = { [E in ApiEndpointName]: ApiCall<E> }[ApiEndpointName];
|
|
5706
|
-
type AnyApiNext = (params?: unknown) => Promise<unknown>;
|
|
5707
|
-
type AnyApiHook = (call: AnyApiCall, next: AnyApiNext) => unknown | Promise<unknown>;
|
|
5708
|
-
type ApiEndpointFunction<E extends ApiEndpointName> = RawApiEndpoint<E>['request'] extends null
|
|
5709
|
-
? () => Promise<ApiResponse<E>>
|
|
5710
|
-
: AllOptional<RawApiEndpoint<E>['request']> extends true
|
|
5711
|
-
? (params?: RawApiEndpoint<E>['request']) => Promise<ApiResponse<E>>
|
|
5712
|
-
: (params: RawApiEndpoint<E>['request']) => Promise<ApiResponse<E>>;
|
|
5713
|
-
type ApiEndpoints = { [E in ApiEndpointName]: ApiEndpointFunction<E> };
|
|
5714
|
-
type EventMap = {
|
|
5715
|
-
[K in Event['event_type']]: Extract<
|
|
5716
|
-
Event,
|
|
5717
|
-
{
|
|
5718
|
-
event_type: K;
|
|
5719
|
-
}
|
|
5720
|
-
>;
|
|
5721
|
-
};
|
|
5722
|
-
//#endregion
|
|
5723
|
-
//#region src/protocol/client.d.ts
|
|
5724
|
-
interface MilkyClient extends ApiEndpoints {}
|
|
5725
|
-
declare class MilkyClientBase {
|
|
5726
|
-
readonly baseUrl: string;
|
|
5727
|
-
readonly wsBaseUrl: string;
|
|
5728
|
-
private readonly accessToken?;
|
|
5729
|
-
private readonly baseHeaders;
|
|
5730
|
-
constructor(
|
|
5731
|
-
baseUrl: string | URL,
|
|
5732
|
-
options?: {
|
|
5733
|
-
accessToken?: string;
|
|
5734
|
-
},
|
|
5735
|
-
);
|
|
5736
|
-
callApi(endpoint: string, params?: unknown): Promise<unknown>;
|
|
5737
|
-
}
|
|
5738
|
-
declare function createMilkyClient(...params: ConstructorParameters<typeof MilkyClientBase>): MilkyClient;
|
|
5739
|
-
//#endregion
|
|
5740
|
-
//#region src/protocol/event.d.ts
|
|
5741
|
-
interface MilkyEventSubscription {
|
|
5742
|
-
closed: Promise<void>;
|
|
5743
|
-
stop(): void | Promise<void>;
|
|
5744
|
-
}
|
|
5745
|
-
interface MilkyEventSource {
|
|
5746
|
-
readonly name?: string;
|
|
5747
|
-
start(onEvent: (event: Event) => void | Promise<void>): Promise<MilkyEventSubscription>;
|
|
5748
|
-
}
|
|
5749
|
-
interface MilkyWebSocketEventSourceOptions {
|
|
5750
|
-
accessToken?: string;
|
|
5751
|
-
}
|
|
5752
|
-
declare function createMilkyWebSocketEventSource(
|
|
5753
|
-
baseUrl: string | URL,
|
|
5754
|
-
options?: MilkyWebSocketEventSourceOptions,
|
|
5755
|
-
): MilkyEventSource;
|
|
5756
|
-
//#endregion
|
|
5757
5724
|
//#region src/core/filter.d.ts
|
|
5758
5725
|
type Filter = { [K in keyof EventMap]?: (event: EventMap[K]) => boolean };
|
|
5759
5726
|
declare namespace filter {
|
|
@@ -5836,7 +5803,9 @@ interface ContextOptions {
|
|
|
5836
5803
|
maxDelayMs?: number;
|
|
5837
5804
|
};
|
|
5838
5805
|
logHandler?: LogHandler;
|
|
5839
|
-
routing?:
|
|
5806
|
+
routing?: {
|
|
5807
|
+
activationResolver?: RouteActivationResolver;
|
|
5808
|
+
};
|
|
5840
5809
|
}
|
|
5841
5810
|
interface ContextUrlOptions {
|
|
5842
5811
|
accessToken?: string;
|
|
@@ -5940,12 +5909,6 @@ export {
|
|
|
5940
5909
|
CommandBuilder,
|
|
5941
5910
|
Context,
|
|
5942
5911
|
ContextOptions,
|
|
5943
|
-
ContextRouteActivation,
|
|
5944
|
-
ContextRouteActivationByScene,
|
|
5945
|
-
ContextRouteActivationConfig,
|
|
5946
|
-
ContextRouteActivationMatcher,
|
|
5947
|
-
ContextRouteActivationRule,
|
|
5948
|
-
ContextRoutingOptions,
|
|
5949
5912
|
ContextUrlOptions,
|
|
5950
5913
|
Disposable,
|
|
5951
5914
|
EventMap,
|
|
@@ -5967,7 +5930,6 @@ export {
|
|
|
5967
5930
|
Plugin,
|
|
5968
5931
|
RawPattern,
|
|
5969
5932
|
RouteActivation,
|
|
5970
|
-
RouteActivationInput,
|
|
5971
5933
|
RouteActivationResolver,
|
|
5972
5934
|
RouteBranch,
|
|
5973
5935
|
RouteDescriptor,
|
|
@@ -5981,7 +5943,6 @@ export {
|
|
|
5981
5943
|
SessionReplyOptions,
|
|
5982
5944
|
TypeInstruction,
|
|
5983
5945
|
combineLogHandlers,
|
|
5984
|
-
createContextRouteActivationResolver,
|
|
5985
5946
|
createMilkyClient,
|
|
5986
5947
|
createMilkyWebSocketEventSource,
|
|
5987
5948
|
defaultRouteActivationResolver,
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,210 @@
|
|
|
1
1
|
import mitt from "mitt";
|
|
2
|
+
//#region src/protocol/client.ts
|
|
3
|
+
var MilkyClientBase = class {
|
|
4
|
+
baseUrl;
|
|
5
|
+
wsBaseUrl;
|
|
6
|
+
accessToken;
|
|
7
|
+
baseHeaders;
|
|
8
|
+
constructor(baseUrl, options) {
|
|
9
|
+
const normalizedBaseUrl = baseUrl.toString();
|
|
10
|
+
this.baseUrl = normalizedBaseUrl.endsWith("/") ? normalizedBaseUrl.slice(0, -1) : normalizedBaseUrl;
|
|
11
|
+
this.wsBaseUrl = this.baseUrl.replace(/^http/, "ws");
|
|
12
|
+
this.accessToken = options?.accessToken;
|
|
13
|
+
this.baseHeaders = { "Content-Type": "application/json" };
|
|
14
|
+
if (options?.accessToken) this.baseHeaders.Authorization = `Bearer ${options.accessToken}`;
|
|
15
|
+
}
|
|
16
|
+
async callApi(endpoint, params) {
|
|
17
|
+
const response = await fetch(`${this.baseUrl}/api/${endpoint}`, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
body: JSON.stringify(params ?? {}),
|
|
20
|
+
headers: this.baseHeaders
|
|
21
|
+
});
|
|
22
|
+
if (!response.ok) throw new Error(`API call ${endpoint} failed with HTTP status ${response.status}`);
|
|
23
|
+
const json = await response.json();
|
|
24
|
+
if (json.status === "failed") throw new Error(`API call ${endpoint} failed with retcode ${json.retcode}: ${json.message}`);
|
|
25
|
+
return json.data;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function createMilkyClient(...params) {
|
|
29
|
+
const base = new MilkyClientBase(...params);
|
|
30
|
+
return new Proxy(base, { get(target, endpoint) {
|
|
31
|
+
if (typeof endpoint === "string" && endpoint.includes("_")) return (params) => target.callApi(endpoint, params);
|
|
32
|
+
else return target[endpoint];
|
|
33
|
+
} });
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/protocol/event.ts
|
|
37
|
+
function createMilkyWebSocketEventSource(baseUrl, options) {
|
|
38
|
+
const normalizedBaseUrl = baseUrl.toString();
|
|
39
|
+
const wsBaseUrl = normalizedBaseUrl.endsWith("/") ? normalizedBaseUrl.slice(0, -1).replace(/^http/, "ws") : normalizedBaseUrl.replace(/^http/, "ws");
|
|
40
|
+
return {
|
|
41
|
+
name: "websocket",
|
|
42
|
+
async start(onEvent) {
|
|
43
|
+
const ws = new WebSocket(`${wsBaseUrl}/event${options?.accessToken ? `?access_token=${options.accessToken}` : ""}`);
|
|
44
|
+
let closeSubscription = () => {};
|
|
45
|
+
const closed = new Promise((resolve, reject) => {
|
|
46
|
+
closeSubscription = (error) => {
|
|
47
|
+
if (error) reject(error);
|
|
48
|
+
else resolve();
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
ws.addEventListener("message", async (event) => {
|
|
52
|
+
try {
|
|
53
|
+
if (typeof event.data !== "string") throw new Error(`Expected text frame, got ${typeof event.data}`);
|
|
54
|
+
await onEvent(JSON.parse(event.data));
|
|
55
|
+
} catch (error) {
|
|
56
|
+
closeSubscription(error);
|
|
57
|
+
ws.close();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
await new Promise((resolve, reject) => {
|
|
61
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
62
|
+
ws.addEventListener("error", (event) => reject(/* @__PURE__ */ new Error(`WebSocket error: ${event}`)));
|
|
63
|
+
});
|
|
64
|
+
ws.addEventListener("error", (event) => closeSubscription(/* @__PURE__ */ new Error(`WebSocket error: ${event}`)));
|
|
65
|
+
ws.addEventListener("close", () => closeSubscription(), { once: true });
|
|
66
|
+
return {
|
|
67
|
+
closed,
|
|
68
|
+
stop() {
|
|
69
|
+
ws.close();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/protocol/segment.ts
|
|
77
|
+
function msg(strings, ...values) {
|
|
78
|
+
let buffer = "";
|
|
79
|
+
const segments = [];
|
|
80
|
+
for (let i = 0; i < strings.length; i++) {
|
|
81
|
+
buffer += strings[i];
|
|
82
|
+
if (i < values.length) {
|
|
83
|
+
const value = values[i];
|
|
84
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") buffer += value.toString();
|
|
85
|
+
else {
|
|
86
|
+
if (buffer) {
|
|
87
|
+
segments.push({
|
|
88
|
+
type: "text",
|
|
89
|
+
data: { text: buffer }
|
|
90
|
+
});
|
|
91
|
+
buffer = "";
|
|
92
|
+
}
|
|
93
|
+
segments.push(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (buffer) segments.push({
|
|
98
|
+
type: "text",
|
|
99
|
+
data: { text: buffer }
|
|
100
|
+
});
|
|
101
|
+
return trimBoundaryTextSegments(segments);
|
|
102
|
+
}
|
|
103
|
+
function isTextSegment(segment) {
|
|
104
|
+
return segment.type === "text";
|
|
105
|
+
}
|
|
106
|
+
function withText(segment, text) {
|
|
107
|
+
return {
|
|
108
|
+
...segment,
|
|
109
|
+
data: {
|
|
110
|
+
...segment.data,
|
|
111
|
+
text
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function trimBoundaryTextSegments(segments) {
|
|
116
|
+
const result = [...segments];
|
|
117
|
+
const first = result[0];
|
|
118
|
+
if (first && isTextSegment(first)) {
|
|
119
|
+
const text = first.data.text.trimStart();
|
|
120
|
+
if (text) result[0] = withText(first, text);
|
|
121
|
+
else result.shift();
|
|
122
|
+
}
|
|
123
|
+
const lastIndex = result.length - 1;
|
|
124
|
+
const last = result[lastIndex];
|
|
125
|
+
if (last && isTextSegment(last)) {
|
|
126
|
+
const text = last.data.text.trimEnd();
|
|
127
|
+
if (text) result[lastIndex] = withText(last, text);
|
|
128
|
+
else result.pop();
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
let seg;
|
|
133
|
+
(function(_seg) {
|
|
134
|
+
function mention(userId) {
|
|
135
|
+
return {
|
|
136
|
+
type: "mention",
|
|
137
|
+
data: { user_id: userId }
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
_seg.mention = mention;
|
|
141
|
+
function mentionAll() {
|
|
142
|
+
return {
|
|
143
|
+
type: "mention_all",
|
|
144
|
+
data: {}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
_seg.mentionAll = mentionAll;
|
|
148
|
+
function face(faceId, options) {
|
|
149
|
+
return {
|
|
150
|
+
type: "face",
|
|
151
|
+
data: {
|
|
152
|
+
face_id: faceId.toString(),
|
|
153
|
+
is_large: options?.isLarge ?? false
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
_seg.face = face;
|
|
158
|
+
function reply(messageSeq) {
|
|
159
|
+
return {
|
|
160
|
+
type: "reply",
|
|
161
|
+
data: { message_seq: messageSeq }
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
_seg.reply = reply;
|
|
165
|
+
function image(uri, options) {
|
|
166
|
+
return {
|
|
167
|
+
type: "image",
|
|
168
|
+
data: {
|
|
169
|
+
uri,
|
|
170
|
+
sub_type: options?.subType,
|
|
171
|
+
summary: options?.summary
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
_seg.image = image;
|
|
176
|
+
function record(uri) {
|
|
177
|
+
return {
|
|
178
|
+
type: "record",
|
|
179
|
+
data: { uri }
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
_seg.record = record;
|
|
183
|
+
function video(uri, options) {
|
|
184
|
+
return {
|
|
185
|
+
type: "video",
|
|
186
|
+
data: {
|
|
187
|
+
uri,
|
|
188
|
+
thumb_uri: options?.thumbUri
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
_seg.video = video;
|
|
193
|
+
function forward(messages, options) {
|
|
194
|
+
return {
|
|
195
|
+
type: "forward",
|
|
196
|
+
data: {
|
|
197
|
+
messages,
|
|
198
|
+
title: options?.title,
|
|
199
|
+
preview: options?.preview,
|
|
200
|
+
summary: options?.summary,
|
|
201
|
+
prompt: options?.prompt
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
_seg.forward = forward;
|
|
206
|
+
})(seg || (seg = {}));
|
|
207
|
+
//#endregion
|
|
2
208
|
//#region src/routing/command.ts
|
|
3
209
|
var CommandBuilder = class {
|
|
4
210
|
name;
|
|
@@ -235,8 +441,8 @@ var Tokenizer = class {
|
|
|
235
441
|
};
|
|
236
442
|
//#endregion
|
|
237
443
|
//#region src/routing/router.ts
|
|
238
|
-
const
|
|
239
|
-
const defaultRouteActivationResolver = () =>
|
|
444
|
+
const defaultActivations = [{ type: "direct" }];
|
|
445
|
+
const defaultRouteActivationResolver = () => defaultActivations;
|
|
240
446
|
var Router = class Router {
|
|
241
447
|
entries = [];
|
|
242
448
|
groups = /* @__PURE__ */ new Map();
|
|
@@ -315,11 +521,10 @@ var Router = class Router {
|
|
|
315
521
|
match(session, message) {
|
|
316
522
|
for (const branch of this.branchesFrom(session, [], { includeHidden: true })) {
|
|
317
523
|
const literalActivationIndex = branch.type === "rawPattern" ? Object.values(branch.rawPattern.pattern).findIndex((parameter) => parameter.capturer.typeInstruction.type === "literal") : -1;
|
|
318
|
-
let activationInputs =
|
|
524
|
+
let activationInputs = defaultActivations;
|
|
319
525
|
if (branch.type === "command" || literalActivationIndex !== -1 || branch.path.length > 0) {
|
|
320
526
|
const descriptor = this.describeBranch(branch);
|
|
321
|
-
|
|
322
|
-
activationInputs = Array.isArray(activations) ? activations : [activations];
|
|
527
|
+
activationInputs = this.activationResolver(descriptor, session) ?? defaultActivations;
|
|
323
528
|
}
|
|
324
529
|
for (const activation of activationInputs) {
|
|
325
530
|
const tokenizer = new Tokenizer(message.segments);
|
|
@@ -498,275 +703,6 @@ var Router = class Router {
|
|
|
498
703
|
}
|
|
499
704
|
};
|
|
500
705
|
//#endregion
|
|
501
|
-
//#region src/core/activation.ts
|
|
502
|
-
function createContextRouteActivationResolver(routing, fallback = defaultRouteActivationResolver) {
|
|
503
|
-
if (!routing) return fallback;
|
|
504
|
-
if (routing.activation && routing.activationResolver) throw new Error("Context routing cannot specify both activation and activationResolver.");
|
|
505
|
-
if (routing.activationResolver) return routing.activationResolver;
|
|
506
|
-
if (routing.activation) return compileContextRouteActivationConfig(routing.activation, fallback);
|
|
507
|
-
return fallback;
|
|
508
|
-
}
|
|
509
|
-
function compileContextRouteActivationConfig(config, fallback) {
|
|
510
|
-
return (route, session) => {
|
|
511
|
-
const rules = config.rules === void 0 ? [] : Array.isArray(config.rules) ? config.rules : [config.rules];
|
|
512
|
-
for (const rule of rules) {
|
|
513
|
-
if (!matchesContextRouteActivationRule(route, session, rule)) continue;
|
|
514
|
-
const activation = resolveContextRouteActivation(rule.activation, session.raw.message_scene);
|
|
515
|
-
if (activation !== void 0) return activation;
|
|
516
|
-
}
|
|
517
|
-
if (config.default !== void 0) {
|
|
518
|
-
const activation = resolveContextRouteActivation(config.default, session.raw.message_scene);
|
|
519
|
-
if (activation !== void 0) return activation;
|
|
520
|
-
}
|
|
521
|
-
return fallback(route, session);
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
function resolveContextRouteActivation(activation, scene) {
|
|
525
|
-
if (Array.isArray(activation) || "type" in activation) return activation;
|
|
526
|
-
const activationByScene = activation;
|
|
527
|
-
return activationByScene[scene] ?? activationByScene.default;
|
|
528
|
-
}
|
|
529
|
-
function matchesContextRouteActivationRule(route, session, rule) {
|
|
530
|
-
const match = rule.match;
|
|
531
|
-
if (!match) return true;
|
|
532
|
-
if (!matchesStringSelector(match.type, route.type)) return false;
|
|
533
|
-
if (!matchesStringSelector(match.plugin, routeMetaString(route, "plugin"))) return false;
|
|
534
|
-
if (!matchesStringSelector(match.context, routeMetaString(route, "context"))) return false;
|
|
535
|
-
if (!matchesTagSelector(match.tag, route.meta?.tags)) return false;
|
|
536
|
-
if (match.command !== void 0 && (route.type !== "command" || !matchesStringSelector(match.command, route.name))) return false;
|
|
537
|
-
if (match.path !== void 0 && !sameStringArray(match.path, route.path)) return false;
|
|
538
|
-
if (match.route !== void 0 && !sameStringArray(match.route, routeSegments(route))) return false;
|
|
539
|
-
if (match.predicate && match.predicate(route, session) !== true) return false;
|
|
540
|
-
return true;
|
|
541
|
-
}
|
|
542
|
-
function routeMetaString(route, key) {
|
|
543
|
-
const value = route.meta?.[key];
|
|
544
|
-
return typeof value === "string" ? value : void 0;
|
|
545
|
-
}
|
|
546
|
-
function matchesStringSelector(selector, value) {
|
|
547
|
-
if (selector === void 0) return true;
|
|
548
|
-
if (value === void 0) return false;
|
|
549
|
-
return typeof selector === "string" ? selector === value : selector.includes(value);
|
|
550
|
-
}
|
|
551
|
-
function matchesTagSelector(selector, tags) {
|
|
552
|
-
if (selector === void 0) return true;
|
|
553
|
-
if (!tags) return false;
|
|
554
|
-
return typeof selector === "string" ? tags.includes(selector) : selector.some((tag) => tags.includes(tag));
|
|
555
|
-
}
|
|
556
|
-
function routeSegments(route) {
|
|
557
|
-
if (route.type === "command") return [...route.path, route.name];
|
|
558
|
-
return route.path;
|
|
559
|
-
}
|
|
560
|
-
function sameStringArray(left, right) {
|
|
561
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
562
|
-
}
|
|
563
|
-
//#endregion
|
|
564
|
-
//#region src/protocol/client.ts
|
|
565
|
-
var MilkyClientBase = class {
|
|
566
|
-
baseUrl;
|
|
567
|
-
wsBaseUrl;
|
|
568
|
-
accessToken;
|
|
569
|
-
baseHeaders;
|
|
570
|
-
constructor(baseUrl, options) {
|
|
571
|
-
const normalizedBaseUrl = baseUrl.toString();
|
|
572
|
-
this.baseUrl = normalizedBaseUrl.endsWith("/") ? normalizedBaseUrl.slice(0, -1) : normalizedBaseUrl;
|
|
573
|
-
this.wsBaseUrl = this.baseUrl.replace(/^http/, "ws");
|
|
574
|
-
this.accessToken = options?.accessToken;
|
|
575
|
-
this.baseHeaders = { "Content-Type": "application/json" };
|
|
576
|
-
if (options?.accessToken) this.baseHeaders.Authorization = `Bearer ${options.accessToken}`;
|
|
577
|
-
}
|
|
578
|
-
async callApi(endpoint, params) {
|
|
579
|
-
const response = await fetch(`${this.baseUrl}/api/${endpoint}`, {
|
|
580
|
-
method: "POST",
|
|
581
|
-
body: JSON.stringify(params ?? {}),
|
|
582
|
-
headers: this.baseHeaders
|
|
583
|
-
});
|
|
584
|
-
if (!response.ok) throw new Error(`API call ${endpoint} failed with HTTP status ${response.status}`);
|
|
585
|
-
const json = await response.json();
|
|
586
|
-
if (json.status === "failed") throw new Error(`API call ${endpoint} failed with retcode ${json.retcode}: ${json.message}`);
|
|
587
|
-
return json.data;
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
function createMilkyClient(...params) {
|
|
591
|
-
const base = new MilkyClientBase(...params);
|
|
592
|
-
return new Proxy(base, { get(target, endpoint) {
|
|
593
|
-
if (typeof endpoint === "string" && endpoint.includes("_")) return (params) => target.callApi(endpoint, params);
|
|
594
|
-
else return target[endpoint];
|
|
595
|
-
} });
|
|
596
|
-
}
|
|
597
|
-
//#endregion
|
|
598
|
-
//#region src/protocol/event.ts
|
|
599
|
-
function createMilkyWebSocketEventSource(baseUrl, options) {
|
|
600
|
-
const normalizedBaseUrl = baseUrl.toString();
|
|
601
|
-
const wsBaseUrl = normalizedBaseUrl.endsWith("/") ? normalizedBaseUrl.slice(0, -1).replace(/^http/, "ws") : normalizedBaseUrl.replace(/^http/, "ws");
|
|
602
|
-
return {
|
|
603
|
-
name: "websocket",
|
|
604
|
-
async start(onEvent) {
|
|
605
|
-
const ws = new WebSocket(`${wsBaseUrl}/event${options?.accessToken ? `?access_token=${options.accessToken}` : ""}`);
|
|
606
|
-
let closeSubscription = () => {};
|
|
607
|
-
const closed = new Promise((resolve, reject) => {
|
|
608
|
-
closeSubscription = (error) => {
|
|
609
|
-
if (error) reject(error);
|
|
610
|
-
else resolve();
|
|
611
|
-
};
|
|
612
|
-
});
|
|
613
|
-
ws.addEventListener("message", async (event) => {
|
|
614
|
-
try {
|
|
615
|
-
if (typeof event.data !== "string") throw new Error(`Expected text frame, got ${typeof event.data}`);
|
|
616
|
-
await onEvent(JSON.parse(event.data));
|
|
617
|
-
} catch (error) {
|
|
618
|
-
closeSubscription(error);
|
|
619
|
-
ws.close();
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
await new Promise((resolve, reject) => {
|
|
623
|
-
ws.addEventListener("open", () => resolve(), { once: true });
|
|
624
|
-
ws.addEventListener("error", (event) => reject(/* @__PURE__ */ new Error(`WebSocket error: ${event}`)));
|
|
625
|
-
});
|
|
626
|
-
ws.addEventListener("error", (event) => closeSubscription(/* @__PURE__ */ new Error(`WebSocket error: ${event}`)));
|
|
627
|
-
ws.addEventListener("close", () => closeSubscription(), { once: true });
|
|
628
|
-
return {
|
|
629
|
-
closed,
|
|
630
|
-
stop() {
|
|
631
|
-
ws.close();
|
|
632
|
-
}
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
//#endregion
|
|
638
|
-
//#region src/protocol/segment.ts
|
|
639
|
-
function msg(strings, ...values) {
|
|
640
|
-
let buffer = "";
|
|
641
|
-
const segments = [];
|
|
642
|
-
for (let i = 0; i < strings.length; i++) {
|
|
643
|
-
buffer += strings[i];
|
|
644
|
-
if (i < values.length) {
|
|
645
|
-
const value = values[i];
|
|
646
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") buffer += value.toString();
|
|
647
|
-
else {
|
|
648
|
-
if (buffer) {
|
|
649
|
-
segments.push({
|
|
650
|
-
type: "text",
|
|
651
|
-
data: { text: buffer }
|
|
652
|
-
});
|
|
653
|
-
buffer = "";
|
|
654
|
-
}
|
|
655
|
-
segments.push(value);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
if (buffer) segments.push({
|
|
660
|
-
type: "text",
|
|
661
|
-
data: { text: buffer }
|
|
662
|
-
});
|
|
663
|
-
return trimBoundaryTextSegments(segments);
|
|
664
|
-
}
|
|
665
|
-
function isTextSegment(segment) {
|
|
666
|
-
return segment.type === "text";
|
|
667
|
-
}
|
|
668
|
-
function withText(segment, text) {
|
|
669
|
-
return {
|
|
670
|
-
...segment,
|
|
671
|
-
data: {
|
|
672
|
-
...segment.data,
|
|
673
|
-
text
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
function trimBoundaryTextSegments(segments) {
|
|
678
|
-
const result = [...segments];
|
|
679
|
-
const first = result[0];
|
|
680
|
-
if (first && isTextSegment(first)) {
|
|
681
|
-
const text = first.data.text.trimStart();
|
|
682
|
-
if (text) result[0] = withText(first, text);
|
|
683
|
-
else result.shift();
|
|
684
|
-
}
|
|
685
|
-
const lastIndex = result.length - 1;
|
|
686
|
-
const last = result[lastIndex];
|
|
687
|
-
if (last && isTextSegment(last)) {
|
|
688
|
-
const text = last.data.text.trimEnd();
|
|
689
|
-
if (text) result[lastIndex] = withText(last, text);
|
|
690
|
-
else result.pop();
|
|
691
|
-
}
|
|
692
|
-
return result;
|
|
693
|
-
}
|
|
694
|
-
let seg;
|
|
695
|
-
(function(_seg) {
|
|
696
|
-
function mention(userId) {
|
|
697
|
-
return {
|
|
698
|
-
type: "mention",
|
|
699
|
-
data: { user_id: userId }
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
_seg.mention = mention;
|
|
703
|
-
function mentionAll() {
|
|
704
|
-
return {
|
|
705
|
-
type: "mention_all",
|
|
706
|
-
data: {}
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
_seg.mentionAll = mentionAll;
|
|
710
|
-
function face(faceId, options) {
|
|
711
|
-
return {
|
|
712
|
-
type: "face",
|
|
713
|
-
data: {
|
|
714
|
-
face_id: faceId.toString(),
|
|
715
|
-
is_large: options?.isLarge ?? false
|
|
716
|
-
}
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
_seg.face = face;
|
|
720
|
-
function reply(messageSeq) {
|
|
721
|
-
return {
|
|
722
|
-
type: "reply",
|
|
723
|
-
data: { message_seq: messageSeq }
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
_seg.reply = reply;
|
|
727
|
-
function image(uri, options) {
|
|
728
|
-
return {
|
|
729
|
-
type: "image",
|
|
730
|
-
data: {
|
|
731
|
-
uri,
|
|
732
|
-
sub_type: options?.subType,
|
|
733
|
-
summary: options?.summary
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
_seg.image = image;
|
|
738
|
-
function record(uri) {
|
|
739
|
-
return {
|
|
740
|
-
type: "record",
|
|
741
|
-
data: { uri }
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
_seg.record = record;
|
|
745
|
-
function video(uri, options) {
|
|
746
|
-
return {
|
|
747
|
-
type: "video",
|
|
748
|
-
data: {
|
|
749
|
-
uri,
|
|
750
|
-
thumb_uri: options?.thumbUri
|
|
751
|
-
}
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
_seg.video = video;
|
|
755
|
-
function forward(messages, options) {
|
|
756
|
-
return {
|
|
757
|
-
type: "forward",
|
|
758
|
-
data: {
|
|
759
|
-
messages,
|
|
760
|
-
title: options?.title,
|
|
761
|
-
preview: options?.preview,
|
|
762
|
-
summary: options?.summary,
|
|
763
|
-
prompt: options?.prompt
|
|
764
|
-
}
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
_seg.forward = forward;
|
|
768
|
-
})(seg || (seg = {}));
|
|
769
|
-
//#endregion
|
|
770
706
|
//#region src/core/logging.ts
|
|
771
707
|
var Logger = class {
|
|
772
708
|
logHandler;
|
|
@@ -1355,7 +1291,7 @@ var Context = class Context {
|
|
|
1355
1291
|
this.logHandler = options?.logHandler ?? parent?.logHandler;
|
|
1356
1292
|
this.name = name ?? "root";
|
|
1357
1293
|
this.logger = new Logger((message) => this.logHandler?.(message), `context:${this.name}`);
|
|
1358
|
-
this.routeActivationResolver =
|
|
1294
|
+
this.routeActivationResolver = options?.routing?.activationResolver ?? parent?.routeActivationResolver ?? defaultRouteActivationResolver;
|
|
1359
1295
|
this.router.setActivationResolver(this.routeActivationResolver);
|
|
1360
1296
|
this.parent = parent;
|
|
1361
1297
|
this.filter = filter;
|
|
@@ -1781,4 +1717,4 @@ let param;
|
|
|
1781
1717
|
_param.segment = segment;
|
|
1782
1718
|
})(param || (param = {}));
|
|
1783
1719
|
//#endregion
|
|
1784
|
-
export { CommandBuilder, Context, Logger, Parameter, Router, combineLogHandlers,
|
|
1720
|
+
export { CommandBuilder, Context, Logger, Parameter, Router, combineLogHandlers, createMilkyClient, createMilkyWebSocketEventSource, defaultRouteActivationResolver, definePlugin, filter, implementsESNextDisposable, isDisposable, mergeRouteMeta, milkyPackageVersion, milkyVersion, msg, param, seg };
|