rocketride 1.0.0 → 1.0.3

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 (96) hide show
  1. package/README.md +466 -476
  2. package/dist/cjs/client.js +44 -8
  3. package/dist/cjs/client.js.map +1 -1
  4. package/dist/cjs/constants.js +25 -4
  5. package/dist/cjs/constants.js.map +1 -1
  6. package/dist/cjs/core/DAPBase.js +1 -1
  7. package/dist/cjs/core/DAPClient.js +1 -1
  8. package/dist/cjs/core/TransportBase.js +1 -1
  9. package/dist/cjs/core/TransportWebSocket.js +1 -1
  10. package/dist/cjs/exceptions/index.js +1 -1
  11. package/dist/cjs/index.js +1 -1
  12. package/dist/cjs/schema/Doc.js +1 -1
  13. package/dist/cjs/schema/DocFilter.js +1 -1
  14. package/dist/cjs/schema/DocGroup.js +1 -1
  15. package/dist/cjs/schema/DocMetadata.js +1 -1
  16. package/dist/cjs/schema/Question.js +25 -16
  17. package/dist/cjs/schema/Question.js.map +1 -1
  18. package/dist/cjs/schema/index.js +1 -1
  19. package/dist/cjs/types/client.js +1 -1
  20. package/dist/cjs/types/data.js +1 -1
  21. package/dist/cjs/types/events.js +1 -1
  22. package/dist/cjs/types/index.js +1 -1
  23. package/dist/cjs/types/pipeline.js +1 -1
  24. package/dist/cjs/types/task.js +1 -1
  25. package/dist/cli/cli/rocketride.js +8 -13
  26. package/dist/cli/cli/rocketride.js.map +1 -1
  27. package/dist/cli/client/client.js +44 -8
  28. package/dist/cli/client/client.js.map +1 -1
  29. package/dist/cli/client/constants.js +25 -4
  30. package/dist/cli/client/constants.js.map +1 -1
  31. package/dist/cli/client/core/DAPBase.js +1 -1
  32. package/dist/cli/client/core/DAPClient.js +1 -1
  33. package/dist/cli/client/core/TransportBase.js +1 -1
  34. package/dist/cli/client/core/TransportWebSocket.js +1 -1
  35. package/dist/cli/client/exceptions/index.js +1 -1
  36. package/dist/cli/client/index.js +1 -1
  37. package/dist/cli/client/schema/Doc.js +1 -1
  38. package/dist/cli/client/schema/DocFilter.js +1 -1
  39. package/dist/cli/client/schema/DocGroup.js +1 -1
  40. package/dist/cli/client/schema/DocMetadata.js +1 -1
  41. package/dist/cli/client/schema/Question.js +25 -16
  42. package/dist/cli/client/schema/Question.js.map +1 -1
  43. package/dist/cli/client/schema/index.js +1 -1
  44. package/dist/cli/client/types/client.js +1 -1
  45. package/dist/cli/client/types/data.js +1 -1
  46. package/dist/cli/client/types/events.js +1 -1
  47. package/dist/cli/client/types/index.js +1 -1
  48. package/dist/cli/client/types/pipeline.js +1 -1
  49. package/dist/cli/client/types/task.js +1 -1
  50. package/dist/esm/client.js +45 -9
  51. package/dist/esm/client.js.map +1 -1
  52. package/dist/esm/constants.js +24 -3
  53. package/dist/esm/constants.js.map +1 -1
  54. package/dist/esm/core/DAPBase.js +1 -1
  55. package/dist/esm/core/DAPClient.js +1 -1
  56. package/dist/esm/core/TransportBase.js +1 -1
  57. package/dist/esm/core/TransportWebSocket.js +1 -1
  58. package/dist/esm/exceptions/index.js +1 -1
  59. package/dist/esm/index.js +1 -1
  60. package/dist/esm/schema/Doc.js +1 -1
  61. package/dist/esm/schema/DocFilter.js +1 -1
  62. package/dist/esm/schema/DocGroup.js +1 -1
  63. package/dist/esm/schema/DocMetadata.js +1 -1
  64. package/dist/esm/schema/Question.js +25 -16
  65. package/dist/esm/schema/Question.js.map +1 -1
  66. package/dist/esm/schema/index.js +1 -1
  67. package/dist/esm/types/client.js +1 -1
  68. package/dist/esm/types/data.js +1 -1
  69. package/dist/esm/types/events.js +1 -1
  70. package/dist/esm/types/index.js +1 -1
  71. package/dist/esm/types/pipeline.js +1 -1
  72. package/dist/esm/types/task.js +1 -1
  73. package/dist/types/client.d.ts +19 -2
  74. package/dist/types/client.d.ts.map +1 -1
  75. package/dist/types/constants.d.ts +24 -3
  76. package/dist/types/constants.d.ts.map +1 -1
  77. package/dist/types/core/DAPBase.d.ts +1 -1
  78. package/dist/types/core/DAPClient.d.ts +1 -1
  79. package/dist/types/core/TransportBase.d.ts +1 -1
  80. package/dist/types/core/TransportWebSocket.d.ts +1 -1
  81. package/dist/types/exceptions/index.d.ts +1 -1
  82. package/dist/types/index.d.ts +1 -1
  83. package/dist/types/schema/Doc.d.ts +1 -1
  84. package/dist/types/schema/DocFilter.d.ts +1 -1
  85. package/dist/types/schema/DocGroup.d.ts +1 -1
  86. package/dist/types/schema/DocMetadata.d.ts +1 -1
  87. package/dist/types/schema/Question.d.ts +1 -1
  88. package/dist/types/schema/Question.d.ts.map +1 -1
  89. package/dist/types/schema/index.d.ts +1 -1
  90. package/dist/types/types/client.d.ts +1 -1
  91. package/dist/types/types/data.d.ts +1 -1
  92. package/dist/types/types/events.d.ts +1 -1
  93. package/dist/types/types/index.d.ts +1 -1
  94. package/dist/types/types/pipeline.d.ts +1 -1
  95. package/dist/types/types/task.d.ts +1 -1
  96. package/package.json +61 -61
