koishi-plugin-forward-hime 1.4.1-alpha.2 → 1.4.2-alpha.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.
@@ -0,0 +1,45 @@
1
+ // client/index.ts
2
+ import { send } from "@koishijs/client";
3
+ import { defineComponent, h, inject } from "vue";
4
+ var index_default = (ctx) => {
5
+ ctx.slot({
6
+ type: "plugin-details",
7
+ order: -800,
8
+ component: defineComponent({
9
+ setup() {
10
+ const current = inject(
11
+ "manager.settings.current"
12
+ );
13
+ return () => {
14
+ const plugin = current?.value;
15
+ if (!plugin || plugin.name !== "forward-hime" && !plugin.path?.includes("forward-hime")) {
16
+ return null;
17
+ }
18
+ return h(
19
+ "button",
20
+ {
21
+ class: "k-button",
22
+ onClick: async () => {
23
+ const contents = await send(
24
+ "forward-hime:get-diagnostics"
25
+ );
26
+ const url = URL.createObjectURL(
27
+ new Blob([contents], { type: "application/x-ndjson" })
28
+ );
29
+ const anchor = document.createElement("a");
30
+ anchor.href = url;
31
+ anchor.download = "forward-hime-diagnostics.jsonl";
32
+ anchor.click();
33
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
34
+ }
35
+ },
36
+ "\u4E0B\u8F7D\u8BCA\u65AD\u65E5\u5FD7"
37
+ );
38
+ };
39
+ }
40
+ })
41
+ });
42
+ };
43
+ export {
44
+ index_default as default
45
+ };
@@ -0,0 +1,2 @@
1
+ import { Context } from "koishi";
2
+ export declare function consoleInit(ctx: Context): void;
@@ -8,7 +8,7 @@ export declare function decoratorInit(cfg: ConfigSet): void;
8
8
  export declare function defaultDecorator({ head, content }: ForwardMsg): Element[];
9
9
  export declare function defaultMiddleware(session: Session): ForwardMsg;
10
10
  export declare function MsgMiddlewareCache(session: Session): Promise<void>;
11
- export declare function MsgDecorator(session: Session, node: ForwardNode): Promise<any>;
11
+ export declare function MsgDecorator(session: Session, node: ForwardNode, traceId?: string): Promise<any>;
12
12
  export declare function MsgDecoratorNoRelay(session: Session, node: ForwardNode): Promise<any>;
13
13
  export declare function MsgDecoratorFallback(session: Session, node: ForwardNode): Promise<Element[]>;
14
14
  export declare function MsgDecoratorFallbackReason(session: Session, node: ForwardNode, reason: string): Promise<Element[]>;
