@seedcord/services 0.3.3 → 0.4.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.cts CHANGED
@@ -1,7 +1,168 @@
1
- import { ILogger, TypedExclude } from '@seedcord/types';
2
1
  import { EventEmitter } from 'node:events';
2
+ import { ILogger, TypedExclude } from '@seedcord/types';
3
3
  import { IntClosedRange, UnionToTuple } from 'type-fest';
4
4
 
5
+ /**
6
+ * Configuration options for CooldownManager.
7
+ */
8
+ interface CooldownOptions {
9
+ /** Cooldown window in milliseconds (default 1000) */
10
+ cooldown?: number;
11
+ /** Custom error class to throw when a key is still cooling down */
12
+ err?: new (msg: string, ...args: any[]) => Error;
13
+ /** Message passed to the error constructor (default "Cooldown active") */
14
+ message?: string;
15
+ }
16
+ /**
17
+ * Lightweight utility for per-key cooldowns.
18
+ *
19
+ * Manages time-based restrictions on operations by key,
20
+ * useful for rate limiting, command cooldowns, and spam prevention.
21
+ */
22
+ declare class CooldownManager {
23
+ private readonly window;
24
+ private readonly Err;
25
+ private readonly msg;
26
+ private readonly map;
27
+ /**
28
+ * Creates a new CooldownManager instance.
29
+ *
30
+ * @param opts - Configuration options for the cooldown behavior
31
+ */
32
+ constructor(opts?: CooldownOptions);
33
+ /**
34
+ * Records usage timestamp for a key without any cooldown checks.
35
+ *
36
+ * @param key - The unique identifier for the cooldown entry
37
+ */
38
+ set(key: string): void;
39
+ /**
40
+ * Verifies cooldown status for a key and updates timestamp if not active.
41
+ *
42
+ * If the cooldown is still active, throws the configured error.
43
+ * If not active, updates the timestamp and returns successfully.
44
+ *
45
+ * @param key - The unique identifier to check cooldown for
46
+ * @throws An {@link Err} When the cooldown is still active for the given key
47
+ */
48
+ check(key: string): void;
49
+ /**
50
+ * Checks if a key is currently cooling down without updating timestamp.
51
+ *
52
+ * @param key - The unique identifier to check
53
+ * @returns True if the key is still cooling down, false otherwise
54
+ */
55
+ isActive(key: string): boolean;
56
+ /**
57
+ * Removes a key from the cooldown map.
58
+ *
59
+ * @param key - The unique identifier to remove (useful for manual resets)
60
+ */
61
+ clear(key: string): void;
62
+ }
63
+
64
+ declare enum SeedcordErrorCode {
65
+ ConfigMissingDiscordToken = 1001,
66
+ ConfigUnknownExceptionWebhookMissing = 1002,
67
+ ConfigUnknownExceptionWebhookInvalid = 1003,
68
+ LifecycleAddAfterCompletion = 1101,
69
+ LifecycleAddDuringRun = 1102,
70
+ LifecycleRemoveDuringRun = 1103,
71
+ LifecycleUnknownPhase = 1104,
72
+ LifecyclePhaseFailures = 1105,
73
+ LifecycleTaskTimeout = 1106,
74
+ CoreSingletonViolation = 1201,
75
+ CorePluginAfterInit = 1202,
76
+ CorePluginKeyExists = 1203,
77
+ CoreClientUserUnavailable = 1204,
78
+ CoreBotRoleMissing = 1205,
79
+ DecoratorInteractionEventFilter = 1301,
80
+ DecoratorMethodNotFound = 1302,
81
+ DecoratorCommandAlreadyRegistered = 1303,
82
+ DecoratorCommandGlobalWithGuilds = 1304,
83
+ DecoratorCommandGuildWithoutGuilds = 1305,
84
+ DecoratorInvalidMiddlewarePriority = 1306,
85
+ UtilHexInputType = 1401,
86
+ UtilHexInvalid = 1402,
87
+ UtilInvalidSlashRouteArgument = 1403,
88
+ PluginMongoServiceDecoratorMissing = 2101,
89
+ PluginMongoModelDecoratorMissing = 2102,
90
+ PluginMongoConnectionFailed = 2103,
91
+ PluginKpgServiceDecoratorMissing = 2201,
92
+ PluginKpgServiceTableMissing = 2202,
93
+ PluginKpgInvalidStepCount = 2203,
94
+ PluginKpgUnknownDirection = 2204,
95
+ PluginKpgUnresolvedMigrationsPath = 2205,
96
+ PluginKpgNoMigrationFiles = 2206,
97
+ PluginKpgInvalidMigrationModule = 2207,
98
+ PluginKpgNonErrorFailure = 2208
99
+ }
100
+
101
+ declare const messages: {
102
+ readonly 1001: () => string;
103
+ readonly 1002: () => string;
104
+ readonly 1003: () => string;
105
+ readonly 1101: () => string;
106
+ readonly 1102: () => string;
107
+ readonly 1103: () => string;
108
+ readonly 1104: (phase: unknown) => string;
109
+ readonly 1105: (phase: string, failures: number) => string;
110
+ readonly 1106: (taskName: string, timeout: number) => string;
111
+ readonly 1201: () => string;
112
+ readonly 1202: () => string;
113
+ readonly 1203: (key: string) => string;
114
+ readonly 1204: () => string;
115
+ readonly 1205: (guildId?: string) => string;
116
+ readonly 1301: () => string;
117
+ readonly 1302: () => string;
118
+ readonly 1303: (commandName: string, existingScope: string, requestedScope: string) => string;
119
+ readonly 1304: () => string;
120
+ readonly 1305: () => string;
121
+ readonly 1306: () => string;
122
+ readonly 1401: () => string;
123
+ readonly 1402: () => string;
124
+ readonly 1403: () => string;
125
+ readonly 2101: (className: string) => string;
126
+ readonly 2102: (className: string) => string;
127
+ readonly 2103: (databaseName?: string) => string;
128
+ readonly 2201: (className: string) => string;
129
+ readonly 2202: (className: string) => string;
130
+ readonly 2203: () => string;
131
+ readonly 2204: (direction: unknown) => string;
132
+ readonly 2205: (label: string) => string;
133
+ readonly 2206: () => string;
134
+ readonly 2207: (filePath: string) => string;
135
+ readonly 2208: (message: string) => string;
136
+ };
137
+ type SeedcordErrorArguments<TCode extends SeedcordErrorCode> = Parameters<(typeof messages)[TCode]>;
138
+ declare function formatSeedcordErrorMessage<TCode extends SeedcordErrorCode>(code: TCode, args?: SeedcordErrorArguments<TCode>): string;
139
+
140
+ type SeedcordErrorIdentifier = keyof typeof SeedcordErrorCode;
141
+ interface SeedcordErrorOptions extends ErrorOptions {
142
+ }
143
+ declare class SeedcordError extends Error {
144
+ readonly code: SeedcordErrorCode;
145
+ readonly identifier: SeedcordErrorIdentifier;
146
+ constructor(code: SeedcordErrorCode, args?: SeedcordErrorArguments<SeedcordErrorCode>, options?: SeedcordErrorOptions);
147
+ }
148
+ declare class SeedcordTypeError extends TypeError {
149
+ readonly code: SeedcordErrorCode;
150
+ readonly identifier: SeedcordErrorIdentifier;
151
+ constructor(code: SeedcordErrorCode, args?: SeedcordErrorArguments<SeedcordErrorCode>, options?: SeedcordErrorOptions);
152
+ }
153
+ declare class SeedcordRangeError extends RangeError {
154
+ readonly code: SeedcordErrorCode;
155
+ readonly identifier: SeedcordErrorIdentifier;
156
+ constructor(code: SeedcordErrorCode, args?: SeedcordErrorArguments<SeedcordErrorCode>, options?: SeedcordErrorOptions);
157
+ }
158
+ declare const SeedcordErrors: {
159
+ readonly Error: typeof SeedcordError;
160
+ readonly TypeError: typeof SeedcordTypeError;
161
+ readonly RangeError: typeof SeedcordRangeError;
162
+ };
163
+ type AnySeedcordError = SeedcordError | SeedcordTypeError | SeedcordRangeError;
164
+ declare function isSeedcordError(error: unknown): error is AnySeedcordError;
165
+
5
166
  /**
6
167
  * Logging service with console and file output support
7
168
  *
@@ -304,63 +465,111 @@ declare class HealthCheck {
304
465
  stop(): Promise<void>;
305
466
  }
306
467
 
468
+ /** Tuple type used for all event payloads. */
469
+ type SEArgsTuple = readonly unknown[];
470
+ /** Convenience map for emitters that intentionally expose no events. */
471
+ type SENoEvents = Record<never, SEArgsTuple>;
307
472
  /**
308
- * Configuration options for CooldownManager.
473
+ * Accepts any object type and constrains every value to be a tuple.
474
+ *
475
+ * @typeParam TEvents - Map of event names to readonly tuple payloads
309
476
  */
