@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.
Files changed (2) hide show
  1. package/README.md +124 -10
  2. 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
- onPairingToken: (info) => {
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 `onPairingToken` with a QR/deeplink URL. After the user approves in the Nority app, the bridge receives a durable credential and connects automatically.
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; // Nority backend WebSocket URL
147
- dataDir: string; // Directory for durable state (identity, keys)
148
- agent: AgentAdapter; // Your adapter implementation
149
- onPairingToken?: (info) => void; // Called when pairing token is ready
150
- logger?: BridgeLogger; // Structured logging
151
- webSocketFactory?: WebSocketFactory; // Custom WebSocket creation
152
- heartbeatIntervalMs?: number; // Default: 15000
153
- idleTimeoutMs?: number; // Default: 45000
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nority/bridge-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Public SDK for building Nority bridge implementations",
6
6
  "main": "./dist/index.js",