@critical-path/core 0.29.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.
- package/CHANGELOG.md +22 -0
- package/README.md +10 -0
- package/dist/engine/index.d.ts +9 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +28 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/schemas/index.d.ts +75 -22
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +26 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/store/firebase.d.ts +4 -0
- package/dist/store/firebase.d.ts.map +1 -1
- package/dist/store/firebase.js +10 -0
- package/dist/store/firebase.js.map +1 -1
- package/dist/store/index.d.ts +8 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +10 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/query.d.ts +50 -0
- package/dist/store/query.d.ts.map +1 -0
- package/dist/store/query.js +79 -0
- package/dist/store/query.js.map +1 -0
- package/dist/store/query.test.d.ts +2 -0
- package/dist/store/query.test.d.ts.map +1 -0
- package/dist/store/query.test.js +89 -0
- package/dist/store/query.test.js.map +1 -0
- package/dist/store/sqlite.d.ts +3 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +90 -0
- package/dist/store/sqlite.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/index.ts +30 -1
- package/src/schemas/index.ts +31 -0
- package/src/store/firebase.ts +14 -0
- package/src/store/index.ts +24 -0
- package/src/store/query.test.ts +110 -0
- package/src/store/query.ts +113 -0
- package/src/store/sqlite.ts +93 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/store/sqlite.ts
CHANGED
|
@@ -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,
|
|
@@ -288,6 +289,17 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
288
289
|
// Column may already exist
|
|
289
290
|
}
|
|
290
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
|
+
|
|
291
303
|
for (const column of ['name TEXT', 'tenantId TEXT']) {
|
|
292
304
|
try {
|
|
293
305
|
this.db.exec(`ALTER TABLE webhooks ADD COLUMN ${column}`);
|
|
@@ -688,6 +700,55 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
688
700
|
return rows.map((r) => this.mapTask(r));
|
|
689
701
|
}
|
|
690
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
|
+
|
|
691
752
|
async getTask(id: string): Promise<Task | null> {
|
|
692
753
|
const stmt = this.db.prepare('SELECT * FROM tasks WHERE id = ?');
|
|
693
754
|
const row = stmt.get(id) as any;
|
|
@@ -1124,6 +1185,38 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
1124
1185
|
);
|
|
1125
1186
|
}
|
|
1126
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 };
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1127
1220
|
async logActivity(activity: Omit<Activity, 'id' | 'createdAt'>): Promise<Activity> {
|
|
1128
1221
|
const id = `act_${Math.random().toString(36).substring(2, 9)}`;
|
|
1129
1222
|
const now = new Date().toISOString();
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -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/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/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"}
|