310
- interface CooldownOptions {
311
- /** Cooldown window in milliseconds (default 1000) */
312
- cooldown?: number;
313
- /** Custom error class to throw when a key is still cooling down */
314
- err?: new (msg: string, ...args: any[]) => Error;
315
- /** Message passed to the error constructor (default "Cooldown active") */
316
- message?: string;
317
- }
477
+ type SEEventMapLike<TEvents extends object> = {
478
+ [K in keyof TEvents]: SEArgsTuple;
479
+ };
318
480
  /**
319
- * Lightweight utility for per-key cooldowns.
481
+ * Narrows a provided event map to the keys that can be emitted or listened for.
320
482
  *
321
- * Manages time-based restrictions on operations by key,
322
- * useful for rate limiting, command cooldowns, and spam prevention.
483
+ * @typeParam TEvents - Map of event names to readonly tuple payloads
484
+ * @internal
323
485
  */
324
- declare class CooldownManager {
325
- private readonly window;
326
- private readonly Err;
327
- private readonly msg;
328
- private readonly map;
486
+ type SEEventKey<TEvents extends object> = Extract<keyof TEvents, string | symbol>;
487
+ /**
488
+ * Typed wrapper around Node.js {@link EventEmitter} enforcing tuple payloads per event name.
489
+ *
490
+ * @typeParam TEvents - Map of event names to readonly tuple payloads
491
+ */
492
+ declare class StrictEventEmitter<TEvents extends SEEventMapLike<TEvents>> extends EventEmitter {
329
493
  /**
330
- * Creates a new CooldownManager instance.
494
+ * Registers a persistent listener with tuple-safe arguments for the given event.
331
495
  *
332
- * @param opts - Configuration options for the cooldown behavior
496
+ * @param event - The event name to attach to
497
+ * @param listener - Callback operating on the typed argument tuple for the event
498
+ * @returns This emitter instance for chaining
333
499
  */
334
- constructor(opts?: CooldownOptions);
500
+ on<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
335
501
  /**
336
- * Records usage timestamp for a key without any cooldown checks.
502
+ * Registers a one time listener that is removed after the first invocation.
337
503
  *
338
- * @param key - The unique identifier for the cooldown entry
504
+ * @param event - The event name to attach to
505
+ * @param listener - Callback operating on the typed argument tuple for the event
506
+ * @returns This emitter instance for chaining
339
507
  */
340
- set(key: string): void;
508
+ once<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
341
509
  /**
342
- * Verifies cooldown status for a key and updates timestamp if not active.
510
+ * Removes a previously registered listener for the given event.
343
511
  *
344
- * If the cooldown is still active, throws the configured error.
345
- * If not active, updates the timestamp and returns successfully.
512
+ * @param event - The event name whose listener should be removed
513
+ * @param listener - Callback originally registered for the event
514
+ * @returns This emitter instance for chaining
515
+ */
516
+ off<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
517
+ /**
518
+ * Alias of {@link StrictEventEmitter.on} for compatibility with Node.js EventEmitter APIs.
346
519
  *
347
- * @param key - The unique identifier to check cooldown for
348
- * @throws An {@link Err} When the cooldown is still active for the given key
520
+ * @param event - The event name to attach to
521
+ * @param listener - Callback operating on the typed argument tuple for the event
522
+ * @returns This emitter instance for chaining
349
523
  */
350
- check(key: string): void;
524
+ addListener<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
351
525
  /**
352
- * Checks if a key is currently cooling down without updating timestamp.
526
+ * Alias of {@link StrictEventEmitter.off} for compatibility with Node.js EventEmitter APIs.
353
527
  *
354
- * @param key - The unique identifier to check
355
- * @returns True if the key is still cooling down, false otherwise
528
+ * @param event - The event name whose listener should be removed
529
+ * @param listener - Callback originally registered for the event
530
+ * @returns This emitter instance for chaining
356
531
  */
357
- isActive(key: string): boolean;
532
+ removeListener<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
358
533
  /**
359
- * Removes a key from the cooldown map.
534
+ * Emits an event with the strictly typed argument tuple for the event name.
360
535
  *
361
- * @param key - The unique identifier to remove (useful for manual resets)
536
+ * @param event - The event name to emit
537
+ * @param args - Tuple payload for the event
538
+ * @returns True when the event had listeners, false otherwise
362
539
  */
363
- clear(key: string): void;
540
+ emit<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, ...args: TEvents[TEventKey]): boolean;
541
+ /**
542
+ * Retrieves the listener list for a given event with the correct tuple signature.
543
+ *
544
+ * @param event - The event name to inspect
545
+ * @returns Array of listeners registered for the event
546
+ */
547
+ listeners<TEventKey extends SEEventKey<TEvents>>(event: TEventKey): ((...args: TEvents[TEventKey]) => void)[];
548
+ /**
549
+ * Counts listeners for an event without widening the return type of {@link EventEmitter.listenerCount}.
550
+ *
551
+ * @param event - The event name to inspect
552
+ * @returns The total number of listeners registered for the event
553
+ */
554
+ listenerCountTyped<TEventKey extends SEEventKey<TEvents>>(event: TEventKey): number;
555
+ /**
556
+ * Returns the list of event names known to the emitter with the mapped key type.
557
+ *
558
+ * @returns Array of event keys supported by the emitter
559
+ */
560
+ eventNamesTyped(): SEEventKey<TEvents>[];
561
+ /**
562
+ * Waits for an event to be emitted, resolving with the listener arguments tuple once triggered.
563
+ * Supports optional abort signals and timeouts for cancellation semantics.
564
+ *
565
+ * @param event - The event name to wait for
566
+ * @param opts - Optional abort signal or timeout in milliseconds
567
+ * @returns Promise resolving with the emitted argument tuple; rejects when aborted or timed out
568
+ */
569
+ waitFor<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, opts?: {
570
+ signal?: AbortSignal;
571
+ timeoutMs?: number;
572
+ }): Promise<TEvents[TEventKey]>;
364
573
  }
