@pikku/redis 0.12.4 → 0.12.5
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 +14 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/redis-channel-store.d.ts +3 -4
- package/dist/src/redis-channel-store.js +6 -6
- package/dist/src/redis-channel-store.js.map +1 -1
- package/dist/src/redis-deployment-service.d.ts +6 -3
- package/dist/src/redis-deployment-service.js +28 -20
- package/dist/src/redis-deployment-service.js.map +1 -1
- package/dist/src/redis-secret-service.js +1 -1
- package/dist/src/redis-secret-service.js.map +1 -1
- package/dist/src/redis-session-store.d.ts +16 -0
- package/dist/src/redis-session-store.js +55 -0
- package/dist/src/redis-session-store.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/redis-channel-store.ts +8 -9
- package/src/redis-deployment-service.ts +40 -23
- package/src/redis-secret-service.ts +1 -1
- package/src/redis-session-store.ts +71 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
## 0.12.0
|
|
2
2
|
|
|
3
|
+
## 0.12.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 311c0c4: Unify session persistence through SessionStore, remove session blob from ChannelStore
|
|
8
|
+
|
|
9
|
+
- PikkuSessionService now persists sessions via SessionStore on set()/clear() instead of every function call
|
|
10
|
+
- ChannelStore no longer stores session data — maps channelId to pikkuUserId only
|
|
11
|
+
- ChannelStore API: setUserSession/getChannelAndSession replaced with setPikkuUserId/getChannel
|
|
12
|
+
- Serverless channel runner resolves sessions from SessionStore using pikkuUserId from ChannelStore
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [311c0c4]
|
|
15
|
+
- @pikku/core@0.12.18
|
|
16
|
+
|
|
3
17
|
## 0.12.4
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/src/index.d.ts
CHANGED
|
@@ -8,3 +8,4 @@ export { RedisAgentRunService } from './redis-agent-run-service.js';
|
|
|
8
8
|
export { RedisSecretService } from './redis-secret-service.js';
|
|
9
9
|
export type { RedisSecretServiceConfig } from './redis-secret-service.js';
|
|
10
10
|
export type { AgentRunService, AgentRunRow } from '@pikku/core/ai-agent';
|
|
11
|
+
export { RedisSessionStore } from './redis-session-store.js';
|
package/dist/src/index.js
CHANGED
|
@@ -5,4 +5,5 @@ export { RedisWorkflowService } from './redis-workflow-service.js';
|
|
|
5
5
|
export { RedisWorkflowRunService } from './redis-workflow-run-service.js';
|
|
6
6
|
export { RedisAgentRunService } from './redis-agent-run-service.js';
|
|
7
7
|
export { RedisSecretService } from './redis-secret-service.js';
|
|
8
|
+
export { RedisSessionStore } from './redis-session-store.js';
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAEzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAEzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAG9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CoreUserSession } from '@pikku/core';
|
|
2
1
|
import type { Channel } from '@pikku/core/channel';
|
|
3
2
|
import { ChannelStore } from '@pikku/core/channel';
|
|
4
3
|
import { Redis, type RedisOptions } from 'ioredis';
|
|
@@ -11,9 +10,9 @@ export declare class RedisChannelStore extends ChannelStore {
|
|
|
11
10
|
private channelKey;
|
|
12
11
|
addChannel({ channelId, channelName, openingData, }: Channel): Promise<void>;
|
|
13
12
|
removeChannels(channelIds: string[]): Promise<void>;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
setPikkuUserId(channelId: string, pikkuUserId: string | null): Promise<void>;
|
|
14
|
+
getChannel(channelId: string): Promise<Channel & {
|
|
15
|
+
pikkuUserId?: string;
|
|
17
16
|
}>;
|
|
18
17
|
close(): Promise<void>;
|
|
19
18
|
}
|
|
@@ -42,16 +42,16 @@ export class RedisChannelStore extends ChannelStore {
|
|
|
42
42
|
}
|
|
43
43
|
await pipeline.exec();
|
|
44
44
|
}
|
|
45
|
-
async
|
|
45
|
+
async setPikkuUserId(channelId, pikkuUserId) {
|
|
46
46
|
const key = this.channelKey(channelId);
|
|
47
|
-
if (
|
|
48
|
-
await this.redis.hset(key, '
|
|
47
|
+
if (pikkuUserId) {
|
|
48
|
+
await this.redis.hset(key, 'pikkuUserId', pikkuUserId);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
|
-
await this.redis.hdel(key, '
|
|
51
|
+
await this.redis.hdel(key, 'pikkuUserId');
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
async
|
|
54
|
+
async getChannel(channelId) {
|
|
55
55
|
const key = this.channelKey(channelId);
|
|
56
56
|
const data = await this.redis.hgetall(key);
|
|
57
57
|
if (!data.channelId) {
|
|
@@ -61,7 +61,7 @@ export class RedisChannelStore extends ChannelStore {
|
|
|
61
61
|
channelId: data.channelId,
|
|
62
62
|
channelName: data.channelName,
|
|
63
63
|
openingData: data.openingData ? JSON.parse(data.openingData) : {},
|
|
64
|
-
|
|
64
|
+
pikkuUserId: data.pikkuUserId || undefined,
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
async close() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-channel-store.js","sourceRoot":"","sources":["../../src/redis-channel-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis-channel-store.js","sourceRoot":"","sources":["../../src/redis-channel-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type { DeploymentService, DeploymentServiceConfig, DeploymentConfig
|
|
1
|
+
import type { DeploymentService, DeploymentServiceConfig, DeploymentConfig } from '@pikku/core/services';
|
|
2
|
+
import type { JWTService, SecretService } from '@pikku/core/services';
|
|
2
3
|
import { Redis, type RedisOptions } from 'ioredis';
|
|
3
4
|
export declare class RedisDeploymentService implements DeploymentService {
|
|
5
|
+
private jwt?;
|
|
6
|
+
private secrets?;
|
|
4
7
|
private redis;
|
|
5
8
|
private keyPrefix;
|
|
6
9
|
private ownsConnection;
|
|
@@ -8,12 +11,12 @@ export declare class RedisDeploymentService implements DeploymentService {
|
|
|
8
11
|
private deploymentConfig?;
|
|
9
12
|
private heartbeatInterval;
|
|
10
13
|
private heartbeatTtl;
|
|
11
|
-
constructor(config: DeploymentServiceConfig, connectionOrConfig: Redis | RedisOptions | string, keyPrefix?: string);
|
|
14
|
+
constructor(config: DeploymentServiceConfig, connectionOrConfig: Redis | RedisOptions | string, keyPrefix?: string, jwt?: JWTService | undefined, secrets?: SecretService | undefined);
|
|
12
15
|
private deploymentKey;
|
|
13
16
|
private functionsIndexKey;
|
|
14
17
|
init(): Promise<void>;
|
|
15
18
|
start(config: DeploymentConfig): Promise<void>;
|
|
16
19
|
stop(): Promise<void>;
|
|
17
|
-
|
|
20
|
+
invoke(funcName: string, data: unknown, session?: unknown, traceId?: string): Promise<unknown>;
|
|
18
21
|
private sendHeartbeat;
|
|
19
22
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { buildRemoteHeaders } from '@pikku/core/remote';
|
|
1
2
|
import { getAllFunctionNames } from '@pikku/core/function';
|
|
2
3
|
import { Redis } from 'ioredis';
|
|
3
4
|
export class RedisDeploymentService {
|
|
5
|
+
jwt;
|
|
6
|
+
secrets;
|
|
4
7
|
redis;
|
|
5
8
|
keyPrefix;
|
|
6
9
|
ownsConnection;
|
|
@@ -8,7 +11,9 @@ export class RedisDeploymentService {
|
|
|
8
11
|
deploymentConfig;
|
|
9
12
|
heartbeatInterval;
|
|
10
13
|
heartbeatTtl;
|
|
11
|
-
constructor(config, connectionOrConfig, keyPrefix = 'pikku') {
|
|
14
|
+
constructor(config, connectionOrConfig, keyPrefix = 'pikku', jwt, secrets) {
|
|
15
|
+
this.jwt = jwt;
|
|
16
|
+
this.secrets = secrets;
|
|
12
17
|
this.heartbeatInterval = config.heartbeatInterval ?? 10000;
|
|
13
18
|
this.heartbeatTtl = config.heartbeatTtl ?? 30000;
|
|
14
19
|
this.keyPrefix = keyPrefix;
|
|
@@ -67,28 +72,31 @@ export class RedisDeploymentService {
|
|
|
67
72
|
await this.redis.quit();
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
|
-
async
|
|
71
|
-
const
|
|
75
|
+
async invoke(funcName, data, session, traceId) {
|
|
76
|
+
const headers = await buildRemoteHeaders(this.jwt, this.secrets, funcName, session, traceId);
|
|
77
|
+
const indexKey = this.functionsIndexKey(funcName);
|
|
72
78
|
const now = Date.now();
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const pipelineResults = await pipeline.exec();
|
|
77
|
-
const deploymentIds = pipelineResults?.[1]?.[1] ?? [];
|
|
78
|
-
if (deploymentIds.length === 0) {
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
const results = [];
|
|
79
|
+
await this.redis.zremrangebyscore(indexKey, '-inf', now);
|
|
80
|
+
const deploymentIds = await this.redis.zrangebyscore(indexKey, now, '+inf');
|
|
81
|
+
let endpoint = null;
|
|
82
82
|
for (const deploymentId of deploymentIds) {
|
|
83
|
-
|
|
84
|
-
if (endpoint)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
endpoint = await this.redis.hget(this.deploymentKey(deploymentId), 'endpoint');
|
|
84
|
+
if (endpoint)
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
if (!endpoint) {
|
|
88
|
+
throw new Error(`No deployment found for function '${funcName}'`);
|
|
89
|
+
}
|
|
90
|
+
const url = `${endpoint}/remote/rpc/${encodeURIComponent(funcName)}`;
|
|
91
|
+
const response = await fetch(url, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers,
|
|
94
|
+
body: JSON.stringify({ data }),
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
throw new Error(`Remote RPC call to '${funcName}' failed: ${response.status}`);
|
|
90
98
|
}
|
|
91
|
-
return
|
|
99
|
+
return response.json();
|
|
92
100
|
}
|
|
93
101
|
async sendHeartbeat() {
|
|
94
102
|
if (!this.deploymentConfig)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-deployment-service.js","sourceRoot":"","sources":["../../src/redis-deployment-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis-deployment-service.js","sourceRoot":"","sources":["../../src/redis-deployment-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,7 +40,7 @@ export class RedisSecretService {
|
|
|
40
40
|
async getSecret(key) {
|
|
41
41
|
const data = await this.redis.hgetall(this.secretKey(key));
|
|
42
42
|
if (!data.ciphertext)
|
|
43
|
-
throw new Error(
|
|
43
|
+
throw new Error('Requested secret not found');
|
|
44
44
|
const kek = this.getKEK(Number(data.key_version));
|
|
45
45
|
return envelopeDecrypt(kek, data.ciphertext, data.wrapped_dek);
|
|
46
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-secret-service.js","sourceRoot":"","sources":["../../src/redis-secret-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAqB,MAAM,SAAS,CAAA;AAClD,OAAO,EACL,eAAe,EACf,eAAe,EACf,cAAc,GACf,MAAM,0BAA0B,CAAA;AASjC,MAAM,OAAO,kBAAkB;IACrB,KAAK,CAAO;IACZ,cAAc,CAAS;IACvB,GAAG,CAAQ;IACX,UAAU,CAAQ;IAClB,WAAW,CAAS;IACpB,SAAS,CAAQ;IAEzB,YACE,kBAAiD,EACjD,MAAgC;QAEhC,IACE,OAAO,kBAAkB,KAAK,QAAQ;YACtC,SAAS,IAAI,kBAAkB;YAC/B,MAAM,IAAI,kBAAkB,EAC5B,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,kBAA2B,CAAA;YACxC,IAAI,CAAC,cAAc,GAAG,KAAK,CAAA;QAC7B,CAAC;aAAM,IAAI,OAAO,kBAAkB,KAAK,QAAQ,EAAE,CAAC;YAClD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;YAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;YAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;QAC5B,CAAC;QAED,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;QACrB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,CAAC,CAAA;QACxC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAA;QACrC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,OAAO,CAAA;IAC9C,CAAC;IAEO,SAAS,CAAC,GAAW;QAC3B,OAAO,GAAG,IAAI,CAAC,SAAS,WAAW,GAAG,EAAE,CAAA;IAC1C,CAAC;IAEO,MAAM,CAAC,OAAe;QAC5B,IAAI,OAAO,KAAK,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC,GAAG,CAAA;QAChD,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,WAAW,CAAA;QAC7C,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAA;IAChE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,GAAW;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;QAC1D,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"redis-secret-service.js","sourceRoot":"","sources":["../../src/redis-secret-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CoreUserSession } from '@pikku/core';
|
|
2
|
+
import type { SessionStore } from '@pikku/core/services';
|
|
3
|
+
import { Redis, type RedisOptions } from 'ioredis';
|
|
4
|
+
export declare class RedisSessionStore implements SessionStore {
|
|
5
|
+
private redis;
|
|
6
|
+
private keyPrefix;
|
|
7
|
+
private ownsConnection;
|
|
8
|
+
private ttlSeconds?;
|
|
9
|
+
constructor(connectionOrConfig: Redis | RedisOptions | string, keyPrefix?: string, ttlSeconds?: number);
|
|
10
|
+
init(): Promise<void>;
|
|
11
|
+
private sessionKey;
|
|
12
|
+
get(pikkuUserId: string): Promise<CoreUserSession | undefined>;
|
|
13
|
+
set(pikkuUserId: string, session: CoreUserSession): Promise<void>;
|
|
14
|
+
clear(pikkuUserId: string): Promise<void>;
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Redis } from 'ioredis';
|
|
2
|
+
export class RedisSessionStore {
|
|
3
|
+
redis;
|
|
4
|
+
keyPrefix;
|
|
5
|
+
ownsConnection;
|
|
6
|
+
ttlSeconds;
|
|
7
|
+
constructor(connectionOrConfig, keyPrefix = 'pikku', ttlSeconds) {
|
|
8
|
+
this.keyPrefix = keyPrefix;
|
|
9
|
+
this.ttlSeconds = ttlSeconds;
|
|
10
|
+
if (connectionOrConfig instanceof Redis) {
|
|
11
|
+
this.redis = connectionOrConfig;
|
|
12
|
+
this.ownsConnection = false;
|
|
13
|
+
}
|
|
14
|
+
else if (typeof connectionOrConfig === 'string') {
|
|
15
|
+
this.redis = new Redis(connectionOrConfig);
|
|
16
|
+
this.ownsConnection = true;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
this.redis = new Redis(connectionOrConfig);
|
|
20
|
+
this.ownsConnection = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async init() {
|
|
24
|
+
await this.redis.ping();
|
|
25
|
+
}
|
|
26
|
+
sessionKey(pikkuUserId) {
|
|
27
|
+
return `${this.keyPrefix}:session:${pikkuUserId}`;
|
|
28
|
+
}
|
|
29
|
+
async get(pikkuUserId) {
|
|
30
|
+
const data = await this.redis.get(this.sessionKey(pikkuUserId));
|
|
31
|
+
if (!data) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return JSON.parse(data);
|
|
35
|
+
}
|
|
36
|
+
async set(pikkuUserId, session) {
|
|
37
|
+
const key = this.sessionKey(pikkuUserId);
|
|
38
|
+
const value = JSON.stringify(session);
|
|
39
|
+
if (this.ttlSeconds) {
|
|
40
|
+
await this.redis.set(key, value, 'EX', this.ttlSeconds);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
await this.redis.set(key, value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async clear(pikkuUserId) {
|
|
47
|
+
await this.redis.del(this.sessionKey(pikkuUserId));
|
|
48
|
+
}
|
|
49
|
+
async close() {
|
|
50
|
+
if (this.ownsConnection) {
|
|
51
|
+
await this.redis.quit();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=redis-session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-session-store.js","sourceRoot":"","sources":["../../src/redis-session-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAqB,MAAM,SAAS,CAAA;AAElD,MAAM,OAAO,iBAAiB;IACpB,KAAK,CAAO;IACZ,SAAS,CAAQ;IACjB,cAAc,CAAS;IACvB,UAAU,CAAS;IAO3B,YACE,kBAAiD,EACjD,SAAS,GAAG,OAAO,EACnB,UAAmB;QAEnB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAE5B,IAAI,kBAAkB,YAAY,KAAK,EAAE,CAAC;YACxC,IAAI,CAAC,KAAK,GAAG,kBAAkB,CAAA;YAC/B,IAAI,CAAC,cAAc,GAAG,KAAK,CAAA;QAC7B,CAAC;aAAM,IAAI,OAAO,kBAAkB,KAAK,QAAQ,EAAE,CAAC;YAClD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;YAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;YAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;QAC5B,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAEO,UAAU,CAAC,WAAmB;QACpC,OAAO,GAAG,IAAI,CAAC,SAAS,YAAY,WAAW,EAAE,CAAA;IACnD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,WAAmB;QAC3B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAA;QAC/D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,WAAmB,EAAE,OAAwB;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QACrC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;QACzD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,WAAmB;QAC7B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAA;IACpD,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;QACzB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/redis-agent-run-service.ts","../src/redis-channel-store.ts","../src/redis-deployment-service.ts","../src/redis-eventhub-store.ts","../src/redis-secret-service.ts","../src/redis-workflow-run-service.ts","../src/redis-workflow-service.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/index.ts","../src/redis-agent-run-service.ts","../src/redis-channel-store.ts","../src/redis-deployment-service.ts","../src/redis-eventhub-store.ts","../src/redis-secret-service.ts","../src/redis-session-store.ts","../src/redis-workflow-run-service.ts","../src/redis-workflow-service.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/redis",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/src/index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"prepublishOnly": "yarn build"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@pikku/core": "^0.12.
|
|
20
|
+
"@pikku/core": "^0.12.18"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"ioredis": "^5.10.0"
|
package/src/index.ts
CHANGED
|
@@ -8,3 +8,4 @@ export { RedisAgentRunService } from './redis-agent-run-service.js'
|
|
|
8
8
|
export { RedisSecretService } from './redis-secret-service.js'
|
|
9
9
|
export type { RedisSecretServiceConfig } from './redis-secret-service.js'
|
|
10
10
|
export type { AgentRunService, AgentRunRow } from '@pikku/core/ai-agent'
|
|
11
|
+
export { RedisSessionStore } from './redis-session-store.js'
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CoreUserSession } from '@pikku/core'
|
|
2
1
|
import type { Channel } from '@pikku/core/channel'
|
|
3
2
|
import { ChannelStore } from '@pikku/core/channel'
|
|
4
3
|
import { Redis, type RedisOptions } from 'ioredis'
|
|
@@ -95,22 +94,22 @@ export class RedisChannelStore extends ChannelStore {
|
|
|
95
94
|
await pipeline.exec()
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
public async
|
|
97
|
+
public async setPikkuUserId(
|
|
99
98
|
channelId: string,
|
|
100
|
-
|
|
99
|
+
pikkuUserId: string | null
|
|
101
100
|
): Promise<void> {
|
|
102
101
|
const key = this.channelKey(channelId)
|
|
103
102
|
|
|
104
|
-
if (
|
|
105
|
-
await this.redis.hset(key, '
|
|
103
|
+
if (pikkuUserId) {
|
|
104
|
+
await this.redis.hset(key, 'pikkuUserId', pikkuUserId)
|
|
106
105
|
} else {
|
|
107
|
-
await this.redis.hdel(key, '
|
|
106
|
+
await this.redis.hdel(key, 'pikkuUserId')
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
public async
|
|
110
|
+
public async getChannel(
|
|
112
111
|
channelId: string
|
|
113
|
-
): Promise<Channel & {
|
|
112
|
+
): Promise<Channel & { pikkuUserId?: string }> {
|
|
114
113
|
const key = this.channelKey(channelId)
|
|
115
114
|
const data = await this.redis.hgetall(key)
|
|
116
115
|
|
|
@@ -122,7 +121,7 @@ export class RedisChannelStore extends ChannelStore {
|
|
|
122
121
|
channelId: data.channelId!,
|
|
123
122
|
channelName: data.channelName!,
|
|
124
123
|
openingData: data.openingData ? JSON.parse(data.openingData) : {},
|
|
125
|
-
|
|
124
|
+
pikkuUserId: data.pikkuUserId || undefined,
|
|
126
125
|
}
|
|
127
126
|
}
|
|
128
127
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { buildRemoteHeaders } from '@pikku/core/remote'
|
|
1
2
|
import type {
|
|
2
3
|
DeploymentService,
|
|
3
4
|
DeploymentServiceConfig,
|
|
4
5
|
DeploymentConfig,
|
|
5
|
-
DeploymentInfo,
|
|
6
6
|
} from '@pikku/core/services'
|
|
7
|
+
import type { JWTService, SecretService } from '@pikku/core/services'
|
|
7
8
|
import { getAllFunctionNames } from '@pikku/core/function'
|
|
8
9
|
import { Redis, type RedisOptions } from 'ioredis'
|
|
9
10
|
|
|
@@ -19,7 +20,9 @@ export class RedisDeploymentService implements DeploymentService {
|
|
|
19
20
|
constructor(
|
|
20
21
|
config: DeploymentServiceConfig,
|
|
21
22
|
connectionOrConfig: Redis | RedisOptions | string,
|
|
22
|
-
keyPrefix = 'pikku'
|
|
23
|
+
keyPrefix = 'pikku',
|
|
24
|
+
private jwt?: JWTService,
|
|
25
|
+
private secrets?: SecretService
|
|
23
26
|
) {
|
|
24
27
|
this.heartbeatInterval = config.heartbeatInterval ?? 10000
|
|
25
28
|
this.heartbeatTtl = config.heartbeatTtl ?? 30000
|
|
@@ -100,36 +103,50 @@ export class RedisDeploymentService implements DeploymentService {
|
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
|
|
103
|
-
async
|
|
104
|
-
|
|
106
|
+
async invoke(
|
|
107
|
+
funcName: string,
|
|
108
|
+
data: unknown,
|
|
109
|
+
session?: unknown,
|
|
110
|
+
traceId?: string
|
|
111
|
+
): Promise<unknown> {
|
|
112
|
+
const headers = await buildRemoteHeaders(
|
|
113
|
+
this.jwt,
|
|
114
|
+
this.secrets,
|
|
115
|
+
funcName,
|
|
116
|
+
session,
|
|
117
|
+
traceId
|
|
118
|
+
)
|
|
119
|
+
const indexKey = this.functionsIndexKey(funcName)
|
|
105
120
|
const now = Date.now()
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
pipeline.zrangebyscore(indexKey, now, '+inf')
|
|
110
|
-
const pipelineResults = await pipeline.exec()
|
|
111
|
-
|
|
112
|
-
const deploymentIds = (pipelineResults?.[1]?.[1] as string[]) ?? []
|
|
113
|
-
|
|
114
|
-
if (deploymentIds.length === 0) {
|
|
115
|
-
return []
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const results: DeploymentInfo[] = []
|
|
122
|
+
await this.redis.zremrangebyscore(indexKey, '-inf', now)
|
|
123
|
+
const deploymentIds = await this.redis.zrangebyscore(indexKey, now, '+inf')
|
|
119
124
|
|
|
125
|
+
let endpoint: string | null = null
|
|
120
126
|
for (const deploymentId of deploymentIds) {
|
|
121
|
-
|
|
127
|
+
endpoint = await this.redis.hget(
|
|
122
128
|
this.deploymentKey(deploymentId),
|
|
123
129
|
'endpoint'
|
|
124
130
|
)
|
|
125
|
-
if (endpoint)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
131
|
+
if (endpoint) break
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!endpoint) {
|
|
135
|
+
throw new Error(`No deployment found for function '${funcName}'`)
|
|
130
136
|
}
|
|
131
137
|
|
|
132
|
-
|
|
138
|
+
const url = `${endpoint}/remote/rpc/${encodeURIComponent(funcName)}`
|
|
139
|
+
const response = await fetch(url, {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
headers,
|
|
142
|
+
body: JSON.stringify({ data }),
|
|
143
|
+
})
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Remote RPC call to '${funcName}' failed: ${response.status}`
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
return response.json()
|
|
133
150
|
}
|
|
134
151
|
|
|
135
152
|
private async sendHeartbeat(): Promise<void> {
|
|
@@ -58,7 +58,7 @@ export class RedisSecretService implements SecretService {
|
|
|
58
58
|
|
|
59
59
|
async getSecret(key: string): Promise<string> {
|
|
60
60
|
const data = await this.redis.hgetall(this.secretKey(key))
|
|
61
|
-
if (!data.ciphertext) throw new Error(
|
|
61
|
+
if (!data.ciphertext) throw new Error('Requested secret not found')
|
|
62
62
|
|
|
63
63
|
const kek = this.getKEK(Number(data.key_version))
|
|
64
64
|
return envelopeDecrypt<string>(kek, data.ciphertext!, data.wrapped_dek!)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { CoreUserSession } from '@pikku/core'
|
|
2
|
+
import type { SessionStore } from '@pikku/core/services'
|
|
3
|
+
import { Redis, type RedisOptions } from 'ioredis'
|
|
4
|
+
|
|
5
|
+
export class RedisSessionStore implements SessionStore {
|
|
6
|
+
private redis: Redis
|
|
7
|
+
private keyPrefix: string
|
|
8
|
+
private ownsConnection: boolean
|
|
9
|
+
private ttlSeconds?: number
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param connectionOrConfig - ioredis Redis instance or RedisOptions config
|
|
13
|
+
* @param keyPrefix - Redis key prefix (default: 'pikku')
|
|
14
|
+
* @param ttlSeconds - Optional TTL in seconds for session entries
|
|
15
|
+
*/
|
|
16
|
+
constructor(
|
|
17
|
+
connectionOrConfig: Redis | RedisOptions | string,
|
|
18
|
+
keyPrefix = 'pikku',
|
|
19
|
+
ttlSeconds?: number
|
|
20
|
+
) {
|
|
21
|
+
this.keyPrefix = keyPrefix
|
|
22
|
+
this.ttlSeconds = ttlSeconds
|
|
23
|
+
|
|
24
|
+
if (connectionOrConfig instanceof Redis) {
|
|
25
|
+
this.redis = connectionOrConfig
|
|
26
|
+
this.ownsConnection = false
|
|
27
|
+
} else if (typeof connectionOrConfig === 'string') {
|
|
28
|
+
this.redis = new Redis(connectionOrConfig)
|
|
29
|
+
this.ownsConnection = true
|
|
30
|
+
} else {
|
|
31
|
+
this.redis = new Redis(connectionOrConfig)
|
|
32
|
+
this.ownsConnection = true
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public async init(): Promise<void> {
|
|
37
|
+
await this.redis.ping()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private sessionKey(pikkuUserId: string): string {
|
|
41
|
+
return `${this.keyPrefix}:session:${pikkuUserId}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async get(pikkuUserId: string): Promise<CoreUserSession | undefined> {
|
|
45
|
+
const data = await this.redis.get(this.sessionKey(pikkuUserId))
|
|
46
|
+
if (!data) {
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
49
|
+
return JSON.parse(data) as CoreUserSession
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async set(pikkuUserId: string, session: CoreUserSession): Promise<void> {
|
|
53
|
+
const key = this.sessionKey(pikkuUserId)
|
|
54
|
+
const value = JSON.stringify(session)
|
|
55
|
+
if (this.ttlSeconds) {
|
|
56
|
+
await this.redis.set(key, value, 'EX', this.ttlSeconds)
|
|
57
|
+
} else {
|
|
58
|
+
await this.redis.set(key, value)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async clear(pikkuUserId: string): Promise<void> {
|
|
63
|
+
await this.redis.del(this.sessionKey(pikkuUserId))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public async close(): Promise<void> {
|
|
67
|
+
if (this.ownsConnection) {
|
|
68
|
+
await this.redis.quit()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|