@starcite/sdk 0.0.3 → 0.0.4
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 +244 -182
- package/dist/index.cjs +1640 -645
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +589 -204
- package/dist/index.d.ts +589 -204
- package/dist/index.js +1618 -641
- package/dist/index.js.map +1 -1
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -2,262 +2,324 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for [Starcite](https://starcite.ai), built for multi-agent systems.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
If you need a single ordered session stream across multiple producers, this is the SDK you use.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Install
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
```bash
|
|
10
|
+
npm install @starcite/sdk
|
|
11
|
+
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Runtime Requirements
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
- Node.js 22+ (or Bun / modern runtime with `fetch` + `WebSocket`)
|
|
16
|
+
- Starcite base URL (for example `https://<your-instance>.starcite.io`)
|
|
17
|
+
- API key JWT for backend flows
|
|
18
|
+
- Session token JWTs for frontend/session-scoped flows
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
The SDK normalizes the API URL to `/v1` automatically.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
- b) keep frontend consistency by reading from the same ordered stream.
|
|
22
|
+
## The Core Model
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
- `Starcite`: tenant-scoped client
|
|
25
|
+
- `StarciteIdentity`: `user` or `agent` principal tied to tenant
|
|
26
|
+
- `StarciteSession`: session-scoped handle for append/tail/consume/live-sync
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
npm install @starcite/sdk
|
|
29
|
-
```
|
|
28
|
+
The key split:
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
- backend: construct `Starcite` with `apiKey`
|
|
31
|
+
- frontend: construct `Starcite` without `apiKey`, bind with `session({ token })`
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
- Your Starcite Cloud instance URL (`https://<your-instance>.starcite.io`)
|
|
35
|
-
- Your Starcite API key / service JWT
|
|
33
|
+
## How You Use This SDK
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
This is the practical shape teams end up using in production.
|
|
38
36
|
|
|
39
|
-
|
|
37
|
+
### A) Agent Backend (worker/service)
|
|
38
|
+
|
|
39
|
+
Use the identity flow. This creates or binds a session and mints a session token.
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
-
import {
|
|
42
|
+
import { InMemoryCursorStore, Starcite } from "@starcite/sdk";
|
|
43
43
|
|
|
44
|
-
const
|
|
45
|
-
baseUrl: process.env.STARCITE_BASE_URL
|
|
44
|
+
const starcite = new Starcite({
|
|
45
|
+
baseUrl: process.env.STARCITE_BASE_URL,
|
|
46
46
|
apiKey: process.env.STARCITE_API_KEY,
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
// Use a persistent store in production
|
|
50
|
+
const cursorStore = new InMemoryCursorStore();
|
|
51
|
+
|
|
52
|
+
export async function runPlanner(prompt: string, sessionId?: string) {
|
|
53
|
+
const planner = starcite.agent({ id: "planner" });
|
|
54
|
+
|
|
55
|
+
const session = await starcite.session({
|
|
56
|
+
identity: planner,
|
|
57
|
+
id: sessionId,
|
|
58
|
+
title: "Planning session",
|
|
59
|
+
metadata: { workflow: "planner" },
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await session.append({ text: `Planning started: ${prompt}` });
|
|
63
|
+
|
|
64
|
+
await session.consume({
|
|
65
|
+
cursorStore,
|
|
66
|
+
reconnectPolicy: { mode: "fixed", initialDelayMs: 500, maxAttempts: 20 },
|
|
67
|
+
handler: async (event) => {
|
|
68
|
+
if (event.type === "content") {
|
|
69
|
+
// Your business logic here.
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await session.append({ text: "Planning complete." });
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
sessionId: session.id,
|
|
78
|
+
sessionToken: session.token, // hand off to UI when needed
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### B) User Frontend (browser)
|
|
84
|
+
|
|
85
|
+
Do not use API keys in browser code. Your backend mints a per-session token and sends it to the UI.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { Starcite } from "@starcite/sdk";
|
|
89
|
+
|
|
90
|
+
const starcite = new Starcite({
|
|
91
|
+
baseUrl: import.meta.env.VITE_STARCITE_BASE_URL,
|
|
53
92
|
});
|
|
54
93
|
|
|
55
|
-
await session
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
94
|
+
const { token } = await fetch("/api/chat/session", {
|
|
95
|
+
method: "POST",
|
|
96
|
+
}).then((res) => res.json());
|
|
97
|
+
|
|
98
|
+
const session = starcite.session({ token });
|
|
99
|
+
|
|
100
|
+
const stopEvents = session.on("event", (event) => {
|
|
101
|
+
// Replay + live events from canonical ordered session log.
|
|
102
|
+
renderEvent(event);
|
|
60
103
|
});
|
|
61
104
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
producerId: "producer:drafter",
|
|
65
|
-
producerSeq: 1,
|
|
66
|
-
text: "Drafted clause 4.2 with references.",
|
|
105
|
+
session.on("error", (error) => {
|
|
106
|
+
console.error("Session live-sync error", error);
|
|
67
107
|
});
|
|
68
108
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
109
|
+
await session.append({
|
|
110
|
+
text: "Can you summarize the last 3 updates?",
|
|
111
|
+
source: "user",
|
|
112
|
+
});
|
|
73
113
|
|
|
74
|
-
|
|
75
|
-
|
|
114
|
+
// cleanup on unmount/navigation
|
|
115
|
+
stopEvents();
|
|
116
|
+
session.disconnect();
|
|
76
117
|
```
|
|
77
118
|
|
|
78
|
-
|
|
119
|
+
### C) Admin Panel (ops/audit)
|
|
120
|
+
|
|
121
|
+
Typical split:
|
|
79
122
|
|
|
80
|
-
|
|
81
|
-
|
|
123
|
+
1. Backend lists sessions using API key.
|
|
124
|
+
2. Backend mints an admin viewer token for a selected session.
|
|
125
|
+
3. Frontend binds with `session({ token })` and tails/replays safely.
|
|
126
|
+
|
|
127
|
+
Backend:
|
|
82
128
|
|
|
83
129
|
```ts
|
|
84
|
-
import {
|
|
130
|
+
import { Starcite } from "@starcite/sdk";
|
|
85
131
|
|
|
86
|
-
const
|
|
87
|
-
baseUrl: process.env.STARCITE_BASE_URL
|
|
132
|
+
const starcite = new Starcite({
|
|
133
|
+
baseUrl: process.env.STARCITE_BASE_URL,
|
|
88
134
|
apiKey: process.env.STARCITE_API_KEY,
|
|
135
|
+
authUrl: process.env.STARCITE_AUTH_URL,
|
|
89
136
|
});
|
|
90
|
-
```
|
|
91
137
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
138
|
+
export async function listSessionsForAdmin() {
|
|
139
|
+
return await starcite.listSessions({ limit: 50 });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function mintAdminViewerToken(sessionId: string) {
|
|
143
|
+
const response = await fetch(
|
|
144
|
+
`${process.env.STARCITE_AUTH_URL}/api/v1/session-tokens`,
|
|
145
|
+
{
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers: {
|
|
148
|
+
authorization: `Bearer ${process.env.STARCITE_API_KEY}`,
|
|
149
|
+
"content-type": "application/json",
|
|
150
|
+
},
|
|
151
|
+
body: JSON.stringify({
|
|
152
|
+
session_id: sessionId,
|
|
153
|
+
principal: { type: "user", id: "admin:dashboard" },
|
|
154
|
+
scopes: ["session:read"],
|
|
155
|
+
}),
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
throw new Error(`Failed to mint admin token: ${response.status}`);
|
|
161
|
+
}
|
|
95
162
|
|
|
96
|
-
|
|
163
|
+
return (await response.json()) as { token: string; expires_in: number };
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Frontend admin inspector:
|
|
97
168
|
|
|
98
169
|
```ts
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
170
|
+
import { Starcite } from "@starcite/sdk";
|
|
171
|
+
|
|
172
|
+
const starcite = new Starcite({
|
|
173
|
+
baseUrl: import.meta.env.VITE_STARCITE_BASE_URL,
|
|
102
174
|
});
|
|
103
175
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
176
|
+
export async function inspectSession(sessionId: string) {
|
|
177
|
+
const { token } = await fetch(`/admin/api/sessions/${sessionId}/viewer-token`).then(
|
|
178
|
+
(res) => res.json()
|
|
179
|
+
);
|
|
107
180
|
|
|
108
|
-
|
|
109
|
-
```
|
|
181
|
+
const session = starcite.session({ token });
|
|
110
182
|
|
|
111
|
-
|
|
183
|
+
const stop = session.on("event", (event) => {
|
|
184
|
+
appendAuditRow(event);
|
|
185
|
+
});
|
|
112
186
|
|
|
113
|
-
|
|
187
|
+
session.on("error", (error) => {
|
|
188
|
+
showBanner(`Stream error: ${error.message}`);
|
|
189
|
+
});
|
|
114
190
|
|
|
115
|
-
|
|
116
|
-
|
|
191
|
+
return () => {
|
|
192
|
+
stop();
|
|
193
|
+
session.disconnect();
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
```
|
|
117
197
|
|
|
118
|
-
|
|
198
|
+
## Public API (Current)
|
|
119
199
|
|
|
120
200
|
```ts
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
201
|
+
import {
|
|
202
|
+
MemoryStore,
|
|
203
|
+
Starcite,
|
|
204
|
+
type AppendResult,
|
|
205
|
+
type SessionEvent,
|
|
206
|
+
type SessionStore,
|
|
207
|
+
type StarciteWebSocket,
|
|
208
|
+
} from "@starcite/sdk";
|
|
128
209
|
|
|
129
|
-
|
|
210
|
+
// ── Construction ────────────────────────────────────────────────────────────
|
|
130
211
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
idempotency_key: "req-123",
|
|
139
|
-
expected_seq: 3,
|
|
212
|
+
const starcite = new Starcite({
|
|
213
|
+
apiKey: process.env.STARCITE_API_KEY, // required for server-side session creation
|
|
214
|
+
baseUrl: process.env.STARCITE_BASE_URL, // default: STARCITE_BASE_URL or http://localhost:4000
|
|
215
|
+
authUrl: process.env.STARCITE_AUTH_URL, // overrides iss-derived auth URL for token minting
|
|
216
|
+
fetch: globalThis.fetch,
|
|
217
|
+
websocketFactory: (url) => new WebSocket(url),
|
|
218
|
+
store: new MemoryStore(), // cursor + event persistence (default: MemoryStore)
|
|
140
219
|
});
|
|
141
|
-
```
|
|
142
220
|
|
|
143
|
-
|
|
221
|
+
// WebSocketFactory — simplified, auth is always in access_token query string.
|
|
222
|
+
type WebSocketFactory = (url: string) => StarciteWebSocket;
|
|
144
223
|
|
|
145
|
-
|
|
146
|
-
const session = client.session("ses_demo");
|
|
147
|
-
const controller = new AbortController();
|
|
148
|
-
|
|
149
|
-
setTimeout(() => controller.abort(), 5000);
|
|
150
|
-
|
|
151
|
-
for await (const event of session.tail({
|
|
152
|
-
cursor: 0,
|
|
153
|
-
agent: "drafter",
|
|
154
|
-
reconnect: true,
|
|
155
|
-
reconnectDelayMs: 3000,
|
|
156
|
-
signal: controller.signal,
|
|
157
|
-
})) {
|
|
158
|
-
console.log(event);
|
|
159
|
-
}
|
|
160
|
-
```
|
|
224
|
+
// ── Identities (server-side, require apiKey) ───────────────────────────────
|
|
161
225
|
|
|
162
|
-
|
|
163
|
-
|
|
226
|
+
const alice = starcite.user({ id: "u_123" });
|
|
227
|
+
const bot = starcite.agent({ id: "planner" });
|
|
164
228
|
|
|
165
|
-
|
|
166
|
-
- By default, reconnect retries continue until the stream is aborted or closes gracefully.
|
|
167
|
-
- Use `reconnectDelayMs` to control retry cadence for spotty networks.
|
|
229
|
+
// ── Sessions ────────────────────────────────────────────────────────────────
|
|
168
230
|
|
|
169
|
-
|
|
231
|
+
// Server-side: creates session + mints token (async)
|
|
232
|
+
const aliceSession = await starcite.session({ identity: alice });
|
|
233
|
+
const botSession = await starcite.session({
|
|
234
|
+
identity: bot,
|
|
235
|
+
id: aliceSession.id,
|
|
236
|
+
});
|
|
170
237
|
|
|
171
|
-
|
|
172
|
-
|
|
238
|
+
// Client-side: wraps existing JWT (sync, no network calls)
|
|
239
|
+
const session = starcite.session({ token: "<jwt>" });
|
|
173
240
|
|
|
174
|
-
|
|
175
|
-
const sessionId = "ses_demo";
|
|
176
|
-
const cursorKey = `starcite:${sessionId}:lastSeq`;
|
|
241
|
+
// ── Session properties ──────────────────────────────────────────────────────
|
|
177
242
|
|
|
178
|
-
|
|
179
|
-
|
|
243
|
+
session.id; // string
|
|
244
|
+
session.token; // string
|
|
245
|
+
session.identity; // StarciteIdentity
|
|
246
|
+
session.log; // SessionLog — canonical source of truth
|
|
180
247
|
|
|
181
|
-
|
|
182
|
-
lastSeq = 0;
|
|
183
|
-
}
|
|
248
|
+
// ── Session log ─────────────────────────────────────────────────────────────
|
|
184
249
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
reconnect: true,
|
|
188
|
-
reconnectDelayMs: 3000,
|
|
189
|
-
})) {
|
|
190
|
-
// Process event first, then persist cursor when your side effects succeed.
|
|
191
|
-
await renderOrStore(event);
|
|
192
|
-
lastSeq = event.seq;
|
|
193
|
-
localStorage.setItem(cursorKey, `${lastSeq}`);
|
|
194
|
-
}
|
|
195
|
-
```
|
|
250
|
+
session.log.events; // readonly SessionEvent[] — ordered by seq, no gaps
|
|
251
|
+
session.log.cursor; // number — highest applied seq
|
|
196
252
|
|
|
197
|
-
|
|
198
|
-
event handler to be idempotent by `seq` to safely tolerate replays.
|
|
253
|
+
// ── Append ──────────────────────────────────────────────────────────────────
|
|
199
254
|
|
|
200
|
-
|
|
255
|
+
await session.append({ text: "hello" });
|
|
256
|
+
await session.append({ payload: { ok: true }, type: "custom", source: "user" });
|
|
257
|
+
// -> Promise<AppendResult> = { seq: number, deduped: boolean }
|
|
201
258
|
|
|
202
|
-
|
|
203
|
-
import {
|
|
204
|
-
StarciteApiError,
|
|
205
|
-
StarciteConnectionError,
|
|
206
|
-
createStarciteClient,
|
|
207
|
-
} from "@starcite/sdk";
|
|
259
|
+
// ── Subscribe ───────────────────────────────────────────────────────────────
|
|
208
260
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
261
|
+
// Late subscribers get synchronous replay of log.events, then live events.
|
|
262
|
+
// WS connects lazily on first subscriber, disconnects when all leave.
|
|
263
|
+
const unsub = session.on("event", (event) => {
|
|
264
|
+
console.log(event.seq);
|
|
212
265
|
});
|
|
213
266
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
267
|
+
// Fatal errors only (for example token expiry). Transient drops auto-reconnect.
|
|
268
|
+
const unsubErr = session.on("error", (error) => {
|
|
269
|
+
console.error(error.message);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
unsub();
|
|
273
|
+
unsubErr();
|
|
274
|
+
|
|
275
|
+
// ── Teardown ────────────────────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
session.disconnect(); // stops WS immediately, removes all listeners
|
|
225
278
|
```
|
|
226
279
|
|
|
227
|
-
##
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
- `
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
280
|
+
## Tail Reliability Controls
|
|
281
|
+
|
|
282
|
+
`SessionTailOptions` supports:
|
|
283
|
+
|
|
284
|
+
- `cursor`, `batchSize`, `agent`
|
|
285
|
+
- `follow`, `reconnect`, `reconnectPolicy`
|
|
286
|
+
- `connectionTimeoutMs`, `inactivityTimeoutMs`
|
|
287
|
+
- `maxBufferedBatches`
|
|
288
|
+
- `signal`
|
|
289
|
+
- `onLifecycleEvent`
|
|
290
|
+
|
|
291
|
+
This is designed for robust reconnect + resume semantics in long-running multi-agent workflows.
|
|
292
|
+
|
|
293
|
+
## Session Stores
|
|
294
|
+
|
|
295
|
+
`new Starcite({ store })` accepts a `SessionStore` for cursor + retained-event
|
|
296
|
+
persistence across session rebinds.
|
|
297
|
+
|
|
298
|
+
- Default: `MemoryStore`
|
|
299
|
+
- Bring your own by implementing:
|
|
300
|
+
- `load(sessionId)`
|
|
301
|
+
- `save(sessionId, { cursor, events })`
|
|
302
|
+
- optional `clear(sessionId)`
|
|
303
|
+
|
|
304
|
+
## Error Types You Should Handle
|
|
305
|
+
|
|
306
|
+
- `StarciteApiError` for non-2xx responses
|
|
307
|
+
- `StarciteConnectionError` for transport/JSON issues
|
|
308
|
+
- `StarciteTailError` for streaming failures
|
|
309
|
+
- `StarciteTokenExpiredError` when close code `4001` is observed
|
|
310
|
+
- `StarciteRetryLimitError` when reconnect budget is exhausted
|
|
311
|
+
- `StarciteBackpressureError` when consumer buffering limits are exceeded
|
|
244
312
|
|
|
245
313
|
## Local Development
|
|
246
314
|
|
|
247
315
|
```bash
|
|
248
316
|
bun install
|
|
249
317
|
bun run --cwd packages/typescript-sdk build
|
|
250
|
-
bun run --cwd packages/typescript-sdk
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
Optional reconnect soak test (runs ~40s, disabled by default):
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
STARCITE_SDK_RUN_SOAK=1 bun run --cwd packages/typescript-sdk test -- test/client.reconnect.integration.test.ts
|
|
318
|
+
bun run --cwd packages/typescript-sdk check
|
|
319
|
+
bun run --cwd packages/typescript-sdk check:browser:all
|
|
257
320
|
```
|
|
258
321
|
|
|
259
322
|
## Links
|
|
260
323
|
|
|
261
|
-
- Product
|
|
262
|
-
-
|
|
263
|
-
- WebSocket tail docs: https://github.com/fastpaca/starcite/blob/main/docs/api/websocket.md
|
|
324
|
+
- Product: <https://starcite.ai>
|
|
325
|
+
- Repository: <https://github.com/fastpaca/starcite-clients>
|