@@ -0,0 +1,18 @@
1
+ import { Context } from "koishi";
2
+ export interface DiagnosticEvent {
3
+ traceId: string;
4
+ phase: string;
5
+ [key: string]: unknown;
6
+ }
7
+ export declare function createTraceId(): `${string}-${string}-${string}-${string}-${string}`;
8
+ export declare function diagnosticFilename(value: unknown): string;
9
+ export declare function diagnosticMime(value: unknown): string;
10
+ export declare function diagnosticsInit(ctx: Context): void;
11
+ export declare function writeDiagnostic(event: DiagnosticEvent): void;
12
+ export declare function readDiagnosticLogs(): Promise<string>;
13
+ export declare function sanitizeError(error: unknown): {
14
+ name: string;
15
+ code: string | number;
16
+ httpStatus: number;
17
+ summary: string;
18
+ };
package/lib/index.js CHANGED
@@ -250,6 +250,99 @@ var onebot_default = {
250
250
 
251
251
  // src/relay.ts
252
252
  var import_koishi5 = require("koishi");
253
+
254
+ // src/diagnostics.ts
255
+ var import_crypto = require("crypto");
256
+ var import_promises = require("fs/promises");
257
+ var import_path = require("path");
258
+ var RETENTION_DAYS = 7;
259
+ var FILE_PATTERN = /^\d{4}-\d{2}-\d{2}\.jsonl$/;
260
+ var root = "";
261
+ var writeQueue = Promise.resolve();
262
+ var lastCleanupDate = "";
263
+ function createTraceId() {
264
+ return (0, import_crypto.randomUUID)();
265
+ }
266
+ function diagnosticFilename(value) {
267
+ if (typeof value !== "string" || /^https?:\/\//i.test(value)) return void 0;
268
+ return value.replace(/[?#].*$/, "").split(/[\\/]/).pop()?.slice(0, 120);
269
+ }
270
+ function diagnosticMime(value) {
271
+ return typeof value === "string" && /^[\w.+-]+\/[\w.+-]+$/.test(value) ? value : void 0;
272
+ }
273
+ function utcDate(timestamp = Date.now()) {
274
+ return new Date(timestamp).toISOString().slice(0, 10);
275
+ }
276
+ async function cleanup(date) {
277
+ if (date === lastCleanupDate) return;
278
+ const cutoff = Date.parse(`${date}T00:00:00.000Z`) - (RETENTION_DAYS - 1) * 864e5;
279
+ for (const filename of await (0, import_promises.readdir)(root)) {
280
+ if (!FILE_PATTERN.test(filename)) continue;
281
+ if (Date.parse(`${filename.slice(0, 10)}T00:00:00.000Z`) < cutoff) {
282
+ await (0, import_promises.rm)((0, import_path.join)(root, filename), { force: true });
283
+ }
284
+ }
285
+ lastCleanupDate = date;
286
+ }
287
+ function diagnosticsInit(ctx2) {
288
+ root = (0, import_path.join)(ctx2.baseDir, "data", "forward-hime");
289
+ writeQueue = Promise.resolve();
290
+ lastCleanupDate = "";
291
+ writeQueue = writeQueue.then(async () => {
292
+ await (0, import_promises.mkdir)(root, { recursive: true });
293
+ await cleanup(utcDate());
294
+ }).catch((error) => logger.warn("failed to initialize diagnostic log", error));
295
+ }
296
+ function writeDiagnostic(event) {
297
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
298
+ const date = timestamp.slice(0, 10);
299
+ const line = JSON.stringify({ timestamp, ...event }) + "\n";
300
+ writeQueue = writeQueue.then(async () => {
301
+ await (0, import_promises.mkdir)(root, { recursive: true });
302
+ await cleanup(date);
303
+ await (0, import_promises.appendFile)((0, import_path.join)(root, `${date}.jsonl`), line, "utf8");
304
+ }).catch((error) => logger.warn("failed to write diagnostic log", error));
305
+ }
306
+ async function readDiagnosticLogs() {
307
+ await writeQueue;
308
+ const cutoff = new Date(
309
+ Date.parse(`${utcDate()}T00:00:00.000Z`) - (RETENTION_DAYS - 1) * 864e5
310
+ ).toISOString().slice(0, 10);
311
+ const files = (await (0, import_promises.readdir)(root).catch(() => [])).filter(
312
+ (filename) => FILE_PATTERN.test(filename) && filename.slice(0, 10) >= cutoff
313
+ ).sort();
314
+ const contents = await Promise.all(
315
+ files.map((filename) => (0, import_promises.readFile)((0, import_path.join)(root, filename), "utf8"))
316
+ );
317
+ return contents.join("");
318
+ }
319
+ function sanitizeError(error) {
320
+ const value = error;
321
+ const message = typeof value?.message === "string" ? value.message : String(error);
322
+ const lowerMessage = message.toLowerCase();
323
+ let summary = "request failed";
324
+ if (lowerMessage.includes("timeout") || lowerMessage.includes("timed out")) {
325
+ summary = "request timed out";
326
+ } else if (lowerMessage.includes("denied") || lowerMessage.includes("401") || lowerMessage.includes("403")) {
327
+ summary = "request denied";
328
+ } else if (lowerMessage.includes("not found") || lowerMessage.includes("404")) {
329
+ summary = "resource not found";
330
+ } else if (lowerMessage.includes("too large")) {
331
+ summary = "media exceeds size limit";
332
+ } else if (lowerMessage.includes("network") || lowerMessage.includes("econn") || lowerMessage.includes("enotfound")) {
333
+ summary = "network error";
334
+ } else if (lowerMessage.includes("empty media")) {
335
+ summary = "empty media payload";
336
+ }
337
+ return {
338
+ name: typeof value?.name === "string" && /^[a-z][\w.-]{0,63}$/i.test(value.name) ? value.name : "Error",
339
+ code: typeof value?.code === "string" && /^[\w.-]{1,64}$/.test(value.code) || typeof value?.code === "number" ? value.code : void 0,
340
+ httpStatus: typeof value?.status === "number" ? value.status : Number(/\bstatus\s+(\d{3})\b/i.exec(message)?.[1]) || void 0,
341
+ summary
342
+ };
343
+ }
344
+
345
+ // src/relay.ts
253
346
  var DEFAULT_IMAGE_MIME = "image/jpeg";
254
347
  var DEFAULT_AUDIO_MIME = "audio/mpeg";
255
348
  var DEFAULT_VIDEO_MIME = "video/mp4";
@@ -340,8 +433,11 @@ function createRelayElement(kind, mime, buffer, filename) {
340
433
  if (kind === "img") {
341
434
  return import_koishi5.h.image(buffer, mime);
342
435
  }
436
+ if (kind === "file") {
437
+ return helperMap.file(buffer, mime, { filename });
438
+ }
343
439
  if (helperMap[kind]) {
344
- return helperMap[kind](buffer, mime, filename);
440
+ return helperMap[kind](buffer, mime);
345
441
  }
346
442
  const base64 = buffer.toString("base64");
347
443
  return (0, import_koishi5.h)(kind, { src: `data:${mime};base64,${base64}`, filename });
@@ -361,9 +457,23 @@ function networkMessageFromError(error) {
361
457
  }
362
458
  return "\u7F51\u7EDC\u95EE\u9898\uFF1A\u5A92\u4F53\u6587\u4EF6\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\u3002";
363
459
  }
364
- async function downloadAndRelay(element) {
460
+ async function downloadAndRelay(element, traceId, session, node) {
461
+ const startedAt = Date.now();
365
462
  const kind = normalizeMediaType(element.type);
366
463
  const src = mediaUrlFromElement(element);
464
+ const media = {
465
+ type: kind,
466
+ filename: diagnosticFilename(element.attrs?.filename),
467
+ mime: diagnosticMime(element.attrs?.mime),
468
+ size: typeof element.attrs?.size === "number" ? element.attrs.size : void 0
469
+ };
470
+ const context = {
471
+ source: session && { platform: session.platform, node: session.channelId },
472
+ target: node && { platform: node.Platform, node: node.Guild }
473
+ };
474
+ if (traceId) {
475
+ writeDiagnostic({ traceId, phase: "media-relay-start", media, ...context });
476
+ }
367
477
  if (!src) {
368
478
  throw new MediaRelayError(
369
479
  `missing media src for ${element.type}`,
@@ -374,6 +484,17 @@ async function downloadAndRelay(element) {
374
484
  const cacheKey = getCacheKey(element);
375
485
  const cacheItem = relayCache.get(cacheKey);
376
486
  if (cacheItem) {
487
+ if (traceId) {
488
+ writeDiagnostic({
489
+ traceId,
490
+ phase: "media-relay-result",
491
+ status: "cache-hit",
492
+ bytes: cacheItem.buffer.length,
493
+ mime: diagnosticMime(cacheItem.mime),
494
+ durationMs: Date.now() - startedAt,
495
+ ...context
496
+ });
497
+ }
377
498
  return relayElementFromCache(cacheItem);
378
499
  }
379
500
  const timeoutSignal = typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(relayConfig.RequestTimeoutSec * 1e3) : void 0;
@@ -435,9 +556,21 @@ async function downloadAndRelay(element) {
435
556
  buffer,
436
557
  filename
437
558
  });
559
+ if (traceId) {
560
+ writeDiagnostic({
561
+ traceId,
562
+ phase: "media-relay-result",
563
+ status: "success",
564
+ media,
565
+ bytes: buffer.length,
566
+ mime: diagnosticMime(mime),
567
+ ...context,
568
+ durationMs: Date.now() - startedAt
569
+ });
570
+ }
438
571
  return relayed;
439
572
  }
440
- async function relayForwardContent(content) {
573
+ async function relayForwardContent(content, traceId, session, node) {
441
574
  if (!relayConfig.Enabled) {
442
575
  return content;
443
576
  }
@@ -447,9 +580,24 @@ async function relayForwardContent(content) {
447
580
  newContent.push(element);
448
581
  continue;
449
582
  }
583
+ const startedAt = Date.now();
450
584
  try {
451
- newContent.push(await downloadAndRelay(element));
585
+ newContent.push(await downloadAndRelay(element, traceId, session, node));
452
586
  } catch (error) {
587
+ if (traceId) {
588
+ writeDiagnostic({
589
+ traceId,
590
+ phase: "media-relay-result",
591
+ status: "error",
592
+ error: sanitizeError(error),
593
+ durationMs: Date.now() - startedAt,
594
+ source: session && {
595
+ platform: session.platform,
596
+ node: session.channelId
597
+ },
598
+ target: node && { platform: node.Platform, node: node.Guild }
599
+ });
600
+ }
453
601
  throw new MediaRelayError(
454
602
  error instanceof Error ? error.message : "relay failed",
455
603
  networkMessageFromError(error)
@@ -460,29 +608,63 @@ async function relayForwardContent(content) {
460
608
  }
461
609
 
462
610
  // src/message.ts
463
- async function MessageSendWithDecorator(ctx2, node, session, Deco) {
611
+ async function MessageSendWithDecorator(ctx2, node, session, Deco, traceId, attempt) {
612
+ const startedAt = Date.now();
464
613
  const uuid = session.channelId + ":" + session.messageId;
465
- const content = await Deco(session, node);
466
- await ctx2.bots[`${node.Platform}:${node.BotID}`].sendMessage(node.Guild, content).then((res) => {
467
- const mc = {
468
- platform: node.Platform,
469
- bot: node.BotID,
470
- guild: node.Guild,
471
- msgid: res[0],
472
- uuid
473
- };
474
- if (!mc.msgid) {
475
- throw new Error(`Empty Message ID`);
476
- } else {
477
- msgCache(mc);
478
- logger.debug(`[MessageForward] to ${mc.platform} ${mc.uuid}`);
614
+ writeDiagnostic({
615
+ traceId,
616
+ phase: "send-attempt",
617
+ attempt,
618
+ source: { platform: session.platform, node: session.channelId },
619
+ target: { platform: node.Platform, node: node.Guild },
620
+ elementTypes: session.elements.map((element) => element.type)
621
+ });
622
+ try {
623
+ const content = await Deco(session, node, traceId);
624
+ const res = await ctx2.bots[`${node.Platform}:${node.BotID}`].sendMessage(
625
+ node.Guild,
626
+ content
627
+ );
628
+ {
629
+ const mc = {
630
+ platform: node.Platform,
631
+ bot: node.BotID,
632
+ guild: node.Guild,
633
+ msgid: res[0],
634
+ uuid
635
+ };
636
+ if (!mc.msgid) {
637
+ throw new Error(`Empty Message ID`);
638
+ } else {
639
+ msgCache(mc);
640
+ logger.debug(`[MessageForward] to ${mc.platform} ${mc.uuid}`);
641
+ }
479
642
  }
480
- }).catch((error) => {
643
+ writeDiagnostic({
644
+ traceId,
645
+ phase: "send-result",
646
+ attempt,
647
+ status: "success",
648
+ durationMs: Date.now() - startedAt,
649
+ source: { platform: session.platform, node: session.channelId },
650
+ target: { platform: node.Platform, node: node.Guild }
651
+ });
652
+ } catch (error) {
653
+ writeDiagnostic({
654
+ traceId,
655
+ phase: "send-result",
656
+ attempt,
657
+ status: "error",
658
+ durationMs: Date.now() - startedAt,
659
+ source: { platform: session.platform, node: session.channelId },
660
+ target: { platform: node.Platform, node: node.Guild },
661
+ error: sanitizeError(error)
662
+ });
481
663
  logger.error(
482
664
  `ERROR:<MessageSendWithDecorator ${node.Platform}> ctx=${ctx2} ${error}`
483
665
  );
484
666
  throw error;
485
- });
667
+ }
486
668
  }
487
669
  function sessionTypeArray(session) {
488
670
  let contentTypes = "|";
@@ -492,9 +674,34 @@ function sessionTypeArray(session) {
492
674
  return contentTypes;
493
675
  }
494
676
  async function MessageForward(ctx2, node, session, timeoutSec, relayEnabled) {
677
+ const traceId = createTraceId();
678
+ const source = { platform: session.platform, node: session.channelId };
679
+ const target = { platform: node.Platform, node: node.Guild };
495
680
  if (!botExistsCheck(ctx2, node)) {
681
+ writeDiagnostic({
682
+ traceId,
683
+ phase: "forward-result",
684
+ status: "bot-missing",
685
+ source,
686
+ target
687
+ });
496
688
  return;
497
689
  }
690
+ writeDiagnostic({
691
+ traceId,
692
+ phase: "forward-start",
693
+ source,
694
+ target,
695
+ elementTypes: session.elements.map((element) => element.type),
696
+ media: session.elements.filter(
697
+ (element) => ["img", "image", "audio", "video", "file"].includes(element.type)
698
+ ).map((element) => ({
699
+ type: element.type,
700
+ filename: diagnosticFilename(element.attrs?.filename),
701
+ mime: diagnosticMime(element.attrs?.mime),
702
+ size: typeof element.attrs?.size === "number" ? element.attrs.size : void 0
703
+ }))
704
+ });
498
705
  const timeoutMs = (timeoutSec ?? 30) * 1e3;
499
706
  const deco = relayEnabled !== false ? MsgDecorator : MsgDecoratorNoRelay;
500
707
  function warnIfSlow(promise) {
@@ -506,8 +713,16 @@ async function MessageForward(ctx2, node, session, timeoutSec, relayEnabled) {
506
713
  return promise.finally(() => clearTimeout(timer));
507
714
  }
508
715
  function sendDegraded(reason) {
716
+ writeDiagnostic({ traceId, phase: "forward-degraded", source, target });
509
717
  const fallbackDeco = reason ? (fallbackSession, fallbackNode) => MsgDecoratorFallbackReason(fallbackSession, fallbackNode, reason) : MsgDecoratorFallback;
510
- MessageSendWithDecorator(ctx2, node, session, fallbackDeco).catch((error) => {
718
+ MessageSendWithDecorator(
719
+ ctx2,
720
+ node,
721
+ session,
722
+ fallbackDeco,
723
+ traceId,
724
+ "fallback"
725
+ ).catch((error) => {
511
726
  logger.error(
512
727
  `ERROR:<MessageSendFallback ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${error}`
513
728
  );
@@ -519,28 +734,43 @@ async function MessageForward(ctx2, node, session, timeoutSec, relayEnabled) {
519
734
  }
520
735
  return void 0;
521
736
  }
522
- warnIfSlow(MessageSendWithDecorator(ctx2, node, session, deco)).catch(
523
- (firstError) => {
524
- logger.error(
525
- `ERROR:<MessageSend ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${firstError}`
737
+ const traceableDeco = (sourceSession, targetNode, id) => deco(sourceSession, targetNode, id);
738
+ warnIfSlow(
739
+ MessageSendWithDecorator(
740
+ ctx2,
741
+ node,
742
+ session,
743
+ traceableDeco,
744
+ traceId,
745
+ relayEnabled === false ? "direct" : "relay"
746
+ )
747
+ ).catch((firstError) => {
748
+ logger.error(
749
+ `ERROR:<MessageSend ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${firstError}`
750
+ );
751
+ if (relayEnabled !== false && firstError instanceof MediaRelayError) {
752
+ logger.info(
753
+ `[MessageForward] relay failed, retrying without relay: ${node.Platform}`
526
754
  );
527
- if (relayEnabled !== false && firstError instanceof MediaRelayError) {
528
- logger.info(
529
- `[MessageForward] relay failed, retrying without relay: ${node.Platform}`
755
+ warnIfSlow(
756
+ MessageSendWithDecorator(
757
+ ctx2,
758
+ node,
759
+ session,
760
+ MsgDecoratorNoRelay,
761
+ traceId,
762
+ "direct-retry"
763
+ )
764
+ ).catch((secondError) => {
765
+ logger.error(
766
+ `ERROR:<MessageSendDirect ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${secondError}`
530
767
  );
531
- warnIfSlow(
532
- MessageSendWithDecorator(ctx2, node, session, MsgDecoratorNoRelay)
533
- ).catch((secondError) => {
534
- logger.error(
535
- `ERROR:<MessageSendDirect ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${secondError}`
536
- );
537
- sendDegraded(reasonFromError(secondError));
538
- });
539
- } else {
540
- sendDegraded(reasonFromError(firstError));
541
- }
768
+ sendDegraded(reasonFromError(secondError));
769
+ });
770
+ } else {
771
+ sendDegraded(reasonFromError(firstError));
542
772
  }
543
- );
773
+ });
544
774
  }
545
775
  async function MessageDelete(ctx2, msg) {
546
776
  if (!botExistsCheck(ctx2, { Platform: msg.platform, BotID: msg.bot, Guild: msg.guild })) {
@@ -617,7 +847,7 @@ async function MsgMiddlewareCache(session) {
617
847
  msgMiddleCacheAppend({ UUID: MsgUUIDFromSession(session), msg: elems });
618
848
  logger.debug(`[msgMiddleCache] CACHED`);
619
849
  }
620
- async function MsgDecorator(session, node) {
850
+ async function MsgDecorator(session, node, traceId) {
621
851
  let elems;
622
852
  const _platform_out = decorators_exports[node.Platform];
623
853
  const elemCache = msgMiddleCacheFind(MsgUUIDFromSession(session));
@@ -633,7 +863,7 @@ async function MsgDecorator(session, node) {
633
863
  }
634
864
  elems = {
635
865
  head: elems.head,
636
- content: await relayForwardContent(elems.content)
866
+ content: await relayForwardContent(elems.content, traceId, session, node)
637
867
  };
638
868
  if (_platform_out && typeof _platform_out.Decorator === "function") {
639
869
  return _platform_out.Decorator(elems);
@@ -689,7 +919,7 @@ async function MsgDecoratorFallbackReason(session, node, reason) {
689
919
  return defaultDecoratorFallback(elems, reason);
690
920
  }
691
921
  async function atTranslator(session, _, { head, content }) {
692
- const newMsg = await new Promise((resolve) => {
922
+ const newMsg = await new Promise((resolve2) => {
693
923
  const newContent = [];
694
924
  for (const key in content) {
695
925
  const element = content[key];
@@ -703,7 +933,7 @@ async function atTranslator(session, _, { head, content }) {
703
933
  newContent.push(element);
704
934
  }
705
935
  }
706
- resolve({ head, content: newContent });
936
+ resolve2({ head, content: newContent });
707
937
  });
708
938
  return newMsg;
709
939
  }
@@ -725,6 +955,21 @@ async function quoteTranslator(session, node, { head, content }) {
725
955
  return { head, content };
726
956
  }
727
957
 
958
+ // src/console.ts
959
+ var import_path2 = require("path");
960
+ function consoleInit(ctx2) {
961
+ ctx2.inject(["console"], (ctx3) => {
962
+ const console = ctx3.console;
963
+ console.addListener("forward-hime:get-diagnostics", readDiagnosticLogs, {
964
+ authority: 4
965
+ });
966
+ console.addEntry({
967
+ dev: (0, import_path2.resolve)(__dirname, "../client/index.ts"),
968
+ prod: (0, import_path2.resolve)(__dirname, "client")
969
+ });
970
+ });
971
+ }
972
+
728
973
  // src/index.ts
729
974
  var name = `forward hime - \u8F6C\u53D1\u59EC`;
730
975
  var usage = `
@@ -740,11 +985,13 @@ var usage = `
740
985
  ---`;
741
986
  var reusable = true;
742
987
  var inject = {
743
- optional: ["cache"]
988
+ optional: ["cache", "console"]
744
989
  };
745
990
  var Config = createConfig();
746
991
  function apply(ctx2, cfg) {
747
992
  loggerInit(ctx2);
993
+ diagnosticsInit(ctx2);
994
+ consoleInit(ctx2);
748
995
  msgCacheInit(ctx2, cfg);
749
996
  decoratorInit(cfg);
750
997
  ctx2.on("message-created", async (session) => {
@@ -814,7 +1061,7 @@ function apply(ctx2, cfg) {
814
1061
  });
815
1062
  });
816
1063
  ctx2.on("message-updated", async (session) => {
817
- logger.debug("[message-updated]", session.messageId, session);
1064
+ logger.debug("[message-updated]", session.messageId);
818
1065
  });
819
1066
  }
820
1067
  // Annotate the CommonJS export names for ESM import in node:
package/lib/relay.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { Element } from "koishi";
2
2
  import { ConfigSet } from "./config";
3
+ import { Session } from "koishi";
4
+ import { ForwardNode } from "./config";
3
5
  export declare class MediaRelayError extends Error {
4
6
  userMessage: string;
5
7
  constructor(message: string, userMessage: string);
6
8
  }
7
9
  export declare function relayInit(cfg: ConfigSet): void;
8
- export declare function relayForwardContent(content: Element[]): Promise<Element[]>;
10
+ export declare function relayForwardContent(content: Element[], traceId?: string, session?: Session, node?: ForwardNode): Promise<Element[]>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-forward-hime",
3
3
  "description": "多群组消息互通",
4
- "version": "1.4.1-alpha.2",
4
+ "version": "1.4.2-alpha.1",
5
5
  "author": {
6
6
  "name": "xianii",
7
7
  "email": "jiyucheng007@gmail.com"
@@ -57,7 +57,8 @@
57
57
  },
58
58
  "scripts": {
59
59
  "prepare": "husky",
60
- "build": "rm -f tsconfig.tsbuildinfo && rm -rf lib && tsc -b && esbuild src/index.ts --bundle --platform=node --packages=external --outfile=lib/index.js",
60
+ "build": "rm -f tsconfig.tsbuildinfo && rm -rf lib && tsc -b && esbuild src/index.ts --bundle --platform=node --packages=external --outfile=lib/index.js && esbuild client/index.ts --bundle --platform=browser --format=esm --packages=external --outfile=lib/client/index.js",
61
+ "test": "node --test",
61
62
  "eslint": "eslint \"src/**/*.{ts,tsx}\"",
62
63
  "format": "prettier --write .",
63
64
  "pub": "npm publish --access public"