@critical-path/core 0.28.0 → 0.30.0

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 (52) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +14 -0
  3. package/dist/domain/events.d.ts +8 -2
  4. package/dist/domain/events.d.ts.map +1 -1
  5. package/dist/domain/events.js +1 -0
  6. package/dist/domain/events.js.map +1 -1
  7. package/dist/engine/cascade.test.d.ts +2 -0
  8. package/dist/engine/cascade.test.d.ts.map +1 -0
  9. package/dist/engine/cascade.test.js +99 -0
  10. package/dist/engine/cascade.test.js.map +1 -0
  11. package/dist/engine/index.d.ts +25 -2
  12. package/dist/engine/index.d.ts.map +1 -1
  13. package/dist/engine/index.js +117 -6
  14. package/dist/engine/index.js.map +1 -1
  15. package/dist/schemas/index.d.ts +81 -28
  16. package/dist/schemas/index.d.ts.map +1 -1
  17. package/dist/schemas/index.js +26 -0
  18. package/dist/schemas/index.js.map +1 -1
  19. package/dist/store/firebase.d.ts +12 -0
  20. package/dist/store/firebase.d.ts.map +1 -1
  21. package/dist/store/firebase.js +40 -8
  22. package/dist/store/firebase.js.map +1 -1
  23. package/dist/store/index.d.ts +15 -0
  24. package/dist/store/index.d.ts.map +1 -1
  25. package/dist/store/index.js +19 -0
  26. package/dist/store/index.js.map +1 -1
  27. package/dist/store/query.d.ts +50 -0
  28. package/dist/store/query.d.ts.map +1 -0
  29. package/dist/store/query.js +79 -0
  30. package/dist/store/query.js.map +1 -0
  31. package/dist/store/query.test.d.ts +2 -0
  32. package/dist/store/query.test.d.ts.map +1 -0
  33. package/dist/store/query.test.js +89 -0
  34. package/dist/store/query.test.js.map +1 -0
  35. package/dist/store/sqlite.d.ts +6 -0
  36. package/dist/store/sqlite.d.ts.map +1 -1
  37. package/dist/store/sqlite.js +131 -24
  38. package/dist/store/sqlite.js.map +1 -1
  39. package/dist/webhooks/webhooks.test.js +2 -1
  40. package/dist/webhooks/webhooks.test.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/domain/events.ts +7 -0
  43. package/src/engine/cascade.test.ts +121 -0
  44. package/src/engine/index.ts +126 -6
  45. package/src/schemas/index.ts +31 -0
  46. package/src/store/firebase.ts +47 -8
  47. package/src/store/index.ts +40 -0
  48. package/src/store/query.test.ts +110 -0
  49. package/src/store/query.ts +113 -0
  50. package/src/store/sqlite.ts +149 -31
  51. package/src/webhooks/webhooks.test.ts +2 -1
  52. package/tsconfig.tsbuildinfo +1 -1
