ocpp-ws-io 2.1.7 → 2.1.8
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 +1 -1
- package/dist/adapters/redis.d.mts +2 -1
- package/dist/adapters/redis.d.ts +2 -1
- package/dist/adapters/redis.js +27 -6
- package/dist/adapters/redis.js.map +1 -1
- package/dist/adapters/redis.mjs +27 -6
- package/dist/adapters/redis.mjs.map +1 -1
- package/dist/browser.d.mts +1129 -2
- package/dist/browser.d.ts +1129 -2
- package/dist/browser.js +4 -0
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +4 -0
- package/dist/browser.mjs.map +1 -1
- package/dist/index-C0mn42-8.d.mts +161 -0
- package/dist/index-s9f97CmV.d.ts +161 -0
- package/dist/index.d.mts +131 -287
- package/dist/index.d.ts +131 -287
- package/dist/index.js +628 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +642 -56
- package/dist/index.mjs.map +1 -1
- package/dist/plugins.d.mts +246 -0
- package/dist/plugins.d.ts +246 -0
- package/dist/plugins.js +370 -0
- package/dist/plugins.js.map +1 -0
- package/dist/plugins.mjs +350 -0
- package/dist/plugins.mjs.map +1 -0
- package/dist/{index-BRblF1XV.d.mts → types-BZXEmDQ1.d.mts} +468 -89
- package/dist/{index-BRblF1XV.d.ts → types-BZXEmDQ1.d.ts} +468 -89
- package/package.json +7 -3
- package/assets/banner.svg +0 -31
|
@@ -2,7 +2,7 @@ import * as WebSocket from 'ws';
|
|
|
2
2
|
import WebSocket__default, { WebSocket as WebSocket$1 } from 'ws';
|
|
3
3
|
import * as node_https from 'node:https';
|
|
4
4
|
import * as node_http from 'node:http';
|
|
5
|
-
import { IncomingMessage } from 'node:http';
|
|
5
|
+
import { Server, IncomingMessage } from 'node:http';
|
|
6
6
|
import { EventEmitter } from 'node:events';
|
|
7
7
|
import { Duplex } from 'node:stream';
|
|
8
8
|
import { TLSSocket } from 'node:tls';
|
|
@@ -4431,6 +4431,100 @@ type OCPPResponseType<P extends keyof OCPPMethodMap, M extends string> = P exten
|
|
|
4431
4431
|
response: infer R;
|
|
4432
4432
|
} ? R : never : never : never;
|
|
4433
4433
|
|
|
4434
|
+
/**
|
|
4435
|
+
* Compiled regex pattern for RegExp-based route fallback.
|
|
4436
|
+
* Only used when a user registers a RegExp pattern (not string patterns).
|
|
4437
|
+
* @internal
|
|
4438
|
+
*/
|
|
4439
|
+
interface CompiledRegexPattern {
|
|
4440
|
+
regex: RegExp;
|
|
4441
|
+
paramNames: string[];
|
|
4442
|
+
}
|
|
4443
|
+
declare const OCPPRouter_base: new () => TypedEventEmitter<ServerEvents>;
|
|
4444
|
+
/**
|
|
4445
|
+
* OCPPRouter — An Express-like Connection dispatcher.
|
|
4446
|
+
* Isolated handler for a specific set of matching URL route patterns.
|
|
4447
|
+
*
|
|
4448
|
+
* String patterns are matched via radix trie (O(k) lookup, managed by OCPPServer).
|
|
4449
|
+
* RegExp patterns fall back to linear matching.
|
|
4450
|
+
*/
|
|
4451
|
+
declare class OCPPRouter extends OCPPRouter_base {
|
|
4452
|
+
/** Raw registered patterns (strings and/or RegExp) for reference. */
|
|
4453
|
+
patterns: Array<string | RegExp>;
|
|
4454
|
+
/** Connection middlewares attached to this router. */
|
|
4455
|
+
middlewares: ConnectionMiddleware[];
|
|
4456
|
+
/** Auth callback for this route endpoint. */
|
|
4457
|
+
authCallback: AuthCallback<unknown> | null;
|
|
4458
|
+
/** Route-level CORS options. */
|
|
4459
|
+
_routeCORS?: CORSOptions;
|
|
4460
|
+
/** Route-level config overrides. */
|
|
4461
|
+
_routeConfig?: RouterConfig;
|
|
4462
|
+
/**
|
|
4463
|
+
* Compiled RegExp patterns for fallback linear matching.
|
|
4464
|
+
* Only populated when RegExp patterns are registered.
|
|
4465
|
+
* @internal
|
|
4466
|
+
*/
|
|
4467
|
+
_regexPatterns: CompiledRegexPattern[];
|
|
4468
|
+
constructor(patterns?: Array<string | RegExp>, middlewares?: ConnectionMiddleware[]);
|
|
4469
|
+
/**
|
|
4470
|
+
* Appends URL paths or regular expressions to this router's match condition.
|
|
4471
|
+
* String patterns are stored for trie insertion by OCPPServer.
|
|
4472
|
+
* RegExp patterns are compiled for linear fallback matching.
|
|
4473
|
+
*/
|
|
4474
|
+
route(...patterns: Array<string | RegExp>): this;
|
|
4475
|
+
/**
|
|
4476
|
+
* Appends connection middlewares to this router's execution chain.
|
|
4477
|
+
*/
|
|
4478
|
+
use(...middlewares: ConnectionMiddleware[]): this;
|
|
4479
|
+
/**
|
|
4480
|
+
* Applies specific CORS rules to connections matching this router's paths.
|
|
4481
|
+
*/
|
|
4482
|
+
cors(options: CORSOptions): this;
|
|
4483
|
+
/**
|
|
4484
|
+
* Overrides global connection settings (e.g. timeouts, protocols) for this router.
|
|
4485
|
+
*/
|
|
4486
|
+
config(options: RouterConfig): this;
|
|
4487
|
+
/**
|
|
4488
|
+
* Registers an authentication and protocol-negotiation callback for this route endpoint.
|
|
4489
|
+
*/
|
|
4490
|
+
auth<TSession = Record<string, unknown>>(callback: AuthCallback<TSession>): this;
|
|
4491
|
+
/**
|
|
4492
|
+
* Binds a version-specific OCPP message handler directly to all clients that match this route.
|
|
4493
|
+
*
|
|
4494
|
+
* @throws {Error} AT RUNTIME when a client connects, if a handler for this version and method is already registered for that client.
|
|
4495
|
+
*/
|
|
4496
|
+
handle<V extends OCPPProtocol, M extends AllMethodNames<V>>(version: V, method: M, handler: (context: RouterHandlerContext<OCPPRequestType<V, M>>) => OCPPResponseType<V, M> | Promise<OCPPResponseType<V, M>>): this;
|
|
4497
|
+
/**
|
|
4498
|
+
* Binds a custom/extension message handler directly to all clients that match this route.
|
|
4499
|
+
*
|
|
4500
|
+
* @throws {Error} AT RUNTIME when a client connects, if a handler for this protocol and method is already registered for that client.
|
|
4501
|
+
*/
|
|
4502
|
+
handle<S extends string>(version: S extends OCPPProtocol ? never : S, method: string, handler: (context: RouterHandlerContext<Record<string, any>>) => any): this;
|
|
4503
|
+
/**
|
|
4504
|
+
* Binds a message handler directly to all clients that match this route using the default protocol.
|
|
4505
|
+
*
|
|
4506
|
+
* @throws {Error} AT RUNTIME when a client connects, if a handler for this method is already registered for that client.
|
|
4507
|
+
*/
|
|
4508
|
+
handle<M extends AllMethodNames<OCPPProtocol>>(method: M, handler: (context: RouterHandlerContext<OCPPRequestType<OCPPProtocol, M>>) => OCPPResponseType<OCPPProtocol, M> | Promise<OCPPResponseType<OCPPProtocol, M>>): this;
|
|
4509
|
+
/**
|
|
4510
|
+
* Binds a custom/extension method not in the typed map.
|
|
4511
|
+
*
|
|
4512
|
+
* @throws {Error} AT RUNTIME when a client connects, if a handler for this method is already registered for that client.
|
|
4513
|
+
*/
|
|
4514
|
+
handle(method: string, handler: (context: RouterHandlerContext<Record<string, any>>) => any): this;
|
|
4515
|
+
/**
|
|
4516
|
+
* Binds a wildcard handler to all clients that match this route.
|
|
4517
|
+
*
|
|
4518
|
+
* @throws {Error} AT RUNTIME when a client connects, if a wildcard handler is already registered for that client.
|
|
4519
|
+
*/
|
|
4520
|
+
handle(handler: RouterWildcardHandler): this;
|
|
4521
|
+
}
|
|
4522
|
+
/**
|
|
4523
|
+
* Creates a standalone, modular `OCPPRouter` instance that can be attached
|
|
4524
|
+
* to an `OCPPServer` later via `server.attachRouters()`.
|
|
4525
|
+
*/
|
|
4526
|
+
declare function createRouter(...patterns: Array<string | RegExp>): OCPPRouter;
|
|
4527
|
+
|
|
4434
4528
|
/**
|
|
4435
4529
|
* Middleware handling for intercepting and modifying OCPP operations.
|
|
4436
4530
|
*
|
|
@@ -4641,7 +4735,7 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
|
|
|
4641
4735
|
sendRaw(message: string): void;
|
|
4642
4736
|
reconfigure(options: Partial<ClientOptions>): void;
|
|
4643
4737
|
protected _attachWebsocket(ws: WebSocket__default): void;
|
|
4644
|
-
|
|
4738
|
+
protected _onMessage(rawData: WebSocket__default.RawData, preParsed?: unknown): void;
|
|
4645
4739
|
private _handleIncomingCall;
|
|
4646
4740
|
private _handleCallResult;
|
|
4647
4741
|
private _handleCallError;
|
|
@@ -4686,6 +4780,43 @@ declare class OCPPClient<P extends OCPPProtocol = OCPPProtocol> extends OCPPClie
|
|
|
4686
4780
|
private _cleanup;
|
|
4687
4781
|
}
|
|
4688
4782
|
|
|
4783
|
+
interface WorkerPoolOptions {
|
|
4784
|
+
/** Number of worker threads (default: Math.max(2, cpus - 2)) */
|
|
4785
|
+
poolSize?: number;
|
|
4786
|
+
/** Max pending parse jobs before rejecting (default: 10000) */
|
|
4787
|
+
maxQueueSize?: number;
|
|
4788
|
+
}
|
|
4789
|
+
interface ParseResult {
|
|
4790
|
+
message: unknown;
|
|
4791
|
+
validationError?: {
|
|
4792
|
+
schemaId: string;
|
|
4793
|
+
errors: string;
|
|
4794
|
+
};
|
|
4795
|
+
}
|
|
4796
|
+
declare class WorkerPool {
|
|
4797
|
+
private _workers;
|
|
4798
|
+
private _nextWorker;
|
|
4799
|
+
private _taskId;
|
|
4800
|
+
private _pending;
|
|
4801
|
+
private _maxQueueSize;
|
|
4802
|
+
private _terminated;
|
|
4803
|
+
constructor(options?: WorkerPoolOptions);
|
|
4804
|
+
/** Number of worker threads in the pool */
|
|
4805
|
+
get size(): number;
|
|
4806
|
+
/** Number of pending (unresolved) parse tasks */
|
|
4807
|
+
get pendingTasks(): number;
|
|
4808
|
+
/**
|
|
4809
|
+
* Send raw data to a worker for JSON parsing + optional validation.
|
|
4810
|
+
* Uses round-robin worker selection.
|
|
4811
|
+
*/
|
|
4812
|
+
parse(data: Buffer | string, schemaInfo?: {
|
|
4813
|
+
protocol: string;
|
|
4814
|
+
schemas: Record<string, unknown>;
|
|
4815
|
+
}): Promise<ParseResult>;
|
|
4816
|
+
/** Gracefully terminate all workers */
|
|
4817
|
+
shutdown(): Promise<void>;
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4689
4820
|
/**
|
|
4690
4821
|
* OCPPServerClient — A server-side client representation.
|
|
4691
4822
|
*
|
|
@@ -4700,8 +4831,14 @@ declare class OCPPServerClient extends OCPPClient {
|
|
|
4700
4831
|
handshake: HandshakeInfo;
|
|
4701
4832
|
session: Record<string, any>;
|
|
4702
4833
|
protocol?: string;
|
|
4834
|
+
/** Optional adaptive rate multiplier getter (from OCPPServer.AdaptiveLimiter) */
|
|
4835
|
+
adaptiveMultiplier?: () => number;
|
|
4836
|
+
/** Optional worker pool for off-thread JSON parsing */
|
|
4837
|
+
workerPool?: WorkerPool;
|
|
4703
4838
|
});
|
|
4704
4839
|
private _rateLimits;
|
|
4840
|
+
private _adaptiveMultiplier;
|
|
4841
|
+
private _workerPool;
|
|
4705
4842
|
private _checkRateLimit;
|
|
4706
4843
|
private _attachServerWebsocket;
|
|
4707
4844
|
private _handleRateLimitExceeded;
|
|
@@ -4732,6 +4869,240 @@ declare class OCPPServerClient extends OCPPClient {
|
|
|
4732
4869
|
}>;
|
|
4733
4870
|
}
|
|
4734
4871
|
|
|
4872
|
+
declare const OCPPServer_base: new () => TypedEventEmitter<ServerEvents>;
|
|
4873
|
+
/**
|
|
4874
|
+
* OCPPServer — A typed WebSocket RPC server for OCPP communication.
|
|
4875
|
+
*
|
|
4876
|
+
* Supports all 3 OCPP Security Profiles:
|
|
4877
|
+
* - Profile 1: Basic Auth over unsecured WS
|
|
4878
|
+
* - Profile 2: TLS + Basic Auth (HTTPS server)
|
|
4879
|
+
* - Profile 3: Mutual TLS (HTTPS server with requestCert)
|
|
4880
|
+
*/
|
|
4881
|
+
declare class OCPPServer extends OCPPServer_base {
|
|
4882
|
+
private _options;
|
|
4883
|
+
/** Radix trie for O(k) route matching (string patterns). */
|
|
4884
|
+
private _trie;
|
|
4885
|
+
/** Global middleware routers (server.use() with no patterns — catch-all). */
|
|
4886
|
+
private _globalMiddlewareRouters;
|
|
4887
|
+
/** Routers with RegExp patterns (fallback linear scan). */
|
|
4888
|
+
private _regexRouters;
|
|
4889
|
+
private _clients;
|
|
4890
|
+
private _clientsByIdentity;
|
|
4891
|
+
private _httpServers;
|
|
4892
|
+
private _wss;
|
|
4893
|
+
private _state;
|
|
4894
|
+
private _adapter;
|
|
4895
|
+
private _httpServerAbortControllers;
|
|
4896
|
+
private _logger;
|
|
4897
|
+
private _globalCORS?;
|
|
4898
|
+
private _connectionBuckets;
|
|
4899
|
+
private _adaptiveLimiter;
|
|
4900
|
+
private _plugins;
|
|
4901
|
+
private _workerPool;
|
|
4902
|
+
private readonly _nodeId;
|
|
4903
|
+
private _sessions;
|
|
4904
|
+
private _gcInterval;
|
|
4905
|
+
private readonly _sessionTimeoutMs;
|
|
4906
|
+
constructor(options?: ServerOptions);
|
|
4907
|
+
get log(): LoggerLikeNotOptional;
|
|
4908
|
+
/**
|
|
4909
|
+
* Returns a readonly set of all currently connected OCPPServerClient instances.
|
|
4910
|
+
*/
|
|
4911
|
+
get clients(): ReadonlySet<OCPPServerClient>;
|
|
4912
|
+
/**
|
|
4913
|
+
* Returns the current server state (OPEN, CLOSING, CLOSED).
|
|
4914
|
+
*/
|
|
4915
|
+
get state(): "OPEN" | "CLOSING" | "CLOSED";
|
|
4916
|
+
/**
|
|
4917
|
+
* Returns current node observability statistics
|
|
4918
|
+
* (e.g. connected socket count, tracked memory sessions, and process CPU/Memory usage).
|
|
4919
|
+
* Fully compatible with Loki/Prometheus node metric ingestion.
|
|
4920
|
+
*/
|
|
4921
|
+
stats(): OCPPServerStats;
|
|
4922
|
+
/**
|
|
4923
|
+
* Returns observability statistics from the active Event Adapter (e.g. Redis).
|
|
4924
|
+
* Useful for tracking consumer backlog and enabling Horizontal Pod Autoscaling.
|
|
4925
|
+
*/
|
|
4926
|
+
adapterMetrics(): Promise<Record<string, unknown> | null>;
|
|
4927
|
+
/**
|
|
4928
|
+
* Synchronously returns the OCPPServerClient instance if the specific identity
|
|
4929
|
+
* is connected to THIS local server node.
|
|
4930
|
+
* Note: In a clustered environment, clients connected to other nodes will NOT be returned here.
|
|
4931
|
+
*
|
|
4932
|
+
* @param identity The client identity (username/station ID)
|
|
4933
|
+
*/
|
|
4934
|
+
getLocalClient(identity: string): OCPPServerClient | undefined;
|
|
4935
|
+
/**
|
|
4936
|
+
* Synchronously checks if the specific identity is connected to THIS local server node.
|
|
4937
|
+
* Note: In a clustered environment, this will return false if the client is connected to another node.
|
|
4938
|
+
*
|
|
4939
|
+
* @param identity The client identity (username/station ID)
|
|
4940
|
+
*/
|
|
4941
|
+
hasLocalClient(identity: string): boolean;
|
|
4942
|
+
/**
|
|
4943
|
+
* Asynchronously checks if the specific identity is connected to the server.
|
|
4944
|
+
* In a single-node setup, this checks the local connections.
|
|
4945
|
+
* In a clustered setup (with a pub/sub adapter), this will also check the global presence registry
|
|
4946
|
+
* to see if the client is connected to ANY node in the cluster.
|
|
4947
|
+
*
|
|
4948
|
+
* @param identity The client identity (username/station ID)
|
|
4949
|
+
*/
|
|
4950
|
+
isClientConnected(identity: string): Promise<boolean>;
|
|
4951
|
+
/**
|
|
4952
|
+
* Applies global CORS rules to all incoming connections before routing.
|
|
4953
|
+
*/
|
|
4954
|
+
cors(options: CORSOptions): this;
|
|
4955
|
+
/**
|
|
4956
|
+
* Registers a new routing dispatcher for multiplexing connections.
|
|
4957
|
+
* `server.route("/api/:tenant").use(middleware).auth(cb).on("client", ...)`
|
|
4958
|
+
*/
|
|
4959
|
+
route(...patterns: Array<string | RegExp>): OCPPRouter;
|
|
4960
|
+
/**
|
|
4961
|
+
* Attaches one or more standalone modular routers created via `createRouter()`.
|
|
4962
|
+
* This is useful for separating route definitions across different files.
|
|
4963
|
+
*/
|
|
4964
|
+
attachRouters(...routers: OCPPRouter[]): this;
|
|
4965
|
+
/**
|
|
4966
|
+
* Registers one or more plugins for server lifecycle hooks.
|
|
4967
|
+
* Plugins are called in registration order for all lifecycle events.
|
|
4968
|
+
*
|
|
4969
|
+
* @example Single plugin
|
|
4970
|
+
* ```ts
|
|
4971
|
+
* server.plugin(metricsPlugin);
|
|
4972
|
+
* ```
|
|
4973
|
+
*
|
|
4974
|
+
* @example Multiple plugins
|
|
4975
|
+
* ```ts
|
|
4976
|
+
* server.plugin(metricsPlugin, loggingPlugin, otelPlugin);
|
|
4977
|
+
* ```
|
|
4978
|
+
*/
|
|
4979
|
+
plugin(...plugins: OCPPPlugin[]): this;
|
|
4980
|
+
/**
|
|
4981
|
+
* Registers middleware chain(s) as a wildcard/catch-all router.
|
|
4982
|
+
*
|
|
4983
|
+
* @example
|
|
4984
|
+
* ```ts
|
|
4985
|
+
* server.use(myMiddleware).route("/api").on("client", ...);
|
|
4986
|
+
* ```
|
|
4987
|
+
*/
|
|
4988
|
+
use(...middlewares: ConnectionMiddleware[]): OCPPRouter;
|
|
4989
|
+
/**
|
|
4990
|
+
* Registers a top-level auth handler, returning a router to attach `.on()` or `.use()`.
|
|
4991
|
+
*/
|
|
4992
|
+
auth<TSession = Record<string, unknown>>(callback: AuthCallback<TSession>): OCPPRouter;
|
|
4993
|
+
/**
|
|
4994
|
+
* Routes a router into the appropriate internal structure:
|
|
4995
|
+
* - String patterns → radix trie (O(k) lookup)
|
|
4996
|
+
* - RegExp patterns → linear fallback array
|
|
4997
|
+
* - No patterns → global middleware (catch-all)
|
|
4998
|
+
* @internal
|
|
4999
|
+
*/
|
|
5000
|
+
private _registerRouter;
|
|
5001
|
+
listen(port?: number, host?: string, options?: ListenOptions): Promise<Server>;
|
|
5002
|
+
/**
|
|
5003
|
+
* Hot-reloads the TLS certificate on all active HTTPS servers without
|
|
5004
|
+
* dropping any existing WebSocket connections.
|
|
5005
|
+
*
|
|
5006
|
+
* **When to use:** Call this whenever your TLS certificate is renewed —
|
|
5007
|
+
* for example, after a Let's Encrypt auto-renewal (every ~90 days).
|
|
5008
|
+
* Without this, you would need to restart the Node.js process to pick up
|
|
5009
|
+
* the new certificate, disconnecting all connected charging stations.
|
|
5010
|
+
*
|
|
5011
|
+
* **How to use:**
|
|
5012
|
+
* ```ts
|
|
5013
|
+
* server.updateTLS({ cert: newCert, key: newKey });
|
|
5014
|
+
* ```
|
|
5015
|
+
*
|
|
5016
|
+
* **Optional:** Only relevant if you are terminating TLS directly in Node.js
|
|
5017
|
+
* (i.e. `SecurityProfile.TLS_BASIC_AUTH` or `TLS_CLIENT_CERT`). If you are
|
|
5018
|
+
* running behind a reverse proxy (Nginx, AWS ALB, etc.) that handles TLS,
|
|
5019
|
+
* you do not need this method — just rotate the cert on the proxy.
|
|
5020
|
+
*
|
|
5021
|
+
* @throws If the server is not using a TLS Security Profile.
|
|
5022
|
+
*/
|
|
5023
|
+
updateTLS(tlsOpts: TLSOptions): void;
|
|
5024
|
+
get handleUpgrade(): (req: IncomingMessage, socket: Duplex, head: Buffer) => Promise<void>;
|
|
5025
|
+
/**
|
|
5026
|
+
* Core upgrade handler. Follows a strict pipeline:
|
|
5027
|
+
*
|
|
5028
|
+
* 1. Validate socket readyState & upgrade header
|
|
5029
|
+
* 2. Parse URL → identity + endpoint
|
|
5030
|
+
* 3. Enable TCP Keep-Alive
|
|
5031
|
+
* 4. Parse & negotiate subprotocols
|
|
5032
|
+
* 5. Parse Basic Auth (via modular parseBasicAuth)
|
|
5033
|
+
* 6. Extract TLS client certificate (Profile 3)
|
|
5034
|
+
* 7. Build HandshakeInfo
|
|
5035
|
+
* 8. Run auth callback with AbortController + handshake timeout
|
|
5036
|
+
* 9. Complete WebSocket upgrade
|
|
5037
|
+
* 10. Create OCPPServerClient
|
|
5038
|
+
*/
|
|
5039
|
+
private _handleUpgrade;
|
|
5040
|
+
private _updateSessionActivity;
|
|
5041
|
+
close(options?: CloseOptions): Promise<void>;
|
|
5042
|
+
reconfigure(options: Partial<ServerOptions>): void;
|
|
5043
|
+
/**
|
|
5044
|
+
* Send a request to a specific client (local or remote).
|
|
5045
|
+
*
|
|
5046
|
+
* 1. Checks local clients.
|
|
5047
|
+
* 2. Checks Presence Registry -> Unicast.
|
|
5048
|
+
* 3. Fallback: Broadcast.
|
|
5049
|
+
*/
|
|
5050
|
+
/**
|
|
5051
|
+
* Send a request to a specific client (local or remote).
|
|
5052
|
+
*
|
|
5053
|
+
* 1. Checks local clients.
|
|
5054
|
+
* 2. Checks Presence Registry -> Unicast.
|
|
5055
|
+
* 3. Fallback: Error (Client not found).
|
|
5056
|
+
*/
|
|
5057
|
+
sendToClient<V extends OCPPProtocol, M extends AllMethodNames<V>>(identity: string, version: V, method: M, params: OCPPRequestType<V, M>, options?: CallOptions): Promise<OCPPResponseType<V, M> | undefined>;
|
|
5058
|
+
sendToClient<M extends AllMethodNames<any>>(identity: string, method: M, params: OCPPRequestType<any, M>, options?: CallOptions): Promise<OCPPResponseType<any, M> | undefined>;
|
|
5059
|
+
sendToClient<_T = any>(identity: string, method: string, params: Record<string, any>, options?: CallOptions): Promise<any | undefined>;
|
|
5060
|
+
safeSendToClient<V extends OCPPProtocol, M extends AllMethodNames<V>>(identity: string, version: V, method: M, params: OCPPRequestType<V, M>, options?: CallOptions): Promise<OCPPResponseType<V, M> | undefined>;
|
|
5061
|
+
safeSendToClient<M extends AllMethodNames<any>>(identity: string, method: M, params: OCPPRequestType<any, M>, options?: CallOptions): Promise<OCPPResponseType<any, M> | undefined>;
|
|
5062
|
+
safeSendToClient<_T = any>(identity: string, method: string, params: Record<string, any>, options?: CallOptions): Promise<any | undefined>;
|
|
5063
|
+
/**
|
|
5064
|
+
* Pipeline multiple calls to a single client into a concurrent batch.
|
|
5065
|
+
* Useful for reconnection warm-up (e.g. GetConfiguration, ChangeAvailability, etc.)
|
|
5066
|
+
* where sequential calls would add unnecessary round-trip latency.
|
|
5067
|
+
*
|
|
5068
|
+
* @param identity The client identity to send calls to
|
|
5069
|
+
* @param calls Array of { method, params, options? } to execute concurrently
|
|
5070
|
+
* @returns Array of results in the same order as the calls array.
|
|
5071
|
+
* Each element is the call result, or `undefined` if that individual call failed.
|
|
5072
|
+
*
|
|
5073
|
+
* @example
|
|
5074
|
+
* ```ts
|
|
5075
|
+
* const results = await server.sendBatch('CP-101', [
|
|
5076
|
+
* { method: 'GetConfiguration', params: { key: ['MeterInterval'] } },
|
|
5077
|
+
* { method: 'ChangeAvailability', params: { type: 'Operative' } },
|
|
5078
|
+
* { method: 'TriggerMessage', params: { requestedMessage: 'StatusNotification' } },
|
|
5079
|
+
* ]);
|
|
5080
|
+
* ```
|
|
5081
|
+
*/
|
|
5082
|
+
sendBatch(identity: string, calls: Array<{
|
|
5083
|
+
method: string;
|
|
5084
|
+
params: Record<string, unknown>;
|
|
5085
|
+
options?: CallOptions;
|
|
5086
|
+
}>): Promise<Array<unknown | undefined>>;
|
|
5087
|
+
setAdapter(adapter: EventAdapterInterface): Promise<void>;
|
|
5088
|
+
private _onBroadcast;
|
|
5089
|
+
private _onUnicast;
|
|
5090
|
+
publish(channel: string, data: unknown): Promise<void>;
|
|
5091
|
+
broadcast<V extends AllMethodNames<any>>(method: V, params: OCPPRequestType<any, V>): Promise<void>;
|
|
5092
|
+
/**
|
|
5093
|
+
* Send a specific method & params to a list of specific clients efficiently.
|
|
5094
|
+
* This leverages adapter pipelining (e.g. Redis .pipeline()) to minimize network overhead
|
|
5095
|
+
* when communicating with thousands of nodes simultaneously.
|
|
5096
|
+
*
|
|
5097
|
+
* @param identities Array of target client identities
|
|
5098
|
+
* @param method The OCPP method to send
|
|
5099
|
+
* @param params The request parameters
|
|
5100
|
+
* @param options Call options
|
|
5101
|
+
*/
|
|
5102
|
+
broadcastBatch<V extends AllMethodNames<any>>(identities: string[], method: V, params: OCPPRequestType<any, V>, options?: CallOptions): Promise<void>;
|
|
5103
|
+
private _buildCompressionConfig;
|
|
5104
|
+
}
|
|
5105
|
+
|
|
4735
5106
|
interface ValidatorSchema {
|
|
4736
5107
|
$schema?: string;
|
|
4737
5108
|
$id?: string;
|
|
@@ -5068,6 +5439,26 @@ interface ClientOptions {
|
|
|
5068
5439
|
* Oldest messages are dropped when exceeded. (default: 100)
|
|
5069
5440
|
*/
|
|
5070
5441
|
offlineQueueMaxSize?: number;
|
|
5442
|
+
/**
|
|
5443
|
+
* Enable WebSocket `permessage-deflate` compression.
|
|
5444
|
+
* Reduces bandwidth by ~80% for JSON payloads at the cost of ~0.2ms CPU per message.
|
|
5445
|
+
* - `true` → sensible defaults (threshold: 1024, level: 6)
|
|
5446
|
+
* - `object` → fine-tuned configuration
|
|
5447
|
+
* (default: false)
|
|
5448
|
+
*/
|
|
5449
|
+
compression?: boolean | CompressionOptions;
|
|
5450
|
+
}
|
|
5451
|
+
interface CompressionOptions {
|
|
5452
|
+
/** Minimum payload size in bytes to compress (default: 1024) */
|
|
5453
|
+
threshold?: number;
|
|
5454
|
+
/** zlib compression level 1 (fastest) to 9 (smallest) (default: 6) */
|
|
5455
|
+
level?: number;
|
|
5456
|
+
/** zlib memory level 1–9 (default: 8) */
|
|
5457
|
+
memLevel?: number;
|
|
5458
|
+
/** Server does not retain deflate context between messages (default: true — saves ~120KB/conn) */
|
|
5459
|
+
serverNoContextTakeover?: boolean;
|
|
5460
|
+
/** Client does not retain deflate context between messages (default: true) */
|
|
5461
|
+
clientNoContextTakeover?: boolean;
|
|
5071
5462
|
}
|
|
5072
5463
|
interface RateLimitOptions {
|
|
5073
5464
|
/** Maximum number of messages allowed within the window */
|
|
@@ -5090,6 +5481,27 @@ interface RateLimitOptions {
|
|
|
5090
5481
|
limit: number;
|
|
5091
5482
|
windowMs: number;
|
|
5092
5483
|
}>;
|
|
5484
|
+
/**
|
|
5485
|
+
* Enable adaptive rate limiting based on CPU/memory pressure.
|
|
5486
|
+
* When enabled, the token refill rate is automatically reduced under
|
|
5487
|
+
* high load and restored after a cooldown period. (default: false)
|
|
5488
|
+
*/
|
|
5489
|
+
adaptive?: boolean;
|
|
5490
|
+
/**
|
|
5491
|
+
* CPU usage percent threshold to begin throttling.
|
|
5492
|
+
* Applies only when `adaptive` is true. (default: 80)
|
|
5493
|
+
*/
|
|
5494
|
+
cpuThresholdPercent?: number;
|
|
5495
|
+
/**
|
|
5496
|
+
* Heap usage percent threshold to begin throttling.
|
|
5497
|
+
* Applies only when `adaptive` is true. (default: 85)
|
|
5498
|
+
*/
|
|
5499
|
+
memThresholdPercent?: number;
|
|
5500
|
+
/**
|
|
5501
|
+
* Time (ms) both CPU and memory must stay below their thresholds
|
|
5502
|
+
* before restoring the original rate. (default: 5000)
|
|
5503
|
+
*/
|
|
5504
|
+
cooldownMs?: number;
|
|
5093
5505
|
}
|
|
5094
5506
|
interface RouterConfig {
|
|
5095
5507
|
/** Accepted OCPP subprotocols (e.g. ["ocpp1.6"]) */
|
|
@@ -5189,6 +5601,26 @@ interface ServerOptionsBase {
|
|
|
5189
5601
|
* (default: 65536 / 64KB — sufficient for any standard OCPP message)
|
|
5190
5602
|
*/
|
|
5191
5603
|
maxPayloadBytes?: number;
|
|
5604
|
+
/**
|
|
5605
|
+
* Enable worker thread pool for JSON parsing (+ optional AJV validation).
|
|
5606
|
+
* Offloads CPU-heavy work to worker threads, keeping the main event loop free.
|
|
5607
|
+
* Recommended for 10k+ concurrent connections. (default: false)
|
|
5608
|
+
*
|
|
5609
|
+
* - `true` → uses default pool size: `Math.max(2, os.cpus() - 2)`
|
|
5610
|
+
* - `{ poolSize, maxQueueSize }` → fine-tuned pool configuration
|
|
5611
|
+
*/
|
|
5612
|
+
workerThreads?: boolean | {
|
|
5613
|
+
poolSize?: number;
|
|
5614
|
+
maxQueueSize?: number;
|
|
5615
|
+
};
|
|
5616
|
+
/**
|
|
5617
|
+
* Enable WebSocket `permessage-deflate` compression.
|
|
5618
|
+
* Reduces bandwidth by ~80% for JSON payloads at the cost of ~0.2ms CPU per message.
|
|
5619
|
+
* - `true` → sensible defaults (threshold: 1024, level: 6)
|
|
5620
|
+
* - `object` → fine-tuned configuration
|
|
5621
|
+
* (default: false)
|
|
5622
|
+
*/
|
|
5623
|
+
compression?: boolean | CompressionOptions;
|
|
5192
5624
|
}
|
|
5193
5625
|
/** When strictMode is enabled, protocols MUST be specified */
|
|
5194
5626
|
interface StrictServerOptions extends ServerOptionsBase {
|
|
@@ -5339,6 +5771,39 @@ interface EventAdapterInterface {
|
|
|
5339
5771
|
}[]): Promise<void>;
|
|
5340
5772
|
metrics?(): Promise<Record<string, unknown>>;
|
|
5341
5773
|
}
|
|
5774
|
+
/**
|
|
5775
|
+
* Plugin interface for extending OCPPServer functionality.
|
|
5776
|
+
*
|
|
5777
|
+
* Plugins provide a unified way to hook into server lifecycle events
|
|
5778
|
+
* without modifying core internals. Useful for:
|
|
5779
|
+
* - Observability (OpenTelemetry, Prometheus)
|
|
5780
|
+
* - Custom adapters and integrations
|
|
5781
|
+
* - Auditing and compliance
|
|
5782
|
+
*
|
|
5783
|
+
* @example
|
|
5784
|
+
* ```ts
|
|
5785
|
+
* const myPlugin: OCPPPlugin = {
|
|
5786
|
+
* name: 'my-plugin',
|
|
5787
|
+
* onInit(server) { console.log('Plugin initialized'); },
|
|
5788
|
+
* onConnection(client) { console.log(`${client.identity} connected`); },
|
|
5789
|
+
* onDisconnect(client) { console.log(`${client.identity} disconnected`); },
|
|
5790
|
+
* onClose() { console.log('Server shutting down'); },
|
|
5791
|
+
* };
|
|
5792
|
+
* server.plugin(myPlugin);
|
|
5793
|
+
* ```
|
|
5794
|
+
*/
|
|
5795
|
+
interface OCPPPlugin {
|
|
5796
|
+
/** Unique plugin name (used for logging and deduplication) */
|
|
5797
|
+
name: string;
|
|
5798
|
+
/** Called when the plugin is registered via server.plugin(plugin) */
|
|
5799
|
+
onInit?(server: OCPPServer): void | Promise<void>;
|
|
5800
|
+
/** Called for each new client connection after auth succeeds */
|
|
5801
|
+
onConnection?(client: OCPPServerClient): void | Promise<void>;
|
|
5802
|
+
/** Called when a client disconnects */
|
|
5803
|
+
onDisconnect?(client: OCPPServerClient, code: number, reason: string): void;
|
|
5804
|
+
/** Called during server.close() for plugin cleanup */
|
|
5805
|
+
onClose?(): void | Promise<void>;
|
|
5806
|
+
}
|
|
5342
5807
|
declare const NOREPLY: unique symbol;
|
|
5343
5808
|
type MiddlewareContext = {
|
|
5344
5809
|
type: "incoming_call";
|
|
@@ -5384,90 +5849,4 @@ interface AuthContext<TSession = Record<string, unknown>> extends BaseConnection
|
|
|
5384
5849
|
}
|
|
5385
5850
|
type ConnectionMiddleware = (ctx: ConnectionContext) => Promise<void> | void;
|
|
5386
5851
|
|
|
5387
|
-
|
|
5388
|
-
publish(channel: string, message: string): Promise<number | unknown | undefined>;
|
|
5389
|
-
subscribe(channel: string, ...args: unknown[]): Promise<unknown | undefined>;
|
|
5390
|
-
unsubscribe(channel: string, ...args: unknown[]): Promise<unknown | undefined>;
|
|
5391
|
-
on?(event: "message", callback: (channel: string, message: string) => void): unknown;
|
|
5392
|
-
disconnect?(): Promise<void> | void;
|
|
5393
|
-
quit?(): Promise<unknown> | undefined;
|
|
5394
|
-
isOpen?: boolean;
|
|
5395
|
-
}
|
|
5396
|
-
|
|
5397
|
-
interface RedisAdapterOptions {
|
|
5398
|
-
/** Redis client for publishing */
|
|
5399
|
-
pubClient: RedisLikeClient;
|
|
5400
|
-
/** Redis client for subscribing (must be a separate connection) */
|
|
5401
|
-
subClient: RedisLikeClient;
|
|
5402
|
-
/** Redis client for blocking stream operations (recommended for reliability) */
|
|
5403
|
-
blockingClient?: RedisLikeClient;
|
|
5404
|
-
/** Optional key prefix for channels (default: 'ocpp-ws-io:') */
|
|
5405
|
-
prefix?: string;
|
|
5406
|
-
/** StreamMaxLen for trimming (default: 1000) */
|
|
5407
|
-
streamMaxLen?: number;
|
|
5408
|
-
/**
|
|
5409
|
-
* TTL in seconds for ephemeral stream keys (default: 300).
|
|
5410
|
-
* Prevents abandoned channel keys from leaking memory in Redis.
|
|
5411
|
-
*/
|
|
5412
|
-
streamTtlSeconds?: number;
|
|
5413
|
-
/**
|
|
5414
|
-
* Presence TTL in seconds (default: 300).
|
|
5415
|
-
* Used for batch presence heartbeat pipeline.
|
|
5416
|
-
*/
|
|
5417
|
-
presenceTtlSeconds?: number;
|
|
5418
|
-
}
|
|
5419
|
-
/**
|
|
5420
|
-
* Redis adapter for cross-process event distribution.
|
|
5421
|
-
*
|
|
5422
|
-
* Supports `ioredis` and `node-redis` (v4+).
|
|
5423
|
-
* Uses Redis Streams for reliable unicast (node-to-node) and Pub/Sub for broadcast.
|
|
5424
|
-
*/
|
|
5425
|
-
declare class RedisAdapter implements EventAdapterInterface {
|
|
5426
|
-
private _driver;
|
|
5427
|
-
private _prefix;
|
|
5428
|
-
private _streamMaxLen;
|
|
5429
|
-
private _streamTtlSeconds;
|
|
5430
|
-
private _presenceTtlSeconds;
|
|
5431
|
-
private _handlers;
|
|
5432
|
-
private _streamOffsets;
|
|
5433
|
-
private _streams;
|
|
5434
|
-
private _polling;
|
|
5435
|
-
private _closed;
|
|
5436
|
-
private _sequenceCounters;
|
|
5437
|
-
private _unsubError?;
|
|
5438
|
-
private _unsubReconnect?;
|
|
5439
|
-
private _presenceCache;
|
|
5440
|
-
constructor(options: RedisAdapterOptions);
|
|
5441
|
-
publish(channel: string, data: unknown): Promise<void>;
|
|
5442
|
-
publishBatch(messages: {
|
|
5443
|
-
channel: string;
|
|
5444
|
-
data: unknown;
|
|
5445
|
-
}[]): Promise<void>;
|
|
5446
|
-
subscribe(channel: string, handler: (data: unknown) => void): Promise<void>;
|
|
5447
|
-
unsubscribe(channel: string): Promise<void>;
|
|
5448
|
-
disconnect(): Promise<void>;
|
|
5449
|
-
private _handleMessage;
|
|
5450
|
-
private _ensurePolling;
|
|
5451
|
-
private _pollLoop;
|
|
5452
|
-
setPresence(identity: string, nodeId: string, ttl: number): Promise<void>;
|
|
5453
|
-
getPresence(identity: string): Promise<string | null>;
|
|
5454
|
-
getPresenceBatch(identities: string[]): Promise<(string | null)[]>;
|
|
5455
|
-
removePresence(identity: string): Promise<void>;
|
|
5456
|
-
metrics(): Promise<Record<string, unknown>>;
|
|
5457
|
-
/**
|
|
5458
|
-
* Set multiple presence entries in a single Redis pipeline.
|
|
5459
|
-
* Reduces N network round-trips to 1 for bulk presence updates.
|
|
5460
|
-
*/
|
|
5461
|
-
setPresenceBatch(entries: {
|
|
5462
|
-
identity: string;
|
|
5463
|
-
nodeId: string;
|
|
5464
|
-
ttl?: number;
|
|
5465
|
-
}[]): Promise<void>;
|
|
5466
|
-
/**
|
|
5467
|
-
* Re-syncs all cached presence entries to Redis after a reconnection.
|
|
5468
|
-
* Called automatically when the Redis client reconnects.
|
|
5469
|
-
*/
|
|
5470
|
-
private _rehydratePresence;
|
|
5471
|
-
}
|
|
5472
|
-
|
|
5473
|
-
export { createValidator as $, type AuthCallback as A, MiddlewareStack as B, type ConnectionMiddleware as C, type OCPP16Methods as D, type EventAdapterInterface as E, type OCPP201Methods as F, type OCPP21Methods as G, type HandlerContext as H, type OCPPCall as I, type OCPPCallError as J, type OCPPCallResult as K, type LoggerLike as L, type MiddlewareFunction as M, NOREPLY as N, type OCPPProtocol as O, OCPPClient as P, type OCPPMessage as Q, type RouterConfig as R, type ServerEvents as S, type TypedEventEmitter as T, type OCPPMethodMap as U, Validator as V, type OCPPProtocolKey as W, RedisAdapter as X, SecurityProfile as Y, type SessionData 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 TLSOptions as n, type CloseOptions as o, type CallOptions as p, type AnyOCPPProtocol as q, type AuthAccept as r, type CallHandler as s, type ClientEvents as t, type ClientOptions as u, type ConnectionContext as v, ConnectionState as w, type HandshakeInfo as x, MessageType as y, type MiddlewareNext as z };
|
|
5852
|
+
export { createRouter as $, type AuthCallback as A, type OCPPMessage as B, type ConnectionMiddleware as C, type OCPPMethodMap as D, type EventAdapterInterface as E, type OCPPProtocol as F, type OCPPProtocolKey as G, type HandlerContext as H, type OCPPRequestType as I, type OCPPResponseType as J, OCPPRouter as K, type LoggerLike as L, type MiddlewareFunction as M, NOREPLY as N, type OCPPPlugin as O, OCPPServer as P, OCPPServerClient as Q, type RateLimitOptions as R, type RouterConfig as S, SecurityProfile as T, type ServerEvents as U, Validator as V, type ServerOptions as W, type SessionData as X, type TLSOptions as Y, type TypedEventEmitter as Z, type WildcardHandler as _, type LoggingConfig as a, createValidator as a0, type MiddlewareContext as b, type AllMethodNames as c, type AnyOCPPProtocol as d, type AuthAccept as e, type CORSOptions as f, type CallHandler as g, type CallOptions as h, type ClientEvents as i, type ClientOptions as j, type CloseOptions as k, type CompressionOptions as l, type ConnectionContext as m, ConnectionState as n, type HandshakeInfo as o, type ListenOptions as p, MessageType as q, type MiddlewareNext as r, MiddlewareStack as s, type OCPP16Methods as t, type OCPP201Methods as u, type OCPP21Methods as v, type OCPPCall as w, type OCPPCallError as x, type OCPPCallResult as y, OCPPClient as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ocpp-ws-io",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.8",
|
|
4
4
|
"description": "Type-safe OCPP 1.6 & 2.0.1 WebSocket RPC client & server. Build EV charging CSMS platforms with Redis clustering, strict validation, and DDoS protection.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
"types": "./dist/logger.d.ts",
|
|
30
30
|
"import": "./dist/logger.mjs",
|
|
31
31
|
"require": "./dist/logger.js"
|
|
32
|
+
},
|
|
33
|
+
"./plugins": {
|
|
34
|
+
"types": "./dist/plugins.d.ts",
|
|
35
|
+
"import": "./dist/plugins.mjs",
|
|
36
|
+
"require": "./dist/plugins.js"
|
|
32
37
|
}
|
|
33
38
|
},
|
|
34
39
|
"scripts": {
|
|
@@ -79,8 +84,7 @@
|
|
|
79
84
|
"url": "https://github.com/rohittiwari-dev/ocpp-ws-io/issues"
|
|
80
85
|
},
|
|
81
86
|
"files": [
|
|
82
|
-
"dist"
|
|
83
|
-
"assets"
|
|
87
|
+
"dist"
|
|
84
88
|
],
|
|
85
89
|
"license": "MIT",
|
|
86
90
|
"dependencies": {
|