@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/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
- if (!(tenantId && id && claims.principal_type)) {
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: claims.principal_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
- getSnapshot(syncing) {
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 ?? 4e3;
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.load(this.id);
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
- async append(input, options) {
1286
+ append(input, options) {
1284
1287
  const parsed = SessionAppendInputSchema.parse(input);
1285
- this.producerSeq += 1;
1286
- const result = await this.appendRaw(
1287
- {
1288
- type: parsed.type ?? "content",
1289
- payload: parsed.payload ?? { text: parsed.text },
1290
- actor: parsed.actor ?? this.identity.toActor(),
1291
- producer_id: this.producerId,
1292
- producer_seq: this.producerSeq,
1293
- source: parsed.source ?? "agent",
1294
- metadata: parsed.metadata,
1295
- refs: parsed.refs,
1296
- idempotency_key: parsed.idempotencyKey,
1297
- expected_seq: parsed.expectedSeq
1298
- },
1299
- options
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 unsubscribe = this.log.subscribe(eventListener, { replay: true });
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 snapshot of the current canonical in-memory log.
1419
+ * Returns a stable view of the current canonical in-memory log state.
1388
1420
  */
1389
- getSnapshot() {
1390
- return this.log.getSnapshot(this.liveSyncTask !== void 0);
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
- * Streams tail event batches grouped by incoming frame via callback.
1425
+ * Returns the retained canonical event list.
1404
1426
  */
1405
- async tailBatches(onBatch, options = {}) {
1406
- await new TailStream({
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
- * Durably consumes events and checkpoints `event.seq` after each successful handler invocation.
1431
+ * Streams canonical events as an async iterator.
1432
+ *
1433
+ * Replay semantics and schema validation mirror `session.on("event", ...)`.
1416
1434
  */
1417
- async consume(options) {
1418
- const {
1419
- cursorStore,
1420
- handler,
1421
- cursor: requestedCursor,
1422
- ...tailOptions
1423
- } = options;
1424
- let cursor;
1425
- if (requestedCursor !== void 0) {
1426
- cursor = requestedCursor;
1427
- } else {
1428
- try {
1429
- cursor = await cursorStore.load(this.id) ?? 0;
1430
- } catch (error) {
1431
- throw new StarciteError(
1432
- `consume() failed to load cursor for session '${this.id}': ${error instanceof Error ? error.message : String(error)}`
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
- const stream = new TailStream({
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
- await stream.subscribe(async (batch) => {
1447
- for (const event of batch) {
1448
- await handler(event);
1449
- try {
1450
- await cursorStore.save(this.id, event.seq);
1451
- } catch (error) {
1452
- throw new StarciteError(
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
- const stream = new TailStream({
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 stream.subscribe((batch) => {
1498
- const appliedEvents = this.log.applyBatch(batch);
1499
- if (appliedEvents.length > 0) {
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
- throw error;
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
- // src/session-store.ts
1523
- function cloneEvents(events) {
1524
- return events.map((event) => structuredClone(event));
1525
- }
1526
- function cloneState(state) {
1527
- return {
1528
- cursor: state.cursor,
1529
- events: cloneEvents(state.events)
1530
- };
1531
- }
1532
- var MemoryStore = class {
1533
- sessions = /* @__PURE__ */ new Map();
1534
- load(sessionId) {
1535
- const stored = this.sessions.get(sessionId);
1536
- return stored ? cloneState(stored) : void 0;
1537
- }
1538
- save(sessionId, state) {
1539
- this.sessions.set(sessionId, cloneState(state));
1540
- }
1541
- clear(sessionId) {
1542
- this.sessions.delete(sessionId);
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 ?? new MemoryStore();
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/cursor-store.ts
1930
+ // src/session-store.ts
1931
+ import { z as z5 } from "zod";
1754
1932
  var DEFAULT_KEY_PREFIX = "starcite";
1755
- var InMemoryCursorStore = class {
1756
- cursors;
1757
- constructor(initial = {}) {
1758
- this.cursors = new Map(Object.entries(initial));
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
- return this.cursors.get(sessionId);
1955
+ const stored = this.sessions.get(sessionId);
1956
+ return stored ? cloneState(stored) : void 0;
1762
1957
  }
1763
- save(sessionId, cursor) {
1764
- this.cursors.set(sessionId, cursor);
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 WebStorageCursorStore = class {
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}:lastSeq`);
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
- const parsed = Number.parseInt(raw, 10);
1781
- return Number.isInteger(parsed) && parsed >= 0 ? parsed : void 0;
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, cursor) {
1784
- this.storage.setItem(this.keyForSession(sessionId), `${cursor}`);
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 LocalStorageCursorStore = class extends WebStorageCursorStore {
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 WebStorageCursorStore with a custom storage adapter."
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
- InMemoryCursorStore,
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
- WebStorageCursorStore
2027
+ WebStorageSessionStore
1814
2028
  };
1815
2029
  //# sourceMappingURL=index.js.map