365
574
 
366
575
  /**
@@ -446,4 +655,4 @@ declare class CoordinatedStartup extends CoordinatedLifecycle<StartupPhase> {
446
655
  get isRunning(): boolean;
447
656
  }
448
657
 
449
- export { CooldownManager, type CooldownOptions, CoordinatedLifecycle, CoordinatedShutdown, type CoordinatedShutdownEventKey, CoordinatedStartup, type CoordinatedStartupEventKey, HealthCheck, type LifecycleAction, type LifecycleTask, Logger, type PhaseEvents, ShutdownPhase, StartupPhase };
658
+ export { type AnySeedcordError, CooldownManager, type CooldownOptions, CoordinatedLifecycle, CoordinatedShutdown, type CoordinatedShutdownEventKey, CoordinatedStartup, type CoordinatedStartupEventKey, HealthCheck, type LifecycleAction, type LifecycleTask, Logger, type PhaseEvents, type SEArgsTuple, type SEEventKey, type SEEventMapLike, type SENoEvents, SeedcordError, type SeedcordErrorArguments, SeedcordErrorCode, type SeedcordErrorIdentifier, type SeedcordErrorOptions, SeedcordErrors, SeedcordRangeError, SeedcordTypeError, ShutdownPhase, StartupPhase, StrictEventEmitter, formatSeedcordErrorMessage, isSeedcordError, messages as seedcordErrorMessages };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,168 @@
1
- import { ILogger, TypedExclude } from '@seedcord/types';
2
1
  import { EventEmitter } from 'node:events';
2
+ import { ILogger, TypedExclude } from '@seedcord/types';
3
3
  import { IntClosedRange, UnionToTuple } from 'type-fest';
4
4
 
5
+ /**
6
+ * Configuration options for CooldownManager.
7
+ */
8
+ interface CooldownOptions {
9
+ /** Cooldown window in milliseconds (default 1000) */
10
+ cooldown?: number;
11
+ /** Custom error class to throw when a key is still cooling down */
12
+ err?: new (msg: string, ...args: any[]) => Error;
13
+ /** Message passed to the error constructor (default "Cooldown active") */
14
+ message?: string;
15
+ }
16
+ /**
17
+ * Lightweight utility for per-key cooldowns.
18
+ *
19
+ * Manages time-based restrictions on operations by key,
20
+ * useful for rate limiting, command cooldowns, and spam prevention.
21
+ */
22
+ declare class CooldownManager {
23
+ private readonly window;
24
+ private readonly Err;
25
+ private readonly msg;
26
+ private readonly map;
27
+ /**
28
+ * Creates a new CooldownManager instance.
29
+ *
30
+ * @param opts - Configuration options for the cooldown behavior
31
+ */
32
+ constructor(opts?: CooldownOptions);
33
+ /**
34
+ * Records usage timestamp for a key without any cooldown checks.
35
+ *
36
+ * @param key - The unique identifier for the cooldown entry
37
+ */
38
+ set(key: string): void;
39
+ /**
40
+ * Verifies cooldown status for a key and updates timestamp if not active.
41
+ *
42
+ * If the cooldown is still active, throws the configured error.
43
+ * If not active, updates the timestamp and returns successfully.
44
+ *
45
+ * @param key - The unique identifier to check cooldown for
46
+ * @throws An {@link Err} When the cooldown is still active for the given key
47
+ */
48
+ check(key: string): void;
49
+ /**
50
+ * Checks if a key is currently cooling down without updating timestamp.
51
+ *
52
+ * @param key - The unique identifier to check
53
+ * @returns True if the key is still cooling down, false otherwise
54
+ */
55
+ isActive(key: string): boolean;
56
+ /**
57
+ * Removes a key from the cooldown map.
58
+ *
59
+ * @param key - The unique identifier to remove (useful for manual resets)
60
+ */
61
+ clear(key: string): void;
62
+ }
63
+
64
+ declare enum SeedcordErrorCode {
65
+ ConfigMissingDiscordToken = 1001,
66
+ ConfigUnknownExceptionWebhookMissing = 1002,
67
+ ConfigUnknownExceptionWebhookInvalid = 1003,
68
+ LifecycleAddAfterCompletion = 1101,
69
+ LifecycleAddDuringRun = 1102,
70
+ LifecycleRemoveDuringRun = 1103,
71
+ LifecycleUnknownPhase = 1104,
72
+ LifecyclePhaseFailures = 1105,
73
+ LifecycleTaskTimeout = 1106,
74
+ CoreSingletonViolation = 1201,
75
+ CorePluginAfterInit = 1202,
76
+ CorePluginKeyExists = 1203,
77
+ CoreClientUserUnavailable = 1204,
78
+ CoreBotRoleMissing = 1205,
79
+ DecoratorInteractionEventFilter = 1301,
80
+ DecoratorMethodNotFound = 1302,
81
+ DecoratorCommandAlreadyRegistered = 1303,
82
+ DecoratorCommandGlobalWithGuilds = 1304,
83
+ DecoratorCommandGuildWithoutGuilds = 1305,
84
+ DecoratorInvalidMiddlewarePriority = 1306,
85
+ UtilHexInputType = 1401,
86
+ UtilHexInvalid = 1402,
87
+ UtilInvalidSlashRouteArgument = 1403,
88
+ PluginMongoServiceDecoratorMissing = 2101,
89
+ PluginMongoModelDecoratorMissing = 2102,
90
+ PluginMongoConnectionFailed = 2103,
91
+ PluginKpgServiceDecoratorMissing = 2201,
92
+ PluginKpgServiceTableMissing = 2202,
93
+ PluginKpgInvalidStepCount = 2203,
94
+ PluginKpgUnknownDirection = 2204,
95
+ PluginKpgUnresolvedMigrationsPath = 2205,
96
+ PluginKpgNoMigrationFiles = 2206,
97
+ PluginKpgInvalidMigrationModule = 2207,
98
+ PluginKpgNonErrorFailure = 2208
99
+ }
100
+
101
+ declare const messages: {
102
+ readonly 1001: () => string;
103
+ readonly 1002: () => string;
104
+ readonly 1003: () => string;
105
+ readonly 1101: () => string;
106
+ readonly 1102: () => string;
107
+ readonly 1103: () => string;
108
+ readonly 1104: (phase: unknown) => string;
109
+ readonly 1105: (phase: string, failures: number) => string;
110
+ readonly 1106: (taskName: string, timeout: number) => string;
111
+ readonly 1201: () => string;
112
+ readonly 1202: () => string;
113
+ readonly 1203: (key: string) => string;
114
+ readonly 1204: () => string;
115
+ readonly 1205: (guildId?: string) => string;
116
+ readonly 1301: () => string;
117
+ readonly 1302: () => string;
118
+ readonly 1303: (commandName: string, existingScope: string, requestedScope: string) => string;
119
+ readonly 1304: () => string;
120
+ readonly 1305: () => string;
121
+ readonly 1306: () => string;
122
+ readonly 1401: () => string;
123
+ readonly 1402: () => string;
124
+ readonly 1403: () => string;
125
+ readonly 2101: (className: string) => string;
126
+ readonly 2102: (className: string) => string;
127
+ readonly 2103: (databaseName?: string) => string;
128
+ readonly 2201: (className: string) => string;
129
+ readonly 2202: (className: string) => string;
130
+ readonly 2203: () => string;
131
+ readonly 2204: (direction: unknown) => string;
132
+ readonly 2205: (label: string) => string;
133
+ readonly 2206: () => string;
134
+ readonly 2207: (filePath: string) => string;
135
+ readonly 2208: (message: string) => string;
136
+ };
137
+ type SeedcordErrorArguments<TCode extends SeedcordErrorCode> = Parameters<(typeof messages)[TCode]>;
138
+ declare function formatSeedcordErrorMessage<TCode extends SeedcordErrorCode>(code: TCode, args?: SeedcordErrorArguments<TCode>): string;
139
+
140
+ type SeedcordErrorIdentifier = keyof typeof SeedcordErrorCode;
141
+ interface SeedcordErrorOptions extends ErrorOptions {
142
+ }
143
+ declare class SeedcordError extends Error {
144
+ readonly code: SeedcordErrorCode;
145
+ readonly identifier: SeedcordErrorIdentifier;
146
+ constructor(code: SeedcordErrorCode, args?: SeedcordErrorArguments<SeedcordErrorCode>, options?: SeedcordErrorOptions);
147
+ }
148
+ declare class SeedcordTypeError extends TypeError {
149
+ readonly code: SeedcordErrorCode;
150
+ readonly identifier: SeedcordErrorIdentifier;
151
+ constructor(code: SeedcordErrorCode, args?: SeedcordErrorArguments<SeedcordErrorCode>, options?: SeedcordErrorOptions);
152
+ }
153
+ declare class SeedcordRangeError extends RangeError {
154
+ readonly code: SeedcordErrorCode;
155
+ readonly identifier: SeedcordErrorIdentifier;
156
+ constructor(code: SeedcordErrorCode, args?: SeedcordErrorArguments<SeedcordErrorCode>, options?: SeedcordErrorOptions);
157
+ }
158
+ declare const SeedcordErrors: {
159
+ readonly Error: typeof SeedcordError;
160
+ readonly TypeError: typeof SeedcordTypeError;
161
+ readonly RangeError: typeof SeedcordRangeError;
162
+ };
163
+ type AnySeedcordError = SeedcordError | SeedcordTypeError | SeedcordRangeError;
164
+ declare function isSeedcordError(error: unknown): error is AnySeedcordError;
165
+
5
166
  /**
6
167
  * Logging service with console and file output support
7
168
  *
@@ -304,63 +465,111 @@ declare class HealthCheck {
304
465
  stop(): Promise<void>;
305
466
  }
306
467
 
468
+ /** Tuple type used for all event payloads. */
469
+ type SEArgsTuple = readonly unknown[];
470
+ /** Convenience map for emitters that intentionally expose no events. */
471
+ type SENoEvents = Record<never, SEArgsTuple>;
307
472
  /**
308
- * Configuration options for CooldownManager.
473
+ * Accepts any object type and constrains every value to be a tuple.
474
+ *
475
+ * @typeParam TEvents - Map of event names to readonly tuple payloads
309
476
  */
