@andrew_l/app 0.3.7

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.
@@ -0,0 +1,651 @@
1
+ import { IfAny, Data, Logger, AnyFunction, Awaitable, SimpleEventEmitter, ExecResult, LogLevel, Scheduler, AsyncIterableQueue, ResourcePool, CancellablePromise } from '@andrew_l/toolkit';
2
+ import * as cp from 'node:child_process';
3
+ import { EventEmitter } from 'node:events';
4
+
5
+ /**
6
+ * Declaration for a single typed app prop.
7
+ * @group Types
8
+ */
9
+ interface PropOptions<T = any> {
10
+ type: PropType<T> | null;
11
+ description?: string;
12
+ alias?: string;
13
+ required?: boolean;
14
+ env?: string | string[];
15
+ default?: () => InferPropType<T>;
16
+ parser?: (value: string) => InferPropType<T>;
17
+ enum?: string[];
18
+ }
19
+ /**
20
+ * @group Types
21
+ */
22
+ type PropType<T> = PropConstructor<T> | PropConstructor<T>[];
23
+ /**
24
+ * Map of prop declarations keyed by name — passed as `props` in `defineApp`.
25
+ * @group Types
26
+ */
27
+ type ObjectPropsOptions<P = Data> = {
28
+ [K in keyof P]: PropOptions<P[K]>;
29
+ };
30
+ type PropConstructor<T = any> = {
31
+ new (...args: any[]): T & {};
32
+ } | {
33
+ (): T;
34
+ } | PropMethod<T>;
35
+ type PropMethod<T, TConstructor = any> = [T] extends [
36
+ ((...args: any) => any) | undefined
37
+ ] ? {
38
+ new (): TConstructor;
39
+ (): T;
40
+ readonly prototype: TConstructor;
41
+ } : never;
42
+ type OptionalKeys<T> = Exclude<keyof T, RequiredKeys<T>>;
43
+ type RequiredKeys<T> = {
44
+ [K in keyof T]: T[K] extends {
45
+ required: true;
46
+ } ? K : never;
47
+ }[keyof T];
48
+ type InferPropType<T> = [T] extends [null] ? any : [T] extends [{
49
+ type: null;
50
+ }] ? any : [T] extends [ObjectConstructor | {
51
+ type: ObjectConstructor;
52
+ }] ? Record<string, any> : [T] extends [BooleanConstructor | {
53
+ type: BooleanConstructor;
54
+ }] ? boolean : [T] extends [DateConstructor | {
55
+ type: DateConstructor;
56
+ }] ? Date : [T] extends [DateConstructor | {
57
+ type: DateConstructor;
58
+ }] ? Date : [T] extends [StringConstructor | {
59
+ type: StringConstructor;
60
+ }] ? string : [T] extends [(infer U)[] | {
61
+ type: (infer U)[];
62
+ }] ? U extends DateConstructor ? Date | InferPropType<U> : InferPropType<U> : [T] extends [PropOptions<infer V>] ? unknown extends V ? IfAny<V, V, V> : V : T;
63
+ /**
64
+ * Resolve the concrete prop value types from an `ObjectPropsOptions` declaration.
65
+ * @group Types
66
+ */
67
+ type ExtractPropTypes<O> = {
68
+ [K in keyof Pick<O, RequiredKeys<O>>]: InferPropType<O[K]>;
69
+ } & {
70
+ [K in keyof Pick<O, OptionalKeys<O>>]?: InferPropType<O[K]>;
71
+ };
72
+
73
+ declare namespace AppDefinition {
74
+ type EntryContext<T extends Data = Data> = T & {
75
+ log: Logger;
76
+ };
77
+ type SetupContext<T extends Data = Data> = T & {
78
+ log: Logger;
79
+ };
80
+ type RuntimeContext<T extends Data = Data> = T & {
81
+ log: Logger;
82
+ };
83
+ }
84
+ /**
85
+ * Shape of an application — name, typed props, lifecycle hooks, and optional methods.
86
+ * @group Types
87
+ */
88
+ interface AppDefinition<P extends ObjectPropsOptions = {}, S extends Record<string, any> = {}, M extends Record<string, AnyFunction> = {}, RuntimeContext extends AppDefinition.RuntimeContext = AppDefinition.RuntimeContext<S & M>, EntryContext extends AppDefinition.EntryContext = AppDefinition.EntryContext<S & M>, SetupContext extends AppDefinition.SetupContext = AppDefinition.SetupContext<M>> {
89
+ /**
90
+ * Name of your awesome application
91
+ */
92
+ name: string;
93
+ /**
94
+ * Describe what your application does
95
+ */
96
+ description?: string;
97
+ /**
98
+ * Props options to be parsed from cli arguments of env variables
99
+ */
100
+ props?: P;
101
+ /**
102
+ * Path to the file where this definition exports default
103
+ * Usually you should not use this option, because it tracks automatically
104
+ */
105
+ filePath?: string | null;
106
+ /**
107
+ * Logger instance or constructor function
108
+ */
109
+ logger?: false | Logger | ((definition: AppDefinition) => Logger);
110
+ /**
111
+ * Setup function to initialize application. Will be called once
112
+ */
113
+ setup?(this: SetupContext, props: ExtractPropTypes<P>): Awaitable<S>;
114
+ /**
115
+ * Custom methods which will be available under `this` context
116
+ */
117
+ methods?: M & ThisType<RuntimeContext>;
118
+ /**
119
+ * Entry function that will be called each time when application starts
120
+ */
121
+ entry?(this: EntryContext, props: ExtractPropTypes<P>): Awaitable<any>;
122
+ /**
123
+ * Stop function that will be called each time when application stops
124
+ */
125
+ stop?(this: RuntimeContext, props: ExtractPropTypes<P>): Awaitable<void>;
126
+ /**
127
+ * Shutdown function that will be called before application/process graceful shutdown
128
+ */
129
+ shutdown?(this: RuntimeContext, props: ExtractPropTypes<P>): Awaitable<void>;
130
+ }
131
+ declare const APP_INSTANCE_STATE: {
132
+ readonly INIT: "init";
133
+ readonly IN_SETUP: "in-setup";
134
+ readonly SETUP: "setup";
135
+ readonly IN_STOP: "in-stop";
136
+ readonly IN_RUN: "in-run";
137
+ readonly RUN: "run";
138
+ readonly STOP: "stop";
139
+ readonly IN_SHUTDOWN: "in-shutdown";
140
+ readonly SHUTDOWN: "shutdown";
141
+ readonly ERROR: "error";
142
+ };
143
+ declare namespace AppInstance {
144
+ type EventMap = {
145
+ state: [newState: State, oldState: State];
146
+ error: [err: Error];
147
+ } & {
148
+ [K in State as `state:${K}`]: [];
149
+ };
150
+ type State = (typeof APP_INSTANCE_STATE)[keyof typeof APP_INSTANCE_STATE];
151
+ }
152
+ /**
153
+ * Runtime state of a created app instance.
154
+ * @group Types
155
+ */
156
+ interface AppInstance<P extends ObjectPropsOptions = {}, S extends Record<string, any> = {}, M extends Record<string, AnyFunction> = {}> {
157
+ definition: AppDefinition<P, S, M>;
158
+ props: ExtractPropTypes<P> | null;
159
+ setupState: AppDefinition.SetupContext<Data>;
160
+ eventBus: SimpleEventEmitter<AppInstance.EventMap>;
161
+ /** @internal */
162
+ mutexName: string | null;
163
+ /** @internal */
164
+ mutexQueue: Promise<void>;
165
+ readonly state: AppInstance.State;
166
+ logger: Logger;
167
+ }
168
+ /**
169
+ * Define an application with typed props and lifecycle hooks.
170
+ *
171
+ * When executed directly (`node app.ts`), the CLI is launched automatically.
172
+ * @group Main
173
+ * @example
174
+ * ```ts
175
+ * import { defineApp } from '@andrew_l/app';
176
+ *
177
+ * export default defineApp({
178
+ * name: 'server',
179
+ * props: {
180
+ * port: { type: Number, default: () => 3000 },
181
+ * },
182
+ * setup() {
183
+ * return { server: createServer() };
184
+ * },
185
+ * async entry(props) {
186
+ * await this.server.listen(props.port);
187
+ * },
188
+ * async stop() {
189
+ * await this.server.close();
190
+ * },
191
+ * });
192
+ * ```
193
+ */
194
+ declare function defineApp<P extends ObjectPropsOptions, S extends Record<string, any>, M extends Record<string, AnyFunction>>(definition: AppDefinition<P, S, M>): AppDefinition<P, S, M>;
195
+ /**
196
+ * Create a new runtime instance from an app definition.
197
+ * @group App Lifecycle
198
+ * @example
199
+ * ```ts
200
+ * const instance = createAppInstance(myApp);
201
+ * await setupApp(instance, { port: 3000 });
202
+ * await runApp(instance);
203
+ * ```
204
+ */
205
+ declare function createAppInstance<P extends ObjectPropsOptions, S extends Record<string, any>, M extends Record<string, AnyFunction>>(definition: AppDefinition<P, S, M>): AppInstance<P, S, M>;
206
+ /**
207
+ * Returns true if the value was created by `defineApp`.
208
+ * @group Utils
209
+ */
210
+ declare function isAppDefinition(value: unknown): value is AppDefinition;
211
+ /**
212
+ * Run setup and entry in one call. Shuts down automatically if entry fails.
213
+ * @group App Lifecycle
214
+ * @example
215
+ * ```ts
216
+ * const result = await startApp(myApp, { port: 3000 });
217
+ * if (isSuccess(result)) {
218
+ * await appWaitShutdown(result.app);
219
+ * }
220
+ * ```
221
+ */
222
+ declare function startApp<P extends ObjectPropsOptions, S extends Record<string, any>>(app: AppDefinition<P, S> | AppInstance<P, S>, props: ExtractPropTypes<P>): Promise<ExecResult<{
223
+ app: AppInstance<P, S>;
224
+ }>>;
225
+ /**
226
+ * Run the setup phase of an app instance.
227
+ * @group App Lifecycle
228
+ * @example
229
+ * ```ts
230
+ * const result = await setupApp(instance, { port: 3000 });
231
+ * if (isSuccess(result)) {
232
+ * await runApp(instance);
233
+ * }
234
+ * ```
235
+ */
236
+ declare function setupApp(instance: AppInstance, props: Data): Promise<ExecResult>;
237
+ /**
238
+ * Run the entry phase of an app instance.
239
+ * @group App Lifecycle
240
+ * @example
241
+ * ```ts
242
+ * await setupApp(instance, props);
243
+ * await runApp(instance);
244
+ * ```
245
+ */
246
+ declare function runApp$1(instance: AppInstance): Promise<ExecResult>;
247
+ /**
248
+ * Stop a running app instance and call its `stop` hook.
249
+ * @group App Lifecycle
250
+ * @example
251
+ * ```ts
252
+ * process.on('SIGTERM', async () => {
253
+ * await stopApp(instance);
254
+ * await shutdownApp(instance);
255
+ * });
256
+ * ```
257
+ */
258
+ declare function stopApp(instance: AppInstance): Promise<ExecResult>;
259
+ /**
260
+ * Shut down an app instance, call its `shutdown` hook, and reset all state.
261
+ * @group App Lifecycle
262
+ * @example
263
+ * ```ts
264
+ * await stopApp(instance);
265
+ * await shutdownApp(instance);
266
+ * // instance can be set up and started again after this
267
+ * ```
268
+ */
269
+ declare function shutdownApp(instance: AppInstance): Promise<ExecResult>;
270
+ /**
271
+ * Returns a promise that resolves when the app emits its shutdown event.
272
+ * Resolves immediately if the app is not running.
273
+ * @group App Lifecycle
274
+ * @example
275
+ * ```ts
276
+ * await startApp(myApp, props);
277
+ * await appWaitShutdown(instance); // blocks until shutdown
278
+ * ```
279
+ */
280
+ declare function appWaitShutdown(instance: AppInstance): Promise<void>;
281
+
282
+ /**
283
+ * Combine multiple app definitions into a single orchestrated app.
284
+ * Props from each definition are namespaced by their app name.
285
+ * @group Utils
286
+ */
287
+ declare function createAppHub(definitions: AppDefinition[]): AppDefinition;
288
+ declare function getPrefixedProps(definition: AppDefinition, props: Data): Data;
289
+ declare function prefixifyProps(definitions: AppDefinition[]): ObjectPropsOptions;
290
+
291
+ /**
292
+ * Wrap an app definition to run across N child processes. Adds a
293
+ * `threads` prop and manages the full lifecycle of each child.
294
+ * @group Types
295
+ */
296
+ declare function createAppThread(definition: AppDefinition): AppDefinition;
297
+ interface CreateAppThreadInstanceParams {
298
+ definition: AppDefinition;
299
+ parentPort: ParentPortLike;
300
+ threadId: number;
301
+ onShutdown?: () => void;
302
+ }
303
+ /**
304
+ * A minimal port abstraction implemented by both IPC `MessagePort`
305
+ * and the `process`-based shim spawned by {@link initThread}.
306
+ * @group Types
307
+ */
308
+ interface ParentPortLike {
309
+ on(event: 'message', cb: (msg: unknown) => void): unknown;
310
+ postMessage(msg: unknown, cb?: () => void): unknown;
311
+ close?(): unknown;
312
+ }
313
+ /**
314
+ * Create app instance with IPC fully managed lifecycle
315
+ * @group Threads
316
+ */
317
+ declare function createAppThreadInstance({ definition, parentPort, threadId, onShutdown, }: CreateAppThreadInstanceParams): AppInstance;
318
+
319
+ interface RunAppOptions {
320
+ scriptFile?: string;
321
+ cliName?: string;
322
+ cliDescription?: string;
323
+ argv?: string[];
324
+ }
325
+ declare function runApp({ scriptFile, cliName, cliDescription, argv, }: RunAppOptions): Promise<void>;
326
+
327
+ /**
328
+ * Programmatic access to the `vrun` CLI internals.
329
+ * @group Utils
330
+ */
331
+ declare const cli: Readonly<{
332
+ readonly runApp: typeof runApp;
333
+ }>;
334
+
335
+ type LogEventFields = Record<string, any>;
336
+
337
+ /**
338
+ * @group Types
339
+ */
340
+ declare namespace ManagedThread {
341
+ type State = AppInstance.State | 'ready';
342
+ interface LogEntry {
343
+ ts: number;
344
+ level: LogLevel;
345
+ text: string;
346
+ }
347
+ type EventMap = {
348
+ ready: [];
349
+ state: [newState: State, oldState: State];
350
+ log: [entry: LogEntry];
351
+ pid: [pid: number];
352
+ exit: [code: number | null, signal: NodeJS.Signals | null];
353
+ message: [message: ManagedThread.ThreadMessage];
354
+ error: [err: Error];
355
+ } & {
356
+ [K in ManagedThread.ThreadMessage as `msg:${K['type']}`]: [msg: K];
357
+ };
358
+ type ThreadMessage = ThreadMessage.AppState | ThreadMessage.Ping | ThreadMessage.Pong | ThreadMessage.Ready | ThreadMessage.Shutdown | ThreadMessage.ShutdownDone | ThreadMessage.Start | ThreadMessage.StartDone | ThreadMessage.Setup | ThreadMessage.SetupDone | ThreadMessage.Stop | ThreadMessage.StopDone;
359
+ type ThreadMessageMap = {
360
+ [K in ManagedThread.ThreadMessage as K['type']]: K;
361
+ };
362
+ type ThreadMessageDone<T extends string> = `${T}_done` extends keyof ThreadMessageMap ? `${T}_done` : never;
363
+ namespace ThreadMessage {
364
+ interface Base<T extends string> {
365
+ type: T;
366
+ vrun_app_thread_message: true;
367
+ }
368
+ type AppState = Base<'app-state'> & {
369
+ state: AppInstance.State;
370
+ };
371
+ type Start = Base<'start'>;
372
+ type StartDone = Base<'start_done'> & {
373
+ result: ExecResult;
374
+ };
375
+ type Setup = Base<'setup'> & {
376
+ props: Data;
377
+ };
378
+ type SetupDone = Base<'setup_done'> & {
379
+ result: ExecResult;
380
+ };
381
+ type Stop = Base<'stop'>;
382
+ type StopDone = Base<'stop_done'> & {
383
+ result: ExecResult;
384
+ };
385
+ type Shutdown = Base<'shutdown'>;
386
+ type ShutdownDone = Base<'shutdown_done'> & {
387
+ result: ExecResult;
388
+ };
389
+ type Ping = Base<'ping'>;
390
+ type Pong = Base<'pong'>;
391
+ type Ready = Base<'ready'> & {
392
+ pid: number;
393
+ };
394
+ }
395
+ }
396
+ /**
397
+ * A child process managed by the parent.
398
+ * @group Types
399
+ */
400
+ interface ManagedThread {
401
+ child: cp.ChildProcess;
402
+ threadId: number;
403
+ pid: number;
404
+ state: ManagedThread.State;
405
+ restartCount: number;
406
+ scriptFile: string;
407
+ threadProps: Record<string, unknown>;
408
+ eventBus: EventEmitter<ManagedThread.EventMap>;
409
+ scheduler: Scheduler;
410
+ writeLog(level: LogLevel, event: string, fields?: LogEventFields): void;
411
+ /** @internal */ heartbeatTimer?: NodeJS.Timeout;
412
+ /** @internal */ lastPong: number;
413
+ }
414
+ /**
415
+ * Wait for thread ready signal
416
+ * @group Threads
417
+ */
418
+ declare function waitForThreadReady(w: ManagedThread): Promise<void>;
419
+ /**
420
+ * Spawn a child process for `scriptFile` and return its {@link ManagedThread}
421
+ * immediately — synchronously, before the child signals readiness.
422
+ * @group Threads
423
+ */
424
+ declare function initThread(threadId: number, scriptFile: string, threadProps: Record<string, unknown>): ManagedThread;
425
+ /**
426
+ * Send the setup message; resolves when child replies setup_done.
427
+ * @group Threads
428
+ */
429
+ declare function setupThreadApp(w: ManagedThread): Promise<void>;
430
+ /**
431
+ * Send the start message; on reply, switch to running and arm heartbeat.
432
+ * @group Threads
433
+ */
434
+ declare function startThreadApp(w: ManagedThread): Promise<void>;
435
+ /**
436
+ * Send the stop message; child keeps running, app inside is stopped.
437
+ * @group Threads
438
+ */
439
+ declare function stopThreadApp(w: ManagedThread): Promise<void>;
440
+ /**
441
+ * Send shutdown and wait for the OS process to exit (SIGKILL fallback).
442
+ * @group Threads
443
+ */
444
+ declare function shutdownThreadApp(w: ManagedThread): Promise<void>;
445
+ /**
446
+ * Terminate the child and spawn a fresh one with the same script + props.
447
+ * @group Threads
448
+ */
449
+ declare function restartThreadApp(w: ManagedThread): Promise<void>;
450
+ declare function isThreadMessage(value: unknown): value is ManagedThread.ThreadMessage;
451
+ declare function createThreadMessage<T extends keyof ManagedThread.ThreadMessageMap>(type: T, msg: Omit<ManagedThread.ThreadMessageMap[T], 'type' | 'vrun_app_thread_message'>): ManagedThread.ThreadMessageMap[T];
452
+ declare function isThreadExit(w: ManagedThread): boolean;
453
+
454
+ type WorkerSuccessData = {
455
+ [x: string]: unknown;
456
+ };
457
+ type WorkerSkipData = {
458
+ error?: boolean;
459
+ [x: string]: unknown;
460
+ };
461
+ type WorkerResult = ExecResult<WorkerSuccessData, WorkerSkipData>;
462
+ /**
463
+ * @group Types
464
+ */
465
+ declare namespace WorkerStrategy {
466
+ /**
467
+ * Base context bag emitted by strategies per task. Strategies extend this with typed fields.
468
+ * @group Types
469
+ */
470
+ interface Context {
471
+ [key: string]: unknown;
472
+ }
473
+ }
474
+ /**
475
+ * Pluggable trigger source. Drives when tasks are enqueued.
476
+ * @group Types
477
+ */
478
+ interface WorkerStrategy<C extends WorkerStrategy.Context = WorkerStrategy.Context> {
479
+ doSetup(opts: {
480
+ worker: WorkerInstance;
481
+ }): Awaitable<void>;
482
+ startSignal(): void;
483
+ stopSignal(done: () => void): void;
484
+ doShutdown(): Awaitable<void>;
485
+ createTask(...args: any[]): C;
486
+ executeSignal?(ctx: WorkerDefinition.EntryContext<WorkerStrategy<C>>): Awaitable<ExecResult>;
487
+ completeSignal?(ctx: WorkerDefinition.EntryContext<WorkerStrategy<C>>, result: WorkerResult | WorkerResult[]): Awaitable<void>;
488
+ overloadedSignal?(): void;
489
+ availableSignal?(): void;
490
+ handleEntryError?(err: Error): WorkerResult;
491
+ }
492
+ declare namespace WorkerDefinition {
493
+ /**
494
+ * Entry function that will be called each time when worker handle a job
495
+ */
496
+ type EntryFn<Context extends Data, Props extends Data> = (this: Context, props: Props) => Awaitable<WorkerResult | WorkerResult[] | void>;
497
+ type SetupFn<Context extends Data, Props extends Data, Result> = (this: Context, props: Props) => Awaitable<Result>;
498
+ type EntryContext<T extends WorkerStrategy = WorkerStrategy> = AppDefinition.EntryContext<{
499
+ worker: WorkerInstance<T>;
500
+ } & TaskContext<T>>;
501
+ type SetupContext<T extends Data = Data> = AppDefinition.SetupContext<T & {
502
+ worker: WorkerInstance;
503
+ }>;
504
+ type RuntimeContext<T extends Data = Data> = AppDefinition.RuntimeContext<T & {
505
+ worker: WorkerInstance;
506
+ }>;
507
+ type TaskContext<T extends WorkerStrategy> = T extends WorkerStrategy<infer X> ? X : never;
508
+ }
509
+ /**
510
+ * Worker definition — extends AppDefinition with strategy, per-task entry, and concurrency config.
511
+ * @group Types
512
+ */
513
+ interface WorkerDefinition<P extends ObjectPropsOptions = {}, S extends Record<string, any> = {}, M extends Record<string, AnyFunction> = {}, C extends WorkerStrategy = WorkerStrategy, RuntimeContext extends WorkerDefinition.RuntimeContext = WorkerDefinition.RuntimeContext<S & M>, EntryContext extends WorkerDefinition.EntryContext = WorkerDefinition.EntryContext<C> & S & M, SetupContext extends WorkerDefinition.SetupContext = WorkerDefinition.SetupContext<M>> extends AppDefinition<P, S, M, RuntimeContext, EntryContext, SetupContext> {
514
+ /**
515
+ * Entry function that will be called each time when worker handle a job
516
+ */
517
+ entry?(this: EntryContext, props: ExtractPropTypes<P>): Awaitable<WorkerResult | WorkerResult[] | void>;
518
+ /**
519
+ * Setup function will be called once while worker setup.
520
+ */
521
+ setup?(this: SetupContext, props: ExtractPropTypes<P>): Awaitable<S>;
522
+ executeStrategy: C;
523
+ /**
524
+ * Maximum limit of queued tasks
525
+ * @default 50
526
+ */
527
+ taskLimit?: number;
528
+ /**
529
+ * Amount of task to be executed in parallel
530
+ * @default 2
531
+ */
532
+ taskParallel?: number;
533
+ /**
534
+ * Disable worker
535
+ * @default false
536
+ */
537
+ disabled?: boolean;
538
+ }
539
+ /**
540
+ * Runtime state of a worker instance. Extends AppInstance with task queue and pool.
541
+ * Managed with the standard startApp / stopApp / shutdownApp lifecycle.
542
+ * @group Types
543
+ */
544
+ interface WorkerInstance<C extends WorkerStrategy = WorkerStrategy> {
545
+ definition: WorkerDefinition<{}, {}, {}, C>;
546
+ queue: AsyncIterableQueue<WorkerDefinition.TaskContext<C>>;
547
+ pool: ResourcePool<symbol>;
548
+ runTask: CancellablePromise<void> | null;
549
+ overloadedSignaled: boolean;
550
+ log: Logger;
551
+ readonly queueMaxSize: number;
552
+ readonly taskParallel: number;
553
+ /**
554
+ * Tasks queue size
555
+ */
556
+ readonly queueSize: number;
557
+ /**
558
+ * Check if the worker is overloaded (e.g., queue length is high)
559
+ */
560
+ readonly isOverloaded: boolean;
561
+ /**
562
+ * Returns true when worker do nothing
563
+ */
564
+ readonly isIdle: boolean;
565
+ /**
566
+ * Add task into execution queue
567
+ */
568
+ addTask(ctx: WorkerDefinition.TaskContext<C>): void;
569
+ }
570
+ /**
571
+ * Create a runtime WorkerInstance from a WorkerDefinition.
572
+ * Use with startApp / stopApp / shutdownApp.
573
+ * @group Worker
574
+ */
575
+ declare function createWorkerInstance<C extends WorkerStrategy>(definition: WorkerDefinition<{}, {}, {}, C>, logger: Logger): WorkerInstance<C>;
576
+ /**
577
+ * Enqueue a task context on the worker. Fires backpressure signals at 80% capacity.
578
+ * @group Worker
579
+ */
580
+ declare function addWorkerTask<C extends WorkerStrategy>(instance: WorkerInstance<C>, ctx: WorkerDefinition.TaskContext<C>): void;
581
+ /**
582
+ * Define a background worker with a pluggable execution strategy.
583
+ * Returns a WorkerDefinition that can be run with createWorkerInstance + startApp.
584
+ *
585
+ * @example
586
+ * ```ts
587
+ * import { defineWorker, IntervalStrategy } from '@andrew_l/app';
588
+ *
589
+ * export default defineWorker({
590
+ * name: 'clock',
591
+ * executeStrategy: new IntervalStrategy({
592
+ * intervalSeconds: 1,
593
+ * }),
594
+ * entry() {
595
+ * this.log.info('tick=%d', this.timerSequence);
596
+ * },
597
+ * async shutdown() {
598
+ * await delay(1000);
599
+ * },
600
+ * });
601
+ * ```
602
+ *
603
+ * @group Main
604
+ */
605
+ declare function defineWorker<P extends ObjectPropsOptions, S extends Record<string, any>, M extends Record<string, AnyFunction>, C extends WorkerStrategy = WorkerStrategy>(definition: WorkerDefinition<P, S, M, C>): WorkerDefinition<P, S, M, C>;
606
+ /**
607
+ * Returns true if the value was created by defineWorker.
608
+ * @group Utils
609
+ */
610
+ declare function isWorkerDefinition(value: unknown): value is WorkerDefinition;
611
+ /**
612
+ * Returns true if the value is a WorkerInstance.
613
+ * @group Utils
614
+ */
615
+ declare function isWorkerInstance(value: unknown): value is WorkerInstance;
616
+
617
+ declare namespace IntervalStrategy {
618
+ /**
619
+ * Options for the built-in IntervalStrategy.
620
+ */
621
+ interface Options {
622
+ intervalSeconds: number;
623
+ }
624
+ /**
625
+ * Context emitted by IntervalStrategy on each tick.
626
+ */
627
+ interface Context extends WorkerStrategy.Context {
628
+ timerSequence: number;
629
+ }
630
+ }
631
+ /**
632
+ * Triggers a worker task on a fixed interval.
633
+ * Skips the tick with a warning if the worker is not idle.
634
+ * @group Worker Strategies
635
+ */
636
+ declare class IntervalStrategy implements WorkerStrategy<IntervalStrategy.Context> {
637
+ private readonly options;
638
+ private timerSequence;
639
+ private timer;
640
+ private worker;
641
+ constructor(options: IntervalStrategy.Options);
642
+ doSetup({ worker }: {
643
+ worker: WorkerInstance;
644
+ }): void;
645
+ startSignal(): void;
646
+ stopSignal(done: () => void): void;
647
+ doShutdown(): void;
648
+ createTask(): IntervalStrategy.Context;
649
+ }
650
+
651
+ export { APP_INSTANCE_STATE, AppDefinition, AppInstance, type CreateAppThreadInstanceParams, type ExtractPropTypes, IntervalStrategy, ManagedThread, type ObjectPropsOptions, type ParentPortLike, type PropOptions, WorkerDefinition, type WorkerInstance, type WorkerResult, type WorkerSkipData, WorkerStrategy, type WorkerSuccessData, addWorkerTask, appWaitShutdown, cli, createAppHub, createAppInstance, createAppThread, createAppThreadInstance, createThreadMessage, createWorkerInstance, defineApp, defineWorker, getPrefixedProps, initThread, isAppDefinition, isThreadExit, isThreadMessage, isWorkerDefinition, isWorkerInstance, prefixifyProps, restartThreadApp, runApp$1 as runApp, setupApp, setupThreadApp, shutdownApp, shutdownThreadApp, startApp, startThreadApp, stopApp, stopThreadApp, waitForThreadReady };