@fraqjs/fraq 0.9.1 → 0.9.2

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
+ segments: 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,35 @@ 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 (segments, options) => {
728
+ const actualSegments = [...segments];
729
+ if (options?.withMention && message.message_scene === "group") actualSegments.unshift(seg.mention(message.sender_id));
730
+ if (options?.withQuote) actualSegments.unshift(seg.reply(message.message_seq));
731
+ switch (message.message_scene) {
732
+ case "friend": {
733
+ const { message_seq } = await this.client.send_private_message({
734
+ user_id: message.peer_id,
735
+ message: actualSegments
736
+ });
737
+ return { messageSeq: message_seq };
738
+ }
739
+ case "group": {
740
+ const { message_seq } = await this.client.send_group_message({
741
+ group_id: message.peer_id,
742
+ message: actualSegments
743
+ });
744
+ return { messageSeq: message_seq };
610
745
  }
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
746
  }
747
+ return { messageSeq: 0 };
748
+ },
749
+ reaction: async (type, reactionId) => {
750
+ if (message.message_scene === "group") await this.client.send_group_message_reaction({
751
+ group_id: message.peer_id,
752
+ message_seq: message.message_seq,
753
+ reaction_type: type,
754
+ reaction: reactionId
755
+ });
614
756
  }
615
757
  };
616
758
  }
@@ -726,15 +868,15 @@ and implement the dispose method to clean up resources when the context stops.
726
868
  for (const installedPlugin of sortedPlugins) {
727
869
  const { plugin, args } = installedPlugin;
728
870
  const providedBeforeApply = new Set(this.services.keys());
729
- let debugMessage = `Applying plugin ${plugin.name}`;
871
+ let applyingMessage = `Applying plugin ${plugin.name}`;
730
872
  const requiredServices = [];
731
873
  const providedServices = [];
732
874
  if (plugin.requires) for (const service of plugin.requires) requiredServices.push(service.name);
733
875
  if (plugin.optionalRequires) for (const service of plugin.optionalRequires) requiredServices.push(`${service.name}?`);
734
876
  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);
877
+ if (requiredServices.length > 0) applyingMessage += `, requires: [${requiredServices.join(", ")}]`;
878
+ if (providedServices.length > 0) applyingMessage += `, provides: [${providedServices.join(", ")}]`;
879
+ this.logger.info(applyingMessage);
738
880
  await plugin.apply(this.getPluginContext(installedPlugin), ...args);
739
881
  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
882
  }
@@ -1063,138 +1205,6 @@ function definePlugin(plugin) {
1063
1205
  return plugin;
1064
1206
  }
1065
1207
  //#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
1208
  //#region src/protocol/types.ts
1199
1209
  const milkyVersion = "1.3";
1200
1210
  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.9.2",
5
5
  "description": "Milky Bot framework",
6
6
  "files": [
7
7
  "dist"