package/README.md CHANGED
@@ -1,476 +1,466 @@
1
- # rocketride
2
-
3
- RocketRide TypeScript Client — TypeScript/JavaScript SDK for the RocketRide Engine. Complete API reference below.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install rocketride
9
- # or
10
- pnpm add rocketride
11
- ```
12
-
13
- ## Quick Start
14
-
15
- ```typescript
16
- import { RocketRideClient } from 'rocketride';
17
-
18
- const client = new RocketRideClient({
19
- auth: process.env.ROCKETRIDE_APIKEY!,
20
- uri: 'https://cloud.rocketride.ai',
21
- });
22
- await client.connect();
23
- const { token } = await client.use({ filepath: './pipeline.json' });
24
- const result = await client.send(token, 'Hello, pipeline!', { name: 'input.txt' }, 'text/plain');
25
- console.log(result);
26
- await client.terminate(token);
27
- await client.disconnect();
28
- ```
29
-
30
- ## Features
31
-
32
- - **Pipeline execution** — Start with `use()`, send data via `send()`, `sendFiles()`, or `pipe()`
33
- - **Chat** — Conversational AI via `chat()` and `Question`
34
- - **Event streaming** — Real-time events via `onEvent` and `setEvents()`
35
- - **File upload** — `sendFiles()` with progress; streaming with `pipe()`
36
- - **Connection lifecycle** — Optional persist mode, reconnection, and callbacks (`onConnected`, `onDisconnected`, `onConnectError`)
37
- - **Full TypeScript support** — Complete type definitions
38
-
39
- ---
40
-
41
- ## RocketRideClientConfig
42
-
43
- Configuration object passed to `new RocketRideClient(config)`.
44
-
45
- **Why it matters:** The config controls not only where you connect and how you authenticate, but also how the client behaves when the connection drops or when the server is slow to start. Getting `persist`, `maxRetryTime`, and the callbacks right avoids confusing "connection lost" vs "never connected" UX.
46
-
47
- | Property | Type | Required | Description |
48
- |----------|------|----------|-------------|
49
- | `auth` | `string` | No | API key. Optional: omit and set via `env.ROCKETRIDE_APIKEY` or `.env` (Node only), or set later with `setConnectionParams({ auth })` before calling `connect()`. |
50
- | `uri` | `string` | No | Server URI (e.g. `https://cloud.rocketride.ai` or `ws://localhost:8080`). Optional: omit and use `env.ROCKETRIDE_URI` or built-in default, or set later with `setConnectionParams({ uri })` before calling `connect()`. |
51
- | `env` | `Record<string, string>` | No | Override env; if omitted, `.env` is loaded in Node (only). Used for `${ROCKETRIDE_*}` substitution in pipeline config and for `ROCKETRIDE_APIKEY`/`ROCKETRIDE_URI` when not passed as `auth`/`uri`. |
52
- | `persist` | `boolean` | No | Enable automatic reconnection with exponential backoff. Default: `false`. **Use `true`** for long-lived UIs or when the server may restart; the client will retry (250ms → 2500ms) and call `onConnectError` on each failure until `maxRetryTime` or success. |
53
- | `maxRetryTime` | `number` | No | Max time in ms to keep retrying connection. Default: no limit. **Use** (e.g. 300000 for 5 min) so you can show "gave up" after a bounded time instead of retrying forever. |
54
- | `requestTimeout` | `number` | No | Default timeout in ms for each request; overridable per `request()` call. Prevents a single slow DAP call from hanging indefinitely. |
55
- | `onConnected` | `(info?: string) => Promise<void>` | No | Called when connection is established. **Use** to refresh UI, refetch services, or clear "connecting" state. |
56
- | `onDisconnected` | `(reason?: string, hasError?: boolean) => Promise<void>` | No | Called when connection is lost **only if** `onConnected` was already called. So "failed to connect in the first place" does *not* fire this—use `onConnectError` for that. **Do not** call `client.disconnect()` here if you want the client to auto-reconnect in persist mode. |
57
- | `onConnectError` | `(message: string) => void \| Promise<void>` | No | Called on each failed connection attempt (e.g. while retrying in persist mode). **Use** to show "Connection failed: …" or "Still connecting…"; on auth failure the client stops retrying, so you can prompt the user to fix credentials and call `connect()` again. |
58
- | `onEvent` | `(event: DAPMessage) => Promise<void>` | No | Called for each server event (e.g. upload progress, task status). **Use** to drive progress bars or status text; event type is `event.event`, payload in `event.body`. |
59
- | `onProtocolMessage` | `(message: string) => void` | No | Optional; for logging raw DAP messages. Helpful when debugging protocol issues. |
60
- | `onDebugMessage` | `(message: string) => void` | No | Optional; for debug output. |
61
- | `module` | `string` | No | Client name for logging. Default: `CLIENT-0`, `CLIENT-1`, … |
62
-
63
- **Example — long-lived app with persist and status:**
64
-
65
- ```ts
66
- const client = new RocketRideClient({
67
- auth: process.env.ROCKETRIDE_APIKEY!,
68
- uri: 'wss://cloud.rocketride.ai',
69
- persist: true,
70
- maxRetryTime: 300000,
71
- requestTimeout: 30000,
72
- onConnected: async () => setStatus('connected'),
73
- onDisconnected: async () => setStatus('disconnected'),
74
- onConnectError: (msg) => setStatus('error', msg),
75
- onEvent: async (e) => handleServerEvent(e),
76
- });
77
- ```
78
-
79
- ---
80
-
81
- ## RocketRideClient
82
-
83
- ### Constructor
84
-
85
- ```ts
86
- constructor(config: RocketRideClientConfig = {})
87
- ```
88
-
89
- Creates a client instance; it does **not** connect until you call `connect()`. You can set up callbacks and then open the connection when ready. `auth` and `uri` are optional at construction and can be set later with `setConnectionParams()` before `connect()`.
90
-
91
- **Example:**
92
-
93
- ```ts
94
- const client = new RocketRideClient({ auth: 'my-key', uri: 'https://cloud.rocketride.ai' });
95
- await client.connect();
96
- ```
97
-
98
- ---
99
-
100
- ### Connection
101
-
102
- | Method | Signature | Returns | Description |
103
- |--------|-----------|---------|-------------|
104
- | `connect` | `connect(timeout?: number): Promise<void>` | — | Opens the WebSocket and performs DAP auth. Optional `timeout` (ms) bounds the connect + auth handshake (non-persist only; in persist mode timeout is not applied). In **persist** mode, if this fails the client calls `onConnectError` and schedules retries (exponential backoff); on **auth** failure it does *not* retry so the app can fix credentials and call `connect()` again. |
105
- | `disconnect` | `disconnect(): Promise<void>` | — | Closes the connection and cancels any pending reconnection. Call when the user explicitly disconnects or the app is shutting down. |
106
- | `isConnected` | `isConnected(): boolean` | `boolean` | Whether the client is currently connected. Use before calling `use()` or `send()` to avoid confusing errors. |
107
- | `setConnectionParams` | `setConnectionParams(options: { uri?: string; auth?: string }): Promise<void>` | — | Updates server URI and/or auth at runtime. If currently connected, disconnects and reconnects with the new params (in persist mode, reconnection is scheduled; otherwise reconnects once). Use when the user changes server or credentials without creating a new client. |
108
-
109
- **How to use:** For one-off scripts, call `connect()` once, do your work, then `disconnect()`. For UIs, use `persist: true` and rely on the client to reconnect; only call `disconnect()` when the user logs out or you are done with the client. The client supports `await using` (Symbol.asyncDispose) for automatic disconnect when exiting scope.
110
-
111
- ---
112
-
113
- ### Low-level DAP
114
-
115
- | Method | Signature | Returns | Description |
116
- |--------|-----------|---------|-------------|
117
- | `buildRequest` | `buildRequest(command: string, options?: { token?: string; arguments?: Record<string, unknown>; data?: Uint8Array \| string }): DAPMessage` | `DAPMessage` | Builds a DAP request message with the next sequence number. Use when you need a custom command not wrapped by `use()`, `send()`, etc. |
118
- | `request` | `request(request: DAPMessage, timeout?: number): Promise<DAPMessage>` | `Promise<DAPMessage>` | Sends the request and returns the response. Pass `timeout` (ms) to override the config default for this call. Check `didFail(response)` or `response.success` before using `response.body`. |
119
- | `dapRequest` | `dapRequest(command: string, args?: Record<string, unknown>, token?: string, timeout?: number): Promise<DAPMessage>` | `Promise<DAPMessage>` | Shorthand: builds a request and sends it in one call. Equivalent to `buildRequest()` + `request()`. |
120
- | `didFail` | `didFail(response: DAPMessage): boolean` | `boolean` | Returns `true` when the server indicated failure (`success === false`). Use after `request()` to decide whether to use `body` or surface `message` as an error. |
121
-
122
- **Example custom DAP command:**
123
-
124
- ```ts
125
- const req = client.buildRequest('rrext_monitor', { token, arguments: { types: ['apaevt_status_upload'] } });
126
- const res = await client.request(req, 5000);
127
- if (client.didFail(res)) throw new Error(res.message);
128
- ```
129
-
130
- ---
131
-
132
- ### Pipeline execution
133
-
134
- | Method | Signature | Returns | Description |
135
- |--------|-----------|---------|-------------|
136
- | `use` | `use(options?: { token?: string; filepath?: string; pipeline?: PipelineConfig; source?: string; threads?: number; useExisting?: boolean; args?: string[]; ttl?: number }): Promise<Record<string, any> & { token: string }>` | `Promise<{ token: string, ... }>` | Starts a pipeline. You must pass either `pipeline` (object) or `filepath` (path to a JSON file; Node only). The client substitutes `${ROCKETRIDE_*}` in the config from its `env` (or `.env`). Returns at least `token`; use that token for `send()`, `sendFiles()`, `pipe()`, `chat()`, `getTaskStatus()`, and `terminate()`. |
137
- | `validate` | `validate(options: { pipeline: PipelineConfig \| Record<string, unknown>; source?: string }): Promise<Record<string, unknown>>` | `Promise<Record<string, unknown>>` | Validates a pipeline configuration without starting it. Returns validation results (e.g. errors, warnings). Use to check pipeline correctness before `use()`. |
138
- | `terminate` | `terminate(token: string): Promise<void>` | — | Stops the pipeline for that token and frees server resources. Call when the user cancels or when you are done sending data. |
139
- | `getTaskStatus` | `getTaskStatus(token: string): Promise<TASK_STATUS>` | `Promise<TASK_STATUS>` | Returns current task status: e.g. `completedCount`, `totalCount`, `completed`, `state`, `exitCode`. Use to poll until `completed` is true or to show progress. |
140
-
141
- **Why `use()` returns a token:** The server runs each pipeline as a separate task. The token identifies that task so all subsequent operations (sending data, chat, status, terminate) target the right pipeline.
142
-
143
- **Example start from file and poll until done:**
144
-
145
- ```ts
146
- const { token } = await client.use({ filepath: './pipeline.json', ttl: 3600 });
147
- await client.setEvents(token, ['apaevt_status_processing']);
148
- // ... send data ...
149
- while (true) {
150
- const status = await client.getTaskStatus(token);
151
- if (status.completed) break;
152
- await new Promise(r => setTimeout(r, 2000));
153
- }
154
- await client.terminate(token);
155
- ```
156
-
157
- ---
158
-
159
- ### Data
160
-
161
- | Method | Signature | Returns | Description |
162
- |--------|-----------|---------|-------------|
163
- | `pipe` | `pipe(token: string, objinfo?: Record<string, any>, mimeType?: string, provider?: string): Promise<DataPipe>` | `Promise<DataPipe>` | Creates a **streaming** data pipe. Use when you have large payloads or chunks arriving over time; you call `open()`, then one or more `write()`, then `close()`. Default MIME: `application/octet-stream`. |
164
- | `send` | `send(token: string, data: string \| Uint8Array, objinfo?: Record<string, any>, mimetype?: string): Promise<PIPELINE_RESULT \| undefined>` | `Promise<PIPELINE_RESULT \| undefined>` | Sends data in **one shot** (internally: open pipe, write once, close). Use for small payloads when you have the full buffer in memory. |
165
- | `sendFiles` | `sendFiles(files: Array<{ file: File; objinfo?: Record<string, any>; mimetype?: string }>, token: string): Promise<UPLOAD_RESULT[]>` | `Promise<UPLOAD_RESULT[]>` | Uploads multiple browser `File` objects. Results are in the same order as `files`. Progress is reported via `onEvent` as `apaevt_status_upload` events (e.g. `body.filepath`, `body.bytes_sent`, `body.file_size`). |
166
-
167
- **When to use `pipe` vs `send`:** Use `send()` when you have a single blob (e.g. a string or one `Uint8Array`) and don't need to stream. Use `pipe()` when you are reading a large file in chunks, or when data arrives incrementally (e.g. from a stream or multiple buffers).
168
-
169
- **Example — send a string:**
170
-
171
- ```ts
172
- const result = await client.send(token, 'Hello, pipeline!', { name: 'greeting.txt' }, 'text/plain');
173
- ```
174
-
175
- **Example stream chunks with a pipe:**
176
-
177
- ```ts
178
- const pipe = await client.pipe(token, { name: 'data.json' }, 'application/json');
179
- await pipe.open();
180
- for (const chunk of chunks) await pipe.write(new TextEncoder().encode(chunk));
181
- const result = await pipe.close();
182
- ```
183
-
184
- ---
185
-
186
- ### Events
187
-
188
- | Method | Signature | Returns | Description |
189
- |--------|-----------|---------|-------------|
190
- | `setEvents` | `setEvents(token: string, eventTypes: string[]): Promise<void>` | — | Subscribes this task to the given event types (e.g. `apaevt_status_upload`, `apaevt_status_processing`). After this, those events are delivered to your `onEvent` callback. Call after `use()` and before or while sending data. |
191
-
192
- ---
193
-
194
- ### Services, validation, and ping
195
-
196
- | Method | Signature | Returns | Description |
197
- |--------|-----------|---------|-------------|
198
- | `getServices` | `getServices(): Promise<Record<string, any>>` | `Promise<Record<string, any>>` | Returns all service/connector definitions from the server (schemas, UI schemas). Use to discover what pipelines or features the server supports. |
199
- | `getService` | `getService(service: string): Promise<Record<string, any> \| undefined>` | `Promise<Record<string, any> \| undefined>` | Returns the definition for one service by name. Throws if the request fails. |
200
- | `ping` | `ping(token?: string): Promise<void>` | | Lightweight liveness check. Throws if the server responds with an error. Optional `token` for task-scoped ping. |
201
-
202
- ---
203
-
204
- ### Chat
205
-
206
- | Method | Signature | Returns | Description |
207
- |--------|-----------|---------|-------------|
208
- | `chat` | `chat(options: { token: string; question: Question }): Promise<PIPELINE_RESULT>` | `Promise<PIPELINE_RESULT>` | Sends the `Question` to the AI for the given pipeline token and returns the pipeline result. The answer content is in the result body (e.g. fields described by `result_types`); you can use `Answer.parseJson()` on raw text if the AI returned JSON. |
209
-
210
- **How it works:** The client opens a pipe with MIME type `application/rocketride-question`, writes the serialized `Question`, closes the pipe, and returns the server's result. The pipeline must support the chat provider for that token.
211
-
212
- ---
213
-
214
- ### Convenience
215
-
216
- | Method | Signature | Returns | Description |
217
- |--------|-----------|---------|-------------|
218
- | `getConnectionInfo` | `getConnectionInfo(): { connected: boolean; transport: string; uri: string }` | object | Current connection state and URI. Useful for debugging or displaying "Connected to …" in the UI. |
219
- | `getApiKey` | `getApiKey(): string \| undefined` | `string \| undefined` | The API key in use (for debugging only; avoid logging in production). |
220
-
221
- ---
222
-
223
- ### Static
224
-
225
- | Method | Signature | Returns | Description |
226
- |--------|-----------|---------|-------------|
227
- | `withConnection` | `RocketRideClient.withConnection<T>(config: RocketRideClientConfig, callback: (client: RocketRideClient) => Promise<T>): Promise<T>` | `Promise<T>` | Creates a client, calls `connect()`, runs `callback(client)`, then `disconnect()` in a `finally` block. Returns the callback result. **Use** for one-off scripts so you never forget to disconnect. |
228
-
229
- ---
230
-
231
- ## DataPipe
232
-
233
- Returned by `client.pipe()`. Represents one streaming upload: **open** → one or more **write** → **close**. The server assigns a `pipeId` when you open; each `write()` sends a chunk for that pipe, and `close()` finalizes the stream and returns the pipeline result.
234
-
235
- | Member | Type | Description |
236
- |--------|------|-------------|
237
- | `isOpened` | `boolean` (getter) | Whether the pipe has been opened and not yet closed. |
238
- | `pipeId` | `number \| undefined` (getter) | Server-assigned pipe ID; set after `open()`. |
239
-
240
- | Method | Signature | Returns | Description |
241
- |--------|-----------|---------|-------------|
242
- | `open` | `open(): Promise<DataPipe>` | `Promise<DataPipe>` | Opens the pipe on the server. Must be called before `write()`. |
243
- | `write` | `write(buffer: Uint8Array): Promise<void>` | | Writes a chunk. Pipe must be open. |
244
- | `close` | `close(): Promise<PIPELINE_RESULT \| undefined>` | `Promise<PIPELINE_RESULT \| undefined>` | Closes the pipe and returns the processing result. No-op if already closed. |
245
-
246
- ---
247
-
248
- ## Question
249
-
250
- From `rocketride`. Build a question for `client.chat({ token, question })`. You can add instructions (how to answer), examples (example input/output), context (background), history (prior messages), and documents (what to reference).
251
-
252
- ### Constructor
253
-
254
- ```ts
255
- constructor(options?: {
256
- type?: QuestionType;
257
- filter?: DocFilter;
258
- expectJson?: boolean;
259
- role?: string;
260
- })
261
- ```
262
-
263
- `QuestionType`: `QUESTION`, `SEMANTIC`, `KEYWORD`, `GET`, `PROMPT`. Default type is `QUESTION`. Default filter and `expectJson: false`, `role: ''` if omitted.
264
-
265
- ### Methods
266
-
267
- | Method | Signature | Description |
268
- |--------|-----------|-------------|
269
- | `addInstruction` | `addInstruction(title: string, instruction: string): void` | Adds an instruction for the AI (e.g. "Answer in bullet points"). |
270
- | `addExample` | `addExample(given: string, result: string \| object \| any[]): void` | Adds an example input/output so the AI can match format. |
271
- | `addContext` | `addContext(context: string \| object \| string[] \| object[]): void` | Adds context (e.g. "Q4 2024 data"). |
272
- | `addHistory` | `addHistory(item: QuestionHistory): void` | Adds a history item (`{ role, content }`) for multi-turn chat. |
273
- | `addQuestion` | `addQuestion(question: string): void` | Appends the main question text. |
274
- | `addDocuments` | `addDocuments(documents: Doc \| Doc[]): void` | Adds documents for the AI to reference. |
275
- | `getPrompt` | `getPrompt(hasPreviousJsonFailed?: boolean): string` | Returns the full prompt (internal use). |
276
-
277
- ---
278
-
279
- ## Answer
280
-
281
- Used to parse chat response content. The client does not attach an `Answer` instance to the pipeline result; you read the response body and, if needed, use these static helpers to extract JSON or code from AI text (which often includes markdown or code fences).
282
-
283
- | Method | Signature | Description |
284
- |--------|-----------|-------------|
285
- | `Answer.parseJson` | `parseJson(value: string): any` | Parses JSON from AI text (strips markdown/code blocks). |
286
- | `Answer.parsePython` | `parsePython(value: string): string` | Extracts Python code from a code block in the response. |
287
-
288
- ---
289
-
290
- ## Types
291
-
292
- - **DAPMessage**: `{ type, seq, command?, arguments?, body?, success?, message?, request_seq?, event?, token?, data?, trace? }`.
293
- - **TASK_STATUS**: Task status with `completedCount`, `totalCount`, `completed`, `state`, `exitCode`, and many more fields.
294
- - **PIPELINE_RESULT**: `{ name, path, objectId, result_types?, [key: string]: any }`.
295
- - **PipelineConfig**: Pipeline definition with `name`, `description`, `version`, `components`, `source`, `project_id`.
296
- - **UPLOAD_RESULT**: Per-file result with e.g. `action` (`'complete'` \| `'error'`), `filepath`, `error?`, `result?`, `upload_time?`.
297
- - **QuestionHistory**: `{ role: string, content: string }`.
298
- - **QuestionInstruction**: `{ subtitle: string, instructions: string }`.
299
- - **QuestionExample**: `{ given: string, result: string }`.
300
-
301
- ---
302
-
303
- ## Exceptions
304
-
305
- `AuthenticationException` extends `ConnectionException`; thrown on DAP auth failure. In persist mode the client catches it, calls `onConnectError`, and does not retry so the app can fix credentials and call `connect()` again.
306
-
307
- ---
308
-
309
- ## Examples (full API usage)
310
-
311
- ### 1. Minimal: connect, run pipeline from file, send one string, disconnect
312
-
313
- ```ts
314
- import { RocketRideClient } from 'rocketride';
315
-
316
- const client = new RocketRideClient({
317
- auth: process.env.ROCKETRIDE_APIKEY!,
318
- uri: 'https://cloud.rocketride.ai',
319
- });
320
- await client.connect();
321
- const { token } = await client.use({ filepath: './pipeline.json' });
322
- const result = await client.send(token, 'Hello, pipeline!', { name: 'input.txt' }, 'text/plain');
323
- console.log(result);
324
- await client.terminate(token);
325
- await client.disconnect();
326
- ```
327
-
328
- ### 2. One-off script with automatic disconnect (withConnection)
329
-
330
- ```ts
331
- import { RocketRideClient } from 'rocketride';
332
-
333
- const status = await RocketRideClient.withConnection(
334
- { auth: 'my-key', uri: 'wss://cloud.rocketride.ai' },
335
- async (client) => {
336
- const { token } = await client.use({ pipeline: { pipeline: myPipelineConfig } });
337
- await client.send(token, JSON.stringify({ data: 1 }));
338
- return await client.getTaskStatus(token);
339
- }
340
- );
341
- console.log(status);
342
- ```
343
-
344
- ### 3. Long-lived app: persist mode, callbacks, and status handling
345
-
346
- ```ts
347
- import { RocketRideClient } from 'rocketride';
348
-
349
- const client = new RocketRideClient({
350
- auth: apiKey,
351
- uri: serverUri,
352
- persist: true,
353
- maxRetryTime: 300000,
354
- onConnected: async () => updateUI({ state: 'connected' }),
355
- onDisconnected: async (reason, hasError) => updateUI({ state: 'disconnected', reason, hasError }),
356
- onConnectError: (msg) => updateUI({ state: 'error', message: msg }),
357
- onEvent: async (e) => {
358
- if (e.event === 'apaevt_status_upload') updateProgress(e.body);
359
- },
360
- });
361
- await client.connect();
362
- // Later: use(), sendFiles(), etc. If connection drops, client retries; do not call disconnect() in onDisconnected.
363
- ```
364
-
365
- ### 4. Upload multiple files and poll until pipeline completes
366
-
367
- ```ts
368
- import { RocketRideClient } from 'rocketride';
369
-
370
- const client = new RocketRideClient({ auth, uri, onEvent: async (e) => console.log(e.event, e.body) });
371
- await client.connect();
372
- const { token } = await client.use({ filepath: './vectorize.json' });
373
- await client.setEvents(token, ['apaevt_status_upload', 'apaevt_status_processing']);
374
-
375
- const files = [new File([content1], 'a.md'), new File([content2], 'b.md')];
376
- const uploadResults = await client.sendFiles(files.map(file => ({ file })), token);
377
- console.log('Uploaded:', uploadResults.filter(r => r.action === 'complete').length);
378
-
379
- while (true) {
380
- const status = await client.getTaskStatus(token);
381
- console.log(`Progress: ${status.completedCount}/${status.totalCount}`);
382
- if (status.completed) break;
383
- await new Promise(r => setTimeout(r, 2000));
384
- }
385
- await client.terminate(token);
386
- await client.disconnect();
387
- ```
388
-
389
- ### 5. Streaming large data with a pipe
390
-
391
- ```ts
392
- import { RocketRideClient } from 'rocketride';
393
- import { createReadStream } from 'fs';
394
- import { createInterface } from 'readline';
395
-
396
- const client = new RocketRideClient({ auth, uri });
397
- await client.connect();
398
- const { token } = await client.use({ pipeline: { pipeline: config } });
399
-
400
- const pipe = await client.pipe(token, { name: 'large.csv' }, 'text/csv');
401
- await pipe.open();
402
- const rl = createInterface({ input: createReadStream('large.csv') });
403
- for await (const line of rl) {
404
- await pipe.write(new TextEncoder().encode(line + '\n'));
405
- }
406
- const result = await pipe.close();
407
- console.log(result);
408
- await client.terminate(token);
409
- await client.disconnect();
410
- ```
411
-
412
- ### 6. Chat: Question with instructions and examples, parse JSON answer
413
-
414
- ```ts
415
- import { RocketRideClient, Question, Answer } from 'rocketride';
416
-
417
- const client = new RocketRideClient({ auth, uri });
418
- await client.connect();
419
- const { token } = await client.use({ pipeline: { pipeline: chatPipelineConfig } });
420
-
421
- const question = new Question({ expectJson: true });
422
- question.addInstruction('Format', 'Return a JSON object with keys: summary, keywords.');
423
- question.addExample('Summarize X', { summary: '...', keywords: ['a', 'b'] });
424
- question.addQuestion('Summarize the main points and list keywords.');
425
-
426
- const response = await client.chat({ token, question });
427
- const answerText = response?.data?.answer ?? response?.answers?.[0];
428
- const structured = answerText ? Answer.parseJson(answerText) : null;
429
- console.log(structured);
430
-
431
- await client.terminate(token);
432
- await client.disconnect();
433
- ```
434
-
435
- ### 7. Discover services and send a custom DAP request
436
-
437
- ```ts
438
- import { RocketRideClient } from 'rocketride';
439
-
440
- const client = new RocketRideClient({ auth, uri });
441
- await client.connect();
442
-
443
- const services = await client.getServices();
444
- console.log('Available:', Object.keys(services));
445
- const ocrSchema = await client.getService('ocr');
446
-
447
- const req = client.buildRequest('rrext_ping', { token: myToken });
448
- const res = await client.request(req, 5000);
449
- if (client.didFail(res)) throw new Error(res.message);
450
- await client.disconnect();
451
- ```
452
-
453
- ---
454
-
455
- ## Directory structure
456
-
457
- ```text
458
- packages/client-typescript/
459
- ├── src/
460
- │ ├── client/ # Main client (RocketRideClient, DAP, transport)
461
- │ │ ├── core/ # DAPClient, DAPBase, TransportBase, TransportWebSocket
462
- │ │ ├── exceptions/
463
- │ │ ├── schema/ # Question, Doc, DocFilter, etc.
464
- │ │ └── types/
465
- │ └── cli/ # CLI (rocketride command)
466
- ├── tests/
467
- ├── package.json
468
- ├── tsconfig.json
469
- └── README.md # This file
470
- ```
471
-
472
- ---
473
-
474
- ## License
475
-
476
- MIT License — see [LICENSE](./LICENSE) in this package.
1
+ # RocketRide
2
+
3
+ TypeScript/JavaScript SDK for the RocketRide Engine - build, run, and manage AI pipelines from Node.js or the browser.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # NPM
9
+ npm install rocketride
10
+ # Yarn
11
+ yarn add rocketride
12
+ # PNPM
13
+ pnpm add rocketride
14
+ ```
15
+
16
+ ```typescript
17
+ import { RocketRideClient } from 'rocketride';
18
+
19
+ const client = new RocketRideClient({
20
+ auth: process.env.ROCKETRIDE_APIKEY!,
21
+ uri: 'https://cloud.rocketride.ai',
22
+ });
23
+ await client.connect();
24
+ const { token } = await client.use({ filepath: './pipeline.pipe' });
25
+ const result = await client.send(token, 'Hello, pipeline!', { name: 'input.txt' }, 'text/plain');
26
+ console.log(result);
27
+ await client.terminate(token);
28
+ await client.disconnect();
29
+ ```
30
+
31
+ Don't have a pipeline yet? Visit [RocketRide on GitHub](https://github.com/rocketride-org/rocketride-server) or download the extension directly in your IDE.
32
+
33
+ <p align="center">
34
+ <img src="https://raw.githubusercontent.com/rocketride-org/rocketride-server/develop/images/install.png" alt="Install RocketRide extension" width="600">
35
+ </p>
36
+
37
+ ## What is RocketRide?
38
+
39
+ [RocketRide](https://rocketride.org) is an open source, developer-native AI pipeline platform.
40
+ It lets you build, debug, and deploy production AI workflows without leaving your IDE -
41
+ using a visual drag-and-drop canvas or code-first with TypeScript and Python SDKs.
42
+
43
+ - **50+ ready-to-use nodes** - 13 LLM providers, 8 vector databases, OCR, NER, PII anonymization, and more
44
+ - **High-performance C++ engine** - production-grade speed and reliability
45
+ - **Deploy anywhere** - locally, on-premises, or self-hosted with Docker
46
+ - **MIT licensed** - fully open source, OSI-compliant
47
+
48
+ You build your `.pipe` - and you run it against the fastest AI runtime available.
49
+
50
+ <img src="https://raw.githubusercontent.com/rocketride-org/rocketride-server/develop/docs/images/canvas.png" alt="RocketRide visual canvas builder" width="800">
51
+
52
+ ## Features
53
+
54
+ - **Pipeline execution** - Start with `use()`, send data via `send()`, `sendFiles()`, or `pipe()`
55
+ - **Chat** - Conversational AI via `chat()` and `Question`
56
+ - **Event streaming** - Real-time events via `onEvent` and `setEvents()`
57
+ - **File upload** - `sendFiles()` with progress; streaming with `pipe()`
58
+ - **Connection lifecycle** - Optional persist mode, reconnection, and callbacks (`onConnected`, `onDisconnected`, `onConnectError`)
59
+ - **Full TypeScript support** - Complete type definitions
60
+
61
+ ---
62
+
63
+ ## RocketRideClientConfig
64
+
65
+ Configuration object passed to `new RocketRideClient(config)`.
66
+
67
+ **Why it matters:** The config controls not only where you connect and how you authenticate, but also how the client behaves when the connection drops or when the server is slow to start. Getting `persist`, `maxRetryTime`, and the callbacks right avoids confusing "connection lost" vs "never connected" UX.
68
+
69
+ | Property | Type | Required | Description |
70
+ | ------------------- | ------------------------------------------------------- | -------- | ----------- |
71
+ | `auth` | `string` | No | API key. Optional: omit and set via `env.ROCKETRIDE_APIKEY` or `.env` (Node only), or set later with `setConnectionParams({ auth })` before calling `connect()`. |
72
+ | `uri` | `string` | No | Server URI (e.g. `https://cloud.rocketride.ai` or `ws://localhost:8080`). Optional: omit and use `env.ROCKETRIDE_URI` or built-in default, or set later with `setConnectionParams({ uri })` before calling `connect()`. |
73
+ | `env` | `Record<string, string>` | No | Override env; if omitted, `.env` is loaded in Node (only). Used for `${ROCKETRIDE_*}` substitution in pipeline config and for `ROCKETRIDE_APIKEY`/`ROCKETRIDE_URI` when not passed as `auth`/`uri`. |
74
+ | `persist` | `boolean` | No | Enable automatic reconnection with exponential backoff. Default: `false`. **Use `true`** for long-lived UIs or when the server may restart; the client will retry (250ms -> 2500ms) and call `onConnectError` on each failure until `maxRetryTime` or success. |
75
+ | `maxRetryTime` | `number` | No | Max time in ms to keep retrying connection. Default: no limit. **Use** (e.g. 300000 for 5 min) so you can show "gave up" after a bounded time instead of retrying forever. |
76
+ | `requestTimeout` | `number` | No | Default timeout in ms for each request; overridable per `request()` call. Prevents a single slow DAP call from hanging indefinitely. |
77
+ | `onConnected` | `(info?: string) => Promise<void>` | No | Called when connection is established. **Use** to refresh UI, refetch services, or clear "connecting" state. |
78
+ | `onDisconnected` | `(reason?: string, hasError?: boolean) => Promise<void>` | No | Called when connection is lost **only if** `onConnected` was already called. So "failed to connect in the first place" does *not* fire this - use `onConnectError` for that. **Do not** call `client.disconnect()` here if you want the client to auto-reconnect in persist mode. |
79
+ | `onConnectError` | `(message: string) => void \| Promise<void>` | No | Called on each failed connection attempt (e.g. while retrying in persist mode). **Use** to show "Connection failed: ..." or "Still connecting..."; on auth failure the client stops retrying, so you can prompt the user to fix credentials and call `connect()` again. |
80
+ | `onEvent` | `(event: DAPMessage) => Promise<void>` | No | Called for each server event (e.g. upload progress, task status). **Use** to drive progress bars or status text; event type is `event.event`, payload in `event.body`. |
81
+ | `onProtocolMessage` | `(message: string) => void` | No | Optional; for logging raw DAP messages. Helpful when debugging protocol issues. |
82
+ | `onDebugMessage` | `(message: string) => void` | No | Optional; for debug output. |
83
+ | `module` | `string` | No | Client name for logging. Default: `CLIENT-0`, `CLIENT-1`, ... |
84
+
85
+ **Example - long-lived app with persist and status:**
86
+
87
+ ```typescript
88
+ const client = new RocketRideClient({
89
+ auth: process.env.ROCKETRIDE_APIKEY!,
90
+ uri: 'wss://cloud.rocketride.ai',
91
+ persist: true,
92
+ maxRetryTime: 300000,
93
+ requestTimeout: 30000,
94
+ onConnected: async () => setStatus('connected'),
95
+ onDisconnected: async () => setStatus('disconnected'),
96
+ onConnectError: (msg) => setStatus('error', msg),
97
+ onEvent: async (e) => handleServerEvent(e),
98
+ });
99
+ ```
100
+
101
+ ## RocketRideClient
102
+
103
+ ### Constructor
104
+
105
+ ```typescript
106
+ constructor(config: RocketRideClientConfig = {})
107
+ ```
108
+
109
+ Creates a client instance; it does **not** connect until you call `connect()`. You can set up callbacks and then open the connection when ready. `auth` and `uri` are optional at construction and can be set later with `setConnectionParams()` before `connect()`.
110
+
111
+ **Example:**
112
+
113
+ ```typescript
114
+ const client = new RocketRideClient({ auth: 'my-key', uri: 'https://cloud.rocketride.ai' });
115
+ await client.connect();
116
+ ```
117
+
118
+ ### Connection
119
+
120
+ | Method | Signature | Returns | Description |
121
+ | --------------------- | --------- | ------- | ----------- |
122
+ | `connect` | `connect(timeout?: number): Promise<void>` | - | Opens the WebSocket and performs DAP auth. Optional `timeout` (ms) bounds the connect + auth handshake (non-persist only; in persist mode timeout is not applied). In **persist** mode, if this fails the client calls `onConnectError` and schedules retries (exponential backoff); on **auth** failure it does *not* retry so the app can fix credentials and call `connect()` again. |
123
+ | `disconnect` | `disconnect(): Promise<void>` | - | Closes the connection and cancels any pending reconnection. Call when the user explicitly disconnects or the app is shutting down. |
124
+ | `isConnected` | `isConnected(): boolean` | `boolean` | Whether the client is currently connected. Use before calling `use()` or `send()` to avoid confusing errors. |
125
+ | `setConnectionParams` | `setConnectionParams(options: { uri?: string; auth?: string }): Promise<void>` | - | Updates server URI and/or auth at runtime. If currently connected, disconnects and reconnects with the new params (in persist mode, reconnection is scheduled; otherwise reconnects once). Use when the user changes server or credentials without creating a new client. |
126
+
127
+ **How to use:** For one-off scripts, call `connect()` once, do your work, then `disconnect()`. For UIs, use `persist: true` and rely on the client to reconnect; only call `disconnect()` when the user logs out or you are done with the client. The client supports `await using` (Symbol.asyncDispose) for automatic disconnect when exiting scope.
128
+
129
+ ### Low-level DAP
130
+
131
+ | Method | Signature | Returns | Description |
132
+ | -------------- | --------- | ------- | ----------- |
133
+ | `buildRequest` | `buildRequest(command: string, options?: { token?: string; arguments?: Record<string, unknown>; data?: Uint8Array \| string }): DAPMessage` | `DAPMessage` | Builds a DAP request message with the next sequence number. Use when you need a custom command not wrapped by `use()`, `send()`, etc. |
134
+ | `request` | `request(request: DAPMessage, timeout?: number): Promise<DAPMessage>` | `Promise<DAPMessage>` | Sends the request and returns the response. Pass `timeout` (ms) to override the config default for this call. Check `didFail(response)` or `response.success` before using `response.body`. |
135
+ | `dapRequest` | `dapRequest(command: string, args?: Record<string, unknown>, token?: string, timeout?: number): Promise<DAPMessage>` | `Promise<DAPMessage>` | Shorthand: builds a request and sends it in one call. Equivalent to `buildRequest()` + `request()`. |
136
+ | `didFail` | `didFail(response: DAPMessage): boolean` | `boolean` | Returns `true` when the server indicated failure (`success === false`). Use after `request()` to decide whether to use `body` or surface `message` as an error. |
137
+
138
+ **Example - custom DAP command:**
139
+
140
+ ```typescript
141
+ const req = client.buildRequest('rrext_monitor', { token, arguments: { types: ['apaevt_status_upload'] } });
142
+ const res = await client.request(req, 5000);
143
+ if (client.didFail(res)) throw new Error(res.message);
144
+ ```
145
+
146
+ ### Pipeline execution
147
+
148
+ | Method | Signature | Returns | Description |
149
+ | --------------- | --------- | ------- | ----------- |
150
+ | `use` | `use(options?: { token?: string; filepath?: string; pipeline?: PipelineConfig; source?: string; threads?: number; useExisting?: boolean; args?: string[]; ttl?: number }): Promise<Record<string, any> & { token: string }>` | `Promise<{ token: string, ... }>` | Starts a pipeline. You must pass either `pipeline` (object) or `filepath` (path to a JSON file; Node only). The client substitutes `${ROCKETRIDE_*}` in the config from its `env` (or `.env`). Returns at least `token`; use that token for `send()`, `sendFiles()`, `pipe()`, `chat()`, `getTaskStatus()`, and `terminate()`. |
151
+ | `validate` | `validate(options: { pipeline: PipelineConfig \| Record<string, unknown>; source?: string }): Promise<Record<string, unknown>>` | `Promise<Record<string, unknown>>` | Validates a pipeline configuration without starting it. Returns validation results (e.g. errors, warnings). Use to check pipeline correctness before `use()`. |
152
+ | `terminate` | `terminate(token: string): Promise<void>` | - | Stops the pipeline for that token and frees server resources. Call when the user cancels or when you are done sending data. |
153
+ | `getTaskStatus` | `getTaskStatus(token: string): Promise<TASK_STATUS>` | `Promise<TASK_STATUS>` | Returns current task status: e.g. `completedCount`, `totalCount`, `completed`, `state`, `exitCode`. Use to poll until `completed` is true or to show progress. |
154
+
155
+ **Why `use()` returns a token:** The server runs each pipeline as a separate task. The token identifies that task so all subsequent operations (sending data, chat, status, terminate) target the right pipeline.
156
+
157
+ **Example - start from file and poll until done:**
158
+
159
+ ```typescript
160
+ const { token } = await client.use({ filepath: './pipeline.json', ttl: 3600 });
161
+ await client.setEvents(token, ['apaevt_status_processing']);
162
+ // ... send data ...
163
+ while (true) {
164
+ const status = await client.getTaskStatus(token);
165
+ if (status.completed) break;
166
+ await new Promise(r => setTimeout(r, 2000));
167
+ }
168
+ await client.terminate(token);
169
+ ```
170
+
171
+ ### Data
172
+
173
+ | Method | Signature | Returns | Description |
174
+ | ----------- | --------- | ------- | ----------- |
175
+ | `pipe` | `pipe(token: string, objinfo?: Record<string, any>, mimeType?: string, provider?: string): Promise<DataPipe>` | `Promise<DataPipe>` | Creates a **streaming** data pipe. Use when you have large payloads or chunks arriving over time; you call `open()`, then one or more `write()`, then `close()`. Default MIME: `application/octet-stream`. |
176
+ | `send` | `send(token: string, data: string \| Uint8Array, objinfo?: Record<string, any>, mimetype?: string): Promise<PIPELINE_RESULT \| undefined>` | `Promise<PIPELINE_RESULT \| undefined>` | Sends data in **one shot** (internally: open pipe, write once, close). Use for small payloads when you have the full buffer in memory. |
177
+ | `sendFiles` | `sendFiles(files: Array<{ file: File; objinfo?: Record<string, any>; mimetype?: string }>, token: string): Promise<UPLOAD_RESULT[]>` | `Promise<UPLOAD_RESULT[]>` | Uploads multiple browser `File` objects. Results are in the same order as `files`. Progress is reported via `onEvent` as `apaevt_status_upload` events (e.g. `body.filepath`, `body.bytes_sent`, `body.file_size`). |
178
+
179
+ **When to use `pipe` vs `send`:** Use `send()` when you have a single blob (e.g. a string or one `Uint8Array`) and don't need to stream. Use `pipe()` when you are reading a large file in chunks, or when data arrives incrementally (e.g. from a stream or multiple buffers).
180
+
181
+ **Example - send a string:**
182
+
183
+ ```typescript
184
+ const result = await client.send(token, 'Hello, pipeline!', { name: 'greeting.txt' }, 'text/plain');
185
+ ```
186
+
187
+ **Example - stream chunks with a pipe:**
188
+
189
+ ```typescript
190
+ const pipe = await client.pipe(token, { name: 'data.json' }, 'application/json');
191
+ await pipe.open();
192
+ for (const chunk of chunks) await pipe.write(new TextEncoder().encode(chunk));
193
+ const result = await pipe.close();
194
+ ```
195
+
196
+ ### Events
197
+
198
+ | Method | Signature | Returns | Description |
199
+ | ----------- | --------- | ------- | ----------- |
200
+ | `setEvents` | `setEvents(token: string, eventTypes: string[]): Promise<void>` | - | Subscribes this task to the given event types (e.g. `apaevt_status_upload`, `apaevt_status_processing`). After this, those events are delivered to your `onEvent` callback. Call after `use()` and before or while sending data. |
201
+
202
+ ### Services, validation, and ping
203
+
204
+ | Method | Signature | Returns | Description |
205
+ | ------------- | --------- | ------- | ----------- |
206
+ | `getServices` | `getServices(): Promise<Record<string, any>>` | `Promise<Record<string, any>>` | Returns all service/connector definitions from the server (schemas, UI schemas). Use to discover what pipelines or features the server supports. |
207
+ | `getService` | `getService(service: string): Promise<Record<string, any> \| undefined>` | `Promise<Record<string, any> \| undefined>` | Returns the definition for one service by name. Throws if the request fails. |
208
+ | `ping` | `ping(token?: string): Promise<void>` | - | Lightweight liveness check. Throws if the server responds with an error. Optional `token` for task-scoped ping. |
209
+
210
+ ### Chat
211
+
212
+ | Method | Signature | Returns | Description |
213
+ | ------ | --------- | ------- | ----------- |
214
+ | `chat` | `chat(options: { token: string; question: Question }): Promise<PIPELINE_RESULT>` | `Promise<PIPELINE_RESULT>` | Sends the `Question` to the AI for the given pipeline token and returns the pipeline result. The answer content is in the result body (e.g. fields described by `result_types`); you can use `Answer.parseJson()` on raw text if the AI returned JSON. |
215
+
216
+ **How it works:** The client opens a pipe with MIME type `application/rocketride-question`, writes the serialized `Question`, closes the pipe, and returns the server's result. The pipeline must support the chat provider for that token.
217
+
218
+ ### Convenience
219
+
220
+ | Method | Signature | Returns | Description |
221
+ | ------------------- | --------- | ------- | ----------- |
222
+ | `getConnectionInfo` | `getConnectionInfo(): { connected: boolean; transport: string; uri: string }` | object | Current connection state and URI. Useful for debugging or displaying "Connected to ..." in the UI. |
223
+ | `getApiKey` | `getApiKey(): string \| undefined` | `string \| undefined` | The API key in use (for debugging only; avoid logging in production). |
224
+
225
+ ### Static
226
+
227
+ | Method | Signature | Returns | Description |
228
+ | ---------------- | --------- | ------- | ----------- |
229
+ | `withConnection` | `RocketRideClient.withConnection<T>(config: RocketRideClientConfig, callback: (client: RocketRideClient) => Promise<T>): Promise<T>` | `Promise<T>` | Creates a client, calls `connect()`, runs `callback(client)`, then `disconnect()` in a `finally` block. Returns the callback result. **Use** for one-off scripts so you never forget to disconnect. |
230
+
231
+ ---
232
+
233
+ ## DataPipe
234
+
235
+ Returned by `client.pipe()`. Represents one streaming upload: **open** -> one or more **write** -> **close**. The server assigns a `pipeId` when you open; each `write()` sends a chunk for that pipe, and `close()` finalizes the stream and returns the pipeline result.
236
+
237
+ | Member | Type | Description |
238
+ | ---------- | ----------------------------- | ---------------------------------------------------- |
239
+ | `isOpened` | `boolean` (getter) | Whether the pipe has been opened and not yet closed. |
240
+ | `pipeId` | `number \| undefined` (getter) | Server-assigned pipe ID; set after `open()`. |
241
+
242
+ | Method | Signature | Returns | Description |
243
+ | ------- | --------- | ------- | ----------- |
244
+ | `open` | `open(): Promise<DataPipe>` | `Promise<DataPipe>` | Opens the pipe on the server. Must be called before `write()`. |
245
+ | `write` | `write(buffer: Uint8Array): Promise<void>` | - | Writes a chunk. Pipe must be open. |
246
+ | `close` | `close(): Promise<PIPELINE_RESULT \| undefined>` | `Promise<PIPELINE_RESULT \| undefined>` | Closes the pipe and returns the processing result. No-op if already closed. |
247
+
248
+ ---
249
+
250
+ ## Question
251
+
252
+ From `rocketride`. Build a question for `client.chat({ token, question })`. You can add instructions (how to answer), examples (example input/output), context (background), history (prior messages), and documents (what to reference).
253
+
254
+ ### Constructor
255
+
256
+ ```typescript
257
+ constructor(options?: {
258
+ type?: QuestionType;
259
+ filter?: DocFilter;
260
+ expectJson?: boolean;
261
+ role?: string;
262
+ })
263
+ ```
264
+
265
+ `QuestionType`: `QUESTION`, `SEMANTIC`, `KEYWORD`, `GET`, `PROMPT`. Default type is `QUESTION`. Default filter and `expectJson: false`, `role: ''` if omitted.
266
+
267
+ ### Methods
268
+
269
+ | Method | Signature | Description |
270
+ | ---------------- | --------- | ----------- |
271
+ | `addInstruction` | `addInstruction(title: string, instruction: string): void` | Adds an instruction for the AI (e.g. "Answer in bullet points"). |
272
+ | `addExample` | `addExample(given: string, result: string \| object \| any[]): void` | Adds an example input/output so the AI can match format. |
273
+ | `addContext` | `addContext(context: string \| object \| string[] \| object[]): void` | Adds context (e.g. "Q4 2024 data"). |
274
+ | `addHistory` | `addHistory(item: QuestionHistory): void` | Adds a history item (`{ role, content }`) for multi-turn chat. |
275
+ | `addQuestion` | `addQuestion(question: string): void` | Appends the main question text. |
276
+ | `addDocuments` | `addDocuments(documents: Doc \| Doc[]): void` | Adds documents for the AI to reference. |
277
+ | `getPrompt` | `getPrompt(hasPreviousJsonFailed?: boolean): string` | Returns the full prompt (internal use). |
278
+
279
+ ---
280
+
281
+ ## Answer
282
+
283
+ Used to parse chat response content. The client does not attach an `Answer` instance to the pipeline result; you read the response body and, if needed, use these static helpers to extract JSON or code from AI text (which often includes markdown or code fences).
284
+
285
+ | Method | Signature | Description |
286
+ | ------------------ | --------- | ----------- |
287
+ | `Answer.parseJson` | `parseJson(value: string): any` | Parses JSON from AI text (strips markdown/code blocks). |
288
+ | `Answer.parsePython` | `parsePython(value: string): string` | Extracts Python code from a code block in the response. |
289
+
290
+ ---
291
+
292
+ ## Types
293
+
294
+ - **DAPMessage**: `{ type, seq, command?, arguments?, body?, success?, message?, request_seq?, event?, token?, data?, trace? }`.
295
+ - **TASK_STATUS**: Task status with `completedCount`, `totalCount`, `completed`, `state`, `exitCode`, and many more fields.
296
+ - **PIPELINE_RESULT**: `{ name, path, objectId, result_types?, [key: string]: any }`.
297
+ - **PipelineConfig**: Pipeline definition with `name`, `description`, `version`, `components`, `source`, `project_id`.
298
+ - **UPLOAD_RESULT**: Per-file result with e.g. `action` (`'complete'` \| `'error'`), `filepath`, `error?`, `result?`, `upload_time?`.
299
+ - **QuestionHistory**: `{ role: string, content: string }`.
300
+ - **QuestionInstruction**: `{ subtitle: string, instructions: string }`.
301
+ - **QuestionExample**: `{ given: string, result: string }`.
302
+
303
+ ---
304
+
305
+ ## Exceptions
306
+
307
+ `AuthenticationException` extends `ConnectionException`; thrown on DAP auth failure. In persist mode the client catches it, calls `onConnectError`, and does not retry so the app can fix credentials and call `connect()` again.
308
+
309
+ ---
310
+
311
+ ## Examples (Full API Usage)
312
+
313
+ ### 1. Minimal: connect, run pipeline from file, send one string, disconnect
314
+
315
+ ```typescript
316
+ import { RocketRideClient } from 'rocketride';
317
+
318
+ const client = new RocketRideClient({
319
+ auth: process.env.ROCKETRIDE_APIKEY!,
320
+ uri: 'https://cloud.rocketride.ai',
321
+ });
322
+ await client.connect();
323
+ const { token } = await client.use({ filepath: './pipeline.json' });
324
+ const result = await client.send(token, 'Hello, pipeline!', { name: 'input.txt' }, 'text/plain');
325
+ console.log(result);
326
+ await client.terminate(token);
327
+ await client.disconnect();
328
+ ```
329
+
330
+ ### 2. One-off script with automatic disconnect (withConnection)
331
+
332
+ ```typescript
333
+ import { RocketRideClient } from 'rocketride';
334
+
335
+ const status = await RocketRideClient.withConnection(
336
+ { auth: 'my-key', uri: 'wss://cloud.rocketride.ai' },
337
+ async (client) => {
338
+ const { token } = await client.use({ pipeline: { pipeline: myPipelineConfig } });
339
+ await client.send(token, JSON.stringify({ data: 1 }));
340
+ return await client.getTaskStatus(token);
341
+ }
342
+ );
343
+ console.log(status);
344
+ ```
345
+
346
+ ### 3. Long-lived app: persist mode, callbacks, and status handling
347
+
348
+ ```typescript
349
+ import { RocketRideClient } from 'rocketride';
350
+
351
+ const client = new RocketRideClient({
352
+ auth: apiKey,
353
+ uri: serverUri,
354
+ persist: true,
355
+ maxRetryTime: 300000,
356
+ onConnected: async () => updateUI({ state: 'connected' }),
357
+ onDisconnected: async (reason, hasError) => updateUI({ state: 'disconnected', reason, hasError }),
358
+ onConnectError: (msg) => updateUI({ state: 'error', message: msg }),
359
+ onEvent: async (e) => {
360
+ if (e.event === 'apaevt_status_upload') updateProgress(e.body);
361
+ },
362
+ });
363
+ await client.connect();
364
+ // Later: use(), sendFiles(), etc. If connection drops, client retries; do not call disconnect() in onDisconnected.
365
+ ```
366
+
367
+ ### 4. Upload multiple files and poll until pipeline completes
368
+
369
+ ```typescript
370
+ import { RocketRideClient } from 'rocketride';
371
+
372
+ const client = new RocketRideClient({ auth, uri, onEvent: async (e) => console.log(e.event, e.body) });
373
+ await client.connect();
374
+ const { token } = await client.use({ filepath: './vectorize.json' });
375
+ await client.setEvents(token, ['apaevt_status_upload', 'apaevt_status_processing']);
376
+
377
+ const files = [new File([content1], 'a.md'), new File([content2], 'b.md')];
378
+ const uploadResults = await client.sendFiles(files.map(file => ({ file })), token);
379
+ console.log('Uploaded:', uploadResults.filter(r => r.action === 'complete').length);
380
+
381
+ while (true) {
382
+ const status = await client.getTaskStatus(token);
383
+ console.log(`Progress: ${status.completedCount}/${status.totalCount}`);
384
+ if (status.completed) break;
385
+ await new Promise(r => setTimeout(r, 2000));
386
+ }
387
+ await client.terminate(token);
388
+ await client.disconnect();
389
+ ```
390
+
391
+ ### 5. Streaming large data with a pipe
392
+
393
+ ```typescript
394
+ import { RocketRideClient } from 'rocketride';
395
+ import { createReadStream } from 'fs';
396
+ import { createInterface } from 'readline';
397
+
398
+ const client = new RocketRideClient({ auth, uri });
399
+ await client.connect();
400
+ const { token } = await client.use({ pipeline: { pipeline: config } });
401
+
402
+ const pipe = await client.pipe(token, { name: 'large.csv' }, 'text/csv');
403
+ await pipe.open();
404
+ const rl = createInterface({ input: createReadStream('large.csv') });
405
+ for await (const line of rl) {
406
+ await pipe.write(new TextEncoder().encode(line + '\n'));
407
+ }
408
+ const result = await pipe.close();
409
+ console.log(result);
410
+ await client.terminate(token);
411
+ await client.disconnect();
412
+ ```
413
+
414
+ ### 6. Chat: question with instructions and examples, parse JSON answer
415
+
416
+ ```typescript
417
+ import { RocketRideClient, Question, Answer } from 'rocketride';
418
+
419
+ const client = new RocketRideClient({ auth, uri });
420
+ await client.connect();
421
+ const { token } = await client.use({ pipeline: { pipeline: chatPipelineConfig } });
422
+
423
+ const question = new Question({ expectJson: true });
424
+ question.addInstruction('Format', 'Return a JSON object with keys: summary, keywords.');
425
+ question.addExample('Summarize X', { summary: '...', keywords: ['a', 'b'] });
426
+ question.addQuestion('Summarize the main points and list keywords.');
427
+
428
+ const response = await client.chat({ token, question });
429
+ const answerText = response?.data?.answer ?? response?.answers?.[0];
430
+ const structured = answerText ? Answer.parseJson(answerText) : null;
431
+ console.log(structured);
432
+
433
+ await client.terminate(token);
434
+ await client.disconnect();
435
+ ```
436
+
437
+ ### 7. Discover services and send a custom DAP request
438
+
439
+ ```typescript
440
+ import { RocketRideClient } from 'rocketride';
441
+
442
+ const client = new RocketRideClient({ auth, uri });
443
+ await client.connect();
444
+
445
+ const services = await client.getServices();
446
+ console.log('Available:', Object.keys(services));
447
+ const ocrSchema = await client.getService('ocr');
448
+
449
+ const req = client.buildRequest('rrext_ping', { token: myToken });
450
+ const res = await client.request(req, 5000);
451
+ if (client.didFail(res)) throw new Error(res.message);
452
+ await client.disconnect();
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Links
458
+
459
+ - [Documentation](https://docs.rocketride.org/)
460
+ - [GitHub](https://github.com/rocketride-org/rocketride-server)
461
+ - [Discord](https://discord.gg/9hr3tdZmEG)
462
+ - [Contributing](https://github.com/rocketride-org/rocketride-server/blob/develop/CONTRIBUTING.md)
463
+
464
+ ## License
465
+
466
+ MIT - see [LICENSE](https://github.com/rocketride-org/rocketride-server/blob/develop/LICENSE).