@stackory/gateway-persistence 0.0.1

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.
Files changed (62) hide show
  1. package/README.md +49 -0
  2. package/dist/esm/database/index.d.ts +3 -0
  3. package/dist/esm/database/index.d.ts.map +1 -0
  4. package/dist/esm/database/index.js +3 -0
  5. package/dist/esm/database/index.js.map +1 -0
  6. package/dist/esm/database.d.ts +23 -0
  7. package/dist/esm/database.d.ts.map +1 -0
  8. package/dist/esm/database.js +53 -0
  9. package/dist/esm/database.js.map +1 -0
  10. package/dist/esm/gateway-database.d.ts +6 -0
  11. package/dist/esm/gateway-database.d.ts.map +1 -0
  12. package/dist/esm/gateway-database.js +19 -0
  13. package/dist/esm/gateway-database.js.map +1 -0
  14. package/dist/esm/index.d.ts +2 -0
  15. package/dist/esm/index.d.ts.map +1 -0
  16. package/dist/esm/index.js +3 -0
  17. package/dist/esm/index.js.map +1 -0
  18. package/dist/esm/migrations/generated.d.ts +3 -0
  19. package/dist/esm/migrations/generated.d.ts.map +1 -0
  20. package/dist/esm/migrations/generated.js +7 -0
  21. package/dist/esm/migrations/generated.js.map +1 -0
  22. package/dist/esm/migrations/index.d.ts +3 -0
  23. package/dist/esm/migrations/index.d.ts.map +1 -0
  24. package/dist/esm/migrations/index.js +2 -0
  25. package/dist/esm/migrations/index.js.map +1 -0
  26. package/dist/esm/migrations/types.d.ts +5 -0
  27. package/dist/esm/migrations/types.d.ts.map +1 -0
  28. package/dist/esm/migrations/types.js +2 -0
  29. package/dist/esm/migrations/types.js.map +1 -0
  30. package/dist/esm/schema.d.ts +579 -0
  31. package/dist/esm/schema.d.ts.map +1 -0
  32. package/dist/esm/schema.js +91 -0
  33. package/dist/esm/schema.js.map +1 -0
  34. package/dist/esm/stores/dedup-store.d.ts +14 -0
  35. package/dist/esm/stores/dedup-store.d.ts.map +1 -0
  36. package/dist/esm/stores/dedup-store.js +62 -0
  37. package/dist/esm/stores/dedup-store.js.map +1 -0
  38. package/dist/esm/stores/in-memory-session-store.d.ts +12 -0
  39. package/dist/esm/stores/in-memory-session-store.d.ts.map +1 -0
  40. package/dist/esm/stores/in-memory-session-store.js +64 -0
  41. package/dist/esm/stores/in-memory-session-store.js.map +1 -0
  42. package/dist/esm/stores/index.d.ts +7 -0
  43. package/dist/esm/stores/index.d.ts.map +1 -0
  44. package/dist/esm/stores/index.js +8 -0
  45. package/dist/esm/stores/index.js.map +1 -0
  46. package/dist/esm/stores/sqlite-binding-store.d.ts +14 -0
  47. package/dist/esm/stores/sqlite-binding-store.d.ts.map +1 -0
  48. package/dist/esm/stores/sqlite-binding-store.js +58 -0
  49. package/dist/esm/stores/sqlite-binding-store.js.map +1 -0
  50. package/dist/esm/stores/sqlite-pair-request-store.d.ts +11 -0
  51. package/dist/esm/stores/sqlite-pair-request-store.d.ts.map +1 -0
  52. package/dist/esm/stores/sqlite-pair-request-store.js +64 -0
  53. package/dist/esm/stores/sqlite-pair-request-store.js.map +1 -0
  54. package/dist/esm/stores/sqlite-policy-store.d.ts +12 -0
  55. package/dist/esm/stores/sqlite-policy-store.d.ts.map +1 -0
  56. package/dist/esm/stores/sqlite-policy-store.js +95 -0
  57. package/dist/esm/stores/sqlite-policy-store.js.map +1 -0
  58. package/dist/esm/stores/sqlite-session-store.d.ts +13 -0
  59. package/dist/esm/stores/sqlite-session-store.d.ts.map +1 -0
  60. package/dist/esm/stores/sqlite-session-store.js +107 -0
  61. package/dist/esm/stores/sqlite-session-store.js.map +1 -0
  62. package/package.json +52 -0
