@cordy/electro 1.1.2 → 1.2.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/dist/index.d.mts +353 -372
- package/dist/index.mjs +70 -84
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,122 +1,6 @@
|
|
|
1
|
-
import { BaseWindow, BaseWindowConstructorOptions, WebContentsView
|
|
1
|
+
import { BaseWindow, BaseWindowConstructorOptions, WebContentsView } from "electron";
|
|
2
2
|
import { UserConfig } from "vite";
|
|
3
3
|
|
|
4
|
-
//#region src/config/types.d.ts
|
|
5
|
-
declare const RUNTIME_BRAND: unique symbol;
|
|
6
|
-
declare const VIEW_BRAND: unique symbol;
|
|
7
|
-
declare const CONFIG_BRAND: unique symbol;
|
|
8
|
-
interface RuntimeDefinition {
|
|
9
|
-
readonly [RUNTIME_BRAND]: true;
|
|
10
|
-
readonly entry: string;
|
|
11
|
-
readonly vite?: UserConfig;
|
|
12
|
-
/** @internal Caller path captured by defineRuntime(). */
|
|
13
|
-
readonly __source: string;
|
|
14
|
-
}
|
|
15
|
-
interface ViewDefinition {
|
|
16
|
-
readonly [VIEW_BRAND]: true;
|
|
17
|
-
readonly name: string;
|
|
18
|
-
readonly entry: string;
|
|
19
|
-
readonly features?: readonly string[];
|
|
20
|
-
readonly vite?: UserConfig;
|
|
21
|
-
readonly preload?: string;
|
|
22
|
-
readonly webPreferences?: Record<string, unknown>;
|
|
23
|
-
/** @internal Caller path captured by defineView(). */
|
|
24
|
-
readonly __source: string;
|
|
25
|
-
}
|
|
26
|
-
interface ElectroConfig {
|
|
27
|
-
readonly [CONFIG_BRAND]: true;
|
|
28
|
-
readonly runtime: RuntimeDefinition;
|
|
29
|
-
readonly views?: readonly ViewDefinition[];
|
|
30
|
-
}
|
|
31
|
-
interface DefineRuntimeInput {
|
|
32
|
-
entry: string;
|
|
33
|
-
vite?: UserConfig;
|
|
34
|
-
}
|
|
35
|
-
interface DefineViewInput {
|
|
36
|
-
name: string;
|
|
37
|
-
entry: string;
|
|
38
|
-
features?: readonly string[];
|
|
39
|
-
vite?: UserConfig;
|
|
40
|
-
preload?: string;
|
|
41
|
-
webPreferences?: Record<string, unknown>;
|
|
42
|
-
}
|
|
43
|
-
interface DefineConfigInput {
|
|
44
|
-
runtime: RuntimeDefinition;
|
|
45
|
-
views?: readonly ViewDefinition[];
|
|
46
|
-
}
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/config/define-config.d.ts
|
|
49
|
-
declare function defineConfig(input: DefineConfigInput): ElectroConfig;
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region src/config/define-runtime.d.ts
|
|
52
|
-
declare function defineRuntime(input: DefineRuntimeInput): RuntimeDefinition;
|
|
53
|
-
//#endregion
|
|
54
|
-
//#region src/config/define-view.d.ts
|
|
55
|
-
declare function defineView(input: DefineViewInput): ViewDefinition;
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/core/event-bus/types.d.ts
|
|
58
|
-
type EventHandler = (payload: unknown) => void;
|
|
59
|
-
type EventSubscription = {
|
|
60
|
-
channel: string;
|
|
61
|
-
handler: EventHandler;
|
|
62
|
-
ownerId: string;
|
|
63
|
-
};
|
|
64
|
-
type EventId = string;
|
|
65
|
-
/**
|
|
66
|
-
* Type-erased event interface for heterogeneous collections.
|
|
67
|
-
*/
|
|
68
|
-
interface EventInstance {
|
|
69
|
-
readonly id: EventId;
|
|
70
|
-
readonly defaults: unknown;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Public interface returned by {@link createEvent}.
|
|
74
|
-
*
|
|
75
|
-
* Generic parameter preserves payload type for codegen inference
|
|
76
|
-
* (`_EventPayload<T>` infers `T` from `payload()` phantom method).
|
|
77
|
-
*/
|
|
78
|
-
interface CreatedEvent<T = void> extends EventInstance {
|
|
79
|
-
readonly id: EventId;
|
|
80
|
-
readonly defaults: T | undefined;
|
|
81
|
-
/** @internal Phantom method for codegen type extraction. Never called. */
|
|
82
|
-
payload(): T;
|
|
83
|
-
}
|
|
84
|
-
//#endregion
|
|
85
|
-
//#region src/core/event-bus/event-bus.d.ts
|
|
86
|
-
declare class EventBus {
|
|
87
|
-
private readonly subscriptions;
|
|
88
|
-
publish(channel: string, payload?: unknown): void;
|
|
89
|
-
subscribe(channel: string, handler: EventHandler, ownerId: string): () => void;
|
|
90
|
-
removeByOwner(ownerId: string): void;
|
|
91
|
-
}
|
|
92
|
-
//#endregion
|
|
93
|
-
//#region src/core/event-bus/accessor.d.ts
|
|
94
|
-
/**
|
|
95
|
-
* Scoped event access per feature.
|
|
96
|
-
*
|
|
97
|
-
* - `publish("name", payload)` -> publishes as `"ownerId:name"`
|
|
98
|
-
* - `on("dep:name", handler)` -> validates `dep` is a declared dependency
|
|
99
|
-
* - `on("name", handler)` -> subscribes to own `"ownerId:name"`
|
|
100
|
-
*/
|
|
101
|
-
declare class EventAccessor {
|
|
102
|
-
private readonly bus;
|
|
103
|
-
private readonly ownerId;
|
|
104
|
-
private readonly declaredDeps;
|
|
105
|
-
constructor(bus: EventBus, ownerId: string, declaredDeps: Set<string>);
|
|
106
|
-
publish(event: string, payload?: unknown): void;
|
|
107
|
-
on(event: string, handler: EventHandler): () => void;
|
|
108
|
-
}
|
|
109
|
-
//#endregion
|
|
110
|
-
//#region src/core/event-bus/helpers.d.ts
|
|
111
|
-
/**
|
|
112
|
-
* Creates a typed event definition.
|
|
113
|
-
*
|
|
114
|
-
* @overload Explicit generic — `createEvent<{ version: string }>("ready")`
|
|
115
|
-
* @overload Infer from defaults — `createEvent("ready", { version: "unknown" })`
|
|
116
|
-
*/
|
|
117
|
-
declare function createEvent<T = void>(id: EventId): CreatedEvent<T>;
|
|
118
|
-
declare function createEvent<T>(id: EventId, defaults: T): CreatedEvent<T>;
|
|
119
|
-
//#endregion
|
|
120
4
|
//#region src/core/feature/enums.d.ts
|
|
121
5
|
declare enum FeatureStatus {
|
|
122
6
|
NONE = "none",
|
|
@@ -134,25 +18,18 @@ declare enum FeatureStatus {
|
|
|
134
18
|
//#endregion
|
|
135
19
|
//#region src/core/view/types.d.ts
|
|
136
20
|
type ViewId = string;
|
|
137
|
-
/**
|
|
138
|
-
interface
|
|
21
|
+
/** Runtime view registry entry — injected by CLI via __ELECTRO_VIEW_REGISTRY__. */
|
|
22
|
+
interface ViewRegistryEntry {
|
|
139
23
|
id: ViewId;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
webPreferences?: WebPreferences;
|
|
143
|
-
}
|
|
144
|
-
/** Config for dynamic views (no renderer entry, programmatic). */
|
|
145
|
-
interface DynamicViewConfig {
|
|
146
|
-
id: ViewId;
|
|
147
|
-
webPreferences?: WebPreferences;
|
|
24
|
+
hasRenderer: boolean;
|
|
25
|
+
webPreferences?: Record<string, unknown>;
|
|
148
26
|
}
|
|
149
|
-
type ViewConfig = RendererViewConfig | DynamicViewConfig;
|
|
150
27
|
/** A WebContentsView augmented with `load()` for renderer-linked views. */
|
|
151
28
|
type ElectroView = WebContentsView & {
|
|
152
29
|
load(): Promise<void>;
|
|
153
30
|
};
|
|
154
31
|
/** Public interface — hides the View class. */
|
|
155
|
-
interface
|
|
32
|
+
interface ViewInstance {
|
|
156
33
|
readonly id: ViewId;
|
|
157
34
|
/** Create the WebContentsView. Idempotent: returns existing if alive. */
|
|
158
35
|
create(): ElectroView;
|
|
@@ -161,13 +38,6 @@ interface CreatedView {
|
|
|
161
38
|
/** Destroy the WebContentsView and clear refs. */
|
|
162
39
|
destroy(): void;
|
|
163
40
|
}
|
|
164
|
-
/** Type-erased interface for managers. */
|
|
165
|
-
interface ViewInstance {
|
|
166
|
-
readonly id: ViewId;
|
|
167
|
-
create(): ElectroView;
|
|
168
|
-
view(): ElectroView | null;
|
|
169
|
-
destroy(): void;
|
|
170
|
-
}
|
|
171
41
|
//#endregion
|
|
172
42
|
//#region src/core/view/manager.d.ts
|
|
173
43
|
/**
|
|
@@ -190,24 +60,28 @@ interface WindowConfig<TApi = void> {
|
|
|
190
60
|
options?: BaseWindowConstructorOptions;
|
|
191
61
|
api?: (window: BaseWindow) => TApi;
|
|
192
62
|
}
|
|
193
|
-
/**
|
|
194
|
-
interface
|
|
63
|
+
/** Base window interface (without API methods). */
|
|
64
|
+
interface WindowBase {
|
|
195
65
|
readonly id: WindowId;
|
|
196
66
|
/** Create the BaseWindow. Idempotent: returns existing if alive. */
|
|
197
67
|
create(): BaseWindow;
|
|
198
68
|
/** The live BaseWindow, or null if not yet created / destroyed. */
|
|
199
69
|
readonly window: BaseWindow | null;
|
|
200
|
-
/** The typed API, or null if not yet created / destroyed. */
|
|
201
|
-
readonly api: TApi | null;
|
|
202
70
|
/** Destroy the BaseWindow and clear refs. */
|
|
203
71
|
destroy(): void;
|
|
204
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Public interface — API methods are mixed directly onto the object.
|
|
75
|
+
* Access API methods directly: `window.show()` instead of `window.api?.show()`.
|
|
76
|
+
*/
|
|
77
|
+
type CreatedWindow<TApi = void> = WindowBase & (TApi extends void ? {} : TApi) & {
|
|
78
|
+
/** @internal Phantom type for API type inference. */readonly __apiType?: TApi;
|
|
79
|
+
};
|
|
205
80
|
/** Type-erased interface for managers. */
|
|
206
81
|
interface WindowInstance {
|
|
207
82
|
readonly id: WindowId;
|
|
208
83
|
create(): BaseWindow;
|
|
209
84
|
readonly window: BaseWindow | null;
|
|
210
|
-
readonly api: unknown;
|
|
211
85
|
destroy(): void;
|
|
212
86
|
}
|
|
213
87
|
//#endregion
|
|
@@ -224,6 +98,99 @@ declare class WindowManager {
|
|
|
224
98
|
destroyAll(): void;
|
|
225
99
|
}
|
|
226
100
|
//#endregion
|
|
101
|
+
//#region src/core/event-bus/types.d.ts
|
|
102
|
+
type EventHandler = (payload: unknown) => void;
|
|
103
|
+
type EventSubscription = {
|
|
104
|
+
channel: string;
|
|
105
|
+
handler: EventHandler;
|
|
106
|
+
ownerId: string;
|
|
107
|
+
};
|
|
108
|
+
type EventId = string;
|
|
109
|
+
/**
|
|
110
|
+
* Type-erased event interface for heterogeneous collections.
|
|
111
|
+
*/
|
|
112
|
+
interface EventInstance {
|
|
113
|
+
readonly id: EventId;
|
|
114
|
+
readonly defaults: unknown;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Public interface returned by {@link createEvent}.
|
|
118
|
+
*
|
|
119
|
+
* Generic parameter preserves payload type for codegen inference
|
|
120
|
+
* (`_EventPayload<T>` infers `T` from `payload()` phantom method).
|
|
121
|
+
*/
|
|
122
|
+
interface CreatedEvent<T = void> extends EventInstance {
|
|
123
|
+
readonly id: EventId;
|
|
124
|
+
readonly defaults: T | undefined;
|
|
125
|
+
/** @internal Phantom method for codegen type extraction. Never called. */
|
|
126
|
+
payload(): T;
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/core/event-bus/event-bus.d.ts
|
|
130
|
+
declare class EventBus {
|
|
131
|
+
private readonly subscriptions;
|
|
132
|
+
publish(channel: string, payload?: unknown): void;
|
|
133
|
+
subscribe(channel: string, handler: EventHandler, ownerId: string): () => void;
|
|
134
|
+
removeByOwner(ownerId: string): void;
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/core/service/enums.d.ts
|
|
138
|
+
declare enum ServiceScope {
|
|
139
|
+
PRIVATE = "private",
|
|
140
|
+
INTERNAL = "internal",
|
|
141
|
+
EXPOSED = "exposed"
|
|
142
|
+
}
|
|
143
|
+
declare enum ServiceStatus {
|
|
144
|
+
REGISTERED = "registered",
|
|
145
|
+
ACTIVE = "active",
|
|
146
|
+
DESTROYED = "destroyed"
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/core/service/types.d.ts
|
|
150
|
+
type ServiceId = string;
|
|
151
|
+
type ServiceConfig<Scope extends ServiceScope = ServiceScope, TApi = unknown, TId extends ServiceId = ServiceId> = {
|
|
152
|
+
id: TId;
|
|
153
|
+
scope?: Scope;
|
|
154
|
+
api: (ctx: FeatureContext<_ServiceOwner<TId>, TId>) => TApi;
|
|
155
|
+
};
|
|
156
|
+
interface ServiceInfo {
|
|
157
|
+
serviceId: ServiceId;
|
|
158
|
+
scope: ServiceScope;
|
|
159
|
+
state: ServiceStatus;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Type-erased service interface for heterogeneous collections.
|
|
163
|
+
*
|
|
164
|
+
* Mirrors the public API of {@link Service} without exposing private fields.
|
|
165
|
+
* Used internally by {@link ServiceManager} and {@link FeatureConfig}.
|
|
166
|
+
*/
|
|
167
|
+
interface ServiceInstance {
|
|
168
|
+
readonly id: ServiceId;
|
|
169
|
+
readonly scope: ServiceScope;
|
|
170
|
+
build(ctx: FeatureContext<any>): void;
|
|
171
|
+
destroy(): void;
|
|
172
|
+
api(): unknown;
|
|
173
|
+
status(): ServiceInfo;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Public interface returned by {@link createService}.
|
|
177
|
+
*
|
|
178
|
+
* Hides class internals so consumers can safely
|
|
179
|
+
* `export const myService = createService({...})` without TypeScript
|
|
180
|
+
* "cannot be named" errors in declaration emit.
|
|
181
|
+
*
|
|
182
|
+
* Generic parameters preserve scope + API types for codegen inference
|
|
183
|
+
* (`_SvcApi<T>` infers from `api()`).
|
|
184
|
+
*/
|
|
185
|
+
interface CreatedService<Scope extends ServiceScope = ServiceScope, TApi = unknown> {
|
|
186
|
+
readonly id: ServiceId;
|
|
187
|
+
readonly scope: Scope;
|
|
188
|
+
build(ctx: FeatureContext<any>): void;
|
|
189
|
+
destroy(): void;
|
|
190
|
+
api(): TApi | null;
|
|
191
|
+
status(): ServiceInfo;
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
227
194
|
//#region src/core/task/enums.d.ts
|
|
228
195
|
declare enum TaskOverlapStrategy {
|
|
229
196
|
Skip = "skip",
|
|
@@ -275,231 +242,43 @@ type TaskConfig<TId extends TaskId, TPayload = void> = {
|
|
|
275
242
|
*/
|
|
276
243
|
interface TaskInstance {
|
|
277
244
|
readonly id: TaskId;
|
|
278
|
-
enable(ctx: FeatureContext<any>): void;
|
|
279
|
-
disable(mode?: StopMode): void;
|
|
280
|
-
start(payload?: unknown): Promise<void>;
|
|
281
|
-
queue(payload: unknown): void;
|
|
282
|
-
stop(): void;
|
|
283
|
-
clear(): void;
|
|
284
|
-
status(): TaskStatusInfo;
|
|
285
|
-
}
|
|
286
|
-
interface TaskStatusInfo {
|
|
287
|
-
taskId: string;
|
|
288
|
-
state: TaskStatus;
|
|
289
|
-
running: boolean;
|
|
290
|
-
queueSize: number;
|
|
291
|
-
lastRunAt: number | null;
|
|
292
|
-
lastSuccessAt: number | null;
|
|
293
|
-
lastErrorAt: number | null;
|
|
294
|
-
lastError: Error | null;
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Public interface returned by {@link createTask}.
|
|
298
|
-
*
|
|
299
|
-
* Hides class internals (private fields) so consumers can safely
|
|
300
|
-
* `export const myTask = createTask({...})` without TypeScript
|
|
301
|
-
* "cannot be named" errors in declaration emit.
|
|
302
|
-
*
|
|
303
|
-
* Generic parameters preserve payload type for codegen inference
|
|
304
|
-
* (`_TaskPayload<T>` infers `TPayload` from `start(payload?)`).
|
|
305
|
-
*/
|
|
306
|
-
interface CreatedTask<TId extends TaskId = TaskId, TPayload = void> {
|
|
307
|
-
readonly id: TId;
|
|
308
|
-
enable(ctx: FeatureContext<any>): void;
|
|
309
|
-
disable(mode?: StopMode): void;
|
|
310
|
-
start(payload?: TPayload): Promise<void>;
|
|
311
|
-
queue(payload: TPayload): void;
|
|
312
|
-
stop(): void;
|
|
313
|
-
clear(): void;
|
|
314
|
-
status(): TaskStatusInfo;
|
|
315
|
-
}
|
|
316
|
-
//#endregion
|
|
317
|
-
//#region src/core/task/handle.d.ts
|
|
318
|
-
/**
|
|
319
|
-
* Ergonomic handle for a single {@link Task}.
|
|
320
|
-
*
|
|
321
|
-
* Provides per-task control: start, queue, stop, enable, disable, clear, status.
|
|
322
|
-
* Created by Feature and bound to `ctx.getTask(name)`.
|
|
323
|
-
*/
|
|
324
|
-
declare class TaskHandle<TPayload = unknown> {
|
|
325
|
-
private readonly task;
|
|
326
|
-
private readonly ctx;
|
|
327
|
-
constructor(task: TaskInstance, ctx?: FeatureContext<any> | undefined);
|
|
328
|
-
/** Execute immediately (respects overlap policy). */
|
|
329
|
-
start(payload?: TPayload): Promise<void>;
|
|
330
|
-
/** Push payload to FIFO queue, processes sequentially. */
|
|
331
|
-
queue(payload: TPayload): void;
|
|
332
|
-
/** Abort current execution. Queue continues processing. */
|
|
333
|
-
stop(): void;
|
|
334
|
-
/** Re-enable the task (cron, ready for start/queue). */
|
|
335
|
-
enable(): void;
|
|
336
|
-
/** Abort current + clear queue + stop cron. */
|
|
337
|
-
disable(mode?: StopMode): void;
|
|
338
|
-
/** Clear the FIFO queue without stopping current execution. */
|
|
339
|
-
clear(): void;
|
|
340
|
-
/** Snapshot of the task's current state. */
|
|
341
|
-
status(): TaskStatusInfo;
|
|
342
|
-
}
|
|
343
|
-
//#endregion
|
|
344
|
-
//#region src/core/types.d.ts
|
|
345
|
-
/**
|
|
346
|
-
* Declaration-merging registry.
|
|
347
|
-
* Codegen populates this via `declare module "@cordy/electro"`.
|
|
348
|
-
*
|
|
349
|
-
* Each key is a feature ID mapping to its services, tasks, and dependencies.
|
|
350
|
-
*/
|
|
351
|
-
interface FeatureMap {}
|
|
352
|
-
/** Maps service ID → owning feature ID. Populated by codegen. */
|
|
353
|
-
interface ServiceOwnerMap {}
|
|
354
|
-
/** Maps task ID → owning feature ID. Populated by codegen. */
|
|
355
|
-
interface TaskOwnerMap {}
|
|
356
|
-
/** Declaration-merging registry for view types. Codegen populates this. */
|
|
357
|
-
interface ViewMap {}
|
|
358
|
-
/** Declaration-merging registry for window API types. Codegen populates this. */
|
|
359
|
-
interface WindowApiMap {}
|
|
360
|
-
/** Resolve the owning feature ID for a service. Falls back to `string` (→ BaseContext). */
|
|
361
|
-
type _ServiceOwner<TId extends string> = TId extends keyof ServiceOwnerMap ? ServiceOwnerMap[TId] : string;
|
|
362
|
-
/** Resolve the owning feature ID for a task. Falls back to `string` (→ BaseContext). */
|
|
363
|
-
type _TaskOwner<TId extends string> = TId extends keyof TaskOwnerMap ? TaskOwnerMap[TId] : string;
|
|
364
|
-
type _SuggestViewKeys = (keyof ViewMap & string) | (string & {});
|
|
365
|
-
type _SuggestWindowKeys = (keyof WindowApiMap & string) | (string & {});
|
|
366
|
-
type _ResolveWindowApi<K extends string> = K extends keyof WindowApiMap ? WindowApiMap[K] : unknown;
|
|
367
|
-
/** Extract the dependency IDs union for a feature. */
|
|
368
|
-
type _DepIds<FId> = FId extends keyof FeatureMap ? FeatureMap[FId]["dependencies"] : never;
|
|
369
|
-
/** Own service keys for a feature. */
|
|
370
|
-
type _OwnSvcKeys<FId> = FId extends keyof FeatureMap ? keyof FeatureMap[FId]["services"] & string : never;
|
|
371
|
-
/** Distributive helper — maps a single dep ID to its qualified service keys. */
|
|
372
|
-
type _DepSvcOf<D> = D extends keyof FeatureMap & string ? `${D}:${keyof FeatureMap[D]["services"] & string}` : never;
|
|
373
|
-
/** Qualified dependency service keys ("dep:svc"), distributes over the deps union. */
|
|
374
|
-
type _DepSvcKeys<FId> = _DepSvcOf<_DepIds<FId>>;
|
|
375
|
-
/** Resolve a service type from own or dependency services. */
|
|
376
|
-
type _ResolveSvc<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["services"] ? FeatureMap[FId]["services"][K] : K extends `${infer D}:${infer S}` ? D extends _DepIds<FId> & keyof FeatureMap ? S extends keyof FeatureMap[D]["services"] ? FeatureMap[D]["services"][S] : unknown : unknown : unknown : unknown;
|
|
377
|
-
/** Resolve a task type from own tasks. FeatureMap stores payloads; wraps in TaskHandle. */
|
|
378
|
-
type _ResolveTask<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["tasks"] ? TaskHandle<FeatureMap[FId]["tasks"][K]> : unknown : unknown;
|
|
379
|
-
/** Resolve a feature handle from dependency features. */
|
|
380
|
-
type _ResolveFeature<FId, K extends string> = FId extends keyof FeatureMap ? K extends _DepIds<FId> & string ? FeatureHandle : unknown : unknown;
|
|
381
|
-
type _SuggestSvcKeys<FId> = _OwnSvcKeys<FId> | _DepSvcKeys<FId>;
|
|
382
|
-
type _SuggestTaskKeys<FId> = FId extends keyof FeatureMap ? keyof FeatureMap[FId]["tasks"] & string : never;
|
|
383
|
-
type _SuggestDepKeys<FId> = _DepIds<FId> & string;
|
|
384
|
-
/** Own event keys for a feature. */
|
|
385
|
-
type _OwnEventKeys<FId> = FId extends keyof FeatureMap ? keyof FeatureMap[FId]["events"] & string : never;
|
|
386
|
-
/** Distributive helper — maps a single dep ID to its qualified event keys. */
|
|
387
|
-
type _DepEventOf<D> = D extends keyof FeatureMap & string ? `${D}:${keyof FeatureMap[D]["events"] & string}` : never;
|
|
388
|
-
/** Qualified dependency event keys ("dep:event"), distributes over the deps union. */
|
|
389
|
-
type _DepEventKeys<FId> = _DepEventOf<_DepIds<FId>>;
|
|
390
|
-
/** Resolve own event payload. */
|
|
391
|
-
type _ResolveOwnEvent<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["events"] ? FeatureMap[FId]["events"][K] : unknown : unknown;
|
|
392
|
-
/** Resolve any event payload (own or dep). */
|
|
393
|
-
type _ResolveEvent<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["events"] ? FeatureMap[FId]["events"][K] : K extends `${infer D}:${infer E}` ? D extends _DepIds<FId> & keyof FeatureMap ? E extends keyof FeatureMap[D]["events"] ? FeatureMap[D]["events"][E] : unknown : unknown : unknown : unknown;
|
|
394
|
-
/** All service keys across all features (mapped type distributes over each feature). */
|
|
395
|
-
type _AllSvcKeys = { [F in keyof FeatureMap]: keyof FeatureMap[F]["services"] & string }[keyof FeatureMap];
|
|
396
|
-
/** All task keys across all features (mapped type distributes over each feature). */
|
|
397
|
-
type _AllTaskKeys = { [F in keyof FeatureMap]: keyof FeatureMap[F]["tasks"] & string }[keyof FeatureMap];
|
|
398
|
-
/** All feature IDs. */
|
|
399
|
-
type _AllFeatureIds = keyof FeatureMap & string;
|
|
400
|
-
/** All event keys across all features. */
|
|
401
|
-
type _AllEventKeys = { [F in keyof FeatureMap]: keyof FeatureMap[F]["events"] & string }[keyof FeatureMap];
|
|
402
|
-
type _SuggestAllSvc = _AllSvcKeys | (string & {});
|
|
403
|
-
type _SuggestAllTask = _AllTaskKeys | (string & {});
|
|
404
|
-
type _SuggestAllFeature = _AllFeatureIds | (string & {});
|
|
405
|
-
type _SuggestAllEvent = _AllEventKeys | (string & {});
|
|
406
|
-
/** Flat resolve for unscoped service lookup. */
|
|
407
|
-
type _FlatResolveSvc<K extends string> = { [F in keyof FeatureMap]: K extends keyof FeatureMap[F]["services"] ? FeatureMap[F]["services"][K] : never }[keyof FeatureMap] extends infer U ? [U] extends [never] ? unknown : U : unknown;
|
|
408
|
-
/** Flat resolve for unscoped task lookup. FeatureMap stores payloads; wraps in TaskHandle. */
|
|
409
|
-
type _FlatResolveTask<K extends string> = { [F in keyof FeatureMap]: K extends keyof FeatureMap[F]["tasks"] ? TaskHandle<FeatureMap[F]["tasks"][K]> : never }[keyof FeatureMap] extends infer U ? [U] extends [never] ? unknown : U : unknown;
|
|
410
|
-
/** Flat resolve for unscoped feature lookup. */
|
|
411
|
-
type _FlatResolveFeature<K extends string> = K extends keyof FeatureMap ? FeatureHandle : unknown;
|
|
412
|
-
/** Scoped context — used when `FId` is a concrete feature key. */
|
|
413
|
-
type TypedContext<FId extends keyof FeatureMap, ExcludeSvc extends string = never, ExcludeTask extends string = never> = {
|
|
414
|
-
signal: AbortSignal;
|
|
415
|
-
logger: LoggerContext;
|
|
416
|
-
getService: <K extends Exclude<_SuggestSvcKeys<FId>, ExcludeSvc>>(name: K) => _ResolveSvc<FId, K & string>;
|
|
417
|
-
getTask: <K extends Exclude<_SuggestTaskKeys<FId>, ExcludeTask>>(name: K) => _ResolveTask<FId, K & string>;
|
|
418
|
-
getFeature: <K extends _SuggestDepKeys<FId>>(name: K) => _ResolveFeature<FId, K & string>;
|
|
419
|
-
events: {
|
|
420
|
-
publish<K extends _OwnEventKeys<FId>>(event: K, ...args: undefined extends _ResolveOwnEvent<FId, K> ? [payload?: _ResolveOwnEvent<FId, K>] : [payload: _ResolveOwnEvent<FId, K>]): void;
|
|
421
|
-
on<K extends _OwnEventKeys<FId> | _DepEventKeys<FId>>(event: K, handler: (payload: _ResolveEvent<FId, K>) => void): () => void;
|
|
422
|
-
};
|
|
423
|
-
getWindow: <K extends _SuggestWindowKeys>(id: K) => CreatedWindow<_ResolveWindowApi<K & string>> | null;
|
|
424
|
-
createView: <K extends _SuggestViewKeys>(id: K) => ElectroView;
|
|
425
|
-
getView: <K extends _SuggestViewKeys>(id: K) => ElectroView | null;
|
|
426
|
-
};
|
|
427
|
-
/** Unscoped context — flat suggestions from all features. */
|
|
428
|
-
type BaseContext = {
|
|
429
|
-
signal: AbortSignal;
|
|
430
|
-
logger: LoggerContext;
|
|
431
|
-
getService: <K extends _SuggestAllSvc>(name: K) => _FlatResolveSvc<K & string>;
|
|
432
|
-
getTask: <K extends _SuggestAllTask>(name: K) => _FlatResolveTask<K & string>;
|
|
433
|
-
getFeature: <K extends _SuggestAllFeature>(name: K) => _FlatResolveFeature<K & string>;
|
|
434
|
-
events: {
|
|
435
|
-
publish(event: _SuggestAllEvent, payload?: unknown): void;
|
|
436
|
-
on(event: string, handler: (payload: unknown) => void): () => void;
|
|
437
|
-
};
|
|
438
|
-
getWindow: <K extends _SuggestWindowKeys>(id: K) => CreatedWindow<_ResolveWindowApi<K & string>> | null;
|
|
439
|
-
createView: <K extends _SuggestViewKeys>(id: K) => ElectroView;
|
|
440
|
-
getView: <K extends _SuggestViewKeys>(id: K) => ElectroView | null;
|
|
441
|
-
};
|
|
442
|
-
interface LoggerContext {
|
|
443
|
-
debug(code: string, message: string, details?: Record<string, unknown>): void;
|
|
444
|
-
warn(code: string, message: string, details?: Record<string, unknown>): void;
|
|
445
|
-
error(code: string, message: string, details?: Record<string, unknown>): void;
|
|
446
|
-
}
|
|
447
|
-
//#endregion
|
|
448
|
-
//#region src/core/service/enums.d.ts
|
|
449
|
-
declare enum ServiceScope {
|
|
450
|
-
PRIVATE = "private",
|
|
451
|
-
INTERNAL = "internal",
|
|
452
|
-
EXPOSED = "exposed"
|
|
453
|
-
}
|
|
454
|
-
declare enum ServiceStatus {
|
|
455
|
-
REGISTERED = "registered",
|
|
456
|
-
ACTIVE = "active",
|
|
457
|
-
DESTROYED = "destroyed"
|
|
458
|
-
}
|
|
459
|
-
//#endregion
|
|
460
|
-
//#region src/core/service/types.d.ts
|
|
461
|
-
type ServiceId = string;
|
|
462
|
-
type ServiceConfig<Scope extends ServiceScope = ServiceScope, TApi = unknown, TId extends ServiceId = ServiceId> = {
|
|
463
|
-
id: TId;
|
|
464
|
-
scope?: Scope;
|
|
465
|
-
api: (ctx: FeatureContext<_ServiceOwner<TId>, TId>) => TApi;
|
|
466
|
-
};
|
|
467
|
-
interface ServiceInfo {
|
|
468
|
-
serviceId: ServiceId;
|
|
469
|
-
scope: ServiceScope;
|
|
470
|
-
state: ServiceStatus;
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* Type-erased service interface for heterogeneous collections.
|
|
474
|
-
*
|
|
475
|
-
* Mirrors the public API of {@link Service} without exposing private fields.
|
|
476
|
-
* Used internally by {@link ServiceManager} and {@link FeatureConfig}.
|
|
477
|
-
*/
|
|
478
|
-
interface ServiceInstance {
|
|
479
|
-
readonly id: ServiceId;
|
|
480
|
-
readonly scope: ServiceScope;
|
|
481
|
-
build(ctx: FeatureContext<any>): void;
|
|
482
|
-
destroy(): void;
|
|
483
|
-
api(): unknown;
|
|
484
|
-
status(): ServiceInfo;
|
|
245
|
+
enable(ctx: FeatureContext<any>): void;
|
|
246
|
+
disable(mode?: StopMode): void;
|
|
247
|
+
start(payload?: unknown): Promise<void>;
|
|
248
|
+
queue(payload: unknown): void;
|
|
249
|
+
stop(): void;
|
|
250
|
+
clear(): void;
|
|
251
|
+
status(): TaskStatusInfo;
|
|
252
|
+
}
|
|
253
|
+
interface TaskStatusInfo {
|
|
254
|
+
taskId: string;
|
|
255
|
+
state: TaskStatus;
|
|
256
|
+
running: boolean;
|
|
257
|
+
queueSize: number;
|
|
258
|
+
lastRunAt: number | null;
|
|
259
|
+
lastSuccessAt: number | null;
|
|
260
|
+
lastErrorAt: number | null;
|
|
261
|
+
lastError: Error | null;
|
|
485
262
|
}
|
|
486
263
|
/**
|
|
487
|
-
* Public interface returned by {@link
|
|
264
|
+
* Public interface returned by {@link createTask}.
|
|
488
265
|
*
|
|
489
|
-
* Hides class internals so consumers can safely
|
|
490
|
-
* `export const
|
|
266
|
+
* Hides class internals (private fields) so consumers can safely
|
|
267
|
+
* `export const myTask = createTask({...})` without TypeScript
|
|
491
268
|
* "cannot be named" errors in declaration emit.
|
|
492
269
|
*
|
|
493
|
-
* Generic parameters preserve
|
|
494
|
-
* (`
|
|
270
|
+
* Generic parameters preserve payload type for codegen inference
|
|
271
|
+
* (`_TaskPayload<T>` infers `TPayload` from `start(payload?)`).
|
|
495
272
|
*/
|
|
496
|
-
interface
|
|
497
|
-
readonly id:
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
273
|
+
interface CreatedTask<TId extends TaskId = TaskId, TPayload = void> {
|
|
274
|
+
readonly id: TId;
|
|
275
|
+
enable(ctx: FeatureContext<any>): void;
|
|
276
|
+
disable(mode?: StopMode): void;
|
|
277
|
+
start(payload?: TPayload): Promise<void>;
|
|
278
|
+
queue(payload: TPayload): void;
|
|
279
|
+
stop(): void;
|
|
280
|
+
clear(): void;
|
|
281
|
+
status(): TaskStatusInfo;
|
|
503
282
|
}
|
|
504
283
|
//#endregion
|
|
505
284
|
//#region src/core/feature/types.d.ts
|
|
@@ -697,6 +476,219 @@ declare class FeatureHandle {
|
|
|
697
476
|
disable(): Promise<void>;
|
|
698
477
|
}
|
|
699
478
|
//#endregion
|
|
479
|
+
//#region src/core/task/handle.d.ts
|
|
480
|
+
/**
|
|
481
|
+
* Ergonomic handle for a single {@link Task}.
|
|
482
|
+
*
|
|
483
|
+
* Provides per-task control: start, queue, stop, enable, disable, clear, status.
|
|
484
|
+
* Created by Feature and bound to `ctx.getTask(name)`.
|
|
485
|
+
*/
|
|
486
|
+
declare class TaskHandle<TPayload = unknown> {
|
|
487
|
+
private readonly task;
|
|
488
|
+
private readonly ctx;
|
|
489
|
+
constructor(task: TaskInstance, ctx?: FeatureContext<any> | undefined);
|
|
490
|
+
/** Execute immediately (respects overlap policy). */
|
|
491
|
+
start(payload?: TPayload): Promise<void>;
|
|
492
|
+
/** Push payload to FIFO queue, processes sequentially. */
|
|
493
|
+
queue(payload: TPayload): void;
|
|
494
|
+
/** Abort current execution. Queue continues processing. */
|
|
495
|
+
stop(): void;
|
|
496
|
+
/** Re-enable the task (cron, ready for start/queue). */
|
|
497
|
+
enable(): void;
|
|
498
|
+
/** Abort current + clear queue + stop cron. */
|
|
499
|
+
disable(mode?: StopMode): void;
|
|
500
|
+
/** Clear the FIFO queue without stopping current execution. */
|
|
501
|
+
clear(): void;
|
|
502
|
+
/** Snapshot of the task's current state. */
|
|
503
|
+
status(): TaskStatusInfo;
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/core/types.d.ts
|
|
507
|
+
/**
|
|
508
|
+
* Declaration-merging registry.
|
|
509
|
+
* Codegen populates this via `declare module "@cordy/electro"`.
|
|
510
|
+
*
|
|
511
|
+
* Each key is a feature ID mapping to its services, tasks, and dependencies.
|
|
512
|
+
*/
|
|
513
|
+
interface FeatureMap {}
|
|
514
|
+
/** Maps service ID → owning feature ID. Populated by codegen. */
|
|
515
|
+
interface ServiceOwnerMap {}
|
|
516
|
+
/** Maps task ID → owning feature ID. Populated by codegen. */
|
|
517
|
+
interface TaskOwnerMap {}
|
|
518
|
+
/** Declaration-merging registry for view types. Codegen populates this. */
|
|
519
|
+
interface ViewMap {}
|
|
520
|
+
/** Declaration-merging registry for window API types. Codegen populates this. */
|
|
521
|
+
interface WindowApiMap {}
|
|
522
|
+
/** Resolve the owning feature ID for a service. Falls back to `string` (→ BaseContext). */
|
|
523
|
+
type _ServiceOwner<TId extends string> = TId extends keyof ServiceOwnerMap ? ServiceOwnerMap[TId] : string;
|
|
524
|
+
/** Resolve the owning feature ID for a task. Falls back to `string` (→ BaseContext). */
|
|
525
|
+
type _TaskOwner<TId extends string> = TId extends keyof TaskOwnerMap ? TaskOwnerMap[TId] : string;
|
|
526
|
+
type _SuggestViewKeys = (keyof ViewMap & string) | (string & {});
|
|
527
|
+
type _SuggestWindowKeys = (keyof WindowApiMap & string) | (string & {});
|
|
528
|
+
type _ResolveWindowApi<K extends string> = K extends keyof WindowApiMap ? WindowApiMap[K] : unknown;
|
|
529
|
+
/** Extract the dependency IDs union for a feature. */
|
|
530
|
+
type _DepIds<FId> = FId extends keyof FeatureMap ? FeatureMap[FId]["dependencies"] : never;
|
|
531
|
+
/** Own service keys for a feature. */
|
|
532
|
+
type _OwnSvcKeys<FId> = FId extends keyof FeatureMap ? keyof FeatureMap[FId]["services"] & string : never;
|
|
533
|
+
/** Distributive helper — maps a single dep ID to its qualified service keys. */
|
|
534
|
+
type _DepSvcOf<D> = D extends keyof FeatureMap & string ? `${D}:${keyof FeatureMap[D]["services"] & string}` : never;
|
|
535
|
+
/** Qualified dependency service keys ("dep:svc"), distributes over the deps union. */
|
|
536
|
+
type _DepSvcKeys<FId> = _DepSvcOf<_DepIds<FId>>;
|
|
537
|
+
/** Resolve a service type from own or dependency services. */
|
|
538
|
+
type _ResolveSvc<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["services"] ? FeatureMap[FId]["services"][K] : K extends `${infer D}:${infer S}` ? D extends _DepIds<FId> & keyof FeatureMap ? S extends keyof FeatureMap[D]["services"] ? FeatureMap[D]["services"][S] : unknown : unknown : unknown : unknown;
|
|
539
|
+
/** Resolve a task type from own tasks. FeatureMap stores payloads; wraps in TaskHandle. */
|
|
540
|
+
type _ResolveTask<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["tasks"] ? TaskHandle<FeatureMap[FId]["tasks"][K]> : unknown : unknown;
|
|
541
|
+
/** Resolve a feature handle from dependency features. */
|
|
542
|
+
type _ResolveFeature<FId, K extends string> = FId extends keyof FeatureMap ? K extends _DepIds<FId> & string ? FeatureHandle : unknown : unknown;
|
|
543
|
+
type _SuggestSvcKeys<FId> = _OwnSvcKeys<FId> | _DepSvcKeys<FId>;
|
|
544
|
+
type _SuggestTaskKeys<FId> = FId extends keyof FeatureMap ? keyof FeatureMap[FId]["tasks"] & string : never;
|
|
545
|
+
type _SuggestDepKeys<FId> = _DepIds<FId> & string;
|
|
546
|
+
/** Own event keys for a feature. */
|
|
547
|
+
type _OwnEventKeys<FId> = FId extends keyof FeatureMap ? keyof FeatureMap[FId]["events"] & string : never;
|
|
548
|
+
/** Distributive helper — maps a single dep ID to its qualified event keys. */
|
|
549
|
+
type _DepEventOf<D> = D extends keyof FeatureMap & string ? `${D}:${keyof FeatureMap[D]["events"] & string}` : never;
|
|
550
|
+
/** Qualified dependency event keys ("dep:event"), distributes over the deps union. */
|
|
551
|
+
type _DepEventKeys<FId> = _DepEventOf<_DepIds<FId>>;
|
|
552
|
+
/** Resolve own event payload. */
|
|
553
|
+
type _ResolveOwnEvent<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["events"] ? FeatureMap[FId]["events"][K] : unknown : unknown;
|
|
554
|
+
/** Resolve any event payload (own or dep). */
|
|
555
|
+
type _ResolveEvent<FId, K extends string> = FId extends keyof FeatureMap ? K extends keyof FeatureMap[FId]["events"] ? FeatureMap[FId]["events"][K] : K extends `${infer D}:${infer E}` ? D extends _DepIds<FId> & keyof FeatureMap ? E extends keyof FeatureMap[D]["events"] ? FeatureMap[D]["events"][E] : unknown : unknown : unknown : unknown;
|
|
556
|
+
/** All service keys across all features (mapped type distributes over each feature). */
|
|
557
|
+
type _AllSvcKeys = { [F in keyof FeatureMap]: keyof FeatureMap[F]["services"] & string }[keyof FeatureMap];
|
|
558
|
+
/** All task keys across all features (mapped type distributes over each feature). */
|
|
559
|
+
type _AllTaskKeys = { [F in keyof FeatureMap]: keyof FeatureMap[F]["tasks"] & string }[keyof FeatureMap];
|
|
560
|
+
/** All feature IDs. */
|
|
561
|
+
type _AllFeatureIds = keyof FeatureMap & string;
|
|
562
|
+
/** All event keys across all features. */
|
|
563
|
+
type _AllEventKeys = { [F in keyof FeatureMap]: keyof FeatureMap[F]["events"] & string }[keyof FeatureMap];
|
|
564
|
+
type _SuggestAllSvc = _AllSvcKeys | (string & {});
|
|
565
|
+
type _SuggestAllTask = _AllTaskKeys | (string & {});
|
|
566
|
+
type _SuggestAllFeature = _AllFeatureIds | (string & {});
|
|
567
|
+
type _SuggestAllEvent = _AllEventKeys | (string & {});
|
|
568
|
+
/** Flat resolve for unscoped service lookup. */
|
|
569
|
+
type _FlatResolveSvc<K extends string> = { [F in keyof FeatureMap]: K extends keyof FeatureMap[F]["services"] ? FeatureMap[F]["services"][K] : never }[keyof FeatureMap] extends infer U ? [U] extends [never] ? unknown : U : unknown;
|
|
570
|
+
/** Flat resolve for unscoped task lookup. FeatureMap stores payloads; wraps in TaskHandle. */
|
|
571
|
+
type _FlatResolveTask<K extends string> = { [F in keyof FeatureMap]: K extends keyof FeatureMap[F]["tasks"] ? TaskHandle<FeatureMap[F]["tasks"][K]> : never }[keyof FeatureMap] extends infer U ? [U] extends [never] ? unknown : U : unknown;
|
|
572
|
+
/** Flat resolve for unscoped feature lookup. */
|
|
573
|
+
type _FlatResolveFeature<K extends string> = K extends keyof FeatureMap ? FeatureHandle : unknown;
|
|
574
|
+
/** Scoped context — used when `FId` is a concrete feature key. */
|
|
575
|
+
type TypedContext<FId extends keyof FeatureMap, ExcludeSvc extends string = never, ExcludeTask extends string = never> = {
|
|
576
|
+
signal: AbortSignal;
|
|
577
|
+
logger: LoggerContext;
|
|
578
|
+
getService: <K extends Exclude<_SuggestSvcKeys<FId>, ExcludeSvc>>(name: K) => _ResolveSvc<FId, K & string>;
|
|
579
|
+
getTask: <K extends Exclude<_SuggestTaskKeys<FId>, ExcludeTask>>(name: K) => _ResolveTask<FId, K & string>;
|
|
580
|
+
getFeature: <K extends _SuggestDepKeys<FId>>(name: K) => _ResolveFeature<FId, K & string>;
|
|
581
|
+
events: {
|
|
582
|
+
publish<K extends _OwnEventKeys<FId>>(event: K, ...args: undefined extends _ResolveOwnEvent<FId, K> ? [payload?: _ResolveOwnEvent<FId, K>] : [payload: _ResolveOwnEvent<FId, K>]): void;
|
|
583
|
+
on<K extends _OwnEventKeys<FId> | _DepEventKeys<FId>>(event: K, handler: (payload: _ResolveEvent<FId, K>) => void): () => void;
|
|
584
|
+
};
|
|
585
|
+
getWindow: <K extends _SuggestWindowKeys>(id: K) => CreatedWindow<_ResolveWindowApi<K & string>> | null;
|
|
586
|
+
createView: <K extends _SuggestViewKeys>(id: K) => ElectroView;
|
|
587
|
+
getView: <K extends _SuggestViewKeys>(id: K) => ElectroView | null;
|
|
588
|
+
};
|
|
589
|
+
/** Unscoped context — flat suggestions from all features. */
|
|
590
|
+
type BaseContext = {
|
|
591
|
+
signal: AbortSignal;
|
|
592
|
+
logger: LoggerContext;
|
|
593
|
+
getService: <K extends _SuggestAllSvc>(name: K) => _FlatResolveSvc<K & string>;
|
|
594
|
+
getTask: <K extends _SuggestAllTask>(name: K) => _FlatResolveTask<K & string>;
|
|
595
|
+
getFeature: <K extends _SuggestAllFeature>(name: K) => _FlatResolveFeature<K & string>;
|
|
596
|
+
events: {
|
|
597
|
+
publish(event: _SuggestAllEvent, payload?: unknown): void;
|
|
598
|
+
on(event: string, handler: (payload: unknown) => void): () => void;
|
|
599
|
+
};
|
|
600
|
+
getWindow: <K extends _SuggestWindowKeys>(id: K) => CreatedWindow<_ResolveWindowApi<K & string>> | null;
|
|
601
|
+
createView: <K extends _SuggestViewKeys>(id: K) => ElectroView;
|
|
602
|
+
getView: <K extends _SuggestViewKeys>(id: K) => ElectroView | null;
|
|
603
|
+
};
|
|
604
|
+
interface LoggerContext {
|
|
605
|
+
debug(code: string, message: string, details?: Record<string, unknown>): void;
|
|
606
|
+
warn(code: string, message: string, details?: Record<string, unknown>): void;
|
|
607
|
+
error(code: string, message: string, details?: Record<string, unknown>): void;
|
|
608
|
+
}
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region src/config/types.d.ts
|
|
611
|
+
declare const RUNTIME_BRAND: unique symbol;
|
|
612
|
+
declare const VIEW_BRAND: unique symbol;
|
|
613
|
+
declare const CONFIG_BRAND: unique symbol;
|
|
614
|
+
interface RuntimeDefinition {
|
|
615
|
+
readonly [RUNTIME_BRAND]: true;
|
|
616
|
+
readonly entry: string;
|
|
617
|
+
readonly vite?: UserConfig;
|
|
618
|
+
/** @internal Caller path captured by defineRuntime(). */
|
|
619
|
+
readonly __source: string;
|
|
620
|
+
}
|
|
621
|
+
interface ViewDefinition {
|
|
622
|
+
readonly [VIEW_BRAND]: true;
|
|
623
|
+
readonly name: string;
|
|
624
|
+
readonly entry?: string;
|
|
625
|
+
readonly features?: readonly string[];
|
|
626
|
+
readonly vite?: UserConfig;
|
|
627
|
+
readonly preload?: string;
|
|
628
|
+
readonly webPreferences?: Record<string, unknown>;
|
|
629
|
+
/** @internal Caller path captured by defineView(). */
|
|
630
|
+
readonly __source: string;
|
|
631
|
+
}
|
|
632
|
+
interface ElectroConfig {
|
|
633
|
+
readonly [CONFIG_BRAND]: true;
|
|
634
|
+
readonly runtime: RuntimeDefinition;
|
|
635
|
+
readonly views?: readonly ViewDefinition[];
|
|
636
|
+
}
|
|
637
|
+
interface DefineRuntimeInput {
|
|
638
|
+
entry: string;
|
|
639
|
+
vite?: UserConfig;
|
|
640
|
+
}
|
|
641
|
+
/** Suggests known feature IDs from FeatureMap while still allowing arbitrary strings. */
|
|
642
|
+
type SuggestFeatureId = (keyof FeatureMap & string) | (string & {});
|
|
643
|
+
interface DefineViewInput {
|
|
644
|
+
name: string;
|
|
645
|
+
entry?: string;
|
|
646
|
+
features?: readonly SuggestFeatureId[];
|
|
647
|
+
vite?: UserConfig;
|
|
648
|
+
preload?: string;
|
|
649
|
+
webPreferences?: Record<string, unknown>;
|
|
650
|
+
}
|
|
651
|
+
interface DefineConfigInput {
|
|
652
|
+
runtime: RuntimeDefinition;
|
|
653
|
+
views?: readonly ViewDefinition[];
|
|
654
|
+
}
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/config/define-config.d.ts
|
|
657
|
+
declare function defineConfig(input: DefineConfigInput): ElectroConfig;
|
|
658
|
+
//#endregion
|
|
659
|
+
//#region src/config/define-runtime.d.ts
|
|
660
|
+
declare function defineRuntime(input: DefineRuntimeInput): RuntimeDefinition;
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/config/define-view.d.ts
|
|
663
|
+
declare function defineView(input: DefineViewInput): ViewDefinition;
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/core/event-bus/accessor.d.ts
|
|
666
|
+
/**
|
|
667
|
+
* Scoped event access per feature.
|
|
668
|
+
*
|
|
669
|
+
* - `publish("name", payload)` -> publishes as `"ownerId:name"`
|
|
670
|
+
* - `on("dep:name", handler)` -> validates `dep` is a declared dependency
|
|
671
|
+
* - `on("name", handler)` -> subscribes to own `"ownerId:name"`
|
|
672
|
+
*/
|
|
673
|
+
declare class EventAccessor {
|
|
674
|
+
private readonly bus;
|
|
675
|
+
private readonly ownerId;
|
|
676
|
+
private readonly declaredDeps;
|
|
677
|
+
constructor(bus: EventBus, ownerId: string, declaredDeps: Set<string>);
|
|
678
|
+
publish(event: string, payload?: unknown): void;
|
|
679
|
+
on(event: string, handler: EventHandler): () => void;
|
|
680
|
+
}
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region src/core/event-bus/helpers.d.ts
|
|
683
|
+
/**
|
|
684
|
+
* Creates a typed event definition.
|
|
685
|
+
*
|
|
686
|
+
* @overload Explicit generic — `createEvent<{ version: string }>("ready")`
|
|
687
|
+
* @overload Infer from defaults — `createEvent("ready", { version: "unknown" })`
|
|
688
|
+
*/
|
|
689
|
+
declare function createEvent<T = void>(id: EventId): CreatedEvent<T>;
|
|
690
|
+
declare function createEvent<T>(id: EventId, defaults: T): CreatedEvent<T>;
|
|
691
|
+
//#endregion
|
|
700
692
|
//#region src/core/feature/helpers.d.ts
|
|
701
693
|
/**
|
|
702
694
|
* Method for creating a feature
|
|
@@ -741,7 +733,6 @@ declare class Logger implements LoggerContext {
|
|
|
741
733
|
type RuntimeConfig = {
|
|
742
734
|
features?: FeatureConfig<any>[];
|
|
743
735
|
windows?: WindowInstance[];
|
|
744
|
-
views?: ViewInstance[];
|
|
745
736
|
logger?: {
|
|
746
737
|
handlers?: LogHandler[];
|
|
747
738
|
};
|
|
@@ -791,16 +782,6 @@ declare function createTask<TId extends TaskId, TPayload = void>(config: TaskCon
|
|
|
791
782
|
*/
|
|
792
783
|
declare function createWindow<TApi = void>(config: WindowConfig<TApi>): CreatedWindow<TApi>;
|
|
793
784
|
//#endregion
|
|
794
|
-
//#region src/core/view/helpers.d.ts
|
|
795
|
-
/**
|
|
796
|
-
* Creates a {@link View} instance from a configuration object.
|
|
797
|
-
*
|
|
798
|
-
* @param config - View configuration with `id`, and either `renderer` (for Vite-built views) or `webPreferences` (for dynamic views).
|
|
799
|
-
* @returns A new `View` instance ready for registration.
|
|
800
|
-
* @throws If `config.id` is empty.
|
|
801
|
-
*/
|
|
802
|
-
declare function createView(config: ViewConfig): CreatedView;
|
|
803
|
-
//#endregion
|
|
804
785
|
//#region src/policy/types.d.ts
|
|
805
786
|
/** Outcome of a policy check. */
|
|
806
787
|
declare enum PolicyDecision {
|
|
@@ -839,4 +820,4 @@ declare class PolicyEngine {
|
|
|
839
820
|
getViewNames(): string[];
|
|
840
821
|
}
|
|
841
822
|
//#endregion
|
|
842
|
-
export { type BaseContext, type CreatedEvent, type CreatedService, type CreatedTask, type
|
|
823
|
+
export { type BaseContext, type CreatedEvent, type CreatedService, type CreatedTask, type CreatedWindow, type DefineConfigInput, type DefineRuntimeInput, type DefineViewInput, type ElectroConfig, type ElectroView, EventAccessor, type EventHandler, type EventId, type EventInstance, type EventSubscription, type FeatureConfig, type FeatureContext, type FeatureHandle, type FeatureId, type FeatureMap, FeatureStatus, type LogEntry, type LogHandler, type LoggerContext, PolicyDecision, PolicyEngine, type PolicyResult, Runtime, type RuntimeConfig, type RuntimeDefinition, RuntimeState, type ServiceConfig, type ServiceId, type ServiceInfo, type ServiceOwnerMap, ServiceScope, ServiceStatus, type StopMode, type TaskConfig, type TaskExecutionContext, type TaskHandle, type TaskId, TaskOverlapStrategy, type TaskOwnerMap, TaskRetryStrategy, TaskStatus, type TaskStatusInfo, type TypedContext, type ViewDefinition, type ViewId, type ViewInstance, type ViewMap, type ViewRegistryEntry, type WindowApiMap, type WindowConfig, type WindowId, type WindowInstance, createEvent, createFeature, createRuntime, createService, createTask, createWindow, defineConfig, defineRuntime, defineView };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { Cron } from "croner";
|
|
3
2
|
import { join } from "node:path";
|
|
3
|
+
import { Cron } from "croner";
|
|
4
4
|
|
|
5
5
|
//#region \0rolldown/runtime.js
|
|
6
6
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
@@ -58,7 +58,6 @@ const VIEW_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
|
58
58
|
function defineView(input) {
|
|
59
59
|
if (!input.name || input.name.trim().length === 0) throw new Error("[electro] defineView: name must be a non-empty string");
|
|
60
60
|
if (!VIEW_NAME_PATTERN.test(input.name)) throw new Error(`[electro] defineView: name "${input.name}" is invalid. Must match ${VIEW_NAME_PATTERN.toString()}`);
|
|
61
|
-
if (!input.entry || input.entry.trim().length === 0) throw new Error("[electro] defineView: entry must be a non-empty string");
|
|
62
61
|
return {
|
|
63
62
|
name: input.name,
|
|
64
63
|
entry: input.entry,
|
|
@@ -900,6 +899,55 @@ var ViewManager = class {
|
|
|
900
899
|
}
|
|
901
900
|
};
|
|
902
901
|
|
|
902
|
+
//#endregion
|
|
903
|
+
//#region src/core/view/view.ts
|
|
904
|
+
/**
|
|
905
|
+
* View — manages a single WebContentsView instance.
|
|
906
|
+
*
|
|
907
|
+
* `create()` is idempotent: calling it while an alive view exists returns
|
|
908
|
+
* the existing instance. After the view is destroyed, calling `create()`
|
|
909
|
+
* spawns a fresh one.
|
|
910
|
+
*
|
|
911
|
+
* For renderer-linked views, `load()` resolves the dev URL or production
|
|
912
|
+
* file path automatically.
|
|
913
|
+
*/
|
|
914
|
+
var View = class {
|
|
915
|
+
_view = null;
|
|
916
|
+
constructor(entry) {
|
|
917
|
+
this.entry = entry;
|
|
918
|
+
}
|
|
919
|
+
get id() {
|
|
920
|
+
return this.entry.id;
|
|
921
|
+
}
|
|
922
|
+
create() {
|
|
923
|
+
if (this._view && !this._view.webContents.isDestroyed()) return this._view;
|
|
924
|
+
const { WebContentsView: WCV } = __require("electron");
|
|
925
|
+
const view = new WCV({ webPreferences: { ...this.entry.webPreferences ?? {} } });
|
|
926
|
+
if (this.entry.hasRenderer) {
|
|
927
|
+
const viewId = this.entry.id;
|
|
928
|
+
view.load = async () => {
|
|
929
|
+
const devUrl = process.env[`ELECTRO_DEV_URL_${viewId}`];
|
|
930
|
+
if (devUrl) {
|
|
931
|
+
await view.webContents.loadURL(devUrl);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
const { app } = await import("electron");
|
|
935
|
+
await view.webContents.loadFile(join(app.getAppPath(), ".electro", "out", "renderer", viewId, "index.html"));
|
|
936
|
+
};
|
|
937
|
+
} else view.load = async () => {};
|
|
938
|
+
this._view = view;
|
|
939
|
+
return view;
|
|
940
|
+
}
|
|
941
|
+
view() {
|
|
942
|
+
if (this._view?.webContents.isDestroyed()) this._view = null;
|
|
943
|
+
return this._view;
|
|
944
|
+
}
|
|
945
|
+
destroy() {
|
|
946
|
+
if (this._view && !this._view.webContents.isDestroyed()) this._view.webContents.close();
|
|
947
|
+
this._view = null;
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
|
|
903
951
|
//#endregion
|
|
904
952
|
//#region src/core/window/manager.ts
|
|
905
953
|
/**
|
|
@@ -952,7 +1000,8 @@ var Runtime = class {
|
|
|
952
1000
|
this.windowManager = new WindowManager();
|
|
953
1001
|
for (const win of config?.windows ?? []) this.windowManager.register(win);
|
|
954
1002
|
this.viewManager = new ViewManager();
|
|
955
|
-
|
|
1003
|
+
const viewRegistry = typeof __ELECTRO_VIEW_REGISTRY__ !== "undefined" ? __ELECTRO_VIEW_REGISTRY__ : [];
|
|
1004
|
+
for (const entry of viewRegistry) this.viewManager.register(new View(entry));
|
|
956
1005
|
this.featureManager.setWindowManager(this.windowManager);
|
|
957
1006
|
this.featureManager.setViewManager(this.viewManager);
|
|
958
1007
|
if (config?.features) this.featureManager.register(config.features);
|
|
@@ -1451,10 +1500,13 @@ function createTask(config) {
|
|
|
1451
1500
|
* `create()` is idempotent: calling it while an alive window exists returns
|
|
1452
1501
|
* the existing instance. After the window is destroyed (user close, etc.),
|
|
1453
1502
|
* calling `create()` again spawns a fresh one.
|
|
1503
|
+
*
|
|
1504
|
+
* API methods from `config.api()` are mixed directly onto the instance
|
|
1505
|
+
* via Object.assign, so callers can do `window.show()` instead of `window.api?.show()`.
|
|
1454
1506
|
*/
|
|
1455
1507
|
var Window = class {
|
|
1456
1508
|
_window = null;
|
|
1457
|
-
|
|
1509
|
+
_apiKeys = null;
|
|
1458
1510
|
constructor(config) {
|
|
1459
1511
|
this.config = config;
|
|
1460
1512
|
}
|
|
@@ -1468,27 +1520,30 @@ var Window = class {
|
|
|
1468
1520
|
show: false,
|
|
1469
1521
|
...this.config.options ?? {}
|
|
1470
1522
|
});
|
|
1471
|
-
if (this.config.api)
|
|
1523
|
+
if (this.config.api) {
|
|
1524
|
+
const api = this.config.api(this._window);
|
|
1525
|
+
this._apiKeys = Object.keys(api);
|
|
1526
|
+
Object.assign(this, api);
|
|
1527
|
+
}
|
|
1472
1528
|
return this._window;
|
|
1473
1529
|
}
|
|
1474
1530
|
get window() {
|
|
1475
1531
|
if (this._window?.isDestroyed()) {
|
|
1476
1532
|
this._window = null;
|
|
1477
|
-
this.
|
|
1533
|
+
this.clearApi();
|
|
1478
1534
|
}
|
|
1479
1535
|
return this._window;
|
|
1480
1536
|
}
|
|
1481
|
-
get api() {
|
|
1482
|
-
if (this._window?.isDestroyed()) {
|
|
1483
|
-
this._window = null;
|
|
1484
|
-
this._api = null;
|
|
1485
|
-
}
|
|
1486
|
-
return this._api;
|
|
1487
|
-
}
|
|
1488
1537
|
destroy() {
|
|
1489
1538
|
if (this._window && !this._window.isDestroyed()) this._window.destroy();
|
|
1490
1539
|
this._window = null;
|
|
1491
|
-
this.
|
|
1540
|
+
this.clearApi();
|
|
1541
|
+
}
|
|
1542
|
+
clearApi() {
|
|
1543
|
+
if (this._apiKeys) {
|
|
1544
|
+
for (const key of this._apiKeys) delete this[key];
|
|
1545
|
+
this._apiKeys = null;
|
|
1546
|
+
}
|
|
1492
1547
|
}
|
|
1493
1548
|
};
|
|
1494
1549
|
|
|
@@ -1506,75 +1561,6 @@ function createWindow(config) {
|
|
|
1506
1561
|
return new Window(config);
|
|
1507
1562
|
}
|
|
1508
1563
|
|
|
1509
|
-
//#endregion
|
|
1510
|
-
//#region src/core/view/view.ts
|
|
1511
|
-
function isRendererConfig(config) {
|
|
1512
|
-
return "renderer" in config;
|
|
1513
|
-
}
|
|
1514
|
-
function resolveRendererName(config) {
|
|
1515
|
-
return config.renderer === true ? config.id : config.renderer;
|
|
1516
|
-
}
|
|
1517
|
-
/**
|
|
1518
|
-
* View — manages a single WebContentsView instance.
|
|
1519
|
-
*
|
|
1520
|
-
* `create()` is idempotent: calling it while an alive view exists returns
|
|
1521
|
-
* the existing instance. After the view is destroyed, calling `create()`
|
|
1522
|
-
* spawns a fresh one.
|
|
1523
|
-
*
|
|
1524
|
-
* For renderer-linked views, `load()` resolves the dev URL or production
|
|
1525
|
-
* file path automatically.
|
|
1526
|
-
*/
|
|
1527
|
-
var View = class {
|
|
1528
|
-
_view = null;
|
|
1529
|
-
constructor(config) {
|
|
1530
|
-
this.config = config;
|
|
1531
|
-
}
|
|
1532
|
-
get id() {
|
|
1533
|
-
return this.config.id;
|
|
1534
|
-
}
|
|
1535
|
-
create() {
|
|
1536
|
-
if (this._view && !this._view.webContents.isDestroyed()) return this._view;
|
|
1537
|
-
const { WebContentsView: WCV } = __require("electron");
|
|
1538
|
-
const view = new WCV({ webPreferences: { ...this.config.webPreferences ?? {} } });
|
|
1539
|
-
if (isRendererConfig(this.config)) {
|
|
1540
|
-
const rendererName = resolveRendererName(this.config);
|
|
1541
|
-
view.load = async () => {
|
|
1542
|
-
const devUrl = process.env[`ELECTRO_DEV_URL_${rendererName}`];
|
|
1543
|
-
if (devUrl) {
|
|
1544
|
-
await view.webContents.loadURL(devUrl);
|
|
1545
|
-
return;
|
|
1546
|
-
}
|
|
1547
|
-
const { app } = await import("electron");
|
|
1548
|
-
await view.webContents.loadFile(join(app.getAppPath(), ".electro", "out", "renderer", rendererName, "index.html"));
|
|
1549
|
-
};
|
|
1550
|
-
} else view.load = async () => {};
|
|
1551
|
-
this._view = view;
|
|
1552
|
-
return view;
|
|
1553
|
-
}
|
|
1554
|
-
view() {
|
|
1555
|
-
if (this._view?.webContents.isDestroyed()) this._view = null;
|
|
1556
|
-
return this._view;
|
|
1557
|
-
}
|
|
1558
|
-
destroy() {
|
|
1559
|
-
if (this._view && !this._view.webContents.isDestroyed()) this._view.webContents.close();
|
|
1560
|
-
this._view = null;
|
|
1561
|
-
}
|
|
1562
|
-
};
|
|
1563
|
-
|
|
1564
|
-
//#endregion
|
|
1565
|
-
//#region src/core/view/helpers.ts
|
|
1566
|
-
/**
|
|
1567
|
-
* Creates a {@link View} instance from a configuration object.
|
|
1568
|
-
*
|
|
1569
|
-
* @param config - View configuration with `id`, and either `renderer` (for Vite-built views) or `webPreferences` (for dynamic views).
|
|
1570
|
-
* @returns A new `View` instance ready for registration.
|
|
1571
|
-
* @throws If `config.id` is empty.
|
|
1572
|
-
*/
|
|
1573
|
-
function createView(config) {
|
|
1574
|
-
if (!config.id) throw new Error("View must have an id");
|
|
1575
|
-
return new View(config);
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
1564
|
//#endregion
|
|
1579
1565
|
//#region src/policy/types.ts
|
|
1580
1566
|
/** Outcome of a policy check. */
|
|
@@ -1633,4 +1619,4 @@ var PolicyEngine = class {
|
|
|
1633
1619
|
};
|
|
1634
1620
|
|
|
1635
1621
|
//#endregion
|
|
1636
|
-
export { EventAccessor, FeatureStatus, PolicyDecision, PolicyEngine, Runtime, RuntimeState, ServiceScope, ServiceStatus, TaskOverlapStrategy, TaskRetryStrategy, TaskStatus, createEvent, createFeature, createRuntime, createService, createTask,
|
|
1622
|
+
export { EventAccessor, FeatureStatus, PolicyDecision, PolicyEngine, Runtime, RuntimeState, ServiceScope, ServiceStatus, TaskOverlapStrategy, TaskRetryStrategy, TaskStatus, createEvent, createFeature, createRuntime, createService, createTask, createWindow, defineConfig, defineRuntime, defineView };
|