ocpp-ws-io 1.0.0 → 1.0.1
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.
Potentially problematic release.
This version of ocpp-ws-io might be problematic. Click here for more details.
- package/README.md +364 -16
- package/dist/adapters/redis.d.mts +13 -43
- package/dist/adapters/redis.d.ts +13 -43
- package/dist/adapters/redis.js +84 -40
- package/dist/adapters/redis.js.map +1 -1
- package/dist/adapters/redis.mjs +82 -40
- package/dist/adapters/redis.mjs.map +1 -1
- package/dist/browser.d.mts +4751 -0
- package/dist/browser.d.ts +4751 -0
- package/dist/browser.js +806 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.mjs +783 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/index.d.mts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +74 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +74 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{types-CpxyZ6AL.d.mts → types-CJQYxOD8.d.mts} +7 -4
- package/dist/{types-CpxyZ6AL.d.ts → types-CJQYxOD8.d.ts} +7 -4
- package/keywords.json +14 -0
- package/package.json +20 -3
- package/scripts/generate-types.js +32 -17
- package/src/adapters/redis/helpers.ts +101 -0
- package/src/adapters/redis/index.ts +84 -0
- package/src/browser/client.ts +777 -0
- package/src/browser/emitter.ts +73 -0
- package/src/browser/errors.ts +160 -0
- package/src/browser/index.ts +47 -0
- package/src/browser/queue.ts +65 -0
- package/src/browser/types.ts +100 -0
- package/src/browser/util.ts +81 -0
- package/src/client.ts +2 -2
- package/src/generated/index.ts +7 -12
- package/src/index.ts +2 -0
- package/src/server.ts +110 -1
- package/src/types.ts +14 -3
- package/src/util.ts +1 -1
- package/test/browser-client.test.ts +1165 -0
- package/test/browser-emitter.test.ts +209 -0
- package/test/browser-errors.test.ts +183 -0
- package/test/browser-queue.test.ts +169 -0
- package/test/browser-util.test.ts +137 -0
- package/test/client.test.ts +81 -1
- package/test/generate-types.test.ts +61 -0
- package/test/index.test.ts +13 -0
- package/test/redis-adapter.test.ts +226 -0
- package/test/redis-driver.test.ts +44 -0
- package/test/server.test.ts +321 -1
- package/tsup.config.ts +30 -13
- package/.github/workflows/publish.yml +0 -57
- package/LICENSE +0 -21
- package/src/adapters/redis.ts +0 -144
package/README.md
CHANGED
|
@@ -11,9 +11,11 @@ Built with TypeScript from the ground up — supports OCPP 1.6, 2.0.1, and 2.1 w
|
|
|
11
11
|
- 📐 **Strict Mode** — Optional schema validation using built-in OCPP JSON schemas
|
|
12
12
|
- 🔁 **Auto-Reconnect** — Exponential backoff with configurable limits
|
|
13
13
|
- 🧩 **Framework Agnostic** — Use standalone, or attach to Express, Fastify, NestJS, etc.
|
|
14
|
-
- 📡 **Clustering** — Optional Redis adapter
|
|
14
|
+
- 📡 **Clustering** — Optional Redis adapter (supports `ioredis` & `node-redis`)
|
|
15
15
|
- 🎯 **Type-Safe** — Auto-generated types for all OCPP 1.6, 2.0.1 & 2.1 methods with full request/response inference
|
|
16
|
+
- 🛠️ **Schema-to-TS** — Built-in script to re-generate types from official JSON schemas
|
|
16
17
|
- 🔀 **Version-Aware Handlers** — Register handlers per OCPP version with typed params, or use generic handlers with protocol context
|
|
18
|
+
- 🌐 **Browser Client** — Zero-dependency browser WebSocket client via `ocpp-ws-io/browser`
|
|
17
19
|
|
|
18
20
|
## Installation
|
|
19
21
|
|
|
@@ -112,6 +114,39 @@ await server.listen(3000);
|
|
|
112
114
|
console.log("OCPP Server listening on port 3000");
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
### Browser Client
|
|
118
|
+
|
|
119
|
+
For browser environments (React, Vue, Next.js client components, etc.), use `BrowserOCPPClient` from the `ocpp-ws-io/browser` subpath. Designed for **building charge point simulators, testing dashboards, and debugging tools** directly in the browser — zero Node.js dependencies.
|
|
120
|
+
|
|
121
|
+
> **Note:** The browser client does not support all OCPP features (no Security Profiles, Strict Mode, TLS, Ping/Pong, or custom headers). For production use, use `OCPPClient` in Node.js.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
|
|
125
|
+
|
|
126
|
+
const client = new BrowserOCPPClient({
|
|
127
|
+
endpoint: "wss://csms.example.com/ocpp",
|
|
128
|
+
identity: "CP001",
|
|
129
|
+
protocols: ["ocpp1.6"],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Same typed API as OCPPClient
|
|
133
|
+
client.handle("Reset", ({ params }) => {
|
|
134
|
+
console.log("Reset type:", params.type);
|
|
135
|
+
return { status: "Accepted" };
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await client.connect();
|
|
139
|
+
|
|
140
|
+
const response = await client.call("ocpp1.6", "BootNotification", {
|
|
141
|
+
chargePointVendor: "VendorX",
|
|
142
|
+
chargePointModel: "ModelY",
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
console.log("Status:", response.status); // typed: "Accepted" | "Pending" | "Rejected"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
> See [Browser Client](#browser-client-1) below for the full API reference, configuration options, and framework integration examples.
|
|
149
|
+
|
|
115
150
|
---
|
|
116
151
|
|
|
117
152
|
## Security Profiles
|
|
@@ -398,10 +433,11 @@ client.removeAllHandlers();
|
|
|
398
433
|
```typescript
|
|
399
434
|
import type {
|
|
400
435
|
OCPPProtocol, // "ocpp1.6" | "ocpp2.0.1" | "ocpp2.1"
|
|
436
|
+
OCPPProtocolKey, // keyof OCPPMethodMap — extensible via module augmentation
|
|
437
|
+
OCPPMethodMap, // Full method map interface
|
|
401
438
|
AllMethodNames, // All method names for a given protocol
|
|
402
439
|
OCPPRequestType, // Request type for a method, e.g. OCPPRequestType<"ocpp1.6", "Reset">
|
|
403
440
|
OCPPResponseType, // Response type for a method
|
|
404
|
-
OCPPMethodMap, // Full method map for a protocol
|
|
405
441
|
} from "ocpp-ws-io";
|
|
406
442
|
|
|
407
443
|
// Example: Get all method names for OCPP 1.6
|
|
@@ -448,15 +484,82 @@ Custom validators:
|
|
|
448
484
|
import { createValidator } from "ocpp-ws-io";
|
|
449
485
|
import myCustomSchemas from "./my-schemas.json";
|
|
450
486
|
|
|
451
|
-
const myValidator = createValidator("
|
|
487
|
+
const myValidator = createValidator("vendor-proto", myCustomSchemas);
|
|
452
488
|
|
|
453
489
|
const client = new OCPPClient({
|
|
454
|
-
protocols: ["
|
|
490
|
+
protocols: ["ocpp1.6", "vendor-proto"],
|
|
455
491
|
strictMode: true,
|
|
456
|
-
strictModeValidators: [myValidator],
|
|
492
|
+
strictModeValidators: [myValidator], // adds to built-in validators
|
|
457
493
|
});
|
|
458
494
|
```
|
|
459
495
|
|
|
496
|
+
> **Tip:** Combine custom validators with module augmentation to get both runtime validation **and** compile-time type safety. See [Extending with Custom Protocols](#extending-with-custom-protocols) below.
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Extending with Custom Protocols
|
|
501
|
+
|
|
502
|
+
`OCPPMethodMap` is a TypeScript **interface**, so you can extend it with your own protocols using [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation). This gives you full type safety for custom/vendor-specific protocols in `handle()`, `call()`, and `protocols`.
|
|
503
|
+
|
|
504
|
+
### Step 1: Define Your Method Types
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
// src/vendor-types.ts
|
|
508
|
+
export interface MyVendorMethods {
|
|
509
|
+
VendorAction: {
|
|
510
|
+
request: { data: string; priority: number };
|
|
511
|
+
response: { status: "Accepted" | "Rejected" };
|
|
512
|
+
};
|
|
513
|
+
VendorQuery: {
|
|
514
|
+
request: { query: string };
|
|
515
|
+
response: { results: string[] };
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Step 2: Augment OCPPMethodMap
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// src/ocpp-extensions.d.ts
|
|
524
|
+
import type { MyVendorMethods } from "./vendor-types";
|
|
525
|
+
|
|
526
|
+
declare module "ocpp-ws-io" {
|
|
527
|
+
interface OCPPMethodMap {
|
|
528
|
+
"vendor-proto": MyVendorMethods;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Step 3: Use Everywhere — Fully Typed
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
import { OCPPClient, createValidator } from "ocpp-ws-io";
|
|
537
|
+
import vendorSchemas from "./vendor-schemas.json";
|
|
538
|
+
|
|
539
|
+
const vendorValidator = createValidator("vendor-proto", vendorSchemas);
|
|
540
|
+
|
|
541
|
+
const client = new OCPPClient({
|
|
542
|
+
endpoint: "ws://localhost:3000",
|
|
543
|
+
identity: "CP001",
|
|
544
|
+
protocols: ["ocpp1.6", "vendor-proto"], // ✅ autocompletes
|
|
545
|
+
strictMode: true,
|
|
546
|
+
strictModeValidators: [vendorValidator],
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// ✅ Fully typed handle
|
|
550
|
+
client.handle("vendor-proto", "VendorAction", ({ params }) => {
|
|
551
|
+
console.log(params.data); // string
|
|
552
|
+
console.log(params.priority); // number
|
|
553
|
+
return { status: "Accepted" }; // typed response
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// ✅ Fully typed call
|
|
557
|
+
const res = await client.call("vendor-proto", "VendorQuery", {
|
|
558
|
+
query: "status",
|
|
559
|
+
});
|
|
560
|
+
console.log(res.results); // string[]
|
|
561
|
+
```
|
|
562
|
+
|
|
460
563
|
---
|
|
461
564
|
|
|
462
565
|
## Clustering with Redis
|
|
@@ -472,9 +575,9 @@ const server = new OCPPServer({ protocols: ["ocpp2.0.1"] });
|
|
|
472
575
|
|
|
473
576
|
server.setAdapter(
|
|
474
577
|
new RedisAdapter({
|
|
475
|
-
pubClient: new Redis(),
|
|
476
|
-
subClient: new Redis(),
|
|
477
|
-
prefix: "ocpp:", // optional
|
|
578
|
+
pubClient: new Redis(process.env.REDIS_URL),
|
|
579
|
+
subClient: new Redis(process.env.REDIS_URL),
|
|
580
|
+
prefix: "ocpp-cluster:", // optional
|
|
478
581
|
}),
|
|
479
582
|
);
|
|
480
583
|
|
|
@@ -485,20 +588,27 @@ server.on("client", (client) => {
|
|
|
485
588
|
await server.listen(3000);
|
|
486
589
|
```
|
|
487
590
|
|
|
488
|
-
The adapter
|
|
591
|
+
The adapter automatically detects and works with both `ioredis` and `node-redis` (v4+).
|
|
489
592
|
|
|
490
593
|
```typescript
|
|
491
594
|
// With node-redis
|
|
492
595
|
import { createClient } from "redis";
|
|
493
596
|
|
|
494
|
-
const pub = createClient();
|
|
597
|
+
const pub = createClient({ url: process.env.REDIS_URL });
|
|
495
598
|
const sub = pub.duplicate();
|
|
496
|
-
await pub.connect();
|
|
497
|
-
await sub.connect();
|
|
599
|
+
await Promise.all([pub.connect(), sub.connect()]);
|
|
498
600
|
|
|
499
601
|
server.setAdapter(new RedisAdapter({ pubClient: pub, subClient: sub }));
|
|
500
602
|
```
|
|
501
603
|
|
|
604
|
+
## Type Generation
|
|
605
|
+
|
|
606
|
+
Re-generate TypeScript definitions from the latest OCPP JSON schemas:
|
|
607
|
+
|
|
608
|
+
```bash
|
|
609
|
+
npm run generate
|
|
610
|
+
```
|
|
611
|
+
|
|
502
612
|
---
|
|
503
613
|
|
|
504
614
|
## API Reference
|
|
@@ -521,7 +631,7 @@ const client = new OCPPClient(options: ClientOptions);
|
|
|
521
631
|
| --------------------------- | ------------------------ | ---------- | -------------------------------------------- |
|
|
522
632
|
| `identity` | `string` | _required_ | Charging station ID |
|
|
523
633
|
| `endpoint` | `string` | _required_ | WebSocket URL (`ws://` or `wss://`) |
|
|
524
|
-
| `protocols` | `
|
|
634
|
+
| `protocols` | `OCPPProtocol[]` | `[]` | OCPP subprotocols to negotiate |
|
|
525
635
|
| `securityProfile` | `SecurityProfile` | `NONE` | Security profile (0–3) |
|
|
526
636
|
| `password` | `string \| Buffer` | — | Password for Basic Auth (Profile 1 & 2) |
|
|
527
637
|
| `tls` | `TLSOptions` | — | TLS/SSL options (Profile 2 & 3) |
|
|
@@ -683,7 +793,7 @@ const server = new OCPPServer(options?: ServerOptions);
|
|
|
683
793
|
|
|
684
794
|
| Option | Type | Default | Description |
|
|
685
795
|
| --------------------------- | --------------------- | ---------- | ----------------------------------------- |
|
|
686
|
-
| `protocols` | `
|
|
796
|
+
| `protocols` | `OCPPProtocol[]` | `[]` | Accepted OCPP subprotocols |
|
|
687
797
|
| `securityProfile` | `SecurityProfile` | `NONE` | Security profile for auto-created servers |
|
|
688
798
|
| `tls` | `TLSOptions` | — | TLS options (Profile 2 & 3) |
|
|
689
799
|
| `callTimeoutMs` | `number` | `30000` | Inherited by server clients |
|
|
@@ -886,10 +996,11 @@ All types are exported for use in your application:
|
|
|
886
996
|
import type {
|
|
887
997
|
// OCPP protocol types (auto-generated)
|
|
888
998
|
OCPPProtocol, // "ocpp1.6" | "ocpp2.0.1" | "ocpp2.1"
|
|
999
|
+
OCPPProtocolKey, // keyof OCPPMethodMap — extensible via module augmentation
|
|
889
1000
|
AllMethodNames, // Union of method names for a protocol
|
|
890
1001
|
OCPPRequestType, // Request type for a method + protocol
|
|
891
1002
|
OCPPResponseType, // Response type for a method + protocol
|
|
892
|
-
OCPPMethodMap, // Full method map
|
|
1003
|
+
OCPPMethodMap, // Full method map interface
|
|
893
1004
|
|
|
894
1005
|
// OCPP message types
|
|
895
1006
|
OCPPCall,
|
|
@@ -931,9 +1042,246 @@ import type {
|
|
|
931
1042
|
|
|
932
1043
|
---
|
|
933
1044
|
|
|
1045
|
+
## Browser Client
|
|
1046
|
+
|
|
1047
|
+
`BrowserOCPPClient` is a lightweight OCPP WebSocket RPC client designed for **building charge point simulators, testing dashboards, and debugging tools** in the browser. It provides the same typed API as `OCPPClient` — without any Node.js dependencies.
|
|
1048
|
+
|
|
1049
|
+
> **Note:** The browser client is designed for testing and simulating charge points — it does not support all OCPP features. Missing: Security Profiles (0–3), Strict Mode (schema validation), TLS/mTLS configuration, WebSocket Ping/Pong, and custom HTTP headers. For production charge point communication, use `OCPPClient` in a Node.js environment.
|
|
1050
|
+
|
|
1051
|
+
```typescript
|
|
1052
|
+
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
### Why a Separate Browser Client?
|
|
1056
|
+
|
|
1057
|
+
`OCPPClient` depends on Node.js modules (`ws`, `node:crypto`, `node:events`, `node:net`). `BrowserOCPPClient` replaces all of these with browser-native APIs:
|
|
1058
|
+
|
|
1059
|
+
| Feature | `OCPPClient` | `BrowserOCPPClient` |
|
|
1060
|
+
| ----------------- | ---------------------- | -------------------------- |
|
|
1061
|
+
| WebSocket | `ws` (Node.js) | Native browser `WebSocket` |
|
|
1062
|
+
| Events | `node:events` | Custom `EventEmitter` |
|
|
1063
|
+
| ID Generation | `@paralleldrive/cuid2` | `@paralleldrive/cuid2` |
|
|
1064
|
+
| Security Profiles | 0–3 (TLS, mTLS, certs) | N/A (handled by browser) |
|
|
1065
|
+
| Custom Headers | ✅ via `ws` | ❌ browser limitation |
|
|
1066
|
+
| Ping/Pong | ✅ | ❌ browser limitation |
|
|
1067
|
+
| Type Safety | ✅ Full | ✅ Full (same types) |
|
|
1068
|
+
| Reconnection | ✅ | ✅ |
|
|
1069
|
+
| Strict Mode | ✅ | ❌ |
|
|
1070
|
+
|
|
1071
|
+
### Constructor
|
|
1072
|
+
|
|
1073
|
+
```typescript
|
|
1074
|
+
const client = new BrowserOCPPClient(options: BrowserClientOptions);
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
**`BrowserClientOptions`**:
|
|
1078
|
+
|
|
1079
|
+
| Option | Type | Default | Description |
|
|
1080
|
+
| --------------------------- | ------------------------ | ---------- | -------------------------------------- |
|
|
1081
|
+
| `identity` | `string` | _required_ | Charging station ID |
|
|
1082
|
+
| `endpoint` | `string` | _required_ | WebSocket URL (`ws://` or `wss://`) |
|
|
1083
|
+
| `protocols` | `string[]` | `[]` | OCPP subprotocols to negotiate |
|
|
1084
|
+
| `query` | `Record<string, string>` | — | Additional URL query parameters |
|
|
1085
|
+
| `reconnect` | `boolean` | `true` | Auto-reconnect on disconnect |
|
|
1086
|
+
| `maxReconnects` | `number` | `Infinity` | Max reconnection attempts |
|
|
1087
|
+
| `backoffMin` | `number` | `1000` | Initial reconnect delay (ms) |
|
|
1088
|
+
| `backoffMax` | `number` | `30000` | Maximum reconnect delay (ms) |
|
|
1089
|
+
| `callTimeoutMs` | `number` | `30000` | Default RPC call timeout (ms) |
|
|
1090
|
+
| `callConcurrency` | `number` | `1` | Max concurrent outbound calls |
|
|
1091
|
+
| `maxBadMessages` | `number` | `Infinity` | Close after N consecutive bad messages |
|
|
1092
|
+
| `respondWithDetailedErrors` | `boolean` | `false` | Include error details in responses |
|
|
1093
|
+
|
|
1094
|
+
### Properties
|
|
1095
|
+
|
|
1096
|
+
| Property | Type | Description |
|
|
1097
|
+
| ----------------- | --------------------- | ------------------------- |
|
|
1098
|
+
| `client.identity` | `string` | Charging station identity |
|
|
1099
|
+
| `client.protocol` | `string \| undefined` | Negotiated subprotocol |
|
|
1100
|
+
| `client.state` | `ConnectionState` | Current connection state |
|
|
1101
|
+
|
|
1102
|
+
### Static Constants
|
|
1103
|
+
|
|
1104
|
+
```typescript
|
|
1105
|
+
BrowserOCPPClient.CONNECTING; // 0
|
|
1106
|
+
BrowserOCPPClient.OPEN; // 1
|
|
1107
|
+
BrowserOCPPClient.CLOSING; // 2
|
|
1108
|
+
BrowserOCPPClient.CLOSED; // 3
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
### Methods
|
|
1112
|
+
|
|
1113
|
+
The API is identical to `OCPPClient` — all `call()`, `handle()`, `close()`, `sendRaw()`, `reconfigure()`, `removeHandler()`, and `removeAllHandlers()` methods work the same way with the same type signatures.
|
|
1114
|
+
|
|
1115
|
+
```typescript
|
|
1116
|
+
// Connect
|
|
1117
|
+
await client.connect();
|
|
1118
|
+
|
|
1119
|
+
// Version-aware typed call
|
|
1120
|
+
const result = await client.call("ocpp1.6", "BootNotification", {
|
|
1121
|
+
chargePointVendor: "VendorX",
|
|
1122
|
+
chargePointModel: "ModelY",
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
// Call with timeout and AbortSignal
|
|
1126
|
+
const controller = new AbortController();
|
|
1127
|
+
const res = await client.call(
|
|
1128
|
+
"Heartbeat",
|
|
1129
|
+
{},
|
|
1130
|
+
{
|
|
1131
|
+
timeoutMs: 5000,
|
|
1132
|
+
signal: controller.signal,
|
|
1133
|
+
},
|
|
1134
|
+
);
|
|
1135
|
+
|
|
1136
|
+
// Register handlers (version-specific, generic, wildcard)
|
|
1137
|
+
client.handle("ocpp1.6", "Reset", ({ params }) => {
|
|
1138
|
+
return { status: "Accepted" };
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
client.handle("StatusNotification", ({ params }) => {
|
|
1142
|
+
return {};
|
|
1143
|
+
});
|
|
1144
|
+
|
|
1145
|
+
client.handle((method, { params }) => {
|
|
1146
|
+
console.log(`Unhandled: ${method}`);
|
|
1147
|
+
return {};
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
// Close the connection
|
|
1151
|
+
await client.close();
|
|
1152
|
+
await client.close({ code: 1000, reason: "Normal" });
|
|
1153
|
+
await client.close({ awaitPending: true });
|
|
1154
|
+
await client.close({ force: true });
|
|
1155
|
+
|
|
1156
|
+
// Reconfigure at runtime
|
|
1157
|
+
client.reconfigure({ callTimeoutMs: 10000, reconnect: false });
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
### Events
|
|
1161
|
+
|
|
1162
|
+
```typescript
|
|
1163
|
+
client.on("open", (event) => {
|
|
1164
|
+
/* connected */
|
|
1165
|
+
});
|
|
1166
|
+
client.on("close", ({ code, reason }) => {
|
|
1167
|
+
/* disconnected */
|
|
1168
|
+
});
|
|
1169
|
+
client.on("error", (error) => {
|
|
1170
|
+
/* error occurred */
|
|
1171
|
+
});
|
|
1172
|
+
client.on("connecting", ({ url }) => {
|
|
1173
|
+
/* attempting connection */
|
|
1174
|
+
});
|
|
1175
|
+
client.on("reconnect", ({ attempt, delay }) => {
|
|
1176
|
+
/* reconnecting */
|
|
1177
|
+
});
|
|
1178
|
+
client.on("message", (message) => {
|
|
1179
|
+
/* any OCPP message */
|
|
1180
|
+
});
|
|
1181
|
+
client.on("call", (call) => {
|
|
1182
|
+
/* incoming call */
|
|
1183
|
+
});
|
|
1184
|
+
client.on("callResult", (result) => {
|
|
1185
|
+
/* call result received */
|
|
1186
|
+
});
|
|
1187
|
+
client.on("callError", (error) => {
|
|
1188
|
+
/* call error received */
|
|
1189
|
+
});
|
|
1190
|
+
client.on("badMessage", ({ message, error }) => {
|
|
1191
|
+
/* malformed message */
|
|
1192
|
+
});
|
|
1193
|
+
```
|
|
1194
|
+
|
|
1195
|
+
### Framework Integration
|
|
1196
|
+
|
|
1197
|
+
#### React
|
|
1198
|
+
|
|
1199
|
+
```typescript
|
|
1200
|
+
import { useEffect, useRef, useState } from "react";
|
|
1201
|
+
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
|
|
1202
|
+
|
|
1203
|
+
function useOCPP(identity: string, endpoint: string) {
|
|
1204
|
+
const clientRef = useRef<BrowserOCPPClient | null>(null);
|
|
1205
|
+
const [connected, setConnected] = useState(false);
|
|
1206
|
+
|
|
1207
|
+
useEffect(() => {
|
|
1208
|
+
const client = new BrowserOCPPClient({
|
|
1209
|
+
identity,
|
|
1210
|
+
endpoint,
|
|
1211
|
+
protocols: ["ocpp1.6"],
|
|
1212
|
+
});
|
|
1213
|
+
|
|
1214
|
+
client.on("open", () => setConnected(true));
|
|
1215
|
+
client.on("close", () => setConnected(false));
|
|
1216
|
+
|
|
1217
|
+
client.connect();
|
|
1218
|
+
clientRef.current = client;
|
|
1219
|
+
|
|
1220
|
+
return () => {
|
|
1221
|
+
client.close();
|
|
1222
|
+
};
|
|
1223
|
+
}, [identity, endpoint]);
|
|
1224
|
+
|
|
1225
|
+
return { client: clientRef.current, connected };
|
|
1226
|
+
}
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
#### Next.js (Client Component)
|
|
1230
|
+
|
|
1231
|
+
```typescript
|
|
1232
|
+
"use client";
|
|
1233
|
+
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
|
|
1234
|
+
|
|
1235
|
+
// ✅ Works in client components — no Node.js dependencies
|
|
1236
|
+
const client = new BrowserOCPPClient({
|
|
1237
|
+
identity: "CP001",
|
|
1238
|
+
endpoint: "wss://csms.example.com/ocpp",
|
|
1239
|
+
protocols: ["ocpp1.6"],
|
|
1240
|
+
});
|
|
1241
|
+
```
|
|
1242
|
+
|
|
1243
|
+
### Browser Exports
|
|
1244
|
+
|
|
1245
|
+
All exports from `ocpp-ws-io/browser`:
|
|
1246
|
+
|
|
1247
|
+
```typescript
|
|
1248
|
+
import {
|
|
1249
|
+
// Client
|
|
1250
|
+
BrowserOCPPClient,
|
|
1251
|
+
|
|
1252
|
+
// Error classes
|
|
1253
|
+
RPCGenericError,
|
|
1254
|
+
RPCNotImplementedError,
|
|
1255
|
+
RPCNotSupportedError,
|
|
1256
|
+
RPCInternalError,
|
|
1257
|
+
RPCProtocolError,
|
|
1258
|
+
RPCSecurityError,
|
|
1259
|
+
RPCFormatViolationError,
|
|
1260
|
+
RPCFormationViolationError,
|
|
1261
|
+
RPCPropertyConstraintViolationError,
|
|
1262
|
+
RPCOccurrenceConstraintViolationError,
|
|
1263
|
+
RPCTypeConstraintViolationError,
|
|
1264
|
+
RPCMessageTypeNotSupportedError,
|
|
1265
|
+
RPCFrameworkError,
|
|
1266
|
+
TimeoutError,
|
|
1267
|
+
|
|
1268
|
+
// Utilities
|
|
1269
|
+
createRPCError,
|
|
1270
|
+
getErrorPlainObject,
|
|
1271
|
+
|
|
1272
|
+
// Constants
|
|
1273
|
+
ConnectionState,
|
|
1274
|
+
MessageType,
|
|
1275
|
+
NOREPLY,
|
|
1276
|
+
} from "ocpp-ws-io/browser";
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
---
|
|
1280
|
+
|
|
934
1281
|
## Requirements
|
|
935
1282
|
|
|
936
|
-
- **Node.js** ≥ 18.0.0
|
|
1283
|
+
- **Node.js** ≥ 18.0.0 (for `OCPPClient` and `OCPPServer`)
|
|
1284
|
+
- **Browser**: Any modern browser with `WebSocket` support (for `BrowserOCPPClient`)
|
|
937
1285
|
- **TypeScript** ≥ 5.0 (optional, but recommended)
|
|
938
1286
|
|
|
939
1287
|
## Inspired By
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EventAdapterInterface } from '../types-
|
|
1
|
+
import { E as EventAdapterInterface } from '../types-CJQYxOD8.mjs';
|
|
2
2
|
import 'node:https';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
import 'node:tls';
|
|
@@ -6,19 +6,16 @@ import 'node:stream';
|
|
|
6
6
|
import 'node:events';
|
|
7
7
|
import 'ajv';
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Generic Redis-compatible client interface.
|
|
11
|
-
* This works with both `ioredis` and the official `redis` package,
|
|
12
|
-
* or any other client that implements these methods.
|
|
13
|
-
*/
|
|
14
9
|
interface RedisLikeClient {
|
|
15
|
-
publish(channel: string, message: string): Promise<number | unknown>;
|
|
16
|
-
subscribe(channel: string, ...args: unknown[]): Promise<unknown>;
|
|
17
|
-
unsubscribe(channel: string, ...args: unknown[]): Promise<unknown>;
|
|
18
|
-
on(event: "message", callback: (channel: string, message: string) => void): unknown;
|
|
19
|
-
disconnect?(): Promise<void
|
|
20
|
-
quit?(): Promise<unknown
|
|
10
|
+
publish(channel: string, message: string): Promise<number | unknown | void>;
|
|
11
|
+
subscribe(channel: string, ...args: unknown[]): Promise<unknown | void>;
|
|
12
|
+
unsubscribe(channel: string, ...args: unknown[]): Promise<unknown | void>;
|
|
13
|
+
on?(event: "message", callback: (channel: string, message: string) => void): unknown;
|
|
14
|
+
disconnect?(): Promise<void> | void;
|
|
15
|
+
quit?(): Promise<unknown> | void;
|
|
16
|
+
isOpen?: boolean;
|
|
21
17
|
}
|
|
18
|
+
|
|
22
19
|
interface RedisAdapterOptions {
|
|
23
20
|
/** Redis client for publishing */
|
|
24
21
|
pubClient: RedisLikeClient;
|
|
@@ -30,45 +27,18 @@ interface RedisAdapterOptions {
|
|
|
30
27
|
/**
|
|
31
28
|
* Redis adapter for cross-process event distribution.
|
|
32
29
|
*
|
|
33
|
-
*
|
|
34
|
-
* that implements the `RedisLikeClient` interface:
|
|
35
|
-
* - `ioredis`
|
|
36
|
-
* - `redis` (node-redis)
|
|
37
|
-
* - Any custom implementation
|
|
38
|
-
*
|
|
39
|
-
* The user provides their own pub/sub client instances.
|
|
40
|
-
* No Redis dependency is forced on the user.
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```typescript
|
|
44
|
-
* // With ioredis
|
|
45
|
-
* import Redis from 'ioredis';
|
|
46
|
-
* const adapter = new RedisAdapter({
|
|
47
|
-
* pubClient: new Redis(),
|
|
48
|
-
* subClient: new Redis(),
|
|
49
|
-
* });
|
|
50
|
-
*
|
|
51
|
-
* // With node-redis
|
|
52
|
-
* import { createClient } from 'redis';
|
|
53
|
-
* const pub = createClient();
|
|
54
|
-
* const sub = pub.duplicate();
|
|
55
|
-
* await pub.connect();
|
|
56
|
-
* await sub.connect();
|
|
57
|
-
* const adapter = new RedisAdapter({ pubClient: pub, subClient: sub });
|
|
58
|
-
* ```
|
|
30
|
+
* Supports `ioredis` and `node-redis` (v4+).
|
|
59
31
|
*/
|
|
60
32
|
declare class RedisAdapter implements EventAdapterInterface {
|
|
61
|
-
private
|
|
62
|
-
private _sub;
|
|
33
|
+
private _driver;
|
|
63
34
|
private _prefix;
|
|
64
35
|
private _handlers;
|
|
65
|
-
private _listening;
|
|
66
36
|
constructor(options: RedisAdapterOptions);
|
|
67
|
-
private _setupSubscriber;
|
|
68
37
|
publish(channel: string, data: unknown): Promise<void>;
|
|
69
38
|
subscribe(channel: string, handler: (data: unknown) => void): Promise<void>;
|
|
70
39
|
unsubscribe(channel: string): Promise<void>;
|
|
71
40
|
disconnect(): Promise<void>;
|
|
41
|
+
private _handleMessage;
|
|
72
42
|
}
|
|
73
43
|
|
|
74
|
-
export { RedisAdapter, type RedisAdapterOptions
|
|
44
|
+
export { RedisAdapter, type RedisAdapterOptions };
|
package/dist/adapters/redis.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EventAdapterInterface } from '../types-
|
|
1
|
+
import { E as EventAdapterInterface } from '../types-CJQYxOD8.js';
|
|
2
2
|
import 'node:https';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
import 'node:tls';
|
|
@@ -6,19 +6,16 @@ import 'node:stream';
|
|
|
6
6
|
import 'node:events';
|
|
7
7
|
import 'ajv';
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Generic Redis-compatible client interface.
|
|
11
|
-
* This works with both `ioredis` and the official `redis` package,
|
|
12
|
-
* or any other client that implements these methods.
|
|
13
|
-
*/
|
|
14
9
|
interface RedisLikeClient {
|
|
15
|
-
publish(channel: string, message: string): Promise<number | unknown>;
|
|
16
|
-
subscribe(channel: string, ...args: unknown[]): Promise<unknown>;
|
|
17
|
-
unsubscribe(channel: string, ...args: unknown[]): Promise<unknown>;
|
|
18
|
-
on(event: "message", callback: (channel: string, message: string) => void): unknown;
|
|
19
|
-
disconnect?(): Promise<void
|
|
20
|
-
quit?(): Promise<unknown
|
|
10
|
+
publish(channel: string, message: string): Promise<number | unknown | void>;
|
|
11
|
+
subscribe(channel: string, ...args: unknown[]): Promise<unknown | void>;
|
|
12
|
+
unsubscribe(channel: string, ...args: unknown[]): Promise<unknown | void>;
|
|
13
|
+
on?(event: "message", callback: (channel: string, message: string) => void): unknown;
|
|
14
|
+
disconnect?(): Promise<void> | void;
|
|
15
|
+
quit?(): Promise<unknown> | void;
|
|
16
|
+
isOpen?: boolean;
|
|
21
17
|
}
|
|
18
|
+
|
|
22
19
|
interface RedisAdapterOptions {
|
|
23
20
|
/** Redis client for publishing */
|
|
24
21
|
pubClient: RedisLikeClient;
|
|
@@ -30,45 +27,18 @@ interface RedisAdapterOptions {
|
|
|
30
27
|
/**
|
|
31
28
|
* Redis adapter for cross-process event distribution.
|
|
32
29
|
*
|
|
33
|
-
*
|
|
34
|
-
* that implements the `RedisLikeClient` interface:
|
|
35
|
-
* - `ioredis`
|
|
36
|
-
* - `redis` (node-redis)
|
|
37
|
-
* - Any custom implementation
|
|
38
|
-
*
|
|
39
|
-
* The user provides their own pub/sub client instances.
|
|
40
|
-
* No Redis dependency is forced on the user.
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```typescript
|
|
44
|
-
* // With ioredis
|
|
45
|
-
* import Redis from 'ioredis';
|
|
46
|
-
* const adapter = new RedisAdapter({
|
|
47
|
-
* pubClient: new Redis(),
|
|
48
|
-
* subClient: new Redis(),
|
|
49
|
-
* });
|
|
50
|
-
*
|
|
51
|
-
* // With node-redis
|
|
52
|
-
* import { createClient } from 'redis';
|
|
53
|
-
* const pub = createClient();
|
|
54
|
-
* const sub = pub.duplicate();
|
|
55
|
-
* await pub.connect();
|
|
56
|
-
* await sub.connect();
|
|
57
|
-
* const adapter = new RedisAdapter({ pubClient: pub, subClient: sub });
|
|
58
|
-
* ```
|
|
30
|
+
* Supports `ioredis` and `node-redis` (v4+).
|
|
59
31
|
*/
|
|
60
32
|
declare class RedisAdapter implements EventAdapterInterface {
|
|
61
|
-
private
|
|
62
|
-
private _sub;
|
|
33
|
+
private _driver;
|
|
63
34
|
private _prefix;
|
|
64
35
|
private _handlers;
|
|
65
|
-
private _listening;
|
|
66
36
|
constructor(options: RedisAdapterOptions);
|
|
67
|
-
private _setupSubscriber;
|
|
68
37
|
publish(channel: string, data: unknown): Promise<void>;
|
|
69
38
|
subscribe(channel: string, handler: (data: unknown) => void): Promise<void>;
|
|
70
39
|
unsubscribe(channel: string): Promise<void>;
|
|
71
40
|
disconnect(): Promise<void>;
|
|
41
|
+
private _handleMessage;
|
|
72
42
|
}
|
|
73
43
|
|
|
74
|
-
export { RedisAdapter, type RedisAdapterOptions
|
|
44
|
+
export { RedisAdapter, type RedisAdapterOptions };
|