electron-state-sync 1.1.0

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.
Files changed (97) hide show
  1. package/CLAUDE.md +254 -0
  2. package/LICENSE +21 -0
  3. package/README.md +753 -0
  4. package/README.zh-CN.md +743 -0
  5. package/bun.lock +542 -0
  6. package/bunfig.toml +7 -0
  7. package/dist/jotai.cjs +106 -0
  8. package/dist/jotai.d.cts +48 -0
  9. package/dist/jotai.d.cts.map +1 -0
  10. package/dist/jotai.d.ts +48 -0
  11. package/dist/jotai.d.ts.map +1 -0
  12. package/dist/jotai.js +105 -0
  13. package/dist/jotai.js.map +1 -0
  14. package/dist/main.cjs +177 -0
  15. package/dist/main.d.cts +26 -0
  16. package/dist/main.d.cts.map +1 -0
  17. package/dist/main.d.ts +26 -0
  18. package/dist/main.d.ts.map +1 -0
  19. package/dist/main.js +177 -0
  20. package/dist/main.js.map +1 -0
  21. package/dist/preact.cjs +46 -0
  22. package/dist/preact.d.cts +11 -0
  23. package/dist/preact.d.cts.map +1 -0
  24. package/dist/preact.d.ts +11 -0
  25. package/dist/preact.d.ts.map +1 -0
  26. package/dist/preact.js +46 -0
  27. package/dist/preact.js.map +1 -0
  28. package/dist/preload.cjs +51 -0
  29. package/dist/preload.d.cts +20 -0
  30. package/dist/preload.d.cts.map +1 -0
  31. package/dist/preload.d.ts +20 -0
  32. package/dist/preload.d.ts.map +1 -0
  33. package/dist/preload.js +51 -0
  34. package/dist/preload.js.map +1 -0
  35. package/dist/react-query.cjs +113 -0
  36. package/dist/react-query.d.cts +58 -0
  37. package/dist/react-query.d.cts.map +1 -0
  38. package/dist/react-query.d.ts +58 -0
  39. package/dist/react-query.d.ts.map +1 -0
  40. package/dist/react-query.js +112 -0
  41. package/dist/react-query.js.map +1 -0
  42. package/dist/react.cjs +46 -0
  43. package/dist/react.d.cts +11 -0
  44. package/dist/react.d.cts.map +1 -0
  45. package/dist/react.d.ts +11 -0
  46. package/dist/react.d.ts.map +1 -0
  47. package/dist/react.js +46 -0
  48. package/dist/react.js.map +1 -0
  49. package/dist/redux.cjs +148 -0
  50. package/dist/redux.d.cts +80 -0
  51. package/dist/redux.d.cts.map +1 -0
  52. package/dist/redux.d.ts +80 -0
  53. package/dist/redux.d.ts.map +1 -0
  54. package/dist/redux.js +146 -0
  55. package/dist/redux.js.map +1 -0
  56. package/dist/renderer/index.cjs +7 -0
  57. package/dist/renderer/index.d.cts +23 -0
  58. package/dist/renderer/index.d.cts.map +1 -0
  59. package/dist/renderer/index.d.ts +23 -0
  60. package/dist/renderer/index.d.ts.map +1 -0
  61. package/dist/renderer/index.js +3 -0
  62. package/dist/renderer-C7zF3UQm.js +57 -0
  63. package/dist/renderer-C7zF3UQm.js.map +1 -0
  64. package/dist/renderer-D3YziJ_U.cjs +86 -0
  65. package/dist/solid.cjs +74 -0
  66. package/dist/solid.d.cts +13 -0
  67. package/dist/solid.d.cts.map +1 -0
  68. package/dist/solid.d.ts +13 -0
  69. package/dist/solid.d.ts.map +1 -0
  70. package/dist/solid.js +74 -0
  71. package/dist/solid.js.map +1 -0
  72. package/dist/svelte.cjs +63 -0
  73. package/dist/svelte.d.cts +14 -0
  74. package/dist/svelte.d.cts.map +1 -0
  75. package/dist/svelte.d.ts +14 -0
  76. package/dist/svelte.d.ts.map +1 -0
  77. package/dist/svelte.js +63 -0
  78. package/dist/svelte.js.map +1 -0
  79. package/dist/types-7wPPX0ty.d.ts +37 -0
  80. package/dist/types-7wPPX0ty.d.ts.map +1 -0
  81. package/dist/types-C18dHgLI.d.cts +37 -0
  82. package/dist/types-C18dHgLI.d.cts.map +1 -0
  83. package/dist/vue.cjs +69 -0
  84. package/dist/vue.d.cts +15 -0
  85. package/dist/vue.d.cts.map +1 -0
  86. package/dist/vue.d.ts +15 -0
  87. package/dist/vue.d.ts.map +1 -0
  88. package/dist/vue.js +70 -0
  89. package/dist/vue.js.map +1 -0
  90. package/dist/zustand.cjs +193 -0
  91. package/dist/zustand.d.cts +61 -0
  92. package/dist/zustand.d.cts.map +1 -0
  93. package/dist/zustand.d.ts +61 -0
  94. package/dist/zustand.d.ts.map +1 -0
  95. package/dist/zustand.js +191 -0
  96. package/dist/zustand.js.map +1 -0
  97. package/package.json +162 -0
