@chat-adapter/state-memory 4.21.0 → 4.23.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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { StateAdapter, Lock } from 'chat';
1
+ import { StateAdapter, Lock, QueueEntry } from 'chat';
2
2
 
3
3
  /**
4
4
  * In-memory state adapter for development and testing.
@@ -10,6 +10,7 @@ declare class MemoryStateAdapter implements StateAdapter {
10
10
  private readonly subscriptions;
11
11
  private readonly locks;
12
12
  private readonly cache;
13
+ private readonly queues;
13
14
  private connected;
14
15
  private connectPromise;
15
16
  connect(): Promise<void>;
@@ -29,6 +30,9 @@ declare class MemoryStateAdapter implements StateAdapter {
29
30
  maxLength?: number;
30
31
  ttlMs?: number;
31
32
  }): Promise<void>;
33
+ enqueue(threadId: string, entry: QueueEntry, maxSize: number): Promise<number>;
34
+ dequeue(threadId: string): Promise<QueueEntry | null>;
35
+ queueDepth(threadId: string): Promise<number>;
32
36
  getList<T = unknown>(key: string): Promise<T[]>;
33
37
  private ensureConnected;
34
38
  private cleanExpiredLocks;
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ var MemoryStateAdapter = class {
3
3
  subscriptions = /* @__PURE__ */ new Set();
4
4
  locks = /* @__PURE__ */ new Map();
5
5
  cache = /* @__PURE__ */ new Map();
6
+ queues = /* @__PURE__ */ new Map();
6
7
  connected = false;
7
8
  connectPromise = null;
8
9
  async connect() {
@@ -26,6 +27,7 @@ var MemoryStateAdapter = class {
26
27
  this.connectPromise = null;
27
28
  this.subscriptions.clear();
28
29
  this.locks.clear();
30
+ this.queues.clear();
29
31
  }
30
32
  async subscribe(threadId) {
31
33
  this.ensureConnected();
@@ -137,6 +139,36 @@ var MemoryStateAdapter = class {
137
139
  expiresAt: options?.ttlMs ? Date.now() + options.ttlMs : null
138
140
  });
139
141
  }
