@nority/bridge-sdk 0.2.0 → 0.2.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.
- package/README.md +124 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,18 +68,92 @@ const bridge = new NorityBridge({
|
|
|
68
68
|
backendUrl: "wss://api.nority.ai/v1/bridge",
|
|
69
69
|
dataDir: "./bridge-data",
|
|
70
70
|
agent: new MyAdapter(),
|
|
71
|
-
|
|
71
|
+
onPairingInfo: (info) => {
|
|
72
72
|
console.log(`Pair: ${info.deeplinkUrl} (expires ${info.expiresAt})`);
|
|
73
73
|
},
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
await bridge.start();
|
|
77
|
+
// Bridge is now connected and handling conversations
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
On first run, the SDK generates an Ed25519 identity, enters the pairing flow, and calls `
|
|
80
|
+
On first run, the SDK generates an Ed25519 identity, enters the pairing flow, and calls `onPairingInfo` with a QR/deeplink URL. `start()` blocks until the user approves in the Nority app and the bridge connects.
|
|
80
81
|
|
|
81
82
|
On subsequent runs, the SDK loads the stored credential, mints a fresh JWT via challenge-response, reconnects, replays missed events, and resumes normal operation.
|
|
82
83
|
|
|
84
|
+
## Layered API
|
|
85
|
+
|
|
86
|
+
The SDK exposes three levels of abstraction. Most developers only need `NorityBridge`.
|
|
87
|
+
|
|
88
|
+
### `NorityBridge` — managed (recommended)
|
|
89
|
+
|
|
90
|
+
Handles everything: pairing, credential persistence, auth, transport, conversations. `start()` blocks until fully connected regardless of whether pairing was needed.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { NorityBridge } from "@nority/bridge-sdk";
|
|
94
|
+
|
|
95
|
+
const bridge = new NorityBridge({
|
|
96
|
+
backendUrl: "wss://api.nority.ai/v1/bridge",
|
|
97
|
+
dataDir: "./bridge-data",
|
|
98
|
+
agent: myAdapter,
|
|
99
|
+
onPairingInfo: (info) => console.log(`Scan: ${info.deeplinkUrl}`),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await bridge.start(); // blocks until connected
|
|
103
|
+
await bridge.stop(); // graceful shutdown
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `PairingClient` — standalone pairing
|
|
107
|
+
|
|
108
|
+
Use this when you want to control the pairing ceremony yourself — embed the QR in your own UI, store the credential in your own database, or skip pairing entirely with pre-provisioned credentials.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { PairingClient } from "@nority/bridge-sdk";
|
|
112
|
+
|
|
113
|
+
const pairing = new PairingClient({
|
|
114
|
+
backendUrl: "wss://api.nority.ai/v1/bridge",
|
|
115
|
+
dataDir: "./bridge-data",
|
|
116
|
+
onPairingInfo: (info) => renderQRCode(info.deeplinkUrl),
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const result = await pairing.pair(); // blocks until user approves
|
|
120
|
+
// result.credential — durable bridge credential
|
|
121
|
+
// result.identity — Ed25519 keypair
|
|
122
|
+
// result.initialToken — first JWT (pass as seedJwt to BridgeConnection)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Methods:**
|
|
126
|
+
- `pair()` — performs the pairing ceremony. Resolves when the user approves. Single-flight (throws if called while already pairing).
|
|
127
|
+
- `cancel()` — cancels in-progress pairing. Rejects the pending `pair()` promise. Idempotent.
|
|
128
|
+
- `regenerateToken()` — closes the WebSocket, opens a new one, sends a fresh `pair_request`. Returns updated `PairingInfo`.
|
|
129
|
+
- `getPairingInfo()` — returns current pairing info or `null`.
|
|
130
|
+
|
|
131
|
+
### `BridgeConnection` — standalone connection
|
|
132
|
+
|
|
133
|
+
Use this when you already have a credential (pre-provisioned from a dashboard, stored in your own secret manager, or obtained via `PairingClient`).
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { BridgeConnection } from "@nority/bridge-sdk";
|
|
137
|
+
|
|
138
|
+
const connection = new BridgeConnection({
|
|
139
|
+
backendUrl: "wss://api.nority.ai/v1/bridge",
|
|
140
|
+
dataDir: "./bridge-data",
|
|
141
|
+
credential: process.env.BRIDGE_CREDENTIAL,
|
|
142
|
+
privateKeyPem: fs.readFileSync("./bridge-key.pem", "utf-8"),
|
|
143
|
+
agent: myAdapter,
|
|
144
|
+
seedJwt: cachedToken, // optional — skip first challenge-response
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await connection.connect(); // blocks until connected
|
|
148
|
+
await connection.disconnect(); // graceful shutdown
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Methods:**
|
|
152
|
+
- `connect()` — authenticates via challenge-response, opens authenticated WebSocket, sends replay request. Resolves when connected.
|
|
153
|
+
- `disconnect()` — closes connection, stops reconnection, aborts active agent invocations. Idempotent.
|
|
154
|
+
- `getState()` — returns current state (`idle | connecting | connected | reconnecting | blocked | failed | stopped`).
|
|
155
|
+
- `createProactiveTurnFrame(conversationId, request)` — creates an `assistant_turn_start` frame for bridge-initiated turns.
|
|
156
|
+
|
|
83
157
|
## Key concepts
|
|
84
158
|
|
|
85
159
|
| Concept | Description |
|
|
@@ -141,16 +215,56 @@ idle → pairing → connecting → connected
|
|
|
141
215
|
|
|
142
216
|
## Configuration
|
|
143
217
|
|
|
218
|
+
### `BridgeConfig` (for `NorityBridge`)
|
|
219
|
+
|
|
144
220
|
```ts
|
|
145
221
|
interface BridgeConfig {
|
|
146
|
-
backendUrl: string;
|
|
147
|
-
dataDir: string;
|
|
148
|
-
agent: AgentAdapter;
|
|
149
|
-
|
|
150
|
-
logger?: BridgeLogger;
|
|
151
|
-
webSocketFactory?: WebSocketFactory;
|
|
152
|
-
|
|
153
|
-
|
|
222
|
+
backendUrl: string; // Nority backend WebSocket URL
|
|
223
|
+
dataDir: string; // Directory for durable state (identity, keys)
|
|
224
|
+
agent: AgentAdapter; // Your adapter implementation
|
|
225
|
+
onPairingInfo?: (pairing: PairingInfo) => void; // Called when pairing token is ready
|
|
226
|
+
logger?: BridgeLogger; // Structured logging
|
|
227
|
+
webSocketFactory?: WebSocketFactory; // Custom WebSocket creation
|
|
228
|
+
fetchImplementation?: typeof fetch; // Custom fetch (for auth challenge-response)
|
|
229
|
+
clock?: () => Date; // Custom clock (for testing)
|
|
230
|
+
pairingTokenFactory?: () => string; // Custom pairing token generator
|
|
231
|
+
backoffRandom?: () => number; // Custom RNG for reconnect backoff jitter
|
|
232
|
+
heartbeatIntervalMs?: number; // Default: 15000
|
|
233
|
+
idleTimeoutMs?: number; // Default: 45000
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `PairingClientConfig`
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
interface PairingClientConfig {
|
|
241
|
+
backendUrl: string;
|
|
242
|
+
dataDir: string;
|
|
243
|
+
onPairingInfo?: (info: PairingInfo) => void;
|
|
244
|
+
logger?: BridgeLogger;
|
|
245
|
+
webSocketFactory?: WebSocketFactory;
|
|
246
|
+
clock?: () => Date;
|
|
247
|
+
pairingTokenFactory?: () => string;
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### `BridgeConnectionConfig`
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
interface BridgeConnectionConfig {
|
|
255
|
+
backendUrl: string;
|
|
256
|
+
dataDir: string;
|
|
257
|
+
credential: string;
|
|
258
|
+
privateKeyPem: string;
|
|
259
|
+
agent: AgentAdapter;
|
|
260
|
+
logger?: BridgeLogger;
|
|
261
|
+
seedJwt?: AccessTokenRecord;
|
|
262
|
+
fetchImplementation?: typeof fetch;
|
|
263
|
+
webSocketFactory?: WebSocketFactory;
|
|
264
|
+
clock?: () => Date;
|
|
265
|
+
backoffRandom?: () => number;
|
|
266
|
+
heartbeatIntervalMs?: number;
|
|
267
|
+
idleTimeoutMs?: number;
|
|
154
268
|
}
|
|
155
269
|
```
|
|
156
270
|
|