@anuma/sdk 9.1.0 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11607,7 +11607,8 @@ declare class RemoteMemoryError extends Error {
11607
11607
  readonly status: number;
11608
11608
  readonly code?: string | undefined;
11609
11609
  readonly retryAfterMs?: number | undefined;
11610
- constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
11610
+ readonly rateLimitBucket?: string | undefined;
11611
+ constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined, rateLimitBucket?: string | undefined);
11611
11612
  }
11612
11613
  /**
11613
11614
  * Remote persistence foundation for MemoryStore, not yet its recall/retain implementation.
@@ -11616,6 +11617,7 @@ declare class RemoteMemoryError extends Error {
11616
11617
  * Migration must have activated the account under the canonical key before construction.
11617
11618
  */
11618
11619
  interface RemoteMemoryPersistence extends RemoteTopicPersistence, RemoteMemoryWorkPersistence {
11620
+ supportsRealtimeChanges?: boolean;
11619
11621
  counts(): Promise<MemoryCounts>;
11620
11622
  temporal(window: {
11621
11623
  start: number;
@@ -11747,6 +11749,12 @@ interface RemoteMemoryStoreOptions {
11747
11749
  graphRanking?: RecallFactSource["graphRanking"];
11748
11750
  temporalRanking?: RecallFactSource["temporalRanking"];
11749
11751
  pollIntervalMs?: number;
11752
+ activity?: {
11753
+ isActive: () => boolean;
11754
+ subscribe: (onChange: () => void) => () => void;
11755
+ };
11756
+ /** Report connection state on subscribe/reconnect and true on each account memory change. */
11757
+ subscribeChanges?: (onChange: (connected: boolean) => void) => () => void;
11750
11758
  }
11751
11759
  declare class RemoteMemoryPartialCreateError extends Error {
11752
11760
  readonly created: StoredVaultMemory[];
@@ -10287,11 +10287,12 @@ function isRemoteWorkLeaseExpired(error) {
10287
10287
 
10288
10288
  // src/lib/memory/store/remotePersistence.ts
10289
10289
  var RemoteMemoryError = class extends Error {
10290
- constructor(message, status, code, retryAfterMs) {
10290
+ constructor(message, status, code, retryAfterMs, rateLimitBucket) {
10291
10291
  super(message);
10292
10292
  this.status = status;
10293
10293
  this.code = code;
10294
10294
  this.retryAfterMs = retryAfterMs;
10295
+ this.rateLimitBucket = rateLimitBucket;
10295
10296
  this.name = "RemoteMemoryError";
10296
10297
  }
10297
10298
  };
@@ -10386,6 +10387,14 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
10386
10387
  throw new Error("timeoutMs must be a positive number");
10387
10388
  const root = base.href.replace(/\/$/, "") + apiPath;
10388
10389
  const fetcher = options.fetch ?? globalThis.fetch;
10390
+ const cooldowns = /* @__PURE__ */ new Map();
10391
+ const memoryBudget = (path, method) => {
10392
+ if (method === "PUT")
10393
+ return path === "/topics" ? "private-memory-import" : "private-memory-write";
10394
+ if (method === "POST" && ["/import", "/memories/batch", "/topics/import"].includes(path))
10395
+ return "private-memory-import";
10396
+ return "private-memory-read";
10397
+ };
10389
10398
  const request = async (path, init = {}, signal) => {
10390
10399
  const controller = new AbortController();
10391
10400
  let timedOut = false;
@@ -10409,6 +10418,25 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
10409
10418
  const token = await Promise.race([options.getToken(), aborted2]);
10410
10419
  if (controller.signal.aborted) await aborted2;
10411
10420
  if (!token) throw new RemoteMemoryError("Authentication required", 401);
10421
+ const pathname = path.split("?")[0];
10422
+ const route = `${init.method ?? "GET"} ${pathname}`;
10423
+ const budgets = ["*", route];
10424
+ if (apiPath === "/api/private-memories")
10425
+ budgets.push("private-memory-ip", memoryBudget(pathname, init.method ?? "GET"));
10426
+ for (const bucket of budgets) {
10427
+ const cooldown = cooldowns.get(bucket);
10428
+ if (!cooldown) continue;
10429
+ const remaining = cooldown.until - Date.now();
10430
+ if (remaining > 0)
10431
+ throw new RemoteMemoryError(
10432
+ cooldown.error.message,
10433
+ 429,
10434
+ cooldown.error.code,
10435
+ remaining,
10436
+ cooldown.error.rateLimitBucket
10437
+ );
10438
+ cooldowns.delete(bucket);
10439
+ }
10412
10440
  const response = await fetcher(root + path, {
10413
10441
  ...init,
10414
10442
  headers: {
@@ -10421,12 +10449,18 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
10421
10449
  if (!response.ok) {
10422
10450
  const body = await response.json().catch(() => null);
10423
10451
  const retryAfter = parseRetryAfterMs(response.headers.get("Retry-After"));
10424
- throw new RemoteMemoryError(
10452
+ const error = new RemoteMemoryError(
10425
10453
  record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
10426
10454
  response.status,
10427
10455
  record(body) && typeof body.code === "string" ? body.code : void 0,
10428
- retryAfter ?? void 0
10456
+ retryAfter ?? void 0,
10457
+ record(body) && typeof body.rate_limit_bucket === "string" ? body.rate_limit_bucket : void 0
10429
10458
  );
10459
+ if (response.status === 429 && retryAfter !== null && retryAfter > 0 && (!error.code || error.code === "rate_limited")) {
10460
+ const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket : record(body) && (body.limit_scope === "account" || body.limit_scope === "ip") && !error.rateLimitBucket ? "*" : route;
10461
+ cooldowns.set(bucket, { until: Date.now() + retryAfter, error });
10462
+ }
10463
+ throw error;
10430
10464
  }
10431
10465
  return await response.json();
10432
10466
  } catch (error) {
@@ -10666,6 +10700,7 @@ async function createRemoteMemoryPersistence(options) {
10666
10700
  return {
10667
10701
  ...createRemoteTopicPersistence(request),
10668
10702
  ...createRemoteWorkPersistence(request),
10703
+ supportsRealtimeChanges: account.realtime_changes === true,
10669
10704
  counts: async () => {
10670
10705
  const result = await request("/counts", {});
10671
10706
  if (!record(result) || ["live", "archived", "quarantined"].some(
@@ -23450,6 +23485,9 @@ var RemoteMemoryPartialCreateError = class extends Error {
23450
23485
  function rejectsInput(error) {
23451
23486
  return error instanceof EmbeddingHttpError && error.status !== void 0 && error.status >= 400 && error.status < 500 && error.status !== 429 && !isFatalEmbeddingError(error);
23452
23487
  }
23488
+ function rejectsMemoryWrite(error) {
23489
+ return error instanceof RemoteMemoryError && (error.status === 400 || error.status === 422) && (error.code === void 0 || error.code === "unknown_field");
23490
+ }
23453
23491
  function warnFailed(failed) {
23454
23492
  if (failed.length)
23455
23493
  getLogger().warn(
@@ -23537,16 +23575,47 @@ function createRemoteMemoryStore(options) {
23537
23575
  const { persistence, embeddingOptions } = options;
23538
23576
  const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
23539
23577
  const pollIntervalMs = options.pollIntervalMs ?? 6e4;
23578
+ const activity = options.activity ?? {
23579
+ isActive: () => (typeof document === "undefined" || document.visibilityState !== "hidden") && (typeof navigator === "undefined" || navigator.onLine !== false),
23580
+ subscribe: (onChange) => {
23581
+ if (typeof window === "undefined" || typeof document === "undefined") return () => {
23582
+ };
23583
+ document.addEventListener("visibilitychange", onChange);
23584
+ window.addEventListener("online", onChange);
23585
+ window.addEventListener("offline", onChange);
23586
+ return () => {
23587
+ document.removeEventListener("visibilitychange", onChange);
23588
+ window.removeEventListener("online", onChange);
23589
+ window.removeEventListener("offline", onChange);
23590
+ };
23591
+ }
23592
+ };
23540
23593
  const pipeline = createRemoteMemoryPipeline({
23541
23594
  ...options,
23542
23595
  graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
23543
23596
  temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
23544
23597
  });
23545
23598
  const subscribers = /* @__PURE__ */ new Set();
23599
+ const retainTopics = () => pollIntervalMs > 0 && [...subscribers].some((subscriber) => subscriber.options.topics);
23546
23600
  const seen = /* @__PURE__ */ new Map();
23601
+ const reads = /* @__PURE__ */ new Map();
23602
+ const metadataReads = /* @__PURE__ */ new Map();
23603
+ let topicSnapshot;
23604
+ let topicCatalog;
23605
+ const invalidateReads = () => {
23606
+ reads.clear();
23607
+ metadataReads.clear();
23608
+ topicSnapshot = void 0;
23609
+ topicCatalog = void 0;
23610
+ };
23547
23611
  let timer;
23612
+ let scheduledAt;
23613
+ let stopActivity;
23614
+ let stopChanges;
23615
+ let changesConnected = false;
23548
23616
  const notify = (change, records = []) => {
23549
- if (timer)
23617
+ invalidateReads();
23618
+ if (subscribers.size)
23550
23619
  for (const record2 of records) {
23551
23620
  const previous = seen.get(record2.memory.memory_id);
23552
23621
  if ((previous?.version ?? 0) + 1 === record2.version)
@@ -23570,8 +23639,37 @@ function createRemoteMemoryStore(options) {
23570
23639
  } while (cursor2 && records.length < max);
23571
23640
  return records.slice(0, max);
23572
23641
  };
23573
- const decrypted = (options2) => persistence.query(options2);
23574
- const metadata3 = (options2) => persistence.queryMetadata(options2);
23642
+ const shareRead = (inflight, options2, read) => {
23643
+ if (options2.signal) return read();
23644
+ const key = JSON.stringify(Object.entries(options2).sort(([a], [b]) => a.localeCompare(b)));
23645
+ const active = inflight.get(key);
23646
+ if (active) return active;
23647
+ const pending2 = read();
23648
+ inflight.set(key, pending2);
23649
+ const clear = () => {
23650
+ if (inflight.get(key) === pending2) inflight.delete(key);
23651
+ };
23652
+ void pending2.then(clear, clear);
23653
+ return pending2;
23654
+ };
23655
+ const decrypted = (options2) => shareRead(reads, options2, () => persistence.query(options2));
23656
+ const metadata3 = (options2) => shareRead(
23657
+ metadataReads,
23658
+ options2,
23659
+ () => persistence.queryMetadata(options2)
23660
+ );
23661
+ const readTopics = () => {
23662
+ if (topicCatalog) return topicCatalog;
23663
+ const pending2 = persistence.topics();
23664
+ topicCatalog = pending2;
23665
+ const clear = () => {
23666
+ if (topicCatalog === pending2) topicCatalog = void 0;
23667
+ };
23668
+ void pending2.then(() => {
23669
+ if (!retainTopics()) clear();
23670
+ }, clear);
23671
+ return pending2;
23672
+ };
23575
23673
  const enumerate = (filters, max = Infinity) => pages(decrypted, filters, max);
23576
23674
  const memoriesByTopics = async (names) => {
23577
23675
  const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
@@ -24025,11 +24123,11 @@ function createRemoteMemoryStore(options) {
24025
24123
  };
24026
24124
  const changesSince = async (cursor2, pending2) => {
24027
24125
  const records = [];
24028
- const failed = /* @__PURE__ */ new Set();
24126
+ const failed = /* @__PURE__ */ new Map();
24029
24127
  const collect = (page) => {
24030
24128
  warnFailed(page.failed);
24031
24129
  records.push(...page.items);
24032
- for (const failure of page.failed) failed.add(failure.memory_id);
24130
+ for (const failure of page.failed) failed.set(failure.memory_id, failure.version);
24033
24131
  };
24034
24132
  let resume = cursor2;
24035
24133
  let next;
@@ -24063,25 +24161,72 @@ function createRemoteMemoryStore(options) {
24063
24161
  let ready = false;
24064
24162
  let cursor;
24065
24163
  let pending = /* @__PURE__ */ new Set();
24164
+ let failedVersions = /* @__PURE__ */ new Map();
24066
24165
  let topicFingerprint;
24067
24166
  let polling = false;
24167
+ let pollRequested = false;
24168
+ let failures = 0;
24169
+ let retryAt = 0;
24170
+ const backoff = (error) => {
24171
+ failures++;
24172
+ retryAt = Date.now() + Math.max(
24173
+ error instanceof RemoteMemoryError ? error.retryAfterMs ?? 0 : 0,
24174
+ Math.min(pollIntervalMs * 2 ** Math.min(failures - 1, 10), 15 * 6e4)
24175
+ );
24176
+ };
24177
+ const schedulePoll = (delay, keepEarlier = false) => {
24178
+ const at = Math.max(Date.now() + delay, retryAt);
24179
+ if (keepEarlier && timer && scheduledAt !== void 0 && scheduledAt <= at) return;
24180
+ if (timer) clearTimeout(timer);
24181
+ timer = void 0;
24182
+ scheduledAt = void 0;
24183
+ if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
24184
+ scheduledAt = at;
24185
+ timer = setTimeout(poll, Math.max(0, at - Date.now()));
24186
+ };
24068
24187
  const poll = () => {
24069
- if (polling) return;
24188
+ if (timer) clearTimeout(timer);
24189
+ timer = void 0;
24190
+ scheduledAt = void 0;
24191
+ if (!subscribers.size || pollIntervalMs <= 0 || !activity.isActive()) return;
24192
+ if (Date.now() < retryAt) {
24193
+ schedulePoll(0);
24194
+ return;
24195
+ }
24196
+ if (polling) {
24197
+ pollRequested = true;
24198
+ return;
24199
+ }
24070
24200
  polling = true;
24201
+ pollRequested = false;
24071
24202
  const current = generation;
24072
24203
  changesSince(cursor, pending).then(async ({ records, resume, failed }) => {
24073
24204
  let topicState;
24205
+ let topicFailed = false;
24074
24206
  if ([...subscribers].some((s) => s.options.topics))
24075
24207
  try {
24076
- topicState = JSON.stringify(
24077
- (await persistence.topics()).map((t) => [t.name, t.version])
24078
- );
24208
+ topicCatalog = void 0;
24209
+ topicState = JSON.stringify((await readTopics()).map((t) => [t.name, t.version]));
24079
24210
  } catch (error) {
24211
+ topicFailed = true;
24212
+ if (current === generation) backoff(error);
24080
24213
  getLogger().warn("[memory/remote-store] Topic subscription poll failed:", error);
24081
24214
  }
24082
24215
  if (current !== generation) return;
24216
+ if (!topicFailed) {
24217
+ failures = 0;
24218
+ retryAt = 0;
24219
+ }
24220
+ const failedChanged = [...failed].some(
24221
+ ([id2, version]) => failedVersions.get(id2) !== version
24222
+ );
24223
+ if (records.length || failedChanged || topicState !== void 0 && topicState !== topicFingerprint) {
24224
+ reads.clear();
24225
+ metadataReads.clear();
24226
+ topicSnapshot = void 0;
24227
+ }
24083
24228
  const changed = /* @__PURE__ */ new Set();
24084
- if (topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
24229
+ if (ready && failedChanged || topicState !== void 0 && topicFingerprint !== void 0 && topicState !== topicFingerprint) {
24085
24230
  for (const subscriber of subscribers)
24086
24231
  if (subscriber.options.topics) changed.add(subscriber);
24087
24232
  }
@@ -24098,15 +24243,40 @@ function createRemoteMemoryStore(options) {
24098
24243
  }
24099
24244
  ready = true;
24100
24245
  cursor = resume;
24101
- pending = failed;
24246
+ pending = new Set(failed.keys());
24247
+ failedVersions = failed;
24102
24248
  for (const subscriber of changed)
24103
24249
  if (subscribers.has(subscriber)) safely(subscriber.onChange);
24104
24250
  }).catch((error) => {
24251
+ if (current === generation) backoff(error);
24105
24252
  getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
24106
24253
  }).finally(() => {
24107
24254
  polling = false;
24255
+ schedulePoll(
24256
+ current !== generation ? 0 : pollRequested ? 200 : changesConnected ? Math.max(pollIntervalMs, 5 * 6e4) : pollIntervalMs
24257
+ );
24108
24258
  });
24109
24259
  };
24260
+ const refreshActivity = () => {
24261
+ if (timer) clearTimeout(timer);
24262
+ timer = void 0;
24263
+ if (!activity.isActive()) {
24264
+ stopChanges?.();
24265
+ stopChanges = void 0;
24266
+ changesConnected = false;
24267
+ return;
24268
+ }
24269
+ if (!stopChanges && persistence.supportsRealtimeChanges && options.subscribeChanges)
24270
+ stopChanges = options.subscribeChanges((connected) => {
24271
+ changesConnected = connected;
24272
+ if (polling) {
24273
+ pollRequested = true;
24274
+ return;
24275
+ }
24276
+ schedulePoll(connected ? 200 : 0, true);
24277
+ });
24278
+ poll();
24279
+ };
24110
24280
  const unrepairable = /* @__PURE__ */ new Set();
24111
24281
  let repairCursor;
24112
24282
  const repairEmbeddingsUnlocked = async ({
@@ -24162,40 +24332,78 @@ function createRemoteMemoryStore(options) {
24162
24332
  result.failed += targets.length;
24163
24333
  return finish();
24164
24334
  }
24165
- for (const [i, record2] of targets.entries()) {
24335
+ const writes = targets.flatMap((record2, i) => {
24166
24336
  const vector = vectors[i];
24167
24337
  if (!vector) {
24168
24338
  result.failed++;
24169
- continue;
24339
+ return [];
24170
24340
  }
24171
- await serialized(record2.memory.memory_id, async () => {
24172
- signal?.throwIfAborted();
24173
- try {
24174
- const [saved] = await persistence.putMany(
24175
- [
24176
- {
24177
- memory: {
24178
- ...record2.memory,
24179
- embedding: storedVector(vector),
24180
- embedding_model: model
24181
- },
24182
- expectedVersion: record2
24183
- }
24184
- ],
24185
- signal,
24186
- leaseToken
24187
- );
24188
- notify("embedding", [saved]);
24189
- repaired.add(record2.memory.memory_id);
24190
- result.reembedded++;
24191
- } catch (error) {
24341
+ try {
24342
+ return [
24343
+ {
24344
+ memory: {
24345
+ ...record2.memory,
24346
+ embedding: storedVector(vector),
24347
+ embedding_model: model
24348
+ },
24349
+ expectedVersion: record2
24350
+ }
24351
+ ];
24352
+ } catch {
24353
+ result.failed++;
24354
+ return [];
24355
+ }
24356
+ });
24357
+ for (const batch of chunks2(writes, MAX_BATCH)) {
24358
+ const continueRepair = await serializedAll(
24359
+ batch.map(({ memory }) => memory.memory_id),
24360
+ async () => {
24192
24361
  signal?.throwIfAborted();
24193
- if (isRemoteWorkLeaseExpired(error)) throw error;
24194
- if (error instanceof RemoteMemoryError && error.code === "version_conflict")
24195
- result.skippedConflict++;
24196
- else result.failed++;
24362
+ const commit = async (slice) => {
24363
+ const saved = await persistence.putMany(slice, signal, leaseToken);
24364
+ for (const record2 of saved) repaired.add(record2.memory.memory_id);
24365
+ result.reembedded += saved.length;
24366
+ notify("embedding", saved);
24367
+ };
24368
+ try {
24369
+ await commit(batch);
24370
+ } catch (error) {
24371
+ signal?.throwIfAborted();
24372
+ if (isRemoteWorkLeaseExpired(error)) throw error;
24373
+ if (!(error instanceof RemoteMemoryError && error.code === "version_conflict") && !rejectsMemoryWrite(error)) {
24374
+ result.failed += batch.length;
24375
+ return false;
24376
+ }
24377
+ if (batch.length === 1) {
24378
+ if (rejectsMemoryWrite(error)) {
24379
+ unrepairable.add(batch[0].memory.memory_id);
24380
+ result.failed++;
24381
+ } else result.skippedConflict++;
24382
+ return true;
24383
+ }
24384
+ for (const [index, write] of batch.entries()) {
24385
+ signal?.throwIfAborted();
24386
+ try {
24387
+ await commit([write]);
24388
+ } catch (error2) {
24389
+ signal?.throwIfAborted();
24390
+ if (isRemoteWorkLeaseExpired(error2)) throw error2;
24391
+ if (error2 instanceof RemoteMemoryError && error2.code === "version_conflict")
24392
+ result.skippedConflict++;
24393
+ else if (rejectsMemoryWrite(error2)) {
24394
+ unrepairable.add(write.memory.memory_id);
24395
+ result.failed++;
24396
+ } else {
24397
+ result.failed += batch.length - index;
24398
+ return false;
24399
+ }
24400
+ }
24401
+ }
24402
+ }
24403
+ return true;
24197
24404
  }
24198
- });
24405
+ );
24406
+ if (!continueRepair) break;
24199
24407
  }
24200
24408
  return finish();
24201
24409
  };
@@ -24235,7 +24443,7 @@ function createRemoteMemoryStore(options) {
24235
24443
  },
24236
24444
  importTopics: async (topics) => {
24237
24445
  if (!topics.length) return;
24238
- const existing = new Set((await persistence.topics()).map((topic2) => topic2.name));
24446
+ const existing = new Set((await readTopics()).map((topic2) => topic2.name));
24239
24447
  const missing = topics.flatMap((topic2) => {
24240
24448
  const name = normalizeEntityName(topic2.name);
24241
24449
  if (existing.has(name)) return [];
@@ -24244,6 +24452,7 @@ function createRemoteMemoryStore(options) {
24244
24452
  });
24245
24453
  if (!missing.length) return;
24246
24454
  await persistence.importTopics(missing);
24455
+ invalidateReads();
24247
24456
  for (const subscriber of [...subscribers])
24248
24457
  if (subscriber.options.topics) safely(subscriber.onChange);
24249
24458
  },
@@ -24257,40 +24466,51 @@ function createRemoteMemoryStore(options) {
24257
24466
  listProjections: async (listOptions = {}) => (await listRows(metadata3, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
24258
24467
  projection
24259
24468
  ),
24260
- listTopics: async () => {
24261
- const topics = /* @__PURE__ */ new Map();
24262
- for (const { memory } of await pages(metadata3, {
24263
- include_archived: true,
24264
- include_quarantined: true,
24265
- include_superseded: true
24266
- })) {
24267
- for (const topic2 of parseTopics(memory.topics) ?? []) {
24268
- const name = normalizeEntityName(topic2.name);
24269
- if (!name) continue;
24270
- const entry = topics.get(name) ?? {
24271
- name,
24272
- kind: null,
24273
- memoryCount: 0,
24274
- members: /* @__PURE__ */ new Set()
24275
- };
24276
- entry.kind ?? (entry.kind = topic2.kind ?? null);
24277
- entry.members.add(memory.memory_id);
24278
- topics.set(name, entry);
24279
- }
24280
- }
24281
- for (const topic2 of await persistence.topics()) {
24282
- if (topic2.is_deleted) continue;
24283
- const current = topics.get(topic2.name);
24284
- if (current) current.kind ?? (current.kind = topic2.kind ?? null);
24285
- else
24286
- topics.set(topic2.name, {
24287
- name: topic2.name,
24288
- kind: topic2.kind ?? null,
24289
- memoryCount: 0,
24290
- members: /* @__PURE__ */ new Set()
24291
- });
24292
- }
24293
- return [...topics.values()].map(({ members, ...topic2 }) => ({ ...topic2, memoryCount: members.size })).sort((a, b) => a.name.localeCompare(b.name));
24469
+ listTopics: () => {
24470
+ if (topicSnapshot) return topicSnapshot.then((topics) => structuredClone(topics));
24471
+ const snapshot = (async () => {
24472
+ const topics = /* @__PURE__ */ new Map();
24473
+ for (const { memory } of await pages(metadata3, {
24474
+ include_archived: true,
24475
+ include_quarantined: true,
24476
+ include_superseded: true
24477
+ })) {
24478
+ for (const topic2 of parseTopics(memory.topics) ?? []) {
24479
+ const name = normalizeEntityName(topic2.name);
24480
+ if (!name) continue;
24481
+ const entry = topics.get(name) ?? {
24482
+ name,
24483
+ kind: null,
24484
+ memoryCount: 0,
24485
+ members: /* @__PURE__ */ new Set()
24486
+ };
24487
+ entry.kind ?? (entry.kind = topic2.kind ?? null);
24488
+ entry.members.add(memory.memory_id);
24489
+ topics.set(name, entry);
24490
+ }
24491
+ }
24492
+ for (const topic2 of await readTopics()) {
24493
+ if (topic2.is_deleted) continue;
24494
+ const current = topics.get(topic2.name);
24495
+ if (current) current.kind ?? (current.kind = topic2.kind ?? null);
24496
+ else
24497
+ topics.set(topic2.name, {
24498
+ name: topic2.name,
24499
+ kind: topic2.kind ?? null,
24500
+ memoryCount: 0,
24501
+ members: /* @__PURE__ */ new Set()
24502
+ });
24503
+ }
24504
+ return [...topics.values()].map(({ members, ...topic2 }) => ({ ...topic2, memoryCount: members.size })).sort((a, b) => a.name.localeCompare(b.name));
24505
+ })();
24506
+ topicSnapshot = snapshot;
24507
+ const clear = () => {
24508
+ if (topicSnapshot === snapshot) topicSnapshot = void 0;
24509
+ };
24510
+ void snapshot.then(() => {
24511
+ if (!retainTopics()) clear();
24512
+ }, clear);
24513
+ return snapshot.then((topics) => structuredClone(topics));
24294
24514
  },
24295
24515
  get: async (id2) => asStored(await live(id2)),
24296
24516
  listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
@@ -24471,20 +24691,23 @@ function createRemoteMemoryStore(options) {
24471
24691
  subscribe: (onChange, subscribeOptions = {}) => {
24472
24692
  const subscriber = { onChange, options: subscribeOptions };
24473
24693
  subscribers.add(subscriber);
24474
- if (pollIntervalMs > 0 && !timer) {
24475
- timer = setInterval(poll, pollIntervalMs);
24476
- poll();
24694
+ if (pollIntervalMs > 0 && subscribers.size === 1) {
24695
+ stopActivity = activity.subscribe(refreshActivity);
24696
+ refreshActivity();
24477
24697
  }
24478
24698
  return () => {
24479
24699
  subscribers.delete(subscriber);
24480
- if (subscribers.size || !timer) return;
24481
- clearInterval(timer);
24700
+ if (!retainTopics()) invalidateReads();
24701
+ if (subscribers.size) return;
24702
+ if (timer) clearTimeout(timer);
24482
24703
  timer = void 0;
24704
+ stopActivity?.();
24705
+ stopActivity = void 0;
24706
+ stopChanges?.();
24707
+ stopChanges = void 0;
24708
+ changesConnected = false;
24483
24709
  generation++;
24484
- seen.clear();
24485
- ready = false;
24486
- cursor = void 0;
24487
- pending = /* @__PURE__ */ new Set();
24710
+ invalidateReads();
24488
24711
  };
24489
24712
  }
24490
24713
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",