@anuma/sdk 6.8.1 → 6.9.0

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.
@@ -2107,9 +2107,10 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks, embeddingModel) {
2107
2107
  } catch {
2108
2108
  return null;
2109
2109
  }
2110
+ const storedChunks = chunks.map(({ text: _text, ...rest }) => rest);
2110
2111
  await ctx.database.write(async () => {
2111
2112
  await message.update((msg) => {
2112
- msg._setRaw("chunks", JSON.stringify(chunks));
2113
+ msg._setRaw("chunks", JSON.stringify(storedChunks));
2113
2114
  msg._setRaw("embedding_model", embeddingModel);
2114
2115
  });
2115
2116
  });
@@ -2190,6 +2191,16 @@ async function _updateMessageOp(ctx, uniqueId, opts) {
2190
2191
  });
2191
2192
  return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
2192
2193
  }
2194
+ function resolveChunkText(content, chunk, chunksInRow) {
2195
+ if (!chunk) return content;
2196
+ if (typeof chunk.text === "string" && chunk.text.length > 0) return chunk.text;
2197
+ const { startOffset: start, endOffset: end } = chunk;
2198
+ if (!Number.isInteger(start) || !Number.isInteger(end)) return content;
2199
+ if (start < 0 || end <= start || end > content.length) return content;
2200
+ const covered = chunksInRow?.reduce((max, c) => Math.max(max, c.endOffset ?? 0), 0) ?? 0;
2201
+ if (covered !== content.length) return content;
2202
+ return content.slice(start, end);
2203
+ }
2193
2204
  async function readJsonField(model, column, walletAddress) {
2194
2205
  const raw = model._getRaw(column);
2195
2206
  if (!raw) return void 0;
@@ -2270,7 +2281,7 @@ async function searchChunksOp(ctx, queryVector, options) {
2270
2281
  candidates.push({
2271
2282
  message,
2272
2283
  similarity,
2273
- chunkTextSource: { kind: "chunk", text: chunks[ci].text }
2284
+ chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
2274
2285
  });
2275
2286
  }
2276
2287
  }
