@fraqjs/fraq 0.9.1 → 0.10.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 CHANGED
@@ -5522,9 +5522,19 @@ interface RawPattern<P extends Pattern> {
5522
5522
  pattern: P;
5523
5523
  execute: Executor<P>;
5524
5524
  }
5525
+ interface SessionReplyOptions {
5526
+ withQuote?: boolean;
5527
+ withMention?: boolean;
5528
+ }
5525
5529
  interface Session {
5526
5530
  raw: IncomingMessage;
5527
- reply(segments: OutgoingSegment_ZodInput[]): Promise<void>;
5531
+ reply(
5532
+ textOrSegments: string | OutgoingSegment_ZodInput[],
5533
+ options?: SessionReplyOptions,
5534
+ ): Promise<{
5535
+ messageSeq: number;
5536
+ }>;
5537
+ reaction(type: 'face' | 'emoji', reactionId: string): Promise<void>;
5528
5538
  }
5529
5539
  declare class CommandBuilder<P extends Pattern = {}, S = Command<P>> {
5530
5540
  readonly name: string;
@@ -5846,6 +5856,7 @@ export {
5846
5856
  ServiceClass,
5847
5857
  Session,
5848
5858
  SessionPredicate,
5859
+ SessionReplyOptions,
5849
5860
  TypeInstruction,
5850
5861
  combineLogHandlers,
5851
5862
  createMilkyClient,
package/dist/index.mjs CHANGED
@@ -64,6 +64,138 @@ function createMilkyClient(...params) {
64
64
  } });
65
65
  }
66
66
  //#endregion
67
+ //#region src/protocol/segment.ts
68
+ function msg(strings, ...values) {
69
+ let buffer = "";
70
+ const segments = [];
71
+ for (let i = 0; i < strings.length; i++) {
72
+ buffer += strings[i];
73
+ if (i < values.length) {
74
+ const value = values[i];
75
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") buffer += value.toString();
76
+ else {
77
+ if (buffer) {
78
+ segments.push({
79
+ type: "text",
80
+ data: { text: buffer }
81
+ });
82
+ buffer = "";
83
+ }
84
+ segments.push(value);
85
+ }
86
+ }
87
+ }
88
+ if (buffer) segments.push({
89
+ type: "text",
90
+ data: { text: buffer }
91
+ });
92
+ return trimBoundaryTextSegments(segments);
93
+ }
94
+ function isTextSegment(segment) {
95
+ return segment.type === "text";
96
+ }
97
+ function withText(segment, text) {
98
+ return {
99
+ ...segment,
100
+ data: {
101
+ ...segment.data,
102
+ text
103
+ }
104
+ };
105
+ }
106
+ function trimBoundaryTextSegments(segments) {
107
+ const result = [...segments];
108
+ const first = result[0];
109
+ if (first && isTextSegment(first)) {
110
+ const text = first.data.text.trimStart();
111
+ if (text) result[0] = withText(first, text);
112
+ else result.shift();
113
+ }
114
+ const lastIndex = result.length - 1;
115
+ const last = result[lastIndex];
116
+ if (last && isTextSegment(last)) {
117
+ const text = last.data.text.trimEnd();
118
+ if (text) result[lastIndex] = withText(last, text);
119
+ else result.pop();
120
+ }
121
+ return result;
122
+ }
123
+ let seg;
124
+ (function(_seg) {
125
+ function mention(userId) {
126
+ return {
127
+ type: "mention",
128
+ data: { user_id: userId }
129
+ };
130
+ }
131
+ _seg.mention = mention;
132
+ function mentionAll() {
133
+ return {
134
+ type: "mention_all",
135
+ data: {}
136
+ };
137
+ }
138
+ _seg.mentionAll = mentionAll;
139
+ function face(faceId, options) {
140
+ return {
141
+ type: "face",
142
+ data: {
143
+ face_id: faceId.toString(),
144
+ is_large: options?.isLarge ?? false
145
+ }
146
+ };
147
+ }
148
+ _seg.face = face;
149
+ function reply(messageSeq) {
150
+ return {
151
+ type: "reply",
152
+ data: { message_seq: messageSeq }
153
+ };
154
+ }
155
+ _seg.reply = reply;
156
+ function image(uri, options) {
157
+ return {
158
+ type: "image",
159
+ data: {
160
+ uri,
161
+ sub_type: options?.subType,
162
+ summary: options?.summary
163
+ }
164
+ };
165
+ }
166
+ _seg.image = image;
167
+ function record(uri) {
168
+ return {
169
+ type: "record",
170
+ data: { uri }
171
+ };
172
+ }
173
+ _seg.record = record;
174
+ function video(uri, options) {
175
+ return {
176
+ type: "video",
177
+ data: {
178
+ uri,
179
+ thumb_uri: options?.thumbUri
180
+ }
181
+ };
182
+ }
183
+ _seg.video = video;
184
+ function forward(messages, options) {
185
+ return {
186
+ type: "forward",
187
+ data: {
188
+ messages,
189
+ title: options?.title,
190
+ preview: options?.preview,
191
+ summary: options?.summary,
192
+ prompt: options?.prompt
193
+ }
194
+ };
195
+ }
196
+ _seg.forward = forward;
197
+ })(seg || (seg = {}));
198
+ //#endregion
67
199
  //#region src/routing/command.ts