package/dist/main.js ADDED
@@ -0,0 +1,177 @@
1
+ import { ipcMain } from "electron";
2
+
3
+ //#region src/channels.ts
4
+ const createSyncStateChannels = (options) => {
5
+ const channelPrefix = `${options.baseChannel ?? "state"}:${options.name}`;
6
+ return {
7
+ getChannel: `${channelPrefix}:get`,
8
+ setChannel: `${channelPrefix}:set`,
9
+ subscribeChannel: `${channelPrefix}:subscribe`,
10
+ unsubscribeChannel: `${channelPrefix}:unsubscribe`,
11
+ updateChannel: `${channelPrefix}:update`
12
+ };
13
+ };
14
+
15
+ //#endregion
16
+ //#region src/types.ts
17
+ var SyncStateError = class SyncStateError extends Error {
18
+ code;
19
+ stateName;
20
+ baseChannel;
21
+ cause;
22
+ constructor(code, message, context) {
23
+ super(message);
24
+ this.code = code;
25
+ this.name = "SyncStateError";
26
+ this.stateName = context?.stateName;
27
+ this.baseChannel = context?.baseChannel;
28
+ this.cause = context?.cause;
29
+ if (Error.captureStackTrace) Error.captureStackTrace(this, SyncStateError);
30
+ }
31
+ getFullMessage() {
32
+ const parts = [this.message];
33
+ if (this.stateName) parts.push(`\n State name: "${this.stateName}"`);
34
+ if (this.baseChannel) parts.push(`\n Channel prefix: "${this.baseChannel}"`);
35
+ if (this.cause) parts.push(`\n Original error: ${this.cause.message}`);
36
+ return parts.join("");
37
+ }
38
+ };
39
+
40
+ //#endregion
41
+ //#region src/main.ts
42
+ let globalConfig = {};
43
+ const initSyncStateMain = (config) => {
44
+ globalConfig = { ...config };
45
+ };
46
+ const createReadonlyErrorMessage = (stateName, baseChannel) => `syncState renderer write is disabled by main process. State "${stateName}" has channel prefix "${baseChannel}". Please set allowRendererSet: true in main process to enable renderer write.`;
47
+ const createInvalidValueErrorMessage = (stateName, baseChannel) => `syncState renderer write value validation failed. State "${stateName}" has channel prefix "${baseChannel}". Please check if the value conforms to resolveRendererValue validation rules.`;
48
+ const INVALID_INITIAL_VALUE_WARNING_MESSAGE = "syncState Warning: Initial value contains non-serializable content (such as functions, Symbols, BigInts, etc.), which will prevent the value from being transmitted to renderer process via IPC";
49
+ const checkType = (val) => {
50
+ if (val === null || val === void 0) return true;
51
+ if (typeof val === "string") return true;
52
+ if (typeof val === "number") return true;
53
+ if (typeof val === "boolean") return true;
54
+ if (typeof val === "function") return false;
55
+ if (typeof val === "symbol") return false;
56
+ if (typeof val === "bigint") return false;
57
+ if (Array.isArray(val)) return val.every((item) => checkType(item));
58
+ if (typeof val === "object") try {
59
+ JSON.stringify(val);
60
+ return Object.values(val).every((item) => checkType(item));
61
+ } catch {
62
+ return false;
63
+ }
64
+ return true;
65
+ };
66
+ const validateSerializable = (value) => checkType(value);
67
+ const createSyncStateStore = (initialValue) => {
68
+ let state$1 = initialValue;
69
+ const getState = () => state$1;
70
+ const setState = (value) => {
71
+ state$1 = value;
72
+ };
73
+ return {
74
+ getState,
75
+ setState
76
+ };
77
+ };
78
+ const createSubscriptions = (channels, getState) => {
79
+ const subscribers = /* @__PURE__ */ new Set();
80
+ const broadcast = (value) => {
81
+ for (const subscriber of subscribers) if (subscriber.isDestroyed()) subscribers.delete(subscriber);
82
+ else subscriber.send(channels.updateChannel, value);
83
+ };
84
+ const handleSubscribe = ({ sender }) => {
85
+ subscribers.add(sender);
86
+ sender.once("destroyed", () => {
87
+ subscribers.delete(sender);
88
+ });
89
+ sender.send(channels.updateChannel, getState());
90
+ };
91
+ const handleUnsubscribe = ({ sender }) => {
92
+ subscribers.delete(sender);
93
+ };
94
+ const clear = () => {
95
+ subscribers.clear();
96
+ };
97
+ return {
98
+ broadcast,
99
+ clear,
100
+ handleSubscribe,
101
+ handleUnsubscribe
102
+ };
103
+ };
104
+ const createSetStateAndBroadcast = (setState, broadcast) => (value) => {
105
+ setState(value);
106
+ broadcast(value);
107
+ };
108
+ const createInvokeHandlers = (getState, setStateAndBroadcast, options) => {
109
+ const handleGet = () => getState();
110
+ const ensureRendererWritable = () => {
111
+ if (options.allowRendererSet === false) throw new SyncStateError("RENDERER_READONLY", createReadonlyErrorMessage(options.name, options.baseChannel ?? "state"), {
112
+ baseChannel: options.baseChannel ?? "state",
113
+ stateName: options.name
114
+ });
115
+ };
116
+ const resolveRendererValue = (value) => {
117
+ if (!options.resolveRendererValue) return value;
118
+ try {
119
+ return options.resolveRendererValue(value);
120
+ } catch (error) {
121
+ let message = "";
122
+ let cause = void 0;
123
+ if (error instanceof Error) {
124
+ const { message: errorMessage } = error;
125
+ message = errorMessage;
126
+ cause = error;
127
+ } else message = createInvalidValueErrorMessage(options.name, options.baseChannel ?? "state");
128
+ throw new SyncStateError("RENDERER_INVALID_VALUE", message, {
129
+ baseChannel: options.baseChannel ?? "state",
130
+ cause,
131
+ stateName: options.name
132
+ });
133
+ }
134
+ };
135
+ const handleSet = (_event, value) => {
136
+ ensureRendererWritable();
137
+ setStateAndBroadcast(resolveRendererValue(value));
138
+ };
139
+ return {
140
+ handleGet,
141
+ handleSet
142
+ };
143
+ };
144
+ const registerIpcHandlers = (channels, invokeHandlers, subscriptions) => {
145
+ ipcMain.handle(channels.getChannel, invokeHandlers.handleGet);
146
+ ipcMain.handle(channels.setChannel, invokeHandlers.handleSet);
147
+ ipcMain.on(channels.subscribeChannel, subscriptions.handleSubscribe);
148
+ ipcMain.on(channels.unsubscribeChannel, subscriptions.handleUnsubscribe);
149
+ return () => {
150
+ ipcMain.removeHandler(channels.getChannel);
151
+ ipcMain.removeHandler(channels.setChannel);
152
+ ipcMain.removeListener(channels.subscribeChannel, subscriptions.handleSubscribe);
153
+ ipcMain.removeListener(channels.unsubscribeChannel, subscriptions.handleUnsubscribe);
154
+ subscriptions.clear();
155
+ };
156
+ };
157
+ const state = (options) => {
158
+ const mergedOptions = {
159
+ allowRendererSet: globalConfig.allowRendererSet,
160
+ baseChannel: globalConfig.baseChannel,
161
+ ...options
162
+ };
163
+ if (!validateSerializable(mergedOptions.initialValue)) console.warn(`${INVALID_INITIAL_VALUE_WARNING_MESSAGE}\n State name: "${mergedOptions.name}"`);
164
+ const channels = createSyncStateChannels(mergedOptions);
165
+ const store = createSyncStateStore(mergedOptions.initialValue);
166
+ const subscriptions = createSubscriptions(channels, store.getState);
167
+ const setStateAndBroadcast = createSetStateAndBroadcast(store.setState, subscriptions.broadcast);
168
+ return {
169
+ dispose: registerIpcHandlers(channels, createInvokeHandlers(store.getState, setStateAndBroadcast, mergedOptions), subscriptions),
170
+ get: store.getState,
171
+ set: setStateAndBroadcast
172
+ };
173
+ };
174
+
175
+ //#endregion
176
+ export { initSyncStateMain, state };
177
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","names":["state"],"sources":["../src/channels.ts","../src/types.ts","../src/main.ts"],"sourcesContent":["export interface SyncStateChannelOptions {\n name: string;\n baseChannel?: string;\n}\n\nexport interface SyncStateChannels {\n getChannel: string;\n setChannel: string;\n subscribeChannel: string;\n unsubscribeChannel: string;\n updateChannel: string;\n}\n\nexport const createSyncStateChannels = (options: SyncStateChannelOptions): SyncStateChannels => {\n const baseChannel = options.baseChannel ?? \"state\";\n const channelPrefix = `${baseChannel}:${options.name}`;\n\n return {\n getChannel: `${channelPrefix}:get`,\n setChannel: `${channelPrefix}:set`,\n subscribeChannel: `${channelPrefix}:subscribe`,\n unsubscribeChannel: `${channelPrefix}:unsubscribe`,\n updateChannel: `${channelPrefix}:update`,\n };\n};\n","import type { SyncStateChannelOptions } from \"./channels\";\n\nexport type SyncStateListener<StateValue> = (value: StateValue) => void;\n\nexport type SyncStateErrorCode = \"RENDERER_READONLY\" | \"RENDERER_INVALID_VALUE\";\n\nexport class SyncStateError extends Error {\n public readonly code: SyncStateErrorCode;\n public readonly stateName?: string;\n public readonly baseChannel?: string;\n public readonly cause?: Error;\n\n public constructor(\n code: SyncStateErrorCode,\n message: string,\n context?: { stateName?: string; baseChannel?: string; cause?: Error },\n ) {\n super(message);\n this.code = code;\n this.name = \"SyncStateError\";\n this.stateName = context?.stateName;\n this.baseChannel = context?.baseChannel;\n this.cause = context?.cause;\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SyncStateError);\n }\n }\n\n public getFullMessage(): string {\n const parts = [this.message];\n if (this.stateName) {\n parts.push(`\\n State name: \"${this.stateName}\"`);\n }\n if (this.baseChannel) {\n parts.push(`\\n Channel prefix: \"${this.baseChannel}\"`);\n }\n if (this.cause) {\n parts.push(`\\n Original error: ${this.cause.message}`);\n }\n return parts.join(\"\");\n }\n}\n\nexport interface SyncStateBridge {\n get: <StateValue>(options: SyncStateChannelOptions) => Promise<StateValue>;\n set: <StateValue>(options: SyncStateChannelOptions, value: StateValue) => Promise<void>;\n subscribe: <StateValue>(\n options: SyncStateChannelOptions,\n listener: SyncStateListener<StateValue>,\n ) => () => void;\n}\n","import { ipcMain, type IpcMainEvent, type IpcMainInvokeEvent, type WebContents } from \"electron\";\n\nimport {\n createSyncStateChannels,\n type SyncStateChannelOptions,\n type SyncStateChannels,\n} from \"./channels\";\nimport { SyncStateError } from \"./types\";\n\nexport interface SyncStateMainGlobalConfig {\n baseChannel?: string;\n allowRendererSet?: boolean;\n}\n\nlet globalConfig: SyncStateMainGlobalConfig = {};\n\nexport const initSyncStateMain = (config: SyncStateMainGlobalConfig): void => {\n globalConfig = { ...config };\n};\n\nexport interface SyncStateMainOptions<StateValue> extends SyncStateChannelOptions {\n initialValue: StateValue;\n allowRendererSet?: boolean;\n resolveRendererValue?: (value: StateValue) => StateValue;\n}\n\nexport interface SyncStateMainHandle<StateValue> {\n get: () => StateValue;\n set: (value: StateValue) => void;\n dispose: () => void;\n}\n\ninterface SyncStateStore<StateValue> {\n getState: () => StateValue;\n setState: (value: StateValue) => void;\n}\n\ninterface SyncStateSubscriptions<StateValue> {\n broadcast: (value: StateValue) => void;\n clear: () => void;\n handleSubscribe: (event: IpcMainEvent) => void;\n handleUnsubscribe: (event: IpcMainEvent) => void;\n}\n\ninterface SyncStateInvokeHandlers<StateValue> {\n handleGet: () => StateValue;\n handleSet: (_event: IpcMainInvokeEvent, value: StateValue) => void;\n}\n\nconst createReadonlyErrorMessage = (stateName: string, baseChannel: string): string =>\n `syncState renderer write is disabled by main process. State \"${stateName}\" has channel prefix \"${baseChannel}\". Please set allowRendererSet: true in main process to enable renderer write.`;\n\nconst createInvalidValueErrorMessage = (stateName: string, baseChannel: string): string =>\n `syncState renderer write value validation failed. State \"${stateName}\" has channel prefix \"${baseChannel}\". Please check if the value conforms to resolveRendererValue validation rules.`;\n\nconst INVALID_INITIAL_VALUE_WARNING_MESSAGE =\n \"syncState Warning: Initial value contains non-serializable content (such as functions, Symbols, BigInts, etc.), which will prevent the value from being transmitted to renderer process via IPC\";\n\nconst checkType = (val: unknown): boolean => {\n if (val === null || val === undefined) {\n return true;\n }\n if (typeof val === \"string\") {\n return true;\n }\n if (typeof val === \"number\") {\n return true;\n }\n if (typeof val === \"boolean\") {\n return true;\n }\n if (typeof val === \"function\") {\n return false;\n }\n if (typeof val === \"symbol\") {\n return false;\n }\n if (typeof val === \"bigint\") {\n return false;\n }\n\n if (Array.isArray(val)) {\n return val.every((item) => checkType(item));\n }\n\n if (typeof val === \"object\") {\n try {\n JSON.stringify(val);\n return Object.values(val).every((item) => checkType(item));\n } catch {\n return false;\n }\n }\n\n return true;\n};\n\nconst validateSerializable = (value: unknown): boolean => checkType(value);\n\nconst createSyncStateStore = <StateValue>(initialValue: StateValue): SyncStateStore<StateValue> => {\n let state = initialValue;\n\n const getState = (): StateValue => state;\n\n const setState = (value: StateValue): void => {\n state = value;\n };\n\n return {\n getState,\n setState,\n };\n};\n\nconst createSubscriptions = <StateValue>(\n channels: SyncStateChannels,\n getState: () => StateValue,\n): SyncStateSubscriptions<StateValue> => {\n const subscribers = new Set<WebContents>();\n\n const broadcast = (value: StateValue): void => {\n for (const subscriber of subscribers) {\n if (subscriber.isDestroyed()) {\n subscribers.delete(subscriber);\n } else {\n subscriber.send(channels.updateChannel, value);\n }\n }\n };\n\n const handleSubscribe = ({ sender }: IpcMainEvent): void => {\n subscribers.add(sender);\n sender.once(\"destroyed\", () => {\n subscribers.delete(sender);\n });\n sender.send(channels.updateChannel, getState());\n };\n\n const handleUnsubscribe = ({ sender }: IpcMainEvent): void => {\n subscribers.delete(sender);\n };\n\n const clear = (): void => {\n subscribers.clear();\n };\n\n return {\n broadcast,\n clear,\n handleSubscribe,\n handleUnsubscribe,\n };\n};\n\nconst createSetStateAndBroadcast =\n <StateValue>(\n setState: (value: StateValue) => void,\n broadcast: (value: StateValue) => void,\n ): ((value: StateValue) => void) =>\n (value: StateValue): void => {\n setState(value);\n broadcast(value);\n };\n\nconst createInvokeHandlers = <StateValue>(\n getState: () => StateValue,\n setStateAndBroadcast: (value: StateValue) => void,\n options: SyncStateMainOptions<StateValue>,\n): SyncStateInvokeHandlers<StateValue> => {\n const handleGet = (): StateValue => getState();\n\n const ensureRendererWritable = (): void => {\n if (options.allowRendererSet === false) {\n throw new SyncStateError(\n \"RENDERER_READONLY\",\n createReadonlyErrorMessage(options.name, options.baseChannel ?? \"state\"),\n {\n baseChannel: options.baseChannel ?? \"state\",\n stateName: options.name,\n },\n );\n }\n };\n\n const resolveRendererValue = (value: StateValue): StateValue => {\n if (!options.resolveRendererValue) {\n return value;\n }\n\n try {\n return options.resolveRendererValue(value);\n } catch (error) {\n let message = \"\";\n let cause: Error | undefined = undefined;\n if (error instanceof Error) {\n const { message: errorMessage } = error;\n message = errorMessage;\n cause = error;\n } else {\n message = createInvalidValueErrorMessage(options.name, options.baseChannel ?? \"state\");\n }\n\n throw new SyncStateError(\"RENDERER_INVALID_VALUE\", message, {\n baseChannel: options.baseChannel ?? \"state\",\n cause,\n stateName: options.name,\n });\n }\n };\n\n const handleSet = (_event: IpcMainInvokeEvent, value: StateValue): void => {\n ensureRendererWritable();\n const resolvedValue = resolveRendererValue(value);\n setStateAndBroadcast(resolvedValue);\n };\n\n return {\n handleGet,\n handleSet,\n };\n};\n\nconst registerIpcHandlers = <StateValue>(\n channels: SyncStateChannels,\n invokeHandlers: SyncStateInvokeHandlers<StateValue>,\n subscriptions: SyncStateSubscriptions<StateValue>,\n): (() => void) => {\n ipcMain.handle(channels.getChannel, invokeHandlers.handleGet);\n ipcMain.handle(channels.setChannel, invokeHandlers.handleSet);\n ipcMain.on(channels.subscribeChannel, subscriptions.handleSubscribe);\n ipcMain.on(channels.unsubscribeChannel, subscriptions.handleUnsubscribe);\n\n return (): void => {\n ipcMain.removeHandler(channels.getChannel);\n ipcMain.removeHandler(channels.setChannel);\n ipcMain.removeListener(channels.subscribeChannel, subscriptions.handleSubscribe);\n ipcMain.removeListener(channels.unsubscribeChannel, subscriptions.handleUnsubscribe);\n subscriptions.clear();\n };\n};\n\nexport const state = <StateValue>(\n options: SyncStateMainOptions<StateValue>,\n): SyncStateMainHandle<StateValue> => {\n const mergedOptions: SyncStateMainOptions<StateValue> = {\n allowRendererSet: globalConfig.allowRendererSet,\n baseChannel: globalConfig.baseChannel,\n ...options,\n };\n\n if (!validateSerializable(mergedOptions.initialValue)) {\n console.warn(`${INVALID_INITIAL_VALUE_WARNING_MESSAGE}\\n State name: \"${mergedOptions.name}\"`);\n }\n\n const channels = createSyncStateChannels(mergedOptions);\n const store = createSyncStateStore(mergedOptions.initialValue);\n const subscriptions = createSubscriptions(channels, store.getState);\n const setStateAndBroadcast = createSetStateAndBroadcast(store.setState, subscriptions.broadcast);\n const invokeHandlers = createInvokeHandlers(store.getState, setStateAndBroadcast, mergedOptions);\n\n const dispose = registerIpcHandlers(channels, invokeHandlers, subscriptions);\n\n return {\n dispose,\n get: store.getState,\n set: setStateAndBroadcast,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ const require_renderer = require('./renderer-D3YziJ_U.cjs');
2
+ let preact_hooks = require("preact/hooks");
3
+
4
+ //#region src/renderer/preact.ts
5
+ const createChannelOptions = (options) => {
6
+ const globalConfig = require_renderer.getGlobalConfig();
7
+ return {
8
+ baseChannel: options.baseChannel ?? globalConfig.baseChannel,
9
+ name: options.name
10
+ };
11
+ };
12
+ const useSyncState = (initialValue, options) => {
13
+ const [stateValue, setStateValue] = (0, preact_hooks.useState)(initialValue);
14
+ const [isSynced, setIsSynced] = (0, preact_hooks.useState)(false);
15
+ const globalConfig = require_renderer.getGlobalConfig();
16
+ const bridge = require_renderer.resolveSyncStateBridge(options.bridge ?? globalConfig.bridge);
17
+ const channelOptions = (0, preact_hooks.useMemo)(() => createChannelOptions(options), [options.baseChannel, options.name]);
18
+ const applyRemoteValue = (0, preact_hooks.useCallback)((value) => {
19
+ setStateValue(value);
20
+ setIsSynced(true);
21
+ }, []);
22
+ const setAndSync = (0, preact_hooks.useCallback)((value) => {
23
+ setStateValue(value);
24
+ bridge.set(channelOptions, value);
25
+ }, [bridge, channelOptions]);
26
+ (0, preact_hooks.useEffect)(() => {
27
+ const unsubscribe = bridge.subscribe(channelOptions, applyRemoteValue);
28
+ bridge.get(channelOptions).then(applyRemoteValue);
29
+ return () => {
30
+ unsubscribe();
31
+ };
32
+ }, [
33
+ applyRemoteValue,
34
+ bridge,
35
+ channelOptions
36
+ ]);
37
+ return [
38
+ stateValue,
39
+ setAndSync,
40
+ isSynced
41
+ ];
42
+ };
43
+
44
+ //#endregion
45
+ exports.useSyncState = useSyncState;
46
+ exports.useSyncStatePreact = useSyncState;
@@ -0,0 +1,11 @@
1
+ import { a as SyncStateChannelOptions, t as SyncStateBridge } from "./types-C18dHgLI.cjs";
2
+
3
+ //#region src/renderer/preact.d.ts
4
+ interface UseSyncStatePreactOptions extends SyncStateChannelOptions {
5
+ bridge?: SyncStateBridge;
6
+ }
7
+ type UseSyncStatePreactResult<StateValue> = readonly [StateValue, (value: StateValue) => void, boolean];
8
+ declare const useSyncState: <StateValue>(initialValue: StateValue, options: UseSyncStatePreactOptions) => UseSyncStatePreactResult<StateValue>;
9
+ //#endregion
10
+ export { UseSyncStatePreactOptions, UseSyncStatePreactResult, useSyncState, useSyncState as useSyncStatePreact };
11
+ //# sourceMappingURL=preact.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preact.d.cts","names":[],"sources":["../src/renderer/preact.ts"],"sourcesContent":[],"mappings":";;;UAOiB,yBAAA,SAAkC;EAAlC,MAAA,CAAA,EACN,eADM;AAIjB;AAca,KAdD,wBAkDX,CAAA,UAAA,CAAA,GAAA,SAAA,CAjDC,UAcc,EACL,CAAA,KAAA,EAdD,UAcC,EAAA,GAAA,IAAA,EACiB,OAAA,CAAzB;AAAwB,cAHd,YAGc,EAAA,CAAA,UAAA,CAAA,CAAA,YAAA,EAFX,UAEW,EAAA,OAAA,EADhB,yBACgB,EAAA,GAAxB,wBAAwB,CAAC,UAAD,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { a as SyncStateChannelOptions, t as SyncStateBridge } from "./types-7wPPX0ty.js";
2
+
3
+ //#region src/renderer/preact.d.ts
4
+ interface UseSyncStatePreactOptions extends SyncStateChannelOptions {
5
+ bridge?: SyncStateBridge;
6
+ }
7
+ type UseSyncStatePreactResult<StateValue> = readonly [StateValue, (value: StateValue) => void, boolean];
8
+ declare const useSyncState: <StateValue>(initialValue: StateValue, options: UseSyncStatePreactOptions) => UseSyncStatePreactResult<StateValue>;
9
+ //#endregion
10
+ export { UseSyncStatePreactOptions, UseSyncStatePreactResult, useSyncState, useSyncState as useSyncStatePreact };
11
+ //# sourceMappingURL=preact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preact.d.ts","names":[],"sources":["../src/renderer/preact.ts"],"sourcesContent":[],"mappings":";;;UAOiB,yBAAA,SAAkC;EAAlC,MAAA,CAAA,EACN,eADM;AAIjB;AAca,KAdD,wBAkDX,CAAA,UAAA,CAAA,GAAA,SAAA,CAjDC,UAcc,EACL,CAAA,KAAA,EAdD,UAcC,EAAA,GAAA,IAAA,EACiB,OAAA,CAAzB;AAAwB,cAHd,YAGc,EAAA,CAAA,UAAA,CAAA,CAAA,YAAA,EAFX,UAEW,EAAA,OAAA,EADhB,yBACgB,EAAA,GAAxB,wBAAwB,CAAC,UAAD,CAAA"}
package/dist/preact.js ADDED
@@ -0,0 +1,46 @@
1
+ import { a as resolveSyncStateBridge, t as getGlobalConfig } from "./renderer-C7zF3UQm.js";
2
+ import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
3
+
4
+ //#region src/renderer/preact.ts
5
+ const createChannelOptions = (options) => {
6
+ const globalConfig = getGlobalConfig();
7
+ return {
8
+ baseChannel: options.baseChannel ?? globalConfig.baseChannel,
9
+ name: options.name
10
+ };
11
+ };
12
+ const useSyncState = (initialValue, options) => {
13
+ const [stateValue, setStateValue] = useState(initialValue);
14
+ const [isSynced, setIsSynced] = useState(false);
15
+ const globalConfig = getGlobalConfig();
16
+ const bridge = resolveSyncStateBridge(options.bridge ?? globalConfig.bridge);
17
+ const channelOptions = useMemo(() => createChannelOptions(options), [options.baseChannel, options.name]);
18
+ const applyRemoteValue = useCallback((value) => {
19
+ setStateValue(value);
20
+ setIsSynced(true);
21
+ }, []);
22
+ const setAndSync = useCallback((value) => {
23
+ setStateValue(value);
24
+ bridge.set(channelOptions, value);
25
+ }, [bridge, channelOptions]);
26
+ useEffect(() => {
27
+ const unsubscribe = bridge.subscribe(channelOptions, applyRemoteValue);
28
+ bridge.get(channelOptions).then(applyRemoteValue);
29
+ return () => {
30
+ unsubscribe();
31
+ };
32
+ }, [
33
+ applyRemoteValue,
34
+ bridge,
35
+ channelOptions
36
+ ]);
37
+ return [
38
+ stateValue,
39
+ setAndSync,
40
+ isSynced
41
+ ];
42
+ };
43
+
44
+ //#endregion
45
+ export { useSyncState, useSyncState as useSyncStatePreact };
46
+ //# sourceMappingURL=preact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preact.js","names":[],"sources":["../src/renderer/preact.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"preact/hooks\";\n\nimport type { SyncStateChannelOptions } from \"../channels\";\nimport type { SyncStateBridge } from \"../types\";\nimport { resolveSyncStateBridge } from \"./bridge\";\nimport { getGlobalConfig } from \"./index\";\n\nexport interface UseSyncStatePreactOptions extends SyncStateChannelOptions {\n bridge?: SyncStateBridge;\n}\n\nexport type UseSyncStatePreactResult<StateValue> = readonly [\n StateValue,\n (value: StateValue) => void,\n boolean,\n];\n\nconst createChannelOptions = (options: UseSyncStatePreactOptions): SyncStateChannelOptions => {\n const globalConfig = getGlobalConfig();\n return {\n baseChannel: options.baseChannel ?? globalConfig.baseChannel,\n name: options.name,\n };\n};\n\nexport const useSyncState = <StateValue>(\n initialValue: StateValue,\n options: UseSyncStatePreactOptions,\n): UseSyncStatePreactResult<StateValue> => {\n const [stateValue, setStateValue] = useState(initialValue);\n const [isSynced, setIsSynced] = useState(false);\n const globalConfig = getGlobalConfig();\n const bridge = resolveSyncStateBridge(options.bridge ?? globalConfig.bridge);\n const channelOptions = useMemo(\n () => createChannelOptions(options),\n [options.baseChannel, options.name],\n );\n\n const applyRemoteValue = useCallback((value: StateValue): void => {\n setStateValue(value);\n setIsSynced(true);\n }, []);\n\n const setAndSync = useCallback(\n (value: StateValue): void => {\n setStateValue(value);\n void bridge.set(channelOptions, value);\n },\n [bridge, channelOptions],\n );\n\n useEffect(() => {\n const unsubscribe = bridge.subscribe(channelOptions, applyRemoteValue);\n void bridge.get<StateValue>(channelOptions).then(applyRemoteValue);\n\n return () => {\n unsubscribe();\n };\n }, [applyRemoteValue, bridge, channelOptions]);\n\n return [stateValue, setAndSync, isSynced] as const;\n};\n\n// Backward compatibility alias\nexport { useSyncState as useSyncStatePreact };\n"],"mappings":";;;;AAiBA,MAAM,wBAAwB,YAAgE;CAC5F,MAAM,eAAe,iBAAiB;AACtC,QAAO;EACL,aAAa,QAAQ,eAAe,aAAa;EACjD,MAAM,QAAQ;EACf;;AAGH,MAAa,gBACX,cACA,YACyC;CACzC,MAAM,CAAC,YAAY,iBAAiB,SAAS,aAAa;CAC1D,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;CAC/C,MAAM,eAAe,iBAAiB;CACtC,MAAM,SAAS,uBAAuB,QAAQ,UAAU,aAAa,OAAO;CAC5E,MAAM,iBAAiB,cACf,qBAAqB,QAAQ,EACnC,CAAC,QAAQ,aAAa,QAAQ,KAAK,CACpC;CAED,MAAM,mBAAmB,aAAa,UAA4B;AAChE,gBAAc,MAAM;AACpB,cAAY,KAAK;IAChB,EAAE,CAAC;CAEN,MAAM,aAAa,aAChB,UAA4B;AAC3B,gBAAc,MAAM;AACpB,EAAK,OAAO,IAAI,gBAAgB,MAAM;IAExC,CAAC,QAAQ,eAAe,CACzB;AAED,iBAAgB;EACd,MAAM,cAAc,OAAO,UAAU,gBAAgB,iBAAiB;AACtE,EAAK,OAAO,IAAgB,eAAe,CAAC,KAAK,iBAAiB;AAElE,eAAa;AACX,gBAAa;;IAEd;EAAC;EAAkB;EAAQ;EAAe,CAAC;AAE9C,QAAO;EAAC;EAAY;EAAY;EAAS"}
@@ -0,0 +1,51 @@
1
+ let electron = require("electron");
2
+
3
+ //#region src/channels.ts
4
+ const createSyncStateChannels = (options) => {
5
+ const channelPrefix = `${options.baseChannel ?? "state"}:${options.name}`;
6
+ return {
7
+ getChannel: `${channelPrefix}:get`,
8
+ setChannel: `${channelPrefix}:set`,
9
+ subscribeChannel: `${channelPrefix}:subscribe`,
10
+ unsubscribeChannel: `${channelPrefix}:unsubscribe`,
11
+ updateChannel: `${channelPrefix}:update`
12
+ };
13
+ };
14
+
15
+ //#endregion
16
+ //#region src/preload.ts
17
+ const createSyncStateBridge = () => {
18
+ const get = async (options) => {
19
+ const channels = createSyncStateChannels(options);
20
+ return await electron.ipcRenderer.invoke(channels.getChannel);
21
+ };
22
+ const set = async (options, value) => {
23
+ const channels = createSyncStateChannels(options);
24
+ await electron.ipcRenderer.invoke(channels.setChannel, value);
25
+ };
26
+ const subscribe = (options, listener) => {
27
+ const channels = createSyncStateChannels(options);
28
+ const handler = (_event, value) => {
29
+ listener(value);
30
+ };
31
+ electron.ipcRenderer.on(channels.updateChannel, handler);
32
+ electron.ipcRenderer.send(channels.subscribeChannel);
33
+ return () => {
34
+ electron.ipcRenderer.off(channels.updateChannel, handler);
35
+ electron.ipcRenderer.send(channels.unsubscribeChannel);
36
+ };
37
+ };
38
+ return {
39
+ get,
40
+ set,
41
+ subscribe
42
+ };
43
+ };
44
+ const exposeSyncState = () => {
45
+ const bridge = createSyncStateBridge();
46
+ electron.contextBridge.exposeInMainWorld("syncState", bridge);
47
+ };
48
+
49
+ //#endregion
50
+ exports.createSyncStateBridge = createSyncStateBridge;
51
+ exports.exposeSyncState = exposeSyncState;
@@ -0,0 +1,20 @@
1
+ //#region src/channels.d.ts
2
+ interface SyncStateChannelOptions {
3
+ name: string;
4
+ baseChannel?: string;
5
+ }
6
+ //#endregion
7
+ //#region src/types.d.ts
8
+ type SyncStateListener<StateValue> = (value: StateValue) => void;
9
+ interface SyncStateBridge {
10
+ get: <StateValue>(options: SyncStateChannelOptions) => Promise<StateValue>;
11
+ set: <StateValue>(options: SyncStateChannelOptions, value: StateValue) => Promise<void>;
12
+ subscribe: <StateValue>(options: SyncStateChannelOptions, listener: SyncStateListener<StateValue>) => () => void;
13
+ }
14
+ //#endregion
15
+ //#region src/preload.d.ts
16
+ declare const createSyncStateBridge: () => SyncStateBridge;
17
+ declare const exposeSyncState: () => void;
18
+ //#endregion
19
+ export { type SyncStateBridge, type SyncStateChannelOptions, type SyncStateListener, createSyncStateBridge, exposeSyncState };
20
+ //# sourceMappingURL=preload.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preload.d.cts","names":[],"sources":["../src/channels.ts","../src/types.ts","../src/preload.ts"],"sourcesContent":[],"mappings":";UAAiB,uBAAA;EAAA,IAAA,EAAA,MAAA;;;;;AAAA,KCEL,iBDFK,CAAuB,UAAA,CAAA,GAAA,CAAA,KAAA,ECEY,UDFZ,EAAA,GAAA,IAAA;ACiD1B,UALG,eAAA,CAKH;EAAiB,GAAA,EAAA,CAAA,UAAA,CAAA,CAAA,OAAA,EAJF,uBAIE,EAAA,GAJ0B,OAI1B,CAJkC,UAIlC,CAAA;6BAHF,gCAAgC,eAAe;mCAE/D,mCACC,kBAAkB;;;;ADjDf,cEKJ,qBFL2B,EAAA,GAAA,GEKC,eFLD;cE4C3B"}
@@ -0,0 +1,20 @@
1
+ //#region src/channels.d.ts
2
+ interface SyncStateChannelOptions {
3
+ name: string;
4
+ baseChannel?: string;
5
+ }
6
+ //#endregion
7
+ //#region src/types.d.ts
8
+ type SyncStateListener<StateValue> = (value: StateValue) => void;
9
+ interface SyncStateBridge {
10
+ get: <StateValue>(options: SyncStateChannelOptions) => Promise<StateValue>;
11
+ set: <StateValue>(options: SyncStateChannelOptions, value: StateValue) => Promise<void>;
12
+ subscribe: <StateValue>(options: SyncStateChannelOptions, listener: SyncStateListener<StateValue>) => () => void;
13
+ }
14
+ //#endregion
15
+ //#region src/preload.d.ts
16
+ declare const createSyncStateBridge: () => SyncStateBridge;
17
+ declare const exposeSyncState: () => void;
18
+ //#endregion
19
+ export { type SyncStateBridge, type SyncStateChannelOptions, type SyncStateListener, createSyncStateBridge, exposeSyncState };
20
+ //# sourceMappingURL=preload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preload.d.ts","names":[],"sources":["../src/channels.ts","../src/types.ts","../src/preload.ts"],"sourcesContent":[],"mappings":";UAAiB,uBAAA;EAAA,IAAA,EAAA,MAAA;;;;;AAAA,KCEL,iBDFK,CAAuB,UAAA,CAAA,GAAA,CAAA,KAAA,ECEY,UDFZ,EAAA,GAAA,IAAA;ACiD1B,UALG,eAAA,CAKH;EAAiB,GAAA,EAAA,CAAA,UAAA,CAAA,CAAA,OAAA,EAJF,uBAIE,EAAA,GAJ0B,OAI1B,CAJkC,UAIlC,CAAA;6BAHF,gCAAgC,eAAe;mCAE/D,mCACC,kBAAkB;;;;ADjDf,cEKJ,qBFL2B,EAAA,GAAA,GEKC,eFLD;cE4C3B"}
@@ -0,0 +1,51 @@
1
+ import { contextBridge, ipcRenderer } from "electron";
2
+
3
+ //#region src/channels.ts
4
+ const createSyncStateChannels = (options) => {
5
+ const channelPrefix = `${options.baseChannel ?? "state"}:${options.name}`;
6
+ return {
7
+ getChannel: `${channelPrefix}:get`,
8
+ setChannel: `${channelPrefix}:set`,
9
+ subscribeChannel: `${channelPrefix}:subscribe`,
10
+ unsubscribeChannel: `${channelPrefix}:unsubscribe`,
11
+ updateChannel: `${channelPrefix}:update`
12
+ };
13
+ };
14
+
15
+ //#endregion
16
+ //#region src/preload.ts
17
+ const createSyncStateBridge = () => {
18
+ const get = async (options) => {
19
+ const channels = createSyncStateChannels(options);
20
+ return await ipcRenderer.invoke(channels.getChannel);
21
+ };
22
+ const set = async (options, value) => {
23
+ const channels = createSyncStateChannels(options);
24
+ await ipcRenderer.invoke(channels.setChannel, value);
25
+ };
26
+ const subscribe = (options, listener) => {
27
+ const channels = createSyncStateChannels(options);
28
+ const handler = (_event, value) => {
29
+ listener(value);
30
+ };
31
+ ipcRenderer.on(channels.updateChannel, handler);
32
+ ipcRenderer.send(channels.subscribeChannel);
33
+ return () => {
34
+ ipcRenderer.off(channels.updateChannel, handler);
35
+ ipcRenderer.send(channels.unsubscribeChannel);
36
+ };
37
+ };
38
+ return {
39
+ get,
40
+ set,
41
+ subscribe
42
+ };
43
+ };
44
+ const exposeSyncState = () => {
45
+ const bridge = createSyncStateBridge();
46
+ contextBridge.exposeInMainWorld("syncState", bridge);
47
+ };
48
+
49
+ //#endregion
50
+ export { createSyncStateBridge, exposeSyncState };
51
+ //# sourceMappingURL=preload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preload.js","names":[],"sources":["../src/channels.ts","../src/preload.ts"],"sourcesContent":["export interface SyncStateChannelOptions {\n name: string;\n baseChannel?: string;\n}\n\nexport interface SyncStateChannels {\n getChannel: string;\n setChannel: string;\n subscribeChannel: string;\n unsubscribeChannel: string;\n updateChannel: string;\n}\n\nexport const createSyncStateChannels = (options: SyncStateChannelOptions): SyncStateChannels => {\n const baseChannel = options.baseChannel ?? \"state\";\n const channelPrefix = `${baseChannel}:${options.name}`;\n\n return {\n getChannel: `${channelPrefix}:get`,\n setChannel: `${channelPrefix}:set`,\n subscribeChannel: `${channelPrefix}:subscribe`,\n unsubscribeChannel: `${channelPrefix}:unsubscribe`,\n updateChannel: `${channelPrefix}:update`,\n };\n};\n","import { contextBridge, ipcRenderer, type IpcRendererEvent } from \"electron\";\n\nimport { createSyncStateChannels, type SyncStateChannelOptions } from \"./channels\";\nimport type { SyncStateBridge, SyncStateListener } from \"./types\";\n\nexport const createSyncStateBridge = (): SyncStateBridge => {\n const get = async <StateValue>(options: SyncStateChannelOptions): Promise<StateValue> => {\n const channels = createSyncStateChannels(options);\n return (await ipcRenderer.invoke(channels.getChannel)) as StateValue;\n };\n\n const set = async <StateValue>(\n options: SyncStateChannelOptions,\n value: StateValue,\n ): Promise<void> => {\n const channels = createSyncStateChannels(options);\n await ipcRenderer.invoke(channels.setChannel, value);\n };\n\n const subscribe = <StateValue>(\n options: SyncStateChannelOptions,\n listener: SyncStateListener<StateValue>,\n ): (() => void) => {\n const channels = createSyncStateChannels(options);\n const handler = (_event: IpcRendererEvent, value: StateValue): void => {\n listener(value);\n };\n\n ipcRenderer.on(channels.updateChannel, handler);\n ipcRenderer.send(channels.subscribeChannel);\n\n return () => {\n ipcRenderer.off(channels.updateChannel, handler);\n ipcRenderer.send(channels.unsubscribeChannel);\n };\n };\n\n return {\n get,\n set,\n subscribe,\n };\n};\n\nexport const exposeSyncState = (): void => {\n const bridge = createSyncStateBridge();\n contextBridge.exposeInMainWorld(\"syncState\", bridge);\n};\n\nexport type { SyncStateBridge, SyncStateListener } from \"./types\";\nexport type { SyncStateChannelOptions } from \"./channels\";\n"],"mappings":";;;AAaA,MAAa,2BAA2B,YAAwD;CAE9F,MAAM,gBAAgB,GADF,QAAQ,eAAe,QACN,GAAG,QAAQ;AAEhD,QAAO;EACL,YAAY,GAAG,cAAc;EAC7B,YAAY,GAAG,cAAc;EAC7B,kBAAkB,GAAG,cAAc;EACnC,oBAAoB,GAAG,cAAc;EACrC,eAAe,GAAG,cAAc;EACjC;;;;;AClBH,MAAa,8BAA+C;CAC1D,MAAM,MAAM,OAAmB,YAA0D;EACvF,MAAM,WAAW,wBAAwB,QAAQ;AACjD,SAAQ,MAAM,YAAY,OAAO,SAAS,WAAW;;CAGvD,MAAM,MAAM,OACV,SACA,UACkB;EAClB,MAAM,WAAW,wBAAwB,QAAQ;AACjD,QAAM,YAAY,OAAO,SAAS,YAAY,MAAM;;CAGtD,MAAM,aACJ,SACA,aACiB;EACjB,MAAM,WAAW,wBAAwB,QAAQ;EACjD,MAAM,WAAW,QAA0B,UAA4B;AACrE,YAAS,MAAM;;AAGjB,cAAY,GAAG,SAAS,eAAe,QAAQ;AAC/C,cAAY,KAAK,SAAS,iBAAiB;AAE3C,eAAa;AACX,eAAY,IAAI,SAAS,eAAe,QAAQ;AAChD,eAAY,KAAK,SAAS,mBAAmB;;;AAIjD,QAAO;EACL;EACA;EACA;EACD;;AAGH,MAAa,wBAA8B;CACzC,MAAM,SAAS,uBAAuB;AACtC,eAAc,kBAAkB,aAAa,OAAO"}
@@ -0,0 +1,113 @@
1
+ const require_renderer = require('./renderer-D3YziJ_U.cjs');
2
+ let react = require("react");
3
+ let _tanstack_react_query = require("@tanstack/react-query");
4
+
5
+ //#region src/renderer/react-query.ts
6
+ const DEFAULT_STALE_TIME = 1e3;
7
+ const DEFAULT_GC_TIME = 3e5;
8
+ const createChannelOptions = (options) => {
9
+ const globalConfig = require_renderer.getGlobalConfig();
10
+ return {
11
+ baseChannel: options.baseChannel ?? globalConfig.baseChannel,
12
+ name: options.name
13
+ };
14
+ };
15
+ /**
16
+ * Hook for syncing state with TanStack Query
17
+ *
18
+ * Provides a query-based interface to sync state between renderer and main process.
19
+ * Automatically refetches when remote changes occur.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import { useSyncState } from 'electron-state-sync/react-query';
24
+ *
25
+ * function App() {
26
+ * const { data: count, isSynced, update } = useSyncState(0, {
27
+ * name: 'counter'
28
+ * });
29
+ *
30
+ * return <div onClick={() => update(5)}>{count}</div>;
31
+ * }
32
+ * ```
33
+ */
34
+ const useSyncState = (initialValue, options) => {
35
+ const [isSynced, setIsSynced] = (0, react.useState)(false);
36
+ const globalConfig = require_renderer.getGlobalConfig();
37
+ const bridge = require_renderer.resolveSyncStateBridge(options.bridge ?? globalConfig.bridge);
38
+ const channelOptions = (0, react.useMemo)(() => createChannelOptions(options), [options.baseChannel, options.name]);
39
+ const query = (0, _tanstack_react_query.useQuery)({
40
+ gcTime: options.gcTime ?? DEFAULT_GC_TIME,
41
+ queryFn: () => bridge.get(channelOptions),
42
+ queryKey: options.queryKey ?? [
43
+ "sync-state",
44
+ channelOptions.baseChannel,
45
+ channelOptions.name
46
+ ],
47
+ refetchOnWindowFocus: false,
48
+ staleTime: options.staleTime ?? DEFAULT_STALE_TIME
49
+ });
50
+ const mutation = (0, _tanstack_react_query.useMutation)({ mutationFn: (value) => bridge.set(channelOptions, value) });
51
+ (0, react.useEffect)(() => {
52
+ const unsubscribe = bridge.subscribe(channelOptions, () => {
53
+ query.refetch();
54
+ });
55
+ return () => {
56
+ unsubscribe();
57
+ };
58
+ }, [
59
+ bridge,
60
+ channelOptions,
61
+ query
62
+ ]);
63
+ (0, react.useEffect)(() => {
64
+ if (!query.isLoading && !query.isFetching) setIsSynced(true);
65
+ }, [query.isLoading, query.isFetching]);
66
+ const update = (0, react.useCallback)((value) => {
67
+ mutation.mutate(value);
68
+ }, [mutation]);
69
+ return {
70
+ data: query.data ?? initialValue,
71
+ isSynced,
72
+ update
73
+ };
74
+ };
75
+ /**
76
+ * Hook for creating a mutation to update synced state
77
+ *
78
+ * Provides a simpler mutation-only interface for updating state.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * import { useSyncMutation } from 'electron-state-sync/react-query';
83
+ *
84
+ * function App() {
85
+ * const { mutate, isSynced } = useSyncMutation<number>({
86
+ * name: 'counter'
87
+ * });
88
+ *
89
+ * return <button onClick={() => mutate(10)}>Set to 10</button>;
90
+ * }
91
+ * ```
92
+ */
93
+ const useSyncMutation = (options) => {
94
+ const [isSynced, setIsSynced] = (0, react.useState)(false);
95
+ const globalConfig = require_renderer.getGlobalConfig();
96
+ const bridge = require_renderer.resolveSyncStateBridge(options.bridge ?? globalConfig.bridge);
97
+ const channelOptions = (0, react.useMemo)(() => createChannelOptions(options), [options.baseChannel, options.name]);
98
+ (0, react.useEffect)(() => {
99
+ bridge.get(channelOptions).then(() => {
100
+ setIsSynced(true);
101
+ });
102
+ }, [bridge, channelOptions]);
103
+ const mutation = (0, _tanstack_react_query.useMutation)({ mutationFn: (value) => bridge.set(channelOptions, value) });
104
+ return {
105
+ isSynced,
106
+ mutate: (value) => mutation.mutate(value)
107
+ };
108
+ };
109
+
110
+ //#endregion
111
+ exports.useQuerySyncState = useSyncState;
112
+ exports.useSyncState = useSyncState;
113
+ exports.useSyncMutation = useSyncMutation;