@@ -2328,11 +2339,11 @@ async function searchChunksOp(ctx, queryVector, options) {
2328
2339
  const stored = { ...storedById.get(message.id) };
2329
2340
  let chunkText2;
2330
2341
  if (chunkTextSource.kind === "chunk") {
2331
- chunkText2 = chunkTextSource.text;
2342
+ chunkText2 = resolveChunkText(stored.content, chunkTextSource.chunk, chunkTextSource.siblings);
2332
2343
  } else if (chunkTextSource.kind === "chunk-cached") {
2333
2344
  const state = chunkStateByMsgId.get(message.id);
2334
2345
  const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
2335
- chunkText2 = chunk?.text ?? stored.content;
2346
+ chunkText2 = resolveChunkText(stored.content, chunk, state?.chunks);
2336
2347
  } else {
2337
2348
  chunkText2 = stored.content;
2338
2349
  }
@@ -4660,13 +4671,13 @@ async function upsertEntitiesInWrite(ctx, entities) {
4660
4671
  }
4661
4672
  const unique = Array.from(kindByName.keys());
4662
4673
  const out = /* @__PURE__ */ new Map();
4663
- if (unique.length === 0) return { entities: out, operations: [] };
4674
+ if (unique.length === 0) return { entities: out, operations: [], kindBackfills: [] };
4664
4675
  const existing = await ctx.entityCollection.query(import_watermelondb8.Q.where("canonical_name", import_watermelondb8.Q.oneOf(unique))).fetch();
4665
4676
  const existingNames = new Set(existing.map((e) => e.canonicalName));
4666
- const updates = existing.filter((e) => {
4677
+ const kindBackfills = existing.filter((e) => {
4667
4678
  const incoming = kindByName.get(e.canonicalName);
4668
4679
  return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
4669
- });
4680
+ }).map((record) => ({ record, kind: kindByName.get(record.canonicalName) }));
4670
4681
  const missing = unique.filter((n) => !existingNames.has(n));
4671
4682
  const created = missing.map(
4672
4683
  (name) => ctx.entityCollection.prepareCreate((record) => {
@@ -4675,14 +4686,19 @@ async function upsertEntitiesInWrite(ctx, entities) {
4675
4686
  if (kind !== void 0) record._setRaw("kind", kind);
4676
4687
  })
4677
4688
  );
4678
- const updated = updates.map(
4679
- (e) => e.prepareUpdate((record) => {
4680
- record._setRaw("kind", kindByName.get(e.canonicalName));
4681
- })
4682
- );
4683
4689
  for (const e of existing) out.set(e.canonicalName, entityToStored(e));
4684
4690
  for (const record of created) out.set(record.canonicalName, entityToStored(record));
4685
- return { entities: out, operations: [...created, ...updated] };
4691
+ for (const { record, kind } of kindBackfills) {
4692
+ out.set(record.canonicalName, { ...entityToStored(record), kind });
4693
+ }
4694
+ return { entities: out, operations: created, kindBackfills };
4695
+ }
4696
+ function prepareKindBackfills(backfills) {
4697
+ return backfills.map(
4698
+ ({ record, kind }) => record.prepareUpdate((r) => {
4699
+ r._setRaw("kind", kind);
4700
+ })
4701
+ );
4686
4702
  }
4687
4703
  async function findVaultRowInWrite(ctx, memoryId) {
4688
4704
  try {
@@ -4732,10 +4748,12 @@ function topicsForEntities(entities, displayNames, source) {
4732
4748
  function toEntityObjects(entityInputs) {
4733
4749
  return entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
4734
4750
  }
4735
- async function prepareMemoryTopicsUpdate(ctx, memoryId, linked, inputs, source) {
4751
+ async function resolveMemoryTopicsWrite(ctx, memoryId, linked, inputs, source) {
4736
4752
  const row = await findVaultRowInWrite(ctx, memoryId);
4737
- const write = resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
4738
- return write === null ? null : prepareTopicsUpdate(write.row, write.topics, Date.now());
4753
+ return resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
4754
+ }
4755
+ function prepareMemoryTopicsUpdate(write) {
4756
+ return prepareTopicsUpdate(write.row, write.topics, Date.now());
4739
4757
  }
4740
4758
  async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
4741
4759
  if (entityInputs.length === 0) return [];
@@ -4744,15 +4762,16 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
4744
4762
  let skipped = false;
4745
4763
  let entities = [];
4746
4764
  await ctx.database.write(async () => {
4747
- const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
4748
- ctx,
4749
- normalized
4750
- );
4765
+ const {
4766
+ entities: byName,
4767
+ operations: entityOps,
4768
+ kindBackfills
4769
+ } = await upsertEntitiesInWrite(ctx, normalized);
4751
4770
  entities = Array.from(byName.values());
4752
4771
  const vaultRow = await findVaultRowInWrite(ctx, memoryId);
4753
4772
  if (options?.unlessTopicsUserManaged && autoLinkBlocked(vaultRow)) {
4754
- if (entityOps.length > 0) {
4755
- await ctx.database.batch(...entityOps);
4773
+ if (entityOps.length > 0 || kindBackfills.length > 0) {
4774
+ await ctx.database.batch(...entityOps, ...prepareKindBackfills(kindBackfills));
4756
4775
  }
4757
4776
  skipped = true;
4758
4777
  return;
@@ -4772,7 +4791,9 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
4772
4791
  displayNamesOf(normalized),
4773
4792
  options?.topicsSource ?? "auto"
4774
4793
  );
4775
- if (entityOps.length === 0 && toCreate.length === 0 && topicsWrite === null) return;
4794
+ if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && topicsWrite === null) {
4795
+ return;
4796
+ }
4776
4797
  const linkOps = toCreate.map(
4777
4798
  (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
4778
4799
  record._setRaw("memory_id", memoryId);
@@ -4782,6 +4803,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
4782
4803
  );
4783
4804
  await ctx.database.batch(
4784
4805
  ...entityOps,
4806
+ ...prepareKindBackfills(kindBackfills),
4785
4807
  ...linkOps,
4786
4808
  ...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
4787
4809
  );
@@ -4819,10 +4841,11 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
4819
4841
  skipped = true;
4820
4842
  return;
4821
4843
  }
4822
- const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
4823
- ctx,
4824
- normalized
4825
- );
4844
+ const {
4845
+ entities: byName,
4846
+ operations: entityOps,
4847
+ kindBackfills
4848
+ } = await upsertEntitiesInWrite(ctx, normalized);
4826
4849
  entities = Array.from(byName.values());
4827
4850
  const existingLinks = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("memory_id", memoryId)).fetch();
4828
4851
  const keep = new Set(entities.map((e) => e.uniqueId));
@@ -4835,12 +4858,13 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
4835
4858
  displayNamesOf(normalized),
4836
4859
  options.topicsSource
4837
4860
  );
4838
- if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
4861
+ if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
4839
4862
  return;
4840
4863
  }
4841
4864
  const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
4842
4865
  await ctx.database.batch(
4843
4866
  ...entityOps,
4867
+ ...prepareKindBackfills(kindBackfills),
4844
4868
  ...toCreate.map(
4845
4869
  (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
4846
4870
  record._setRaw("memory_id", memoryId);
@@ -5929,27 +5953,36 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
5929
5953
  if (!entityCtx) {
5930
5954
  throw new Error("backfillMemoryTopicsOp requires ctx.entityCtx");
5931
5955
  }
5956
+ const uniqueIds = Array.from(new Set(memoryIds));
5957
+ if (uniqueIds.length === 0) return [];
5932
5958
  const filled = [];
5933
- for (const id of Array.from(new Set(memoryIds))) {
5934
- let record;
5935
- try {
5936
- record = await ctx.vaultMemoryCollection.find(id);
5937
- } catch {
5938
- continue;
5939
- }
5940
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
5941
- if (parseTopics(record.topics) !== null) continue;
5942
- const links = await entityCtx.memoryEntityCollection.query(import_watermelondb9.Q.where("memory_id", id)).unsafeFetchRaw();
5943
- const entityIds = links.map((l) => String(l.entity_id));
5944
- if (entityIds.length === 0) continue;
5945
- const entities = await entityCtx.entityCollection.query(import_watermelondb9.Q.where("id", import_watermelondb9.Q.oneOf(entityIds))).fetch();
5946
- if (entities.length === 0) continue;
5947
- const source = record.topicsUserManaged ? "user" : "auto";
5959
+ const CHUNK = 500;
5960
+ for (let i = 0; i < uniqueIds.length; i += CHUNK) {
5961
+ const chunkIds = uniqueIds.slice(i, i + CHUNK);
5948
5962
  await ctx.database.write(async () => {
5949
- const topicsOp = await prepareMemoryTopicsUpdate(entityCtx, id, entities, [], source);
5950
- if (!topicsOp) return;
5951
- await ctx.database.batch(topicsOp);
5952
- filled.push(id);
5963
+ const writes = [];
5964
+ for (const id of chunkIds) {
5965
+ let record;
5966
+ try {
5967
+ record = await ctx.vaultMemoryCollection.find(id);
5968
+ } catch {
5969
+ continue;
5970
+ }
5971
+ if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
5972
+ if (parseTopics(record.topics) !== null) continue;
5973
+ const links = await entityCtx.memoryEntityCollection.query(import_watermelondb9.Q.where("memory_id", id)).unsafeFetchRaw();
5974
+ const entityIds = links.map((l) => String(l.entity_id));
5975
+ if (entityIds.length === 0) continue;
5976
+ const entities = await entityCtx.entityCollection.query(import_watermelondb9.Q.where("id", import_watermelondb9.Q.oneOf(entityIds))).fetch();
5977
+ if (entities.length === 0) continue;
5978
+ const source = record.topicsUserManaged ? "user" : "auto";
5979
+ const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
5980
+ if (write) writes.push(write);
5981
+ }
5982
+ if (writes.length === 0) return;
5983
+ const prepared = writes.map(prepareMemoryTopicsUpdate);
5984
+ await ctx.database.batch(...prepared);
5985
+ for (const write of writes) filled.push(write.row.id);
5953
5986
  });
5954
5987
  }
5955
5988
  return filled;
@@ -17084,7 +17117,7 @@ function createAutoExtractor(options) {
17084
17117
  const t0 = Date.now();
17085
17118
  void (async () => {
17086
17119
  try {
17087
- const { candidates, results, failedCount, outcome } = await extractAndRetain(
17120
+ const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
17088
17121
  window2,
17089
17122
  retainCtx,
17090
17123
  {
@@ -17124,7 +17157,11 @@ function createAutoExtractor(options) {
17124
17157
  failedCount,
17125
17158
  durationMs: Date.now() - t0,
17126
17159
  conversationId,
17127
- outcome
17160
+ outcome,
17161
+ // Only set alongside `outcome: "empty-after-retry"`. Spread so the key
17162
+ // is absent rather than explicitly undefined on a healthy turn —
17163
+ // analytics backends store an explicit undefined as a real value.
17164
+ ...failure !== void 0 && { failure }
17128
17165
  });
17129
17166
  } catch (err) {
17130
17167
  options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
@@ -3635,8 +3635,26 @@ interface StoredMessageWithSimilarity extends StoredMessage {
3635
3635
  * A chunk of a message with its own embedding for fine-grained search
3636
3636
  */
3637
3637
  interface MessageChunk {
3638
- /** The chunk text */
3639
- text: string;
3638
+ /**
3639
+ * The chunk text — IN MEMORY ONLY. Not persisted (sdk#880).
3640
+ *
3641
+ * `chunkText` covers a message end to end with a 50-character overlap, so the
3642
+ * chunk set of any message over 400 characters reconstructs the whole thing.
3643
+ * Storing it put a fully readable copy of the message next to its own
3644
+ * ciphertext `content` on devices with at-rest encryption enabled.
3645
+ *
3646
+ * `updateMessageChunksOp` now strips this before writing and readers rebuild
3647
+ * the snippet from {@link startOffset}/{@link endOffset} against the message's
3648
+ * own (decrypted) `content` — so the text exists exactly once, under the
3649
+ * protection `content` already has. Encrypting the column instead was
3650
+ * rejected: the client reads this column raw and `JSON.parse`s it in four
3651
+ * places, each swallowing the throw and silently scoring 0.
3652
+ *
3653
+ * Optional because rows written before that change still carry it, and
3654
+ * readers prefer a stored value when present. It is populated in memory by
3655
+ * `chunkText()` and on the way out of a search.
3656
+ */
3657
+ text?: string;
3640
3658
  /**
3641
3659
  * Embedding vector for this chunk.
3642
3660
  *
@@ -6750,6 +6768,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
6750
6768
  * row has: a curated memory's topics are recorded as `user`, everything else as
6751
6769
  * `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
6752
6770
  * a record. Returns the ids filled.
6771
+ *
6772
+ * Runs as ONE writer over the whole (caller-bounded) list, in two phases:
6773
+ * resolve every row's write — all the awaits — and only then prepare and batch,
6774
+ * synchronously. Resolving and preparing per row inside its own writer is what
6775
+ * fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
6776
+ * per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
6777
+ * Same treatment as {@link stampTopicsExtractedAtOp}, including its
6778
+ * transpilation hazard — the prepare pass MUST stay a `.map()`.
6753
6779
  */
6754
6780
  declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
6755
6781
  declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
@@ -7212,6 +7238,22 @@ interface TurnCompleteEvent {
7212
7238
  * previously indistinguishable (both surfaced as zero candidates).
7213
7239
  */
7214
7240
  outcome: ExtractOutcome;
7241
+ /**
7242
+ * Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
7243
+ * the turn (#888).
7244
+ *
7245
+ * `outcome` says extraction gave up; this says why, from a stable enum. The
7246
+ * distinction is the whole point: a 2026-08-11 audit measured ~63% of
7247
+ * production extraction turns ending in `empty-after-retry` and could not tell
7248
+ * from telemetry whether the cause was the freeloader 403 everyone assumed or
7249
+ * something else. It took a Prometheus cross-check to find the real one — the
7250
+ * portal returning HTTP 200 with an empty body, which it counts as a success.
7251
+ *
7252
+ * Forward `failure.reason` into your extraction analytics event; all three
7253
+ * fields are bounded (an enum, an HTTP status, a small attempt count) and none
7254
+ * carries content.
7255
+ */
7256
+ failure?: PortalLlmFailure;
7215
7257
  }
7216
7258
  /** @public */
7217
7259
  /**
@@ -3635,8 +3635,26 @@ interface StoredMessageWithSimilarity extends StoredMessage {
3635
3635
  * A chunk of a message with its own embedding for fine-grained search
3636
3636
  */
3637
3637
  interface MessageChunk {
3638
- /** The chunk text */
3639
- text: string;
3638
+ /**
3639
+ * The chunk text — IN MEMORY ONLY. Not persisted (sdk#880).
3640
+ *
3641
+ * `chunkText` covers a message end to end with a 50-character overlap, so the
3642
+ * chunk set of any message over 400 characters reconstructs the whole thing.
3643
+ * Storing it put a fully readable copy of the message next to its own
3644
+ * ciphertext `content` on devices with at-rest encryption enabled.
3645
+ *
3646
+ * `updateMessageChunksOp` now strips this before writing and readers rebuild
3647
+ * the snippet from {@link startOffset}/{@link endOffset} against the message's
3648
+ * own (decrypted) `content` — so the text exists exactly once, under the
3649
+ * protection `content` already has. Encrypting the column instead was
3650
+ * rejected: the client reads this column raw and `JSON.parse`s it in four
3651
+ * places, each swallowing the throw and silently scoring 0.
3652
+ *
3653
+ * Optional because rows written before that change still carry it, and
3654
+ * readers prefer a stored value when present. It is populated in memory by
3655
+ * `chunkText()` and on the way out of a search.
3656
+ */
3657
+ text?: string;
3640
3658
  /**
3641
3659
  * Embedding vector for this chunk.
3642
3660
  *
@@ -6750,6 +6768,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
6750
6768
  * row has: a curated memory's topics are recorded as `user`, everything else as
6751
6769
  * `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
6752
6770
  * a record. Returns the ids filled.
6771
+ *
6772
+ * Runs as ONE writer over the whole (caller-bounded) list, in two phases:
6773
+ * resolve every row's write — all the awaits — and only then prepare and batch,
6774
+ * synchronously. Resolving and preparing per row inside its own writer is what
6775
+ * fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
6776
+ * per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
6777
+ * Same treatment as {@link stampTopicsExtractedAtOp}, including its
6778
+ * transpilation hazard — the prepare pass MUST stay a `.map()`.
6753
6779
  */
6754
6780
  declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
6755
6781
  declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
@@ -7212,6 +7238,22 @@ interface TurnCompleteEvent {
7212
7238
  * previously indistinguishable (both surfaced as zero candidates).
7213
7239
  */
7214
7240
  outcome: ExtractOutcome;
7241
+ /**
7242
+ * Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
7243
+ * the turn (#888).
7244
+ *
7245
+ * `outcome` says extraction gave up; this says why, from a stable enum. The
7246
+ * distinction is the whole point: a 2026-08-11 audit measured ~63% of
7247
+ * production extraction turns ending in `empty-after-retry` and could not tell
7248
+ * from telemetry whether the cause was the freeloader 403 everyone assumed or
7249
+ * something else. It took a Prometheus cross-check to find the real one — the
7250
+ * portal returning HTTP 200 with an empty body, which it counts as a success.
7251
+ *
7252
+ * Forward `failure.reason` into your extraction analytics event; all three
7253
+ * fields are bounded (an enum, an HTTP status, a small attempt count) and none
7254
+ * carries content.
7255
+ */
7256
+ failure?: PortalLlmFailure;
7215
7257
  }
7216
7258
  /** @public */
7217
7259
  /**
@@ -132,7 +132,7 @@ import {
132
132
  upsertMessageOp,
133
133
  useEncryption,
134
134
  vaultMemoryToStored
135
- } from "./chunk-YO5UXOC4.mjs";
135
+ } from "./chunk-4M56MKBV.mjs";
136
136
  import {
137
137
  PII_PATTERNS,
138
138
  PiiRedactor,
@@ -7539,7 +7539,7 @@ function createAutoExtractor(options) {
7539
7539
  const t0 = Date.now();
7540
7540
  void (async () => {
7541
7541
  try {
7542
- const { candidates, results, failedCount, outcome } = await extractAndRetain(
7542
+ const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
7543
7543
  window,
7544
7544
  retainCtx,
7545
7545
  {
@@ -7579,7 +7579,11 @@ function createAutoExtractor(options) {
7579
7579
  failedCount,
7580
7580
  durationMs: Date.now() - t0,
7581
7581
  conversationId,
7582
- outcome
7582
+ outcome,
7583
+ // Only set alongside `outcome: "empty-after-retry"`. Spread so the key
7584
+ // is absent rather than explicitly undefined on a healthy turn —
7585
+ // analytics backends store an explicit undefined as a real value.
7586
+ ...failure !== void 0 && { failure }
7583
7587
  });
7584
7588
  } catch (err) {
7585
7589
  options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-YO5UXOC4.mjs";
3
+ } from "./chunk-4M56MKBV.mjs";
4
4
  import "./chunk-CJ32HO6Q.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
package/dist/index.d.mts CHANGED
@@ -2462,6 +2462,14 @@ type HandlersUserLookupAccount = {
2462
2462
  fraud_notes?: string;
2463
2463
  id?: number;
2464
2464
  identifier?: string;
2465
+ /**
2466
+ * InternalTester and InternalTesterAt report the People Nearby internal-tester grant (#1578), so
2467
+ * the console renders the toggle's CURRENT state instead of guessing. Always emitted (no omitempty)
2468
+ * because false is meaningful here — an absent field would be indistinguishable from an older
2469
+ * portal build, on a security-relevant flag.
2470
+ */
2471
+ internal_tester?: boolean;
2472
+ internal_tester_at?: string;
2465
2473
  stripe_customer_id?: string;
2466
2474
  type?: string;
2467
2475
  };
package/dist/index.d.ts CHANGED
@@ -2462,6 +2462,14 @@ type HandlersUserLookupAccount = {
2462
2462
  fraud_notes?: string;
2463
2463
  id?: number;
2464
2464
  identifier?: string;
2465
+ /**
2466
+ * InternalTester and InternalTesterAt report the People Nearby internal-tester grant (#1578), so
2467
+ * the console renders the toggle's CURRENT state instead of guessing. Always emitted (no omitempty)
2468
+ * because false is meaningful here — an absent field would be indistinguishable from an older
2469
+ * portal build, on a security-relevant flag.
2470
+ */
2471
+ internal_tester?: boolean;
2472
+ internal_tester_at?: string;
2465
2473
  stripe_customer_id?: string;
2466
2474
  type?: string;
2467
2475
  };