@mastra/redis 1.4.3 → 1.4.4-alpha.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,3 +1,3 @@
1
1
  export * from './storage/index.js';
2
- export { RedisServerCache, type RedisClient, type RedisServerCacheOptions, upstashPreset, nodeRedisPreset, } from './cache.js';
2
+ export { RedisServerCache, type RedisClient, type RedisServerCacheOptions, upstashPreset, nodeRedisPreset, LIST_PUSH_INDEXED_SCRIPT, } from './cache.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC;AAG1B,OAAO,EACL,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC5B,aAAa,EACb,eAAe,GAChB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC;AAG1B,OAAO,EACL,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC5B,aAAa,EACb,eAAe,EACf,wBAAwB,GACzB,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1596,6 +1596,38 @@ const defaultPushToList = (client, key, value) => {
1596
1596
  const defaultGetListRange = (client, key, start, stop) => {
1597
1597
  return client.lrange(key, start, stop);
1598
1598
  };
1599
+ const defaultEvalScript = (client, script, keys, args) => {
1600
+ return client.eval(script, keys.length, ...keys, ...args);
1601
+ };
1602
+ /**
1603
+ * Atomic "allocate index + append + refresh TTLs" used by `listPushIndexed`.
1604
+ *
1605
+ * KEYS[1] = list key, KEYS[2] = counter key
1606
+ * ARGV[1] = JSON-serialized object WITHOUT an `index` property
1607
+ * ARGV[2] = TTL in seconds (0 = no expiry)
1608
+ *
1609
+ * The index is spliced into the JSON text as the first property rather than
1610
+ * decoded/re-encoded with cjson, which would silently alter large integers
1611
+ * and sparse arrays. `JSON.stringify` of an object always starts with `{`,
1612
+ * so `{...}` → `{"index":N,...}` and `{}` → `{"index":N}`.
1613
+ */
1614
+ const LIST_PUSH_INDEXED_SCRIPT = `
1615
+ local i = redis.call('INCR', KEYS[2]) - 1
1616
+ local body = ARGV[1]
1617
+ local doc
1618
+ if #body <= 2 then
1619
+ doc = '{"index":' .. i .. '}'
1620
+ else
1621
+ doc = '{"index":' .. i .. ',' .. string.sub(body, 2)
1622
+ end
1623
+ redis.call('RPUSH', KEYS[1], doc)
1624
+ local ttl = tonumber(ARGV[2])
1625
+ if ttl > 0 then
1626
+ redis.call('EXPIRE', KEYS[1], ttl)
1627
+ redis.call('EXPIRE', KEYS[2], ttl)
1628
+ end
1629
+ return i
1630
+ `.trim();
1599
1631
  var RedisServerCache = class extends MastraServerCache {
1600
1632
  client;
1601
1633
  keyPrefix;
@@ -1605,6 +1637,9 @@ var RedisServerCache = class extends MastraServerCache {
1605
1637
  getListLength;
1606
1638
  pushToList;
1607
1639
  getListRange;
1640
+ evalScript;
1641
+ /** Set once scripting is known to be unusable (no `eval`, or Cluster CROSSSLOT). */
1642
+ scriptingDisabled;
1608
1643
  constructor(config, options = {}) {
1609
1644
  super({ name: "RedisServerCache" });
1610
1645
  this.client = config.client;
@@ -1615,6 +1650,8 @@ var RedisServerCache = class extends MastraServerCache {
1615
1650
  this.getListLength = options.getListLength ?? defaultGetListLength;
1616
1651
  this.pushToList = options.pushToList ?? defaultPushToList;
1617
1652
  this.getListRange = options.getListRange ?? defaultGetListRange;
1653
+ this.evalScript = options.evalScript ?? defaultEvalScript;
1654
+ this.scriptingDisabled = typeof this.client.eval !== "function";
1618
1655
  }
1619
1656
  getKey(key) {
1620
1657
  return `${this.keyPrefix}${key}`;
@@ -1676,13 +1713,34 @@ var RedisServerCache = class extends MastraServerCache {
1676
1713
  if (this.ttlSeconds > 0) await this.client.expire(fullKey, this.ttlSeconds);
1677
1714
  return value;
1678
1715
  }
1716
+ /**
1717
+ * Single round-trip index allocation + list append + TTL refresh via Lua.
1718
+ * This is the durable stream per-chunk hot path (issue #22477): the composed
1719
+ * default costs four awaited commands (INCR, EXPIRE, RPUSH, EXPIRE).
1720
+ */
1721
+ async listPushIndexed(listKey, counterKey, value) {
1722
+ if (this.scriptingDisabled) return super.listPushIndexed(listKey, counterKey, value);
1723
+ const { index: _ignored, ...body } = value;
1724
+ try {
1725
+ const result = await this.evalScript(this.client, LIST_PUSH_INDEXED_SCRIPT, [this.getKey(listKey), this.getKey(counterKey)], [this.serialize(body), String(this.ttlSeconds)]);
1726
+ return Number(result);
1727
+ } catch (error) {
1728
+ if (error instanceof Error && error.message.includes("CROSSSLOT")) {
1729
+ this.scriptingDisabled = true;
1730
+ this.logger.warn("[RedisServerCache] listPushIndexed script rejected with CROSSSLOT; falling back to increment + listPush");
1731
+ return super.listPushIndexed(listKey, counterKey, value);
1732
+ }
1733
+ throw error;
1734
+ }
1735
+ }
1679
1736
  };
1680
1737
  const upstashPreset = {
1681
1738
  setWithExpiry: (client, key, value, seconds) => client.set(key, value, { ex: seconds }),
1682
1739
  scanKeys: (client, cursor, pattern, count) => client.scan(cursor, {
1683
1740
  match: pattern,
1684
1741
  count
1685
- })
1742
+ }),
1743
+ evalScript: (client, script, keys, args) => client.eval(script, keys, args)
1686
1744
  };
1687
1745
  const nodeRedisPreset = {
1688
1746
  setWithExpiry: (client, key, value, seconds) => client.set(key, value, { EX: seconds }),
@@ -1692,9 +1750,13 @@ const nodeRedisPreset = {
1692
1750
  }),
1693
1751
  getListLength: (client, key) => client.lLen(key),
1694
1752
  pushToList: (client, key, value) => client.rPush(key, value),
1695
- getListRange: (client, key, start, stop) => client.lRange(key, start, stop)
1753
+ getListRange: (client, key, start, stop) => client.lRange(key, start, stop),
1754
+ evalScript: (client, script, keys, args) => client.eval(script, {
1755
+ keys,
1756
+ arguments: args
1757
+ })
1696
1758
  };
1697
1759
  //#endregion
1698
- export { RedisServerCache, RedisStore, ScoresRedis, StoreMemoryRedis, WorkflowsRedis, nodeRedisPreset, upstashPreset };
1760
+ export { LIST_PUSH_INDEXED_SCRIPT, RedisServerCache, RedisStore, ScoresRedis, StoreMemoryRedis, WorkflowsRedis, nodeRedisPreset, upstashPreset };
1699
1761
 
1700
1762
  //# sourceMappingURL=index.js.map