agenda 6.0.0 → 6.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/README.md +16 -5
- package/dist/Job.js +107 -0
- package/dist/Job.js.map +1 -1
- package/dist/JobProcessor.d.ts +4 -2
- package/dist/JobProcessor.js +73 -8
- package/dist/JobProcessor.js.map +1 -1
- package/dist/index.d.ts +150 -17
- package/dist/index.js +213 -13
- package/dist/index.js.map +1 -1
- package/dist/notifications/BaseNotificationChannel.d.ts +12 -1
- package/dist/notifications/BaseNotificationChannel.js +30 -0
- package/dist/notifications/BaseNotificationChannel.js.map +1 -1
- package/dist/notifications/InMemoryNotificationChannel.d.ts +2 -1
- package/dist/notifications/InMemoryNotificationChannel.js +7 -0
- package/dist/notifications/InMemoryNotificationChannel.js.map +1 -1
- package/dist/types/AgendaBackend.d.ts +8 -0
- package/dist/types/AgendaConfig.d.ts +1 -0
- package/dist/types/DrainOptions.d.ts +37 -0
- package/dist/types/DrainOptions.js +2 -0
- package/dist/types/DrainOptions.js.map +1 -0
- package/dist/types/JobDefinition.d.ts +9 -0
- package/dist/types/JobLogger.d.ts +111 -0
- package/dist/types/JobLogger.js +2 -0
- package/dist/types/JobLogger.js.map +1 -0
- package/dist/types/NotificationChannel.d.ts +49 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import type { NotificationChannel, NotificationChannelConfig, JobNotification, NotificationHandler, NotificationChannelState } from '../types/NotificationChannel.js';
|
|
2
|
+
import type { NotificationChannel, NotificationChannelConfig, JobNotification, NotificationHandler, NotificationChannelState, JobStateNotification, StateNotificationHandler } from '../types/NotificationChannel.js';
|
|
3
3
|
/**
|
|
4
4
|
* Internal config type with all properties required
|
|
5
5
|
*/
|
|
@@ -19,6 +19,7 @@ interface ResolvedNotificationChannelConfig {
|
|
|
19
19
|
export declare abstract class BaseNotificationChannel extends EventEmitter implements NotificationChannel {
|
|
20
20
|
protected _state: NotificationChannelState;
|
|
21
21
|
protected handlers: Set<NotificationHandler>;
|
|
22
|
+
protected stateHandlers: Set<StateNotificationHandler>;
|
|
22
23
|
protected reconnectAttempts: number;
|
|
23
24
|
protected reconnectTimeout?: ReturnType<typeof setTimeout>;
|
|
24
25
|
protected readonly config: ResolvedNotificationChannelConfig;
|
|
@@ -30,6 +31,16 @@ export declare abstract class BaseNotificationChannel extends EventEmitter imple
|
|
|
30
31
|
abstract publish(notification: JobNotification): Promise<void>;
|
|
31
32
|
subscribe(handler: NotificationHandler): () => void;
|
|
32
33
|
protected notifyHandlers(notification: JobNotification): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Notify all registered state handlers of a state notification.
|
|
36
|
+
* Subclasses should call this when receiving state notifications.
|
|
37
|
+
*/
|
|
38
|
+
protected notifyStateHandlers(notification: JobStateNotification): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Subscribe to state notifications.
|
|
41
|
+
* Default implementation manages the stateHandlers set.
|
|
42
|
+
*/
|
|
43
|
+
subscribeState(handler: StateNotificationHandler): () => void;
|
|
33
44
|
protected scheduleReconnect(): void;
|
|
34
45
|
protected clearReconnect(): void;
|
|
35
46
|
}
|
|
@@ -6,6 +6,7 @@ import { EventEmitter } from 'events';
|
|
|
6
6
|
export class BaseNotificationChannel extends EventEmitter {
|
|
7
7
|
_state = 'disconnected';
|
|
8
8
|
handlers = new Set();
|
|
9
|
+
stateHandlers = new Set();
|
|
9
10
|
reconnectAttempts = 0;
|
|
10
11
|
reconnectTimeout;
|
|
11
12
|
config;
|
|
@@ -51,6 +52,35 @@ export class BaseNotificationChannel extends EventEmitter {
|
|
|
51
52
|
}
|
|
52
53
|
await Promise.allSettled(promises);
|
|
53
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Notify all registered state handlers of a state notification.
|
|
57
|
+
* Subclasses should call this when receiving state notifications.
|
|
58
|
+
*/
|
|
59
|
+
async notifyStateHandlers(notification) {
|
|
60
|
+
const promises = [];
|
|
61
|
+
for (const handler of this.stateHandlers) {
|
|
62
|
+
try {
|
|
63
|
+
const result = handler(notification);
|
|
64
|
+
if (result instanceof Promise) {
|
|
65
|
+
promises.push(result);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.emit('error', error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
await Promise.allSettled(promises);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Subscribe to state notifications.
|
|
76
|
+
* Default implementation manages the stateHandlers set.
|
|
77
|
+
*/
|
|
78
|
+
subscribeState(handler) {
|
|
79
|
+
this.stateHandlers.add(handler);
|
|
80
|
+
return () => {
|
|
81
|
+
this.stateHandlers.delete(handler);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
54
84
|
scheduleReconnect() {
|
|
55
85
|
if (!this.config.reconnect.enabled) {
|
|
56
86
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseNotificationChannel.js","sourceRoot":"","sources":["../../src/notifications/BaseNotificationChannel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseNotificationChannel.js","sourceRoot":"","sources":["../../src/notifications/BaseNotificationChannel.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NotificationChannelConfig, JobNotification } from '../types/NotificationChannel.js';
|
|
1
|
+
import type { NotificationChannelConfig, JobNotification, JobStateNotification } from '../types/NotificationChannel.js';
|
|
2
2
|
import { BaseNotificationChannel } from './BaseNotificationChannel.js';
|
|
3
3
|
/**
|
|
4
4
|
* In-memory notification channel for testing and single-process scenarios.
|
|
@@ -9,4 +9,5 @@ export declare class InMemoryNotificationChannel extends BaseNotificationChannel
|
|
|
9
9
|
connect(): Promise<void>;
|
|
10
10
|
disconnect(): Promise<void>;
|
|
11
11
|
publish(notification: JobNotification): Promise<void>;
|
|
12
|
+
publishState(notification: JobStateNotification): Promise<void>;
|
|
12
13
|
}
|
|
@@ -14,6 +14,7 @@ export class InMemoryNotificationChannel extends BaseNotificationChannel {
|
|
|
14
14
|
async disconnect() {
|
|
15
15
|
this.clearReconnect();
|
|
16
16
|
this.handlers.clear();
|
|
17
|
+
this.stateHandlers.clear();
|
|
17
18
|
this.setState('disconnected');
|
|
18
19
|
}
|
|
19
20
|
async publish(notification) {
|
|
@@ -22,5 +23,11 @@ export class InMemoryNotificationChannel extends BaseNotificationChannel {
|
|
|
22
23
|
}
|
|
23
24
|
await this.notifyHandlers(notification);
|
|
24
25
|
}
|
|
26
|
+
async publishState(notification) {
|
|
27
|
+
if (this._state !== 'connected') {
|
|
28
|
+
throw new Error('Cannot publish state: channel not connected');
|
|
29
|
+
}
|
|
30
|
+
await this.notifyStateHandlers(notification);
|
|
31
|
+
}
|
|
25
32
|
}
|
|
26
33
|
//# sourceMappingURL=InMemoryNotificationChannel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InMemoryNotificationChannel.js","sourceRoot":"","sources":["../../src/notifications/InMemoryNotificationChannel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InMemoryNotificationChannel.js","sourceRoot":"","sources":["../../src/notifications/InMemoryNotificationChannel.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE;;;GAGG;AACH,MAAM,OAAO,2BAA4B,SAAQ,uBAAuB;IACvE,YAAY,SAAoC,EAAE;QACjD,KAAK,CAAC,MAAM,CAAC,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,UAAU;QACf,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,YAA6B;QAC1C,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,YAAkC;QACpD,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,IAAI,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAC9C,CAAC;CACD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { JobRepository } from './JobRepository.js';
|
|
2
2
|
import type { NotificationChannel } from './NotificationChannel.js';
|
|
3
|
+
import type { JobLogger } from './JobLogger.js';
|
|
3
4
|
/**
|
|
4
5
|
* Unified backend interface for Agenda.
|
|
5
6
|
*
|
|
@@ -29,6 +30,13 @@ export interface AgendaBackend {
|
|
|
29
30
|
* If not provided, Agenda falls back to periodic polling.
|
|
30
31
|
*/
|
|
31
32
|
readonly notificationChannel?: NotificationChannel;
|
|
33
|
+
/**
|
|
34
|
+
* Job logger for persistent job event logging.
|
|
35
|
+
* Backends provide a logger that stores events in a dedicated table/collection.
|
|
36
|
+
* The logger is lightweight and only initializes its storage on first use.
|
|
37
|
+
* Agenda activates this logger when the user enables logging via `logging: true`.
|
|
38
|
+
*/
|
|
39
|
+
readonly logger?: JobLogger;
|
|
32
40
|
/**
|
|
33
41
|
* Whether the backend owns its database connection.
|
|
34
42
|
* - true: backend created the connection (e.g., from connection string)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the drain() method
|
|
3
|
+
*/
|
|
4
|
+
export interface DrainOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Maximum time in milliseconds to wait for jobs to complete.
|
|
7
|
+
* If not specified, drain() will wait indefinitely.
|
|
8
|
+
*/
|
|
9
|
+
timeout?: number;
|
|
10
|
+
/**
|
|
11
|
+
* AbortSignal to cancel the drain operation.
|
|
12
|
+
* When aborted, drain() will resolve immediately with the current state.
|
|
13
|
+
*/
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of the drain() operation
|
|
18
|
+
*/
|
|
19
|
+
export interface DrainResult {
|
|
20
|
+
/**
|
|
21
|
+
* Number of jobs that completed during the drain
|
|
22
|
+
*/
|
|
23
|
+
completed: number;
|
|
24
|
+
/**
|
|
25
|
+
* Number of jobs still running when drain finished
|
|
26
|
+
* (only non-zero if timeout was hit or signal was aborted)
|
|
27
|
+
*/
|
|
28
|
+
running: number;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the drain finished because the timeout was reached
|
|
31
|
+
*/
|
|
32
|
+
timedOut: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the drain finished because the signal was aborted
|
|
35
|
+
*/
|
|
36
|
+
aborted: boolean;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrainOptions.js","sourceRoot":"","sources":["../../src/types/DrainOptions.ts"],"names":[],"mappings":""}
|
|
@@ -34,6 +34,15 @@ export interface JobDefinition<DATA = unknown> {
|
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
36
|
backoff?: BackoffStrategy;
|
|
37
|
+
/** Automatically remove this job from database after successful completion (one-time jobs only) */
|
|
38
|
+
removeOnComplete?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Enable or disable persistent logging for this job definition.
|
|
41
|
+
* When `false`, no log entries are written for jobs of this type,
|
|
42
|
+
* even if a global job logger is configured.
|
|
43
|
+
* Defaults to `true` (logging enabled when a job logger is configured).
|
|
44
|
+
*/
|
|
45
|
+
logging?: boolean;
|
|
37
46
|
filePath: string | undefined;
|
|
38
47
|
fn: DefinitionProcessor<DATA, void | ((error?: Error) => void)>;
|
|
39
48
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level for job event entries.
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = 'info' | 'warn' | 'error' | 'debug';
|
|
5
|
+
/**
|
|
6
|
+
* Job lifecycle events that are logged.
|
|
7
|
+
*/
|
|
8
|
+
export type JobLogEvent = 'start' | 'success' | 'fail' | 'complete' | 'retry' | 'retry:exhausted' | 'locked' | 'expired';
|
|
9
|
+
/**
|
|
10
|
+
* A structured log entry for a job lifecycle event.
|
|
11
|
+
*/
|
|
12
|
+
export interface JobLogEntry {
|
|
13
|
+
/** Unique identifier (assigned by the storage backend) */
|
|
14
|
+
_id?: string;
|
|
15
|
+
/** When the event occurred */
|
|
16
|
+
timestamp: Date;
|
|
17
|
+
/** Log severity level */
|
|
18
|
+
level: LogLevel;
|
|
19
|
+
/** The lifecycle event type */
|
|
20
|
+
event: JobLogEvent;
|
|
21
|
+
/** The job ID (if applicable) */
|
|
22
|
+
jobId?: string;
|
|
23
|
+
/** The job name */
|
|
24
|
+
jobName: string;
|
|
25
|
+
/** Human-readable message describing the event */
|
|
26
|
+
message: string;
|
|
27
|
+
/** Duration of execution in milliseconds (for success/complete events) */
|
|
28
|
+
duration?: number;
|
|
29
|
+
/** Error message (for fail events) */
|
|
30
|
+
error?: string;
|
|
31
|
+
/** Number of failures (for fail/retry events) */
|
|
32
|
+
failCount?: number;
|
|
33
|
+
/** Delay before the next retry in milliseconds (for retry events) */
|
|
34
|
+
retryDelay?: number;
|
|
35
|
+
/** The retry attempt number (for retry events) */
|
|
36
|
+
retryAttempt?: number;
|
|
37
|
+
/** The name of the Agenda instance that logged this event */
|
|
38
|
+
agendaName?: string;
|
|
39
|
+
/** Additional metadata */
|
|
40
|
+
meta?: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Query options for retrieving log entries.
|
|
44
|
+
*/
|
|
45
|
+
export interface JobLogQuery {
|
|
46
|
+
/** Filter by job ID */
|
|
47
|
+
jobId?: string;
|
|
48
|
+
/** Filter by job name */
|
|
49
|
+
jobName?: string;
|
|
50
|
+
/** Filter by log level(s) */
|
|
51
|
+
level?: LogLevel | LogLevel[];
|
|
52
|
+
/** Filter by event type(s) */
|
|
53
|
+
event?: JobLogEvent | JobLogEvent[];
|
|
54
|
+
/** Filter entries from this date (inclusive) */
|
|
55
|
+
from?: Date;
|
|
56
|
+
/** Filter entries up to this date (inclusive) */
|
|
57
|
+
to?: Date;
|
|
58
|
+
/** Maximum number of entries to return (default: 50) */
|
|
59
|
+
limit?: number;
|
|
60
|
+
/** Number of entries to skip for pagination */
|
|
61
|
+
offset?: number;
|
|
62
|
+
/** Sort direction by timestamp (default: 'desc') */
|
|
63
|
+
sort?: 'asc' | 'desc';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Result of a log query including entries and total count (for pagination).
|
|
67
|
+
*/
|
|
68
|
+
export interface JobLogQueryResult {
|
|
69
|
+
/** The log entries matching the query */
|
|
70
|
+
entries: JobLogEntry[];
|
|
71
|
+
/** Total number of entries matching the query (ignoring limit/offset) */
|
|
72
|
+
total: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Pluggable interface for persistent job event logging.
|
|
76
|
+
*
|
|
77
|
+
* Implement this interface to store job lifecycle logs in your preferred backend.
|
|
78
|
+
* Each backend package (mongo, postgres, redis) provides a built-in implementation
|
|
79
|
+
* that stores logs in a dedicated table/collection alongside the jobs.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* // Enable backend's built-in logger
|
|
84
|
+
* const agenda = new Agenda({
|
|
85
|
+
* backend: new PostgresBackend({ connectionString: '...', logging: true }),
|
|
86
|
+
* logging: true
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // Query logs
|
|
90
|
+
* const result = await agenda.getLogs({ jobName: 'myJob', limit: 100 });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export interface JobLogger {
|
|
94
|
+
/**
|
|
95
|
+
* Write a log entry.
|
|
96
|
+
* Called automatically by Agenda for each job lifecycle event.
|
|
97
|
+
* Implementations should be fast and non-blocking.
|
|
98
|
+
*/
|
|
99
|
+
log(entry: Omit<JobLogEntry, '_id'>): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Query log entries with optional filtering and pagination.
|
|
102
|
+
* Used by agendash to display logs.
|
|
103
|
+
*/
|
|
104
|
+
getLogs(query?: JobLogQuery): Promise<JobLogQueryResult>;
|
|
105
|
+
/**
|
|
106
|
+
* Delete log entries matching the query.
|
|
107
|
+
* If no query is provided, deletes ALL log entries.
|
|
108
|
+
* Returns the number of deleted entries.
|
|
109
|
+
*/
|
|
110
|
+
clearLogs(query?: JobLogQuery): Promise<number>;
|
|
111
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobLogger.js","sourceRoot":"","sources":["../../src/types/JobLogger.ts"],"names":[],"mappings":""}
|
|
@@ -10,6 +10,42 @@ export interface JobNotification {
|
|
|
10
10
|
timestamp: Date;
|
|
11
11
|
source?: string;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Types of job state events that can be published
|
|
15
|
+
*/
|
|
16
|
+
export type JobStateType = 'start' | 'progress' | 'success' | 'fail' | 'complete' | 'retry';
|
|
17
|
+
/**
|
|
18
|
+
* Notification payload sent when a job's state changes during execution.
|
|
19
|
+
* This enables bi-directional communication so that all subscribers
|
|
20
|
+
* can receive job lifecycle events (start, success, fail, complete, etc.)
|
|
21
|
+
*/
|
|
22
|
+
export interface JobStateNotification {
|
|
23
|
+
type: JobStateType;
|
|
24
|
+
jobId: JobId;
|
|
25
|
+
jobName: string;
|
|
26
|
+
timestamp: Date;
|
|
27
|
+
source?: string;
|
|
28
|
+
/** Progress percentage (0-100) for 'progress' events */
|
|
29
|
+
progress?: number;
|
|
30
|
+
/** Error message for 'fail' events */
|
|
31
|
+
error?: string;
|
|
32
|
+
/** Failure count for 'fail' events */
|
|
33
|
+
failCount?: number;
|
|
34
|
+
/** Scheduled retry time for 'retry' events */
|
|
35
|
+
retryAt?: Date;
|
|
36
|
+
/** Retry attempt number for 'retry' events */
|
|
37
|
+
retryAttempt?: number;
|
|
38
|
+
/** Job execution duration in ms for 'complete' events */
|
|
39
|
+
duration?: number;
|
|
40
|
+
/** When the job started for 'complete' events */
|
|
41
|
+
lastRunAt?: Date;
|
|
42
|
+
/** When the job finished for 'complete' events */
|
|
43
|
+
lastFinishedAt?: Date;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Handler function for processing job state notifications
|
|
47
|
+
*/
|
|
48
|
+
export type StateNotificationHandler = (notification: JobStateNotification) => void | Promise<void>;
|
|
13
49
|
/**
|
|
14
50
|
* Handler function for processing job notifications
|
|
15
51
|
*/
|
|
@@ -68,4 +104,17 @@ export interface NotificationChannel {
|
|
|
68
104
|
*/
|
|
69
105
|
off(event: 'stateChange', listener: (state: NotificationChannelState) => void): this;
|
|
70
106
|
off(event: 'error', listener: (error: Error) => void): this;
|
|
107
|
+
/**
|
|
108
|
+
* Publish a job state notification (bi-directional communication).
|
|
109
|
+
* Optional - only implement if the channel supports state notifications.
|
|
110
|
+
* @param notification - The state notification to publish
|
|
111
|
+
*/
|
|
112
|
+
publishState?(notification: JobStateNotification): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Subscribe to job state notifications (bi-directional communication).
|
|
115
|
+
* Optional - only implement if the channel supports state notifications.
|
|
116
|
+
* @param handler - Function to call when a state notification is received
|
|
117
|
+
* @returns Unsubscribe function
|
|
118
|
+
*/
|
|
119
|
+
subscribeState?(handler: StateNotificationHandler): () => void;
|
|
71
120
|
}
|