@critical-path/core 0.35.0 → 0.36.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/README.md +11 -0
- package/dist/engine/index.d.ts +2 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +25 -2
- package/dist/engine/index.js.map +1 -1
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +5 -1
- package/CHANGELOG.md +0 -584
- package/dist/deliverables.test.d.ts +0 -2
- package/dist/deliverables.test.d.ts.map +0 -1
- package/dist/deliverables.test.js +0 -232
- package/dist/deliverables.test.js.map +0 -1
- package/dist/domain/calendar.test.d.ts +0 -2
- package/dist/domain/calendar.test.d.ts.map +0 -1
- package/dist/domain/calendar.test.js +0 -181
- package/dist/domain/calendar.test.js.map +0 -1
- package/dist/domain/cpm.test.d.ts +0 -2
- package/dist/domain/cpm.test.d.ts.map +0 -1
- package/dist/domain/cpm.test.js +0 -166
- package/dist/domain/cpm.test.js.map +0 -1
- package/dist/domain/ddd.test.d.ts +0 -2
- package/dist/domain/ddd.test.d.ts.map +0 -1
- package/dist/domain/ddd.test.js +0 -349
- package/dist/domain/ddd.test.js.map +0 -1
- package/dist/domain/ladder.test.d.ts +0 -2
- package/dist/domain/ladder.test.d.ts.map +0 -1
- package/dist/domain/ladder.test.js +0 -213
- package/dist/domain/ladder.test.js.map +0 -1
- package/dist/domain/metrics.test.d.ts +0 -2
- package/dist/domain/metrics.test.d.ts.map +0 -1
- package/dist/domain/metrics.test.js +0 -252
- package/dist/domain/metrics.test.js.map +0 -1
- package/dist/domain/task-duration.test.d.ts +0 -2
- package/dist/domain/task-duration.test.d.ts.map +0 -1
- package/dist/domain/task-duration.test.js +0 -307
- package/dist/domain/task-duration.test.js.map +0 -1
- package/dist/domain/workload.test.d.ts +0 -2
- package/dist/domain/workload.test.d.ts.map +0 -1
- package/dist/domain/workload.test.js +0 -261
- package/dist/domain/workload.test.js.map +0 -1
- package/dist/engine/actor.test.d.ts +0 -2
- package/dist/engine/actor.test.d.ts.map +0 -1
- package/dist/engine/actor.test.js +0 -54
- package/dist/engine/actor.test.js.map +0 -1
- package/dist/engine/authorization.test.d.ts +0 -2
- package/dist/engine/authorization.test.d.ts.map +0 -1
- package/dist/engine/authorization.test.js +0 -154
- package/dist/engine/authorization.test.js.map +0 -1
- package/dist/engine/cascade.test.d.ts +0 -2
- package/dist/engine/cascade.test.d.ts.map +0 -1
- package/dist/engine/cascade.test.js +0 -99
- package/dist/engine/cascade.test.js.map +0 -1
- package/dist/engine/config.test.d.ts +0 -2
- package/dist/engine/config.test.d.ts.map +0 -1
- package/dist/engine/config.test.js +0 -46
- package/dist/engine/config.test.js.map +0 -1
- package/dist/engine/entity-events.test.d.ts +0 -2
- package/dist/engine/entity-events.test.d.ts.map +0 -1
- package/dist/engine/entity-events.test.js +0 -61
- package/dist/engine/entity-events.test.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -429
- package/dist/index.test.js.map +0 -1
- package/dist/plugins/plugins.test.d.ts +0 -2
- package/dist/plugins/plugins.test.d.ts.map +0 -1
- package/dist/plugins/plugins.test.js +0 -137
- package/dist/plugins/plugins.test.js.map +0 -1
- package/dist/schemas/schemas.test.d.ts +0 -2
- package/dist/schemas/schemas.test.d.ts.map +0 -1
- package/dist/schemas/schemas.test.js +0 -58
- package/dist/schemas/schemas.test.js.map +0 -1
- package/dist/status.test.d.ts +0 -2
- package/dist/status.test.d.ts.map +0 -1
- package/dist/status.test.js +0 -295
- package/dist/status.test.js.map +0 -1
- package/dist/storage/storage.test.d.ts +0 -2
- package/dist/storage/storage.test.d.ts.map +0 -1
- package/dist/storage/storage.test.js +0 -236
- package/dist/storage/storage.test.js.map +0 -1
- package/dist/store/conformance.test.d.ts +0 -2
- package/dist/store/conformance.test.d.ts.map +0 -1
- package/dist/store/conformance.test.js +0 -15
- package/dist/store/conformance.test.js.map +0 -1
- package/dist/store/firebase.test.d.ts +0 -2
- package/dist/store/firebase.test.d.ts.map +0 -1
- package/dist/store/firebase.test.js +0 -103
- package/dist/store/firebase.test.js.map +0 -1
- package/dist/store/query.test.d.ts +0 -2
- package/dist/store/query.test.d.ts.map +0 -1
- package/dist/store/query.test.js +0 -89
- package/dist/store/query.test.js.map +0 -1
- package/dist/store/sqlite.test.d.ts +0 -2
- package/dist/store/sqlite.test.d.ts.map +0 -1
- package/dist/store/sqlite.test.js +0 -177
- package/dist/store/sqlite.test.js.map +0 -1
- package/dist/task-state.test.d.ts +0 -2
- package/dist/task-state.test.d.ts.map +0 -1
- package/dist/task-state.test.js +0 -423
- package/dist/task-state.test.js.map +0 -1
- package/dist/use-case-validation.test.d.ts +0 -2
- package/dist/use-case-validation.test.d.ts.map +0 -1
- package/dist/use-case-validation.test.js +0 -281
- package/dist/use-case-validation.test.js.map +0 -1
- package/dist/utils/fractional-index.test.d.ts +0 -2
- package/dist/utils/fractional-index.test.d.ts.map +0 -1
- package/dist/utils/fractional-index.test.js +0 -182
- package/dist/utils/fractional-index.test.js.map +0 -1
- package/dist/utils/key.test.d.ts +0 -2
- package/dist/utils/key.test.d.ts.map +0 -1
- package/dist/utils/key.test.js +0 -65
- package/dist/utils/key.test.js.map +0 -1
- package/dist/utils/mentions.test.d.ts +0 -2
- package/dist/utils/mentions.test.d.ts.map +0 -1
- package/dist/utils/mentions.test.js +0 -114
- package/dist/utils/mentions.test.js.map +0 -1
- package/dist/webhooks/webhooks.test.d.ts +0 -2
- package/dist/webhooks/webhooks.test.d.ts.map +0 -1
- package/dist/webhooks/webhooks.test.js +0 -154
- package/dist/webhooks/webhooks.test.js.map +0 -1
- package/src/deliverables.test.ts +0 -284
- package/src/domain/authorization.ts +0 -82
- package/src/domain/calendar.test.ts +0 -216
- package/src/domain/calendar.ts +0 -502
- package/src/domain/cpm.test.ts +0 -189
- package/src/domain/cpm.ts +0 -258
- package/src/domain/custom-fields.ts +0 -172
- package/src/domain/ddd.test.ts +0 -442
- package/src/domain/entities.ts +0 -798
- package/src/domain/errors.ts +0 -38
- package/src/domain/events.ts +0 -369
- package/src/domain/graph.ts +0 -70
- package/src/domain/index.ts +0 -12
- package/src/domain/ladder.test.ts +0 -251
- package/src/domain/ladder.ts +0 -474
- package/src/domain/metrics.test.ts +0 -288
- package/src/domain/metrics.ts +0 -497
- package/src/domain/task-duration.test.ts +0 -354
- package/src/domain/workload.test.ts +0 -311
- package/src/domain/workload.ts +0 -457
- package/src/engine/actor.test.ts +0 -63
- package/src/engine/authorization.test.ts +0 -199
- package/src/engine/cascade.test.ts +0 -121
- package/src/engine/config.test.ts +0 -51
- package/src/engine/entity-events.test.ts +0 -67
- package/src/engine/index.ts +0 -2472
- package/src/index.test.ts +0 -514
- package/src/index.ts +0 -9
- package/src/plugins/index.ts +0 -103
- package/src/plugins/plugins.test.ts +0 -161
- package/src/schemas/index.ts +0 -402
- package/src/schemas/schemas.test.ts +0 -116
- package/src/status.test.ts +0 -354
- package/src/storage/file-storage.ts +0 -200
- package/src/storage/firebase-storage.ts +0 -209
- package/src/storage/index.ts +0 -3
- package/src/storage/s3.ts +0 -151
- package/src/storage/storage.test.ts +0 -274
- package/src/store/conformance.test.ts +0 -15
- package/src/store/firebase.test.ts +0 -131
- package/src/store/firebase.ts +0 -658
- package/src/store/index.ts +0 -623
- package/src/store/query.test.ts +0 -110
- package/src/store/query.ts +0 -113
- package/src/store/sqlite.test.ts +0 -218
- package/src/store/sqlite.ts +0 -1480
- package/src/task-state.test.ts +0 -506
- package/src/testing/conformance.ts +0 -319
- package/src/testing/index.ts +0 -1
- package/src/types/index.ts +0 -859
- package/src/use-case-validation.test.ts +0 -324
- package/src/utils/fractional-index.test.ts +0 -228
- package/src/utils/fractional-index.ts +0 -254
- package/src/utils/index.ts +0 -7
- package/src/utils/key.test.ts +0 -76
- package/src/utils/key.ts +0 -62
- package/src/utils/mentions.test.ts +0 -132
- package/src/utils/mentions.ts +0 -131
- package/src/utils/status.ts +0 -419
- package/src/utils/workflow.ts +0 -306
- package/src/webhooks/dispatcher.ts +0 -190
- package/src/webhooks/index.ts +0 -2
- package/src/webhooks/signature.ts +0 -57
- package/src/webhooks/webhooks.test.ts +0 -201
- package/tsconfig.json +0 -8
- package/tsconfig.tsbuildinfo +0 -1
package/src/store/index.ts
DELETED
|
@@ -1,623 +0,0 @@
|
|
|
1
|
-
export * from './sqlite.js';
|
|
2
|
-
export * from './firebase.js';
|
|
3
|
-
|
|
4
|
-
import type {
|
|
5
|
-
Project,
|
|
6
|
-
Task,
|
|
7
|
-
Iteration,
|
|
8
|
-
Team,
|
|
9
|
-
TaskContainer,
|
|
10
|
-
Comment,
|
|
11
|
-
Attachment,
|
|
12
|
-
TimeEntry,
|
|
13
|
-
Activity,
|
|
14
|
-
Webhook,
|
|
15
|
-
TaskDependency,
|
|
16
|
-
Workflow,
|
|
17
|
-
Deliverable,
|
|
18
|
-
CreateDeliverableInput
|
|
19
|
-
} from '../types/index.js';
|
|
20
|
-
import { generateProjectKey } from '../utils/key.js';
|
|
21
|
-
import {
|
|
22
|
-
matchesActivityQuery,
|
|
23
|
-
matchesTaskQuery,
|
|
24
|
-
paginate,
|
|
25
|
-
type ActivityQuery,
|
|
26
|
-
type Page,
|
|
27
|
-
type TaskQuery
|
|
28
|
-
} from './query.js';
|
|
29
|
-
|
|
30
|
-
export * from './query.js';
|
|
31
|
-
|
|
32
|
-
export interface ProjectRepository {
|
|
33
|
-
getProjects(): Promise<Project[]>;
|
|
34
|
-
getProject(id: string): Promise<Project | null>;
|
|
35
|
-
createProject(project: Omit<Project, 'id' | 'createdAt' | 'updatedAt'>): Promise<Project>;
|
|
36
|
-
updateProject(id: string, updates: Partial<Project>): Promise<Project | null>;
|
|
37
|
-
deleteProject(id: string): Promise<boolean>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface WorkflowRepository {
|
|
41
|
-
getWorkflows(): Promise<Workflow[]>;
|
|
42
|
-
getWorkflow(id: string): Promise<Workflow | null>;
|
|
43
|
-
createWorkflow(workflow: Omit<Workflow, 'id' | 'createdAt' | 'updatedAt'>): Promise<Workflow>;
|
|
44
|
-
updateWorkflow(id: string, updates: Partial<Workflow>): Promise<Workflow | null>;
|
|
45
|
-
deleteWorkflow(id: string): Promise<boolean>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface TaskRepository {
|
|
49
|
-
getTasks(projectId?: string): Promise<Task[]>;
|
|
50
|
-
/** Filtered, paginated tasks ordered by `(createdAt, id)` ascending. */
|
|
51
|
-
queryTasks(query: TaskQuery): Promise<Page<Task>>;
|
|
52
|
-
getTask(id: string): Promise<Task | null>;
|
|
53
|
-
createTask(task: Omit<Task, 'id' | 'createdAt' | 'updatedAt'>): Promise<Task>;
|
|
54
|
-
updateTask(id: string, updates: Partial<Task>): Promise<Task | null>;
|
|
55
|
-
deleteTask(id: string): Promise<boolean>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface TeamRepository {
|
|
59
|
-
getTeams(): Promise<Team[]>;
|
|
60
|
-
getTeam(id: string): Promise<Team | null>;
|
|
61
|
-
createTeam(team: Omit<Team, 'id' | 'createdAt' | 'updatedAt'>): Promise<Team>;
|
|
62
|
-
updateTeam(id: string, updates: Partial<Team>): Promise<Team | null>;
|
|
63
|
-
deleteTeam(id: string): Promise<boolean>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface ContainerRepository {
|
|
67
|
-
getContainers(projectId: string): Promise<TaskContainer[]>;
|
|
68
|
-
getContainer(id: string): Promise<TaskContainer | null>;
|
|
69
|
-
createContainer(container: Omit<TaskContainer, 'id' | 'createdAt' | 'updatedAt'>): Promise<TaskContainer>;
|
|
70
|
-
updateContainer(id: string, updates: Partial<TaskContainer>): Promise<TaskContainer | null>;
|
|
71
|
-
deleteContainer(id: string): Promise<boolean>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface IterationRepository {
|
|
75
|
-
getIterations(projectId: string): Promise<Iteration[]>;
|
|
76
|
-
getIteration(id: string): Promise<Iteration | null>;
|
|
77
|
-
createIteration(iteration: Omit<Iteration, 'id' | 'createdAt'>): Promise<Iteration>;
|
|
78
|
-
updateIteration(id: string, updates: Partial<Iteration>): Promise<Iteration | null>;
|
|
79
|
-
deleteIteration(id: string): Promise<boolean>;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface CommentRepository {
|
|
83
|
-
getComments(taskId: string): Promise<Comment[]>;
|
|
84
|
-
getComment(id: string): Promise<Comment | null>;
|
|
85
|
-
addComment(comment: Omit<Comment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Comment>;
|
|
86
|
-
updateComment(id: string, updates: Partial<Comment>): Promise<Comment | null>;
|
|
87
|
-
deleteComment(id: string): Promise<boolean>;
|
|
88
|
-
addReaction?(commentId: string, reaction: { emoji: string; userId: string }): Promise<Comment | null>;
|
|
89
|
-
removeReaction?(commentId: string, reaction: { emoji: string; userId: string }): Promise<Comment | null>;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface AttachmentRepository {
|
|
93
|
-
getAttachments(filter?: { taskId?: string; projectId?: string; commentId?: string }): Promise<Attachment[]>;
|
|
94
|
-
getAttachment(id: string): Promise<Attachment | null>;
|
|
95
|
-
createAttachment(attachment: Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Attachment>;
|
|
96
|
-
deleteAttachment(id: string): Promise<boolean>;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface ActivityRepository {
|
|
100
|
-
getActivities(filter?: { projectId?: string; taskId?: string }): Promise<Activity[]>;
|
|
101
|
-
/** Paginated activity feed ordered by `(createdAt, id)` descending (newest first). */
|
|
102
|
-
queryActivities(query: ActivityQuery): Promise<Page<Activity>>;
|
|
103
|
-
logActivity(activity: Omit<Activity, 'id' | 'createdAt'>): Promise<Activity>;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface TimeEntryRepository {
|
|
107
|
-
getTimeEntries(taskId: string): Promise<TimeEntry[]>;
|
|
108
|
-
logTime(entry: Omit<TimeEntry, 'id' | 'loggedAt'> & { loggedAt?: string }): Promise<TimeEntry>;
|
|
109
|
-
deleteTimeEntry(id: string): Promise<boolean>;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface DependencyRepository {
|
|
113
|
-
/** Dependencies where `taskId` is either the dependent or the upstream task. */
|
|
114
|
-
getDependencies(taskId: string): Promise<TaskDependency[]>;
|
|
115
|
-
getDependency(id: string): Promise<TaskDependency | null>;
|
|
116
|
-
addDependency(dep: Omit<TaskDependency, 'id'>): Promise<TaskDependency>;
|
|
117
|
-
removeDependency(id: string): Promise<boolean>;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export interface WebhookRepository {
|
|
121
|
-
getWebhooks(): Promise<Webhook[]>;
|
|
122
|
-
getWebhook(id: string): Promise<Webhook | null>;
|
|
123
|
-
addWebhook(webhook: Omit<Webhook, 'id' | 'createdAt'>): Promise<Webhook>;
|
|
124
|
-
updateWebhook(id: string, updates: Partial<Omit<Webhook, 'id' | 'createdAt'>>): Promise<Webhook | null>;
|
|
125
|
-
deleteWebhook(id: string): Promise<boolean>;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export interface DeliverableRepository {
|
|
129
|
-
getDeliverables(projectId: string): Promise<Deliverable[]>;
|
|
130
|
-
getDeliverable(id: string): Promise<Deliverable | null>;
|
|
131
|
-
createDeliverable(deliverable: CreateDeliverableInput): Promise<Deliverable>;
|
|
132
|
-
updateDeliverable(id: string, updates: Partial<Deliverable>): Promise<Deliverable | null>;
|
|
133
|
-
deleteDeliverable(id: string): Promise<boolean>;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface StorageAdapter
|
|
137
|
-
extends ProjectRepository,
|
|
138
|
-
WorkflowRepository,
|
|
139
|
-
TaskRepository,
|
|
140
|
-
TeamRepository,
|
|
141
|
-
ContainerRepository,
|
|
142
|
-
DeliverableRepository,
|
|
143
|
-
IterationRepository,
|
|
144
|
-
CommentRepository,
|
|
145
|
-
AttachmentRepository,
|
|
146
|
-
ActivityRepository,
|
|
147
|
-
TimeEntryRepository,
|
|
148
|
-
DependencyRepository,
|
|
149
|
-
WebhookRepository {}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Map-backed store for development and tests. Reads and writes are deep-copied, so it behaves
|
|
153
|
-
* like a database: returned records can be mutated freely without affecting stored state.
|
|
154
|
-
*/
|
|
155
|
-
export class InMemoryStore implements StorageAdapter {
|
|
156
|
-
private projects = new Map<string, Project>();
|
|
157
|
-
private workflows = new Map<string, Workflow>();
|
|
158
|
-
private tasks = new Map<string, Task>();
|
|
159
|
-
private teams = new Map<string, Team>();
|
|
160
|
-
private containers = new Map<string, TaskContainer>();
|
|
161
|
-
private deliverables = new Map<string, Deliverable>();
|
|
162
|
-
private iterations = new Map<string, Iteration>();
|
|
163
|
-
private comments = new Map<string, Comment>();
|
|
164
|
-
private attachments = new Map<string, Attachment>();
|
|
165
|
-
private activities: Activity[] = [];
|
|
166
|
-
private timeEntries = new Map<string, TimeEntry>();
|
|
167
|
-
private dependencies = new Map<string, TaskDependency>();
|
|
168
|
-
private webhooks = new Map<string, Webhook>();
|
|
169
|
-
|
|
170
|
-
constructor() {
|
|
171
|
-
// Hand out copies: callers mutating a returned record (or an input they keep using) must not
|
|
172
|
-
// change what is stored, matching the database-backed adapters. Internal calls between
|
|
173
|
-
// methods use the unwrapped instance, so each call clones only at the boundary.
|
|
174
|
-
return new Proxy(this, {
|
|
175
|
-
get(target, property, receiver) {
|
|
176
|
-
const value = Reflect.get(target, property, receiver);
|
|
177
|
-
if (typeof value !== 'function' || property === 'constructor') return value;
|
|
178
|
-
return async (...args: unknown[]) => structuredClone(await value.apply(target, structuredClone(args)));
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async getProjects(): Promise<Project[]> {
|
|
184
|
-
return Array.from(this.projects.values());
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async getProject(id: string): Promise<Project | null> {
|
|
188
|
-
return this.projects.get(id) || null;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async createProject(project: Omit<Project, 'id' | 'createdAt' | 'updatedAt'>): Promise<Project> {
|
|
192
|
-
const id = `proj_${crypto.randomUUID()}`;
|
|
193
|
-
const now = new Date().toISOString();
|
|
194
|
-
const key = project.key || generateProjectKey(project.name);
|
|
195
|
-
const newProject: Project = {
|
|
196
|
-
...project,
|
|
197
|
-
key,
|
|
198
|
-
id,
|
|
199
|
-
createdAt: now,
|
|
200
|
-
updatedAt: now
|
|
201
|
-
};
|
|
202
|
-
this.projects.set(id, newProject);
|
|
203
|
-
return newProject;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async updateProject(id: string, updates: Partial<Project>): Promise<Project | null> {
|
|
207
|
-
const existing = this.projects.get(id);
|
|
208
|
-
if (!existing) return null;
|
|
209
|
-
const updated: Project = {
|
|
210
|
-
...existing,
|
|
211
|
-
...updates,
|
|
212
|
-
updatedAt: new Date().toISOString()
|
|
213
|
-
};
|
|
214
|
-
this.projects.set(id, updated);
|
|
215
|
-
return updated;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
async deleteProject(id: string): Promise<boolean> {
|
|
219
|
-
return this.projects.delete(id);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Workflows
|
|
223
|
-
async getWorkflows(): Promise<Workflow[]> {
|
|
224
|
-
return Array.from(this.workflows.values());
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async getWorkflow(id: string): Promise<Workflow | null> {
|
|
228
|
-
return this.workflows.get(id) || null;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async createWorkflow(workflow: Omit<Workflow, 'id' | 'createdAt' | 'updatedAt'>): Promise<Workflow> {
|
|
232
|
-
const id = `wf_${crypto.randomUUID()}`;
|
|
233
|
-
const now = new Date().toISOString();
|
|
234
|
-
const newWorkflow: Workflow = {
|
|
235
|
-
...workflow,
|
|
236
|
-
id,
|
|
237
|
-
createdAt: now,
|
|
238
|
-
updatedAt: now
|
|
239
|
-
};
|
|
240
|
-
this.workflows.set(id, newWorkflow);
|
|
241
|
-
return newWorkflow;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async updateWorkflow(id: string, updates: Partial<Workflow>): Promise<Workflow | null> {
|
|
245
|
-
const existing = this.workflows.get(id);
|
|
246
|
-
if (!existing) return null;
|
|
247
|
-
const updated: Workflow = {
|
|
248
|
-
...existing,
|
|
249
|
-
...updates,
|
|
250
|
-
updatedAt: new Date().toISOString()
|
|
251
|
-
};
|
|
252
|
-
this.workflows.set(id, updated);
|
|
253
|
-
return updated;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async deleteWorkflow(id: string): Promise<boolean> {
|
|
257
|
-
return this.workflows.delete(id);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
async getTasks(projectId?: string): Promise<Task[]> {
|
|
261
|
-
const all = Array.from(this.tasks.values());
|
|
262
|
-
if (projectId) {
|
|
263
|
-
return all.filter((t) => t.projectId === projectId);
|
|
264
|
-
}
|
|
265
|
-
return all;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
async queryTasks(query: TaskQuery): Promise<Page<Task>> {
|
|
269
|
-
const tasks = Array.from(this.tasks.values()).filter((t) => matchesTaskQuery(t, query));
|
|
270
|
-
return paginate(tasks, (t) => t.createdAt, 'asc', query.limit, query.cursor);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
async getTask(id: string): Promise<Task | null> {
|
|
274
|
-
return this.tasks.get(id) || null;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async createTask(task: Omit<Task, 'id' | 'createdAt' | 'updatedAt'>): Promise<Task> {
|
|
278
|
-
const id = `task_${crypto.randomUUID()}`;
|
|
279
|
-
const now = new Date().toISOString();
|
|
280
|
-
const newTask: Task = {
|
|
281
|
-
...task,
|
|
282
|
-
id,
|
|
283
|
-
createdAt: now,
|
|
284
|
-
updatedAt: now
|
|
285
|
-
};
|
|
286
|
-
this.tasks.set(id, newTask);
|
|
287
|
-
return newTask;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
async updateTask(id: string, updates: Partial<Task>): Promise<Task | null> {
|
|
291
|
-
const existing = this.tasks.get(id);
|
|
292
|
-
if (!existing) return null;
|
|
293
|
-
const updated: Task = {
|
|
294
|
-
...existing,
|
|
295
|
-
...updates,
|
|
296
|
-
updatedAt: new Date().toISOString()
|
|
297
|
-
};
|
|
298
|
-
this.tasks.set(id, updated);
|
|
299
|
-
return updated;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
async deleteTask(id: string): Promise<boolean> {
|
|
303
|
-
return this.tasks.delete(id);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Teams
|
|
307
|
-
async getTeams(): Promise<Team[]> {
|
|
308
|
-
return Array.from(this.teams.values());
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async getTeam(id: string): Promise<Team | null> {
|
|
312
|
-
return this.teams.get(id) || null;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
async createTeam(team: Omit<Team, 'id' | 'createdAt' | 'updatedAt'>): Promise<Team> {
|
|
316
|
-
const id = `team_${crypto.randomUUID()}`;
|
|
317
|
-
const now = new Date().toISOString();
|
|
318
|
-
const newTeam: Team = { ...team, id, createdAt: now, updatedAt: now };
|
|
319
|
-
this.teams.set(id, newTeam);
|
|
320
|
-
return newTeam;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
async updateTeam(id: string, updates: Partial<Team>): Promise<Team | null> {
|
|
324
|
-
const existing = this.teams.get(id);
|
|
325
|
-
if (!existing) return null;
|
|
326
|
-
const updated: Team = { ...existing, ...updates, updatedAt: new Date().toISOString() };
|
|
327
|
-
this.teams.set(id, updated);
|
|
328
|
-
return updated;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async deleteTeam(id: string): Promise<boolean> {
|
|
332
|
-
return this.teams.delete(id);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Containers
|
|
336
|
-
async getContainers(projectId: string): Promise<TaskContainer[]> {
|
|
337
|
-
return Array.from(this.containers.values()).filter((c) => c.projectId === projectId);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
async getContainer(id: string): Promise<TaskContainer | null> {
|
|
341
|
-
return this.containers.get(id) || null;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
async createContainer(container: Omit<TaskContainer, 'id' | 'createdAt' | 'updatedAt'>): Promise<TaskContainer> {
|
|
345
|
-
const id = `cnt_${crypto.randomUUID()}`;
|
|
346
|
-
const now = new Date().toISOString();
|
|
347
|
-
const newContainer: TaskContainer = { ...container, id, createdAt: now, updatedAt: now };
|
|
348
|
-
this.containers.set(id, newContainer);
|
|
349
|
-
return newContainer;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
async updateContainer(id: string, updates: Partial<TaskContainer>): Promise<TaskContainer | null> {
|
|
353
|
-
const existing = this.containers.get(id);
|
|
354
|
-
if (!existing) return null;
|
|
355
|
-
const updated: TaskContainer = { ...existing, ...updates, updatedAt: new Date().toISOString() };
|
|
356
|
-
this.containers.set(id, updated);
|
|
357
|
-
return updated;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
async deleteContainer(id: string): Promise<boolean> {
|
|
361
|
-
return this.containers.delete(id);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Deliverables
|
|
365
|
-
async getDeliverables(projectId: string): Promise<Deliverable[]> {
|
|
366
|
-
return Array.from(this.deliverables.values()).filter((d) => d.projectId === projectId);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
async getDeliverable(id: string): Promise<Deliverable | null> {
|
|
370
|
-
return this.deliverables.get(id) || null;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
async createDeliverable(deliverable: CreateDeliverableInput): Promise<Deliverable> {
|
|
374
|
-
const id = (deliverable as any).id || `deliv_${crypto.randomUUID()}`;
|
|
375
|
-
const now = new Date().toISOString();
|
|
376
|
-
const newDeliverable: Deliverable = {
|
|
377
|
-
...deliverable,
|
|
378
|
-
id,
|
|
379
|
-
status: deliverable.status || 'planned',
|
|
380
|
-
outputUrls: deliverable.outputUrls ? [...deliverable.outputUrls] : [],
|
|
381
|
-
customFields: deliverable.customFields ? { ...deliverable.customFields } : {},
|
|
382
|
-
createdAt: now,
|
|
383
|
-
updatedAt: now
|
|
384
|
-
};
|
|
385
|
-
this.deliverables.set(id, newDeliverable);
|
|
386
|
-
return newDeliverable;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
async updateDeliverable(id: string, updates: Partial<Deliverable>): Promise<Deliverable | null> {
|
|
390
|
-
const existing = this.deliverables.get(id);
|
|
391
|
-
if (!existing) return null;
|
|
392
|
-
const updated: Deliverable = {
|
|
393
|
-
...existing,
|
|
394
|
-
...updates,
|
|
395
|
-
updatedAt: new Date().toISOString()
|
|
396
|
-
};
|
|
397
|
-
this.deliverables.set(id, updated);
|
|
398
|
-
return updated;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
async deleteDeliverable(id: string): Promise<boolean> {
|
|
402
|
-
return this.deliverables.delete(id);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Iterations
|
|
406
|
-
async getIterations(projectId: string): Promise<Iteration[]> {
|
|
407
|
-
return Array.from(this.iterations.values()).filter((s) => s.projectId === projectId);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
async getIteration(id: string): Promise<Iteration | null> {
|
|
411
|
-
return this.iterations.get(id) || null;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async createIteration(iteration: Omit<Iteration, 'id' | 'createdAt'>): Promise<Iteration> {
|
|
415
|
-
const id = `iter_${crypto.randomUUID()}`;
|
|
416
|
-
const newIteration: Iteration = {
|
|
417
|
-
...iteration,
|
|
418
|
-
id,
|
|
419
|
-
createdAt: new Date().toISOString()
|
|
420
|
-
};
|
|
421
|
-
this.iterations.set(id, newIteration);
|
|
422
|
-
return newIteration;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
async updateIteration(id: string, updates: Partial<Iteration>): Promise<Iteration | null> {
|
|
426
|
-
const existing = this.iterations.get(id);
|
|
427
|
-
if (!existing) return null;
|
|
428
|
-
const updated: Iteration = { ...existing, ...updates };
|
|
429
|
-
this.iterations.set(id, updated);
|
|
430
|
-
return updated;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
async deleteIteration(id: string): Promise<boolean> {
|
|
434
|
-
return this.iterations.delete(id);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Comments
|
|
438
|
-
async getComments(taskId: string): Promise<Comment[]> {
|
|
439
|
-
return Array.from(this.comments.values()).filter((c) => c.taskId === taskId);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
async getComment(id: string): Promise<Comment | null> {
|
|
443
|
-
return this.comments.get(id) || null;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async addComment(comment: Omit<Comment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Comment> {
|
|
447
|
-
const id = `cmt_${crypto.randomUUID()}`;
|
|
448
|
-
const now = new Date().toISOString();
|
|
449
|
-
const newComment: Comment = { ...comment, id, createdAt: now, updatedAt: now };
|
|
450
|
-
this.comments.set(id, newComment);
|
|
451
|
-
return newComment;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
async updateComment(id: string, updates: Partial<Comment>): Promise<Comment | null> {
|
|
455
|
-
const existing = this.comments.get(id);
|
|
456
|
-
if (!existing) return null;
|
|
457
|
-
const updated: Comment = {
|
|
458
|
-
...existing,
|
|
459
|
-
...updates,
|
|
460
|
-
updatedAt: new Date().toISOString()
|
|
461
|
-
};
|
|
462
|
-
this.comments.set(id, updated);
|
|
463
|
-
return updated;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
async deleteComment(id: string): Promise<boolean> {
|
|
467
|
-
return this.comments.delete(id);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
async addReaction(commentId: string, reaction: { emoji: string; userId: string }): Promise<Comment | null> {
|
|
471
|
-
const existing = this.comments.get(commentId);
|
|
472
|
-
if (!existing) return null;
|
|
473
|
-
const reactions = existing.reactions ? [...existing.reactions] : [];
|
|
474
|
-
const alreadyExists = reactions.some((r) => r.emoji === reaction.emoji && r.userId === reaction.userId);
|
|
475
|
-
if (!alreadyExists) {
|
|
476
|
-
reactions.push({
|
|
477
|
-
emoji: reaction.emoji,
|
|
478
|
-
userId: reaction.userId,
|
|
479
|
-
createdAt: new Date().toISOString()
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
const updated: Comment = {
|
|
483
|
-
...existing,
|
|
484
|
-
reactions,
|
|
485
|
-
updatedAt: new Date().toISOString()
|
|
486
|
-
};
|
|
487
|
-
this.comments.set(commentId, updated);
|
|
488
|
-
return updated;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
async removeReaction(commentId: string, reaction: { emoji: string; userId: string }): Promise<Comment | null> {
|
|
492
|
-
const existing = this.comments.get(commentId);
|
|
493
|
-
if (!existing) return null;
|
|
494
|
-
const reactions = (existing.reactions || []).filter(
|
|
495
|
-
(r) => !(r.emoji === reaction.emoji && r.userId === reaction.userId)
|
|
496
|
-
);
|
|
497
|
-
const updated: Comment = {
|
|
498
|
-
...existing,
|
|
499
|
-
reactions,
|
|
500
|
-
updatedAt: new Date().toISOString()
|
|
501
|
-
};
|
|
502
|
-
this.comments.set(commentId, updated);
|
|
503
|
-
return updated;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Attachments
|
|
507
|
-
async getAttachments(filter?: { taskId?: string; projectId?: string; commentId?: string }): Promise<Attachment[]> {
|
|
508
|
-
return Array.from(this.attachments.values()).filter((a) => {
|
|
509
|
-
if (filter?.taskId && a.taskId !== filter.taskId) return false;
|
|
510
|
-
if (filter?.projectId && a.projectId !== filter.projectId) return false;
|
|
511
|
-
if (filter?.commentId && a.commentId !== filter.commentId) return false;
|
|
512
|
-
return true;
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
async getAttachment(id: string): Promise<Attachment | null> {
|
|
517
|
-
return this.attachments.get(id) || null;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
async createAttachment(attachment: Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Attachment> {
|
|
521
|
-
const id = `att_${crypto.randomUUID()}`;
|
|
522
|
-
const now = new Date().toISOString();
|
|
523
|
-
const newAttachment: Attachment = {
|
|
524
|
-
...attachment,
|
|
525
|
-
id,
|
|
526
|
-
createdAt: now,
|
|
527
|
-
updatedAt: now
|
|
528
|
-
};
|
|
529
|
-
this.attachments.set(id, newAttachment);
|
|
530
|
-
return newAttachment;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
async deleteAttachment(id: string): Promise<boolean> {
|
|
534
|
-
return this.attachments.delete(id);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// Activities
|
|
538
|
-
async getActivities(filter?: { projectId?: string; taskId?: string }): Promise<Activity[]> {
|
|
539
|
-
return this.activities.filter((a) => {
|
|
540
|
-
if (filter?.projectId && a.projectId !== filter.projectId) return false;
|
|
541
|
-
if (filter?.taskId && a.taskId !== filter.taskId) return false;
|
|
542
|
-
return true;
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
async queryActivities(query: ActivityQuery): Promise<Page<Activity>> {
|
|
547
|
-
const activities = this.activities.filter((a) => matchesActivityQuery(a, query));
|
|
548
|
-
return paginate(activities, (a) => a.createdAt, 'desc', query.limit, query.cursor);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
async logActivity(activity: Omit<Activity, 'id' | 'createdAt'>): Promise<Activity> {
|
|
552
|
-
const id = `act_${crypto.randomUUID()}`;
|
|
553
|
-
const newAct: Activity = { ...activity, id, createdAt: new Date().toISOString() };
|
|
554
|
-
this.activities.unshift(newAct);
|
|
555
|
-
return newAct;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Time Entries
|
|
559
|
-
async getTimeEntries(taskId: string): Promise<TimeEntry[]> {
|
|
560
|
-
return Array.from(this.timeEntries.values()).filter((e) => e.taskId === taskId);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
async logTime(entry: Omit<TimeEntry, 'id' | 'loggedAt'> & { loggedAt?: string }): Promise<TimeEntry> {
|
|
564
|
-
const id = `time_${crypto.randomUUID()}`;
|
|
565
|
-
const newEntry: TimeEntry = { ...entry, id, loggedAt: entry.loggedAt || new Date().toISOString() };
|
|
566
|
-
this.timeEntries.set(id, newEntry);
|
|
567
|
-
return newEntry;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
async deleteTimeEntry(id: string): Promise<boolean> {
|
|
571
|
-
return this.timeEntries.delete(id);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Dependencies
|
|
575
|
-
async getDependencies(taskId: string): Promise<TaskDependency[]> {
|
|
576
|
-
return Array.from(this.dependencies.values()).filter(
|
|
577
|
-
(d) => d.taskId === taskId || d.dependsOnTaskId === taskId
|
|
578
|
-
);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
async getDependency(id: string): Promise<TaskDependency | null> {
|
|
582
|
-
return this.dependencies.get(id) ?? null;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
async addDependency(dep: Omit<TaskDependency, 'id'>): Promise<TaskDependency> {
|
|
586
|
-
const id = `dep_${crypto.randomUUID()}`;
|
|
587
|
-
const newDep: TaskDependency = { ...dep, id };
|
|
588
|
-
this.dependencies.set(id, newDep);
|
|
589
|
-
return newDep;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
async removeDependency(id: string): Promise<boolean> {
|
|
593
|
-
return this.dependencies.delete(id);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Webhooks
|
|
597
|
-
async getWebhooks(): Promise<Webhook[]> {
|
|
598
|
-
return Array.from(this.webhooks.values());
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
async getWebhook(id: string): Promise<Webhook | null> {
|
|
602
|
-
return this.webhooks.get(id) ?? null;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
async addWebhook(webhook: Omit<Webhook, 'id' | 'createdAt'>): Promise<Webhook> {
|
|
606
|
-
const id = `wh_${crypto.randomUUID()}`;
|
|
607
|
-
const newWh: Webhook = { ...webhook, id, createdAt: new Date().toISOString() };
|
|
608
|
-
this.webhooks.set(id, newWh);
|
|
609
|
-
return newWh;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
async updateWebhook(id: string, updates: Partial<Omit<Webhook, 'id' | 'createdAt'>>): Promise<Webhook | null> {
|
|
613
|
-
const existing = this.webhooks.get(id);
|
|
614
|
-
if (!existing) return null;
|
|
615
|
-
const updated: Webhook = { ...existing, ...updates, id, createdAt: existing.createdAt };
|
|
616
|
-
this.webhooks.set(id, updated);
|
|
617
|
-
return updated;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
async deleteWebhook(id: string): Promise<boolean> {
|
|
621
|
-
return this.webhooks.delete(id);
|
|
622
|
-
}
|
|
623
|
-
}
|