@noego/wood 0.0.1 → 0.0.4
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/bin/wood.js +1 -0
- package/dist/bridge/backend_entry.cjs +23 -4
- package/dist/bridge/backend_entry.cjs.map +1 -1
- package/dist/bridge/backend_entry.d.cts +8 -2
- package/dist/bridge/backend_entry.d.ts +8 -2
- package/dist/bridge/backend_entry.js +22 -4
- package/dist/bridge/backend_entry.js.map +1 -1
- package/dist/bridge/buffered_ipc_sender.cjs +120 -0
- package/dist/bridge/buffered_ipc_sender.cjs.map +1 -0
- package/dist/bridge/buffered_ipc_sender.d.cts +49 -0
- package/dist/bridge/buffered_ipc_sender.d.ts +49 -0
- package/dist/bridge/buffered_ipc_sender.js +95 -0
- package/dist/bridge/buffered_ipc_sender.js.map +1 -0
- package/dist/client/controller_contract.cjs.map +1 -1
- package/dist/client/controller_contract.d.cts +3 -5
- package/dist/client/controller_contract.d.ts +3 -5
- package/dist/client/index.cjs +18 -20
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +1 -2
- package/dist/client/index.d.ts +1 -2
- package/dist/client/index.js +18 -19
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/preload_generator.cjs +10 -4
- package/dist/codegen/preload_generator.cjs.map +1 -1
- package/dist/codegen/preload_generator.js +10 -4
- package/dist/codegen/preload_generator.js.map +1 -1
- package/dist/main/index.cjs +9 -0
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.d.cts +4 -0
- package/dist/main/index.d.ts +4 -0
- package/dist/main/index.js +9 -0
- package/dist/main/index.js.map +1 -1
- package/dist/router/wood_router.cjs +1 -1
- package/dist/router/wood_router.cjs.map +1 -1
- package/dist/router/wood_router.d.cts +1 -1
- package/dist/router/wood_router.d.ts +1 -1
- package/dist/router/wood_router.js +1 -1
- package/dist/router/wood_router.js.map +1 -1
- package/dist/runtime/runtime.cjs +35 -24
- package/dist/runtime/runtime.cjs.map +1 -1
- package/dist/runtime/runtime.d.cts +5 -0
- package/dist/runtime/runtime.d.ts +5 -0
- package/dist/runtime/runtime.js +35 -24
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/tracing/index.cjs +6 -2
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.cts +1 -1
- package/dist/tracing/index.d.ts +1 -1
- package/dist/tracing/index.js +5 -1
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/trace_hub.cjs +37 -8
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +3 -1
- package/dist/tracing/trace_hub.d.ts +3 -1
- package/dist/tracing/trace_hub.js +34 -7
- package/dist/tracing/trace_hub.js.map +1 -1
- package/dist/tracing/trace_provider.cjs +12 -0
- package/dist/tracing/trace_provider.cjs.map +1 -1
- package/dist/tracing/trace_provider.d.cts +4 -1
- package/dist/tracing/trace_provider.d.ts +4 -1
- package/dist/tracing/trace_provider.js +15 -1
- package/dist/tracing/trace_provider.js.map +1 -1
- package/package.json +1 -1
- package/src/components/WoodRecursiveRender.svelte +6 -6
- package/src/stick/WoodRecursiveRender.svelte +4 -4
- package/dist/client/wood_controller.svelte.cjs +0 -110
- package/dist/client/wood_controller.svelte.cjs.map +0 -1
- package/dist/client/wood_controller.svelte.d.cts +0 -30
- package/dist/client/wood_controller.svelte.d.ts +0 -30
- package/dist/client/wood_controller.svelte.js +0 -86
- package/dist/client/wood_controller.svelte.js.map +0 -1
package/bin/wood.js
CHANGED
|
@@ -189,6 +189,7 @@ function generateWindowConfigSnippet(rawWindows) {
|
|
|
189
189
|
backgroundColor?: string;
|
|
190
190
|
rememberBounds?: boolean;
|
|
191
191
|
contextMenu?: 'native' | 'custom';
|
|
192
|
+
acceptFirstMouse?: boolean;
|
|
192
193
|
};
|
|
193
194
|
|
|
194
195
|
export const WINDOW_DEFS = ${serializedDefs} as Record<string, WoodWindowConfig>;
|
|
@@ -19,23 +19,34 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var backend_entry_exports = {};
|
|
20
20
|
__export(backend_entry_exports, {
|
|
21
21
|
pushEvent: () => pushEvent,
|
|
22
|
+
pushObservational: () => pushObservational,
|
|
22
23
|
startBackendLoop: () => startBackendLoop
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(backend_entry_exports);
|
|
26
|
+
var import_buffered_ipc_sender = require("./buffered_ipc_sender.js");
|
|
27
|
+
let sender = null;
|
|
28
|
+
function getSender() {
|
|
29
|
+
if (!sender) {
|
|
30
|
+
sender = new import_buffered_ipc_sender.PriorityIpcSender(
|
|
31
|
+
(message, callback) => process.send(message, callback)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return sender;
|
|
35
|
+
}
|
|
25
36
|
function startBackendLoop(handler) {
|
|
26
37
|
process.on("message", async (msg) => {
|
|
27
38
|
const message = msg;
|
|
28
39
|
if (message.type === "request") {
|
|
29
40
|
try {
|
|
30
41
|
const result = await handler.dispatch(message.channel, message.data);
|
|
31
|
-
|
|
42
|
+
getSender().sendData({
|
|
32
43
|
type: "response",
|
|
33
44
|
id: message.id,
|
|
34
45
|
result
|
|
35
46
|
});
|
|
36
47
|
} catch (err) {
|
|
37
48
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
38
|
-
|
|
49
|
+
getSender().sendData({
|
|
39
50
|
type: "response",
|
|
40
51
|
id: message.id,
|
|
41
52
|
error: {
|
|
@@ -47,10 +58,17 @@ function startBackendLoop(handler) {
|
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
60
|
});
|
|
50
|
-
|
|
61
|
+
getSender().sendData({ type: "ready" });
|
|
51
62
|
}
|
|
52
63
|
function pushEvent(channel, data) {
|
|
53
|
-
|
|
64
|
+
getSender().sendData({
|
|
65
|
+
type: "push",
|
|
66
|
+
channel,
|
|
67
|
+
data
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function pushObservational(channel, data) {
|
|
71
|
+
getSender().sendObservational({
|
|
54
72
|
type: "push",
|
|
55
73
|
channel,
|
|
56
74
|
data
|
|
@@ -59,6 +77,7 @@ function pushEvent(channel, data) {
|
|
|
59
77
|
// Annotate the CommonJS export names for ESM import in node:
|
|
60
78
|
0 && (module.exports = {
|
|
61
79
|
pushEvent,
|
|
80
|
+
pushObservational,
|
|
62
81
|
startBackendLoop
|
|
63
82
|
});
|
|
64
83
|
//# sourceMappingURL=backend_entry.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/backend_entry.ts"],"sourcesContent":["import type { BridgeRequest, BridgePush, BridgeResponse, BridgeReady } from '../types/bridge.cjs';\n\nexport interface BackendHandler {\n dispatch(channel: string, data: unknown): Promise<unknown>;\n}\n\n/**\n * Start the backend message loop.\n * Called from the backend entry point after initialization.\n */\nexport function startBackendLoop(handler: BackendHandler): void {\n process.on('message', async (msg: unknown) => {\n const message = msg as BridgeRequest;\n\n if (message.type === 'request') {\n try {\n const result = await handler.dispatch(message.channel, message.data);\n
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/backend_entry.ts"],"sourcesContent":["import type { BridgeRequest, BridgePush, BridgeResponse, BridgeReady } from '../types/bridge.cjs';\nimport { PriorityIpcSender } from './buffered_ipc_sender.js';\n\nexport interface BackendHandler {\n dispatch(channel: string, data: unknown): Promise<unknown>;\n}\n\nlet sender: PriorityIpcSender | null = null;\n\nfunction getSender(): PriorityIpcSender {\n if (!sender) {\n sender = new PriorityIpcSender(\n (message, callback) => process.send!(message, callback),\n );\n }\n return sender;\n}\n\n/**\n * Start the backend message loop.\n * Called from the backend entry point after initialization.\n */\nexport function startBackendLoop(handler: BackendHandler): void {\n process.on('message', async (msg: unknown) => {\n const message = msg as BridgeRequest;\n\n if (message.type === 'request') {\n try {\n const result = await handler.dispatch(message.channel, message.data);\n getSender().sendData({\n type: 'response',\n id: message.id,\n result,\n } satisfies BridgeResponse);\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n getSender().sendData({\n type: 'response',\n id: message.id,\n error: {\n message: error.message,\n name: error.name,\n stack: error.stack,\n },\n } satisfies BridgeResponse);\n }\n }\n });\n\n // Signal ready to the shell process\n getSender().sendData({ type: 'ready' } satisfies BridgeReady);\n}\n\n/**\n * Push a data-path event to the shell (forwarded to all renderers).\n * These have priority over observational messages.\n */\nexport function pushEvent(channel: string, data: unknown): void {\n getSender().sendData({\n type: 'push',\n channel,\n data,\n } satisfies BridgePush);\n}\n\n/**\n * Push an observational event to the shell (traces, logs).\n * These yield to data-path messages when the pipe is contended.\n */\nexport function pushObservational(channel: string, data: unknown): void {\n getSender().sendObservational({\n type: 'push',\n channel,\n data,\n } satisfies BridgePush);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,iCAAkC;AAMlC,IAAI,SAAmC;AAEvC,SAAS,YAA+B;AACtC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI;AAAA,MACX,CAAC,SAAS,aAAa,QAAQ,KAAM,SAAS,QAAQ;AAAA,IACxD;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,iBAAiB,SAA+B;AAC9D,UAAQ,GAAG,WAAW,OAAO,QAAiB;AAC5C,UAAM,UAAU;AAEhB,QAAI,QAAQ,SAAS,WAAW;AAC9B,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ,SAAS,QAAQ,IAAI;AACnE,kBAAU,EAAE,SAAS;AAAA,UACnB,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ;AAAA,QACF,CAA0B;AAAA,MAC5B,SAAS,KAAc;AACrB,cAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,kBAAU,EAAE,SAAS;AAAA,UACnB,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ,OAAO;AAAA,YACL,SAAS,MAAM;AAAA,YACf,MAAM,MAAM;AAAA,YACZ,OAAO,MAAM;AAAA,UACf;AAAA,QACF,CAA0B;AAAA,MAC5B;AAAA,IACF;AAAA,EACF,CAAC;AAGD,YAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAuB;AAC9D;AAMO,SAAS,UAAU,SAAiB,MAAqB;AAC9D,YAAU,EAAE,SAAS;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,CAAsB;AACxB;AAMO,SAAS,kBAAkB,SAAiB,MAAqB;AACtE,YAAU,EAAE,kBAAkB;AAAA,IAC5B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,CAAsB;AACxB;","names":[]}
|
|
@@ -7,8 +7,14 @@ interface BackendHandler {
|
|
|
7
7
|
*/
|
|
8
8
|
declare function startBackendLoop(handler: BackendHandler): void;
|
|
9
9
|
/**
|
|
10
|
-
* Push
|
|
10
|
+
* Push a data-path event to the shell (forwarded to all renderers).
|
|
11
|
+
* These have priority over observational messages.
|
|
11
12
|
*/
|
|
12
13
|
declare function pushEvent(channel: string, data: unknown): void;
|
|
14
|
+
/**
|
|
15
|
+
* Push an observational event to the shell (traces, logs).
|
|
16
|
+
* These yield to data-path messages when the pipe is contended.
|
|
17
|
+
*/
|
|
18
|
+
declare function pushObservational(channel: string, data: unknown): void;
|
|
13
19
|
|
|
14
|
-
export { type BackendHandler, pushEvent, startBackendLoop };
|
|
20
|
+
export { type BackendHandler, pushEvent, pushObservational, startBackendLoop };
|
|
@@ -7,8 +7,14 @@ interface BackendHandler {
|
|
|
7
7
|
*/
|
|
8
8
|
declare function startBackendLoop(handler: BackendHandler): void;
|
|
9
9
|
/**
|
|
10
|
-
* Push
|
|
10
|
+
* Push a data-path event to the shell (forwarded to all renderers).
|
|
11
|
+
* These have priority over observational messages.
|
|
11
12
|
*/
|
|
12
13
|
declare function pushEvent(channel: string, data: unknown): void;
|
|
14
|
+
/**
|
|
15
|
+
* Push an observational event to the shell (traces, logs).
|
|
16
|
+
* These yield to data-path messages when the pipe is contended.
|
|
17
|
+
*/
|
|
18
|
+
declare function pushObservational(channel: string, data: unknown): void;
|
|
13
19
|
|
|
14
|
-
export { type BackendHandler, pushEvent, startBackendLoop };
|
|
20
|
+
export { type BackendHandler, pushEvent, pushObservational, startBackendLoop };
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
import { PriorityIpcSender } from "./buffered_ipc_sender.js";
|
|
2
|
+
let sender = null;
|
|
3
|
+
function getSender() {
|
|
4
|
+
if (!sender) {
|
|
5
|
+
sender = new PriorityIpcSender(
|
|
6
|
+
(message, callback) => process.send(message, callback)
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
return sender;
|
|
10
|
+
}
|
|
1
11
|
function startBackendLoop(handler) {
|
|
2
12
|
process.on("message", async (msg) => {
|
|
3
13
|
const message = msg;
|
|
4
14
|
if (message.type === "request") {
|
|
5
15
|
try {
|
|
6
16
|
const result = await handler.dispatch(message.channel, message.data);
|
|
7
|
-
|
|
17
|
+
getSender().sendData({
|
|
8
18
|
type: "response",
|
|
9
19
|
id: message.id,
|
|
10
20
|
result
|
|
11
21
|
});
|
|
12
22
|
} catch (err) {
|
|
13
23
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
14
|
-
|
|
24
|
+
getSender().sendData({
|
|
15
25
|
type: "response",
|
|
16
26
|
id: message.id,
|
|
17
27
|
error: {
|
|
@@ -23,10 +33,17 @@ function startBackendLoop(handler) {
|
|
|
23
33
|
}
|
|
24
34
|
}
|
|
25
35
|
});
|
|
26
|
-
|
|
36
|
+
getSender().sendData({ type: "ready" });
|
|
27
37
|
}
|
|
28
38
|
function pushEvent(channel, data) {
|
|
29
|
-
|
|
39
|
+
getSender().sendData({
|
|
40
|
+
type: "push",
|
|
41
|
+
channel,
|
|
42
|
+
data
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function pushObservational(channel, data) {
|
|
46
|
+
getSender().sendObservational({
|
|
30
47
|
type: "push",
|
|
31
48
|
channel,
|
|
32
49
|
data
|
|
@@ -34,6 +51,7 @@ function pushEvent(channel, data) {
|
|
|
34
51
|
}
|
|
35
52
|
export {
|
|
36
53
|
pushEvent,
|
|
54
|
+
pushObservational,
|
|
37
55
|
startBackendLoop
|
|
38
56
|
};
|
|
39
57
|
//# sourceMappingURL=backend_entry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/backend_entry.ts"],"sourcesContent":["import type { BridgeRequest, BridgePush, BridgeResponse, BridgeReady } from '../types/bridge.js';\n\nexport interface BackendHandler {\n dispatch(channel: string, data: unknown): Promise<unknown>;\n}\n\n/**\n * Start the backend message loop.\n * Called from the backend entry point after initialization.\n */\nexport function startBackendLoop(handler: BackendHandler): void {\n process.on('message', async (msg: unknown) => {\n const message = msg as BridgeRequest;\n\n if (message.type === 'request') {\n try {\n const result = await handler.dispatch(message.channel, message.data);\n
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/backend_entry.ts"],"sourcesContent":["import type { BridgeRequest, BridgePush, BridgeResponse, BridgeReady } from '../types/bridge.js';\nimport { PriorityIpcSender } from './buffered_ipc_sender.js';\n\nexport interface BackendHandler {\n dispatch(channel: string, data: unknown): Promise<unknown>;\n}\n\nlet sender: PriorityIpcSender | null = null;\n\nfunction getSender(): PriorityIpcSender {\n if (!sender) {\n sender = new PriorityIpcSender(\n (message, callback) => process.send!(message, callback),\n );\n }\n return sender;\n}\n\n/**\n * Start the backend message loop.\n * Called from the backend entry point after initialization.\n */\nexport function startBackendLoop(handler: BackendHandler): void {\n process.on('message', async (msg: unknown) => {\n const message = msg as BridgeRequest;\n\n if (message.type === 'request') {\n try {\n const result = await handler.dispatch(message.channel, message.data);\n getSender().sendData({\n type: 'response',\n id: message.id,\n result,\n } satisfies BridgeResponse);\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n getSender().sendData({\n type: 'response',\n id: message.id,\n error: {\n message: error.message,\n name: error.name,\n stack: error.stack,\n },\n } satisfies BridgeResponse);\n }\n }\n });\n\n // Signal ready to the shell process\n getSender().sendData({ type: 'ready' } satisfies BridgeReady);\n}\n\n/**\n * Push a data-path event to the shell (forwarded to all renderers).\n * These have priority over observational messages.\n */\nexport function pushEvent(channel: string, data: unknown): void {\n getSender().sendData({\n type: 'push',\n channel,\n data,\n } satisfies BridgePush);\n}\n\n/**\n * Push an observational event to the shell (traces, logs).\n * These yield to data-path messages when the pipe is contended.\n */\nexport function pushObservational(channel: string, data: unknown): void {\n getSender().sendObservational({\n type: 'push',\n channel,\n data,\n } satisfies BridgePush);\n}\n"],"mappings":"AACA,SAAS,yBAAyB;AAMlC,IAAI,SAAmC;AAEvC,SAAS,YAA+B;AACtC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI;AAAA,MACX,CAAC,SAAS,aAAa,QAAQ,KAAM,SAAS,QAAQ;AAAA,IACxD;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,iBAAiB,SAA+B;AAC9D,UAAQ,GAAG,WAAW,OAAO,QAAiB;AAC5C,UAAM,UAAU;AAEhB,QAAI,QAAQ,SAAS,WAAW;AAC9B,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ,SAAS,QAAQ,IAAI;AACnE,kBAAU,EAAE,SAAS;AAAA,UACnB,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ;AAAA,QACF,CAA0B;AAAA,MAC5B,SAAS,KAAc;AACrB,cAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,kBAAU,EAAE,SAAS;AAAA,UACnB,MAAM;AAAA,UACN,IAAI,QAAQ;AAAA,UACZ,OAAO;AAAA,YACL,SAAS,MAAM;AAAA,YACf,MAAM,MAAM;AAAA,YACZ,OAAO,MAAM;AAAA,UACf;AAAA,QACF,CAA0B;AAAA,MAC5B;AAAA,IACF;AAAA,EACF,CAAC;AAGD,YAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAuB;AAC9D;AAMO,SAAS,UAAU,SAAiB,MAAqB;AAC9D,YAAU,EAAE,SAAS;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,CAAsB;AACxB;AAMO,SAAS,kBAAkB,SAAiB,MAAqB;AACtE,YAAU,EAAE,kBAAkB;AAAA,IAC5B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,CAAsB;AACxB;","names":[]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var buffered_ipc_sender_exports = {};
|
|
20
|
+
__export(buffered_ipc_sender_exports, {
|
|
21
|
+
BufferedIpcSender: () => BufferedIpcSender,
|
|
22
|
+
PriorityIpcSender: () => PriorityIpcSender
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(buffered_ipc_sender_exports);
|
|
25
|
+
var import_rxjs = require("rxjs");
|
|
26
|
+
var import_operators = require("rxjs/operators");
|
|
27
|
+
class BufferedIpcSender {
|
|
28
|
+
constructor(sendFn, options) {
|
|
29
|
+
this.queue$ = new import_rxjs.Subject();
|
|
30
|
+
this.onSendError = options?.onError;
|
|
31
|
+
this.subscription = this.queue$.pipe((0, import_operators.concatMap)((message) => this.writeOne(sendFn, message))).subscribe();
|
|
32
|
+
}
|
|
33
|
+
send(message) {
|
|
34
|
+
this.queue$.next(message);
|
|
35
|
+
}
|
|
36
|
+
stop() {
|
|
37
|
+
this.queue$.complete();
|
|
38
|
+
this.subscription.unsubscribe();
|
|
39
|
+
}
|
|
40
|
+
writeOne(sendFn, message) {
|
|
41
|
+
return new import_rxjs.Observable((subscriber) => {
|
|
42
|
+
try {
|
|
43
|
+
sendFn(message, (error) => {
|
|
44
|
+
if (error) {
|
|
45
|
+
this.onSendError?.(error, message);
|
|
46
|
+
}
|
|
47
|
+
subscriber.next();
|
|
48
|
+
subscriber.complete();
|
|
49
|
+
});
|
|
50
|
+
} catch (err) {
|
|
51
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
52
|
+
this.onSendError?.(error, message);
|
|
53
|
+
subscriber.next();
|
|
54
|
+
subscriber.complete();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function writeOneMessage(sendFn, message, onError) {
|
|
60
|
+
return new import_rxjs.Observable((subscriber) => {
|
|
61
|
+
try {
|
|
62
|
+
sendFn(message, (error) => {
|
|
63
|
+
if (error) {
|
|
64
|
+
onError?.(error, message);
|
|
65
|
+
}
|
|
66
|
+
subscriber.next();
|
|
67
|
+
subscriber.complete();
|
|
68
|
+
});
|
|
69
|
+
} catch (err) {
|
|
70
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
71
|
+
onError?.(error, message);
|
|
72
|
+
subscriber.next();
|
|
73
|
+
subscriber.complete();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
class PriorityIpcSender {
|
|
78
|
+
constructor(sendFn, options) {
|
|
79
|
+
this.dataQueue = [];
|
|
80
|
+
this.obsQueue = [];
|
|
81
|
+
this.draining = false;
|
|
82
|
+
this.drain$ = new import_rxjs.Subject();
|
|
83
|
+
this.onSendError = options?.onError;
|
|
84
|
+
this.subscription = this.drain$.pipe(
|
|
85
|
+
(0, import_operators.concatMap)(() => {
|
|
86
|
+
const msg = this.dataQueue.shift() ?? this.obsQueue.shift();
|
|
87
|
+
if (!msg) {
|
|
88
|
+
this.draining = false;
|
|
89
|
+
return import_rxjs.EMPTY;
|
|
90
|
+
}
|
|
91
|
+
return writeOneMessage(sendFn, msg, this.onSendError).pipe(
|
|
92
|
+
(0, import_operators.finalize)(() => this.tryScheduleDrain())
|
|
93
|
+
);
|
|
94
|
+
})
|
|
95
|
+
).subscribe();
|
|
96
|
+
}
|
|
97
|
+
sendData(message) {
|
|
98
|
+
this.dataQueue.push(message);
|
|
99
|
+
this.tryScheduleDrain();
|
|
100
|
+
}
|
|
101
|
+
sendObservational(message) {
|
|
102
|
+
this.obsQueue.push(message);
|
|
103
|
+
this.tryScheduleDrain();
|
|
104
|
+
}
|
|
105
|
+
stop() {
|
|
106
|
+
this.drain$.complete();
|
|
107
|
+
this.subscription.unsubscribe();
|
|
108
|
+
}
|
|
109
|
+
tryScheduleDrain() {
|
|
110
|
+
if (this.draining) return;
|
|
111
|
+
this.draining = true;
|
|
112
|
+
this.drain$.next();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
116
|
+
0 && (module.exports = {
|
|
117
|
+
BufferedIpcSender,
|
|
118
|
+
PriorityIpcSender
|
|
119
|
+
});
|
|
120
|
+
//# sourceMappingURL=buffered_ipc_sender.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/buffered_ipc_sender.ts"],"sourcesContent":["import { Subject, Subscription, Observable, EMPTY } from 'rxjs';\nimport { concatMap, finalize } from 'rxjs/operators';\n\nexport type IpcSendFn = (\n message: unknown,\n callback: (error: Error | null) => void,\n) => void;\n\nexport interface BufferedIpcSenderOptions {\n onError?: (error: Error, message: unknown) => void;\n}\n\n/**\n * Serializes IPC writes through an RxJS pipeline to prevent ENOBUFS.\n *\n * Without backpressure, rapid `process.send()` calls can overflow the\n * kernel socket buffer. BufferedIpcSender queues messages in the JS\n * heap and drains them one at a time, waiting for each write callback\n * before pulling the next message.\n */\nexport class BufferedIpcSender {\n private readonly queue$ = new Subject<unknown>();\n private readonly subscription: Subscription;\n private readonly onSendError: ((error: Error, message: unknown) => void) | undefined;\n\n constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions) {\n this.onSendError = options?.onError;\n\n this.subscription = this.queue$\n .pipe(concatMap((message) => this.writeOne(sendFn, message)))\n .subscribe();\n }\n\n send(message: unknown): void {\n this.queue$.next(message);\n }\n\n stop(): void {\n this.queue$.complete();\n this.subscription.unsubscribe();\n }\n\n private writeOne(sendFn: IpcSendFn, message: unknown): Observable<void> {\n return new Observable<void>((subscriber) => {\n try {\n sendFn(message, (error) => {\n if (error) {\n this.onSendError?.(error, message);\n }\n subscriber.next();\n subscriber.complete();\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.onSendError?.(error, message);\n subscriber.next();\n subscriber.complete();\n }\n });\n }\n}\n\nfunction writeOneMessage(\n sendFn: IpcSendFn,\n message: unknown,\n onError?: (error: Error, message: unknown) => void,\n): Observable<void> {\n return new Observable<void>((subscriber) => {\n try {\n sendFn(message, (error) => {\n if (error) {\n onError?.(error, message);\n }\n subscriber.next();\n subscriber.complete();\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, message);\n subscriber.next();\n subscriber.complete();\n }\n });\n}\n\n/**\n * Two-queue IPC sender with priority interleaving.\n *\n * Data-path messages (RPC responses, push events) always drain before\n * observational messages (traces, logs). Both queues share a single\n * `process.send()` call with backpressure — at most one message is in\n * flight at a time.\n *\n * The drain loop checks the data queue first on every iteration. If a\n * data message arrives while observational messages are draining, the\n * data message is picked up on the very next write cycle (latency ≈\n * one `process.send()` callback, typically microseconds).\n */\nexport class PriorityIpcSender {\n private readonly dataQueue: unknown[] = [];\n private readonly obsQueue: unknown[] = [];\n private draining = false;\n private readonly drain$ = new Subject<void>();\n private readonly subscription: Subscription;\n private readonly onSendError: ((error: Error, message: unknown) => void) | undefined;\n\n constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions) {\n this.onSendError = options?.onError;\n\n this.subscription = this.drain$\n .pipe(\n concatMap(() => {\n const msg = this.dataQueue.shift() ?? this.obsQueue.shift();\n if (!msg) {\n this.draining = false;\n return EMPTY;\n }\n return writeOneMessage(sendFn, msg, this.onSendError).pipe(\n finalize(() => this.tryScheduleDrain()),\n );\n }),\n )\n .subscribe();\n }\n\n sendData(message: unknown): void {\n this.dataQueue.push(message);\n this.tryScheduleDrain();\n }\n\n sendObservational(message: unknown): void {\n this.obsQueue.push(message);\n this.tryScheduleDrain();\n }\n\n stop(): void {\n this.drain$.complete();\n this.subscription.unsubscribe();\n }\n\n private tryScheduleDrain(): void {\n if (this.draining) return;\n this.draining = true;\n this.drain$.next();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAyD;AACzD,uBAAoC;AAmB7B,MAAM,kBAAkB;AAAA,EAK7B,YAAY,QAAmB,SAAoC;AAJnE,SAAiB,SAAS,IAAI,oBAAiB;AAK7C,SAAK,cAAc,SAAS;AAE5B,SAAK,eAAe,KAAK,OACtB,SAAK,4BAAU,CAAC,YAAY,KAAK,SAAS,QAAQ,OAAO,CAAC,CAAC,EAC3D,UAAU;AAAA,EACf;AAAA,EAEA,KAAK,SAAwB;AAC3B,SAAK,OAAO,KAAK,OAAO;AAAA,EAC1B;AAAA,EAEA,OAAa;AACX,SAAK,OAAO,SAAS;AACrB,SAAK,aAAa,YAAY;AAAA,EAChC;AAAA,EAEQ,SAAS,QAAmB,SAAoC;AACtE,WAAO,IAAI,uBAAiB,CAAC,eAAe;AAC1C,UAAI;AACF,eAAO,SAAS,CAAC,UAAU;AACzB,cAAI,OAAO;AACT,iBAAK,cAAc,OAAO,OAAO;AAAA,UACnC;AACA,qBAAW,KAAK;AAChB,qBAAW,SAAS;AAAA,QACtB,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,aAAK,cAAc,OAAO,OAAO;AACjC,mBAAW,KAAK;AAChB,mBAAW,SAAS;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,gBACP,QACA,SACA,SACkB;AAClB,SAAO,IAAI,uBAAiB,CAAC,eAAe;AAC1C,QAAI;AACF,aAAO,SAAS,CAAC,UAAU;AACzB,YAAI,OAAO;AACT,oBAAU,OAAO,OAAO;AAAA,QAC1B;AACA,mBAAW,KAAK;AAChB,mBAAW,SAAS;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,gBAAU,OAAO,OAAO;AACxB,iBAAW,KAAK;AAChB,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF,CAAC;AACH;AAeO,MAAM,kBAAkB;AAAA,EAQ7B,YAAY,QAAmB,SAAoC;AAPnE,SAAiB,YAAuB,CAAC;AACzC,SAAiB,WAAsB,CAAC;AACxC,SAAQ,WAAW;AACnB,SAAiB,SAAS,IAAI,oBAAc;AAK1C,SAAK,cAAc,SAAS;AAE5B,SAAK,eAAe,KAAK,OACtB;AAAA,UACC,4BAAU,MAAM;AACd,cAAM,MAAM,KAAK,UAAU,MAAM,KAAK,KAAK,SAAS,MAAM;AAC1D,YAAI,CAAC,KAAK;AACR,eAAK,WAAW;AAChB,iBAAO;AAAA,QACT;AACA,eAAO,gBAAgB,QAAQ,KAAK,KAAK,WAAW,EAAE;AAAA,cACpD,2BAAS,MAAM,KAAK,iBAAiB,CAAC;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH,EACC,UAAU;AAAA,EACf;AAAA,EAEA,SAAS,SAAwB;AAC/B,SAAK,UAAU,KAAK,OAAO;AAC3B,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,kBAAkB,SAAwB;AACxC,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,OAAa;AACX,SAAK,OAAO,SAAS;AACrB,SAAK,aAAa,YAAY;AAAA,EAChC;AAAA,EAEQ,mBAAyB;AAC/B,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,SAAK,OAAO,KAAK;AAAA,EACnB;AACF;","names":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type IpcSendFn = (message: unknown, callback: (error: Error | null) => void) => void;
|
|
2
|
+
interface BufferedIpcSenderOptions {
|
|
3
|
+
onError?: (error: Error, message: unknown) => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Serializes IPC writes through an RxJS pipeline to prevent ENOBUFS.
|
|
7
|
+
*
|
|
8
|
+
* Without backpressure, rapid `process.send()` calls can overflow the
|
|
9
|
+
* kernel socket buffer. BufferedIpcSender queues messages in the JS
|
|
10
|
+
* heap and drains them one at a time, waiting for each write callback
|
|
11
|
+
* before pulling the next message.
|
|
12
|
+
*/
|
|
13
|
+
declare class BufferedIpcSender {
|
|
14
|
+
private readonly queue$;
|
|
15
|
+
private readonly subscription;
|
|
16
|
+
private readonly onSendError;
|
|
17
|
+
constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions);
|
|
18
|
+
send(message: unknown): void;
|
|
19
|
+
stop(): void;
|
|
20
|
+
private writeOne;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Two-queue IPC sender with priority interleaving.
|
|
24
|
+
*
|
|
25
|
+
* Data-path messages (RPC responses, push events) always drain before
|
|
26
|
+
* observational messages (traces, logs). Both queues share a single
|
|
27
|
+
* `process.send()` call with backpressure — at most one message is in
|
|
28
|
+
* flight at a time.
|
|
29
|
+
*
|
|
30
|
+
* The drain loop checks the data queue first on every iteration. If a
|
|
31
|
+
* data message arrives while observational messages are draining, the
|
|
32
|
+
* data message is picked up on the very next write cycle (latency ≈
|
|
33
|
+
* one `process.send()` callback, typically microseconds).
|
|
34
|
+
*/
|
|
35
|
+
declare class PriorityIpcSender {
|
|
36
|
+
private readonly dataQueue;
|
|
37
|
+
private readonly obsQueue;
|
|
38
|
+
private draining;
|
|
39
|
+
private readonly drain$;
|
|
40
|
+
private readonly subscription;
|
|
41
|
+
private readonly onSendError;
|
|
42
|
+
constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions);
|
|
43
|
+
sendData(message: unknown): void;
|
|
44
|
+
sendObservational(message: unknown): void;
|
|
45
|
+
stop(): void;
|
|
46
|
+
private tryScheduleDrain;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { BufferedIpcSender, type BufferedIpcSenderOptions, type IpcSendFn, PriorityIpcSender };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type IpcSendFn = (message: unknown, callback: (error: Error | null) => void) => void;
|
|
2
|
+
interface BufferedIpcSenderOptions {
|
|
3
|
+
onError?: (error: Error, message: unknown) => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Serializes IPC writes through an RxJS pipeline to prevent ENOBUFS.
|
|
7
|
+
*
|
|
8
|
+
* Without backpressure, rapid `process.send()` calls can overflow the
|
|
9
|
+
* kernel socket buffer. BufferedIpcSender queues messages in the JS
|
|
10
|
+
* heap and drains them one at a time, waiting for each write callback
|
|
11
|
+
* before pulling the next message.
|
|
12
|
+
*/
|
|
13
|
+
declare class BufferedIpcSender {
|
|
14
|
+
private readonly queue$;
|
|
15
|
+
private readonly subscription;
|
|
16
|
+
private readonly onSendError;
|
|
17
|
+
constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions);
|
|
18
|
+
send(message: unknown): void;
|
|
19
|
+
stop(): void;
|
|
20
|
+
private writeOne;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Two-queue IPC sender with priority interleaving.
|
|
24
|
+
*
|
|
25
|
+
* Data-path messages (RPC responses, push events) always drain before
|
|
26
|
+
* observational messages (traces, logs). Both queues share a single
|
|
27
|
+
* `process.send()` call with backpressure — at most one message is in
|
|
28
|
+
* flight at a time.
|
|
29
|
+
*
|
|
30
|
+
* The drain loop checks the data queue first on every iteration. If a
|
|
31
|
+
* data message arrives while observational messages are draining, the
|
|
32
|
+
* data message is picked up on the very next write cycle (latency ≈
|
|
33
|
+
* one `process.send()` callback, typically microseconds).
|
|
34
|
+
*/
|
|
35
|
+
declare class PriorityIpcSender {
|
|
36
|
+
private readonly dataQueue;
|
|
37
|
+
private readonly obsQueue;
|
|
38
|
+
private draining;
|
|
39
|
+
private readonly drain$;
|
|
40
|
+
private readonly subscription;
|
|
41
|
+
private readonly onSendError;
|
|
42
|
+
constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions);
|
|
43
|
+
sendData(message: unknown): void;
|
|
44
|
+
sendObservational(message: unknown): void;
|
|
45
|
+
stop(): void;
|
|
46
|
+
private tryScheduleDrain;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { BufferedIpcSender, type BufferedIpcSenderOptions, type IpcSendFn, PriorityIpcSender };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Subject, Observable, EMPTY } from "rxjs";
|
|
2
|
+
import { concatMap, finalize } from "rxjs/operators";
|
|
3
|
+
class BufferedIpcSender {
|
|
4
|
+
constructor(sendFn, options) {
|
|
5
|
+
this.queue$ = new Subject();
|
|
6
|
+
this.onSendError = options?.onError;
|
|
7
|
+
this.subscription = this.queue$.pipe(concatMap((message) => this.writeOne(sendFn, message))).subscribe();
|
|
8
|
+
}
|
|
9
|
+
send(message) {
|
|
10
|
+
this.queue$.next(message);
|
|
11
|
+
}
|
|
12
|
+
stop() {
|
|
13
|
+
this.queue$.complete();
|
|
14
|
+
this.subscription.unsubscribe();
|
|
15
|
+
}
|
|
16
|
+
writeOne(sendFn, message) {
|
|
17
|
+
return new Observable((subscriber) => {
|
|
18
|
+
try {
|
|
19
|
+
sendFn(message, (error) => {
|
|
20
|
+
if (error) {
|
|
21
|
+
this.onSendError?.(error, message);
|
|
22
|
+
}
|
|
23
|
+
subscriber.next();
|
|
24
|
+
subscriber.complete();
|
|
25
|
+
});
|
|
26
|
+
} catch (err) {
|
|
27
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
28
|
+
this.onSendError?.(error, message);
|
|
29
|
+
subscriber.next();
|
|
30
|
+
subscriber.complete();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function writeOneMessage(sendFn, message, onError) {
|
|
36
|
+
return new Observable((subscriber) => {
|
|
37
|
+
try {
|
|
38
|
+
sendFn(message, (error) => {
|
|
39
|
+
if (error) {
|
|
40
|
+
onError?.(error, message);
|
|
41
|
+
}
|
|
42
|
+
subscriber.next();
|
|
43
|
+
subscriber.complete();
|
|
44
|
+
});
|
|
45
|
+
} catch (err) {
|
|
46
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
47
|
+
onError?.(error, message);
|
|
48
|
+
subscriber.next();
|
|
49
|
+
subscriber.complete();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
class PriorityIpcSender {
|
|
54
|
+
constructor(sendFn, options) {
|
|
55
|
+
this.dataQueue = [];
|
|
56
|
+
this.obsQueue = [];
|
|
57
|
+
this.draining = false;
|
|
58
|
+
this.drain$ = new Subject();
|
|
59
|
+
this.onSendError = options?.onError;
|
|
60
|
+
this.subscription = this.drain$.pipe(
|
|
61
|
+
concatMap(() => {
|
|
62
|
+
const msg = this.dataQueue.shift() ?? this.obsQueue.shift();
|
|
63
|
+
if (!msg) {
|
|
64
|
+
this.draining = false;
|
|
65
|
+
return EMPTY;
|
|
66
|
+
}
|
|
67
|
+
return writeOneMessage(sendFn, msg, this.onSendError).pipe(
|
|
68
|
+
finalize(() => this.tryScheduleDrain())
|
|
69
|
+
);
|
|
70
|
+
})
|
|
71
|
+
).subscribe();
|
|
72
|
+
}
|
|
73
|
+
sendData(message) {
|
|
74
|
+
this.dataQueue.push(message);
|
|
75
|
+
this.tryScheduleDrain();
|
|
76
|
+
}
|
|
77
|
+
sendObservational(message) {
|
|
78
|
+
this.obsQueue.push(message);
|
|
79
|
+
this.tryScheduleDrain();
|
|
80
|
+
}
|
|
81
|
+
stop() {
|
|
82
|
+
this.drain$.complete();
|
|
83
|
+
this.subscription.unsubscribe();
|
|
84
|
+
}
|
|
85
|
+
tryScheduleDrain() {
|
|
86
|
+
if (this.draining) return;
|
|
87
|
+
this.draining = true;
|
|
88
|
+
this.drain$.next();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
BufferedIpcSender,
|
|
93
|
+
PriorityIpcSender
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=buffered_ipc_sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/buffered_ipc_sender.ts"],"sourcesContent":["import { Subject, Subscription, Observable, EMPTY } from 'rxjs';\nimport { concatMap, finalize } from 'rxjs/operators';\n\nexport type IpcSendFn = (\n message: unknown,\n callback: (error: Error | null) => void,\n) => void;\n\nexport interface BufferedIpcSenderOptions {\n onError?: (error: Error, message: unknown) => void;\n}\n\n/**\n * Serializes IPC writes through an RxJS pipeline to prevent ENOBUFS.\n *\n * Without backpressure, rapid `process.send()` calls can overflow the\n * kernel socket buffer. BufferedIpcSender queues messages in the JS\n * heap and drains them one at a time, waiting for each write callback\n * before pulling the next message.\n */\nexport class BufferedIpcSender {\n private readonly queue$ = new Subject<unknown>();\n private readonly subscription: Subscription;\n private readonly onSendError: ((error: Error, message: unknown) => void) | undefined;\n\n constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions) {\n this.onSendError = options?.onError;\n\n this.subscription = this.queue$\n .pipe(concatMap((message) => this.writeOne(sendFn, message)))\n .subscribe();\n }\n\n send(message: unknown): void {\n this.queue$.next(message);\n }\n\n stop(): void {\n this.queue$.complete();\n this.subscription.unsubscribe();\n }\n\n private writeOne(sendFn: IpcSendFn, message: unknown): Observable<void> {\n return new Observable<void>((subscriber) => {\n try {\n sendFn(message, (error) => {\n if (error) {\n this.onSendError?.(error, message);\n }\n subscriber.next();\n subscriber.complete();\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.onSendError?.(error, message);\n subscriber.next();\n subscriber.complete();\n }\n });\n }\n}\n\nfunction writeOneMessage(\n sendFn: IpcSendFn,\n message: unknown,\n onError?: (error: Error, message: unknown) => void,\n): Observable<void> {\n return new Observable<void>((subscriber) => {\n try {\n sendFn(message, (error) => {\n if (error) {\n onError?.(error, message);\n }\n subscriber.next();\n subscriber.complete();\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error, message);\n subscriber.next();\n subscriber.complete();\n }\n });\n}\n\n/**\n * Two-queue IPC sender with priority interleaving.\n *\n * Data-path messages (RPC responses, push events) always drain before\n * observational messages (traces, logs). Both queues share a single\n * `process.send()` call with backpressure — at most one message is in\n * flight at a time.\n *\n * The drain loop checks the data queue first on every iteration. If a\n * data message arrives while observational messages are draining, the\n * data message is picked up on the very next write cycle (latency ≈\n * one `process.send()` callback, typically microseconds).\n */\nexport class PriorityIpcSender {\n private readonly dataQueue: unknown[] = [];\n private readonly obsQueue: unknown[] = [];\n private draining = false;\n private readonly drain$ = new Subject<void>();\n private readonly subscription: Subscription;\n private readonly onSendError: ((error: Error, message: unknown) => void) | undefined;\n\n constructor(sendFn: IpcSendFn, options?: BufferedIpcSenderOptions) {\n this.onSendError = options?.onError;\n\n this.subscription = this.drain$\n .pipe(\n concatMap(() => {\n const msg = this.dataQueue.shift() ?? this.obsQueue.shift();\n if (!msg) {\n this.draining = false;\n return EMPTY;\n }\n return writeOneMessage(sendFn, msg, this.onSendError).pipe(\n finalize(() => this.tryScheduleDrain()),\n );\n }),\n )\n .subscribe();\n }\n\n sendData(message: unknown): void {\n this.dataQueue.push(message);\n this.tryScheduleDrain();\n }\n\n sendObservational(message: unknown): void {\n this.obsQueue.push(message);\n this.tryScheduleDrain();\n }\n\n stop(): void {\n this.drain$.complete();\n this.subscription.unsubscribe();\n }\n\n private tryScheduleDrain(): void {\n if (this.draining) return;\n this.draining = true;\n this.drain$.next();\n }\n}\n"],"mappings":"AAAA,SAAS,SAAuB,YAAY,aAAa;AACzD,SAAS,WAAW,gBAAgB;AAmB7B,MAAM,kBAAkB;AAAA,EAK7B,YAAY,QAAmB,SAAoC;AAJnE,SAAiB,SAAS,IAAI,QAAiB;AAK7C,SAAK,cAAc,SAAS;AAE5B,SAAK,eAAe,KAAK,OACtB,KAAK,UAAU,CAAC,YAAY,KAAK,SAAS,QAAQ,OAAO,CAAC,CAAC,EAC3D,UAAU;AAAA,EACf;AAAA,EAEA,KAAK,SAAwB;AAC3B,SAAK,OAAO,KAAK,OAAO;AAAA,EAC1B;AAAA,EAEA,OAAa;AACX,SAAK,OAAO,SAAS;AACrB,SAAK,aAAa,YAAY;AAAA,EAChC;AAAA,EAEQ,SAAS,QAAmB,SAAoC;AACtE,WAAO,IAAI,WAAiB,CAAC,eAAe;AAC1C,UAAI;AACF,eAAO,SAAS,CAAC,UAAU;AACzB,cAAI,OAAO;AACT,iBAAK,cAAc,OAAO,OAAO;AAAA,UACnC;AACA,qBAAW,KAAK;AAChB,qBAAW,SAAS;AAAA,QACtB,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,aAAK,cAAc,OAAO,OAAO;AACjC,mBAAW,KAAK;AAChB,mBAAW,SAAS;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,gBACP,QACA,SACA,SACkB;AAClB,SAAO,IAAI,WAAiB,CAAC,eAAe;AAC1C,QAAI;AACF,aAAO,SAAS,CAAC,UAAU;AACzB,YAAI,OAAO;AACT,oBAAU,OAAO,OAAO;AAAA,QAC1B;AACA,mBAAW,KAAK;AAChB,mBAAW,SAAS;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,gBAAU,OAAO,OAAO;AACxB,iBAAW,KAAK;AAChB,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF,CAAC;AACH;AAeO,MAAM,kBAAkB;AAAA,EAQ7B,YAAY,QAAmB,SAAoC;AAPnE,SAAiB,YAAuB,CAAC;AACzC,SAAiB,WAAsB,CAAC;AACxC,SAAQ,WAAW;AACnB,SAAiB,SAAS,IAAI,QAAc;AAK1C,SAAK,cAAc,SAAS;AAE5B,SAAK,eAAe,KAAK,OACtB;AAAA,MACC,UAAU,MAAM;AACd,cAAM,MAAM,KAAK,UAAU,MAAM,KAAK,KAAK,SAAS,MAAM;AAC1D,YAAI,CAAC,KAAK;AACR,eAAK,WAAW;AAChB,iBAAO;AAAA,QACT;AACA,eAAO,gBAAgB,QAAQ,KAAK,KAAK,WAAW,EAAE;AAAA,UACpD,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH,EACC,UAAU;AAAA,EACf;AAAA,EAEA,SAAS,SAAwB;AAC/B,SAAK,UAAU,KAAK,OAAO;AAC3B,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,kBAAkB,SAAwB;AACxC,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,OAAa;AACX,SAAK,OAAO,SAAS;AACrB,SAAK,aAAa,YAAY;AAAA,EAChC;AAAA,EAEQ,mBAAyB;AAC/B,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,SAAK,OAAO,KAAK;AAAA,EACnB;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/controller_contract.ts"],"sourcesContent":["export interface ControllerState {}\n\nexport interface ControllerInput {}\n\nexport interface ControllerEvents {}\n\nexport interface PageController<\n S extends ControllerState = ControllerState,\n I extends ControllerInput = ControllerInput,\n E extends ControllerEvents = ControllerEvents,\n> {\n readonly
|
|
1
|
+
{"version":3,"sources":["../../src/client/controller_contract.ts"],"sourcesContent":["export interface ControllerState {}\n\nexport interface ControllerInput {}\n\nexport interface ControllerEvents {}\n\nexport interface PageController<\n S extends ControllerState = ControllerState,\n I extends ControllerInput = ControllerInput,\n E extends ControllerEvents = ControllerEvents,\n> {\n readonly data?: S;\n readonly input?: I;\n readonly events?: E;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -5,11 +5,9 @@ interface ControllerInput {
|
|
|
5
5
|
interface ControllerEvents {
|
|
6
6
|
}
|
|
7
7
|
interface PageController<S extends ControllerState = ControllerState, I extends ControllerInput = ControllerInput, E extends ControllerEvents = ControllerEvents> {
|
|
8
|
-
readonly
|
|
9
|
-
readonly input
|
|
10
|
-
readonly events
|
|
11
|
-
initialize?(): void | Promise<void>;
|
|
12
|
-
destroy(): void;
|
|
8
|
+
readonly data?: S;
|
|
9
|
+
readonly input?: I;
|
|
10
|
+
readonly events?: E;
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
export type { ControllerEvents, ControllerInput, ControllerState, PageController };
|
|
@@ -5,11 +5,9 @@ interface ControllerInput {
|
|
|
5
5
|
interface ControllerEvents {
|
|
6
6
|
}
|
|
7
7
|
interface PageController<S extends ControllerState = ControllerState, I extends ControllerInput = ControllerInput, E extends ControllerEvents = ControllerEvents> {
|
|
8
|
-
readonly
|
|
9
|
-
readonly input
|
|
10
|
-
readonly events
|
|
11
|
-
initialize?(): void | Promise<void>;
|
|
12
|
-
destroy(): void;
|
|
8
|
+
readonly data?: S;
|
|
9
|
+
readonly input?: I;
|
|
10
|
+
readonly events?: E;
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
export type { ControllerEvents, ControllerInput, ControllerState, PageController };
|