@zintrust/cache-redis 0.4.70 → 0.4.72
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,129 @@
|
|
|
1
|
+
import { ErrorFactory, Logger } from '@zintrust/core';
|
|
2
|
+
const createSendCommandFunction = (getStub, connect) => {
|
|
3
|
+
return async (command, args) => {
|
|
4
|
+
await connect();
|
|
5
|
+
const stub = getStub();
|
|
6
|
+
const executePath = 'http://do/execute'; //NOSONAR
|
|
7
|
+
const payload = JSON.stringify({
|
|
8
|
+
command,
|
|
9
|
+
params: args,
|
|
10
|
+
});
|
|
11
|
+
const response = await stub.fetch(executePath, {
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: { 'Content-Type': 'application/json' },
|
|
14
|
+
body: payload,
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
const text = await response.text();
|
|
18
|
+
let errDetail;
|
|
19
|
+
try {
|
|
20
|
+
errDetail = JSON.parse(text);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
errDetail = { error: text };
|
|
24
|
+
}
|
|
25
|
+
const msg = errDetail.error ||
|
|
26
|
+
errDetail.message ||
|
|
27
|
+
response.statusText;
|
|
28
|
+
throw ErrorFactory.createGeneralError(`DO Command Failed: ${msg}`);
|
|
29
|
+
}
|
|
30
|
+
const json = (await response.json());
|
|
31
|
+
if (json !== null && typeof json === 'object' && 'result' in json) {
|
|
32
|
+
return json.result;
|
|
33
|
+
}
|
|
34
|
+
return json;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const createConnectionManager = (getNamespace) => {
|
|
38
|
+
let connected = false;
|
|
39
|
+
const getStub = () => {
|
|
40
|
+
const namespace = getNamespace();
|
|
41
|
+
if (!namespace) {
|
|
42
|
+
throw ErrorFactory.createConfigError('REDIS_POOL binding not found. Cannot connect to Durable Object pool.');
|
|
43
|
+
}
|
|
44
|
+
const id = namespace.idFromName('default');
|
|
45
|
+
return namespace.get(id);
|
|
46
|
+
};
|
|
47
|
+
const connect = async () => {
|
|
48
|
+
if (connected)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const stub = getStub();
|
|
52
|
+
const health = 'http://do/health'; //NOSONAR
|
|
53
|
+
const res = await stub.fetch(health, {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
});
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
throw ErrorFactory.createGeneralError(`DO health check failed: ${res.status}`);
|
|
58
|
+
}
|
|
59
|
+
const body = (await res.json());
|
|
60
|
+
if (!body.connected) {
|
|
61
|
+
Logger.info('[RedisWorkersDurableObjectAdapter] DO not connected yet, will init on first command');
|
|
62
|
+
}
|
|
63
|
+
connected = true;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
Logger.error('[RedisWorkersDurableObjectAdapter] Connection failed', err);
|
|
67
|
+
throw ErrorFactory.createGeneralError('Failed to connect to Redis DO', err);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const sendCommand = createSendCommandFunction(getStub, connect);
|
|
71
|
+
return {
|
|
72
|
+
connect,
|
|
73
|
+
sendCommand,
|
|
74
|
+
disconnect: () => {
|
|
75
|
+
connected = false;
|
|
76
|
+
},
|
|
77
|
+
isConnected: () => connected,
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
const toNumber = (value) => {
|
|
81
|
+
if (typeof value === 'number')
|
|
82
|
+
return value;
|
|
83
|
+
if (typeof value === 'string') {
|
|
84
|
+
const parsed = Number(value);
|
|
85
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
86
|
+
}
|
|
87
|
+
return 0;
|
|
88
|
+
};
|
|
89
|
+
export const RedisWorkersDurableObjectAdapter = Object.freeze({
|
|
90
|
+
create() {
|
|
91
|
+
const connectionManager = createConnectionManager(() => {
|
|
92
|
+
const globalEnv = globalThis.env;
|
|
93
|
+
return globalEnv?.['REDIS_POOL'];
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
async get(key) {
|
|
97
|
+
const raw = await connectionManager.sendCommand('GET', [key]);
|
|
98
|
+
if (raw === null || raw === undefined)
|
|
99
|
+
return null;
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(String(raw));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
async set(key, value, ttl) {
|
|
108
|
+
const json = JSON.stringify(value);
|
|
109
|
+
if (Number.isFinite(ttl) && (ttl ?? 0) > 0) {
|
|
110
|
+
await connectionManager.sendCommand('SET', [key, json, 'EX', ttl]);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
await connectionManager.sendCommand('SET', [key, json]);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
async delete(key) {
|
|
117
|
+
await connectionManager.sendCommand('DEL', [key]);
|
|
118
|
+
},
|
|
119
|
+
async clear() {
|
|
120
|
+
await connectionManager.sendCommand('FLUSHDB', []);
|
|
121
|
+
},
|
|
122
|
+
async has(key) {
|
|
123
|
+
const count = await connectionManager.sendCommand('EXISTS', [key]);
|
|
124
|
+
return toNumber(count) > 0;
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
export default RedisWorkersDurableObjectAdapter;
|
package/dist/build-manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/cache-redis",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"buildDate": "2026-04-
|
|
3
|
+
"version": "0.4.72",
|
|
4
|
+
"buildDate": "2026-04-06T17:13:09.661Z",
|
|
5
5
|
"buildEnvironment": {
|
|
6
|
-
"node": "
|
|
7
|
-
"platform": "
|
|
8
|
-
"arch": "
|
|
6
|
+
"node": "v22.22.1",
|
|
7
|
+
"platform": "darwin",
|
|
8
|
+
"arch": "arm64"
|
|
9
9
|
},
|
|
10
10
|
"git": {
|
|
11
|
-
"commit": "
|
|
12
|
-
"branch": "
|
|
11
|
+
"commit": "996fb4dc",
|
|
12
|
+
"branch": "release"
|
|
13
13
|
},
|
|
14
14
|
"package": {
|
|
15
15
|
"engines": {
|
|
@@ -31,13 +31,25 @@
|
|
|
31
31
|
"size": 1693,
|
|
32
32
|
"sha256": "b1cd4417d827598b41226597355559eef423eac869448df5fd94d338d16a09f2"
|
|
33
33
|
},
|
|
34
|
+
"RedisWorkersDurableObjectAdapter.d.ts": {
|
|
35
|
+
"size": 193,
|
|
36
|
+
"sha256": "859d3177d302c65f93add57216eae91d8c45874801bb75bdea3d6f6b00fb00c3"
|
|
37
|
+
},
|
|
38
|
+
"RedisWorkersDurableObjectAdapter.js": {
|
|
39
|
+
"size": 4482,
|
|
40
|
+
"sha256": "5b0ae2883872ce974ecaf01f07d35b72e6da468439912a57734ccd5222705bfd"
|
|
41
|
+
},
|
|
42
|
+
"build-manifest.json": {
|
|
43
|
+
"size": 1702,
|
|
44
|
+
"sha256": "56b119a0de0905853463885edc07919693b509d40cd06133ffa91eb3a600ab56"
|
|
45
|
+
},
|
|
34
46
|
"index.d.ts": {
|
|
35
47
|
"size": 842,
|
|
36
48
|
"sha256": "b47614dfdb736524165785958f4a685818c055315961c2e2b48d99ef6ca491e2"
|
|
37
49
|
},
|
|
38
50
|
"index.js": {
|
|
39
|
-
"size":
|
|
40
|
-
"sha256": "
|
|
51
|
+
"size": 6819,
|
|
52
|
+
"sha256": "52212fcd6e65730e0fedae07e2207c4270cd40cc1e437a471a9e89b7eebf49c9"
|
|
41
53
|
},
|
|
42
54
|
"register.d.ts": {
|
|
43
55
|
"size": 184,
|
package/dist/index.js
CHANGED
|
@@ -11,9 +11,27 @@ const safeJsonParse = (value) => {
|
|
|
11
11
|
async function importRedis() {
|
|
12
12
|
return (await import('redis'));
|
|
13
13
|
}
|
|
14
|
+
const logCacheFailure = (action, error) => {
|
|
15
|
+
Logger.error(`Redis cache ${action} failed`, error);
|
|
16
|
+
};
|
|
17
|
+
const createCacheFailureState = () => {
|
|
18
|
+
let disabled = false;
|
|
19
|
+
return {
|
|
20
|
+
isDisabled: () => disabled,
|
|
21
|
+
disableAfterFailure: (action, error) => {
|
|
22
|
+
if (!disabled) {
|
|
23
|
+
logCacheFailure(action, error);
|
|
24
|
+
}
|
|
25
|
+
disabled = true;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
};
|
|
14
29
|
const createCacheOperations = (ensureClient, operations, defaultTtl) => {
|
|
30
|
+
const failureState = createCacheFailureState();
|
|
15
31
|
return {
|
|
16
32
|
async get(key) {
|
|
33
|
+
if (failureState.isDisabled())
|
|
34
|
+
return null;
|
|
17
35
|
try {
|
|
18
36
|
const client = await ensureClient();
|
|
19
37
|
const value = await operations.get(client, key);
|
|
@@ -22,28 +40,57 @@ const createCacheOperations = (ensureClient, operations, defaultTtl) => {
|
|
|
22
40
|
return safeJsonParse(value);
|
|
23
41
|
}
|
|
24
42
|
catch (error) {
|
|
25
|
-
|
|
43
|
+
failureState.disableAfterFailure('GET', error);
|
|
26
44
|
return null;
|
|
27
45
|
}
|
|
28
46
|
},
|
|
29
47
|
async set(key, value, ttl) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
if (failureState.isDisabled())
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const client = await ensureClient();
|
|
52
|
+
const json = JSON.stringify(value);
|
|
53
|
+
const effectiveTtl = ttl ?? defaultTtl;
|
|
54
|
+
await operations.set(client, key, json, effectiveTtl);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
failureState.disableAfterFailure('SET', error);
|
|
58
|
+
}
|
|
34
59
|
},
|
|
35
60
|
async delete(key) {
|
|
36
|
-
|
|
37
|
-
|
|
61
|
+
if (failureState.isDisabled())
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
const client = await ensureClient();
|
|
65
|
+
await operations.del(client, key);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
failureState.disableAfterFailure('DEL', error);
|
|
69
|
+
}
|
|
38
70
|
},
|
|
39
71
|
async clear() {
|
|
40
|
-
|
|
41
|
-
|
|
72
|
+
if (failureState.isDisabled())
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
const client = await ensureClient();
|
|
76
|
+
await operations.clear(client);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
failureState.disableAfterFailure('FLUSHDB', error);
|
|
80
|
+
}
|
|
42
81
|
},
|
|
43
82
|
async has(key) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
83
|
+
if (failureState.isDisabled())
|
|
84
|
+
return false;
|
|
85
|
+
try {
|
|
86
|
+
const client = await ensureClient();
|
|
87
|
+
const count = await operations.exists(client, key);
|
|
88
|
+
return count > 0;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
failureState.disableAfterFailure('EXISTS', error);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
47
94
|
},
|
|
48
95
|
};
|
|
49
96
|
};
|
|
@@ -73,9 +120,8 @@ const createWorkersCacheDriver = (config) => {
|
|
|
73
120
|
return redisClient.set(key, json);
|
|
74
121
|
}
|
|
75
122
|
},
|
|
76
|
-
del: (redisClient, key) => {
|
|
77
|
-
redisClient.del(key);
|
|
78
|
-
return Promise.resolve();
|
|
123
|
+
del: async (redisClient, key) => {
|
|
124
|
+
await redisClient.del(key);
|
|
79
125
|
},
|
|
80
126
|
clear: (redisClient) => {
|
|
81
127
|
if (typeof redisClient.flushDb === 'function') {
|
|
@@ -95,7 +141,11 @@ const createNodeCacheDriver = (config) => {
|
|
|
95
141
|
const ensureClient = async () => {
|
|
96
142
|
if (client === undefined) {
|
|
97
143
|
const { createClient } = await importRedis();
|
|
98
|
-
client = createClient({
|
|
144
|
+
client = createClient({
|
|
145
|
+
socket: { host: config.host, port: config.port },
|
|
146
|
+
password: config.password,
|
|
147
|
+
database: config.database ?? 0,
|
|
148
|
+
});
|
|
99
149
|
}
|
|
100
150
|
if (!connected) {
|
|
101
151
|
await client.connect();
|
|
@@ -113,14 +163,10 @@ const createNodeCacheDriver = (config) => {
|
|
|
113
163
|
return redisClient.set(key, json);
|
|
114
164
|
}
|
|
115
165
|
},
|
|
116
|
-
del: (redisClient, key) => {
|
|
117
|
-
redisClient.del(key);
|
|
118
|
-
return Promise.resolve();
|
|
119
|
-
},
|
|
120
|
-
clear: (redisClient) => {
|
|
121
|
-
redisClient.flushDb();
|
|
122
|
-
return Promise.resolve();
|
|
166
|
+
del: async (redisClient, key) => {
|
|
167
|
+
await redisClient.del(key);
|
|
123
168
|
},
|
|
169
|
+
clear: (redisClient) => redisClient.flushDb(),
|
|
124
170
|
exists: (redisClient, key) => redisClient.exists(key),
|
|
125
171
|
}, config.ttl ?? 300);
|
|
126
172
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/cache-redis",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.72",
|
|
4
4
|
"description": "Redis cache driver for ZinTrust.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"node": ">=20.0.0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@zintrust/core": "^0.4.
|
|
26
|
+
"@zintrust/core": "^0.4.72"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|