68
200
  var CommandBuilder = class {
69
201
  name;
@@ -592,25 +724,40 @@ and implement the dispose method to clean up resources when the context stops.
592
724
  createSession(message) {
593
725
  return {
594
726
  raw: message,
595
- reply: async (segments) => {
596
- try {
597
- switch (message.message_scene) {
598
- case "friend":
599
- await this.client.send_private_message({
600
- user_id: message.peer_id,
601
- message: segments
602
- });
603
- break;
604
- case "group":
605
- await this.client.send_group_message({
606
- group_id: message.peer_id,
607
- message: segments
608
- });
609
- break;
727
+ reply: async (textOrSegments, options) => {
728
+ const actualSegments = [];
729
+ if (typeof textOrSegments === "string") actualSegments.push({
730
+ type: "text",
731
+ data: { text: textOrSegments }
732
+ });
733
+ else actualSegments.push(...textOrSegments);
734
+ if (options?.withMention && message.message_scene === "group") actualSegments.unshift(seg.mention(message.sender_id));
735
+ if (options?.withQuote) actualSegments.unshift(seg.reply(message.message_seq));
736
+ switch (message.message_scene) {
737
+ case "friend": {
738
+ const { message_seq } = await this.client.send_private_message({
739
+ user_id: message.peer_id,
740
+ message: actualSegments
741
+ });
742
+ return { messageSeq: message_seq };
743
+ }
744
+ case "group": {
745
+ const { message_seq } = await this.client.send_group_message({
746
+ group_id: message.peer_id,
747
+ message: actualSegments
748
+ });
749
+ return { messageSeq: message_seq };
610
750
  }
611
- } catch (error) {
612
- 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);
613
751
  }
752
+ return { messageSeq: 0 };
753
+ },
754
+ reaction: async (type, reactionId) => {
755
+ if (message.message_scene === "group") await this.client.send_group_message_reaction({
756
+ group_id: message.peer_id,
757
+ message_seq: message.message_seq,
758
+ reaction_type: type,
759
+ reaction: reactionId
760
+ });
614
761
  }
615
762
  };
616
763
  }
@@ -726,15 +873,15 @@ and implement the dispose method to clean up resources when the context stops.
726
873
  for (const installedPlugin of sortedPlugins) {
727
874
  const { plugin, args } = installedPlugin;
728
875
  const providedBeforeApply = new Set(this.services.keys());
729
- let debugMessage = `Applying plugin ${plugin.name}`;
876
+ let applyingMessage = `Applying plugin ${plugin.name}`;
730
877
  const requiredServices = [];
731
878
  const providedServices = [];
732
879
  if (plugin.requires) for (const service of plugin.requires) requiredServices.push(service.name);
733
880
  if (plugin.optionalRequires) for (const service of plugin.optionalRequires) requiredServices.push(`${service.name}?`);
734
881
  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);
882
+ if (requiredServices.length > 0) applyingMessage += `, requires: [${requiredServices.join(", ")}]`;
883
+ if (providedServices.length > 0) applyingMessage += `, provides: [${providedServices.join(", ")}]`;
884
+ this.logger.info(applyingMessage);
738
885
  await plugin.apply(this.getPluginContext(installedPlugin), ...args);
739
886
  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.`);
740
887
  }
@@ -1063,138 +1210,6 @@ function definePlugin(plugin) {
1063
1210
  return plugin;
1064
1211
  }
1065
1212
  //#endregion
1066
- //#region src/protocol/segment.ts
1067
- function msg(strings, ...values) {
1068
- let buffer = "";
1069
- const segments = [];
1070
- for (let i = 0; i < strings.length; i++) {
1071
- buffer += strings[i];
1072
- if (i < values.length) {
1073
- const value = values[i];
1074
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") buffer += value.toString();
1075
- else {
1076
- if (buffer) {
1077
- segments.push({
1078
- type: "text",
1079
- data: { text: buffer }
1080
- });
1081
- buffer = "";
1082
- }
1083
- segments.push(value);
1084
- }
1085
- }
1086
- }
1087
- if (buffer) segments.push({
1088
- type: "text",
1089
- data: { text: buffer }
1090
- });
1091
- return trimBoundaryTextSegments(segments);
1092
- }
1093
- function isTextSegment(segment) {
1094
- return segment.type === "text";
1095
- }
1096
- function withText(segment, text) {
1097
- return {
1098
- ...segment,
1099
- data: {
1100
- ...segment.data,
1101
- text
1102
- }
1103
- };
1104
- }
1105
- function trimBoundaryTextSegments(segments) {
1106
- const result = [...segments];
1107
- const first = result[0];
1108
- if (first && isTextSegment(first)) {
1109
- const text = first.data.text.trimStart();
1110
- if (text) result[0] = withText(first, text);
1111
- else result.shift();
1112
- }
1113
- const lastIndex = result.length - 1;
1114
- const last = result[lastIndex];
1115
- if (last && isTextSegment(last)) {
1116
- const text = last.data.text.trimEnd();
1117
- if (text) result[lastIndex] = withText(last, text);
1118
- else result.pop();
1119
- }
1120
- return result;
1121
- }
1122
- let seg;
1123
- (function(_seg) {
1124
- function mention(userId) {
1125
- return {
1126
- type: "mention",
1127
- data: { user_id: userId }
1128
- };
1129
- }
1130
- _seg.mention = mention;
1131
- function mentionAll() {
1132
- return {
1133
- type: "mention_all",
1134
- data: {}
1135
- };
1136
- }
1137
- _seg.mentionAll = mentionAll;
1138
- function face(faceId, options) {
1139
- return {
1140
- type: "face",
1141
- data: {
1142
- face_id: faceId.toString(),
1143
- is_large: options?.isLarge ?? false
1144
- }
1145
- };
1146
- }
1147
- _seg.face = face;
1148
- function reply(messageSeq) {
1149
- return {
1150
- type: "reply",
1151
- data: { message_seq: messageSeq }
1152
- };
1153
- }
1154
- _seg.reply = reply;
1155
- function image(uri, options) {
1156
- return {
1157
- type: "image",
1158
- data: {
1159
- uri,
1160
- sub_type: options?.subType,
1161
- summary: options?.summary
1162
- }
1163
- };
1164
- }
1165
- _seg.image = image;
1166
- function record(uri) {
1167
- return {
1168
- type: "record",
1169
- data: { uri }
1170
- };
1171
- }
1172
- _seg.record = record;
1173
- function video(uri, options) {
1174
- return {
1175
- type: "video",
1176
- data: {
1177
- uri,
1178
- thumb_uri: options?.thumbUri
1179
- }
1180
- };
1181
- }
1182
- _seg.video = video;
1183
- function forward(messages, options) {
1184
- return {
1185
- type: "forward",
1186
- data: {
1187
- messages,
1188
- title: options?.title,
1189
- preview: options?.preview,
1190
- summary: options?.summary,
1191
- prompt: options?.prompt
1192
- }
1193
- };
1194
- }
1195
- _seg.forward = forward;
1196
- })(seg || (seg = {}));
1197
- //#endregion
1198
1213
  //#region src/protocol/types.ts
1199
1214
  const milkyVersion = "1.3";
1200
1215
  const milkyPackageVersion = "1.3.0-rc.1";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fraqjs/fraq",
3
3
  "type": "module",
4
- "version": "0.9.1",
4
+ "version": "0.10.0",
5
5
  "description": "Milky Bot framework",
6
6
  "files": [
7
7
  "dist"