@electrojs/renderer 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anton Ryuben
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,431 @@
1
+ # @electrojs/renderer
2
+
3
+ Typed renderer-side runtime for Electro applications.
4
+
5
+ `@electrojs/renderer` is the only public entrypoint that renderer code uses to talk to the Electro runtime. It exposes:
6
+
7
+ - `ElectroRenderer.initialize(...)` — bootstraps the renderer package
8
+ - `bridge` — typed query/command API
9
+ - `signals` — typed runtime-to-renderer subscriptions
10
+
11
+ This package does **not** know anything about preload implementation details beyond the public preload contract exposed on `window.__ELECTRO_RENDERER__`. The preload side is provided by the runtime layer.
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @electrojs/renderer
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Core idea
24
+
25
+ The renderer cannot talk to the runtime directly. All communication goes through:
26
+
27
+ - `bridge.<module>.<method>(...)` for queries and commands
28
+ - `signals.subscribe(...)` / `signals.once(...)` for runtime-published signals
29
+
30
+ Bridge and signal types are provided through declaration merging.
31
+
32
+ ---
33
+
34
+ ## Quick start
35
+
36
+ ```ts
37
+ import { ElectroRenderer } from "@electrojs/renderer";
38
+ import { createRoot } from "react-dom/client";
39
+ import { App } from "./app";
40
+
41
+ await ElectroRenderer.initialize(async () => {
42
+ createRoot(document.getElementById("root")!).render(<App />);
43
+ });
44
+ ```
45
+
46
+ After initialization finishes, `bridge` and `signals` are ready to use.
47
+
48
+ ---
49
+
50
+ ## Public API
51
+
52
+ ### `ElectroRenderer.initialize(callback?)`
53
+
54
+ Initializes the renderer package exactly once.
55
+
56
+ ```ts
57
+ import { ElectroRenderer } from "@electrojs/renderer";
58
+
59
+ await ElectroRenderer.initialize(async () => {
60
+ // renderer bootstrap logic
61
+ });
62
+ ```
63
+
64
+ #### Behavior
65
+
66
+ - resolves the preload API from `window.__ELECTRO_RENDERER__`
67
+ - creates the bridge proxy
68
+ - creates the signals client
69
+ - executes the optional callback
70
+ - marks the renderer as initialized only after callback success
71
+
72
+ #### Important rules
73
+
74
+ - `initialize()` can only be called once
75
+ - if initialization fails, internal state is rolled back
76
+ - `bridge` and `signals` must not be used before initialization completes
77
+
78
+ ---
79
+
80
+ ### `bridge`
81
+
82
+ `bridge` is a lazily resolved typed proxy.
83
+
84
+ ```ts
85
+ import { bridge } from "@electrojs/renderer";
86
+
87
+ const user = await bridge.auth.getMe();
88
+ await bridge.auth.login("john@example.com", "secret");
89
+ ```
90
+
91
+ At runtime, bridge calls are translated into channel invocations:
92
+
93
+ ```ts
94
+ bridge.auth.login("a", "b");
95
+ // -> preload.invoke("auth:login", ["a", "b"])
96
+ ```
97
+
98
+ #### Method calling rules
99
+
100
+ A bridge method can have one of three shapes depending on generated types:
101
+
102
+ - no input:
103
+
104
+ ```ts
105
+ await bridge.auth.getMe();
106
+ ```
107
+
108
+ - tuple input:
109
+
110
+ ```ts
111
+ await bridge.auth.login(email, password);
112
+ ```
113
+
114
+ - single object input:
115
+
116
+ ```ts
117
+ await bridge.project.create({ name: "Electro" });
118
+ ```
119
+
120
+ ---
121
+
122
+ ### `signals`
123
+
124
+ `signals` provides typed subscription helpers.
125
+
126
+ ```ts
127
+ import { signals } from "@electrojs/renderer";
128
+
129
+ const subscription = signals.subscribe("auth:user-logged-in", (payload) => {
130
+ console.log(payload);
131
+ });
132
+
133
+ subscription.unsubscribe();
134
+ ```
135
+
136
+ One-time subscription:
137
+
138
+ ```ts
139
+ signals.once("auth:user-logged-in", (payload) => {
140
+ console.log("received once", payload);
141
+ });
142
+ ```
143
+
144
+ Signal handlers support two shapes:
145
+
146
+ - payload signal:
147
+
148
+ ```ts
149
+ signals.subscribe("auth:user-logged-in", (payload) => {
150
+ console.log(payload.userId);
151
+ });
152
+ ```
153
+
154
+ - no-payload signal:
155
+
156
+ ```ts
157
+ signals.subscribe("auth:user-logged-out", () => {
158
+ console.log("logged out");
159
+ });
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Typing bridge and signals
165
+
166
+ This package exposes three empty interfaces intended for declaration merging:
167
+
168
+ ```ts
169
+ export interface BridgeQueries {}
170
+ export interface BridgeCommands {}
171
+ export interface BridgeSignals {}
172
+ ```
173
+
174
+ Generated code augments them.
175
+
176
+ Example:
177
+
178
+ ```ts
179
+ declare module "@electrojs/renderer" {
180
+ interface BridgeQueries {
181
+ "auth:getMe": {
182
+ input: undefined;
183
+ output: { id: string; email: string } | null;
184
+ };
185
+ }
186
+
187
+ interface BridgeCommands {
188
+ "auth:login": {
189
+ input: [email: string, password: string];
190
+ output: void;
191
+ };
192
+ }
193
+
194
+ interface BridgeSignals {
195
+ "auth:user-logged-in": { userId: string };
196
+ "auth:user-logged-out": undefined;
197
+ }
198
+ }
199
+ ```
200
+
201
+ After augmentation:
202
+
203
+ ```ts
204
+ const me = await bridge.auth.getMe();
205
+ await bridge.auth.login("john@example.com", "secret");
206
+
207
+ signals.subscribe("auth:user-logged-in", (payload) => {
208
+ payload.userId;
209
+ });
210
+
211
+ signals.subscribe("auth:user-logged-out", () => {});
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Runtime preload contract
217
+
218
+ The renderer expects preload to expose this API on `window.__ELECTRO_RENDERER__`:
219
+
220
+ ```ts
221
+ interface RendererPreloadApi {
222
+ invoke(channel: string, payload: readonly unknown[]): Promise<unknown>;
223
+ subscribe(signalKey: string, listener: (payload: unknown) => void): () => void;
224
+ once(signalKey: string, listener: (payload: unknown) => void): () => void;
225
+ }
226
+ ```
227
+
228
+ This package does not create that object. It only consumes it.
229
+
230
+ ---
231
+
232
+ ## Usage with React
233
+
234
+ ```tsx
235
+ import { useEffect, useState } from "react";
236
+ import { bridge, signals } from "@electrojs/renderer";
237
+
238
+ export function App(): JSX.Element {
239
+ const [email, setEmail] = useState<string | null>(null);
240
+
241
+ useEffect(() => {
242
+ let mounted = true;
243
+
244
+ bridge.auth.getMe().then((user) => {
245
+ if (!mounted) {
246
+ return;
247
+ }
248
+
249
+ setEmail(user?.email ?? null);
250
+ });
251
+
252
+ const subscription = signals.subscribe("auth:user-logged-in", (payload) => {
253
+ setEmail(payload.email);
254
+ });
255
+
256
+ return () => {
257
+ mounted = false;
258
+ subscription.unsubscribe();
259
+ };
260
+ }, []);
261
+
262
+ return <div>{email ?? "Anonymous"}</div>;
263
+ }
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Errors
269
+
270
+ All package-specific errors inherit from `RendererError`.
271
+
272
+ ### `RendererInitializationError`
273
+
274
+ Thrown when initialization fails or is used incorrectly.
275
+
276
+ Examples:
277
+
278
+ - `ELECTRO_RENDERER_ALREADY_INITIALIZED`
279
+ - `ELECTRO_RENDERER_PRELOAD_API_MISSING`
280
+
281
+ ### `RendererUsageError`
282
+
283
+ Thrown when renderer APIs are used incorrectly.
284
+
285
+ Examples:
286
+
287
+ - `ELECTRO_RENDERER_NOT_INITIALIZED`
288
+ - `ELECTRO_RENDERER_INVALID_BRIDGE_NAMESPACE_KEY`
289
+ - `ELECTRO_RENDERER_INVALID_BRIDGE_METHOD_KEY`
290
+ - `ELECTRO_RENDERER_INVALID_SIGNAL_KEY`
291
+ - `ELECTRO_RENDERER_INVALID_SIGNAL_HANDLER`
292
+
293
+ ### `RendererTransportError`
294
+
295
+ Thrown when preload transport operations fail.
296
+
297
+ Examples:
298
+
299
+ - `ELECTRO_RENDERER_TRANSPORT_INVOKE_FAILED`
300
+ - `ELECTRO_RENDERER_SIGNAL_SUBSCRIBE_FAILED`
301
+
302
+ Example:
303
+
304
+ ```ts
305
+ import { ElectroRenderer, RendererInitializationError } from "@electrojs/renderer";
306
+
307
+ try {
308
+ await ElectroRenderer.initialize();
309
+ } catch (error) {
310
+ if (error instanceof RendererInitializationError) {
311
+ console.error(error.code, error.context);
312
+ }
313
+ }
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Initialization lifecycle
319
+
320
+ Initialization is transactional.
321
+
322
+ ### Successful flow
323
+
324
+ 1. validate initialization state
325
+ 2. resolve preload API from `window.__ELECTRO_RENDERER__`
326
+ 3. create bridge transport
327
+ 4. create bridge proxy
328
+ 5. create signals client
329
+ 6. store bridge and signals
330
+ 7. run user callback
331
+ 8. mark initialized
332
+
333
+ ### Failed flow
334
+
335
+ If any step throws:
336
+
337
+ - bridge storage is cleared
338
+ - signals storage is cleared
339
+ - initialization state is reset
340
+ - original error is rethrown
341
+
342
+ This guarantees the package never stays in a half-initialized state.
343
+
344
+ ---
345
+
346
+ ## Design notes
347
+
348
+ ### Why `initialize()` is async
349
+
350
+ Initialization may include async renderer bootstrap logic:
351
+
352
+ ```ts
353
+ await ElectroRenderer.initialize(async () => {
354
+ await loadI18n();
355
+ await warmupCache();
356
+ renderApp();
357
+ });
358
+ ```
359
+
360
+ The renderer becomes initialized only after this callback succeeds.
361
+
362
+ ---
363
+
364
+ ### Why `bridge` is a proxy
365
+
366
+ The runtime bridge surface is generated and typed externally. A proxy lets the package:
367
+
368
+ - expose ergonomic `bridge.auth.login(...)` syntax
369
+ - avoid static hardcoded namespaces
370
+ - remain compatible with generated declaration merging
371
+
372
+ ---
373
+
374
+ ### Why `"then"` returns `undefined`
375
+
376
+ Both root and namespace proxies explicitly return `undefined` for `"then"` to avoid accidental promise-like behavior during inspection or framework interop.
377
+
378
+ ---
379
+
380
+ ## Exports
381
+
382
+ ```ts
383
+ import { bridge, signals, ElectroRenderer, RendererError, RendererInitializationError, RendererTransportError, RendererUsageError } from "@electrojs/renderer";
384
+ ```
385
+
386
+ Type exports:
387
+
388
+ ```ts
389
+ import type {
390
+ BridgeContractEntry,
391
+ BridgeSignalHandler,
392
+ ElectroRendererApi,
393
+ InitializeCallback,
394
+ RendererPreloadApi,
395
+ RendererSignalListener,
396
+ RendererSignalSubscription,
397
+ } from "@electrojs/renderer";
398
+ ```
399
+
400
+ ---
401
+
402
+ ## Best practices
403
+
404
+ Always initialize the renderer before using `bridge` or `signals`.
405
+
406
+ ```ts
407
+ await ElectroRenderer.initialize(async () => {
408
+ // safe to render app here
409
+ });
410
+ ```
411
+
412
+ Always unsubscribe from long-lived signal subscriptions.
413
+
414
+ ```ts
415
+ const subscription = signals.subscribe("project:updated", onProjectUpdated);
416
+
417
+ // later
418
+ subscription.unsubscribe();
419
+ ```
420
+
421
+ Prefer generated types over handwritten declarations.
422
+
423
+ Keep preload implementation thin and transport-focused. Business logic belongs in the runtime, not in preload.
424
+
425
+ ---
426
+
427
+ ## Browser requirement
428
+
429
+ `@electrojs/renderer` expects a browser-like environment with a `window` global.
430
+
431
+ Running tests in plain Node.js without browser mode or DOM emulation will fail for code paths that access `window`.
@@ -0,0 +1,90 @@
1
+ //#region src/types/transport.d.ts
2
+ type RendererSignalListener = (payload: unknown) => void;
3
+ interface RendererPreloadApi {
4
+ invoke(channel: string, payload: readonly unknown[]): Promise<unknown>;
5
+ subscribe(signalKey: string, listener: RendererSignalListener): () => void;
6
+ once(signalKey: string, listener: RendererSignalListener): () => void;
7
+ }
8
+ //#endregion
9
+ //#region src/types/window.d.ts
10
+ declare global {
11
+ interface Window {
12
+ readonly __ELECTRO_RENDERER__?: RendererPreloadApi;
13
+ }
14
+ }
15
+ //#endregion
16
+ //#region src/types/public-api.d.ts
17
+ type BridgeNoInput = undefined;
18
+ type BridgeNoPayload = undefined;
19
+ interface BridgeContractEntry<TInput = BridgeNoInput, TOutput = unknown> {
20
+ readonly input: TInput;
21
+ readonly output: TOutput;
22
+ }
23
+ type PromiseBridgeResult<TValue> = Promise<TValue>;
24
+ type BridgeTupleInput = readonly unknown[];
25
+ type IsBridgeNoInput<TValue> = [TValue] extends [BridgeNoInput] ? true : false;
26
+ type IsBridgeNoPayload<TValue> = [TValue] extends [BridgeNoPayload] ? true : false;
27
+ type BridgeMethodFromInput<TInput, TOutput> = IsBridgeNoInput<TInput> extends true ? () => PromiseBridgeResult<TOutput> : [TInput] extends [BridgeTupleInput] ? (...args: TInput) => PromiseBridgeResult<TOutput> : (input: TInput) => PromiseBridgeResult<TOutput>;
28
+ type BridgeMethod<TEntry extends BridgeContractEntry<any, any>> = BridgeMethodFromInput<TEntry["input"], TEntry["output"]>;
29
+ type Simplify<TValue> = { [TKey in keyof TValue]: TValue[TKey] } & {};
30
+ type ContractKey<TContracts extends object> = keyof TContracts & string;
31
+ type ContractNamespace<TKey extends string> = TKey extends `${infer TNamespace}:${infer _TMethod}` ? TNamespace : never;
32
+ type ContractMethodName<TKey extends string> = TKey extends `${string}:${infer TMethod}` ? TMethod : never;
33
+ type NormalizeBridgeEntry<TEntry> = TEntry extends BridgeContractEntry<infer TInput, infer TOutput> ? BridgeContractEntry<TInput, TOutput> : never;
34
+ type ContractMethodShape<TContracts extends object, TNamespace extends string> = Simplify<{ [TKey in Extract<ContractKey<TContracts>, `${TNamespace}:${string}`> as ContractMethodName<TKey>]: BridgeMethod<NormalizeBridgeEntry<TContracts[TKey]>> }>;
35
+ type BuildNamespaceMap<TContracts extends object> = Simplify<{ [TNamespace in ContractNamespace<ContractKey<TContracts>>]: ContractMethodShape<TContracts, TNamespace> }>;
36
+ type BuildBridgeApi<TQueries extends object, TCommands extends object> = Simplify<BuildNamespaceMap<TQueries> & BuildNamespaceMap<TCommands>>;
37
+ type BridgeSignalHandlerFromPayload<TPayload> = IsBridgeNoPayload<TPayload> extends true ? () => void : (payload: TPayload) => void;
38
+ type BridgeSignalHandler<TPayload> = BridgeSignalHandlerFromPayload<TPayload>;
39
+ interface RendererSignalSubscription {
40
+ unsubscribe(): void;
41
+ }
42
+ interface RendererSignalsApi<TSignals extends object> {
43
+ subscribe<TKey extends keyof TSignals & string>(signalKey: TKey, handler: BridgeSignalHandler<TSignals[TKey]>): RendererSignalSubscription;
44
+ once<TKey extends keyof TSignals & string>(signalKey: TKey, handler: BridgeSignalHandler<TSignals[TKey]>): RendererSignalSubscription;
45
+ }
46
+ type InitializeCallback = () => void | Promise<void>;
47
+ interface ElectroRendererApi {
48
+ initialize(callback?: InitializeCallback): Promise<void>;
49
+ }
50
+ //#endregion
51
+ //#region src/core/electro-renderer.d.ts
52
+ declare class ElectroRendererManager implements ElectroRendererApi {
53
+ private readonly state;
54
+ initialize(callback?: InitializeCallback): Promise<void>;
55
+ isInitialized(): boolean;
56
+ }
57
+ declare const ElectroRenderer: ElectroRendererManager;
58
+ //#endregion
59
+ //#region src/errors/renderer.error.d.ts
60
+ declare abstract class RendererError extends Error {
61
+ readonly code: string;
62
+ readonly context?: Readonly<Record<string, unknown>>;
63
+ protected constructor(message: string, code: string, context?: Readonly<Record<string, unknown>>);
64
+ }
65
+ declare class RendererInitializationError extends RendererError {
66
+ static alreadyInitialized(): RendererInitializationError;
67
+ static preloadApiMissing(windowKey: string): RendererInitializationError;
68
+ }
69
+ declare class RendererUsageError extends RendererError {
70
+ static notInitialized(operation: string): RendererUsageError;
71
+ static invalidBridgeNamespaceKey(received: unknown): RendererUsageError;
72
+ static invalidBridgeMethodKey(namespace: string, received: unknown): RendererUsageError;
73
+ static invalidSignalKey(signalKey: unknown): RendererUsageError;
74
+ static invalidSignalHandler(signalKey: unknown, received: unknown): RendererUsageError;
75
+ }
76
+ declare class RendererTransportError extends RendererError {
77
+ static invokeFailed(channel: string, cause: unknown): RendererTransportError;
78
+ static subscribeFailed(signalKey: string, cause: unknown): RendererTransportError;
79
+ }
80
+ //#endregion
81
+ //#region src/index.d.ts
82
+ interface BridgeQueries {}
83
+ interface BridgeCommands {}
84
+ interface BridgeSignals {}
85
+ type BridgeApi = BuildBridgeApi<BridgeQueries, {}>;
86
+ type SignalsApi = RendererSignalsApi<BridgeSignals>;
87
+ declare const bridge: BridgeApi;
88
+ declare const signals: SignalsApi;
89
+ //#endregion
90
+ export { BridgeApi, BridgeCommands, type BridgeContractEntry, BridgeQueries, type BridgeSignalHandler, BridgeSignals, ElectroRenderer, type ElectroRendererApi, type InitializeCallback, RendererError, RendererInitializationError, type RendererPreloadApi, type RendererSignalListener, type RendererSignalSubscription, RendererTransportError, RendererUsageError, SignalsApi, bridge, signals };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var e=class extends Error{constructor(e,t,n){super(e),this.name=new.target.name,this.code=t,this.context=n,Object.setPrototypeOf(this,new.target.prototype)}},t=class t extends e{static alreadyInitialized(){return new t(`ElectroRenderer.initialize() can only be called once.`,`ELECTRO_RENDERER_ALREADY_INITIALIZED`)}static preloadApiMissing(e){return new t(`Electro renderer preload API is not available on window.${e}.`,`ELECTRO_RENDERER_PRELOAD_API_MISSING`,{windowKey:e})}},n=class t extends e{static notInitialized(e){return new t(`${e} cannot be used before ElectroRenderer.initialize() has completed.`,`ELECTRO_RENDERER_NOT_INITIALIZED`,{operation:e})}static invalidBridgeNamespaceKey(e){return new t(`Bridge namespace key must be a non-empty string.`,`ELECTRO_RENDERER_INVALID_BRIDGE_NAMESPACE_KEY`,{received:e})}static invalidBridgeMethodKey(e,n){return new t(`Bridge method key for namespace "${e}" must be a non-empty string.`,`ELECTRO_RENDERER_INVALID_BRIDGE_METHOD_KEY`,{namespace:e,received:n})}static invalidSignalKey(e){return new t(`Signal key must be a non-empty string.`,`ELECTRO_RENDERER_INVALID_SIGNAL_KEY`,{received:e})}static invalidSignalHandler(e,n){return new t(`Signal handler for "${String(e)}" must be a function.`,`ELECTRO_RENDERER_INVALID_SIGNAL_HANDLER`,{signalKey:e,receivedType:typeof n})}},r=class t extends e{static invokeFailed(e,n){return new t(`Bridge transport invocation failed for channel "${e}".`,`ELECTRO_RENDERER_TRANSPORT_INVOKE_FAILED`,{channel:e,cause:n})}static subscribeFailed(e,n){return new t(`Signal subscription failed for "${e}".`,`ELECTRO_RENDERER_SIGNAL_SUBSCRIBE_FAILED`,{signalKey:e,cause:n})}};let i;function a(e){i=e}function o(){i=void 0}function s(){if(!i)throw n.notInitialized(`bridge`);return i}function c(e,t){return new Proxy({},{get(r,i){if(typeof i!=`string`||i===`then`)return;let a=i.trim();if(a.length===0)throw n.invalidBridgeMethodKey(t,i);return async(...n)=>e.invoke(`${t}:${a}`,n)},has(e,t){return typeof t==`string`&&t.trim().length>0&&t!==`then`},getOwnPropertyDescriptor(e,t){if(!(typeof t!=`string`||t===`then`||t.trim().length===0))return{configurable:!0,enumerable:!0}}})}function l(e){return new Proxy({},{get(t,r){if(typeof r!=`string`||r===`then`)return;let i=r.trim();if(i.length===0)throw n.invalidBridgeNamespaceKey(r);return c(e,i)},has(e,t){return typeof t==`string`&&t.trim().length>0&&t!==`then`},getOwnPropertyDescriptor(e,t){if(!(typeof t!=`string`||t===`then`||t.trim().length===0))return{configurable:!0,enumerable:!0}}})}var u=class{constructor(e){this.preloadApi=e}async invoke(e,t){try{return await this.preloadApi.invoke(e,t)}catch(t){throw r.invokeFailed(e,t)}}};let d;function f(e){d=e}function p(){d=void 0}function m(){if(!d)throw n.notInitialized(`signals`);return d}var h=class{constructor(e){this.dispose=e,this.unsubscribed=!1}unsubscribe(){this.unsubscribed||(this.unsubscribed=!0,this.dispose())}},g=class{constructor(e){this.preloadApi=e}subscribe(e,t){this.ensureValidHandler(e,t);try{return new h(this.preloadApi.subscribe(e,this.createInternalHandler(t)))}catch(t){throw r.subscribeFailed(e,t)}}once(e,t){this.ensureValidHandler(e,t);try{return new h(this.preloadApi.once(e,this.createInternalHandler(t)))}catch(t){throw r.subscribeFailed(e,t)}}createInternalHandler(e){return t=>{if(t===void 0){e();return}e(t)}}ensureValidHandler(e,t){if(typeof e!=`string`||e.trim().length===0)throw n.invalidSignalKey(e);if(typeof t!=`function`)throw n.invalidSignalHandler(e,t)}},_=class{constructor(){this.initialized=!1,this.initializing=!1}isInitialized(){return this.initialized}isInitializing(){return this.initializing}ensureCanInitialize(){if(this.initialized||this.initializing)throw t.alreadyInitialized()}markInitializing(){this.initializing=!0}markInitialized(){this.initializing=!1,this.initialized=!0}reset(){this.initializing=!1,this.initialized=!1}};const v=`__ELECTRO_RENDERER__`;var y=class{static getPreloadApi(e=window){let n=e[v];if(!n)throw t.preloadApiMissing(v);return n}};const b=new class{constructor(){this.state=new _}async initialize(e){this.state.ensureCanInitialize(),this.state.markInitializing();try{let t=y.getPreloadApi(),n=l(new u(t)),r=new g(t);a(n),f(r),e&&await e(),this.state.markInitialized()}catch(e){throw o(),p(),this.state.reset(),e}}isInitialized(){return this.state.isInitialized()}},x=new Proxy({},{get(e,t){return Reflect.get(s(),t)}}),S={subscribe(e,t){return m().subscribe(e,t)},once(e,t){return m().once(e,t)}};export{b as ElectroRenderer,e as RendererError,t as RendererInitializationError,r as RendererTransportError,n as RendererUsageError,x as bridge,S as signals};
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@electrojs/renderer",
3
+ "version": "1.0.0",
4
+ "description": "Library for working with the renderer process in @electro",
5
+ "homepage": "https://github.com/MyraxByte/electrojs#readme",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/MyraxByte/electrojs.git",
10
+ "directory": "packages/renderer"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "devDependencies": {
28
+ "@vitest/browser-playwright": "^4.1.1",
29
+ "@vitest/coverage-v8": "^4.1.1",
30
+ "@vitest/ui": "^4.1.1",
31
+ "jsdom": "^29.0.1",
32
+ "publint": "^0.3.18",
33
+ "tsdown": "^0.21.4",
34
+ "vitest": "^4.1.1",
35
+ "@electrojs/config": "1.0.0"
36
+ },
37
+ "peerDependencies": {
38
+ "@electrojs/config": ">=1.0.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsdown",
42
+ "test": "vitest",
43
+ "test:browser": "vitest --browser"
44
+ }
45
+ }