@@ -0,0 +1,579 @@
1
+ /**
2
+ * Drizzle schema 是 SQL 表结构的 single source of truth。
3
+ *
4
+ * 注意:复合主键里有任何字段是 NULL 时,SQLite 视作"两行不同"
5
+ * (NULL != NULL)—— 这会破坏 (platform, chat, thread, user) 的去重语义。
6
+ * 对策:threadId / userId 用 NOT NULL DEFAULT '','' 即"无 thread / 任意 user"。
7
+ *
8
+ * 改 schema 后流程:
9
+ * 1) `pnpm --filter @stackory/gateway-session drizzle-kit generate` 产 migrations/*.sql
10
+ * 2) 人工 review SQL(删噪音、确认顺序)
11
+ * 3) 把 SQL 内容贴进 src/migrations/NNN-name.ts 的字符串常量里(runtime 用)
12
+ * 4) 把 .sql 也提交(review 痕迹 + drizzle-kit meta)
13
+ */
14
+ export declare const sessions: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
15
+ name: "sessions";
16
+ schema: undefined;
17
+ columns: {
18
+ adapterId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
19
+ name: string;
20
+ tableName: "sessions";
21
+ dataType: "string";
22
+ data: string;
23
+ driverParam: string;
24
+ notNull: true;
25
+ hasDefault: false;
26
+ isPrimaryKey: false;
27
+ isAutoincrement: false;
28
+ hasRuntimeDefault: false;
29
+ enumValues: [string, ...string[]];
30
+ baseColumn: never;
31
+ identity: undefined;
32
+ generated: undefined;
33
+ }, {}>;
34
+ chatId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
35
+ name: string;
36
+ tableName: "sessions";
37
+ dataType: "string";
38
+ data: string;
39
+ driverParam: string;
40
+ notNull: true;
41
+ hasDefault: false;
42
+ isPrimaryKey: false;
43
+ isAutoincrement: false;
44
+ hasRuntimeDefault: false;
45
+ enumValues: [string, ...string[]];
46
+ baseColumn: never;
47
+ identity: undefined;
48
+ generated: undefined;
49
+ }, {}>;
50
+ threadId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
51
+ name: string;
52
+ tableName: "sessions";
53
+ dataType: "string";
54
+ data: string;
55
+ driverParam: string;
56
+ notNull: true;
57
+ hasDefault: true;
58
+ isPrimaryKey: false;
59
+ isAutoincrement: false;
60
+ hasRuntimeDefault: false;
61
+ enumValues: [string, ...string[]];
62
+ baseColumn: never;
63
+ identity: undefined;
64
+ generated: undefined;
65
+ }, {}>;
66
+ userId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
67
+ name: string;
68
+ tableName: "sessions";
69
+ dataType: "string";
70
+ data: string;
71
+ driverParam: string;
72
+ notNull: true;
73
+ hasDefault: true;
74
+ isPrimaryKey: false;
75
+ isAutoincrement: false;
76
+ hasRuntimeDefault: false;
77
+ enumValues: [string, ...string[]];
78
+ baseColumn: never;
79
+ identity: undefined;
80
+ generated: undefined;
81
+ }, {}>;
82
+ sessionId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
83
+ name: string;
84
+ tableName: "sessions";
85
+ dataType: "string";
86
+ data: string;
87
+ driverParam: string;
88
+ notNull: true;
89
+ hasDefault: false;
90
+ isPrimaryKey: false;
91
+ isAutoincrement: false;
92
+ hasRuntimeDefault: false;
93
+ enumValues: [string, ...string[]];
94
+ baseColumn: never;
95
+ identity: undefined;
96
+ generated: undefined;
97
+ }, {}>;
98
+ stateKind: import("drizzle-orm/sqlite-core").SQLiteColumn<{
99
+ name: string;
100
+ tableName: "sessions";
101
+ dataType: "string enum";
102
+ data: "active" | "idle" | "suspended";
103
+ driverParam: string;
104
+ notNull: true;
105
+ hasDefault: false;
106
+ isPrimaryKey: false;
107
+ isAutoincrement: false;
108
+ hasRuntimeDefault: false;
109
+ enumValues: ["active", "idle", "suspended"];
110
+ baseColumn: never;
111
+ identity: undefined;
112
+ generated: undefined;
113
+ }, {}>;
114
+ stateData: import("drizzle-orm/sqlite-core").SQLiteColumn<{
115
+ name: string;
116
+ tableName: "sessions";
117
+ dataType: "string";
118
+ data: string;
119
+ driverParam: string;
120
+ notNull: true;
121
+ hasDefault: false;
122
+ isPrimaryKey: false;
123
+ isAutoincrement: false;
124
+ hasRuntimeDefault: false;
125
+ enumValues: [string, ...string[]];
126
+ baseColumn: never;
127
+ identity: undefined;
128
+ generated: undefined;
129
+ }, {}>;
130
+ originJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
131
+ name: string;
132
+ tableName: "sessions";
133
+ dataType: "string";
134
+ data: string;
135
+ driverParam: string;
136
+ notNull: true;
137
+ hasDefault: false;
138
+ isPrimaryKey: false;
139
+ isAutoincrement: false;
140
+ hasRuntimeDefault: false;
141
+ enumValues: [string, ...string[]];
142
+ baseColumn: never;
143
+ identity: undefined;
144
+ generated: undefined;
145
+ }, {}>;
146
+ createdAtMs: import("drizzle-orm/sqlite-core").SQLiteColumn<{
147
+ name: string;
148
+ tableName: "sessions";
149
+ dataType: "number int53";
150
+ data: number;
151
+ driverParam: number;
152
+ notNull: true;
153
+ hasDefault: false;
154
+ isPrimaryKey: false;
155
+ isAutoincrement: false;
156
+ hasRuntimeDefault: false;
157
+ enumValues: undefined;
158
+ baseColumn: never;
159
+ identity: undefined;
160
+ generated: undefined;
161
+ }, {}>;
162
+ lastTurnAtMs: import("drizzle-orm/sqlite-core").SQLiteColumn<{
163
+ name: string;
164
+ tableName: "sessions";
165
+ dataType: "number int53";
166
+ data: number;
167
+ driverParam: number;
168
+ notNull: true;
169
+ hasDefault: false;
170
+ isPrimaryKey: false;
171
+ isAutoincrement: false;
172
+ hasRuntimeDefault: false;
173
+ enumValues: undefined;
174
+ baseColumn: never;
175
+ identity: undefined;
176
+ generated: undefined;
177
+ }, {}>;
178
+ tokenInput: import("drizzle-orm/sqlite-core").SQLiteColumn<{
179
+ name: string;
180
+ tableName: "sessions";
181
+ dataType: "number int53";
182
+ data: number;
183
+ driverParam: number;
184
+ notNull: true;
185
+ hasDefault: true;
186
+ isPrimaryKey: false;
187
+ isAutoincrement: false;
188
+ hasRuntimeDefault: false;
189
+ enumValues: undefined;
190
+ baseColumn: never;
191
+ identity: undefined;
192
+ generated: undefined;
193
+ }, {}>;
194
+ tokenOutput: import("drizzle-orm/sqlite-core").SQLiteColumn<{
195
+ name: string;
196
+ tableName: "sessions";
197
+ dataType: "number int53";
198
+ data: number;
199
+ driverParam: number;
200
+ notNull: true;
201
+ hasDefault: true;
202
+ isPrimaryKey: false;
203
+ isAutoincrement: false;
204
+ hasRuntimeDefault: false;
205
+ enumValues: undefined;
206
+ baseColumn: never;
207
+ identity: undefined;
208
+ generated: undefined;
209
+ }, {}>;
210
+ };
211
+ dialect: "sqlite";
212
+ }>;
213
+ /**
214
+ * 入站事件去重 —— 按 adapter_id 隔离。
215
+ *
216
+ * 所有 IM 平台都有 at-least-once 投递语义(飞书 WS ACK 超时、Telegram
217
+ * webhook 重试、Slack Events API 3s 未 ACK …)。本表按 (adapter_id, message_id)
218
+ * 复合主键去重,每个 adapter 复用同一张表,各自的 messageId 命名空间靠
219
+ * `adapter_id` 列隔离。
220
+ *
221
+ * LRU 容量上限(默认 10k)和淘汰策略由 IDedupStore 实现层管理;
222
+ * `seen_at_ms` 索引服务于"删 seen_at_ms 最早的一批"这种清理 query。
223
+ */
224
+ export declare const inboundDedup: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
225
+ name: "inbound_dedup";
226
+ schema: undefined;
227
+ columns: {
228
+ adapterId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
229
+ name: string;
230
+ tableName: "inbound_dedup";
231
+ dataType: "string";
232
+ data: string;
233
+ driverParam: string;
234
+ notNull: true;
235
+ hasDefault: false;
236
+ isPrimaryKey: false;
237
+ isAutoincrement: false;
238
+ hasRuntimeDefault: false;
239
+ enumValues: [string, ...string[]];
240
+ baseColumn: never;
241
+ identity: undefined;
242
+ generated: undefined;
243
+ }, {}>;
244
+ messageId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
245
+ name: string;
246
+ tableName: "inbound_dedup";
247
+ dataType: "string";
248
+ data: string;
249
+ driverParam: string;
250
+ notNull: true;
251
+ hasDefault: false;
252
+ isPrimaryKey: false;
253
+ isAutoincrement: false;
254
+ hasRuntimeDefault: false;
255
+ enumValues: [string, ...string[]];
256
+ baseColumn: never;
257
+ identity: undefined;
258
+ generated: undefined;
259
+ }, {}>;
260
+ seenAtMs: import("drizzle-orm/sqlite-core").SQLiteColumn<{
261
+ name: string;
262
+ tableName: "inbound_dedup";
263
+ dataType: "number int53";
264
+ data: number;
265
+ driverParam: number;
266
+ notNull: true;
267
+ hasDefault: false;
268
+ isPrimaryKey: false;
269
+ isAutoincrement: false;
270
+ hasRuntimeDefault: false;
271
+ enumValues: undefined;
272
+ baseColumn: never;
273
+ identity: undefined;
274
+ generated: undefined;
275
+ }, {}>;
276
+ };
277
+ dialect: "sqlite";
278
+ }>;
279
+ /**
280
+ * M6: DB-backed Store 表。
281
+ */
282
+ export declare const adapterBindings: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
283
+ name: "adapter_bindings";
284
+ schema: undefined;
285
+ columns: {
286
+ adapterId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
287
+ name: string;
288
+ tableName: "adapter_bindings";
289
+ dataType: "string";
290
+ data: string;
291
+ driverParam: string;
292
+ notNull: true;
293
+ hasDefault: false;
294
+ isPrimaryKey: true;
295
+ isAutoincrement: false;
296
+ hasRuntimeDefault: false;
297
+ enumValues: [string, ...string[]];
298
+ baseColumn: never;
299
+ identity: undefined;
300
+ generated: undefined;
301
+ }, {}>;
302
+ platform: import("drizzle-orm/sqlite-core").SQLiteColumn<{
303
+ name: string;
304
+ tableName: "adapter_bindings";
305
+ dataType: "string";
306
+ data: string;
307
+ driverParam: string;
308
+ notNull: true;
309
+ hasDefault: false;
310
+ isPrimaryKey: false;
311
+ isAutoincrement: false;
312
+ hasRuntimeDefault: false;
313
+ enumValues: [string, ...string[]];
314
+ baseColumn: never;
315
+ identity: undefined;
316
+ generated: undefined;
317
+ }, {}>;
318
+ configJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
319
+ name: string;
320
+ tableName: "adapter_bindings";
321
+ dataType: "string";
322
+ data: string;
323
+ driverParam: string;
324
+ notNull: true;
325
+ hasDefault: true;
326
+ isPrimaryKey: false;
327
+ isAutoincrement: false;
328
+ hasRuntimeDefault: false;
329
+ enumValues: [string, ...string[]];
330
+ baseColumn: never;
331
+ identity: undefined;
332
+ generated: undefined;
333
+ }, {}>;
334
+ secretsJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
335
+ name: string;
336
+ tableName: "adapter_bindings";
337
+ dataType: "string";
338
+ data: string;
339
+ driverParam: string;
340
+ notNull: true;
341
+ hasDefault: true;
342
+ isPrimaryKey: false;
343
+ isAutoincrement: false;
344
+ hasRuntimeDefault: false;
345
+ enumValues: [string, ...string[]];
346
+ baseColumn: never;
347
+ identity: undefined;
348
+ generated: undefined;
349
+ }, {}>;
350
+ };
351
+ dialect: "sqlite";
352
+ }>;
353
+ export declare const chatPolicy: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
354
+ name: "chat_policy";
355
+ schema: undefined;
356
+ columns: {
357
+ adapterId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
358
+ name: string;
359
+ tableName: "chat_policy";
360
+ dataType: "string";
361
+ data: string;
362
+ driverParam: string;
363
+ notNull: true;
364
+ hasDefault: false;
365
+ isPrimaryKey: false;
366
+ isAutoincrement: false;
367
+ hasRuntimeDefault: false;
368
+ enumValues: [string, ...string[]];
369
+ baseColumn: never;
370
+ identity: undefined;
371
+ generated: undefined;
372
+ }, {}>;
373
+ chatId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
374
+ name: string;
375
+ tableName: "chat_policy";
376
+ dataType: "string";
377
+ data: string;
378
+ driverParam: string;
379
+ notNull: true;
380
+ hasDefault: false;
381
+ isPrimaryKey: false;
382
+ isAutoincrement: false;
383
+ hasRuntimeDefault: false;
384
+ enumValues: [string, ...string[]];
385
+ baseColumn: never;
386
+ identity: undefined;
387
+ generated: undefined;
388
+ }, {}>;
389
+ policy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
390
+ name: string;
391
+ tableName: "chat_policy";
392
+ dataType: "string";
393
+ data: string;
394
+ driverParam: string;
395
+ notNull: true;
396
+ hasDefault: false;
397
+ isPrimaryKey: false;
398
+ isAutoincrement: false;
399
+ hasRuntimeDefault: false;
400
+ enumValues: [string, ...string[]];
401
+ baseColumn: never;
402
+ identity: undefined;
403
+ generated: undefined;
404
+ }, {}>;
405
+ requireMention: import("drizzle-orm/sqlite-core").SQLiteColumn<{
406
+ name: string;
407
+ tableName: "chat_policy";
408
+ dataType: "number int53";
409
+ data: number;
410
+ driverParam: number;
411
+ notNull: true;
412
+ hasDefault: true;
413
+ isPrimaryKey: false;
414
+ isAutoincrement: false;
415
+ hasRuntimeDefault: false;
416
+ enumValues: undefined;
417
+ baseColumn: never;
418
+ identity: undefined;
419
+ generated: undefined;
420
+ }, {}>;
421
+ allowlistJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
422
+ name: string;
423
+ tableName: "chat_policy";
424
+ dataType: "string";
425
+ data: string;
426
+ driverParam: string;
427
+ notNull: true;
428
+ hasDefault: true;
429
+ isPrimaryKey: false;
430
+ isAutoincrement: false;
431
+ hasRuntimeDefault: false;
432
+ enumValues: [string, ...string[]];
433
+ baseColumn: never;
434
+ identity: undefined;
435
+ generated: undefined;
436
+ }, {}>;
437
+ blacklistJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
438
+ name: string;
439
+ tableName: "chat_policy";
440
+ dataType: "string";
441
+ data: string;
442
+ driverParam: string;
443
+ notNull: true;
444
+ hasDefault: true;
445
+ isPrimaryKey: false;
446
+ isAutoincrement: false;
447
+ hasRuntimeDefault: false;
448
+ enumValues: [string, ...string[]];
449
+ baseColumn: never;
450
+ identity: undefined;
451
+ generated: undefined;
452
+ }, {}>;
453
+ updatedBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
454
+ name: string;
455
+ tableName: "chat_policy";
456
+ dataType: "string";
457
+ data: string;
458
+ driverParam: string;
459
+ notNull: true;
460
+ hasDefault: false;
461
+ isPrimaryKey: false;
462
+ isAutoincrement: false;
463
+ hasRuntimeDefault: false;
464
+ enumValues: [string, ...string[]];
465
+ baseColumn: never;
466
+ identity: undefined;
467
+ generated: undefined;
468
+ }, {}>;
469
+ updatedAtMs: import("drizzle-orm/sqlite-core").SQLiteColumn<{
470
+ name: string;
471
+ tableName: "chat_policy";
472
+ dataType: "number int53";
473
+ data: number;
474
+ driverParam: number;
475
+ notNull: true;
476
+ hasDefault: false;
477
+ isPrimaryKey: false;
478
+ isAutoincrement: false;
479
+ hasRuntimeDefault: false;
480
+ enumValues: undefined;
481
+ baseColumn: never;
482
+ identity: undefined;
483
+ generated: undefined;
484
+ }, {}>;
485
+ };
486
+ dialect: "sqlite";
487
+ }>;
488
+ export declare const pairRequests: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
489
+ name: "pair_requests";
490
+ schema: undefined;
491
+ columns: {
492
+ code: import("drizzle-orm/sqlite-core").SQLiteColumn<{
493
+ name: string;
494
+ tableName: "pair_requests";
495
+ dataType: "string";
496
+ data: string;
497
+ driverParam: string;
498
+ notNull: true;
499
+ hasDefault: false;
500
+ isPrimaryKey: true;
501
+ isAutoincrement: false;
502
+ hasRuntimeDefault: false;
503
+ enumValues: [string, ...string[]];
504
+ baseColumn: never;
505
+ identity: undefined;
506
+ generated: undefined;
507
+ }, {}>;
508
+ adapterId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
509
+ name: string;
510
+ tableName: "pair_requests";
511
+ dataType: "string";
512
+ data: string;
513
+ driverParam: string;
514
+ notNull: true;
515
+ hasDefault: false;
516
+ isPrimaryKey: false;
517
+ isAutoincrement: false;
518
+ hasRuntimeDefault: false;
519
+ enumValues: [string, ...string[]];
520
+ baseColumn: never;
521
+ identity: undefined;
522
+ generated: undefined;
523
+ }, {}>;
524
+ userId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
525
+ name: string;
526
+ tableName: "pair_requests";
527
+ dataType: "string";
528
+ data: string;
529
+ driverParam: string;
530
+ notNull: true;
531
+ hasDefault: false;
532
+ isPrimaryKey: false;
533
+ isAutoincrement: false;
534
+ hasRuntimeDefault: false;
535
+ enumValues: [string, ...string[]];
536
+ baseColumn: never;
537
+ identity: undefined;
538
+ generated: undefined;
539
+ }, {}>;
540
+ chatId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
541
+ name: string;
542
+ tableName: "pair_requests";
543
+ dataType: "string";
544
+ data: string;
545
+ driverParam: string;
546
+ notNull: true;
547
+ hasDefault: false;
548
+ isPrimaryKey: false;
549
+ isAutoincrement: false;
550
+ hasRuntimeDefault: false;
551
+ enumValues: [string, ...string[]];
552
+ baseColumn: never;
553
+ identity: undefined;
554
+ generated: undefined;
555
+ }, {}>;
556
+ expiresAtMs: import("drizzle-orm/sqlite-core").SQLiteColumn<{
557
+ name: string;
558
+ tableName: "pair_requests";
559
+ dataType: "number int53";
560
+ data: number;
561
+ driverParam: number;
562
+ notNull: true;
563
+ hasDefault: false;
564
+ isPrimaryKey: false;
565
+ isAutoincrement: false;
566
+ hasRuntimeDefault: false;
567
+ enumValues: undefined;
568
+ baseColumn: never;
569
+ identity: undefined;
570
+ generated: undefined;
571
+ }, {}>;
572
+ };
573
+ dialect: "sqlite";
574
+ }>;
575
+ export type SessionRow = typeof sessions.$inferSelect;
576
+ export type SessionInsert = typeof sessions.$inferInsert;
577
+ export type InboundDedupRow = typeof inboundDedup.$inferSelect;
578
+ export type InboundDedupInsert = typeof inboundDedup.$inferInsert;
579
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BpB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK1B,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBtB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMvB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAC;AACtD,MAAM,MAAM,aAAa,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAC/D,MAAM,MAAM,kBAAkB,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { index, integer, primaryKey, sqliteTable, text, } from 'drizzle-orm/sqlite-core';
2
+ /**
3
+ * Drizzle schema 是 SQL 表结构的 single source of truth。
4
+ *
5
+ * 注意:复合主键里有任何字段是 NULL 时,SQLite 视作"两行不同"
6
+ * (NULL != NULL)—— 这会破坏 (platform, chat, thread, user) 的去重语义。
7
+ * 对策:threadId / userId 用 NOT NULL DEFAULT '','' 即"无 thread / 任意 user"。
8
+ *
9
+ * 改 schema 后流程:
10
+ * 1) `pnpm --filter @stackory/gateway-session drizzle-kit generate` 产 migrations/*.sql
11
+ * 2) 人工 review SQL(删噪音、确认顺序)
12
+ * 3) 把 SQL 内容贴进 src/migrations/NNN-name.ts 的字符串常量里(runtime 用)
13
+ * 4) 把 .sql 也提交(review 痕迹 + drizzle-kit meta)
14
+ */
15
+ export const sessions = sqliteTable('sessions', {
16
+ adapterId: text('adapter_id').notNull(),
17
+ chatId: text('chat_id').notNull(),
18
+ threadId: text('thread_id').notNull().default(''),
19
+ userId: text('user_id').notNull().default(''),
20
+ sessionId: text('session_id').notNull(),
21
+ stateKind: text('state_kind', {
22
+ enum: ['active', 'idle', 'suspended'],
23
+ }).notNull(),
24
+ stateData: text('state_data').notNull(),
25
+ originJson: text('origin_json').notNull(),
26
+ createdAtMs: integer('created_at_ms').notNull(),
27
+ lastTurnAtMs: integer('last_turn_at_ms').notNull(),
28
+ tokenInput: integer('token_input').notNull().default(0),
29
+ tokenOutput: integer('token_output').notNull().default(0),
30
+ }, (t) => [
31
+ primaryKey({
32
+ name: 'sessions_pkey',
33
+ columns: [t.adapterId, t.chatId, t.threadId, t.userId],
34
+ }),
35
+ index('idx_sessions_adapter_state').on(t.adapterId, t.stateKind),
36
+ index('idx_sessions_adapter_idle').on(t.adapterId, t.lastTurnAtMs),
37
+ ]);
38
+ /**
39
+ * 入站事件去重 —— 按 adapter_id 隔离。
40
+ *
41
+ * 所有 IM 平台都有 at-least-once 投递语义(飞书 WS ACK 超时、Telegram
42
+ * webhook 重试、Slack Events API 3s 未 ACK …)。本表按 (adapter_id, message_id)
43
+ * 复合主键去重,每个 adapter 复用同一张表,各自的 messageId 命名空间靠
44
+ * `adapter_id` 列隔离。
45
+ *
46
+ * LRU 容量上限(默认 10k)和淘汰策略由 IDedupStore 实现层管理;
47
+ * `seen_at_ms` 索引服务于"删 seen_at_ms 最早的一批"这种清理 query。
48
+ */
49
+ export const inboundDedup = sqliteTable('inbound_dedup', {
50
+ adapterId: text('adapter_id').notNull(),
51
+ messageId: text('message_id').notNull(),
52
+ seenAtMs: integer('seen_at_ms').notNull(),
53
+ }, (t) => [
54
+ primaryKey({
55
+ name: 'inbound_dedup_pkey',
56
+ columns: [t.adapterId, t.messageId],
57
+ }),
58
+ index('idx_inbound_dedup_seen').on(t.adapterId, t.seenAtMs),
59
+ ]);
60
+ /**
61
+ * M6: DB-backed Store 表。
62
+ */
63
+ export const adapterBindings = sqliteTable('adapter_bindings', {
64
+ adapterId: text('adapter_id').primaryKey(),
65
+ platform: text('platform').notNull(),
66
+ configJson: text('config_json').notNull().default('{}'),
67
+ secretsJson: text('secrets_json').notNull().default('{}'),
68
+ });
69
+ export const chatPolicy = sqliteTable('chat_policy', {
70
+ adapterId: text('adapter_id').notNull(),
71
+ chatId: text('chat_id').notNull(),
72
+ policy: text('policy').notNull(),
73
+ requireMention: integer('require_mention').notNull().default(0),
74
+ allowlistJson: text('allowlist_json').notNull().default('[]'),
75
+ blacklistJson: text('blacklist_json').notNull().default('[]'),
76
+ updatedBy: text('updated_by').notNull(),
77
+ updatedAtMs: integer('updated_at_ms').notNull(),
78
+ }, (t) => [
79
+ primaryKey({
80
+ name: 'chat_policy_pkey',
81
+ columns: [t.adapterId, t.chatId],
82
+ }),
83
+ ]);
84
+ export const pairRequests = sqliteTable('pair_requests', {
85
+ code: text('code').primaryKey(),
86
+ adapterId: text('adapter_id').notNull(),
87
+ userId: text('user_id').notNull(),
88
+ chatId: text('chat_id').notNull(),
89
+ expiresAtMs: integer('expires_at_ms').notNull(),
90
+ });
91
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { IDedupStore } from '@stackory/gateway-core';
2
+ import type { IInternalDatabaseHandle } from '../database';
3
+ /**
4
+ * SQLite 实现的 IDedupStore。
5
+ */
6
+ export declare class SqliteDedupStore implements IDedupStore {
7
+ private readonly db;
8
+ private readonly maxEntries;
9
+ constructor(db: IInternalDatabaseHandle, maxEntries?: number);
10
+ checkAndMark(adapterId: string, messageId: string, nowMs: number): boolean;
11
+ private evictIfNeeded;
12
+ }
13
+ export declare function createDedupStore(db: IInternalDatabaseHandle, maxEntries?: number): IDedupStore;
14
+ //# sourceMappingURL=dedup-store.d.ts.map