ocpp-ws-io 2.1.4 → 2.1.6
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 +6 -6
- package/dist/adapters/redis.d.mts +1 -1
- package/dist/adapters/redis.d.ts +1 -1
- package/dist/adapters/redis.js +2 -2
- package/dist/adapters/redis.js.map +1 -1
- package/dist/adapters/redis.mjs +2 -2
- package/dist/adapters/redis.mjs.map +1 -1
- package/dist/browser.d.mts +5 -0
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs.map +1 -1
- package/dist/{index-CagcFzyZ.d.mts → index-1QBeqAuc.d.mts} +34 -2
- package/dist/{index-CagcFzyZ.d.ts → index-1QBeqAuc.d.ts} +34 -2
- package/dist/index.d.mts +26 -8
- package/dist/index.d.ts +26 -8
- package/dist/index.js +109 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +108 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -310,9 +310,9 @@ var RedisAdapter = class {
|
|
|
310
310
|
// Active streams to poll
|
|
311
311
|
_polling = false;
|
|
312
312
|
_closed = false;
|
|
313
|
-
//
|
|
313
|
+
// Per-stream sequence counter for message ordering
|
|
314
314
|
_sequenceCounters = /* @__PURE__ */ new Map();
|
|
315
|
-
//
|
|
315
|
+
// Rehydration callbacks
|
|
316
316
|
_unsubError;
|
|
317
317
|
_unsubReconnect;
|
|
318
318
|
// Stored presence entries for rehydration on reconnect
|
|
@@ -36919,6 +36919,8 @@ var Validator = class {
|
|
|
36919
36919
|
/**
|
|
36920
36920
|
* Validate a payload against a schema identified by its $id.
|
|
36921
36921
|
* Throws a typed RPCError if validation fails.
|
|
36922
|
+
*
|
|
36923
|
+
* E2: Schema is compiled on first call to this method (lazy).
|
|
36922
36924
|
*/
|
|
36923
36925
|
validate(schemaId, params) {
|
|
36924
36926
|
const resolvedId = this._normalizeSchemaId(schemaId);
|
|
@@ -36941,16 +36943,26 @@ var Validator = class {
|
|
|
36941
36943
|
return !!this._ajv.getSchema(this._normalizeSchemaId(schemaId));
|
|
36942
36944
|
}
|
|
36943
36945
|
};
|
|
36946
|
+
var _validatorRegistry = /* @__PURE__ */ new Map();
|
|
36944
36947
|
function createValidator(subprotocol, schemas) {
|
|
36945
|
-
|
|
36948
|
+
const existing = _validatorRegistry.get(subprotocol);
|
|
36949
|
+
if (existing) return existing;
|
|
36950
|
+
const validator = new Validator(subprotocol, schemas);
|
|
36951
|
+
_validatorRegistry.set(subprotocol, validator);
|
|
36952
|
+
return validator;
|
|
36946
36953
|
}
|
|
36947
36954
|
|
|
36948
36955
|
// src/standard-validators.ts
|
|
36949
|
-
var
|
|
36950
|
-
|
|
36951
|
-
|
|
36952
|
-
|
|
36953
|
-
|
|
36956
|
+
var _cached = null;
|
|
36957
|
+
function getStandardValidators() {
|
|
36958
|
+
if (_cached) return _cached;
|
|
36959
|
+
_cached = [
|
|
36960
|
+
createValidator("ocpp1.6", ocpp1_6_default),
|
|
36961
|
+
createValidator("ocpp2.0.1", ocpp2_0_1_default),
|
|
36962
|
+
createValidator("ocpp2.1", ocpp2_1_default)
|
|
36963
|
+
];
|
|
36964
|
+
return _cached;
|
|
36965
|
+
}
|
|
36954
36966
|
|
|
36955
36967
|
// src/types.ts
|
|
36956
36968
|
var ConnectionState = {
|
|
@@ -37143,6 +37155,7 @@ var OCPPClient = class _OCPPClient extends EventEmitter {
|
|
|
37143
37155
|
_prettify = false;
|
|
37144
37156
|
constructor(options) {
|
|
37145
37157
|
super();
|
|
37158
|
+
this.setMaxListeners(0);
|
|
37146
37159
|
if (!options.identity) {
|
|
37147
37160
|
throw new Error("identity is required");
|
|
37148
37161
|
}
|
|
@@ -37644,11 +37657,13 @@ var OCPPClient = class _OCPPClient extends EventEmitter {
|
|
|
37644
37657
|
this._recordActivity();
|
|
37645
37658
|
let message;
|
|
37646
37659
|
try {
|
|
37647
|
-
|
|
37648
|
-
message = JSON.parse(str);
|
|
37660
|
+
message = JSON.parse(rawData);
|
|
37649
37661
|
if (!Array.isArray(message)) throw new Error("Message is not an array");
|
|
37650
37662
|
} catch (err) {
|
|
37651
|
-
this._onBadMessage(
|
|
37663
|
+
this._onBadMessage(
|
|
37664
|
+
typeof rawData === "string" ? rawData : rawData.toString(),
|
|
37665
|
+
err
|
|
37666
|
+
);
|
|
37652
37667
|
return;
|
|
37653
37668
|
}
|
|
37654
37669
|
const messageType = message[0];
|
|
@@ -37975,10 +37990,14 @@ var OCPPClient = class _OCPPClient extends EventEmitter {
|
|
|
37975
37990
|
}
|
|
37976
37991
|
if (ws.bufferedAmount > _OCPPClient._BACKPRESSURE_THRESHOLD) {
|
|
37977
37992
|
this._logger?.warn?.("Backpressure \u2014 pausing send", {
|
|
37993
|
+
identity: this._identity,
|
|
37978
37994
|
bufferedAmount: ws.bufferedAmount,
|
|
37979
37995
|
threshold: _OCPPClient._BACKPRESSURE_THRESHOLD
|
|
37980
37996
|
});
|
|
37981
|
-
this.emit("backpressure", {
|
|
37997
|
+
this.emit("backpressure", {
|
|
37998
|
+
identity: this._identity,
|
|
37999
|
+
bufferedAmount: ws.bufferedAmount
|
|
38000
|
+
});
|
|
37982
38001
|
let waited = 0;
|
|
37983
38002
|
const drainCheck = setInterval(() => {
|
|
37984
38003
|
waited += 50;
|
|
@@ -38042,7 +38061,7 @@ var OCPPClient = class _OCPPClient extends EventEmitter {
|
|
|
38042
38061
|
if (this._options.strictModeValidators) {
|
|
38043
38062
|
this._validators = this._options.strictModeValidators;
|
|
38044
38063
|
} else {
|
|
38045
|
-
this._validators =
|
|
38064
|
+
this._validators = getStandardValidators();
|
|
38046
38065
|
}
|
|
38047
38066
|
if (Array.isArray(this._options.strictMode)) {
|
|
38048
38067
|
this._strictProtocols = this._options.strictMode;
|
|
@@ -38598,8 +38617,7 @@ var OCPPServerClient = class extends OCPPClient {
|
|
|
38598
38617
|
let pData;
|
|
38599
38618
|
if (limits.methods) {
|
|
38600
38619
|
try {
|
|
38601
|
-
|
|
38602
|
-
pData = JSON.parse(str);
|
|
38620
|
+
pData = JSON.parse(data);
|
|
38603
38621
|
if (Array.isArray(pData) && pData[0] === 2) {
|
|
38604
38622
|
method = pData[2];
|
|
38605
38623
|
}
|
|
@@ -38726,6 +38744,7 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
38726
38744
|
_sessionTimeoutMs;
|
|
38727
38745
|
constructor(options = {}) {
|
|
38728
38746
|
super();
|
|
38747
|
+
this.setMaxListeners(0);
|
|
38729
38748
|
if (options.strictMode) {
|
|
38730
38749
|
if (!options.strictModeValidators && !options.protocols?.length) {
|
|
38731
38750
|
throw new Error(
|
|
@@ -38748,7 +38767,10 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
38748
38767
|
this._sessionTimeoutMs = this._options.sessionTtlMs;
|
|
38749
38768
|
const maxSessions = this._options.maxSessions ?? 5e4;
|
|
38750
38769
|
this._sessions = new LRUMap(maxSessions);
|
|
38751
|
-
this._wss = new WebSocketServer({
|
|
38770
|
+
this._wss = new WebSocketServer({
|
|
38771
|
+
noServer: true,
|
|
38772
|
+
maxPayload: this._options.maxPayloadBytes ?? 65536
|
|
38773
|
+
});
|
|
38752
38774
|
this._gcInterval = setInterval(() => {
|
|
38753
38775
|
const now = Date.now();
|
|
38754
38776
|
for (const [identity, session] of this._sessions.entries()) {
|
|
@@ -39054,6 +39076,51 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
39054
39076
|
}
|
|
39055
39077
|
return httpServer;
|
|
39056
39078
|
}
|
|
39079
|
+
/**
|
|
39080
|
+
* Hot-reloads the TLS certificate on all active HTTPS servers without
|
|
39081
|
+
* dropping any existing WebSocket connections.
|
|
39082
|
+
*
|
|
39083
|
+
* **When to use:** Call this whenever your TLS certificate is renewed —
|
|
39084
|
+
* for example, after a Let's Encrypt auto-renewal (every ~90 days).
|
|
39085
|
+
* Without this, you would need to restart the Node.js process to pick up
|
|
39086
|
+
* the new certificate, disconnecting all connected charging stations.
|
|
39087
|
+
*
|
|
39088
|
+
* **How to use:**
|
|
39089
|
+
* ```ts
|
|
39090
|
+
* server.updateTLS({ cert: newCert, key: newKey });
|
|
39091
|
+
* ```
|
|
39092
|
+
*
|
|
39093
|
+
* **Optional:** Only relevant if you are terminating TLS directly in Node.js
|
|
39094
|
+
* (i.e. `SecurityProfile.TLS_BASIC_AUTH` or `TLS_CLIENT_CERT`). If you are
|
|
39095
|
+
* running behind a reverse proxy (Nginx, AWS ALB, etc.) that handles TLS,
|
|
39096
|
+
* you do not need this method — just rotate the cert on the proxy.
|
|
39097
|
+
*
|
|
39098
|
+
* @throws If the server is not using a TLS Security Profile.
|
|
39099
|
+
*/
|
|
39100
|
+
updateTLS(tlsOpts) {
|
|
39101
|
+
const profile = this._options.securityProfile ?? 0 /* NONE */;
|
|
39102
|
+
if (profile !== 2 /* TLS_BASIC_AUTH */ && profile !== 3 /* TLS_CLIENT_CERT */) {
|
|
39103
|
+
throw new Error(
|
|
39104
|
+
"updateTLS() requires a TLS Security Profile (TLS_BASIC_AUTH or TLS_CLIENT_CERT)"
|
|
39105
|
+
);
|
|
39106
|
+
}
|
|
39107
|
+
this._options.tls = { ...this._options.tls, ...tlsOpts };
|
|
39108
|
+
const httpsOptions = {};
|
|
39109
|
+
if (tlsOpts.cert) httpsOptions.cert = tlsOpts.cert;
|
|
39110
|
+
if (tlsOpts.key) httpsOptions.key = tlsOpts.key;
|
|
39111
|
+
if (tlsOpts.ca) httpsOptions.ca = tlsOpts.ca;
|
|
39112
|
+
if (tlsOpts.passphrase) httpsOptions.passphrase = tlsOpts.passphrase;
|
|
39113
|
+
let updated = 0;
|
|
39114
|
+
for (const srv of this._httpServers) {
|
|
39115
|
+
if ("setSecureContext" in srv && typeof srv.setSecureContext === "function") {
|
|
39116
|
+
srv.setSecureContext(httpsOptions);
|
|
39117
|
+
updated++;
|
|
39118
|
+
}
|
|
39119
|
+
}
|
|
39120
|
+
this._logger?.info?.(
|
|
39121
|
+
`TLS context hot-reloaded across ${updated} active server(s)`
|
|
39122
|
+
);
|
|
39123
|
+
}
|
|
39057
39124
|
// ─── Handle Upgrade ──────────────────────────────────────────
|
|
39058
39125
|
get handleUpgrade() {
|
|
39059
39126
|
return (req, socket, head) => {
|
|
@@ -39107,6 +39174,12 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
39107
39174
|
}
|
|
39108
39175
|
if (bucket.tokens < 1) {
|
|
39109
39176
|
this._logger?.warn?.("Connection rate limit exceeded", { ip });
|
|
39177
|
+
this.emit("securityEvent", {
|
|
39178
|
+
type: "CONNECTION_RATE_LIMIT",
|
|
39179
|
+
ip,
|
|
39180
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39181
|
+
details: { tokensRemaining: bucket.tokens }
|
|
39182
|
+
});
|
|
39110
39183
|
abortHandshake(socket, 429, "Too Many Requests");
|
|
39111
39184
|
return;
|
|
39112
39185
|
}
|
|
@@ -39363,6 +39436,13 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
39363
39436
|
if (ac.signal.aborted) {
|
|
39364
39437
|
const reason = err instanceof Error ? err.message : "Unknown abort";
|
|
39365
39438
|
this._logger?.warn?.("Handshake aborted", { identity, reason });
|
|
39439
|
+
this.emit("securityEvent", {
|
|
39440
|
+
type: "UPGRADE_ABORTED",
|
|
39441
|
+
identity,
|
|
39442
|
+
ip: req.socket.remoteAddress,
|
|
39443
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39444
|
+
details: { reason }
|
|
39445
|
+
});
|
|
39366
39446
|
this.emit("upgradeAborted", {
|
|
39367
39447
|
identity,
|
|
39368
39448
|
reason,
|
|
@@ -39376,6 +39456,13 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
39376
39456
|
const code = typeof errObj?.code === "number" ? errObj.code : 401;
|
|
39377
39457
|
const message = typeof errObj?.message === "string" ? errObj.message : "Unauthorized";
|
|
39378
39458
|
this._logger?.warn?.("Auth rejected", { identity, code });
|
|
39459
|
+
this.emit("securityEvent", {
|
|
39460
|
+
type: "AUTH_FAILED",
|
|
39461
|
+
identity,
|
|
39462
|
+
ip: req.socket.remoteAddress,
|
|
39463
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39464
|
+
details: { code, message }
|
|
39465
|
+
});
|
|
39379
39466
|
abortHandshake(socket, code, message);
|
|
39380
39467
|
return;
|
|
39381
39468
|
} finally {
|
|
@@ -39399,7 +39486,10 @@ var OCPPServer = class extends EventEmitter3 {
|
|
|
39399
39486
|
return;
|
|
39400
39487
|
}
|
|
39401
39488
|
if (!this._wss) {
|
|
39402
|
-
this._wss = new WebSocketServer({
|
|
39489
|
+
this._wss = new WebSocketServer({
|
|
39490
|
+
noServer: true,
|
|
39491
|
+
maxPayload: this._options.maxPayloadBytes ?? 65536
|
|
39492
|
+
});
|
|
39403
39493
|
}
|
|
39404
39494
|
this._wss.handleUpgrade(req, socket, head, (ws) => {
|
|
39405
39495
|
const clientOptions = {
|
|
@@ -39786,6 +39876,6 @@ export {
|
|
|
39786
39876
|
defineRpcMiddleware,
|
|
39787
39877
|
getErrorPlainObject,
|
|
39788
39878
|
getPackageIdent,
|
|
39789
|
-
|
|
39879
|
+
getStandardValidators
|
|
39790
39880
|
};
|
|
39791
39881
|
//# sourceMappingURL=index.mjs.map
|