142
+ async enqueue(threadId, entry, maxSize) {
143
+ this.ensureConnected();
144
+ let queue = this.queues.get(threadId);
145
+ if (!queue) {
146
+ queue = [];
147
+ this.queues.set(threadId, queue);
148
+ }
149
+ queue.push(entry);
150
+ if (queue.length > maxSize) {
151
+ queue.splice(0, queue.length - maxSize);
152
+ }
153
+ return queue.length;
154
+ }
155
+ async dequeue(threadId) {
156
+ this.ensureConnected();
157
+ const queue = this.queues.get(threadId);
158
+ if (!queue || queue.length === 0) {
159
+ return null;
160
+ }
161
+ const entry = queue.shift();
162
+ if (queue.length === 0) {
163
+ this.queues.delete(threadId);
164
+ }
165
+ return entry ?? null;
166
+ }
167
+ async queueDepth(threadId) {
168
+ this.ensureConnected();
169
+ const queue = this.queues.get(threadId);
170
+ return queue?.length ?? 0;
171
+ }
140
172
  async getList(key) {
141
173
  this.ensureConnected();
142
174
  const cached = this.cache.get(key);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Lock, StateAdapter } from \"chat\";\n\ninterface MemoryLock extends Lock {\n expiresAt: number;\n threadId: string;\n token: string;\n}\n\ninterface CachedValue<T = unknown> {\n expiresAt: number | null; // null = no expiry\n value: T;\n}\n\n/**\n * In-memory state adapter for development and testing.\n *\n * WARNING: State is not persisted across restarts.\n * Use RedisStateAdapter for production.\n */\nexport class MemoryStateAdapter implements StateAdapter {\n private readonly subscriptions = new Set<string>();\n private readonly locks = new Map<string, MemoryLock>();\n private readonly cache = new Map<string, CachedValue>();\n private connected = false;\n private connectPromise: Promise<void> | null = null;\n\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n // Reuse existing connection attempt to avoid race conditions\n if (!this.connectPromise) {\n this.connectPromise = Promise.resolve().then(() => {\n if (process.env.NODE_ENV === \"production\") {\n console.warn(\n \"[chat] MemoryStateAdapter is not recommended for production. \" +\n \"Consider using @chat-adapter/state-redis instead.\"\n );\n }\n this.connected = true;\n });\n }\n\n await this.connectPromise;\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n this.connectPromise = null;\n this.subscriptions.clear();\n this.locks.clear();\n }\n\n async subscribe(threadId: string): Promise<void> {\n this.ensureConnected();\n this.subscriptions.add(threadId);\n }\n\n async unsubscribe(threadId: string): Promise<void> {\n this.ensureConnected();\n this.subscriptions.delete(threadId);\n }\n\n async isSubscribed(threadId: string): Promise<boolean> {\n this.ensureConnected();\n return this.subscriptions.has(threadId);\n }\n\n async acquireLock(threadId: string, ttlMs: number): Promise<Lock | null> {\n this.ensureConnected();\n this.cleanExpiredLocks();\n\n // Check if already locked\n const existingLock = this.locks.get(threadId);\n if (existingLock && existingLock.expiresAt > Date.now()) {\n return null;\n }\n\n // Create new lock\n const lock: MemoryLock = {\n threadId,\n token: generateToken(),\n expiresAt: Date.now() + ttlMs,\n };\n\n this.locks.set(threadId, lock);\n return lock;\n }\n\n async forceReleaseLock(threadId: string): Promise<void> {\n this.ensureConnected();\n this.locks.delete(threadId);\n }\n\n async releaseLock(lock: Lock): Promise<void> {\n this.ensureConnected();\n\n const existingLock = this.locks.get(lock.threadId);\n if (existingLock && existingLock.token === lock.token) {\n this.locks.delete(lock.threadId);\n }\n }\n\n async extendLock(lock: Lock, ttlMs: number): Promise<boolean> {\n this.ensureConnected();\n\n const existingLock = this.locks.get(lock.threadId);\n if (!existingLock || existingLock.token !== lock.token) {\n return false;\n }\n\n if (existingLock.expiresAt < Date.now()) {\n // Lock has already expired\n this.locks.delete(lock.threadId);\n return false;\n }\n\n // Extend the lock\n existingLock.expiresAt = Date.now() + ttlMs;\n return true;\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n this.ensureConnected();\n\n const cached = this.cache.get(key);\n if (!cached) {\n return null;\n }\n\n // Check if expired\n if (cached.expiresAt !== null && cached.expiresAt <= Date.now()) {\n this.cache.delete(key);\n return null;\n }\n\n return cached.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {\n this.ensureConnected();\n\n this.cache.set(key, {\n value,\n expiresAt: ttlMs ? Date.now() + ttlMs : null,\n });\n }\n\n async setIfNotExists(\n key: string,\n value: unknown,\n ttlMs?: number\n ): Promise<boolean> {\n this.ensureConnected();\n\n const existing = this.cache.get(key);\n if (existing) {\n // Check if expired\n if (existing.expiresAt !== null && existing.expiresAt <= Date.now()) {\n this.cache.delete(key);\n } else {\n return false;\n }\n }\n\n this.cache.set(key, {\n value,\n expiresAt: ttlMs ? Date.now() + ttlMs : null,\n });\n return true;\n }\n\n async delete(key: string): Promise<void> {\n this.ensureConnected();\n this.cache.delete(key);\n }\n\n async appendToList(\n key: string,\n value: unknown,\n options?: { maxLength?: number; ttlMs?: number }\n ): Promise<void> {\n this.ensureConnected();\n\n const cached = this.cache.get(key);\n let list: unknown[];\n\n if (cached && cached.expiresAt !== null && cached.expiresAt <= Date.now()) {\n // Expired — start fresh\n list = [];\n } else if (cached && Array.isArray(cached.value)) {\n list = cached.value;\n } else {\n list = [];\n }\n\n list.push(value);\n\n if (options?.maxLength && list.length > options.maxLength) {\n list = list.slice(list.length - options.maxLength);\n }\n\n this.cache.set(key, {\n value: list,\n expiresAt: options?.ttlMs ? Date.now() + options.ttlMs : null,\n });\n }\n\n async getList<T = unknown>(key: string): Promise<T[]> {\n this.ensureConnected();\n\n const cached = this.cache.get(key);\n if (!cached) {\n return [];\n }\n\n if (cached.expiresAt !== null && cached.expiresAt <= Date.now()) {\n this.cache.delete(key);\n return [];\n }\n\n if (Array.isArray(cached.value)) {\n return cached.value as T[];\n }\n\n return [];\n }\n\n private ensureConnected(): void {\n if (!this.connected) {\n throw new Error(\n \"MemoryStateAdapter is not connected. Call connect() first.\"\n );\n }\n }\n\n private cleanExpiredLocks(): void {\n const now = Date.now();\n for (const [threadId, lock] of this.locks) {\n if (lock.expiresAt <= now) {\n this.locks.delete(threadId);\n }\n }\n }\n\n // For testing purposes\n _getSubscriptionCount(): number {\n return this.subscriptions.size;\n }\n\n _getLockCount(): number {\n this.cleanExpiredLocks();\n return this.locks.size;\n }\n}\n\nfunction generateToken(): string {\n return `mem_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;\n}\n\nexport function createMemoryState(): MemoryStateAdapter {\n return new MemoryStateAdapter();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Lock, QueueEntry, StateAdapter } from \"chat\";\n\ninterface MemoryLock extends Lock {\n expiresAt: number;\n threadId: string;\n token: string;\n}\n\ninterface CachedValue<T = unknown> {\n expiresAt: number | null; // null = no expiry\n value: T;\n}\n\n/**\n * In-memory state adapter for development and testing.\n *\n * WARNING: State is not persisted across restarts.\n * Use RedisStateAdapter for production.\n */\nexport class MemoryStateAdapter implements StateAdapter {\n private readonly subscriptions = new Set<string>();\n private readonly locks = new Map<string, MemoryLock>();\n private readonly cache = new Map<string, CachedValue>();\n private readonly queues = new Map<string, QueueEntry[]>();\n private connected = false;\n private connectPromise: Promise<void> | null = null;\n\n async connect(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n // Reuse existing connection attempt to avoid race conditions\n if (!this.connectPromise) {\n this.connectPromise = Promise.resolve().then(() => {\n if (process.env.NODE_ENV === \"production\") {\n console.warn(\n \"[chat] MemoryStateAdapter is not recommended for production. \" +\n \"Consider using @chat-adapter/state-redis instead.\"\n );\n }\n this.connected = true;\n });\n }\n\n await this.connectPromise;\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n this.connectPromise = null;\n this.subscriptions.clear();\n this.locks.clear();\n this.queues.clear();\n }\n\n async subscribe(threadId: string): Promise<void> {\n this.ensureConnected();\n this.subscriptions.add(threadId);\n }\n\n async unsubscribe(threadId: string): Promise<void> {\n this.ensureConnected();\n this.subscriptions.delete(threadId);\n }\n\n async isSubscribed(threadId: string): Promise<boolean> {\n this.ensureConnected();\n return this.subscriptions.has(threadId);\n }\n\n async acquireLock(threadId: string, ttlMs: number): Promise<Lock | null> {\n this.ensureConnected();\n this.cleanExpiredLocks();\n\n // Check if already locked\n const existingLock = this.locks.get(threadId);\n if (existingLock && existingLock.expiresAt > Date.now()) {\n return null;\n }\n\n // Create new lock\n const lock: MemoryLock = {\n threadId,\n token: generateToken(),\n expiresAt: Date.now() + ttlMs,\n };\n\n this.locks.set(threadId, lock);\n return lock;\n }\n\n async forceReleaseLock(threadId: string): Promise<void> {\n this.ensureConnected();\n this.locks.delete(threadId);\n }\n\n async releaseLock(lock: Lock): Promise<void> {\n this.ensureConnected();\n\n const existingLock = this.locks.get(lock.threadId);\n if (existingLock && existingLock.token === lock.token) {\n this.locks.delete(lock.threadId);\n }\n }\n\n async extendLock(lock: Lock, ttlMs: number): Promise<boolean> {\n this.ensureConnected();\n\n const existingLock = this.locks.get(lock.threadId);\n if (!existingLock || existingLock.token !== lock.token) {\n return false;\n }\n\n if (existingLock.expiresAt < Date.now()) {\n // Lock has already expired\n this.locks.delete(lock.threadId);\n return false;\n }\n\n // Extend the lock\n existingLock.expiresAt = Date.now() + ttlMs;\n return true;\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n this.ensureConnected();\n\n const cached = this.cache.get(key);\n if (!cached) {\n return null;\n }\n\n // Check if expired\n if (cached.expiresAt !== null && cached.expiresAt <= Date.now()) {\n this.cache.delete(key);\n return null;\n }\n\n return cached.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {\n this.ensureConnected();\n\n this.cache.set(key, {\n value,\n expiresAt: ttlMs ? Date.now() + ttlMs : null,\n });\n }\n\n async setIfNotExists(\n key: string,\n value: unknown,\n ttlMs?: number\n ): Promise<boolean> {\n this.ensureConnected();\n\n const existing = this.cache.get(key);\n if (existing) {\n // Check if expired\n if (existing.expiresAt !== null && existing.expiresAt <= Date.now()) {\n this.cache.delete(key);\n } else {\n return false;\n }\n }\n\n this.cache.set(key, {\n value,\n expiresAt: ttlMs ? Date.now() + ttlMs : null,\n });\n return true;\n }\n\n async delete(key: string): Promise<void> {\n this.ensureConnected();\n this.cache.delete(key);\n }\n\n async appendToList(\n key: string,\n value: unknown,\n options?: { maxLength?: number; ttlMs?: number }\n ): Promise<void> {\n this.ensureConnected();\n\n const cached = this.cache.get(key);\n let list: unknown[];\n\n if (cached && cached.expiresAt !== null && cached.expiresAt <= Date.now()) {\n // Expired — start fresh\n list = [];\n } else if (cached && Array.isArray(cached.value)) {\n list = cached.value;\n } else {\n list = [];\n }\n\n list.push(value);\n\n if (options?.maxLength && list.length > options.maxLength) {\n list = list.slice(list.length - options.maxLength);\n }\n\n this.cache.set(key, {\n value: list,\n expiresAt: options?.ttlMs ? Date.now() + options.ttlMs : null,\n });\n }\n\n async enqueue(\n threadId: string,\n entry: QueueEntry,\n maxSize: number\n ): Promise<number> {\n this.ensureConnected();\n\n let queue = this.queues.get(threadId);\n if (!queue) {\n queue = [];\n this.queues.set(threadId, queue);\n }\n\n queue.push(entry);\n\n // Trim to maxSize (keep newest)\n if (queue.length > maxSize) {\n queue.splice(0, queue.length - maxSize);\n }\n\n return queue.length;\n }\n\n async dequeue(threadId: string): Promise<QueueEntry | null> {\n this.ensureConnected();\n\n const queue = this.queues.get(threadId);\n if (!queue || queue.length === 0) {\n return null;\n }\n\n const entry = queue.shift();\n\n if (queue.length === 0) {\n this.queues.delete(threadId);\n }\n\n return entry ?? null;\n }\n\n async queueDepth(threadId: string): Promise<number> {\n this.ensureConnected();\n\n const queue = this.queues.get(threadId);\n return queue?.length ?? 0;\n }\n\n async getList<T = unknown>(key: string): Promise<T[]> {\n this.ensureConnected();\n\n const cached = this.cache.get(key);\n if (!cached) {\n return [];\n }\n\n if (cached.expiresAt !== null && cached.expiresAt <= Date.now()) {\n this.cache.delete(key);\n return [];\n }\n\n if (Array.isArray(cached.value)) {\n return cached.value as T[];\n }\n\n return [];\n }\n\n private ensureConnected(): void {\n if (!this.connected) {\n throw new Error(\n \"MemoryStateAdapter is not connected. Call connect() first.\"\n );\n }\n }\n\n private cleanExpiredLocks(): void {\n const now = Date.now();\n for (const [threadId, lock] of this.locks) {\n if (lock.expiresAt <= now) {\n this.locks.delete(threadId);\n }\n }\n }\n\n // For testing purposes\n _getSubscriptionCount(): number {\n return this.subscriptions.size;\n }\n\n _getLockCount(): number {\n this.cleanExpiredLocks();\n return this.locks.size;\n }\n}\n\nfunction generateToken(): string {\n return `mem_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;\n}\n\nexport function createMemoryState(): MemoryStateAdapter {\n return new MemoryStateAdapter();\n}\n"],"mappings":";AAmBO,IAAM,qBAAN,MAAiD;AAAA,EACrC,gBAAgB,oBAAI,IAAY;AAAA,EAChC,QAAQ,oBAAI,IAAwB;AAAA,EACpC,QAAQ,oBAAI,IAAyB;AAAA,EACrC,SAAS,oBAAI,IAA0B;AAAA,EAChD,YAAY;AAAA,EACZ,iBAAuC;AAAA,EAE/C,MAAM,UAAyB;AAC7B,QAAI,KAAK,WAAW;AAClB;AAAA,IACF;AAGA,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAiB,QAAQ,QAAQ,EAAE,KAAK,MAAM;AACjD,YAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,kBAAQ;AAAA,YACN;AAAA,UAEF;AAAA,QACF;AACA,aAAK,YAAY;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,UAAM,KAAK;AAAA,EACb;AAAA,EAEA,MAAM,aAA4B;AAChC,SAAK,YAAY;AACjB,SAAK,iBAAiB;AACtB,SAAK,cAAc,MAAM;AACzB,SAAK,MAAM,MAAM;AACjB,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA,EAEA,MAAM,UAAU,UAAiC;AAC/C,SAAK,gBAAgB;AACrB,SAAK,cAAc,IAAI,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,YAAY,UAAiC;AACjD,SAAK,gBAAgB;AACrB,SAAK,cAAc,OAAO,QAAQ;AAAA,EACpC;AAAA,EAEA,MAAM,aAAa,UAAoC;AACrD,SAAK,gBAAgB;AACrB,WAAO,KAAK,cAAc,IAAI,QAAQ;AAAA,EACxC;AAAA,EAEA,MAAM,YAAY,UAAkB,OAAqC;AACvE,SAAK,gBAAgB;AACrB,SAAK,kBAAkB;AAGvB,UAAM,eAAe,KAAK,MAAM,IAAI,QAAQ;AAC5C,QAAI,gBAAgB,aAAa,YAAY,KAAK,IAAI,GAAG;AACvD,aAAO;AAAA,IACT;AAGA,UAAM,OAAmB;AAAA,MACvB;AAAA,MACA,OAAO,cAAc;AAAA,MACrB,WAAW,KAAK,IAAI,IAAI;AAAA,IAC1B;AAEA,SAAK,MAAM,IAAI,UAAU,IAAI;AAC7B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,iBAAiB,UAAiC;AACtD,SAAK,gBAAgB;AACrB,SAAK,MAAM,OAAO,QAAQ;AAAA,EAC5B;AAAA,EAEA,MAAM,YAAY,MAA2B;AAC3C,SAAK,gBAAgB;AAErB,UAAM,eAAe,KAAK,MAAM,IAAI,KAAK,QAAQ;AACjD,QAAI,gBAAgB,aAAa,UAAU,KAAK,OAAO;AACrD,WAAK,MAAM,OAAO,KAAK,QAAQ;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,MAAY,OAAiC;AAC5D,SAAK,gBAAgB;AAErB,UAAM,eAAe,KAAK,MAAM,IAAI,KAAK,QAAQ;AACjD,QAAI,CAAC,gBAAgB,aAAa,UAAU,KAAK,OAAO;AACtD,aAAO;AAAA,IACT;AAEA,QAAI,aAAa,YAAY,KAAK,IAAI,GAAG;AAEvC,WAAK,MAAM,OAAO,KAAK,QAAQ;AAC/B,aAAO;AAAA,IACT;AAGA,iBAAa,YAAY,KAAK,IAAI,IAAI;AACtC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAiB,KAAgC;AACrD,SAAK,gBAAgB;AAErB,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,cAAc,QAAQ,OAAO,aAAa,KAAK,IAAI,GAAG;AAC/D,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,IAAiB,KAAa,OAAU,OAA+B;AAC3E,SAAK,gBAAgB;AAErB,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB;AAAA,MACA,WAAW,QAAQ,KAAK,IAAI,IAAI,QAAQ;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eACJ,KACA,OACA,OACkB;AAClB,SAAK,gBAAgB;AAErB,UAAM,WAAW,KAAK,MAAM,IAAI,GAAG;AACnC,QAAI,UAAU;AAEZ,UAAI,SAAS,cAAc,QAAQ,SAAS,aAAa,KAAK,IAAI,GAAG;AACnE,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAEA,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB;AAAA,MACA,WAAW,QAAQ,KAAK,IAAI,IAAI,QAAQ;AAAA,IAC1C,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,SAAK,gBAAgB;AACrB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,aACJ,KACA,OACA,SACe;AACf,SAAK,gBAAgB;AAErB,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI;AAEJ,QAAI,UAAU,OAAO,cAAc,QAAQ,OAAO,aAAa,KAAK,IAAI,GAAG;AAEzE,aAAO,CAAC;AAAA,IACV,WAAW,UAAU,MAAM,QAAQ,OAAO,KAAK,GAAG;AAChD,aAAO,OAAO;AAAA,IAChB,OAAO;AACL,aAAO,CAAC;AAAA,IACV;AAEA,SAAK,KAAK,KAAK;AAEf,QAAI,SAAS,aAAa,KAAK,SAAS,QAAQ,WAAW;AACzD,aAAO,KAAK,MAAM,KAAK,SAAS,QAAQ,SAAS;AAAA,IACnD;AAEA,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB,OAAO;AAAA,MACP,WAAW,SAAS,QAAQ,KAAK,IAAI,IAAI,QAAQ,QAAQ;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QACJ,UACA,OACA,SACiB;AACjB,SAAK,gBAAgB;AAErB,QAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ;AACpC,QAAI,CAAC,OAAO;AACV,cAAQ,CAAC;AACT,WAAK,OAAO,IAAI,UAAU,KAAK;AAAA,IACjC;AAEA,UAAM,KAAK,KAAK;AAGhB,QAAI,MAAM,SAAS,SAAS;AAC1B,YAAM,OAAO,GAAG,MAAM,SAAS,OAAO;AAAA,IACxC;AAEA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAM,QAAQ,UAA8C;AAC1D,SAAK,gBAAgB;AAErB,UAAM,QAAQ,KAAK,OAAO,IAAI,QAAQ;AACtC,QAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,MAAM,MAAM;AAE1B,QAAI,MAAM,WAAW,GAAG;AACtB,WAAK,OAAO,OAAO,QAAQ;AAAA,IAC7B;AAEA,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,MAAM,WAAW,UAAmC;AAClD,SAAK,gBAAgB;AAErB,UAAM,QAAQ,KAAK,OAAO,IAAI,QAAQ;AACtC,WAAO,OAAO,UAAU;AAAA,EAC1B;AAAA,EAEA,MAAM,QAAqB,KAA2B;AACpD,SAAK,gBAAgB;AAErB,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,CAAC,QAAQ;AACX,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,OAAO,cAAc,QAAQ,OAAO,aAAa,KAAK,IAAI,GAAG;AAC/D,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,MAAM,QAAQ,OAAO,KAAK,GAAG;AAC/B,aAAO,OAAO;AAAA,IAChB;AAEA,WAAO,CAAC;AAAA,EACV;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,UAAU,IAAI,KAAK,KAAK,OAAO;AACzC,UAAI,KAAK,aAAa,KAAK;AACzB,aAAK,MAAM,OAAO,QAAQ;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,wBAAgC;AAC9B,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEA,gBAAwB;AACtB,SAAK,kBAAkB;AACvB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAEA,SAAS,gBAAwB;AAC/B,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,CAAC;AACzE;AAEO,SAAS,oBAAwC;AACtD,SAAO,IAAI,mBAAmB;AAChC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chat-adapter/state-memory",
3
- "version": "4.21.0",
3
+ "version": "4.23.0",
4
4
  "description": "In-memory state adapter for chat (development/testing)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "dist"
17
17
  ],
18
18
  "dependencies": {
19
- "chat": "4.21.0"
19
+ "chat": "4.23.0"
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",