@chatluna/patchbay 0.1.3 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatluna/patchbay",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Cordis 4 patches for Koishi, Satori, Satori adapters and Cordis plugins, wired into yarn, pnpm or npm",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/patchbay.json CHANGED
@@ -2,12 +2,8 @@
2
2
  "patches": [
3
3
  {
4
4
  "name": "@cordisjs/plugin-cli-cordis",
5
- "version": "1.0.5",
6
- "description": "Stable root include id, launcher include overrides and IPC health pings; best-effort stdio, exit on parent disconnect and a bounded exit",
7
- "fixes": [
8
- "ChatLunaLab/v2-mirror#99",
9
- "cordiverse/cordis#294"
10
- ]
5
+ "version": "1.0.6",
6
+ "description": "Stable root include id, launcher include overrides, IPC health pings and a ready message"
11
7
  },
12
8
  {
13
9
  "name": "@cordisjs/plugin-database",
@@ -17,7 +13,11 @@
17
13
  {
18
14
  "name": "@cordisjs/plugin-http",
19
15
  "version": "1.5.2",
20
- "description": "Use resolveIntercept, which Cordis 4 renamed from resolveConfig"
16
+ "description": "Use resolveIntercept, which Cordis 4 renamed from resolveConfig; merge request headers per name and send the global FormData as multipart",
17
+ "fixes": [
18
+ "ChatLunaLab/v2-mirror#140",
19
+ "ChatLunaLab/v2-mirror#145"
20
+ ]
21
21
  },
22
22
  {
23
23
  "name": "@cordisjs/plugin-loader",
@@ -64,7 +64,10 @@
64
64
  {
65
65
  "name": "koishi-plugin-adapter-onebot",
66
66
  "version": "6.9.5",
67
- "description": "Import Satori directly and inject http, satori and timer"
67
+ "description": "Import Satori directly and inject http, satori and timer; mark friend_recall as a direct channel like private messages",
68
+ "fixes": [
69
+ "ChatLunaLab/v2-mirror#159"
70
+ ]
68
71
  }
69
72
  ],
70
73
  "aliases": {
@@ -0,0 +1,56 @@
1
+ diff --git a/lib/worker/index.d.ts b/lib/worker/index.d.ts
2
+ index 4362cf8..ae92999 100644
3
+ --- a/lib/worker/index.d.ts
4
+ +++ b/lib/worker/index.d.ts
5
+ @@ -4,6 +4,10 @@ export interface Config {
6
+ baseUrl?: string;
7
+ execArgv?: string[];
8
+ path: string;
9
+ + /** Fixed id for the root include entry; defaults to 'chatluna' (keeps tree ids stable). */
10
+ + includeId?: string;
11
+ + /** Override/extend the root include config (e.g. inject `patches` to enable a group). */
12
+ + include?: Record<string, unknown>;
13
+ daemon: daemon.Config;
14
+ prelude?: EntryOptions[];
15
+ }
16
+ diff --git a/lib/worker/index.js b/lib/worker/index.js
17
+ index 39fe113..f0a2566 100644
18
+ --- a/lib/worker/index.js
19
+ +++ b/lib/worker/index.js
20
+ @@ -56,6 +56,12 @@ function* apply(ctx, config = {}) {
21
+ return;
22
+ }
23
+ send({ type: "start", body: config });
24
+ + // Health over IPC: the supervisor pings, the worker answers; no network address involved.
25
+ + const onMessage = /* @__PURE__ */ __name((message) => {
26
+ + if (message?.type === "ping") send({ type: "pong", id: message.id });
27
+ + }, "onMessage");
28
+ + process.on("message", onMessage);
29
+ + yield () => process.off("message", onMessage);
30
+ if (config.heartbeatInterval) {
31
+ const timer = setInterval(() => {
32
+ send({ type: "heartbeat" });
33
+ @@ -86,12 +92,22 @@ async function start(config) {
34
+ await ctx.loader.create(plugin);
35
+ }
36
+ await ctx.loader.create({
37
+ + // Fixed id so tree-side entries keep stable ids (chatluna:<id>) across restarts.
38
+ + id: config.includeId ?? "chatluna",
39
+ name: "@cordisjs/plugin-include",
40
+ config: {
41
+ + // `include` lets the launcher override the include config wholesale (e.g.
42
+ + // `chatluna dev` injects a `patches` entry to enable the dev group).
43
+ path: config.path,
44
+ - enableLogs: true
45
+ + enableLogs: true,
46
+ + ...config.include
47
+ }
48
+ });
49
+ + // Ready once every entry has finished loading (failed plugins included; they are logged).
50
+ + if (config.daemon.enabled) {
51
+ + await ctx.loader.await();
52
+ + send({ type: "ready" });
53
+ + }
54
+ }
55
+ __name(start, "start");
56
+ export {
@@ -1,13 +1,28 @@
1
1
  diff --git a/lib/index.js b/lib/index.js
2
- index 3acbdff..56c9913 100644
2
+ index 3acbdff..0fec2d3 100644
3
3
  --- a/lib/index.js
4
4
  +++ b/lib/index.js
5
- @@ -202,7 +202,7 @@ var Http = class _Http extends Service {
5
+ @@ -202,7 +202,9 @@ var Http = class _Http extends Service {
6
6
  });
7
7
  }
8
8
  resolveConfig(init) {
9
9
  - return this[Service.resolveConfig](this.config, init);
10
- + return { ...this[Service.resolveIntercept](), ...this.config, ...init };
10
+ + // Merge headers per name, so a request's own `headers` (undefined or a Headers instance too) layers over the client's.
11
+ + const configs = [this[Service.resolveIntercept](), this.config, init];
12
+ + return Object.assign({}, ...configs, { headers: Object.fromEntries(configs.flatMap((config) => [...new Headers(config?.headers)])) });
11
13
  }
12
14
  resolveURL(url, config, isWebSocket = false) {
13
15
  try {
16
+ @@ -281,7 +283,11 @@ var Http = class _Http extends Service {
17
+ }
18
+ const response = await this.ctx.waterfall(this, "http/fetch", url, init, config, () => {
19
+ this.ctx.logger("http:request").debug("%C %s", method, url.href);
20
+ - return this.undici.fetch(url, init);
21
+ + // The undici package serializes only its own FormData and would send the global one as "[object FormData]".
22
+ + if (!(init.body instanceof FormData) || init.body instanceof this.undici.FormData) return this.undici.fetch(url, init);
23
+ + const form = new this.undici.FormData();
24
+ + for (const [name, value] of init.body) form.append(name, value);
25
+ + return this.undici.fetch(url, { ...init, body: form });
26
+ }).catch((cause) => {
27
+ this.ctx.logger("http:request").debug("%C %s failed: %o", method, url.href, cause);
28
+ if (_Http.Error.is(cause)) throw cause;
@@ -78,7 +78,7 @@ index 120885c..d5ba237 100644
78
78
  'onebot/message-reactions-updated'(session: Session): void;
79
79
  'onebot/channel-updated'(session: Session): void;
80
80
  diff --git a/lib/index.js b/lib/index.js
81
- index 996a9c8..5b58e18 100644
81
+ index 996a9c8..cf1e9bd 100644
82
82
  --- a/lib/index.js
83
83
  +++ b/lib/index.js
84
84
  @@ -46,10 +46,10 @@ __export(index_exports, {
@@ -108,7 +108,15 @@ index 996a9c8..5b58e18 100644
108
108
  var SafetyLevel = /* @__PURE__ */ ((SafetyLevel2) => {
109
109
  SafetyLevel2[SafetyLevel2["safe"] = 0] = "safe";
110
110
  SafetyLevel2[SafetyLevel2["unknown"] = 1] = "unknown";
111
- @@ -594,7 +594,7 @@ var HttpServer = class extends import_koishi3.Adapter {
111
+ @@ -466,6 +466,7 @@ async function adaptSession(bot, data) {
112
+ session.type = "message-deleted";
113
+ session.subtype = "private";
114
+ session.channelId = `private:${session.userId}`;
115
+ + session.isDirect = true;
116
+ break;
117
+ // from go-cqhttp source code, but not mentioned in official docs
118
+ case "guild_channel_recall":
119
+ @@ -594,7 +595,7 @@ var HttpServer = class extends import_koishi3.Adapter {
112
120
  })(HttpServer || (HttpServer = {}));
113
121
 
114
122
  // src/ws.ts
@@ -117,7 +125,7 @@ index 996a9c8..5b58e18 100644
117
125
  var WsClient = class extends import_koishi4.Adapter.WsClient {
118
126
  static {
119
127
  __name(this, "WsClient");
120
- @@ -734,10 +734,10 @@ function accept(socket, bot) {
128
+ @@ -734,10 +735,10 @@ function accept(socket, bot) {
121
129
  __name(accept, "accept");
122
130
 
123
131
  // src/bot/base.ts
@@ -130,7 +138,7 @@ index 996a9c8..5b58e18 100644
130
138
  var import_node_url = require("node:url");
131
139
  var State = class {
132
140
  constructor(type) {
133
- @@ -830,7 +830,7 @@ var OneBotMessageEncoder = class extends import_koishi5.MessageEncoder {
141
+ @@ -830,7 +831,7 @@ var OneBotMessageEncoder = class extends import_koishi5.MessageEncoder {
134
142
  }
135
143
  async sendFile(attrs) {
136
144
  const src = attrs.src || attrs.url;
@@ -139,7 +147,7 @@ index 996a9c8..5b58e18 100644
139
147
  const file = src.startsWith("file:") ? (0, import_node_url.fileURLToPath)(src) : await this.bot.internal.downloadFile(src);
140
148
  if (this.session.event.channel.type === import_koishi5.Universal.Channel.Type.DIRECT) {
141
149
  await this.bot.internal.uploadPrivateFile(
142
- @@ -977,7 +977,7 @@ var BaseBot2 = class extends import_koishi6.Bot {
150
+ @@ -977,7 +978,7 @@ var BaseBot2 = class extends import_koishi6.Bot {
143
151
  __name(this, "BaseBot");
144
152
  }
145
153
  static MessageEncoder = OneBotMessageEncoder;
@@ -148,7 +156,7 @@ index 996a9c8..5b58e18 100644
148
156
  parent;
149
157
  internal;
150
158
  async createDirectChannel(userId) {
151
- @@ -1112,7 +1112,7 @@ var QQGuildBot = class extends BaseBot2 {
159
+ @@ -1112,7 +1113,7 @@ var QQGuildBot = class extends BaseBot2 {
152
160
  };
153
161
 
154
162
  // src/bot/cqcode.ts
@@ -1,97 +0,0 @@
1
- diff --git a/lib/worker/index.d.ts b/lib/worker/index.d.ts
2
- index 4362cf8..ae92999 100644
3
- --- a/lib/worker/index.d.ts
4
- +++ b/lib/worker/index.d.ts
5
- @@ -4,6 +4,10 @@ export interface Config {
6
- baseUrl?: string;
7
- execArgv?: string[];
8
- path: string;
9
- + /** Fixed id for the root include entry; defaults to 'chatluna' (keeps tree ids stable). */
10
- + includeId?: string;
11
- + /** Override/extend the root include config (e.g. inject `patches` to enable a group). */
12
- + include?: Record<string, unknown>;
13
- daemon: daemon.Config;
14
- prelude?: EntryOptions[];
15
- }
16
- diff --git a/lib/worker/index.js b/lib/worker/index.js
17
- index 91ff829..9c9b5ef 100644
18
- --- a/lib/worker/index.js
19
- +++ b/lib/worker/index.js
20
- @@ -17,20 +17,39 @@ __export(daemon_exports, {
21
- });
22
- var name = "daemon";
23
- function* apply(ctx, config = {}) {
24
- + // Bounded: a stuck `exit` listener must not keep a signalled or orphaned worker alive.
25
- + function exit(signal) {
26
- + setTimeout(() => process.exit(1), 1e4).unref();
27
- + ctx.parallel("exit", signal).finally(() => process.exit());
28
- + }
29
- + __name(exit, "exit");
30
- function handleSignal(signal) {
31
- process.stderr.write("\x1B[2K\r");
32
- if (config.autoRestart) {
33
- process.send({ type: "exit" });
34
- }
35
- ctx.logger.info(`terminated by ${signal}`);
36
- - ctx.parallel("exit", signal).finally(() => process.exit());
37
- + exit(signal);
38
- }
39
- __name(handleSignal, "handleSignal");
40
- process.on("SIGINT", handleSignal);
41
- yield () => process.off("SIGINT", handleSignal);
42
- process.on("SIGTERM", handleSignal);
43
- yield () => process.off("SIGTERM", handleSignal);
44
- + // The parent owns this worker: once its IPC channel closes, nothing pings, restarts or stops it.
45
- + const onDisconnect = /* @__PURE__ */ __name(() => {
46
- + ctx.logger.info("terminated by parent disconnect");
47
- + exit("SIGTERM");
48
- + }, "onDisconnect");
49
- + process.on("disconnect", onDisconnect);
50
- + yield () => process.off("disconnect", onDisconnect);
51
- process.send({ type: "start", body: config });
52
- + // Health over IPC: the supervisor pings, the worker answers; no network address involved.
53
- + const onMessage = /* @__PURE__ */ __name((message) => {
54
- + if (message?.type === "ping") process.send({ type: "pong", id: message.id });
55
- + }, "onMessage");
56
- + process.on("message", onMessage);
57
- + yield () => process.off("message", onMessage);
58
- if (config.heartbeatInterval) {
59
- const timer = setInterval(() => {
60
- process.send({ type: "heartbeat" });
61
- @@ -43,6 +62,12 @@ __name(apply, "apply");
62
- // src/worker/index.ts
63
- async function start(config) {
64
- const ctx = new Context();
65
- + // Output is best-effort. Without a listener, a write to a closed stdout/stderr pipe becomes an
66
- + // uncaughtException, which is logged to the same pipe and fails again, forever.
67
- + const ignore = /* @__PURE__ */ __name(() => {
68
- + }, "ignore");
69
- + process.stdout.on("error", ignore);
70
- + process.stderr.on("error", ignore);
71
- process.on("uncaughtException", (error) => {
72
- ctx.logger.error(error);
73
- process.exitCode = 1;
74
- @@ -59,12 +84,22 @@ async function start(config) {
75
- await ctx.loader.create(plugin);
76
- }
77
- await ctx.loader.create({
78
- + // Fixed id so tree-side entries keep stable ids (chatluna:<id>) across restarts.
79
- + id: config.includeId ?? "chatluna",
80
- name: "@cordisjs/plugin-include",
81
- config: {
82
- + // `include` lets the launcher override the include config wholesale (e.g.
83
- + // `chatluna dev` injects a `patches` entry to enable the dev group).
84
- path: config.path,
85
- - enableLogs: true
86
- + enableLogs: true,
87
- + ...config.include
88
- }
89
- });
90
- + // Ready once every entry has finished loading (failed plugins included; they are logged).
91
- + if (config.daemon.enabled) {
92
- + await ctx.loader.await();
93
- + process.send({ type: "ready" });
94
- + }
95
- }
96
- __name(start, "start");
97
- export {