@starcite/sdk 0.0.6 → 0.0.7
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 +15 -15
- package/dist/index.cjs +357 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +137 -83
- package/dist/index.d.ts +137 -83
- package/dist/index.js +355 -141
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -78,13 +78,14 @@ function inferIdentityFromApiKey(apiKey) {
|
|
|
78
78
|
const claims = ApiKeyClaimsSchema.parse(decodeJwt(apiKey));
|
|
79
79
|
const id = claims.principal_id ?? claims.sub;
|
|
80
80
|
const tenantId = claims.tenant_id;
|
|
81
|
-
|
|
81
|
+
const type = claims.principal_type ?? "user";
|
|
82
|
+
if (!(tenantId && id)) {
|
|
82
83
|
return void 0;
|
|
83
84
|
}
|
|
84
85
|
return new StarciteIdentity({
|
|
85
86
|
tenantId,
|
|
86
87
|
id,
|
|
87
|
-
type
|
|
88
|
+
type
|
|
88
89
|
});
|
|
89
90
|
}
|
|
90
91
|
function decodeSessionToken(token) {
|
|
@@ -285,7 +286,7 @@ var SessionLog = class {
|
|
|
285
286
|
this.enforceRetention();
|
|
286
287
|
return true;
|
|
287
288
|
}
|
|
288
|
-
|
|
289
|
+
state(syncing) {
|
|
289
290
|
return {
|
|
290
291
|
events: this.history.slice(),
|
|
291
292
|
lastSeq: this.appliedSeq,
|
|
@@ -888,7 +889,7 @@ var TailStream = class {
|
|
|
888
889
|
this.follow = follow;
|
|
889
890
|
this.shouldReconnect = follow ? opts.reconnect ?? true : false;
|
|
890
891
|
this.catchUpIdleMs = opts.catchUpIdleMs ?? 1e3;
|
|
891
|
-
this.connectionTimeoutMs = opts.connectionTimeoutMs ??
|
|
892
|
+
this.connectionTimeoutMs = opts.connectionTimeoutMs ?? 12e3;
|
|
892
893
|
this.inactivityTimeoutMs = opts.inactivityTimeoutMs;
|
|
893
894
|
this.maxBufferedBatches = opts.maxBufferedBatches ?? 1024;
|
|
894
895
|
this.signal = opts.signal;
|
|
@@ -1259,8 +1260,10 @@ var StarciteSession = class {
|
|
|
1259
1260
|
store;
|
|
1260
1261
|
lifecycle = new EventEmitter3();
|
|
1261
1262
|
eventSubscriptions = /* @__PURE__ */ new Map();
|
|
1263
|
+
appendTask = Promise.resolve();
|
|
1262
1264
|
liveSyncController;
|
|
1263
1265
|
liveSyncTask;
|
|
1266
|
+
liveSyncCatchUpActive = false;
|
|
1264
1267
|
constructor(options) {
|
|
1265
1268
|
this.id = options.id;
|
|
1266
1269
|
this.token = options.token;
|
|
@@ -1270,8 +1273,8 @@ var StarciteSession = class {
|
|
|
1270
1273
|
this.producerId = crypto.randomUUID();
|
|
1271
1274
|
this.store = options.store;
|
|
1272
1275
|
this.log = new SessionLog(options.logOptions);
|
|
1273
|
-
const storedState = this.store
|
|
1274
|
-
if (storedState) {
|
|
1276
|
+
const storedState = this.store?.load(this.id);
|
|
1277
|
+
if (storedState !== void 0) {
|
|
1275
1278
|
this.log.hydrate(storedState);
|
|
1276
1279
|
}
|
|
1277
1280
|
}
|
|
@@ -1280,28 +1283,35 @@ var StarciteSession = class {
|
|
|
1280
1283
|
*
|
|
1281
1284
|
* The SDK manages `actor`, `producer_id`, and `producer_seq` automatically.
|
|
1282
1285
|
*/
|
|
1283
|
-
|
|
1286
|
+
append(input, options) {
|
|
1284
1287
|
const parsed = SessionAppendInputSchema.parse(input);
|
|
1285
|
-
this.
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1288
|
+
const runAppend = this.appendTask.then(async () => {
|
|
1289
|
+
this.producerSeq += 1;
|
|
1290
|
+
const result = await this.appendRaw(
|
|
1291
|
+
{
|
|
1292
|
+
type: parsed.type ?? "content",
|
|
1293
|
+
payload: parsed.payload ?? { text: parsed.text },
|
|
1294
|
+
actor: parsed.actor ?? this.identity.toActor(),
|
|
1295
|
+
producer_id: this.producerId,
|
|
1296
|
+
producer_seq: this.producerSeq,
|
|
1297
|
+
source: parsed.source ?? "agent",
|
|
1298
|
+
metadata: parsed.metadata,
|
|
1299
|
+
refs: parsed.refs,
|
|
1300
|
+
idempotency_key: parsed.idempotencyKey,
|
|
1301
|
+
expected_seq: parsed.expectedSeq
|
|
1302
|
+
},
|
|
1303
|
+
options
|
|
1304
|
+
);
|
|
1305
|
+
return {
|
|
1306
|
+
seq: result.seq,
|
|
1307
|
+
deduped: result.deduped
|
|
1308
|
+
};
|
|
1309
|
+
});
|
|
1310
|
+
this.appendTask = runAppend.then(
|
|
1311
|
+
() => void 0,
|
|
1312
|
+
() => void 0
|
|
1300
1313
|
);
|
|
1301
|
-
return
|
|
1302
|
-
seq: result.seq,
|
|
1303
|
-
deduped: result.deduped
|
|
1304
|
-
};
|
|
1314
|
+
return runAppend;
|
|
1305
1315
|
}
|
|
1306
1316
|
/**
|
|
1307
1317
|
* Appends a raw event payload as-is. Caller manages all fields.
|
|
@@ -1318,11 +1328,33 @@ var StarciteSession = class {
|
|
|
1318
1328
|
AppendEventResponseSchema
|
|
1319
1329
|
);
|
|
1320
1330
|
}
|
|
1321
|
-
on(eventName, listener) {
|
|
1331
|
+
on(eventName, listener, options) {
|
|
1322
1332
|
if (eventName === "event") {
|
|
1323
1333
|
const eventListener = listener;
|
|
1324
1334
|
if (!this.eventSubscriptions.has(eventListener)) {
|
|
1325
|
-
const
|
|
1335
|
+
const eventOptions = options;
|
|
1336
|
+
const replay = eventOptions?.replay ?? true;
|
|
1337
|
+
const replayCutoffSeq = replay ? this.log.lastSeq : -1;
|
|
1338
|
+
const schema = eventOptions?.schema;
|
|
1339
|
+
const dispatch = (event) => {
|
|
1340
|
+
const parsedEvent = this.parseOnEvent(event, schema);
|
|
1341
|
+
if (!parsedEvent) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
const classifiedContext = this.resolveEventContext(
|
|
1345
|
+
event.seq,
|
|
1346
|
+
replayCutoffSeq,
|
|
1347
|
+
this.liveSyncCatchUpActive
|
|
1348
|
+
);
|
|
1349
|
+
try {
|
|
1350
|
+
this.observeEventListenerResult(
|
|
1351
|
+
eventListener(parsedEvent, classifiedContext)
|
|
1352
|
+
);
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
this.emitStreamError(error);
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
const unsubscribe = this.log.subscribe(dispatch, { replay });
|
|
1326
1358
|
this.eventSubscriptions.set(eventListener, unsubscribe);
|
|
1327
1359
|
}
|
|
1328
1360
|
this.ensureLiveSync();
|
|
@@ -1384,77 +1416,195 @@ var StarciteSession = class {
|
|
|
1384
1416
|
this.persistLogState();
|
|
1385
1417
|
}
|
|
1386
1418
|
/**
|
|
1387
|
-
* Returns a stable
|
|
1419
|
+
* Returns a stable view of the current canonical in-memory log state.
|
|
1388
1420
|
*/
|
|
1389
|
-
|
|
1390
|
-
return this.log.
|
|
1391
|
-
}
|
|
1392
|
-
/**
|
|
1393
|
-
* Streams tail events one at a time via callback.
|
|
1394
|
-
*/
|
|
1395
|
-
async tail(onEvent, options = {}) {
|
|
1396
|
-
await this.tailBatches(async (batch) => {
|
|
1397
|
-
for (const event of batch) {
|
|
1398
|
-
await onEvent(event);
|
|
1399
|
-
}
|
|
1400
|
-
}, options);
|
|
1421
|
+
state() {
|
|
1422
|
+
return this.log.state(this.liveSyncTask !== void 0);
|
|
1401
1423
|
}
|
|
1402
1424
|
/**
|
|
1403
|
-
*
|
|
1425
|
+
* Returns the retained canonical event list.
|
|
1404
1426
|
*/
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
sessionId: this.id,
|
|
1408
|
-
token: this.token,
|
|
1409
|
-
websocketBaseUrl: this.transport.websocketBaseUrl,
|
|
1410
|
-
websocketFactory: this.transport.websocketFactory,
|
|
1411
|
-
options
|
|
1412
|
-
}).subscribe(onBatch);
|
|
1427
|
+
events() {
|
|
1428
|
+
return this.log.events;
|
|
1413
1429
|
}
|
|
1414
1430
|
/**
|
|
1415
|
-
*
|
|
1431
|
+
* Streams canonical events as an async iterator.
|
|
1432
|
+
*
|
|
1433
|
+
* Replay semantics and schema validation mirror `session.on("event", ...)`.
|
|
1416
1434
|
*/
|
|
1417
|
-
|
|
1418
|
-
const {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1435
|
+
tail(options = {}) {
|
|
1436
|
+
const { replay = true, schema, ...tailOptions } = options;
|
|
1437
|
+
const replayCutoffSeq = replay ? this.log.lastSeq : -1;
|
|
1438
|
+
const startCursor = tailOptions.cursor ?? this.log.lastSeq;
|
|
1439
|
+
const session = this;
|
|
1440
|
+
const parseEvent = (event) => session.parseTailEvent(event, schema);
|
|
1441
|
+
return {
|
|
1442
|
+
async *[Symbol.asyncIterator]() {
|
|
1443
|
+
if (replay) {
|
|
1444
|
+
for (const replayEvent of session.log.events) {
|
|
1445
|
+
yield {
|
|
1446
|
+
event: parseEvent(replayEvent),
|
|
1447
|
+
context: { phase: "replay", replayed: true }
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
yield* session.iterateLiveTail({
|
|
1452
|
+
parseEvent,
|
|
1453
|
+
replayCutoffSeq,
|
|
1454
|
+
startCursor,
|
|
1455
|
+
tailOptions
|
|
1456
|
+
});
|
|
1434
1457
|
}
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
parseOnEvent(event, schema) {
|
|
1461
|
+
if (!schema) {
|
|
1462
|
+
return event;
|
|
1435
1463
|
}
|
|
1436
|
-
|
|
1464
|
+
try {
|
|
1465
|
+
return schema.parse(event);
|
|
1466
|
+
} catch (error) {
|
|
1467
|
+
this.emitStreamError(
|
|
1468
|
+
new StarciteError(
|
|
1469
|
+
`session.on("event") schema validation failed for session '${this.id}': ${error instanceof Error ? error.message : String(error)}`
|
|
1470
|
+
)
|
|
1471
|
+
);
|
|
1472
|
+
return void 0;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
parseTailEvent(event, schema) {
|
|
1476
|
+
if (!schema) {
|
|
1477
|
+
return event;
|
|
1478
|
+
}
|
|
1479
|
+
try {
|
|
1480
|
+
return schema.parse(event);
|
|
1481
|
+
} catch (error) {
|
|
1482
|
+
throw new StarciteError(
|
|
1483
|
+
`session.tail() schema validation failed for session '${this.id}': ${error instanceof Error ? error.message : String(error)}`
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
resolveEventContext(eventSeq, replayCutoffSeq, forceReplay = false) {
|
|
1488
|
+
const replayed = forceReplay || eventSeq <= replayCutoffSeq;
|
|
1489
|
+
return replayed ? { phase: "replay", replayed: true } : { phase: "live", replayed: false };
|
|
1490
|
+
}
|
|
1491
|
+
observeEventListenerResult(result) {
|
|
1492
|
+
Promise.resolve(result).catch((error) => {
|
|
1493
|
+
this.emitStreamError(error);
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
createTailAbortController(outerSignal) {
|
|
1497
|
+
const controller = new AbortController();
|
|
1498
|
+
if (!outerSignal) {
|
|
1499
|
+
return { controller, detach: () => void 0 };
|
|
1500
|
+
}
|
|
1501
|
+
const abortFromOuterSignal = () => {
|
|
1502
|
+
controller.abort(outerSignal.reason);
|
|
1503
|
+
};
|
|
1504
|
+
if (outerSignal.aborted) {
|
|
1505
|
+
controller.abort(outerSignal.reason);
|
|
1506
|
+
return { controller, detach: () => void 0 };
|
|
1507
|
+
}
|
|
1508
|
+
outerSignal.addEventListener("abort", abortFromOuterSignal, { once: true });
|
|
1509
|
+
return {
|
|
1510
|
+
controller,
|
|
1511
|
+
detach: () => {
|
|
1512
|
+
outerSignal.removeEventListener("abort", abortFromOuterSignal);
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
createTailRuntime({
|
|
1517
|
+
parseEvent,
|
|
1518
|
+
replayCutoffSeq,
|
|
1519
|
+
startCursor,
|
|
1520
|
+
tailOptions
|
|
1521
|
+
}) {
|
|
1522
|
+
const queue = [];
|
|
1523
|
+
let notify;
|
|
1524
|
+
let done = false;
|
|
1525
|
+
let failure;
|
|
1526
|
+
const shouldApplyToLog = tailOptions.agent === void 0;
|
|
1527
|
+
const { controller, detach } = this.createTailAbortController(
|
|
1528
|
+
tailOptions.signal
|
|
1529
|
+
);
|
|
1530
|
+
const wake = () => {
|
|
1531
|
+
notify?.();
|
|
1532
|
+
};
|
|
1533
|
+
const streamTask = new TailStream({
|
|
1437
1534
|
sessionId: this.id,
|
|
1438
1535
|
token: this.token,
|
|
1439
1536
|
websocketBaseUrl: this.transport.websocketBaseUrl,
|
|
1440
1537
|
websocketFactory: this.transport.websocketFactory,
|
|
1441
1538
|
options: {
|
|
1442
1539
|
...tailOptions,
|
|
1443
|
-
cursor
|
|
1540
|
+
cursor: startCursor,
|
|
1541
|
+
signal: controller.signal
|
|
1542
|
+
}
|
|
1543
|
+
}).subscribe((batch) => {
|
|
1544
|
+
const queuedEvents = shouldApplyToLog ? this.log.applyBatch(batch) : batch;
|
|
1545
|
+
if (shouldApplyToLog && queuedEvents.length > 0) {
|
|
1546
|
+
this.persistLogState();
|
|
1444
1547
|
}
|
|
1548
|
+
for (const event of queuedEvents) {
|
|
1549
|
+
queue.push({
|
|
1550
|
+
event: parseEvent(event),
|
|
1551
|
+
context: this.resolveEventContext(event.seq, replayCutoffSeq)
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
wake();
|
|
1555
|
+
}).catch((error) => {
|
|
1556
|
+
failure = error;
|
|
1557
|
+
}).finally(() => {
|
|
1558
|
+
done = true;
|
|
1559
|
+
wake();
|
|
1445
1560
|
});
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
`consume() failed to save cursor for session '${this.id}': ${error instanceof Error ? error.message : String(error)}`
|
|
1454
|
-
);
|
|
1561
|
+
return {
|
|
1562
|
+
next: async () => {
|
|
1563
|
+
while (queue.length === 0 && !done && !failure) {
|
|
1564
|
+
await new Promise((resolve) => {
|
|
1565
|
+
notify = resolve;
|
|
1566
|
+
});
|
|
1567
|
+
notify = void 0;
|
|
1455
1568
|
}
|
|
1569
|
+
const next = queue.shift();
|
|
1570
|
+
return next;
|
|
1571
|
+
},
|
|
1572
|
+
getFailure: () => failure,
|
|
1573
|
+
dispose: async () => {
|
|
1574
|
+
controller.abort();
|
|
1575
|
+
detach();
|
|
1576
|
+
await streamTask;
|
|
1456
1577
|
}
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
async *iterateLiveTail({
|
|
1581
|
+
parseEvent,
|
|
1582
|
+
replayCutoffSeq,
|
|
1583
|
+
startCursor,
|
|
1584
|
+
tailOptions
|
|
1585
|
+
}) {
|
|
1586
|
+
const runtime = this.createTailRuntime({
|
|
1587
|
+
parseEvent,
|
|
1588
|
+
replayCutoffSeq,
|
|
1589
|
+
startCursor,
|
|
1590
|
+
tailOptions
|
|
1457
1591
|
});
|
|
1592
|
+
try {
|
|
1593
|
+
while (true) {
|
|
1594
|
+
const next = await runtime.next();
|
|
1595
|
+
if (next) {
|
|
1596
|
+
yield next;
|
|
1597
|
+
continue;
|
|
1598
|
+
}
|
|
1599
|
+
const failure = runtime.getFailure();
|
|
1600
|
+
if (failure) {
|
|
1601
|
+
throw failure;
|
|
1602
|
+
}
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
} finally {
|
|
1606
|
+
await runtime.dispose();
|
|
1607
|
+
}
|
|
1458
1608
|
}
|
|
1459
1609
|
emitStreamError(error) {
|
|
1460
1610
|
const streamError = error instanceof Error ? error : new StarciteError(`Session stream failed: ${String(error)}`);
|
|
@@ -1479,67 +1629,94 @@ var StarciteSession = class {
|
|
|
1479
1629
|
}).finally(() => {
|
|
1480
1630
|
this.liveSyncTask = void 0;
|
|
1481
1631
|
this.liveSyncController = void 0;
|
|
1632
|
+
if (this.eventSubscriptions.size > 0) {
|
|
1633
|
+
this.ensureLiveSync();
|
|
1634
|
+
}
|
|
1482
1635
|
});
|
|
1483
1636
|
}
|
|
1484
1637
|
async runLiveSync(signal) {
|
|
1638
|
+
let shouldRunCatchUpPass = this.log.lastSeq === 0;
|
|
1639
|
+
let retryDelayMs = 250;
|
|
1485
1640
|
while (!signal.aborted && this.eventSubscriptions.size > 0) {
|
|
1486
|
-
|
|
1487
|
-
sessionId: this.id,
|
|
1488
|
-
token: this.token,
|
|
1489
|
-
websocketBaseUrl: this.transport.websocketBaseUrl,
|
|
1490
|
-
websocketFactory: this.transport.websocketFactory,
|
|
1491
|
-
options: {
|
|
1492
|
-
cursor: this.log.lastSeq,
|
|
1493
|
-
signal
|
|
1494
|
-
}
|
|
1495
|
-
});
|
|
1641
|
+
this.liveSyncCatchUpActive = shouldRunCatchUpPass;
|
|
1496
1642
|
try {
|
|
1497
|
-
await
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
this.persistLogState();
|
|
1501
|
-
}
|
|
1502
|
-
});
|
|
1643
|
+
await this.subscribeLiveSyncPass(signal, !shouldRunCatchUpPass);
|
|
1644
|
+
shouldRunCatchUpPass = false;
|
|
1645
|
+
retryDelayMs = 250;
|
|
1503
1646
|
} catch (error) {
|
|
1504
1647
|
if (signal.aborted) {
|
|
1505
1648
|
return;
|
|
1506
1649
|
}
|
|
1507
1650
|
if (error instanceof SessionLogGapError) {
|
|
1651
|
+
shouldRunCatchUpPass = true;
|
|
1508
1652
|
continue;
|
|
1509
1653
|
}
|
|
1510
|
-
|
|
1654
|
+
this.emitStreamError(error);
|
|
1655
|
+
shouldRunCatchUpPass = true;
|
|
1656
|
+
await this.waitForLiveSyncRetry(retryDelayMs, signal);
|
|
1657
|
+
retryDelayMs = Math.min(retryDelayMs * 2, 5e3);
|
|
1658
|
+
} finally {
|
|
1659
|
+
this.liveSyncCatchUpActive = false;
|
|
1511
1660
|
}
|
|
1512
1661
|
}
|
|
1513
1662
|
}
|
|
1663
|
+
async subscribeLiveSyncPass(signal, follow) {
|
|
1664
|
+
const stream = new TailStream({
|
|
1665
|
+
sessionId: this.id,
|
|
1666
|
+
token: this.token,
|
|
1667
|
+
websocketBaseUrl: this.transport.websocketBaseUrl,
|
|
1668
|
+
websocketFactory: this.transport.websocketFactory,
|
|
1669
|
+
options: {
|
|
1670
|
+
cursor: this.log.lastSeq,
|
|
1671
|
+
follow,
|
|
1672
|
+
signal
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
await stream.subscribe((batch) => {
|
|
1676
|
+
const appliedEvents = this.log.applyBatch(batch);
|
|
1677
|
+
if (appliedEvents.length > 0) {
|
|
1678
|
+
this.persistLogState();
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1514
1682
|
persistLogState() {
|
|
1683
|
+
if (!this.store) {
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1515
1686
|
this.store.save(this.id, {
|
|
1516
1687
|
cursor: this.log.cursor,
|
|
1517
|
-
events: [...this.log.events]
|
|
1688
|
+
events: [...this.log.events],
|
|
1689
|
+
metadata: {
|
|
1690
|
+
schemaVersion: 1,
|
|
1691
|
+
updatedAtMs: Date.now()
|
|
1692
|
+
}
|
|
1518
1693
|
});
|
|
1519
1694
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1695
|
+
waitForLiveSyncRetry(delayMs, signal) {
|
|
1696
|
+
if (delayMs <= 0 || signal.aborted) {
|
|
1697
|
+
return Promise.resolve();
|
|
1698
|
+
}
|
|
1699
|
+
return new Promise((resolve) => {
|
|
1700
|
+
let settled = false;
|
|
1701
|
+
const timer = setTimeout(() => {
|
|
1702
|
+
if (settled) {
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
settled = true;
|
|
1706
|
+
signal.removeEventListener("abort", onAbort);
|
|
1707
|
+
resolve();
|
|
1708
|
+
}, delayMs);
|
|
1709
|
+
const onAbort = () => {
|
|
1710
|
+
if (settled) {
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
settled = true;
|
|
1714
|
+
clearTimeout(timer);
|
|
1715
|
+
signal.removeEventListener("abort", onAbort);
|
|
1716
|
+
resolve();
|
|
1717
|
+
};
|
|
1718
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1719
|
+
});
|
|
1543
1720
|
}
|
|
1544
1721
|
};
|
|
1545
1722
|
|
|
@@ -1579,7 +1756,7 @@ var Starcite = class {
|
|
|
1579
1756
|
}
|
|
1580
1757
|
this.authBaseUrl = resolveAuthBaseUrl(options.authUrl, apiKey);
|
|
1581
1758
|
const websocketFactory = options.websocketFactory ?? defaultWebSocketFactory;
|
|
1582
|
-
this.store = options.store
|
|
1759
|
+
this.store = options.store;
|
|
1583
1760
|
this.transport = {
|
|
1584
1761
|
baseUrl,
|
|
1585
1762
|
websocketBaseUrl: toWebSocketBaseUrl(baseUrl),
|
|
@@ -1750,53 +1927,90 @@ var Starcite = class {
|
|
|
1750
1927
|
}
|
|
1751
1928
|
};
|
|
1752
1929
|
|
|
1753
|
-
// src/
|
|
1930
|
+
// src/session-store.ts
|
|
1931
|
+
import { z as z5 } from "zod";
|
|
1754
1932
|
var DEFAULT_KEY_PREFIX = "starcite";
|
|
1755
|
-
var
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1933
|
+
var SessionStoreMetadataSchema = z5.object({
|
|
1934
|
+
schemaVersion: z5.literal(1),
|
|
1935
|
+
updatedAtMs: z5.number().int().nonnegative()
|
|
1936
|
+
});
|
|
1937
|
+
var SessionStoreStateSchema = z5.object({
|
|
1938
|
+
cursor: z5.number().int().nonnegative(),
|
|
1939
|
+
events: z5.array(TailEventSchema),
|
|
1940
|
+
metadata: SessionStoreMetadataSchema.optional()
|
|
1941
|
+
});
|
|
1942
|
+
function cloneEvents(events) {
|
|
1943
|
+
return events.map((event) => structuredClone(event));
|
|
1944
|
+
}
|
|
1945
|
+
function cloneState(state) {
|
|
1946
|
+
return {
|
|
1947
|
+
cursor: state.cursor,
|
|
1948
|
+
events: cloneEvents(state.events),
|
|
1949
|
+
metadata: state.metadata ? { ...state.metadata } : void 0
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1952
|
+
var MemoryStore = class {
|
|
1953
|
+
sessions = /* @__PURE__ */ new Map();
|
|
1760
1954
|
load(sessionId) {
|
|
1761
|
-
|
|
1955
|
+
const stored = this.sessions.get(sessionId);
|
|
1956
|
+
return stored ? cloneState(stored) : void 0;
|
|
1762
1957
|
}
|
|
1763
|
-
save(sessionId,
|
|
1764
|
-
this.
|
|
1958
|
+
save(sessionId, state) {
|
|
1959
|
+
this.sessions.set(sessionId, cloneState(state));
|
|
1960
|
+
}
|
|
1961
|
+
clear(sessionId) {
|
|
1962
|
+
this.sessions.delete(sessionId);
|
|
1765
1963
|
}
|
|
1766
1964
|
};
|
|
1767
|
-
var
|
|
1965
|
+
var WebStorageSessionStore = class {
|
|
1768
1966
|
storage;
|
|
1769
1967
|
keyForSession;
|
|
1968
|
+
stateSchema;
|
|
1770
1969
|
constructor(storage, options = {}) {
|
|
1771
1970
|
this.storage = storage;
|
|
1772
1971
|
const prefix = options.keyPrefix?.trim() || DEFAULT_KEY_PREFIX;
|
|
1773
|
-
this.keyForSession = options.keyForSession ?? ((sessionId) => `${prefix}:${sessionId}:
|
|
1972
|
+
this.keyForSession = options.keyForSession ?? ((sessionId) => `${prefix}:${sessionId}:sessionStore`);
|
|
1973
|
+
this.stateSchema = options.stateSchema ?? SessionStoreStateSchema;
|
|
1774
1974
|
}
|
|
1775
1975
|
load(sessionId) {
|
|
1776
1976
|
const raw = this.storage.getItem(this.keyForSession(sessionId));
|
|
1777
1977
|
if (raw === null) {
|
|
1778
1978
|
return void 0;
|
|
1779
1979
|
}
|
|
1780
|
-
|
|
1781
|
-
|
|
1980
|
+
let decoded;
|
|
1981
|
+
try {
|
|
1982
|
+
decoded = JSON.parse(raw);
|
|
1983
|
+
} catch {
|
|
1984
|
+
return void 0;
|
|
1985
|
+
}
|
|
1986
|
+
const parsed = this.stateSchema.safeParse(decoded);
|
|
1987
|
+
if (!parsed.success) {
|
|
1988
|
+
return void 0;
|
|
1989
|
+
}
|
|
1990
|
+
return cloneState(parsed.data);
|
|
1782
1991
|
}
|
|
1783
|
-
save(sessionId,
|
|
1784
|
-
this.storage.setItem(
|
|
1992
|
+
save(sessionId, state) {
|
|
1993
|
+
this.storage.setItem(
|
|
1994
|
+
this.keyForSession(sessionId),
|
|
1995
|
+
JSON.stringify(cloneState(state))
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
clear(sessionId) {
|
|
1999
|
+
this.storage.removeItem?.(this.keyForSession(sessionId));
|
|
1785
2000
|
}
|
|
1786
2001
|
};
|
|
1787
|
-
var
|
|
2002
|
+
var LocalStorageSessionStore = class extends WebStorageSessionStore {
|
|
1788
2003
|
constructor(options = {}) {
|
|
1789
2004
|
if (typeof localStorage === "undefined") {
|
|
1790
2005
|
throw new StarciteError(
|
|
1791
|
-
"localStorage is not available in this runtime. Use
|
|
2006
|
+
"localStorage is not available in this runtime. Use WebStorageSessionStore with a custom storage adapter."
|
|
1792
2007
|
);
|
|
1793
2008
|
}
|
|
1794
2009
|
super(localStorage, options);
|
|
1795
2010
|
}
|
|
1796
2011
|
};
|
|
1797
2012
|
export {
|
|
1798
|
-
|
|
1799
|
-
LocalStorageCursorStore,
|
|
2013
|
+
LocalStorageSessionStore,
|
|
1800
2014
|
MemoryStore,
|
|
1801
2015
|
SessionLogConflictError,
|
|
1802
2016
|
SessionLogGapError,
|
|
@@ -1810,6 +2024,6 @@ export {
|
|
|
1810
2024
|
StarciteSession,
|
|
1811
2025
|
StarciteTailError,
|
|
1812
2026
|
StarciteTokenExpiredError,
|
|
1813
|
-
|
|
2027
|
+
WebStorageSessionStore
|
|
1814
2028
|
};
|
|
1815
2029
|
//# sourceMappingURL=index.js.map
|