310
- interface CooldownOptions {
311
- /** Cooldown window in milliseconds (default 1000) */
312
- cooldown?: number;
313
- /** Custom error class to throw when a key is still cooling down */
314
- err?: new (msg: string, ...args: any[]) => Error;
315
- /** Message passed to the error constructor (default "Cooldown active") */
316
- message?: string;
317
- }
477
+ type SEEventMapLike<TEvents extends object> = {
478
+ [K in keyof TEvents]: SEArgsTuple;
479
+ };
318
480
  /**
319
- * Lightweight utility for per-key cooldowns.
481
+ * Narrows a provided event map to the keys that can be emitted or listened for.
320
482
  *
321
- * Manages time-based restrictions on operations by key,
322
- * useful for rate limiting, command cooldowns, and spam prevention.
483
+ * @typeParam TEvents - Map of event names to readonly tuple payloads
484
+ * @internal
323
485
  */
324
- declare class CooldownManager {
325
- private readonly window;
326
- private readonly Err;
327
- private readonly msg;
328
- private readonly map;
486
+ type SEEventKey<TEvents extends object> = Extract<keyof TEvents, string | symbol>;
487
+ /**
488
+ * Typed wrapper around Node.js {@link EventEmitter} enforcing tuple payloads per event name.
489
+ *
490
+ * @typeParam TEvents - Map of event names to readonly tuple payloads
491
+ */
492
+ declare class StrictEventEmitter<TEvents extends SEEventMapLike<TEvents>> extends EventEmitter {
329
493
  /**
330
- * Creates a new CooldownManager instance.
494
+ * Registers a persistent listener with tuple-safe arguments for the given event.
331
495
  *
332
- * @param opts - Configuration options for the cooldown behavior
496
+ * @param event - The event name to attach to
497
+ * @param listener - Callback operating on the typed argument tuple for the event
498
+ * @returns This emitter instance for chaining
333
499
  */
334
- constructor(opts?: CooldownOptions);
500
+ on<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
335
501
  /**
336
- * Records usage timestamp for a key without any cooldown checks.
502
+ * Registers a one time listener that is removed after the first invocation.
337
503
  *
338
- * @param key - The unique identifier for the cooldown entry
504
+ * @param event - The event name to attach to
505
+ * @param listener - Callback operating on the typed argument tuple for the event
506
+ * @returns This emitter instance for chaining
339
507
  */
340
- set(key: string): void;
508
+ once<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
341
509
  /**
342
- * Verifies cooldown status for a key and updates timestamp if not active.
510
+ * Removes a previously registered listener for the given event.
343
511
  *
344
- * If the cooldown is still active, throws the configured error.
345
- * If not active, updates the timestamp and returns successfully.
512
+ * @param event - The event name whose listener should be removed
513
+ * @param listener - Callback originally registered for the event
514
+ * @returns This emitter instance for chaining
515
+ */
516
+ off<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
517
+ /**
518
+ * Alias of {@link StrictEventEmitter.on} for compatibility with Node.js EventEmitter APIs.
346
519
  *
347
- * @param key - The unique identifier to check cooldown for
348
- * @throws An {@link Err} When the cooldown is still active for the given key
520
+ * @param event - The event name to attach to
521
+ * @param listener - Callback operating on the typed argument tuple for the event
522
+ * @returns This emitter instance for chaining
349
523
  */
350
- check(key: string): void;
524
+ addListener<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
351
525
  /**
352
- * Checks if a key is currently cooling down without updating timestamp.
526
+ * Alias of {@link StrictEventEmitter.off} for compatibility with Node.js EventEmitter APIs.
353
527
  *
354
- * @param key - The unique identifier to check
355
- * @returns True if the key is still cooling down, false otherwise
528
+ * @param event - The event name whose listener should be removed
529
+ * @param listener - Callback originally registered for the event
530
+ * @returns This emitter instance for chaining
356
531
  */
357
- isActive(key: string): boolean;
532
+ removeListener<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, listener: (...args: TEvents[TEventKey]) => void): this;
358
533
  /**
359
- * Removes a key from the cooldown map.
534
+ * Emits an event with the strictly typed argument tuple for the event name.
360
535
  *
361
- * @param key - The unique identifier to remove (useful for manual resets)
536
+ * @param event - The event name to emit
537
+ * @param args - Tuple payload for the event
538
+ * @returns True when the event had listeners, false otherwise
362
539
  */
363
- clear(key: string): void;
540
+ emit<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, ...args: TEvents[TEventKey]): boolean;
541
+ /**
542
+ * Retrieves the listener list for a given event with the correct tuple signature.
543
+ *
544
+ * @param event - The event name to inspect
545
+ * @returns Array of listeners registered for the event
546
+ */
547
+ listeners<TEventKey extends SEEventKey<TEvents>>(event: TEventKey): ((...args: TEvents[TEventKey]) => void)[];
548
+ /**
549
+ * Counts listeners for an event without widening the return type of {@link EventEmitter.listenerCount}.
550
+ *
551
+ * @param event - The event name to inspect
552
+ * @returns The total number of listeners registered for the event
553
+ */
554
+ listenerCountTyped<TEventKey extends SEEventKey<TEvents>>(event: TEventKey): number;
555
+ /**
556
+ * Returns the list of event names known to the emitter with the mapped key type.
557
+ *
558
+ * @returns Array of event keys supported by the emitter
559
+ */
560
+ eventNamesTyped(): SEEventKey<TEvents>[];
561
+ /**
562
+ * Waits for an event to be emitted, resolving with the listener arguments tuple once triggered.
563
+ * Supports optional abort signals and timeouts for cancellation semantics.
564
+ *
565
+ * @param event - The event name to wait for
566
+ * @param opts - Optional abort signal or timeout in milliseconds
567
+ * @returns Promise resolving with the emitted argument tuple; rejects when aborted or timed out
568
+ */
569
+ waitFor<TEventKey extends SEEventKey<TEvents>>(event: TEventKey, opts?: {
570
+ signal?: AbortSignal;
571
+ timeoutMs?: number;
572
+ }): Promise<TEvents[TEventKey]>;
364
573
  }