@@ -1,5 +1,6 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  import type { StorageAdapter } from './index.js';
3
+ import { decodeCursor, encodeCursor, pageSize, type ActivityQuery, type Page, type TaskQuery } from './query.js';
3
4
  import type {
4
5
  Project,
5
6
  Task,
@@ -18,6 +19,14 @@ import type {
18
19
  } from '../types/index.js';
19
20
  import { generateProjectKey } from '../utils/key.js';
20
21
 
22
+ /**
23
+ * SQLite returns NULL columns as `null`, while domain objects leave unset optional fields out.
24
+ * Dropping nulls keeps SQLiteStore results identical to the other adapters.
25
+ */
26
+ function dropNulls<T extends object>(row: T): T {
27
+ return Object.fromEntries(Object.entries(row).filter(([, value]) => value !== null)) as T;
28
+ }
29
+
21
30
  export interface SQLiteStoreConfig {
22
31
  /**
23
32
  * Database file path (e.g., 'critical-path.db' or ':memory:').
@@ -280,6 +289,17 @@ export class SQLiteStore implements StorageAdapter {
280
289
  // Column may already exist
281
290
  }
282
291
 
292
+ // Indexes for filtered queries and keyset pagination
293
+ this.db.exec(`
294
+ CREATE INDEX IF NOT EXISTS idx_tasks_project_created ON tasks (projectId, createdAt, id);
295
+ CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks (parentId);
296
+ CREATE INDEX IF NOT EXISTS idx_activities_project_created ON activities (projectId, createdAt, id);
297
+ CREATE INDEX IF NOT EXISTS idx_activities_task_created ON activities (taskId, createdAt, id);
298
+ CREATE INDEX IF NOT EXISTS idx_comments_task ON comments (taskId);
299
+ CREATE INDEX IF NOT EXISTS idx_dependencies_task ON dependencies (taskId);
300
+ CREATE INDEX IF NOT EXISTS idx_dependencies_upstream ON dependencies (dependsOnTaskId);
301
+ `);
302
+
283
303
  for (const column of ['name TEXT', 'tenantId TEXT']) {
284
304
  try {
285
305
  this.db.exec(`ALTER TABLE webhooks ADD COLUMN ${column}`);
@@ -516,13 +536,13 @@ export class SQLiteStore implements StorageAdapter {
516
536
  async getContainers(projectId: string): Promise<TaskContainer[]> {
517
537
  const stmt = this.db.prepare('SELECT * FROM containers WHERE projectId = ?');
518
538
  const rows = stmt.all(projectId) as any[];
519
- return rows;
539
+ return rows.map(dropNulls);
520
540
  }
521
541
 
522
542
  async getContainer(id: string): Promise<TaskContainer | null> {
523
543
  const stmt = this.db.prepare('SELECT * FROM containers WHERE id = ?');
524
544
  const row = stmt.get(id) as any;
525
- return row || null;
545
+ return row ? dropNulls(row) : null;
526
546
  }
527
547
 
528
548
  async createContainer(container: Omit<TaskContainer, 'id' | 'createdAt' | 'updatedAt'>): Promise<TaskContainer> {
@@ -680,6 +700,55 @@ export class SQLiteStore implements StorageAdapter {
680
700
  return rows.map((r) => this.mapTask(r));
681
701
  }
682
702
 
703
+ async queryTasks(query: TaskQuery): Promise<Page<Task>> {
704
+ const where: string[] = [];
705
+ const params: Array<string | number> = [];
706
+ const inList = (column: string, values: string[]) => {
707
+ where.push(`${column} IN (${values.map(() => '?').join(', ')})`);
708
+ params.push(...values);
709
+ };
710
+
711
+ if (query.projectId) {
712
+ where.push('projectId = ?');
713
+ params.push(query.projectId);
714
+ }
715
+ if (query.projectIds) {
716
+ if (query.projectIds.length === 0) return { items: [] };
717
+ inList('projectId', query.projectIds);
718
+ }
719
+ if (query.status?.length) inList('status', query.status);
720
+ if (query.priority?.length) inList('priority', query.priority);
721
+ for (const column of ['iterationId', 'deliverableId', 'containerId'] as const) {
722
+ if (query[column]) {
723
+ where.push(`${column} = ?`);
724
+ params.push(query[column]!);
725
+ }
726
+ }
727
+ if (query.parentId === null) where.push('parentId IS NULL');
728
+ else if (query.parentId) {
729
+ where.push('parentId = ?');
730
+ params.push(query.parentId);
731
+ }
732
+ if (query.assigneeId) {
733
+ where.push(
734
+ "(assigneeId = ? OR EXISTS (SELECT 1 FROM json_each(COALESCE(assignees, '[]')) WHERE json_extract(value, '$.id') = ?))"
735
+ );
736
+ params.push(query.assigneeId, query.assigneeId);
737
+ }
738
+ const after = decodeCursor(query.cursor);
739
+ if (after) {
740
+ where.push('(createdAt > ? OR (createdAt = ? AND id > ?))');
741
+ params.push(after[0], after[0], after[1]);
742
+ }
743
+
744
+ const size = pageSize(query.limit);
745
+ const sql = `SELECT * FROM tasks ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY createdAt ASC, id ASC LIMIT ?`;
746
+ const rows = this.db.prepare(sql).all(...params, size + 1) as any[];
747
+ const items = rows.slice(0, size).map((r) => this.mapTask(r));
748
+ const last = items[items.length - 1];
749
+ return { items, nextCursor: rows.length > size && last ? encodeCursor(last.createdAt, last.id) : undefined };
750
+ }
751
+
683
752
  async getTask(id: string): Promise<Task | null> {
684
753
  const stmt = this.db.prepare('SELECT * FROM tasks WHERE id = ?');
685
754
  const row = stmt.get(id) as any;
@@ -821,13 +890,13 @@ export class SQLiteStore implements StorageAdapter {
821
890
  async getIterations(projectId: string): Promise<Iteration[]> {
822
891
  const stmt = this.db.prepare('SELECT * FROM iterations WHERE projectId = ?');
823
892
  const rows = stmt.all(projectId) as any[];
824
- return rows;
893
+ return rows.map(dropNulls);
825
894
  }
826
895
 
827
896
  async getIteration(id: string): Promise<Iteration | null> {
828
897
  const stmt = this.db.prepare('SELECT * FROM iterations WHERE id = ?');
829
898
  const row = stmt.get(id) as any;
830
- return row || null;
899
+ return row ? dropNulls(row) : null;
831
900
  }
832
901
 
833
902
  async createIteration(iteration: Omit<Iteration, 'id' | 'createdAt'>): Promise<Iteration> {
@@ -883,7 +952,7 @@ export class SQLiteStore implements StorageAdapter {
883
952
 
884
953
  // --- Comments ---
885
954
  private mapComment(row: any): Comment {
886
- return {
955
+ return dropNulls({
887
956
  id: row.id,
888
957
  taskId: row.taskId,
889
958
  authorId: row.authorId,
@@ -895,7 +964,7 @@ export class SQLiteStore implements StorageAdapter {
895
964
  metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
896
965
  createdAt: row.createdAt,
897
966
  updatedAt: row.updatedAt
898
- };
967
+ });
899
968
  }
900
969
 
901
970
  async getComments(taskId: string): Promise<Comment[]> {
@@ -1028,22 +1097,24 @@ export class SQLiteStore implements StorageAdapter {
1028
1097
 
1029
1098
  const stmt = this.db.prepare(sql);
1030
1099
  const rows = stmt.all(...params) as any[];
1031
- return rows.map((r) => ({
1032
- ...r,
1033
- sizeBytes: Number(r.sizeBytes),
1034
- metadata: r.metadata ? JSON.parse(r.metadata) : undefined
1035
- }));
1100
+ return rows.map((r) =>
1101
+ dropNulls({
1102
+ ...r,
1103
+ sizeBytes: Number(r.sizeBytes),
1104
+ metadata: r.metadata ? JSON.parse(r.metadata) : undefined
1105
+ })
1106
+ );
1036
1107
  }
1037
1108
 
1038
1109
  async getAttachment(id: string): Promise<Attachment | null> {
1039
1110
  const stmt = this.db.prepare('SELECT * FROM attachments WHERE id = ?');
1040
1111
  const row = stmt.get(id) as any;
1041
1112
  if (!row) return null;
1042
- return {
1113
+ return dropNulls({
1043
1114
  ...row,
1044
1115
  sizeBytes: Number(row.sizeBytes),
1045
1116
  metadata: row.metadata ? JSON.parse(row.metadata) : undefined
1046
- };
1117
+ });
1047
1118
  }
1048
1119
 
1049
1120
  async createAttachment(attachment: Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Attachment> {
@@ -1106,10 +1177,44 @@ export class SQLiteStore implements StorageAdapter {
1106
1177
 
1107
1178
  const stmt = this.db.prepare(sql);
1108
1179
  const rows = stmt.all(...params) as any[];
1109
- return rows.map((r) => ({
1110
- ...r,
1111
- details: r.details ? JSON.parse(r.details) : undefined
1112
- }));
1180
+ return rows.map((r) =>
1181
+ dropNulls({
1182
+ ...r,
1183
+ details: r.details ? JSON.parse(r.details) : undefined
1184
+ })
1185
+ );
1186
+ }
1187
+
1188
+ async queryActivities(query: ActivityQuery): Promise<Page<Activity>> {
1189
+ const where: string[] = [];
1190
+ const params: Array<string | number> = [];
1191
+ if (query.projectId) {
1192
+ where.push('projectId = ?');
1193
+ params.push(query.projectId);
1194
+ }
1195
+ if (query.projectIds) {
1196
+ if (query.projectIds.length === 0) return { items: [] };
1197
+ where.push(`projectId IN (${query.projectIds.map(() => '?').join(', ')})`);
1198
+ params.push(...query.projectIds);
1199
+ }
1200
+ if (query.taskId) {
1201
+ where.push('taskId = ?');
1202
+ params.push(query.taskId);
1203
+ }
1204
+ const after = decodeCursor(query.cursor);
1205
+ if (after) {
1206
+ where.push('(createdAt < ? OR (createdAt = ? AND id < ?))');
1207
+ params.push(after[0], after[0], after[1]);
1208
+ }
1209
+
1210
+ const size = pageSize(query.limit);
1211
+ const sql = `SELECT * FROM activities ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY createdAt DESC, id DESC LIMIT ?`;
1212
+ const rows = this.db.prepare(sql).all(...params, size + 1) as any[];
1213
+ const items: Activity[] = rows
1214
+ .slice(0, size)
1215
+ .map((r) => dropNulls({ ...r, details: r.details ? JSON.parse(r.details) : undefined }));
1216
+ const last = items[items.length - 1];
1217
+ return { items, nextCursor: rows.length > size && last ? encodeCursor(last.createdAt, last.id) : undefined };
1113
1218
  }
1114
1219
 
1115
1220
  async logActivity(activity: Omit<Activity, 'id' | 'createdAt'>): Promise<Activity> {
@@ -1137,7 +1242,7 @@ export class SQLiteStore implements StorageAdapter {
1137
1242
  async getTimeEntries(taskId: string): Promise<TimeEntry[]> {
1138
1243
  const stmt = this.db.prepare('SELECT * FROM time_entries WHERE taskId = ?');
1139
1244
  const rows = stmt.all(taskId) as any[];
1140
- return rows.map((r) => ({ ...r, isBillable: r.isBillable !== null ? Boolean(r.isBillable) : undefined }));
1245
+ return rows.map((r) => dropNulls({ ...r, isBillable: r.isBillable !== null ? Boolean(r.isBillable) : undefined }));
1141
1246
  }
1142
1247
 
1143
1248
  async logTime(entry: Omit<TimeEntry, 'id' | 'loggedAt'> & { loggedAt?: string }): Promise<TimeEntry> {
@@ -1164,7 +1269,7 @@ export class SQLiteStore implements StorageAdapter {
1164
1269
  // --- Dependencies ---
1165
1270
  async getDependencies(taskId: string): Promise<TaskDependency[]> {
1166
1271
  const stmt = this.db.prepare('SELECT * FROM dependencies WHERE taskId = ? OR dependsOnTaskId = ?');
1167
- return stmt.all(taskId, taskId) as any[];
1272
+ return (stmt.all(taskId, taskId) as any[]).map(dropNulls);
1168
1273
  }
1169
1274
 
1170
1275
  async addDependency(dep: Omit<TaskDependency, 'id'>): Promise<TaskDependency> {
@@ -1179,6 +1284,19 @@ export class SQLiteStore implements StorageAdapter {
1179
1284
  return newDep;
1180
1285
  }
1181
1286
 
1287
+ async getDependency(id: string): Promise<TaskDependency | null> {
1288
+ const row = this.db.prepare('SELECT * FROM dependencies WHERE id = ?').get(id) as any;
1289
+ return row ? { id: row.id, taskId: row.taskId, dependsOnTaskId: row.dependsOnTaskId, type: row.type } : null;
1290
+ }
1291
+
1292
+ async removeDependency(id: string): Promise<boolean> {
1293
+ return Number(this.db.prepare('DELETE FROM dependencies WHERE id = ?').run(id).changes) > 0;
1294
+ }
1295
+
1296
+ async deleteTimeEntry(id: string): Promise<boolean> {
1297
+ return Number(this.db.prepare('DELETE FROM time_entries WHERE id = ?').run(id).changes) > 0;
1298
+ }
1299
+
1182
1300
  // --- Webhooks ---
1183
1301
  async getWebhooks(): Promise<Webhook[]> {
1184
1302
  const stmt = this.db.prepare('SELECT * FROM webhooks');
@@ -1215,7 +1333,7 @@ export class SQLiteStore implements StorageAdapter {
1215
1333
  }
1216
1334
 
1217
1335
  private mapWebhook(row: any): Webhook {
1218
- return {
1336
+ return dropNulls({
1219
1337
  id: row.id,
1220
1338
  name: row.name ?? '',
1221
1339
  url: row.url,
@@ -1224,7 +1342,7 @@ export class SQLiteStore implements StorageAdapter {
1224
1342
  active: Boolean(row.active),
1225
1343
  tenantId: row.tenantId ?? undefined,
1226
1344
  createdAt: row.createdAt
1227
- };
1345
+ });
1228
1346
  }
1229
1347
 
1230
1348
  async addWebhook(webhook: Omit<Webhook, 'id' | 'createdAt'>): Promise<Webhook> {
@@ -1251,7 +1369,7 @@ export class SQLiteStore implements StorageAdapter {
1251
1369
 
1252
1370
  // Helper mappers
1253
1371
  private mapProject(row: any): Project {
1254
- return {
1372
+ return dropNulls({
1255
1373
  ...row,
1256
1374
  tenantId: row.tenantId ?? undefined,
1257
1375
  workflowId: row.workflowId || undefined,
@@ -1261,30 +1379,30 @@ export class SQLiteStore implements StorageAdapter {
1261
1379
  statusDefinitions: row.statusDefinitions ? JSON.parse(row.statusDefinitions) : [],
1262
1380
  priorityDefinitions: row.priorityDefinitions ? JSON.parse(row.priorityDefinitions) : [],
1263
1381
  customFieldDefinitions: row.customFieldDefinitions ? JSON.parse(row.customFieldDefinitions) : []
1264
- };
1382
+ });
1265
1383
  }
1266
1384
 
1267
1385
  private mapWorkflow(row: any): Workflow {
1268
- return {
1386
+ return dropNulls({
1269
1387
  ...row,
1270
1388
  tenantId: row.tenantId ?? undefined,
1271
1389
  statuses: row.statuses ? JSON.parse(row.statuses) : [],
1272
1390
  transitions: row.transitions ? JSON.parse(row.transitions) : [],
1273
1391
  taskTypes: row.taskTypes ? JSON.parse(row.taskTypes) : undefined,
1274
1392
  isDefault: row.isDefault !== null && row.isDefault !== undefined ? Boolean(row.isDefault) : undefined
1275
- };
1393
+ });
1276
1394
  }
1277
1395
 
1278
1396
  private mapTeam(row: any): Team {
1279
- return {
1397
+ return dropNulls({
1280
1398
  ...row,
1281
1399
  tenantId: row.tenantId ?? undefined,
1282
1400
  memberIds: row.memberIds ? JSON.parse(row.memberIds) : []
1283
- };
1401
+ });
1284
1402
  }
1285
1403
 
1286
1404
  private mapTask(row: any): Task {
1287
- return {
1405
+ return dropNulls({
1288
1406
  ...row,
1289
1407
  actualDurationSeconds: row.actualDurationSeconds ?? undefined,
1290
1408
  inProgressSince: row.inProgressSince || undefined,
@@ -1299,15 +1417,15 @@ export class SQLiteStore implements StorageAdapter {
1299
1417
  tags: row.tags ? JSON.parse(row.tags) : [],
1300
1418
  assignees: row.assignees ? JSON.parse(row.assignees) : undefined,
1301
1419
  customFields: row.customFields ? JSON.parse(row.customFields) : {}
1302
- };
1420
+ });
1303
1421
  }
1304
1422
 
1305
1423
  private mapDeliverable(row: any): Deliverable {
1306
- return {
1424
+ return dropNulls({
1307
1425
  ...row,
1308
1426
  specs: row.specs ? JSON.parse(row.specs) : undefined,
1309
1427
  outputUrls: row.outputUrls ? JSON.parse(row.outputUrls) : [],
1310
1428
  customFields: row.customFields ? JSON.parse(row.customFields) : {}
1311
- };
1429
+ });
1312
1430
  }
1313
1431
  }
@@ -78,7 +78,8 @@ describe('webhook delivery', () => {
78
78
  await engine.createTask({ projectId: project.id, title: 'T' });
79
79
  await engine.webhooks.idle();
80
80
 
81
- expect(deliveries.map((d) => d.body.event)).toEqual(['project.created', 'task.created']);
81
+ // Deliveries are asynchronous, so arrival order is not guaranteed
82
+ expect(deliveries.map((d) => d.body.event).sort()).toEqual(['project.created', 'task.created']);
82
83
  expect(deliveries.every((d) => d.url.endsWith('/all'))).toBe(true);
83
84
  });
84
85
 
@@ -1 +1 @@
1
- {"root":["./src/deliverables.test.ts","./src/index.test.ts","./src/index.ts","./src/status.test.ts","./src/task-state.test.ts","./src/use-case-validation.test.ts","./src/domain/authorization.ts","./src/domain/calendar.test.ts","./src/domain/calendar.ts","./src/domain/cpm.test.ts","./src/domain/cpm.ts","./src/domain/custom-fields.ts","./src/domain/ddd.test.ts","./src/domain/entities.ts","./src/domain/errors.ts","./src/domain/events.ts","./src/domain/graph.ts","./src/domain/index.ts","./src/domain/ladder.test.ts","./src/domain/ladder.ts","./src/domain/metrics.test.ts","./src/domain/metrics.ts","./src/domain/task-duration.test.ts","./src/domain/workload.test.ts","./src/domain/workload.ts","./src/engine/actor.test.ts","./src/engine/authorization.test.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/plugins/plugins.test.ts","./src/schemas/index.ts","./src/schemas/schemas.test.ts","./src/storage/file-storage.ts","./src/storage/firebase-storage.ts","./src/storage/index.ts","./src/storage/s3.ts","./src/storage/storage.test.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts","./src/utils/fractional-index.test.ts","./src/utils/fractional-index.ts","./src/utils/index.ts","./src/utils/key.test.ts","./src/utils/key.ts","./src/utils/mentions.test.ts","./src/utils/mentions.ts","./src/utils/status.ts","./src/utils/workflow.ts","./src/webhooks/dispatcher.ts","./src/webhooks/index.ts","./src/webhooks/signature.ts","./src/webhooks/webhooks.test.ts"],"version":"5.9.3"}
1
+ {"root":["./src/deliverables.test.ts","./src/index.test.ts","./src/index.ts","./src/status.test.ts","./src/task-state.test.ts","./src/use-case-validation.test.ts","./src/domain/authorization.ts","./src/domain/calendar.test.ts","./src/domain/calendar.ts","./src/domain/cpm.test.ts","./src/domain/cpm.ts","./src/domain/custom-fields.ts","./src/domain/ddd.test.ts","./src/domain/entities.ts","./src/domain/errors.ts","./src/domain/events.ts","./src/domain/graph.ts","./src/domain/index.ts","./src/domain/ladder.test.ts","./src/domain/ladder.ts","./src/domain/metrics.test.ts","./src/domain/metrics.ts","./src/domain/task-duration.test.ts","./src/domain/workload.test.ts","./src/domain/workload.ts","./src/engine/actor.test.ts","./src/engine/authorization.test.ts","./src/engine/cascade.test.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/plugins/plugins.test.ts","./src/schemas/index.ts","./src/schemas/schemas.test.ts","./src/storage/file-storage.ts","./src/storage/firebase-storage.ts","./src/storage/index.ts","./src/storage/s3.ts","./src/storage/storage.test.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/query.test.ts","./src/store/query.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts","./src/utils/fractional-index.test.ts","./src/utils/fractional-index.ts","./src/utils/index.ts","./src/utils/key.test.ts","./src/utils/key.ts","./src/utils/mentions.test.ts","./src/utils/mentions.ts","./src/utils/status.ts","./src/utils/workflow.ts","./src/webhooks/dispatcher.ts","./src/webhooks/index.ts","./src/webhooks/signature.ts","./src/webhooks/webhooks.test.ts"],"version":"5.9.3"}