@theokit/sdk-memory 0.2.0 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog — @theokit/sdk-memory
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 826bca0: Security (#56) — close two residual cross-tenant active-recall cache leaks found by adversarial review.
8
+
9
+ - `@theokit/sdk-memory` (publishable) called `cache.get`/`cache.set` with no tenant context, so two callers with the same query text but different identity shared a cached recall — a cross-tenant leak for every consumer of the package. The cache read/write are now keyed by the `{namespace, userId, scope}` tenant tuple (the primitive already supported it).
10
+ - In `@theokit/sdk` the production caller hardcoded `namespace: "default"` and dropped `memoryContext.tenantId`, so two tenants sharing a `userId` collided on one cache entry. The caller now threads `memoryContext.tenantId` into the tenant partition (`namespace`). `sessionId` is intentionally not a key dimension — recall is cross-session by design.
11
+
3
12
  ## 0.2.0
4
13
 
5
14
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -387,7 +387,12 @@ async function runActiveMemory(args) {
387
387
  hits: []
388
388
  });
389
389
  }
390
- const cached = args.cache?.get(args.userText, cfg.queryMode);
390
+ const tenantCtx = {
391
+ namespace: args.namespace,
392
+ userId: args.userId,
393
+ scope: args.scope
394
+ };
395
+ const cached = args.cache?.get(args.userText, cfg.queryMode, tenantCtx);
391
396
  if (cached !== void 0) return endRecallSpan(span, args, cached);
392
397
  const query = buildQuery(args.userText, args.priorMessages, cfg.queryMode, cfg.recentUserTurns);
393
398
  if (query.trim().length === 0) {
@@ -484,7 +489,12 @@ function notifyBreaker(breaker, key, status) {
484
489
  else if (status === "ok" || status === "no-recall") breaker.recordSuccess(key);
485
490
  }
486
491
  async function finalize(args, queryMode, result) {
487
- args.cache?.set(args.userText, queryMode, result);
492
+ const tenantCtx = {
493
+ namespace: args.namespace,
494
+ userId: args.userId,
495
+ scope: args.scope
496
+ };
497
+ args.cache?.set(args.userText, queryMode, result, tenantCtx);
488
498
  if (args.persistTranscripts === true && args.cwd !== void 0) {
489
499
  await persistActiveMemoryTranscript(args.cwd, {
490
500
  runId: args.runId ?? `run-${Date.now()}`,