ocpp-ws-io 2.1.3 → 2.1.4

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.
@@ -4486,6 +4486,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4486
4486
  private _badMessageCount;
4487
4487
  private _lastActivity;
4488
4488
  private _outboundBuffer;
4489
+ private _offlineQueue;
4489
4490
  private _middleware;
4490
4491
  private _validators;
4491
4492
  private _strictProtocols;
@@ -4557,7 +4558,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4557
4558
  *
4558
4559
  * @throws {Error} If a handler for this version and method is already registered on this client instance.
4559
4560
  */
4560
- handle<V extends OCPPProtocol, M extends AllMethodNames<V>>(version: V, method: M, handler: (context: HandlerContext<OCPPRequestType<V, M>>) => OCPPResponseType<V, M> | Promise<OCPPResponseType<V, M>>): void;
4561
+ handle<V extends OCPPProtocol, M extends AllMethodNames<V>>(version: V, method: M, handler: (context: HandlerContext<OCPPRequestType<V, M>>) => OCPPResponseType<V, M> | Promise<OCPPResponseType<V, M>> | typeof NOREPLY): void;
4561
4562
  /**
4562
4563
  * Register a handler for a custom/extension protocol/method not in the typed OCPP method maps.
4563
4564
  * `handle("my-protocol", "my-method", handler)`
@@ -4573,7 +4574,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4573
4574
  *
4574
4575
  * @throws {Error} If a handler for this method is already registered on this client instance.
4575
4576
  */
4576
- handle<M extends AllMethodNames<P>>(method: M, handler: (context: HandlerContext<OCPPRequestType<P, M>>) => OCPPResponseType<P, M> | Promise<OCPPResponseType<P, M>>): void;
4577
+ handle<M extends AllMethodNames<P>>(method: M, handler: (context: HandlerContext<OCPPRequestType<P, M>>) => OCPPResponseType<P, M> | Promise<OCPPResponseType<P, M>> | typeof NOREPLY): void;
4577
4578
  /**
4578
4579
  * Register a handler for a custom/extension method not in the typed OCPP method maps.
4579
4580
  *
@@ -4653,6 +4654,26 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4653
4654
  /** Errors that should stop reconnection immediately */
4654
4655
  private static readonly _INTOLERABLE_ERRORS;
4655
4656
  private _scheduleReconnect;
4657
+ /**
4658
+ * Atomically drains the offline queue and sends each message via _sendCall.
4659
+ * Uses splice(0) to prevent re-entry bugs (double billing) if the connection
4660
+ * drops again mid-flush — the queue is empty before any sends begin.
4661
+ */
4662
+ private _flushOfflineQueue;
4663
+ /**
4664
+ * Retry wrapper using Full Jitter exponential backoff.
4665
+ * delay = random(0, min(retryMaxDelayMs, retryDelayMs * 2^attempt))
4666
+ * Only retries on TimeoutError — all other errors propagate immediately.
4667
+ */
4668
+ private _callWithRetry;
4669
+ /** Maximum bytes allowed in the ws send buffer before applying backpressure (512KB) */
4670
+ private static readonly _BACKPRESSURE_THRESHOLD;
4671
+ /**
4672
+ * Wraps ws.send() with backpressure protection.
4673
+ * If bufferedAmount exceeds the threshold, waits for the buffer to drain
4674
+ * before sending. Prevents OOM on slow 2G/3G charger connections.
4675
+ */
4676
+ private _safeSend;
4656
4677
  private _startPing;
4657
4678
  private _stopPing;
4658
4679
  private _recordActivity;
@@ -4829,6 +4850,22 @@ interface CallOptions {
4829
4850
  timeoutMs?: number;
4830
4851
  /** Abort signal */
4831
4852
  signal?: AbortSignal;
4853
+ /**
4854
+ * Max retry attempts on TimeoutError (default: 0 = no retry).
4855
+ * Uses Full Jitter exponential backoff between retries.
4856
+ */
4857
+ retries?: number;
4858
+ /** Base delay in ms for exponential backoff between retries (default: 1000) */
4859
+ retryDelayMs?: number;
4860
+ /** Max delay cap in ms to prevent unbounded backoff (default: 30000) */
4861
+ retryMaxDelayMs?: number;
4862
+ /**
4863
+ * Idempotency key for deduplication. If provided, this value is used
4864
+ * as the OCPP messageId instead of generating a new random one.
4865
+ * Consumers can use the same key to guarantee exactly-once semantics
4866
+ * when retrying calls across reconnections.
4867
+ */
4868
+ idempotencyKey?: string;
4832
4869
  }
