@pikku/kysely 0.12.9 → 0.12.10

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  ## 0.12.0
2
2
 
3
+ ## 0.12.10
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.9
4
18
 
5
19
  ### Patch Changes
@@ -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
- setUserSession(channelId: string, session: CoreUserSession | null): Promise<void>;
14
- getChannelAndSession(channelId: string): Promise<Channel & {
15
- session: CoreUserSession;
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('user_session', 'text')
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 setUserSession(channelId, session) {
56
+ async setPikkuUserId(channelId, pikkuUserId) {
57
57
  await this.db
58
58
  .updateTable('channels')
59
- .set({ userSession: session ? JSON.stringify(session) : null })
59
+ .set({ pikkuUserId })
60
60
  .where('channelId', '=', channelId)
61
61
  .execute();
62
62
  }
63
- async getChannelAndSession(channelId) {
63
+ async getChannel(channelId) {
64
64
  const row = await this.db
65
65
  .selectFrom('channels')
66
- .select(['channelId', 'channelName', 'openingData', 'userSession'])
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
- session: (parseJson(row.userSession) ?? {}),
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
- userSession: string | null;
8
+ pikkuUserId: string | null;
9
9
  lastWire: Generated<Date>;
10
10
  }
11
11
  export interface ChannelSubscriptionsTable {
@@ -153,6 +153,12 @@ export interface CredentialsAuditTable {
153
153
  action: string;
154
154
  performedAt: Generated<Date>;
155
155
  }
156
+ export interface UserSessionsTable {
157
+ pikkuUserId: string;
158
+ session: string;
159
+ createdAt: Generated<Date>;
160
+ updatedAt: Generated<Date>;
161
+ }
156
162
  export interface KyselyPikkuDB {
157
163
  channels: ChannelsTable;
158
164
  channelSubscriptions: ChannelSubscriptionsTable;
@@ -171,4 +177,5 @@ export interface KyselyPikkuDB {
171
177
  secretsAudit: SecretsAuditTable;
172
178
  credentials: CredentialsTable;
173
179
  credentialsAudit: CredentialsAuditTable;
180
+ pikkuUserSessions: UserSessionsTable;
174
181
  }
@@ -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.9",
3
+ "version": "0.12.10",
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.15"
23
+ "@pikku/core": "^0.12.18"
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('user_session', 'text')
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 setUserSession(
77
+ public async setPikkuUserId(
79
78
  channelId: string,
80
- session: CoreUserSession | null
79
+ pikkuUserId: string | null
81
80
  ): Promise<void> {
82
81
  await this.db
83
82
  .updateTable('channels')
84
- .set({ userSession: session ? JSON.stringify(session) : null })
83
+ .set({ pikkuUserId })
85
84
  .where('channelId', '=', channelId)
86
85
  .execute()
87
86
  }
88
87
 
89
- public async getChannelAndSession(
88
+ public async getChannel(
90
89
  channelId: string
91
- ): Promise<Channel & { session: CoreUserSession }> {
90
+ ): Promise<Channel & { pikkuUserId?: string }> {
92
91
  const row = await this.db
93
92
  .selectFrom('channels')
94
- .select(['channelId', 'channelName', 'openingData', 'userSession'])
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
- session: (parseJson(row.userSession) ?? {}) as CoreUserSession,
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
+ }
@@ -10,7 +10,7 @@ export interface ChannelsTable {
10
10
  channelName: string
11
11
  createdAt: Generated<Date>
12
12
  openingData: string
13
- userSession: string | null
13
+ pikkuUserId: string | null
14
14
  lastWire: Generated<Date>
15
15
  }
16
16
 
@@ -175,6 +175,13 @@ export interface CredentialsAuditTable {
175
175
  performedAt: Generated<Date>
176
176
  }
177
177
 
178
+ export interface UserSessionsTable {
179
+ pikkuUserId: string
180
+ session: string
181
+ createdAt: Generated<Date>
182
+ updatedAt: Generated<Date>
183
+ }
184
+
178
185
  export interface KyselyPikkuDB {
179
186
  channels: ChannelsTable
180
187
  channelSubscriptions: ChannelSubscriptionsTable
@@ -193,4 +200,5 @@ export interface KyselyPikkuDB {
193
200
  secretsAudit: SecretsAuditTable
194
201
  credentials: CredentialsTable
195
202
  credentialsAudit: CredentialsAuditTable
203
+ pikkuUserSessions: UserSessionsTable
196
204
  }