365
574
 
366
575
  /**
@@ -446,4 +655,4 @@ declare class CoordinatedStartup extends CoordinatedLifecycle<StartupPhase> {
446
655
  get isRunning(): boolean;
447
656
  }
448
657
 
449
- export { CooldownManager, type CooldownOptions, CoordinatedLifecycle, CoordinatedShutdown, type CoordinatedShutdownEventKey, CoordinatedStartup, type CoordinatedStartupEventKey, HealthCheck, type LifecycleAction, type LifecycleTask, Logger, type PhaseEvents, ShutdownPhase, StartupPhase };
658
+ export { type AnySeedcordError, CooldownManager, type CooldownOptions, CoordinatedLifecycle, CoordinatedShutdown, type CoordinatedShutdownEventKey, CoordinatedStartup, type CoordinatedStartupEventKey, HealthCheck, type LifecycleAction, type LifecycleTask, Logger, type PhaseEvents, type SEArgsTuple, type SEEventKey, type SEEventMapLike, type SENoEvents, SeedcordError, type SeedcordErrorArguments, SeedcordErrorCode, type SeedcordErrorIdentifier, type SeedcordErrorOptions, SeedcordErrors, SeedcordRangeError, SeedcordTypeError, ShutdownPhase, StartupPhase, StrictEventEmitter, formatSeedcordErrorMessage, isSeedcordError, messages as seedcordErrorMessages };