4833
4870
  interface CloseOptions {
4834
4871
  /** WebSocket close code (default: 1000) */
@@ -5014,6 +5051,16 @@ interface ClientOptions {
5014
5051
  logging?: LoggingConfig | false;
5015
5052
  /** Rate Limiting configuration (Token Bucket) */
5016
5053
  rateLimit?: RateLimitOptions;
5054
+ /**
5055
+ * If true, calls made while disconnected are queued in-memory
5056
+ * and flushed automatically on reconnect. (default: false)
5057
+ */
5058
+ offlineQueue?: boolean;
5059
+ /**
5060
+ * Maximum number of messages to queue while offline.
5061
+ * Oldest messages are dropped when exceeded. (default: 100)
5062
+ */
5063
+ offlineQueueMaxSize?: number;
5017
5064
  }
5018
5065
  interface RateLimitOptions {
5019
5066
  /** Maximum number of messages allowed within the window */
@@ -5109,6 +5156,29 @@ interface ServerOptions {
5109
5156
  * - `LoggingConfig` → custom configuration
5110
5157
  */
5111
5158
  logging?: LoggingConfig | false;
5159
+ /**
5160
+ * Connection-level rate limiting (per-IP) applied at the HTTP upgrade boundary,
5161
+ * before any auth, TLS or JSON parsing occurs — blocks DDoS connection floods in ~1µs.
5162
+ * - `limit`: Max upgrade requests per IP within `windowMs` (default: 20)
5163
+ * - `windowMs`: Sliding window in ms (default: 10000)
5164
+ */
5165
+ connectionRateLimit?: {
5166
+ limit: number;
5167
+ windowMs: number;
5168
+ };
5169
+ /**
5170
+ * Maximum number of inactive sessions to retain in the bounded LRU cache.
5171
+ * Prevents OOM under DDoS or reconnection storms with transient identities.
5172
+ * (default: 50000)
5173
+ */
5174
+ maxSessions?: number;
5175
+ /**
5176
+ * Enable the built-in HTTP health/metrics endpoint.
5177
+ * When enabled, non-upgrade HTTP requests to `/health` return a JSON health check,
5178
+ * and requests to `/metrics` return Prometheus-compatible text metrics.
5179
+ * (default: false)
5180
+ */
5181
+ healthEndpoint?: boolean;
5112
5182
  }
5113
5183
  interface OCPPServerStats {
5114
5184
  /** Number of currently connected WebSockets */
@@ -5219,6 +5289,15 @@ interface EventAdapterInterface {
5219
5289
  getPresence?(identity: string): Promise<string | null>;
5220
5290
  getPresenceBatch?(identities: string[]): Promise<(string | null)[]>;
5221
5291
  removePresence?(identity: string): Promise<void>;
5292
+ /**
5293
+ * Batch set multiple presence entries in a single pipeline.
5294
+ * Reduces N network round-trips to 1 for bulk presence updates.
5295
+ */
5296
+ setPresenceBatch?(entries: {
5297
+ identity: string;
5298
+ nodeId: string;
5299
+ ttl?: number;
5300
+ }[]): Promise<void>;
5222
5301
  metrics?(): Promise<Record<string, unknown>>;
5223
5302
  }
5224
5303
  declare const NOREPLY: unique symbol;
@@ -5287,6 +5366,16 @@ interface RedisAdapterOptions {
5287
5366
  prefix?: string;
5288
5367
  /** StreamMaxLen for trimming (default: 1000) */
5289
5368
  streamMaxLen?: number;
5369
+ /**
5370
+ * TTL in seconds for ephemeral stream keys (default: 300).
5371
+ * Prevents abandoned channel keys from leaking memory in Redis.
5372
+ */
5373
+ streamTtlSeconds?: number;
5374
+ /**
5375
+ * Presence TTL in seconds (default: 300).
5376
+ * Used for batch presence heartbeat pipeline.
5377
+ */
5378
+ presenceTtlSeconds?: number;
5290
5379
  }
5291
5380
  /**
5292
5381
  * Redis adapter for cross-process event distribution.
@@ -5298,11 +5387,17 @@ declare class RedisAdapter implements EventAdapterInterface {
5298
5387
  private _driver;
5299
5388
  private _prefix;
5300
5389
  private _streamMaxLen;
5390
+ private _streamTtlSeconds;
5391
+ private _presenceTtlSeconds;
5301
5392
  private _handlers;
5302
5393
  private _streamOffsets;
5303
5394
  private _streams;
5304
5395
  private _polling;
5305
5396
  private _closed;
5397
+ private _sequenceCounters;
5398
+ private _unsubError?;
5399
+ private _unsubReconnect?;
5400
+ private _presenceCache;
5306
5401
  constructor(options: RedisAdapterOptions);
5307
5402
  publish(channel: string, data: unknown): Promise<void>;
5308
5403
  publishBatch(messages: {
@@ -5320,6 +5415,20 @@ declare class RedisAdapter implements EventAdapterInterface {
5320
5415
  getPresenceBatch(identities: string[]): Promise<(string | null)[]>;
5321
5416
  removePresence(identity: string): Promise<void>;
5322
5417
  metrics(): Promise<Record<string, unknown>>;
5418
+ /**
5419
+ * Set multiple presence entries in a single Redis pipeline.
5420
+ * Reduces N network round-trips to 1 for bulk presence updates.
5421
+ */
5422
+ setPresenceBatch(entries: {
5423
+ identity: string;
5424
+ nodeId: string;
5425
+ ttl?: number;
5426
+ }[]): Promise<void>;
5427
+ /**
5428
+ * Re-syncs all cached presence entries to Redis after a reconnection.
5429
+ * Called automatically when the Redis client reconnects.
5430
+ */
5431
+ private _rehydratePresence;
5323
5432
  }
5324
5433
 
5325
5434
  export { createValidator as $, type AuthCallback as A, type OCPP16Methods as B, type ConnectionMiddleware as C, type OCPP201Methods as D, type EventAdapterInterface as E, type OCPP21Methods as F, type OCPPCall as G, type HandlerContext as H, type OCPPCallError as I, type OCPPCallResult as J, OCPPClient as K, type LoggerLike as L, type MiddlewareFunction as M, NOREPLY as N, type OCPPProtocol as O, type OCPPMessage as P, type OCPPMethodMap as Q, type RouterConfig as R, type ServerEvents as S, type TypedEventEmitter as T, type OCPPProtocolKey as U, Validator as V, RedisAdapter as W, SecurityProfile as X, type SessionData as Y, type TLSOptions as Z, type WildcardHandler as _, type LoggingConfig as a, type RedisAdapterOptions as a0, type MiddlewareContext as b, type CORSOptions as c, type AllMethodNames as d, type RouterHandlerContext as e, type OCPPRequestType as f, type OCPPResponseType as g, type RouterWildcardHandler as h, type ServerOptions as i, type LoggerLikeNotOptional as j, OCPPServerClient as k, type OCPPServerStats as l, type ListenOptions as m, type CloseOptions as n, type CallOptions as o, type AnyOCPPProtocol as p, type AuthAccept as q, type CallHandler as r, type ClientEvents as s, type ClientOptions as t, type ConnectionContext as u, ConnectionState as v, type HandshakeInfo as w, MessageType as x, type MiddlewareNext as y, MiddlewareStack as z };
@@ -4486,6 +4486,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4486
4486
  private _badMessageCount;
4487
4487
  private _lastActivity;
4488
4488
  private _outboundBuffer;
4489
+ private _offlineQueue;
4489
4490
  private _middleware;
4490
4491
  private _validators;
4491
4492
  private _strictProtocols;
@@ -4557,7 +4558,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4557
4558
  *
4558
4559
  * @throws {Error} If a handler for this version and method is already registered on this client instance.
4559
4560
  */
4560
- handle<V extends OCPPProtocol, M extends AllMethodNames<V>>(version: V, method: M, handler: (context: HandlerContext<OCPPRequestType<V, M>>) => OCPPResponseType<V, M> | Promise<OCPPResponseType<V, M>>): void;
4561
+ handle<V extends OCPPProtocol, M extends AllMethodNames<V>>(version: V, method: M, handler: (context: HandlerContext<OCPPRequestType<V, M>>) => OCPPResponseType<V, M> | Promise<OCPPResponseType<V, M>> | typeof NOREPLY): void;
4561
4562
  /**
4562
4563
  * Register a handler for a custom/extension protocol/method not in the typed OCPP method maps.
4563
4564
  * `handle("my-protocol", "my-method", handler)`
@@ -4573,7 +4574,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4573
4574
  *
4574
4575
  * @throws {Error} If a handler for this method is already registered on this client instance.
4575
4576
  */
4576
- handle<M extends AllMethodNames<P>>(method: M, handler: (context: HandlerContext<OCPPRequestType<P, M>>) => OCPPResponseType<P, M> | Promise<OCPPResponseType<P, M>>): void;
4577
+ handle<M extends AllMethodNames<P>>(method: M, handler: (context: HandlerContext<OCPPRequestType<P, M>>) => OCPPResponseType<P, M> | Promise<OCPPResponseType<P, M>> | typeof NOREPLY): void;
4577
4578
  /**
4578
4579
  * Register a handler for a custom/extension method not in the typed OCPP method maps.
4579
4580
  *
@@ -4653,6 +4654,26 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
4653
4654
  /** Errors that should stop reconnection immediately */
4654
4655
  private static readonly _INTOLERABLE_ERRORS;
4655
4656
  private _scheduleReconnect;
4657
+ /**
4658
+ * Atomically drains the offline queue and sends each message via _sendCall.
4659
+ * Uses splice(0) to prevent re-entry bugs (double billing) if the connection
4660
+ * drops again mid-flush — the queue is empty before any sends begin.
4661
+ */
4662
+ private _flushOfflineQueue;
4663
+ /**
4664
+ * Retry wrapper using Full Jitter exponential backoff.
4665
+ * delay = random(0, min(retryMaxDelayMs, retryDelayMs * 2^attempt))
4666
+ * Only retries on TimeoutError — all other errors propagate immediately.
4667
+ */
4668
+ private _callWithRetry;
4669
+ /** Maximum bytes allowed in the ws send buffer before applying backpressure (512KB) */
4670
+ private static readonly _BACKPRESSURE_THRESHOLD;
4671
+ /**
4672
+ * Wraps ws.send() with backpressure protection.
4673
+ * If bufferedAmount exceeds the threshold, waits for the buffer to drain
4674
+ * before sending. Prevents OOM on slow 2G/3G charger connections.
4675
+ */
4676
+ private _safeSend;
4656
4677
  private _startPing;
4657
4678
  private _stopPing;
4658
4679
  private _recordActivity;
@@ -4829,6 +4850,22 @@ interface CallOptions {
4829
4850
  timeoutMs?: number;
4830
4851
  /** Abort signal */
4831
4852
  signal?: AbortSignal;
4853
+ /**
4854
+ * Max retry attempts on TimeoutError (default: 0 = no retry).
4855
+ * Uses Full Jitter exponential backoff between retries.
4856
+ */
4857
+ retries?: number;
4858
+ /** Base delay in ms for exponential backoff between retries (default: 1000) */
4859
+ retryDelayMs?: number;
4860
+ /** Max delay cap in ms to prevent unbounded backoff (default: 30000) */
4861
+ retryMaxDelayMs?: number;
4862
+ /**
4863
+ * Idempotency key for deduplication. If provided, this value is used
4864
+ * as the OCPP messageId instead of generating a new random one.
4865
+ * Consumers can use the same key to guarantee exactly-once semantics
4866
+ * when retrying calls across reconnections.
4867
+ */
4868
+ idempotencyKey?: string;
4832
4869
  }
4833
4870
  interface CloseOptions {
4834
4871
  /** WebSocket close code (default: 1000) */
@@ -5014,6 +5051,16 @@ interface ClientOptions {
5014
5051
  logging?: LoggingConfig | false;
5015
5052
  /** Rate Limiting configuration (Token Bucket) */
5016
5053
  rateLimit?: RateLimitOptions;
5054
+ /**
5055
+ * If true, calls made while disconnected are queued in-memory
5056
+ * and flushed automatically on reconnect. (default: false)
5057
+ */
5058
+ offlineQueue?: boolean;
5059
+ /**
5060
+ * Maximum number of messages to queue while offline.
5061
+ * Oldest messages are dropped when exceeded. (default: 100)
5062
+ */
5063
+ offlineQueueMaxSize?: number;
5017
5064
  }
5018
5065
  interface RateLimitOptions {
5019
5066
  /** Maximum number of messages allowed within the window */
@@ -5109,6 +5156,29 @@ interface ServerOptions {
5109
5156
  * - `LoggingConfig` → custom configuration
5110
5157
  */
5111
5158
  logging?: LoggingConfig | false;
5159
+ /**
5160
+ * Connection-level rate limiting (per-IP) applied at the HTTP upgrade boundary,
5161
+ * before any auth, TLS or JSON parsing occurs — blocks DDoS connection floods in ~1µs.
5162
+ * - `limit`: Max upgrade requests per IP within `windowMs` (default: 20)
5163
+ * - `windowMs`: Sliding window in ms (default: 10000)
5164
+ */
5165
+ connectionRateLimit?: {
5166
+ limit: number;
5167
+ windowMs: number;
5168
+ };
5169
+ /**
5170
+ * Maximum number of inactive sessions to retain in the bounded LRU cache.
5171
+ * Prevents OOM under DDoS or reconnection storms with transient identities.
5172
+ * (default: 50000)
5173
+ */
5174
+ maxSessions?: number;
5175
+ /**
5176
+ * Enable the built-in HTTP health/metrics endpoint.
5177
+ * When enabled, non-upgrade HTTP requests to `/health` return a JSON health check,
5178
+ * and requests to `/metrics` return Prometheus-compatible text metrics.
5179
+ * (default: false)
5180
+ */
5181
+ healthEndpoint?: boolean;
5112
5182
  }
5113
5183
  interface OCPPServerStats {
5114
5184
  /** Number of currently connected WebSockets */
@@ -5219,6 +5289,15 @@ interface EventAdapterInterface {
5219
5289
  getPresence?(identity: string): Promise<string | null>;
5220
5290
  getPresenceBatch?(identities: string[]): Promise<(string | null)[]>;
5221
5291
  removePresence?(identity: string): Promise<void>;
5292
+ /**
5293
+ * Batch set multiple presence entries in a single pipeline.
5294
+ * Reduces N network round-trips to 1 for bulk presence updates.
5295
+ */
5296
+ setPresenceBatch?(entries: {
5297
+ identity: string;
5298
+ nodeId: string;
5299
+ ttl?: number;
5300
+ }[]): Promise<void>;
5222
5301
  metrics?(): Promise<Record<string, unknown>>;
5223
5302
  }
5224
5303
  declare const NOREPLY: unique symbol;
@@ -5287,6 +5366,16 @@ interface RedisAdapterOptions {
5287
5366
  prefix?: string;
5288
5367
  /** StreamMaxLen for trimming (default: 1000) */
5289
5368
  streamMaxLen?: number;
5369
+ /**
5370
+ * TTL in seconds for ephemeral stream keys (default: 300).
5371
+ * Prevents abandoned channel keys from leaking memory in Redis.
5372
+ */
5373
+ streamTtlSeconds?: number;
5374
+ /**
5375
+ * Presence TTL in seconds (default: 300).
5376
+ * Used for batch presence heartbeat pipeline.
5377
+ */
5378
+ presenceTtlSeconds?: number;
5290
5379
  }
5291
5380
  /**
5292
5381
  * Redis adapter for cross-process event distribution.
@@ -5298,11 +5387,17 @@ declare class RedisAdapter implements EventAdapterInterface {
5298
5387
  private _driver;
5299
5388
  private _prefix;
5300
5389
  private _streamMaxLen;
5390
+ private _streamTtlSeconds;
5391
+ private _presenceTtlSeconds;
5301
5392
  private _handlers;
5302
5393
  private _streamOffsets;
5303
5394
  private _streams;
5304
5395
  private _polling;
5305
5396
  private _closed;
5397
+ private _sequenceCounters;
5398
+ private _unsubError?;
5399
+ private _unsubReconnect?;
5400
+ private _presenceCache;
5306
5401
  constructor(options: RedisAdapterOptions);
5307
5402
  publish(channel: string, data: unknown): Promise<void>;
5308
5403
  publishBatch(messages: {
@@ -5320,6 +5415,20 @@ declare class RedisAdapter implements EventAdapterInterface {
5320
5415
  getPresenceBatch(identities: string[]): Promise<(string | null)[]>;
5321
5416
  removePresence(identity: string): Promise<void>;
5322
5417
  metrics(): Promise<Record<string, unknown>>;
5418
+ /**
5419
+ * Set multiple presence entries in a single Redis pipeline.
5420
+ * Reduces N network round-trips to 1 for bulk presence updates.
5421
+ */
5422
+ setPresenceBatch(entries: {
5423
+ identity: string;
5424
+ nodeId: string;
5425
+ ttl?: number;
5426
+ }[]): Promise<void>;
5427
+ /**
5428
+ * Re-syncs all cached presence entries to Redis after a reconnection.
5429
+ * Called automatically when the Redis client reconnects.
5430
+ */
5431
+ private _rehydratePresence;
5323
5432
  }
5324
5433
 
5325
5434
  export { createValidator as $, type AuthCallback as A, type OCPP16Methods as B, type ConnectionMiddleware as C, type OCPP201Methods as D, type EventAdapterInterface as E, type OCPP21Methods as F, type OCPPCall as G, type HandlerContext as H, type OCPPCallError as I, type OCPPCallResult as J, OCPPClient as K, type LoggerLike as L, type MiddlewareFunction as M, NOREPLY as N, type OCPPProtocol as O, type OCPPMessage as P, type OCPPMethodMap as Q, type RouterConfig as R, type ServerEvents as S, type TypedEventEmitter as T, type OCPPProtocolKey as U, Validator as V, RedisAdapter as W, SecurityProfile as X, type SessionData as Y, type TLSOptions as Z, type WildcardHandler as _, type LoggingConfig as a, type RedisAdapterOptions as a0, type MiddlewareContext as b, type CORSOptions as c, type AllMethodNames as d, type RouterHandlerContext as e, type OCPPRequestType as f, type OCPPResponseType as g, type RouterWildcardHandler as h, type ServerOptions as i, type LoggerLikeNotOptional as j, OCPPServerClient as k, type OCPPServerStats as l, type ListenOptions as m, type CloseOptions as n, type CallOptions as o, type AnyOCPPProtocol as p, type AuthAccept as q, type CallHandler as r, type ClientEvents as s, type ClientOptions as t, type ConnectionContext as u, ConnectionState as v, type HandshakeInfo as w, MessageType as x, type MiddlewareNext as y, MiddlewareStack as z };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as EventAdapterInterface, A as AuthCallback, L as LoggerLike, a as LoggingConfig, M as MiddlewareFunction, b as MiddlewareContext, C as ConnectionMiddleware, T as TypedEventEmitter, S as ServerEvents, c as CORSOptions, R as RouterConfig, O as OCPPProtocol, d as AllMethodNames, e as RouterHandlerContext, f as OCPPRequestType, g as OCPPResponseType, h as RouterWildcardHandler, i as ServerOptions, j as LoggerLikeNotOptional, k as OCPPServerClient, l as OCPPServerStats, m as ListenOptions, n as CloseOptions, o as CallOptions, V as Validator } from './index-BixJj_yJ.mjs';
2
- export { p as AnyOCPPProtocol, q as AuthAccept, r as CallHandler, s as ClientEvents, t as ClientOptions, u as ConnectionContext, v as ConnectionState, H as HandlerContext, w as HandshakeInfo, x as MessageType, y as MiddlewareNext, z as MiddlewareStack, N as NOREPLY, B as OCPP16Methods, D as OCPP201Methods, F as OCPP21Methods, G as OCPPCall, I as OCPPCallError, J as OCPPCallResult, K as OCPPClient, P as OCPPMessage, Q as OCPPMethodMap, U as OCPPProtocolKey, W as RedisAdapter, X as SecurityProfile, Y as SessionData, Z as TLSOptions, _ as WildcardHandler, $ as createValidator } from './index-BixJj_yJ.mjs';
1
+ import { E as EventAdapterInterface, A as AuthCallback, L as LoggerLike, a as LoggingConfig, M as MiddlewareFunction, b as MiddlewareContext, C as ConnectionMiddleware, T as TypedEventEmitter, S as ServerEvents, c as CORSOptions, R as RouterConfig, O as OCPPProtocol, d as AllMethodNames, e as RouterHandlerContext, f as OCPPRequestType, g as OCPPResponseType, h as RouterWildcardHandler, i as ServerOptions, j as LoggerLikeNotOptional, k as OCPPServerClient, l as OCPPServerStats, m as ListenOptions, n as CloseOptions, o as CallOptions, V as Validator } from './index-CagcFzyZ.mjs';
2
+ export { p as AnyOCPPProtocol, q as AuthAccept, r as CallHandler, s as ClientEvents, t as ClientOptions, u as ConnectionContext, v as ConnectionState, H as HandlerContext, w as HandshakeInfo, x as MessageType, y as MiddlewareNext, z as MiddlewareStack, N as NOREPLY, B as OCPP16Methods, D as OCPP201Methods, F as OCPP21Methods, G as OCPPCall, I as OCPPCallError, J as OCPPCallResult, K as OCPPClient, P as OCPPMessage, Q as OCPPMethodMap, U as OCPPProtocolKey, W as RedisAdapter, X as SecurityProfile, Y as SessionData, Z as TLSOptions, _ as WildcardHandler, $ as createValidator } from './index-CagcFzyZ.mjs';
3
3
  import { Server, IncomingMessage } from 'node:http';
4
4
  import { Duplex } from 'node:stream';
5
5
  import 'ws';
@@ -28,6 +28,11 @@ declare class InMemoryAdapter implements EventAdapterInterface {
28
28
  getPresence(identity: string): Promise<string | null>;
29
29
  getPresenceBatch(identities: string[]): Promise<(string | null)[]>;
30
30
  removePresence(identity: string): Promise<void>;
31
+ setPresenceBatch(entries: {
32
+ identity: string;
33
+ nodeId: string;
34
+ ttl?: number;
35
+ }[]): Promise<void>;
31
36
  }
32
37
  /**
33
38
  * Helper function to create a custom EventAdapter without needing to define a rigid Class.
@@ -160,6 +165,38 @@ declare function combineAuth(...cbs: AuthCallback[]): AuthCallback;
160
165
  */
161
166
  declare function createLoggingMiddleware(logger: LoggerLike, identity: string, config?: LoggingConfig | boolean): MiddlewareFunction<MiddlewareContext, any>;
162
167
 
168
+ /**
169
+ * LRUMap — A zero-dependency, drop-in Map replacement with a maximum capacity.
170
+ *
171
+ * Evicts the **least recently used** entry when the capacity is exceeded.
172
+ * Uses native Map insertion-order semantics for O(1) LRU tracking
173
+ * (delete + re-insert moves a key to the "most recent" end).
174
+ *
175
+ * @remarks
176
+ * This is used by OCPPServer to bound the `_sessions` map and prevent OOM under
177
+ * DDoS or reconnection storms with transient identities.
178
+ */
179
+ declare class LRUMap<K, V> extends Map<K, V> {
180
+ private _maxSize;
181
+ constructor(maxSize: number);
182
+ /**
183
+ * Returns the configured maximum capacity of this LRU cache.
184
+ */
185
+ get maxSize(): number;
186
+ /**
187
+ * Sets a key-value pair. If the key already exists, it is promoted to the
188
+ * most-recently-used position. If inserting a new key would exceed capacity,
189
+ * the oldest (least-recently-used) entry is evicted.
190
+ */
191
+ set(key: K, value: V): this;
192
+ /**
193
+ * Gets a value by key and promotes it to the most-recently-used position.
194
+ * Uses `this.has(key)` instead of a value truthiness check to correctly
195
+ * handle stored values of `undefined`, `null`, `0`, `""`, etc.
196
+ */
197
+ get(key: K): V | undefined;
198
+ }
199
+
163
200
  /**
164
201
  * Compiled regex pattern for RegExp-based route fallback.
165
202
  * Only used when a user registers a RegExp pattern (not string patterns).
@@ -280,6 +317,7 @@ declare class OCPPServer extends OCPPServer_base {
280
317
  private _httpServerAbortControllers;
281
318
  private _logger;
282
319
  private _globalCORS?;
320
+ private _connectionBuckets;
283
321
  private readonly _nodeId;
284
322
  private _sessions;
285
323
  private _gcInterval;
@@ -446,4 +484,4 @@ declare function getErrorPlainObject(err: Error): Record<string, unknown>;
446
484
  */
447
485
  declare function getPackageIdent(): string;
448
486
 
449
- export { AllMethodNames, AuthCallback, CORSOptions, CallOptions, CloseOptions, ConnectionMiddleware, EventAdapterInterface, InMemoryAdapter, ListenOptions, LoggerLike, LoggingConfig, MiddlewareFunction, OCPPProtocol, OCPPRequestType, OCPPResponseType, OCPPRouter, OCPPServer, OCPPServerClient, type RPCError, RPCFormatViolationError, RPCFormationViolationError, RPCFrameworkError, RPCGenericError, RPCInternalError, RPCMessageTypeNotSupportedError, RPCNotImplementedError, RPCNotSupportedError, RPCOccurrenceConstraintViolationError, RPCPropertyConstraintViolationError, RPCProtocolError, RPCSecurityError, RPCTypeConstraintViolationError, RouterConfig, ServerEvents, ServerOptions, TimeoutError, TypedEventEmitter, UnexpectedHttpResponse, Validator, WebsocketUpgradeError, combineAuth, createLoggingMiddleware, createRPCError, createRouter, defineAdapter, defineAuth, defineMiddleware, defineRpcMiddleware, getErrorPlainObject, getPackageIdent, standardValidators };
487
+ export { AllMethodNames, AuthCallback, CORSOptions, CallOptions, CloseOptions, ConnectionMiddleware, EventAdapterInterface, InMemoryAdapter, LRUMap, ListenOptions, LoggerLike, LoggingConfig, MiddlewareFunction, OCPPProtocol, OCPPRequestType, OCPPResponseType, OCPPRouter, OCPPServer, OCPPServerClient, type RPCError, RPCFormatViolationError, RPCFormationViolationError, RPCFrameworkError, RPCGenericError, RPCInternalError, RPCMessageTypeNotSupportedError, RPCNotImplementedError, RPCNotSupportedError, RPCOccurrenceConstraintViolationError, RPCPropertyConstraintViolationError, RPCProtocolError, RPCSecurityError, RPCTypeConstraintViolationError, RouterConfig, ServerEvents, ServerOptions, TimeoutError, TypedEventEmitter, UnexpectedHttpResponse, Validator, WebsocketUpgradeError, combineAuth, createLoggingMiddleware, createRPCError, createRouter, defineAdapter, defineAuth, defineMiddleware, defineRpcMiddleware, getErrorPlainObject, getPackageIdent, standardValidators };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as EventAdapterInterface, A as AuthCallback, L as LoggerLike, a as LoggingConfig, M as MiddlewareFunction, b as MiddlewareContext, C as ConnectionMiddleware, T as TypedEventEmitter, S as ServerEvents, c as CORSOptions, R as RouterConfig, O as OCPPProtocol, d as AllMethodNames, e as RouterHandlerContext, f as OCPPRequestType, g as OCPPResponseType, h as RouterWildcardHandler, i as ServerOptions, j as LoggerLikeNotOptional, k as OCPPServerClient, l as OCPPServerStats, m as ListenOptions, n as CloseOptions, o as CallOptions, V as Validator } from './index-BixJj_yJ.js';
2
- export { p as AnyOCPPProtocol, q as AuthAccept, r as CallHandler, s as ClientEvents, t as ClientOptions, u as ConnectionContext, v as ConnectionState, H as HandlerContext, w as HandshakeInfo, x as MessageType, y as MiddlewareNext, z as MiddlewareStack, N as NOREPLY, B as OCPP16Methods, D as OCPP201Methods, F as OCPP21Methods, G as OCPPCall, I as OCPPCallError, J as OCPPCallResult, K as OCPPClient, P as OCPPMessage, Q as OCPPMethodMap, U as OCPPProtocolKey, W as RedisAdapter, X as SecurityProfile, Y as SessionData, Z as TLSOptions, _ as WildcardHandler, $ as createValidator } from './index-BixJj_yJ.js';
1
+ import { E as EventAdapterInterface, A as AuthCallback, L as LoggerLike, a as LoggingConfig, M as MiddlewareFunction, b as MiddlewareContext, C as ConnectionMiddleware, T as TypedEventEmitter, S as ServerEvents, c as CORSOptions, R as RouterConfig, O as OCPPProtocol, d as AllMethodNames, e as RouterHandlerContext, f as OCPPRequestType, g as OCPPResponseType, h as RouterWildcardHandler, i as ServerOptions, j as LoggerLikeNotOptional, k as OCPPServerClient, l as OCPPServerStats, m as ListenOptions, n as CloseOptions, o as CallOptions, V as Validator } from './index-CagcFzyZ.js';
2
+ export { p as AnyOCPPProtocol, q as AuthAccept, r as CallHandler, s as ClientEvents, t as ClientOptions, u as ConnectionContext, v as ConnectionState, H as HandlerContext, w as HandshakeInfo, x as MessageType, y as MiddlewareNext, z as MiddlewareStack, N as NOREPLY, B as OCPP16Methods, D as OCPP201Methods, F as OCPP21Methods, G as OCPPCall, I as OCPPCallError, J as OCPPCallResult, K as OCPPClient, P as OCPPMessage, Q as OCPPMethodMap, U as OCPPProtocolKey, W as RedisAdapter, X as SecurityProfile, Y as SessionData, Z as TLSOptions, _ as WildcardHandler, $ as createValidator } from './index-CagcFzyZ.js';
3
3
  import { Server, IncomingMessage } from 'node:http';
4
4
  import { Duplex } from 'node:stream';
5
5
  import 'ws';
@@ -28,6 +28,11 @@ declare class InMemoryAdapter implements EventAdapterInterface {
28
28
  getPresence(identity: string): Promise<string | null>;
29
29
  getPresenceBatch(identities: string[]): Promise<(string | null)[]>;
30
30
  removePresence(identity: string): Promise<void>;
31
+ setPresenceBatch(entries: {
32
+ identity: string;
33
+ nodeId: string;
34
+ ttl?: number;
35
+ }[]): Promise<void>;
31
36
  }
32
37
  /**
33
38
  * Helper function to create a custom EventAdapter without needing to define a rigid Class.
@@ -160,6 +165,38 @@ declare function combineAuth(...cbs: AuthCallback[]): AuthCallback;
160
165
  */
161
166
  declare function createLoggingMiddleware(logger: LoggerLike, identity: string, config?: LoggingConfig | boolean): MiddlewareFunction<MiddlewareContext, any>;
162
167
 
168
+ /**
169
+ * LRUMap — A zero-dependency, drop-in Map replacement with a maximum capacity.
170
+ *
171
+ * Evicts the **least recently used** entry when the capacity is exceeded.
172
+ * Uses native Map insertion-order semantics for O(1) LRU tracking
173
+ * (delete + re-insert moves a key to the "most recent" end).
174
+ *
175
+ * @remarks
176
+ * This is used by OCPPServer to bound the `_sessions` map and prevent OOM under
177
+ * DDoS or reconnection storms with transient identities.
178
+ */
179
+ declare class LRUMap<K, V> extends Map<K, V> {
180
+ private _maxSize;
181
+ constructor(maxSize: number);
182
+ /**
183
+ * Returns the configured maximum capacity of this LRU cache.
184
+ */
185
+ get maxSize(): number;
186
+ /**
187
+ * Sets a key-value pair. If the key already exists, it is promoted to the
188
+ * most-recently-used position. If inserting a new key would exceed capacity,
189
+ * the oldest (least-recently-used) entry is evicted.
190
+ */
191
+ set(key: K, value: V): this;
192
+ /**
193
+ * Gets a value by key and promotes it to the most-recently-used position.
194
+ * Uses `this.has(key)` instead of a value truthiness check to correctly
195
+ * handle stored values of `undefined`, `null`, `0`, `""`, etc.
196
+ */
197
+ get(key: K): V | undefined;
198
+ }
199
+
163
200
  /**
164
201
  * Compiled regex pattern for RegExp-based route fallback.
165
202
  * Only used when a user registers a RegExp pattern (not string patterns).
@@ -280,6 +317,7 @@ declare class OCPPServer extends OCPPServer_base {
280
317
  private _httpServerAbortControllers;
281
318
  private _logger;
282
319
  private _globalCORS?;
320
+ private _connectionBuckets;
283
321
  private readonly _nodeId;
284
322
  private _sessions;
285
323
  private _gcInterval;
@@ -446,4 +484,4 @@ declare function getErrorPlainObject(err: Error): Record<string, unknown>;
446
484
  */
447
485
  declare function getPackageIdent(): string;
448
486
 
449
- export { AllMethodNames, AuthCallback, CORSOptions, CallOptions, CloseOptions, ConnectionMiddleware, EventAdapterInterface, InMemoryAdapter, ListenOptions, LoggerLike, LoggingConfig, MiddlewareFunction, OCPPProtocol, OCPPRequestType, OCPPResponseType, OCPPRouter, OCPPServer, OCPPServerClient, type RPCError, RPCFormatViolationError, RPCFormationViolationError, RPCFrameworkError, RPCGenericError, RPCInternalError, RPCMessageTypeNotSupportedError, RPCNotImplementedError, RPCNotSupportedError, RPCOccurrenceConstraintViolationError, RPCPropertyConstraintViolationError, RPCProtocolError, RPCSecurityError, RPCTypeConstraintViolationError, RouterConfig, ServerEvents, ServerOptions, TimeoutError, TypedEventEmitter, UnexpectedHttpResponse, Validator, WebsocketUpgradeError, combineAuth, createLoggingMiddleware, createRPCError, createRouter, defineAdapter, defineAuth, defineMiddleware, defineRpcMiddleware, getErrorPlainObject, getPackageIdent, standardValidators };
487
+ export { AllMethodNames, AuthCallback, CORSOptions, CallOptions, CloseOptions, ConnectionMiddleware, EventAdapterInterface, InMemoryAdapter, LRUMap, ListenOptions, LoggerLike, LoggingConfig, MiddlewareFunction, OCPPProtocol, OCPPRequestType, OCPPResponseType, OCPPRouter, OCPPServer, OCPPServerClient, type RPCError, RPCFormatViolationError, RPCFormationViolationError, RPCFrameworkError, RPCGenericError, RPCInternalError, RPCMessageTypeNotSupportedError, RPCNotImplementedError, RPCNotSupportedError, RPCOccurrenceConstraintViolationError, RPCPropertyConstraintViolationError, RPCProtocolError, RPCSecurityError, RPCTypeConstraintViolationError, RouterConfig, ServerEvents, ServerOptions, TimeoutError, TypedEventEmitter, UnexpectedHttpResponse, Validator, WebsocketUpgradeError, combineAuth, createLoggingMiddleware, createRPCError, createRouter, defineAdapter, defineAuth, defineMiddleware, defineRpcMiddleware, getErrorPlainObject, getPackageIdent, standardValidators };