@critical-path/core 0.18.0 → 0.19.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.
- package/CHANGELOG.md +23 -0
- package/README.md +43 -0
- package/dist/domain/calendar.d.ts +53 -0
- package/dist/domain/calendar.d.ts.map +1 -0
- package/dist/domain/calendar.js +333 -0
- package/dist/domain/calendar.js.map +1 -0
- package/dist/domain/calendar.test.d.ts +2 -0
- package/dist/domain/calendar.test.d.ts.map +1 -0
- package/dist/domain/calendar.test.js +136 -0
- package/dist/domain/calendar.test.js.map +1 -0
- package/dist/domain/cpm.d.ts +8 -3
- package/dist/domain/cpm.d.ts.map +1 -1
- package/dist/domain/cpm.js +36 -3
- package/dist/domain/cpm.js.map +1 -1
- package/dist/domain/cpm.test.js +53 -0
- package/dist/domain/cpm.test.js.map +1 -1
- package/dist/domain/events.d.ts +38 -2
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/domain/index.d.ts +1 -0
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +1 -0
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/ladder.d.ts +3 -2
- package/dist/domain/ladder.d.ts.map +1 -1
- package/dist/domain/ladder.js +21 -3
- package/dist/domain/ladder.js.map +1 -1
- package/dist/domain/metrics.test.js +5 -4
- package/dist/domain/metrics.test.js.map +1 -1
- package/dist/domain/workload.d.ts.map +1 -1
- package/dist/domain/workload.js +60 -17
- package/dist/domain/workload.js.map +1 -1
- package/dist/domain/workload.test.js +60 -0
- package/dist/domain/workload.test.js.map +1 -1
- package/dist/engine/index.d.ts +22 -2
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +119 -15
- package/dist/engine/index.js.map +1 -1
- package/dist/index.test.js +41 -0
- package/dist/index.test.js.map +1 -1
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +9 -3
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sqlite.test.js +15 -1
- package/dist/store/sqlite.test.js.map +1 -1
- package/dist/task-state.test.js +49 -0
- package/dist/task-state.test.js.map +1 -1
- package/dist/types/index.d.ts +44 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/status.d.ts.map +1 -1
- package/dist/utils/status.js +5 -2
- package/dist/utils/status.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/calendar.test.ts +164 -0
- package/src/domain/calendar.ts +457 -0
- package/src/domain/cpm.test.ts +61 -0
- package/src/domain/cpm.ts +47 -4
- package/src/domain/events.ts +27 -2
- package/src/domain/index.ts +1 -0
- package/src/domain/ladder.ts +25 -4
- package/src/domain/metrics.test.ts +6 -4
- package/src/domain/workload.test.ts +73 -0
- package/src/domain/workload.ts +73 -19
- package/src/engine/index.ts +152 -16
- package/src/index.test.ts +48 -0
- package/src/store/sqlite.test.ts +17 -1
- package/src/store/sqlite.ts +11 -1
- package/src/task-state.test.ts +60 -1
- package/src/types/index.ts +48 -0
- package/src/utils/status.ts +7 -2
- package/tsconfig.tsbuildinfo +1 -1
package/src/store/sqlite.test.ts
CHANGED
|
@@ -40,8 +40,24 @@ describe('SQLiteStore', () => {
|
|
|
40
40
|
expect(task.priority).toBe('high');
|
|
41
41
|
expect(task.tags).toContain('sqlite');
|
|
42
42
|
|
|
43
|
-
const updated = await store.updateTask(task.id, {
|
|
43
|
+
const updated = await store.updateTask(task.id, {
|
|
44
|
+
status: 'in_progress',
|
|
45
|
+
isBlocked: true,
|
|
46
|
+
blockedReason: 'Waiting for SQLite lock'
|
|
47
|
+
});
|
|
44
48
|
expect(updated?.status).toBe('in_progress');
|
|
49
|
+
expect(updated?.isBlocked).toBe(true);
|
|
50
|
+
expect(updated?.blockedReason).toBe('Waiting for SQLite lock');
|
|
51
|
+
|
|
52
|
+
const fetchedTask = await store.getTask(task.id);
|
|
53
|
+
expect(fetchedTask?.isBlocked).toBe(true);
|
|
54
|
+
expect(fetchedTask?.blockedReason).toBe('Waiting for SQLite lock');
|
|
55
|
+
|
|
56
|
+
const unblocked = await store.updateTask(task.id, {
|
|
57
|
+
isBlocked: false,
|
|
58
|
+
blockedReason: null
|
|
59
|
+
});
|
|
60
|
+
expect(unblocked?.isBlocked).toBe(false);
|
|
45
61
|
|
|
46
62
|
const projectTasks = await store.getTasks(project.id);
|
|
47
63
|
expect(projectTasks).toHaveLength(1);
|
package/src/store/sqlite.ts
CHANGED
|
@@ -132,6 +132,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
132
132
|
actualDurationMinutes REAL,
|
|
133
133
|
billableDurationMinutes REAL,
|
|
134
134
|
progress REAL,
|
|
135
|
+
isBlocked INTEGER,
|
|
136
|
+
blockedReason TEXT,
|
|
135
137
|
tags TEXT,
|
|
136
138
|
customFields TEXT,
|
|
137
139
|
parentId TEXT,
|
|
@@ -659,8 +661,9 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
659
661
|
reviewerId, iterationId, teamId, containerId, deliverableId, plannedStartDate, actualStartDate, actualEndDate,
|
|
660
662
|
dueDate, estimatedHours, loggedHours, actualHours, billableHours,
|
|
661
663
|
estimatedDurationMinutes, actualDurationMinutes, billableDurationMinutes, progress,
|
|
664
|
+
isBlocked, blockedReason,
|
|
662
665
|
tags, customFields, parentId, createdAt, updatedAt
|
|
663
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
666
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
664
667
|
`);
|
|
665
668
|
stmt.run(
|
|
666
669
|
newTask.id,
|
|
@@ -690,6 +693,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
690
693
|
newTask.actualDurationMinutes ?? null,
|
|
691
694
|
newTask.billableDurationMinutes ?? null,
|
|
692
695
|
newTask.progress ?? null,
|
|
696
|
+
newTask.isBlocked !== undefined ? (newTask.isBlocked ? 1 : 0) : null,
|
|
697
|
+
newTask.blockedReason ?? null,
|
|
693
698
|
JSON.stringify(newTask.tags || []),
|
|
694
699
|
JSON.stringify(newTask.customFields || {}),
|
|
695
700
|
newTask.parentId || null,
|
|
@@ -716,6 +721,7 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
716
721
|
plannedStartDate = ?, actualStartDate = ?, actualEndDate = ?, dueDate = ?,
|
|
717
722
|
estimatedHours = ?, loggedHours = ?, actualHours = ?, billableHours = ?,
|
|
718
723
|
estimatedDurationMinutes = ?, actualDurationMinutes = ?, billableDurationMinutes = ?, progress = ?,
|
|
724
|
+
isBlocked = ?, blockedReason = ?,
|
|
719
725
|
tags = ?, customFields = ?, parentId = ?, updatedAt = ?
|
|
720
726
|
WHERE id = ?
|
|
721
727
|
`);
|
|
@@ -746,6 +752,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
746
752
|
updated.actualDurationMinutes ?? null,
|
|
747
753
|
updated.billableDurationMinutes ?? null,
|
|
748
754
|
updated.progress ?? null,
|
|
755
|
+
updated.isBlocked !== undefined ? (updated.isBlocked ? 1 : 0) : null,
|
|
756
|
+
updated.blockedReason ?? null,
|
|
749
757
|
JSON.stringify(updated.tags || []),
|
|
750
758
|
JSON.stringify(updated.customFields || {}),
|
|
751
759
|
updated.parentId || null,
|
|
@@ -1188,6 +1196,8 @@ export class SQLiteStore implements StorageAdapter {
|
|
|
1188
1196
|
private mapTask(row: any): Task {
|
|
1189
1197
|
return {
|
|
1190
1198
|
...row,
|
|
1199
|
+
isBlocked: row.isBlocked !== null && row.isBlocked !== undefined ? Boolean(row.isBlocked) : undefined,
|
|
1200
|
+
blockedReason: row.blockedReason || undefined,
|
|
1191
1201
|
taskType: row.taskType || undefined,
|
|
1192
1202
|
deliverableId: row.deliverableId || undefined,
|
|
1193
1203
|
tags: row.tags ? JSON.parse(row.tags) : [],
|
package/src/task-state.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { CriticalPathEngine } from './engine/index.js';
|
|
3
3
|
import { deriveTaskLifecycleState } from './utils/status.js';
|
|
4
|
-
import type { Task, StatusDefinition, TaskUnblockedEvent } from './index.js';
|
|
4
|
+
import type { Task, StatusDefinition, TaskBlockedEvent, TaskUnblockedEvent } from './index.js';
|
|
5
5
|
|
|
6
6
|
describe('Task State Behaviour & Dependency Validation', () => {
|
|
7
7
|
const baseTask: Task = {
|
|
@@ -443,5 +443,64 @@ describe('Task State Behaviour & Dependency Validation', () => {
|
|
|
443
443
|
expect(lifecycle?.isBlocked).toBe(false);
|
|
444
444
|
expect(lifecycle?.isReady).toBe(true);
|
|
445
445
|
});
|
|
446
|
+
|
|
447
|
+
it('manages first-class isBlocked and blockedReason independently of workflow status', async () => {
|
|
448
|
+
const engine = new CriticalPathEngine();
|
|
449
|
+
const project = await engine.createProject({ key: 'BLOCK', name: 'First Class Blocking' });
|
|
450
|
+
|
|
451
|
+
const blockedEvents: TaskBlockedEvent[] = [];
|
|
452
|
+
const unblockedEvents: TaskUnblockedEvent[] = [];
|
|
453
|
+
engine.events.subscribe<TaskBlockedEvent>('task.blocked', (evt) => {
|
|
454
|
+
blockedEvents.push(evt);
|
|
455
|
+
});
|
|
456
|
+
engine.events.subscribe<TaskUnblockedEvent>('task.unblocked', (evt) => {
|
|
457
|
+
unblockedEvents.push(evt);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// 1. Create a task in 'in_progress' status
|
|
461
|
+
const task = await engine.createTask({
|
|
462
|
+
projectId: project.id,
|
|
463
|
+
title: 'Work on feature',
|
|
464
|
+
status: 'in_progress'
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
let lifecycle = await engine.getTaskLifecycleState(task.id);
|
|
468
|
+
expect(lifecycle?.isBlocked).toBe(false);
|
|
469
|
+
|
|
470
|
+
// 2. Explicitly block the task while keeping status in_progress
|
|
471
|
+
const blockedTask = await engine.updateTask(task.id, {
|
|
472
|
+
isBlocked: true,
|
|
473
|
+
blockedReason: 'Awaiting third-party API key'
|
|
474
|
+
});
|
|
475
|
+
expect(blockedTask?.isBlocked).toBe(true);
|
|
476
|
+
expect(blockedTask?.blockedReason).toBe('Awaiting third-party API key');
|
|
477
|
+
expect(blockedTask?.status).toBe('in_progress');
|
|
478
|
+
|
|
479
|
+
// Verify domain event
|
|
480
|
+
expect(blockedEvents).toHaveLength(1);
|
|
481
|
+
expect(blockedEvents[0].aggregateId).toBe(task.id);
|
|
482
|
+
expect(blockedEvents[0].payload.reason).toBe('Awaiting third-party API key');
|
|
483
|
+
|
|
484
|
+
// Verify lifecycle state
|
|
485
|
+
lifecycle = await engine.getTaskLifecycleState(task.id);
|
|
486
|
+
expect(lifecycle?.isBlocked).toBe(true);
|
|
487
|
+
expect(lifecycle?.isReady).toBe(false);
|
|
488
|
+
|
|
489
|
+
// 3. Unblock the task
|
|
490
|
+
const unblockedTask = await engine.updateTask(task.id, {
|
|
491
|
+
isBlocked: false,
|
|
492
|
+
blockedReason: null
|
|
493
|
+
});
|
|
494
|
+
expect(unblockedTask?.isBlocked).toBe(false);
|
|
495
|
+
expect(unblockedTask?.blockedReason).toBeNull();
|
|
496
|
+
expect(unblockedTask?.status).toBe('in_progress');
|
|
497
|
+
|
|
498
|
+
// Verify domain event
|
|
499
|
+
expect(unblockedEvents).toHaveLength(1);
|
|
500
|
+
expect(unblockedEvents[0].aggregateId).toBe(task.id);
|
|
501
|
+
|
|
502
|
+
lifecycle = await engine.getTaskLifecycleState(task.id);
|
|
503
|
+
expect(lifecycle?.isBlocked).toBe(false);
|
|
504
|
+
});
|
|
446
505
|
});
|
|
447
506
|
});
|
package/src/types/index.ts
CHANGED
|
@@ -33,6 +33,32 @@ export type TaskLifecycleState = TaskDerivedStatus;
|
|
|
33
33
|
|
|
34
34
|
export type Role = 'admin' | 'project_manager' | 'contributor' | 'viewer';
|
|
35
35
|
|
|
36
|
+
export interface WorkingHoursRange {
|
|
37
|
+
start: string; // "09:00" (HH:MM 24-hour format)
|
|
38
|
+
end: string; // "17:00"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface DaySchedule {
|
|
42
|
+
dayOfWeek: number; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
|
43
|
+
isWorkingDay: boolean;
|
|
44
|
+
hours?: WorkingHoursRange[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface Holiday {
|
|
48
|
+
date: string; // "YYYY-MM-DD"
|
|
49
|
+
name?: string;
|
|
50
|
+
halfDay?: boolean; // if true, counts as 50% working hours
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface WorkSchedule {
|
|
54
|
+
id?: string;
|
|
55
|
+
name?: string;
|
|
56
|
+
timezone?: string; // Informational (e.g. "UTC", "America/New_York")
|
|
57
|
+
defaultHoursPerDay?: number; // Default: 8
|
|
58
|
+
days: DaySchedule[];
|
|
59
|
+
holidays?: Holiday[];
|
|
60
|
+
}
|
|
61
|
+
|
|
36
62
|
export interface User {
|
|
37
63
|
id: string;
|
|
38
64
|
name: string;
|
|
@@ -40,6 +66,7 @@ export interface User {
|
|
|
40
66
|
avatarUrl?: string;
|
|
41
67
|
role: Role;
|
|
42
68
|
weeklyCapacityHours?: number;
|
|
69
|
+
schedule?: WorkSchedule;
|
|
43
70
|
createdAt: string;
|
|
44
71
|
}
|
|
45
72
|
|
|
@@ -50,6 +77,7 @@ export interface Team {
|
|
|
50
77
|
leaderId?: string;
|
|
51
78
|
memberIds: string[];
|
|
52
79
|
weeklyCapacityHours?: number;
|
|
80
|
+
schedule?: WorkSchedule;
|
|
53
81
|
createdAt: string;
|
|
54
82
|
updatedAt: string;
|
|
55
83
|
}
|
|
@@ -107,6 +135,9 @@ export interface Project {
|
|
|
107
135
|
statusDefinitions?: StatusDefinition[];
|
|
108
136
|
priorityDefinitions?: Array<{ key: string; label: string; level?: number }>;
|
|
109
137
|
customFieldDefinitions?: CustomFieldDefinition[];
|
|
138
|
+
schedule?: WorkSchedule;
|
|
139
|
+
startDate?: string;
|
|
140
|
+
targetEndDate?: string;
|
|
110
141
|
createdAt: string;
|
|
111
142
|
updatedAt: string;
|
|
112
143
|
}
|
|
@@ -185,6 +216,8 @@ export interface Task {
|
|
|
185
216
|
billableDurationMinutes?: number;
|
|
186
217
|
// Progress (0 to 100 percentage)
|
|
187
218
|
progress?: number;
|
|
219
|
+
isBlocked?: boolean;
|
|
220
|
+
blockedReason?: string | null;
|
|
188
221
|
tags?: string[];
|
|
189
222
|
todos?: TaskTodoItem[];
|
|
190
223
|
customFields?: Record<string, unknown>;
|
|
@@ -371,6 +404,7 @@ export type WebhookEvent =
|
|
|
371
404
|
| 'task.updated'
|
|
372
405
|
| 'task.deleted'
|
|
373
406
|
| 'task.status_changed'
|
|
407
|
+
| 'task.blocked'
|
|
374
408
|
| 'task.unblocked'
|
|
375
409
|
| 'comment.created'
|
|
376
410
|
| 'comment.updated'
|
|
@@ -415,6 +449,7 @@ export interface CriticalPathConfig {
|
|
|
415
449
|
fileStorage?: FileStorageAdapter;
|
|
416
450
|
plugins?: CriticalPathPlugin[];
|
|
417
451
|
webhooks?: Omit<Webhook, 'id' | 'createdAt'>[];
|
|
452
|
+
defaultSchedule?: WorkSchedule;
|
|
418
453
|
initialData?: {
|
|
419
454
|
projects?: Project[];
|
|
420
455
|
tasks?: Task[];
|
|
@@ -483,12 +518,21 @@ export interface TaskCriticalPathSchedule {
|
|
|
483
518
|
lateFinish: number;
|
|
484
519
|
totalSlack: number;
|
|
485
520
|
isCritical: boolean;
|
|
521
|
+
durationHours?: number;
|
|
522
|
+
earlyStartDate?: string;
|
|
523
|
+
earlyFinishDate?: string;
|
|
524
|
+
lateStartDate?: string;
|
|
525
|
+
lateFinishDate?: string;
|
|
526
|
+
slackWorkingHours?: number;
|
|
486
527
|
}
|
|
487
528
|
|
|
488
529
|
export interface CriticalPathAnalysis {
|
|
489
530
|
projectId: string;
|
|
490
531
|
calculatedAt: string;
|
|
491
532
|
totalDurationHours: number;
|
|
533
|
+
totalWorkingHours?: number;
|
|
534
|
+
projectStartDate?: string;
|
|
535
|
+
projectEndDate?: string;
|
|
492
536
|
criticalTaskIds: string[];
|
|
493
537
|
tasks: TaskCriticalPathSchedule[];
|
|
494
538
|
}
|
|
@@ -523,6 +567,7 @@ export interface RealityDelta {
|
|
|
523
567
|
effortVarianceHours?: number; // loggedHours - estimatedHours (effort variance)
|
|
524
568
|
durationVarianceHours?: number; // actual duration hours - planned duration hours
|
|
525
569
|
scheduleVarianceDays?: number; // days difference between planned/due vs actual
|
|
570
|
+
scheduleVarianceWorkingDays?: number; // working days difference between planned/due vs actual
|
|
526
571
|
accuracyRatio?: number; // loggedHours / estimatedHours (estimation accuracy ratio)
|
|
527
572
|
isOverdue: boolean;
|
|
528
573
|
isOverEstimate: boolean;
|
|
@@ -669,5 +714,8 @@ export interface WorkloadDistributionOptions {
|
|
|
669
714
|
metric?: WorkloadMetric; // default: 'blended'
|
|
670
715
|
defaultWeeklyCapacityHours?: number; // default: 40
|
|
671
716
|
capacityOverrides?: Record<string, number>; // e.g. { [assigneeOrTeamId]: weeklyCapacityHours }
|
|
717
|
+
schedule?: WorkSchedule;
|
|
718
|
+
userSchedules?: Record<string, WorkSchedule>;
|
|
719
|
+
teamSchedules?: Record<string, WorkSchedule>;
|
|
672
720
|
}
|
|
673
721
|
|
package/src/utils/status.ts
CHANGED
|
@@ -88,8 +88,13 @@ export function deriveTaskLifecycleState(
|
|
|
88
88
|
return upstreamDef.category !== 'completed';
|
|
89
89
|
});
|
|
90
90
|
const blockingTaskIds = blockingTasks.map((t) => t.id);
|
|
91
|
-
const
|
|
92
|
-
|
|
91
|
+
const isExplicitlyBlocked = Boolean(
|
|
92
|
+
task.isBlocked === true ||
|
|
93
|
+
task.customFields?.isBlocked === true ||
|
|
94
|
+
task.status === 'blocked'
|
|
95
|
+
);
|
|
96
|
+
const isBlocked = !isDone && (blockingTaskIds.length > 0 || isExplicitlyBlocked);
|
|
97
|
+
const isReady = semanticStatus === 'not_started' && !isBlocked;
|
|
93
98
|
|
|
94
99
|
// Time & Schedule Indicators
|
|
95
100
|
let isOverdue = false;
|
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/cpm.test.ts","./src/domain/cpm.ts","./src/domain/custom-fields.ts","./src/domain/ddd.test.ts","./src/domain/entities.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/workload.test.ts","./src/domain/workload.ts","./src/engine/index.ts","./src/plugins/index.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/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"],"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/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/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/workload.test.ts","./src/domain/workload.ts","./src/engine/index.ts","./src/plugins/index.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/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"],"version":"5.9.3"}
|