@motiadev/adapter-redis-state 0.13.1-beta.163-660633 → 0.13.1-beta.163-093858

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.
@@ -0,0 +1,3 @@
1
+ export { RedisStateAdapter } from './redis-state-adapter';
2
+ export type { RedisStateAdapterOptions } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,YAAY,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisStateAdapter = void 0;
4
+ var redis_state_adapter_1 = require("./redis-state-adapter");
5
+ Object.defineProperty(exports, "RedisStateAdapter", { enumerable: true, get: function () { return redis_state_adapter_1.RedisStateAdapter; } });
@@ -0,0 +1,30 @@
1
+ import type { StateAdapter, StateItem, StateItemsInput } from '@motiadev/core';
2
+ import { type RedisClientOptions, type RedisClientType } from 'redis';
3
+ import type { RedisStateAdapterOptions } from './types';
4
+ export declare class RedisStateAdapter implements StateAdapter {
5
+ private client;
6
+ private keyPrefix;
7
+ private ttl?;
8
+ private connected;
9
+ private isExternalClient;
10
+ constructor(redisConnection: RedisClientType | RedisClientOptions, options?: RedisStateAdapterOptions);
11
+ private connect;
12
+ private ensureConnected;
13
+ private makeKey;
14
+ private makeTracePrefix;
15
+ private extractKey;
16
+ private determineType;
17
+ get<T>(traceId: string, key: string): Promise<T | null>;
18
+ set<T>(traceId: string, key: string, value: T): Promise<T>;
19
+ delete<T>(traceId: string, key: string): Promise<T | null>;
20
+ getGroup<T>(traceId: string): Promise<T[]>;
21
+ clear(traceId: string): Promise<void>;
22
+ cleanup(): Promise<void>;
23
+ keys(traceId: string): Promise<string[]>;
24
+ traceIds(): Promise<string[]>;
25
+ items(input: StateItemsInput): Promise<StateItem[]>;
26
+ private scanKeys;
27
+ private applyFilters;
28
+ private matchesFilter;
29
+ }
30
+ //# sourceMappingURL=redis-state-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-state-adapter.d.ts","sourceRoot":"","sources":["../src/redis-state-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAe,SAAS,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC3F,OAAO,EAAgB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AACnF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAMvD,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,GAAG,CAAC,CAAQ;IACpB,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,gBAAgB,CAAS;gBAErB,eAAe,EAAE,eAAe,GAAG,kBAAkB,EAAE,OAAO,CAAC,EAAE,wBAAwB;YAmCvF,OAAO;YAWP,eAAe;IAM7B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,aAAa;IAQf,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAOvD,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAc1D,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAQ1D,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAW1C,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAOxC,QAAQ,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAiB7B,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YAkD3C,QAAQ;IAgBtB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;CAmCtB"}
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisStateAdapter = void 0;
4
+ const redis_1 = require("redis");
5
+ function isRedisClient(input) {
6
+ return typeof input === 'object' && 'isOpen' in input && 'connect' in input;
7
+ }
8
+ class RedisStateAdapter {
9
+ constructor(redisConnection, options) {
10
+ this.connected = false;
11
+ this.keyPrefix = options?.keyPrefix || 'motia:state:';
12
+ this.ttl = options?.ttl;
13
+ if (isRedisClient(redisConnection)) {
14
+ this.client = redisConnection;
15
+ this.isExternalClient = true;
16
+ this.connected = this.client.isOpen;
17
+ }
18
+ else {
19
+ const config = redisConnection;
20
+ this.isExternalClient = false;
21
+ this.client = (0, redis_1.createClient)(config);
22
+ this.client.on('error', (err) => {
23
+ console.error('[Redis State] Client error:', err);
24
+ });
25
+ this.client.on('connect', () => {
26
+ this.connected = true;
27
+ });
28
+ this.client.on('disconnect', () => {
29
+ console.warn('[Redis State] Disconnected');
30
+ this.connected = false;
31
+ });
32
+ this.client.on('reconnecting', () => {
33
+ console.log('[Redis State] Reconnecting...');
34
+ });
35
+ this.connect();
36
+ }
37
+ }
38
+ async connect() {
39
+ if (!this.connected && !this.client.isOpen) {
40
+ try {
41
+ await this.client.connect();
42
+ }
43
+ catch (error) {
44
+ console.error('[Redis State] Failed to connect:', error);
45
+ throw error;
46
+ }
47
+ }
48
+ }
49
+ async ensureConnected() {
50
+ if (!this.client.isOpen) {
51
+ await this.connect();
52
+ }
53
+ }
54
+ makeKey(traceId, key) {
55
+ return `${this.keyPrefix}${traceId}:${key}`;
56
+ }
57
+ makeTracePrefix(traceId) {
58
+ return `${this.keyPrefix}${traceId}:`;
59
+ }
60
+ extractKey(fullKey, traceId) {
61
+ const prefix = this.makeTracePrefix(traceId);
62
+ return fullKey.slice(prefix.length);
63
+ }
64
+ determineType(value) {
65
+ if (value === null)
66
+ return 'null';
67
+ if (Array.isArray(value))
68
+ return 'array';
69
+ return (['string', 'number', 'boolean', 'object'].find((type) => typeof value === type) || 'object');
70
+ }
71
+ async get(traceId, key) {
72
+ await this.ensureConnected();
73
+ const fullKey = this.makeKey(traceId, key);
74
+ const value = await this.client.get(fullKey);
75
+ return value ? JSON.parse(value) : null;
76
+ }
77
+ async set(traceId, key, value) {
78
+ await this.ensureConnected();
79
+ const fullKey = this.makeKey(traceId, key);
80
+ const serialized = JSON.stringify(value);
81
+ if (this.ttl) {
82
+ await this.client.setEx(fullKey, this.ttl, serialized);
83
+ }
84
+ else {
85
+ await this.client.set(fullKey, serialized);
86
+ }
87
+ return value;
88
+ }
89
+ async delete(traceId, key) {
90
+ await this.ensureConnected();
91
+ const fullKey = this.makeKey(traceId, key);
92
+ const value = await this.get(traceId, key);
93
+ await this.client.del(fullKey);
94
+ return value;
95
+ }
96
+ async getGroup(traceId) {
97
+ await this.ensureConnected();
98
+ const pattern = `${this.makeTracePrefix(traceId)}*`;
99
+ const keys = await this.scanKeys(pattern);
100
+ if (keys.length === 0)
101
+ return [];
102
+ const values = await this.client.mGet(keys);
103
+ return values.filter((v) => v !== null).map((v) => JSON.parse(v));
104
+ }
105
+ async clear(traceId) {
106
+ await this.ensureConnected();
107
+ const pattern = `${this.makeTracePrefix(traceId)}*`;
108
+ const keys = await this.scanKeys(pattern);
109
+ if (keys.length > 0) {
110
+ await this.client.del(keys);
111
+ }
112
+ }
113
+ async cleanup() {
114
+ if (!this.isExternalClient && this.client.isOpen) {
115
+ await this.client.quit();
116
+ }
117
+ }
118
+ async keys(traceId) {
119
+ await this.ensureConnected();
120
+ const pattern = `${this.makeTracePrefix(traceId)}*`;
121
+ const keys = await this.scanKeys(pattern);
122
+ return keys.map((key) => this.extractKey(key, traceId));
123
+ }
124
+ async traceIds() {
125
+ await this.ensureConnected();
126
+ const pattern = `${this.keyPrefix}*`;
127
+ const keys = await this.scanKeys(pattern);
128
+ const traceIdSet = new Set();
129
+ for (const key of keys) {
130
+ const withoutPrefix = key.slice(this.keyPrefix.length);
131
+ const traceId = withoutPrefix.split(':')[0];
132
+ if (traceId) {
133
+ traceIdSet.add(traceId);
134
+ }
135
+ }
136
+ return Array.from(traceIdSet);
137
+ }
138
+ async items(input) {
139
+ await this.ensureConnected();
140
+ const items = [];
141
+ if (input.groupId) {
142
+ const pattern = `${this.makeTracePrefix(input.groupId)}*`;
143
+ const keys = await this.scanKeys(pattern);
144
+ for (const fullKey of keys) {
145
+ const value = await this.client.get(fullKey);
146
+ if (value !== null) {
147
+ const key = this.extractKey(fullKey, input.groupId);
148
+ const parsedValue = JSON.parse(value);
149
+ items.push({
150
+ groupId: input.groupId,
151
+ key,
152
+ type: this.determineType(parsedValue),
153
+ value: parsedValue,
154
+ });
155
+ }
156
+ }
157
+ }
158
+ else {
159
+ const traceIds = await this.traceIds();
160
+ for (const traceId of traceIds) {
161
+ const pattern = `${this.makeTracePrefix(traceId)}*`;
162
+ const keys = await this.scanKeys(pattern);
163
+ for (const fullKey of keys) {
164
+ const value = await this.client.get(fullKey);
165
+ if (value !== null) {
166
+ const key = this.extractKey(fullKey, traceId);
167
+ const parsedValue = JSON.parse(value);
168
+ items.push({
169
+ groupId: traceId,
170
+ key,
171
+ type: this.determineType(parsedValue),
172
+ value: parsedValue,
173
+ });
174
+ }
175
+ }
176
+ }
177
+ }
178
+ if (input.filter && input.filter.length > 0) {
179
+ return this.applyFilters(items, input.filter);
180
+ }
181
+ return items;
182
+ }
183
+ async scanKeys(pattern) {
184
+ const keys = [];
185
+ let cursor = '0';
186
+ do {
187
+ const result = await this.client.scan(cursor.toString(), {
188
+ MATCH: pattern,
189
+ COUNT: 100,
190
+ });
191
+ cursor = result.cursor;
192
+ keys.push(...result.keys);
193
+ } while (String(cursor) !== '0');
194
+ return keys;
195
+ }
196
+ applyFilters(items, filters) {
197
+ return items.filter((item) => {
198
+ return filters.every((filter) => this.matchesFilter(item, filter));
199
+ });
200
+ }
201
+ matchesFilter(item, filter) {
202
+ const value = typeof item.value === 'object' && item.value !== null ? item.value[filter.valueKey] : item.value;
203
+ const filterValue = filter.value;
204
+ switch (filter.operation) {
205
+ case 'eq':
206
+ return value === filterValue;
207
+ case 'neq':
208
+ return value !== filterValue;
209
+ case 'gt':
210
+ return value > filterValue;
211
+ case 'gte':
212
+ return value >= filterValue;
213
+ case 'lt':
214
+ return value < filterValue;
215
+ case 'lte':
216
+ return value <= filterValue;
217
+ case 'contains':
218
+ return typeof value === 'string' && value.includes(filterValue);
219
+ case 'notContains':
220
+ return typeof value === 'string' && !value.includes(filterValue);
221
+ case 'startsWith':
222
+ return typeof value === 'string' && value.startsWith(filterValue);
223
+ case 'endsWith':
224
+ return typeof value === 'string' && value.endsWith(filterValue);
225
+ case 'isNotNull':
226
+ return value !== null && value !== undefined;
227
+ case 'isNull':
228
+ return value === null || value === undefined;
229
+ default:
230
+ return false;
231
+ }
232
+ }
233
+ }
234
+ exports.RedisStateAdapter = RedisStateAdapter;
@@ -0,0 +1,5 @@
1
+ export interface RedisStateAdapterOptions {
2
+ keyPrefix?: string;
3
+ ttl?: number;
4
+ }
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,27 +1,23 @@
1
1
  {
2
2
  "name": "@motiadev/adapter-redis-state",
3
3
  "description": "Redis state adapter for Motia framework, enabling distributed state management across multiple instances.",
4
- "type": "module",
5
- "main": "dist/index.mjs",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.mts",
8
- "version": "0.13.1-beta.163-660633",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "version": "0.13.1-beta.163-093858",
9
7
  "dependencies": {
10
8
  "redis": "^5.9.0",
11
- "@motiadev/core": "0.13.1-beta.163-660633"
9
+ "@motiadev/core": "0.13.1-beta.163-093858"
12
10
  },
13
11
  "devDependencies": {
14
12
  "@types/node": "^22.10.2",
15
- "tsdown": "^0.16.6",
16
13
  "typescript": "^5.7.2"
17
14
  },
18
15
  "peerDependencies": {
19
16
  "@motiadev/core": "^0.8.0"
20
17
  },
21
18
  "scripts": {
22
- "build": "tsdown",
23
- "dev": "tsdown --watch",
19
+ "build": "rm -rf dist && tsc",
24
20
  "lint": "biome check .",
25
- "clean": "rm -rf dist"
21
+ "watch": "tsc --watch"
26
22
  }
27
23
  }
