@pikku/kysely 0.12.9 → 0.12.11
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 +26 -3
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/kysely-channel-store.d.ts +3 -4
- package/dist/src/kysely-channel-store.js +6 -6
- package/dist/src/kysely-session-store.d.ts +13 -0
- package/dist/src/kysely-session-store.js +54 -0
- package/dist/src/kysely-tables.d.ts +10 -1
- package/dist/src/kysely-workflow-run-service.js +6 -0
- package/dist/src/kysely-workflow-service.d.ts +5 -2
- package/dist/src/kysely-workflow-service.js +7 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/kysely-channel-store.ts +8 -9
- package/src/kysely-services.test.ts +6 -0
- package/src/kysely-session-store.ts +73 -0
- package/src/kysely-tables.ts +11 -1
- package/src/kysely-workflow-run-service.ts +6 -0
- package/src/kysely-workflow-service.ts +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
|
+
## 0.12.11
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- b9ed73e: Add deterministic workflow planned-step metadata support and SSE init stream payload generation.
|
|
6
|
+
- Persist `deterministic` and `plannedSteps` on workflow runs in core and service adapters.
|
|
7
|
+
- Expose planned-step metadata on workflow run status responses.
|
|
8
|
+
- Emit an initial `type: 'init'` SSE event for deterministic workflow streams before incremental updates.
|
|
9
|
+
- Add CLI tests covering serialized stream route output for init/update/done event behavior.
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [b9ed73e]
|
|
12
|
+
- @pikku/core@0.12.19
|
|
13
|
+
|
|
1
14
|
## 0.12.0
|
|
2
15
|
|
|
16
|
+
## 0.12.10
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 311c0c4: Unify session persistence through SessionStore, remove session blob from ChannelStore
|
|
21
|
+
- PikkuSessionService now persists sessions via SessionStore on set()/clear() instead of every function call
|
|
22
|
+
- ChannelStore no longer stores session data — maps channelId to pikkuUserId only
|
|
23
|
+
- ChannelStore API: setUserSession/getChannelAndSession replaced with setPikkuUserId/getChannel
|
|
24
|
+
- Serverless channel runner resolves sessions from SessionStore using pikkuUserId from ChannelStore
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [311c0c4]
|
|
27
|
+
- @pikku/core@0.12.18
|
|
28
|
+
|
|
3
29
|
## 0.12.9
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
|
6
32
|
|
|
7
33
|
- 624097e: Add deploy pipeline with provider-agnostic architecture
|
|
8
|
-
|
|
9
34
|
- Add MetaService with explicit typed API, absorb WiringService reads
|
|
10
35
|
- Add deployment service, traceId propagation, scoped logger
|
|
11
36
|
- Rewrite analyzer: one function = one worker, gateways dispatch via RPC
|
|
@@ -25,7 +50,6 @@
|
|
|
25
50
|
### Patch Changes
|
|
26
51
|
|
|
27
52
|
- f85c234: Add unified credential system with per-user OAuth and AI agent pre-flight checks
|
|
28
|
-
|
|
29
53
|
- Unified CredentialService with lazy loading per user via pikkuUserId
|
|
30
54
|
- wire.getCredential() for typed single credential lookup
|
|
31
55
|
- MissingCredentialError with structured payload for client-side connect flows
|
|
@@ -130,7 +154,6 @@
|
|
|
130
154
|
- Updated dependencies [62a8725]
|
|
131
155
|
- Updated dependencies [62a8725]
|
|
132
156
|
- Updated dependencies [62a8725]
|
|
133
|
-
|
|
134
157
|
- @pikku/core@0.12.1
|
|
135
158
|
|
|
136
159
|
- Updated dependencies
|
package/dist/src/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { KyselySecretService } from './kysely-secret-service.js';
|
|
|
10
10
|
export type { KyselySecretServiceConfig } from './kysely-secret-service.js';
|
|
11
11
|
export { KyselyCredentialService } from './kysely-credential-service.js';
|
|
12
12
|
export type { KyselyCredentialServiceConfig } from './kysely-credential-service.js';
|
|
13
|
+
export { KyselySessionStore } from './kysely-session-store.js';
|
|
13
14
|
export type { KyselyPikkuDB } from './kysely-tables.js';
|
|
14
15
|
export type { WorkflowRunService } from '@pikku/core/workflow';
|
|
15
16
|
export type { AgentRunService, AgentRunRow } from '@pikku/core/ai-agent';
|
package/dist/src/index.js
CHANGED
|
@@ -8,3 +8,4 @@ export { KyselyAgentRunService } from './kysely-ai-agent-run-service.js';
|
|
|
8
8
|
export { KyselyAIRunStateService } from './kysely-ai-run-state-service.js';
|
|
9
9
|
export { KyselySecretService } from './kysely-secret-service.js';
|
|
10
10
|
export { KyselyCredentialService } from './kysely-credential-service.js';
|
|
11
|
+
export { KyselySessionStore } from './kysely-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 type { Kysely } from 'kysely';
|
|
@@ -10,9 +9,9 @@ export declare class KyselyChannelStore extends ChannelStore {
|
|
|
10
9
|
init(): Promise<void>;
|
|
11
10
|
addChannel({ channelId, channelName, openingData, }: Channel): Promise<void>;
|
|
12
11
|
removeChannels(channelIds: string[]): Promise<void>;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
setPikkuUserId(channelId: string, pikkuUserId: string | null): Promise<void>;
|
|
13
|
+
getChannel(channelId: string): Promise<Channel & {
|
|
14
|
+
pikkuUserId?: string;
|
|
16
15
|
}>;
|
|
17
16
|
close(): Promise<void>;
|
|
18
17
|
}
|
|
@@ -19,7 +19,7 @@ export class KyselyChannelStore extends ChannelStore {
|
|
|
19
19
|
.addColumn('channel_name', 'text', (col) => col.notNull())
|
|
20
20
|
.addColumn('created_at', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
21
21
|
.addColumn('opening_data', 'text', (col) => col.notNull().defaultTo('{}'))
|
|
22
|
-
.addColumn('
|
|
22
|
+
.addColumn('pikku_user_id', 'text')
|
|
23
23
|
.addColumn('last_wire', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
24
24
|
.execute();
|
|
25
25
|
await this.db.schema
|
|
@@ -53,17 +53,17 @@ export class KyselyChannelStore extends ChannelStore {
|
|
|
53
53
|
.where('channelId', 'in', channelIds)
|
|
54
54
|
.execute();
|
|
55
55
|
}
|
|
56
|
-
async
|
|
56
|
+
async setPikkuUserId(channelId, pikkuUserId) {
|
|
57
57
|
await this.db
|
|
58
58
|
.updateTable('channels')
|
|
59
|
-
.set({
|
|
59
|
+
.set({ pikkuUserId })
|
|
60
60
|
.where('channelId', '=', channelId)
|
|
61
61
|
.execute();
|
|
62
62
|
}
|
|
63
|
-
async
|
|
63
|
+
async getChannel(channelId) {
|
|
64
64
|
const row = await this.db
|
|
65
65
|
.selectFrom('channels')
|
|
66
|
-
.select(['channelId', 'channelName', 'openingData', '
|
|
66
|
+
.select(['channelId', 'channelName', 'openingData', 'pikkuUserId'])
|
|
67
67
|
.where('channelId', '=', channelId)
|
|
68
68
|
.executeTakeFirst();
|
|
69
69
|
if (!row) {
|
|
@@ -73,7 +73,7 @@ export class KyselyChannelStore extends ChannelStore {
|
|
|
73
73
|
channelId: row.channelId,
|
|
74
74
|
channelName: row.channelName,
|
|
75
75
|
openingData: parseJson(row.openingData) ?? {},
|
|
76
|
-
|
|
76
|
+
pikkuUserId: row.pikkuUserId ?? undefined,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
async close() { }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CoreUserSession } from '@pikku/core';
|
|
2
|
+
import type { SessionStore } from '@pikku/core/services';
|
|
3
|
+
import type { Kysely } from 'kysely';
|
|
4
|
+
import type { KyselyPikkuDB } from './kysely-tables.js';
|
|
5
|
+
export declare class KyselySessionStore implements SessionStore {
|
|
6
|
+
private db;
|
|
7
|
+
private initialized;
|
|
8
|
+
constructor(db: Kysely<KyselyPikkuDB>);
|
|
9
|
+
init(): Promise<void>;
|
|
10
|
+
get(pikkuUserId: string): Promise<CoreUserSession | undefined>;
|
|
11
|
+
set(pikkuUserId: string, session: CoreUserSession): Promise<void>;
|
|
12
|
+
clear(pikkuUserId: string): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { sql } from 'kysely';
|
|
2
|
+
import { parseJson } from './kysely-json.js';
|
|
3
|
+
export class KyselySessionStore {
|
|
4
|
+
db;
|
|
5
|
+
initialized = false;
|
|
6
|
+
constructor(db) {
|
|
7
|
+
this.db = db;
|
|
8
|
+
}
|
|
9
|
+
async init() {
|
|
10
|
+
if (this.initialized) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
await this.db.schema
|
|
14
|
+
.createTable('pikku_user_sessions')
|
|
15
|
+
.ifNotExists()
|
|
16
|
+
.addColumn('pikku_user_id', 'text', (col) => col.primaryKey())
|
|
17
|
+
.addColumn('session', 'text', (col) => col.notNull())
|
|
18
|
+
.addColumn('created_at', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
19
|
+
.addColumn('updated_at', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
20
|
+
.execute();
|
|
21
|
+
this.initialized = true;
|
|
22
|
+
}
|
|
23
|
+
async get(pikkuUserId) {
|
|
24
|
+
const row = await this.db
|
|
25
|
+
.selectFrom('pikkuUserSessions')
|
|
26
|
+
.select(['session'])
|
|
27
|
+
.where('pikkuUserId', '=', pikkuUserId)
|
|
28
|
+
.executeTakeFirst();
|
|
29
|
+
if (!row) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
return (parseJson(row.session) ?? undefined);
|
|
33
|
+
}
|
|
34
|
+
async set(pikkuUserId, session) {
|
|
35
|
+
await this.db
|
|
36
|
+
.insertInto('pikkuUserSessions')
|
|
37
|
+
.values({
|
|
38
|
+
pikkuUserId,
|
|
39
|
+
session: JSON.stringify(session),
|
|
40
|
+
updatedAt: new Date(),
|
|
41
|
+
})
|
|
42
|
+
.onConflict((oc) => oc.column('pikkuUserId').doUpdateSet({
|
|
43
|
+
session: JSON.stringify(session),
|
|
44
|
+
updatedAt: new Date(),
|
|
45
|
+
}))
|
|
46
|
+
.execute();
|
|
47
|
+
}
|
|
48
|
+
async clear(pikkuUserId) {
|
|
49
|
+
await this.db
|
|
50
|
+
.deleteFrom('pikkuUserSessions')
|
|
51
|
+
.where('pikkuUserId', '=', pikkuUserId)
|
|
52
|
+
.execute();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -5,7 +5,7 @@ export interface ChannelsTable {
|
|
|
5
5
|
channelName: string;
|
|
6
6
|
createdAt: Generated<Date>;
|
|
7
7
|
openingData: string;
|
|
8
|
-
|
|
8
|
+
pikkuUserId: string | null;
|
|
9
9
|
lastWire: Generated<Date>;
|
|
10
10
|
}
|
|
11
11
|
export interface ChannelSubscriptionsTable {
|
|
@@ -22,6 +22,8 @@ export interface WorkflowRunsTable {
|
|
|
22
22
|
state: Generated<string>;
|
|
23
23
|
inline: Generated<boolean>;
|
|
24
24
|
graphHash: string | null;
|
|
25
|
+
deterministic: Generated<boolean>;
|
|
26
|
+
plannedSteps: string | null;
|
|
25
27
|
wire: string | null;
|
|
26
28
|
createdAt: Generated<Date>;
|
|
27
29
|
updatedAt: Generated<Date>;
|
|
@@ -153,6 +155,12 @@ export interface CredentialsAuditTable {
|
|
|
153
155
|
action: string;
|
|
154
156
|
performedAt: Generated<Date>;
|
|
155
157
|
}
|
|
158
|
+
export interface UserSessionsTable {
|
|
159
|
+
pikkuUserId: string;
|
|
160
|
+
session: string;
|
|
161
|
+
createdAt: Generated<Date>;
|
|
162
|
+
updatedAt: Generated<Date>;
|
|
163
|
+
}
|
|
156
164
|
export interface KyselyPikkuDB {
|
|
157
165
|
channels: ChannelsTable;
|
|
158
166
|
channelSubscriptions: ChannelSubscriptionsTable;
|
|
@@ -171,4 +179,5 @@ export interface KyselyPikkuDB {
|
|
|
171
179
|
secretsAudit: SecretsAuditTable;
|
|
172
180
|
credentials: CredentialsTable;
|
|
173
181
|
credentialsAudit: CredentialsAuditTable;
|
|
182
|
+
pikkuUserSessions: UserSessionsTable;
|
|
174
183
|
}
|
|
@@ -17,6 +17,8 @@ export class KyselyWorkflowRunService {
|
|
|
17
17
|
'error',
|
|
18
18
|
'inline',
|
|
19
19
|
'graphHash',
|
|
20
|
+
'deterministic',
|
|
21
|
+
'plannedSteps',
|
|
20
22
|
'wire',
|
|
21
23
|
'createdAt',
|
|
22
24
|
'updatedAt',
|
|
@@ -46,6 +48,8 @@ export class KyselyWorkflowRunService {
|
|
|
46
48
|
'error',
|
|
47
49
|
'inline',
|
|
48
50
|
'graphHash',
|
|
51
|
+
'deterministic',
|
|
52
|
+
'plannedSteps',
|
|
49
53
|
'wire',
|
|
50
54
|
'createdAt',
|
|
51
55
|
'updatedAt',
|
|
@@ -204,6 +208,8 @@ export class KyselyWorkflowRunService {
|
|
|
204
208
|
error: parseJson(row.error),
|
|
205
209
|
inline: row.inline,
|
|
206
210
|
graphHash: row.graphHash,
|
|
211
|
+
deterministic: row.deterministic,
|
|
212
|
+
plannedSteps: parseJson(row.plannedSteps),
|
|
207
213
|
wire: parseJson(row.wire) ?? { type: 'unknown' },
|
|
208
214
|
createdAt: new Date(row.createdAt),
|
|
209
215
|
updatedAt: new Date(row.updatedAt),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SerializedError } from '@pikku/core';
|
|
2
|
-
import { PikkuWorkflowService, type WorkflowRun, type WorkflowRunWire, type StepState, type WorkflowStatus, type WorkflowVersionStatus } from '@pikku/core/workflow';
|
|
2
|
+
import { PikkuWorkflowService, type WorkflowPlannedStep, type WorkflowRun, type WorkflowRunWire, type StepState, type WorkflowStatus, type WorkflowVersionStatus } from '@pikku/core/workflow';
|
|
3
3
|
import type { Kysely } from 'kysely';
|
|
4
4
|
import type { KyselyPikkuDB } from './kysely-tables.js';
|
|
5
5
|
export declare class KyselyWorkflowService extends PikkuWorkflowService {
|
|
@@ -8,7 +8,10 @@ export declare class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
8
8
|
private runService;
|
|
9
9
|
constructor(db: Kysely<KyselyPikkuDB>);
|
|
10
10
|
init(): Promise<void>;
|
|
11
|
-
createRun(workflowName: string, input: any, inline: boolean, graphHash: string, wire: WorkflowRunWire
|
|
11
|
+
createRun(workflowName: string, input: any, inline: boolean, graphHash: string, wire: WorkflowRunWire, options?: {
|
|
12
|
+
deterministic?: boolean;
|
|
13
|
+
plannedSteps?: WorkflowPlannedStep[];
|
|
14
|
+
}): Promise<string>;
|
|
12
15
|
getRun(id: string): Promise<WorkflowRun | null>;
|
|
13
16
|
updateRunStatus(id: string, status: WorkflowStatus, output?: any, error?: SerializedError): Promise<void>;
|
|
14
17
|
insertStepState(runId: string, stepName: string, rpcName: string | null, data: any, stepOptions?: {
|
|
@@ -29,6 +29,8 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
29
29
|
.addColumn('state', 'text', (col) => col.defaultTo('{}'))
|
|
30
30
|
.addColumn('inline', 'boolean', (col) => col.defaultTo(false))
|
|
31
31
|
.addColumn('graph_hash', 'text')
|
|
32
|
+
.addColumn('deterministic', 'boolean', (col) => col.defaultTo(false))
|
|
33
|
+
.addColumn('planned_steps', 'text')
|
|
32
34
|
.addColumn('wire', 'text')
|
|
33
35
|
.addColumn('created_at', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
34
36
|
.addColumn('updated_at', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
@@ -95,7 +97,7 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
95
97
|
.execute();
|
|
96
98
|
this.initialized = true;
|
|
97
99
|
}
|
|
98
|
-
async createRun(workflowName, input, inline, graphHash, wire) {
|
|
100
|
+
async createRun(workflowName, input, inline, graphHash, wire, options) {
|
|
99
101
|
const id = crypto.randomUUID();
|
|
100
102
|
await this.db
|
|
101
103
|
.insertInto('workflowRuns')
|
|
@@ -106,6 +108,10 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
106
108
|
input: JSON.stringify(input),
|
|
107
109
|
inline,
|
|
108
110
|
graphHash: graphHash ?? null,
|
|
111
|
+
deterministic: options?.deterministic ?? false,
|
|
112
|
+
plannedSteps: options?.plannedSteps
|
|
113
|
+
? JSON.stringify(options.plannedSteps)
|
|
114
|
+
: null,
|
|
109
115
|
wire: wire ? JSON.stringify(wire) : null,
|
|
110
116
|
})
|
|
111
117
|
.execute();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/kysely-ai-agent-run-service.ts","../src/kysely-ai-run-state-service.ts","../src/kysely-ai-storage-service.ts","../src/kysely-channel-store.ts","../src/kysely-credential-service.ts","../src/kysely-deployment-service.ts","../src/kysely-eventhub-store.ts","../src/kysely-json.ts","../src/kysely-secret-service.ts","../src/kysely-tables.ts","../src/kysely-workflow-run-service.ts","../src/kysely-workflow-service.ts","../bin/pikku-kysely-pure.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/index.ts","../src/kysely-ai-agent-run-service.ts","../src/kysely-ai-run-state-service.ts","../src/kysely-ai-storage-service.ts","../src/kysely-channel-store.ts","../src/kysely-credential-service.ts","../src/kysely-deployment-service.ts","../src/kysely-eventhub-store.ts","../src/kysely-json.ts","../src/kysely-secret-service.ts","../src/kysely-session-store.ts","../src/kysely-tables.ts","../src/kysely-workflow-run-service.ts","../src/kysely-workflow-service.ts","../bin/pikku-kysely-pure.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/kysely",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.11",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/src/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"prepublishOnly": "yarn build"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@pikku/core": "^0.12.
|
|
23
|
+
"@pikku/core": "^0.12.19"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"kysely": "^0.28.12"
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { KyselySecretService } from './kysely-secret-service.js'
|
|
|
10
10
|
export type { KyselySecretServiceConfig } from './kysely-secret-service.js'
|
|
11
11
|
export { KyselyCredentialService } from './kysely-credential-service.js'
|
|
12
12
|
export type { KyselyCredentialServiceConfig } from './kysely-credential-service.js'
|
|
13
|
+
export { KyselySessionStore } from './kysely-session-store.js'
|
|
13
14
|
|
|
14
15
|
export type { KyselyPikkuDB } from './kysely-tables.js'
|
|
15
16
|
export type { WorkflowRunService } from '@pikku/core/workflow'
|
|
@@ -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 type { Kysely } from 'kysely'
|
|
@@ -27,7 +26,7 @@ export class KyselyChannelStore extends ChannelStore {
|
|
|
27
26
|
col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull()
|
|
28
27
|
)
|
|
29
28
|
.addColumn('opening_data', 'text', (col) => col.notNull().defaultTo('{}'))
|
|
30
|
-
.addColumn('
|
|
29
|
+
.addColumn('pikku_user_id', 'text')
|
|
31
30
|
.addColumn('last_wire', 'timestamp', (col) =>
|
|
32
31
|
col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull()
|
|
33
32
|
)
|
|
@@ -75,23 +74,23 @@ export class KyselyChannelStore extends ChannelStore {
|
|
|
75
74
|
.execute()
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
public async
|
|
77
|
+
public async setPikkuUserId(
|
|
79
78
|
channelId: string,
|
|
80
|
-
|
|
79
|
+
pikkuUserId: string | null
|
|
81
80
|
): Promise<void> {
|
|
82
81
|
await this.db
|
|
83
82
|
.updateTable('channels')
|
|
84
|
-
.set({
|
|
83
|
+
.set({ pikkuUserId })
|
|
85
84
|
.where('channelId', '=', channelId)
|
|
86
85
|
.execute()
|
|
87
86
|
}
|
|
88
87
|
|
|
89
|
-
public async
|
|
88
|
+
public async getChannel(
|
|
90
89
|
channelId: string
|
|
91
|
-
): Promise<Channel & {
|
|
90
|
+
): Promise<Channel & { pikkuUserId?: string }> {
|
|
92
91
|
const row = await this.db
|
|
93
92
|
.selectFrom('channels')
|
|
94
|
-
.select(['channelId', 'channelName', 'openingData', '
|
|
93
|
+
.select(['channelId', 'channelName', 'openingData', 'pikkuUserId'])
|
|
95
94
|
.where('channelId', '=', channelId)
|
|
96
95
|
.executeTakeFirst()
|
|
97
96
|
|
|
@@ -103,7 +102,7 @@ export class KyselyChannelStore extends ChannelStore {
|
|
|
103
102
|
channelId: row.channelId,
|
|
104
103
|
channelName: row.channelName,
|
|
105
104
|
openingData: parseJson(row.openingData) ?? {},
|
|
106
|
-
|
|
105
|
+
pikkuUserId: row.pikkuUserId ?? undefined,
|
|
107
106
|
}
|
|
108
107
|
}
|
|
109
108
|
|
|
@@ -17,6 +17,7 @@ import { KyselyAIStorageService } from './kysely-ai-storage-service.js'
|
|
|
17
17
|
import { KyselyAgentRunService } from './kysely-ai-agent-run-service.js'
|
|
18
18
|
import { KyselySecretService } from './kysely-secret-service.js'
|
|
19
19
|
import { KyselyCredentialService } from './kysely-credential-service.js'
|
|
20
|
+
import { KyselySessionStore } from './kysely-session-store.js'
|
|
20
21
|
|
|
21
22
|
function createSqliteDb(): Kysely<KyselyPikkuDB> {
|
|
22
23
|
return new Kysely<KyselyPikkuDB>({
|
|
@@ -109,6 +110,11 @@ function registerTests(
|
|
|
109
110
|
await s.init()
|
|
110
111
|
return s
|
|
111
112
|
},
|
|
113
|
+
sessionStore: async () => {
|
|
114
|
+
const s = new KyselySessionStore(getDb())
|
|
115
|
+
await s.init()
|
|
116
|
+
return s
|
|
117
|
+
},
|
|
112
118
|
},
|
|
113
119
|
})
|
|
114
120
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { CoreUserSession } from '@pikku/core'
|
|
2
|
+
import type { SessionStore } from '@pikku/core/services'
|
|
3
|
+
import type { Kysely } from 'kysely'
|
|
4
|
+
import { sql } from 'kysely'
|
|
5
|
+
import type { KyselyPikkuDB } from './kysely-tables.js'
|
|
6
|
+
import { parseJson } from './kysely-json.js'
|
|
7
|
+
|
|
8
|
+
export class KyselySessionStore implements SessionStore {
|
|
9
|
+
private initialized = false
|
|
10
|
+
|
|
11
|
+
constructor(private db: Kysely<KyselyPikkuDB>) {}
|
|
12
|
+
|
|
13
|
+
public async init(): Promise<void> {
|
|
14
|
+
if (this.initialized) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await this.db.schema
|
|
19
|
+
.createTable('pikku_user_sessions')
|
|
20
|
+
.ifNotExists()
|
|
21
|
+
.addColumn('pikku_user_id', 'text', (col) => col.primaryKey())
|
|
22
|
+
.addColumn('session', 'text', (col) => col.notNull())
|
|
23
|
+
.addColumn('created_at', 'timestamp', (col) =>
|
|
24
|
+
col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull()
|
|
25
|
+
)
|
|
26
|
+
.addColumn('updated_at', 'timestamp', (col) =>
|
|
27
|
+
col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull()
|
|
28
|
+
)
|
|
29
|
+
.execute()
|
|
30
|
+
|
|
31
|
+
this.initialized = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async get(pikkuUserId: string): Promise<CoreUserSession | undefined> {
|
|
35
|
+
const row = await this.db
|
|
36
|
+
.selectFrom('pikkuUserSessions')
|
|
37
|
+
.select(['session'])
|
|
38
|
+
.where('pikkuUserId', '=', pikkuUserId)
|
|
39
|
+
.executeTakeFirst()
|
|
40
|
+
|
|
41
|
+
if (!row) {
|
|
42
|
+
return undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (parseJson(row.session) ?? undefined) as
|
|
46
|
+
| CoreUserSession
|
|
47
|
+
| undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async set(pikkuUserId: string, session: CoreUserSession): Promise<void> {
|
|
51
|
+
await this.db
|
|
52
|
+
.insertInto('pikkuUserSessions')
|
|
53
|
+
.values({
|
|
54
|
+
pikkuUserId,
|
|
55
|
+
session: JSON.stringify(session),
|
|
56
|
+
updatedAt: new Date(),
|
|
57
|
+
})
|
|
58
|
+
.onConflict((oc) =>
|
|
59
|
+
oc.column('pikkuUserId').doUpdateSet({
|
|
60
|
+
session: JSON.stringify(session),
|
|
61
|
+
updatedAt: new Date(),
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
.execute()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async clear(pikkuUserId: string): Promise<void> {
|
|
68
|
+
await this.db
|
|
69
|
+
.deleteFrom('pikkuUserSessions')
|
|
70
|
+
.where('pikkuUserId', '=', pikkuUserId)
|
|
71
|
+
.execute()
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/kysely-tables.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface ChannelsTable {
|
|
|
10
10
|
channelName: string
|
|
11
11
|
createdAt: Generated<Date>
|
|
12
12
|
openingData: string
|
|
13
|
-
|
|
13
|
+
pikkuUserId: string | null
|
|
14
14
|
lastWire: Generated<Date>
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -29,6 +29,8 @@ export interface WorkflowRunsTable {
|
|
|
29
29
|
state: Generated<string>
|
|
30
30
|
inline: Generated<boolean>
|
|
31
31
|
graphHash: string | null
|
|
32
|
+
deterministic: Generated<boolean>
|
|
33
|
+
plannedSteps: string | null
|
|
32
34
|
wire: string | null
|
|
33
35
|
createdAt: Generated<Date>
|
|
34
36
|
updatedAt: Generated<Date>
|
|
@@ -175,6 +177,13 @@ export interface CredentialsAuditTable {
|
|
|
175
177
|
performedAt: Generated<Date>
|
|
176
178
|
}
|
|
177
179
|
|
|
180
|
+
export interface UserSessionsTable {
|
|
181
|
+
pikkuUserId: string
|
|
182
|
+
session: string
|
|
183
|
+
createdAt: Generated<Date>
|
|
184
|
+
updatedAt: Generated<Date>
|
|
185
|
+
}
|
|
186
|
+
|
|
178
187
|
export interface KyselyPikkuDB {
|
|
179
188
|
channels: ChannelsTable
|
|
180
189
|
channelSubscriptions: ChannelSubscriptionsTable
|
|
@@ -193,4 +202,5 @@ export interface KyselyPikkuDB {
|
|
|
193
202
|
secretsAudit: SecretsAuditTable
|
|
194
203
|
credentials: CredentialsTable
|
|
195
204
|
credentialsAudit: CredentialsAuditTable
|
|
205
|
+
pikkuUserSessions: UserSessionsTable
|
|
196
206
|
}
|
|
@@ -30,6 +30,8 @@ export class KyselyWorkflowRunService implements WorkflowRunService {
|
|
|
30
30
|
'error',
|
|
31
31
|
'inline',
|
|
32
32
|
'graphHash',
|
|
33
|
+
'deterministic',
|
|
34
|
+
'plannedSteps',
|
|
33
35
|
'wire',
|
|
34
36
|
'createdAt',
|
|
35
37
|
'updatedAt',
|
|
@@ -64,6 +66,8 @@ export class KyselyWorkflowRunService implements WorkflowRunService {
|
|
|
64
66
|
'error',
|
|
65
67
|
'inline',
|
|
66
68
|
'graphHash',
|
|
69
|
+
'deterministic',
|
|
70
|
+
'plannedSteps',
|
|
67
71
|
'wire',
|
|
68
72
|
'createdAt',
|
|
69
73
|
'updatedAt',
|
|
@@ -255,6 +259,8 @@ export class KyselyWorkflowRunService implements WorkflowRunService {
|
|
|
255
259
|
error: parseJson(row.error),
|
|
256
260
|
inline: row.inline as boolean | undefined,
|
|
257
261
|
graphHash: row.graphHash as string | undefined,
|
|
262
|
+
deterministic: row.deterministic as boolean | undefined,
|
|
263
|
+
plannedSteps: parseJson(row.plannedSteps),
|
|
258
264
|
wire: parseJson(row.wire) ?? { type: 'unknown' },
|
|
259
265
|
createdAt: new Date(row.createdAt as string),
|
|
260
266
|
updatedAt: new Date(row.updatedAt as string),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SerializedError } from '@pikku/core'
|
|
2
2
|
import {
|
|
3
3
|
PikkuWorkflowService,
|
|
4
|
+
type WorkflowPlannedStep,
|
|
4
5
|
type WorkflowRun,
|
|
5
6
|
type WorkflowRunWire,
|
|
6
7
|
type StepState,
|
|
@@ -43,6 +44,8 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
43
44
|
.addColumn('state', 'text', (col) => col.defaultTo('{}'))
|
|
44
45
|
.addColumn('inline', 'boolean', (col) => col.defaultTo(false))
|
|
45
46
|
.addColumn('graph_hash', 'text')
|
|
47
|
+
.addColumn('deterministic', 'boolean', (col) => col.defaultTo(false))
|
|
48
|
+
.addColumn('planned_steps', 'text')
|
|
46
49
|
.addColumn('wire', 'text')
|
|
47
50
|
.addColumn('created_at', 'timestamp', (col) =>
|
|
48
51
|
col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull()
|
|
@@ -139,7 +142,11 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
139
142
|
input: any,
|
|
140
143
|
inline: boolean,
|
|
141
144
|
graphHash: string,
|
|
142
|
-
wire: WorkflowRunWire
|
|
145
|
+
wire: WorkflowRunWire,
|
|
146
|
+
options?: {
|
|
147
|
+
deterministic?: boolean
|
|
148
|
+
plannedSteps?: WorkflowPlannedStep[]
|
|
149
|
+
}
|
|
143
150
|
): Promise<string> {
|
|
144
151
|
const id = crypto.randomUUID()
|
|
145
152
|
await this.db
|
|
@@ -151,6 +158,10 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
151
158
|
input: JSON.stringify(input),
|
|
152
159
|
inline,
|
|
153
160
|
graphHash: graphHash ?? null,
|
|
161
|
+
deterministic: options?.deterministic ?? false,
|
|
162
|
+
plannedSteps: options?.plannedSteps
|
|
163
|
+
? JSON.stringify(options.plannedSteps)
|
|
164
|
+
: null,
|
|
154
165
|
wire: wire ? JSON.stringify(wire) : null,
|
|
155
166
|
})
|
|
156
167
|
.execute()
|