@yiin/reactive-proxy-state 1.0.22 → 1.0.23
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.cjs +94 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +94 -0
- package/dist/integrations/electron-bridge.d.ts +71 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34856,6 +34856,9 @@ __export(exports_src, {
|
|
|
34856
34856
|
isComputed: () => isComputed,
|
|
34857
34857
|
deepEqual: () => deepEqual,
|
|
34858
34858
|
deepClone: () => deepClone,
|
|
34859
|
+
createRendererBridgeEmitter: () => createRendererBridgeEmitter,
|
|
34860
|
+
createMainBridgeEmitter: () => createMainBridgeEmitter,
|
|
34861
|
+
createBridgeEmitter: () => createBridgeEmitter,
|
|
34859
34862
|
computed: () => computed,
|
|
34860
34863
|
cleanupEffect: () => cleanupEffect,
|
|
34861
34864
|
activeEffect: () => activeEffect
|
|
@@ -36487,3 +36490,94 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
|
|
|
36487
36490
|
}
|
|
36488
36491
|
return stop;
|
|
36489
36492
|
}
|
|
36493
|
+
// src/integrations/electron-bridge.ts
|
|
36494
|
+
function makeTx() {
|
|
36495
|
+
try {
|
|
36496
|
+
const g = globalThis;
|
|
36497
|
+
if (g.crypto && typeof g.crypto.randomUUID === "function") {
|
|
36498
|
+
return g.crypto.randomUUID();
|
|
36499
|
+
}
|
|
36500
|
+
} catch {}
|
|
36501
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
36502
|
+
}
|
|
36503
|
+
function createBridgeEmitter(opts) {
|
|
36504
|
+
const { id, apply, send, onMessage, forward, seenLimit = 1000 } = opts;
|
|
36505
|
+
let muteCount = 0;
|
|
36506
|
+
const mute = (fn) => {
|
|
36507
|
+
muteCount++;
|
|
36508
|
+
try {
|
|
36509
|
+
return fn();
|
|
36510
|
+
} finally {
|
|
36511
|
+
muteCount--;
|
|
36512
|
+
}
|
|
36513
|
+
};
|
|
36514
|
+
const seen = new Set;
|
|
36515
|
+
const order = [];
|
|
36516
|
+
const markSeen = (tx) => {
|
|
36517
|
+
if (seen.has(tx))
|
|
36518
|
+
return;
|
|
36519
|
+
seen.add(tx);
|
|
36520
|
+
order.push(tx);
|
|
36521
|
+
if (order.length > seenLimit) {
|
|
36522
|
+
const oldest = order.shift();
|
|
36523
|
+
seen.delete(oldest);
|
|
36524
|
+
}
|
|
36525
|
+
};
|
|
36526
|
+
const emit = (event) => {
|
|
36527
|
+
if (muteCount > 0)
|
|
36528
|
+
return;
|
|
36529
|
+
const msg = { tx: makeTx(), origin: id, event };
|
|
36530
|
+
markSeen(msg.tx);
|
|
36531
|
+
send(msg);
|
|
36532
|
+
};
|
|
36533
|
+
const unsubscribe = onMessage((msg, ctx) => {
|
|
36534
|
+
if (!msg || !msg.tx)
|
|
36535
|
+
return;
|
|
36536
|
+
if (seen.has(msg.tx))
|
|
36537
|
+
return;
|
|
36538
|
+
markSeen(msg.tx);
|
|
36539
|
+
if (msg.origin === id)
|
|
36540
|
+
return;
|
|
36541
|
+
mute(() => apply(msg.event));
|
|
36542
|
+
if (forward)
|
|
36543
|
+
forward(msg, ctx);
|
|
36544
|
+
});
|
|
36545
|
+
const stop = () => unsubscribe();
|
|
36546
|
+
return { emit, stop, mute };
|
|
36547
|
+
}
|
|
36548
|
+
function createRendererBridgeEmitter(opts) {
|
|
36549
|
+
const { id, channel, ipcRenderer, apply, seenLimit } = opts;
|
|
36550
|
+
return createBridgeEmitter({
|
|
36551
|
+
id,
|
|
36552
|
+
apply,
|
|
36553
|
+
seenLimit,
|
|
36554
|
+
send: (msg) => ipcRenderer.send(channel, msg),
|
|
36555
|
+
onMessage: (cb) => {
|
|
36556
|
+
const handler = (_e, msg) => cb(msg);
|
|
36557
|
+
ipcRenderer.on(channel, handler);
|
|
36558
|
+
return () => ipcRenderer.off(channel, handler);
|
|
36559
|
+
}
|
|
36560
|
+
});
|
|
36561
|
+
}
|
|
36562
|
+
function createMainBridgeEmitter(opts) {
|
|
36563
|
+
const { id = "main", channel, ipcMain, windows, apply, seenLimit } = opts;
|
|
36564
|
+
const broadcast = (msg, exceptId) => {
|
|
36565
|
+
for (const w of windows()) {
|
|
36566
|
+
if (exceptId != null && w.webContents.id === exceptId)
|
|
36567
|
+
continue;
|
|
36568
|
+
w.webContents.send(channel, msg);
|
|
36569
|
+
}
|
|
36570
|
+
};
|
|
36571
|
+
return createBridgeEmitter({
|
|
36572
|
+
id,
|
|
36573
|
+
apply,
|
|
36574
|
+
seenLimit,
|
|
36575
|
+
send: (msg) => broadcast(msg),
|
|
36576
|
+
onMessage: (cb) => {
|
|
36577
|
+
const handler = (e, msg) => cb(msg, { senderId: e?.sender?.id });
|
|
36578
|
+
ipcMain.on(channel, handler);
|
|
36579
|
+
return () => ipcMain.off(channel, handler);
|
|
36580
|
+
},
|
|
36581
|
+
forward: (msg, ctx) => broadcast(msg, ctx?.senderId)
|
|
36582
|
+
});
|
|
36583
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -36431,6 +36431,97 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
|
|
|
36431
36431
|
}
|
|
36432
36432
|
return stop;
|
|
36433
36433
|
}
|
|
36434
|
+
// src/integrations/electron-bridge.ts
|
|
36435
|
+
function makeTx() {
|
|
36436
|
+
try {
|
|
36437
|
+
const g = globalThis;
|
|
36438
|
+
if (g.crypto && typeof g.crypto.randomUUID === "function") {
|
|
36439
|
+
return g.crypto.randomUUID();
|
|
36440
|
+
}
|
|
36441
|
+
} catch {}
|
|
36442
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
36443
|
+
}
|
|
36444
|
+
function createBridgeEmitter(opts) {
|
|
36445
|
+
const { id, apply, send, onMessage, forward, seenLimit = 1000 } = opts;
|
|
36446
|
+
let muteCount = 0;
|
|
36447
|
+
const mute = (fn) => {
|
|
36448
|
+
muteCount++;
|
|
36449
|
+
try {
|
|
36450
|
+
return fn();
|
|
36451
|
+
} finally {
|
|
36452
|
+
muteCount--;
|
|
36453
|
+
}
|
|
36454
|
+
};
|
|
36455
|
+
const seen = new Set;
|
|
36456
|
+
const order = [];
|
|
36457
|
+
const markSeen = (tx) => {
|
|
36458
|
+
if (seen.has(tx))
|
|
36459
|
+
return;
|
|
36460
|
+
seen.add(tx);
|
|
36461
|
+
order.push(tx);
|
|
36462
|
+
if (order.length > seenLimit) {
|
|
36463
|
+
const oldest = order.shift();
|
|
36464
|
+
seen.delete(oldest);
|
|
36465
|
+
}
|
|
36466
|
+
};
|
|
36467
|
+
const emit = (event) => {
|
|
36468
|
+
if (muteCount > 0)
|
|
36469
|
+
return;
|
|
36470
|
+
const msg = { tx: makeTx(), origin: id, event };
|
|
36471
|
+
markSeen(msg.tx);
|
|
36472
|
+
send(msg);
|
|
36473
|
+
};
|
|
36474
|
+
const unsubscribe = onMessage((msg, ctx) => {
|
|
36475
|
+
if (!msg || !msg.tx)
|
|
36476
|
+
return;
|
|
36477
|
+
if (seen.has(msg.tx))
|
|
36478
|
+
return;
|
|
36479
|
+
markSeen(msg.tx);
|
|
36480
|
+
if (msg.origin === id)
|
|
36481
|
+
return;
|
|
36482
|
+
mute(() => apply(msg.event));
|
|
36483
|
+
if (forward)
|
|
36484
|
+
forward(msg, ctx);
|
|
36485
|
+
});
|
|
36486
|
+
const stop = () => unsubscribe();
|
|
36487
|
+
return { emit, stop, mute };
|
|
36488
|
+
}
|
|
36489
|
+
function createRendererBridgeEmitter(opts) {
|
|
36490
|
+
const { id, channel, ipcRenderer, apply, seenLimit } = opts;
|
|
36491
|
+
return createBridgeEmitter({
|
|
36492
|
+
id,
|
|
36493
|
+
apply,
|
|
36494
|
+
seenLimit,
|
|
36495
|
+
send: (msg) => ipcRenderer.send(channel, msg),
|
|
36496
|
+
onMessage: (cb) => {
|
|
36497
|
+
const handler = (_e, msg) => cb(msg);
|
|
36498
|
+
ipcRenderer.on(channel, handler);
|
|
36499
|
+
return () => ipcRenderer.off(channel, handler);
|
|
36500
|
+
}
|
|
36501
|
+
});
|
|
36502
|
+
}
|
|
36503
|
+
function createMainBridgeEmitter(opts) {
|
|
36504
|
+
const { id = "main", channel, ipcMain, windows, apply, seenLimit } = opts;
|
|
36505
|
+
const broadcast = (msg, exceptId) => {
|
|
36506
|
+
for (const w of windows()) {
|
|
36507
|
+
if (exceptId != null && w.webContents.id === exceptId)
|
|
36508
|
+
continue;
|
|
36509
|
+
w.webContents.send(channel, msg);
|
|
36510
|
+
}
|
|
36511
|
+
};
|
|
36512
|
+
return createBridgeEmitter({
|
|
36513
|
+
id,
|
|
36514
|
+
apply,
|
|
36515
|
+
seenLimit,
|
|
36516
|
+
send: (msg) => broadcast(msg),
|
|
36517
|
+
onMessage: (cb) => {
|
|
36518
|
+
const handler = (e, msg) => cb(msg, { senderId: e?.sender?.id });
|
|
36519
|
+
ipcMain.on(channel, handler);
|
|
36520
|
+
return () => ipcMain.off(channel, handler);
|
|
36521
|
+
},
|
|
36522
|
+
forward: (msg, ctx) => broadcast(msg, ctx?.senderId)
|
|
36523
|
+
});
|
|
36524
|
+
}
|
|
36434
36525
|
export {
|
|
36435
36526
|
watchEffect,
|
|
36436
36527
|
watch,
|
|
@@ -36454,6 +36545,9 @@ export {
|
|
|
36454
36545
|
isComputed,
|
|
36455
36546
|
deepEqual,
|
|
36456
36547
|
deepClone,
|
|
36548
|
+
createRendererBridgeEmitter,
|
|
36549
|
+
createMainBridgeEmitter,
|
|
36550
|
+
createBridgeEmitter,
|
|
36457
36551
|
computed,
|
|
36458
36552
|
cleanupEffect,
|
|
36459
36553
|
activeEffect
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { StateEvent } from "../types";
|
|
2
|
+
export type BridgeMessage = {
|
|
3
|
+
tx: string;
|
|
4
|
+
origin: string;
|
|
5
|
+
event: StateEvent;
|
|
6
|
+
};
|
|
7
|
+
type OnMessage = (cb: (msg: BridgeMessage, ctx?: any) => void) => () => void;
|
|
8
|
+
type Send = (msg: BridgeMessage, ctx?: any) => void;
|
|
9
|
+
type Forward = (msg: BridgeMessage, ctx?: any) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Create a loop-safe bridge emitter for bi-directional sync.
|
|
12
|
+
* - Tags every message with tx + origin
|
|
13
|
+
* - Mutes emit while applying remote updates
|
|
14
|
+
* - Dedupe by tx using a small LRU
|
|
15
|
+
*/
|
|
16
|
+
export declare function createBridgeEmitter(opts: {
|
|
17
|
+
id: string;
|
|
18
|
+
apply: (event: StateEvent) => void;
|
|
19
|
+
send: Send;
|
|
20
|
+
onMessage: OnMessage;
|
|
21
|
+
forward?: Forward;
|
|
22
|
+
seenLimit?: number;
|
|
23
|
+
}): {
|
|
24
|
+
emit: (event: StateEvent) => void;
|
|
25
|
+
stop: () => void;
|
|
26
|
+
mute: <T>(fn: () => T) => T;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Renderer-side bridge bound to Electron's ipcRenderer.
|
|
30
|
+
* Keep this generic by accepting a minimal ipcRenderer-like object.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createRendererBridgeEmitter(opts: {
|
|
33
|
+
id: string;
|
|
34
|
+
channel: string;
|
|
35
|
+
ipcRenderer: {
|
|
36
|
+
send: (channel: string, msg: any) => void;
|
|
37
|
+
on: (channel: string, handler: (event: any, msg: any) => void) => void;
|
|
38
|
+
off: (channel: string, handler: (event: any, msg: any) => void) => void;
|
|
39
|
+
};
|
|
40
|
+
apply: (event: StateEvent) => void;
|
|
41
|
+
seenLimit?: number;
|
|
42
|
+
}): {
|
|
43
|
+
emit: (event: StateEvent) => void;
|
|
44
|
+
stop: () => void;
|
|
45
|
+
mute: <T>(fn: () => T) => T;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Main-process bridge bound to Electron's ipcMain and BrowserWindows.
|
|
49
|
+
* Accepts a provider for windows to avoid importing Electron types.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createMainBridgeEmitter(opts: {
|
|
52
|
+
id?: string;
|
|
53
|
+
channel: string;
|
|
54
|
+
ipcMain: {
|
|
55
|
+
on: (channel: string, handler: (event: any, msg: any) => void) => void;
|
|
56
|
+
off: (channel: string, handler: (event: any, msg: any) => void) => void;
|
|
57
|
+
};
|
|
58
|
+
windows: () => {
|
|
59
|
+
webContents: {
|
|
60
|
+
id: number;
|
|
61
|
+
send: (channel: string, msg: any) => void;
|
|
62
|
+
};
|
|
63
|
+
}[];
|
|
64
|
+
apply: (event: StateEvent) => void;
|
|
65
|
+
seenLimit?: number;
|
|
66
|
+
}): {
|
|
67
|
+
emit: (event: StateEvent) => void;
|
|
68
|
+
stop: () => void;
|
|
69
|
+
mute: <T>(fn: () => T) => T;
|
|
70
|
+
};
|
|
71
|
+
export {};
|