package/dist/index.d.mts DELETED
@@ -1,3 +0,0 @@
1
- import { RedisStateAdapterOptions } from "./types.mjs";
2
- import { RedisStateAdapter } from "./redis-state-adapter.mjs";
3
- export { RedisStateAdapter, type RedisStateAdapterOptions };
package/dist/index.mjs DELETED
@@ -1,3 +0,0 @@
1
- import { RedisStateAdapter } from "./redis-state-adapter.mjs";
2
-
3
- export { RedisStateAdapter };
@@ -1,34 +0,0 @@
1
- import { RedisStateAdapterOptions } from "./types.mjs";
2
- import { RedisClientOptions, RedisClientType } from "redis";
3
- import { StateAdapter, StateItem, StateItemsInput } from "@motiadev/core";
4
-
5
- //#region src/redis-state-adapter.d.ts
6
- declare class RedisStateAdapter implements StateAdapter {
7
- private client;
8
- private keyPrefix;
9
- private ttl?;
10
- private connected;
11
- private isExternalClient;
12
- constructor(redisConnection: RedisClientType | RedisClientOptions, options?: RedisStateAdapterOptions);
13
- private connect;
14
- private ensureConnected;
15
- private makeKey;
16
- private makeTracePrefix;
17
- private extractKey;
18
- private determineType;
19
- get<T>(traceId: string, key: string): Promise<T | null>;
20
- set<T>(traceId: string, key: string, value: T): Promise<T>;
21
- delete<T>(traceId: string, key: string): Promise<T | null>;
22
- getGroup<T>(traceId: string): Promise<T[]>;
23
- clear(traceId: string): Promise<void>;
24
- cleanup(): Promise<void>;
25
- keys(traceId: string): Promise<string[]>;
26
- traceIds(): Promise<string[]>;
27
- items(input: StateItemsInput): Promise<StateItem[]>;
28
- private scanKeys;
29
- private applyFilters;
30
- private matchesFilter;
31
- }
32
- //#endregion
33
- export { RedisStateAdapter };
34
- //# sourceMappingURL=redis-state-adapter.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redis-state-adapter.d.mts","names":[],"sources":["../src/redis-state-adapter.ts"],"sourcesContent":[],"mappings":";;;;;cAQa,iBAAA,YAA6B;;EAA7B,QAAA,SAAA;EAOkB,QAAA,GAAA;EAAkB,QAAA,SAAA;EAA8B,QAAA,gBAAA;EAyEzB,WAAA,CAAA,eAAA,EAzEvB,eAyEuB,GAzEL,kBAyEK,EAAA,OAAA,CAAA,EAzEyB,wBAyEzB;EAAR,QAAA,OAAA;EAOM,QAAA,eAAA;EAAY,QAAA,OAAA;EAAR,QAAA,eAAA;EAcC,QAAA,UAAA;EAAR,QAAA,aAAA;EAQH,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EA7BA,OA6BA,CA7BQ,CA6BR,GAAA,IAAA,CAAA;EAAR,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAtBc,CAsBd,CAAA,EAtBkB,OAsBlB,CAtB0B,CAsB1B,CAAA;EAWN,MAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EAnBiB,OAmBjB,CAnByB,CAmBzB,GAAA,IAAA,CAAA;EAUb,QAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EArBmB,OAqBnB,CArB2B,CAqB3B,EAAA,CAAA;EAMY,KAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAhBC,OAgBD,CAAA,IAAA,CAAA;EAOX,OAAA,CAAA,CAAA,EAbD,OAaC,CAAA,IAAA,CAAA;EAiBC,IAAA,CAAA,OAAA,EAAA,MAAA,CAAA,EAxBU,OAwBV,CAAA,MAAA,EAAA,CAAA;EAA0B,QAAA,CAAA,CAAA,EAjB3B,OAiB2B,CAAA,MAAA,EAAA,CAAA;EAAR,KAAA,CAAA,KAAA,EAAlB,eAAkB,CAAA,EAAA,OAAA,CAAQ,SAAR,EAAA,CAAA;EAhKG,QAAA,QAAA;EAAY,QAAA,YAAA"}
@@ -1,203 +0,0 @@
1
- import { createClient } from "redis";
2
-
3
- //#region src/redis-state-adapter.ts
4
- function isRedisClient(input) {
5
- return typeof input === "object" && "isOpen" in input && "connect" in input;
6
- }
7
- var RedisStateAdapter = class {
8
- constructor(redisConnection, options) {
9
- this.connected = false;
10
- this.keyPrefix = options?.keyPrefix || "motia:state:";
11
- this.ttl = options?.ttl;
12
- if (isRedisClient(redisConnection)) {
13
- this.client = redisConnection;
14
- this.isExternalClient = true;
15
- this.connected = this.client.isOpen;
16
- } else {
17
- const config = redisConnection;
18
- this.isExternalClient = false;
19
- this.client = createClient(config);
20
- this.client.on("error", (err) => {
21
- console.error("[Redis State] Client error:", err);
22
- });
23
- this.client.on("connect", () => {
24
- this.connected = true;
25
- });
26
- this.client.on("disconnect", () => {
27
- console.warn("[Redis State] Disconnected");
28
- this.connected = false;
29
- });
30
- this.client.on("reconnecting", () => {
31
- console.log("[Redis State] Reconnecting...");
32
- });
33
- this.connect();
34
- }
35
- }
36
- async connect() {
37
- if (!this.connected && !this.client.isOpen) try {
38
- await this.client.connect();
39
- } catch (error) {
40
- console.error("[Redis State] Failed to connect:", error);
41
- throw error;
42
- }
43
- }
44
- async ensureConnected() {
45
- if (!this.client.isOpen) await this.connect();
46
- }
47
- makeKey(traceId, key) {
48
- return `${this.keyPrefix}${traceId}:${key}`;
49
- }
50
- makeTracePrefix(traceId) {
51
- return `${this.keyPrefix}${traceId}:`;
52
- }
53
- extractKey(fullKey, traceId) {
54
- const prefix = this.makeTracePrefix(traceId);
55
- return fullKey.slice(prefix.length);
56
- }
57
- determineType(value) {
58
- if (value === null) return "null";
59
- if (Array.isArray(value)) return "array";
60
- return [
61
- "string",
62
- "number",
63
- "boolean",
64
- "object"
65
- ].find((type) => typeof value === type) || "object";
66
- }
67
- async get(traceId, key) {
68
- await this.ensureConnected();
69
- const fullKey = this.makeKey(traceId, key);
70
- const value = await this.client.get(fullKey);
71
- return value ? JSON.parse(value) : null;
72
- }
73
- async set(traceId, key, value) {
74
- await this.ensureConnected();
75
- const fullKey = this.makeKey(traceId, key);
76
- const serialized = JSON.stringify(value);
77
- if (this.ttl) await this.client.setEx(fullKey, this.ttl, serialized);
78
- else await this.client.set(fullKey, serialized);
79
- return value;
80
- }
81
- async delete(traceId, key) {
82
- await this.ensureConnected();
83
- const fullKey = this.makeKey(traceId, key);
84
- const value = await this.get(traceId, key);
85
- await this.client.del(fullKey);
86
- return value;
87
- }
88
- async getGroup(traceId) {
89
- await this.ensureConnected();
90
- const pattern = `${this.makeTracePrefix(traceId)}*`;
91
- const keys = await this.scanKeys(pattern);
92
- if (keys.length === 0) return [];
93
- return (await this.client.mGet(keys)).filter((v) => v !== null).map((v) => JSON.parse(v));
94
- }
95
- async clear(traceId) {
96
- await this.ensureConnected();
97
- const pattern = `${this.makeTracePrefix(traceId)}*`;
98
- const keys = await this.scanKeys(pattern);
99
- if (keys.length > 0) await this.client.del(keys);
100
- }
101
- async cleanup() {
102
- if (!this.isExternalClient && this.client.isOpen) await this.client.quit();
103
- }
104
- async keys(traceId) {
105
- await this.ensureConnected();
106
- const pattern = `${this.makeTracePrefix(traceId)}*`;
107
- return (await this.scanKeys(pattern)).map((key) => this.extractKey(key, traceId));
108
- }
109
- async traceIds() {
110
- await this.ensureConnected();
111
- const pattern = `${this.keyPrefix}*`;
112
- const keys = await this.scanKeys(pattern);
113
- const traceIdSet = /* @__PURE__ */ new Set();
114
- for (const key of keys) {
115
- const traceId = key.slice(this.keyPrefix.length).split(":")[0];
116
- if (traceId) traceIdSet.add(traceId);
117
- }
118
- return Array.from(traceIdSet);
119
- }
120
- async items(input) {
121
- await this.ensureConnected();
122
- const items = [];
123
- if (input.groupId) {
124
- const pattern = `${this.makeTracePrefix(input.groupId)}*`;
125
- const keys = await this.scanKeys(pattern);
126
- for (const fullKey of keys) {
127
- const value = await this.client.get(fullKey);
128
- if (value !== null) {
129
- const key = this.extractKey(fullKey, input.groupId);
130
- const parsedValue = JSON.parse(value);
131
- items.push({
132
- groupId: input.groupId,
133
- key,
134
- type: this.determineType(parsedValue),
135
- value: parsedValue
136
- });
137
- }
138
- }
139
- } else {
140
- const traceIds = await this.traceIds();
141
- for (const traceId of traceIds) {
142
- const pattern = `${this.makeTracePrefix(traceId)}*`;
143
- const keys = await this.scanKeys(pattern);
144
- for (const fullKey of keys) {
145
- const value = await this.client.get(fullKey);
146
- if (value !== null) {
147
- const key = this.extractKey(fullKey, traceId);
148
- const parsedValue = JSON.parse(value);
149
- items.push({
150
- groupId: traceId,
151
- key,
152
- type: this.determineType(parsedValue),
153
- value: parsedValue
154
- });
155
- }
156
- }
157
- }
158
- }
159
- if (input.filter && input.filter.length > 0) return this.applyFilters(items, input.filter);
160
- return items;
161
- }
162
- async scanKeys(pattern) {
163
- const keys = [];
164
- let cursor = "0";
165
- do {
166
- const result = await this.client.scan(cursor.toString(), {
167
- MATCH: pattern,
168
- COUNT: 100
169
- });
170
- cursor = result.cursor;
171
- keys.push(...result.keys);
172
- } while (String(cursor) !== "0");
173
- return keys;
174
- }
175
- applyFilters(items, filters) {
176
- return items.filter((item) => {
177
- return filters.every((filter) => this.matchesFilter(item, filter));
178
- });
179
- }
180
- matchesFilter(item, filter) {
181
- const value = typeof item.value === "object" && item.value !== null ? item.value[filter.valueKey] : item.value;
182
- const filterValue = filter.value;
183
- switch (filter.operation) {
184
- case "eq": return value === filterValue;
185
- case "neq": return value !== filterValue;
186
- case "gt": return value > filterValue;
187
- case "gte": return value >= filterValue;
188
- case "lt": return value < filterValue;
189
- case "lte": return value <= filterValue;
190
- case "contains": return typeof value === "string" && value.includes(filterValue);
191
- case "notContains": return typeof value === "string" && !value.includes(filterValue);
192
- case "startsWith": return typeof value === "string" && value.startsWith(filterValue);
193
- case "endsWith": return typeof value === "string" && value.endsWith(filterValue);
194
- case "isNotNull": return value !== null && value !== void 0;
195
- case "isNull": return value === null || value === void 0;
196
- default: return false;
197
- }
198
- }
199
- };
200
-
201
- //#endregion
202
- export { RedisStateAdapter };
203
- //# sourceMappingURL=redis-state-adapter.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redis-state-adapter.mjs","names":["config: RedisClientOptions","items: StateItem[]","keys: string[]","cursor: string | number"],"sources":["../src/redis-state-adapter.ts"],"sourcesContent":["import type { StateAdapter, StateFilter, StateItem, StateItemsInput } from '@motiadev/core'\nimport { createClient, type RedisClientOptions, type RedisClientType } from 'redis'\nimport type { RedisStateAdapterOptions } from './types'\n\nfunction isRedisClient(input: RedisClientType | RedisClientOptions): input is RedisClientType {\n return typeof input === 'object' && 'isOpen' in input && 'connect' in input\n}\n\nexport class RedisStateAdapter implements StateAdapter {\n private client: RedisClientType\n private keyPrefix: string\n private ttl?: number\n private connected = false\n private isExternalClient: boolean\n\n constructor(redisConnection: RedisClientType | RedisClientOptions, options?: RedisStateAdapterOptions) {\n this.keyPrefix = options?.keyPrefix || 'motia:state:'\n this.ttl = options?.ttl\n\n if (isRedisClient(redisConnection)) {\n this.client = redisConnection\n this.isExternalClient = true\n this.connected = this.client.isOpen\n } else {\n const config: RedisClientOptions = redisConnection\n this.isExternalClient = false\n\n this.client = createClient(config) as RedisClientType\n\n this.client.on('error', (err) => {\n console.error('[Redis State] Client error:', err)\n })\n\n this.client.on('connect', () => {\n this.connected = true\n })\n\n this.client.on('disconnect', () => {\n console.warn('[Redis State] Disconnected')\n this.connected = false\n })\n\n this.client.on('reconnecting', () => {\n console.log('[Redis State] Reconnecting...')\n })\n\n this.connect()\n }\n }\n\n private async connect(): Promise<void> {\n if (!this.connected && !this.client.isOpen) {\n try {\n await this.client.connect()\n } catch (error) {\n console.error('[Redis State] Failed to connect:', error)\n throw error\n }\n }\n }\n\n private async ensureConnected(): Promise<void> {\n if (!this.client.isOpen) {\n await this.connect()\n }\n }\n\n private makeKey(traceId: string, key: string): string {\n return `${this.keyPrefix}${traceId}:${key}`\n }\n\n private makeTracePrefix(traceId: string): string {\n return `${this.keyPrefix}${traceId}:`\n }\n\n private extractKey(fullKey: string, traceId: string): string {\n const prefix = this.makeTracePrefix(traceId)\n return fullKey.slice(prefix.length)\n }\n\n private determineType(value: unknown): StateItem['type'] {\n if (value === null) return 'null'\n if (Array.isArray(value)) return 'array'\n return (\n (['string', 'number', 'boolean', 'object'].find((type) => typeof value === type) as StateItem['type']) || 'object'\n )\n }\n\n async get<T>(traceId: string, key: string): Promise<T | null> {\n await this.ensureConnected()\n const fullKey = this.makeKey(traceId, key)\n const value = await this.client.get(fullKey)\n return value ? JSON.parse(value) : null\n }\n\n async set<T>(traceId: string, key: string, value: T): Promise<T> {\n await this.ensureConnected()\n const fullKey = this.makeKey(traceId, key)\n const serialized = JSON.stringify(value)\n\n if (this.ttl) {\n await this.client.setEx(fullKey, this.ttl, serialized)\n } else {\n await this.client.set(fullKey, serialized)\n }\n\n return value\n }\n\n async delete<T>(traceId: string, key: string): Promise<T | null> {\n await this.ensureConnected()\n const fullKey = this.makeKey(traceId, key)\n const value = await this.get<T>(traceId, key)\n await this.client.del(fullKey)\n return value\n }\n\n async getGroup<T>(traceId: string): Promise<T[]> {\n await this.ensureConnected()\n const pattern = `${this.makeTracePrefix(traceId)}*`\n const keys = await this.scanKeys(pattern)\n\n if (keys.length === 0) return []\n\n const values = await this.client.mGet(keys)\n return values.filter((v): v is string => v !== null).map((v) => JSON.parse(v))\n }\n\n async clear(traceId: string): Promise<void> {\n await this.ensureConnected()\n const pattern = `${this.makeTracePrefix(traceId)}*`\n const keys = await this.scanKeys(pattern)\n\n if (keys.length > 0) {\n await this.client.del(keys)\n }\n }\n\n async cleanup(): Promise<void> {\n if (!this.isExternalClient && this.client.isOpen) {\n await this.client.quit()\n }\n }\n\n async keys(traceId: string): Promise<string[]> {\n await this.ensureConnected()\n const pattern = `${this.makeTracePrefix(traceId)}*`\n const keys = await this.scanKeys(pattern)\n return keys.map((key) => this.extractKey(key, traceId))\n }\n\n async traceIds(): Promise<string[]> {\n await this.ensureConnected()\n const pattern = `${this.keyPrefix}*`\n const keys = await this.scanKeys(pattern)\n\n const traceIdSet = new Set<string>()\n for (const key of keys) {\n const withoutPrefix = key.slice(this.keyPrefix.length)\n const traceId = withoutPrefix.split(':')[0]\n if (traceId) {\n traceIdSet.add(traceId)\n }\n }\n\n return Array.from(traceIdSet)\n }\n\n async items(input: StateItemsInput): Promise<StateItem[]> {\n await this.ensureConnected()\n const items: StateItem[] = []\n\n if (input.groupId) {\n const pattern = `${this.makeTracePrefix(input.groupId)}*`\n const keys = await this.scanKeys(pattern)\n\n for (const fullKey of keys) {\n const value = await this.client.get(fullKey)\n if (value !== null) {\n const key = this.extractKey(fullKey, input.groupId)\n const parsedValue = JSON.parse(value)\n items.push({\n groupId: input.groupId,\n key,\n type: this.determineType(parsedValue),\n value: parsedValue,\n })\n }\n }\n } else {\n const traceIds = await this.traceIds()\n for (const traceId of traceIds) {\n const pattern = `${this.makeTracePrefix(traceId)}*`\n const keys = await this.scanKeys(pattern)\n\n for (const fullKey of keys) {\n const value = await this.client.get(fullKey)\n if (value !== null) {\n const key = this.extractKey(fullKey, traceId)\n const parsedValue = JSON.parse(value)\n items.push({\n groupId: traceId,\n key,\n type: this.determineType(parsedValue),\n value: parsedValue,\n })\n }\n }\n }\n }\n\n if (input.filter && input.filter.length > 0) {\n return this.applyFilters(items, input.filter)\n }\n\n return items\n }\n\n private async scanKeys(pattern: string): Promise<string[]> {\n const keys: string[] = []\n let cursor: string | number = '0'\n\n do {\n const result = await this.client.scan(cursor.toString(), {\n MATCH: pattern,\n COUNT: 100,\n })\n cursor = result.cursor\n keys.push(...result.keys)\n } while (String(cursor) !== '0')\n\n return keys\n }\n\n private applyFilters(items: StateItem[], filters: StateFilter[]): StateItem[] {\n return items.filter((item) => {\n return filters.every((filter) => this.matchesFilter(item, filter))\n })\n }\n\n private matchesFilter(item: StateItem, filter: StateFilter): boolean {\n const value =\n typeof item.value === 'object' && item.value !== null ? (item.value as any)[filter.valueKey] : item.value\n\n const filterValue = filter.value\n\n switch (filter.operation) {\n case 'eq':\n return value === filterValue\n case 'neq':\n return value !== filterValue\n case 'gt':\n return value > filterValue\n case 'gte':\n return value >= filterValue\n case 'lt':\n return value < filterValue\n case 'lte':\n return value <= filterValue\n case 'contains':\n return typeof value === 'string' && value.includes(filterValue)\n case 'notContains':\n return typeof value === 'string' && !value.includes(filterValue)\n case 'startsWith':\n return typeof value === 'string' && value.startsWith(filterValue)\n case 'endsWith':\n return typeof value === 'string' && value.endsWith(filterValue)\n case 'isNotNull':\n return value !== null && value !== undefined\n case 'isNull':\n return value === null || value === undefined\n default:\n return false\n }\n }\n}\n"],"mappings":"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"}
package/dist/types.d.mts DELETED
@@ -1,8 +0,0 @@
1
- //#region src/types.d.ts
2
- interface RedisStateAdapterOptions {
3
- keyPrefix?: string;
4
- ttl?: number;
5
- }
6
- //#endregion
7
- export { RedisStateAdapterOptions };
8
- //# sourceMappingURL=types.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";UAAiB,wBAAA;EAAA,SAAA,CAAA,EAAA,MAAA"}
package/tsdown.config.ts DELETED
@@ -1,17 +0,0 @@
1
- import { defineConfig } from 'tsdown'
2
-
3
- export default defineConfig({
4
- entry: {
5
- index: './src/index.ts',
6
- },
7
- format: 'esm',
8
- platform: 'node',
9
- external: ['@motiadev/core', 'redis'],
10
- dts: {
11
- build: true,
12
- },
13
- clean: true,
14
- outDir: 'dist',
15
- sourcemap: true,
16
- unbundle: true,
17
- })