@critical-path/core 0.6.0 → 0.8.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 +35 -0
- package/README.md +6 -0
- package/dist/domain/entities.d.ts +4 -0
- package/dist/domain/entities.d.ts.map +1 -1
- package/dist/domain/entities.js +14 -0
- package/dist/domain/entities.js.map +1 -1
- package/dist/domain/events.d.ts +32 -4
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/engine/index.d.ts +23 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +132 -2
- package/dist/engine/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +26 -0
- package/dist/index.test.js.map +1 -1
- package/dist/storage/file-storage.d.ts +24 -0
- package/dist/storage/file-storage.d.ts.map +1 -0
- package/dist/storage/file-storage.js +73 -0
- package/dist/storage/file-storage.js.map +1 -0
- package/dist/storage/firebase-storage.d.ts +48 -0
- package/dist/storage/firebase-storage.d.ts.map +1 -0
- package/dist/storage/firebase-storage.js +142 -0
- package/dist/storage/firebase-storage.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +4 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/s3.d.ts +36 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +135 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/storage/storage.test.d.ts +2 -0
- package/dist/storage/storage.test.d.ts.map +1 -0
- package/dist/storage/storage.test.js +117 -0
- package/dist/storage/storage.test.js.map +1 -0
- package/dist/store/firebase.d.ts +13 -1
- package/dist/store/firebase.d.ts.map +1 -1
- package/dist/store/firebase.js +95 -18
- package/dist/store/firebase.js.map +1 -1
- package/dist/store/firebase.test.js +12 -0
- package/dist/store/firebase.test.js.map +1 -1
- package/dist/store/index.d.ts +27 -2
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +49 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/sqlite.d.ts +12 -1
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +128 -6
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sqlite.test.js +47 -1
- package/dist/store/sqlite.test.js.map +1 -1
- package/dist/types/index.d.ts +52 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/domain/entities.ts +19 -0
- package/src/domain/events.ts +28 -3
- package/src/engine/index.ts +168 -3
- package/src/index.test.ts +32 -0
- package/src/index.ts +2 -0
- package/src/storage/file-storage.ts +96 -0
- package/src/storage/firebase-storage.ts +177 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/s3.ts +165 -0
- package/src/storage/storage.test.ts +146 -0
- package/src/store/firebase.test.ts +15 -0
- package/src/store/firebase.ts +97 -18
- package/src/store/index.ts +64 -0
- package/src/store/sqlite.test.ts +59 -1
- package/src/store/sqlite.ts +172 -6
- package/src/types/index.ts +63 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/types/index.d.ts
CHANGED
|
@@ -157,14 +157,64 @@ export interface Iteration {
|
|
|
157
157
|
status: 'planning' | 'active' | 'completed';
|
|
158
158
|
createdAt: string;
|
|
159
159
|
}
|
|
160
|
+
export type AuthorType = 'user' | 'agent' | 'system';
|
|
160
161
|
export interface Comment {
|
|
161
162
|
id: string;
|
|
162
163
|
taskId: string;
|
|
163
164
|
authorId: string;
|
|
165
|
+
authorType?: AuthorType;
|
|
166
|
+
parentId?: string;
|
|
164
167
|
content: string;
|
|
168
|
+
metadata?: Record<string, unknown>;
|
|
169
|
+
createdAt: string;
|
|
170
|
+
updatedAt: string;
|
|
171
|
+
}
|
|
172
|
+
export interface Attachment {
|
|
173
|
+
id: string;
|
|
174
|
+
taskId?: string;
|
|
175
|
+
projectId?: string;
|
|
176
|
+
commentId?: string;
|
|
177
|
+
uploaderId: string;
|
|
178
|
+
uploaderType?: AuthorType;
|
|
179
|
+
filename: string;
|
|
180
|
+
mimeType: string;
|
|
181
|
+
sizeBytes: number;
|
|
182
|
+
url: string;
|
|
183
|
+
storageKey?: string;
|
|
184
|
+
metadata?: Record<string, unknown>;
|
|
165
185
|
createdAt: string;
|
|
166
186
|
updatedAt: string;
|
|
167
187
|
}
|
|
188
|
+
export type CreateAttachmentInput = Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>;
|
|
189
|
+
export interface UploadFileInput {
|
|
190
|
+
filename: string;
|
|
191
|
+
data: Uint8Array | ArrayBuffer | Buffer | Blob | string;
|
|
192
|
+
mimeType?: string;
|
|
193
|
+
pathPrefix?: string;
|
|
194
|
+
}
|
|
195
|
+
export interface UploadFileResult {
|
|
196
|
+
storageKey: string;
|
|
197
|
+
url: string;
|
|
198
|
+
sizeBytes: number;
|
|
199
|
+
mimeType: string;
|
|
200
|
+
}
|
|
201
|
+
export interface PresignedUrlOptions {
|
|
202
|
+
storageKey: string;
|
|
203
|
+
expiresInSeconds?: number;
|
|
204
|
+
contentType?: string;
|
|
205
|
+
}
|
|
206
|
+
export interface PresignedUploadResult {
|
|
207
|
+
uploadUrl: string;
|
|
208
|
+
storageKey: string;
|
|
209
|
+
method?: 'PUT' | 'POST';
|
|
210
|
+
headers?: Record<string, string>;
|
|
211
|
+
}
|
|
212
|
+
export interface FileStorageAdapter {
|
|
213
|
+
upload(input: UploadFileInput): Promise<UploadFileResult>;
|
|
214
|
+
delete(storageKey: string): Promise<boolean>;
|
|
215
|
+
getDownloadUrl?(storageKey: string): Promise<string>;
|
|
216
|
+
getPresignedUploadUrl?(options: PresignedUrlOptions): Promise<PresignedUploadResult>;
|
|
217
|
+
}
|
|
168
218
|
export interface TimeEntry {
|
|
169
219
|
id: string;
|
|
170
220
|
taskId: string;
|
|
@@ -192,7 +242,7 @@ export interface Webhook {
|
|
|
192
242
|
active: boolean;
|
|
193
243
|
createdAt: string;
|
|
194
244
|
}
|
|
195
|
-
export type WebhookEvent = 'project.created' | 'project.updated' | 'task.created' | 'task.updated' | 'task.deleted' | 'task.status_changed' | 'comment.created' | 'iteration.started' | 'iteration.completed' | 'team.created' | 'container.created' | 'workflow.created' | 'workflow.updated' | 'workflow.deleted';
|
|
245
|
+
export type WebhookEvent = 'project.created' | 'project.updated' | 'task.created' | 'task.updated' | 'task.deleted' | 'task.status_changed' | 'comment.created' | 'comment.updated' | 'comment.deleted' | 'attachment.created' | 'attachment.deleted' | 'iteration.started' | 'iteration.completed' | 'team.created' | 'container.created' | 'workflow.created' | 'workflow.updated' | 'workflow.deleted';
|
|
196
246
|
export interface PluginHooks {
|
|
197
247
|
beforeTaskCreate?: (task: Partial<Task>) => Promise<Partial<Task>> | Partial<Task>;
|
|
198
248
|
afterTaskCreate?: (task: Task) => Promise<void> | void;
|
|
@@ -212,6 +262,7 @@ export interface CriticalPathPlugin {
|
|
|
212
262
|
}
|
|
213
263
|
export interface CriticalPathConfig {
|
|
214
264
|
store?: 'memory' | 'sqlite' | unknown;
|
|
265
|
+
fileStorage?: FileStorageAdapter;
|
|
215
266
|
plugins?: CriticalPathPlugin[];
|
|
216
267
|
webhooks?: Omit<Webhook, 'id' | 'createdAt'>[];
|
|
217
268
|
initialData?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/domain/entities.ts
CHANGED
|
@@ -388,3 +388,22 @@ export class ProjectEntity extends BaseEntity {
|
|
|
388
388
|
};
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
|
+
|
|
392
|
+
export class AttachmentValidationError extends Error {
|
|
393
|
+
constructor(message: string) {
|
|
394
|
+
super(message);
|
|
395
|
+
this.name = 'AttachmentValidationError';
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export function validateAttachmentUrl(url?: string): void {
|
|
400
|
+
if (!url || typeof url !== 'string' || url.trim() === '') {
|
|
401
|
+
throw new AttachmentValidationError('Attachment URL must be a non-empty string.');
|
|
402
|
+
}
|
|
403
|
+
if (url.startsWith('data:') && url.length > 2048) {
|
|
404
|
+
throw new AttachmentValidationError(
|
|
405
|
+
'Attachment URL cannot be a large data URI. Please upload the file using a FileStorageAdapter or Cloud Storage and provide the resulting URL.'
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
package/src/domain/events.ts
CHANGED
|
@@ -7,14 +7,15 @@ import type {
|
|
|
7
7
|
TaskContainer,
|
|
8
8
|
TaskDependency,
|
|
9
9
|
TimeEntry,
|
|
10
|
-
Comment
|
|
10
|
+
Comment,
|
|
11
|
+
Attachment
|
|
11
12
|
} from '../types/index.js';
|
|
12
13
|
|
|
13
14
|
export interface DomainEvent<TPayload = Record<string, unknown>> {
|
|
14
15
|
readonly id: string;
|
|
15
16
|
readonly name: string;
|
|
16
17
|
readonly aggregateId: string;
|
|
17
|
-
readonly aggregateType: 'Task' | 'Project' | 'Workflow' | 'Iteration' | 'Team' | 'Container' | 'Dependency';
|
|
18
|
+
readonly aggregateType: 'Task' | 'Project' | 'Workflow' | 'Iteration' | 'Team' | 'Container' | 'Dependency' | 'Comment' | 'Attachment';
|
|
18
19
|
readonly occurredAt: string;
|
|
19
20
|
readonly payload: TPayload;
|
|
20
21
|
}
|
|
@@ -51,7 +52,27 @@ export interface TimeLoggedEvent extends DomainEvent<{ timeEntry: TimeEntry; tas
|
|
|
51
52
|
|
|
52
53
|
export interface CommentAddedEvent extends DomainEvent<{ comment: Comment; taskId: string }> {
|
|
53
54
|
readonly name: 'comment.created';
|
|
54
|
-
readonly aggregateType: '
|
|
55
|
+
readonly aggregateType: 'Comment';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface CommentUpdatedEvent extends DomainEvent<{ comment: Comment; previous: Comment }> {
|
|
59
|
+
readonly name: 'comment.updated';
|
|
60
|
+
readonly aggregateType: 'Comment';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface CommentDeletedEvent extends DomainEvent<{ commentId: string; taskId: string }> {
|
|
64
|
+
readonly name: 'comment.deleted';
|
|
65
|
+
readonly aggregateType: 'Comment';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface AttachmentCreatedEvent extends DomainEvent<{ attachment: Attachment }> {
|
|
69
|
+
readonly name: 'attachment.created';
|
|
70
|
+
readonly aggregateType: 'Attachment';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface AttachmentDeletedEvent extends DomainEvent<{ attachmentId: string; storageKey?: string; url: string }> {
|
|
74
|
+
readonly name: 'attachment.deleted';
|
|
75
|
+
readonly aggregateType: 'Attachment';
|
|
55
76
|
}
|
|
56
77
|
|
|
57
78
|
export interface TaskDependencyAddedEvent extends DomainEvent<{ dependency: TaskDependency }> {
|
|
@@ -111,6 +132,10 @@ export type CriticalPathDomainEvent =
|
|
|
111
132
|
| TaskDeletedEvent
|
|
112
133
|
| TimeLoggedEvent
|
|
113
134
|
| CommentAddedEvent
|
|
135
|
+
| CommentUpdatedEvent
|
|
136
|
+
| CommentDeletedEvent
|
|
137
|
+
| AttachmentCreatedEvent
|
|
138
|
+
| AttachmentDeletedEvent
|
|
114
139
|
| TaskDependencyAddedEvent
|
|
115
140
|
| ProjectCreatedEvent
|
|
116
141
|
| ProjectUpdatedEvent
|
package/src/engine/index.ts
CHANGED
|
@@ -8,6 +8,11 @@ import type {
|
|
|
8
8
|
TaskContainer,
|
|
9
9
|
Iteration,
|
|
10
10
|
Comment,
|
|
11
|
+
Attachment,
|
|
12
|
+
FileStorageAdapter,
|
|
13
|
+
UploadFileInput,
|
|
14
|
+
PresignedUrlOptions,
|
|
15
|
+
PresignedUploadResult,
|
|
11
16
|
TimeEntry,
|
|
12
17
|
WebhookEvent,
|
|
13
18
|
Workflow,
|
|
@@ -40,13 +45,19 @@ import {
|
|
|
40
45
|
ContainerCreatedEvent,
|
|
41
46
|
TaskDependencyAddedEvent,
|
|
42
47
|
TimeLoggedEvent,
|
|
43
|
-
CommentAddedEvent
|
|
48
|
+
CommentAddedEvent,
|
|
49
|
+
CommentUpdatedEvent,
|
|
50
|
+
CommentDeletedEvent,
|
|
51
|
+
AttachmentCreatedEvent,
|
|
52
|
+
AttachmentDeletedEvent
|
|
44
53
|
} from '../domain/events.js';
|
|
54
|
+
import { validateAttachmentUrl, AttachmentValidationError } from '../domain/entities.js';
|
|
45
55
|
import { validateCustomFieldValues } from '../domain/custom-fields.js';
|
|
46
56
|
import { detectDependencyCycle, CircularDependencyError } from '../domain/graph.js';
|
|
47
57
|
|
|
48
58
|
export class CriticalPathEngine {
|
|
49
59
|
public readonly store: StorageAdapter;
|
|
60
|
+
public readonly fileStorage?: FileStorageAdapter;
|
|
50
61
|
public readonly plugins: PluginRegistry;
|
|
51
62
|
public readonly events: DomainEventBus;
|
|
52
63
|
|
|
@@ -55,6 +66,7 @@ export class CriticalPathEngine {
|
|
|
55
66
|
? (config.store as StorageAdapter)
|
|
56
67
|
: new InMemoryStore();
|
|
57
68
|
|
|
69
|
+
this.fileStorage = config.fileStorage;
|
|
58
70
|
this.plugins = new PluginRegistry();
|
|
59
71
|
this.events = new DomainEventBus();
|
|
60
72
|
|
|
@@ -601,6 +613,14 @@ export class CriticalPathEngine {
|
|
|
601
613
|
}
|
|
602
614
|
|
|
603
615
|
// --- Comments ---
|
|
616
|
+
async getComments(taskId: string): Promise<Comment[]> {
|
|
617
|
+
return this.store.getComments(taskId);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
async getComment(id: string): Promise<Comment | null> {
|
|
621
|
+
return this.store.getComment(id);
|
|
622
|
+
}
|
|
623
|
+
|
|
604
624
|
async addComment(comment: Omit<Comment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Comment> {
|
|
605
625
|
const created = await this.store.addComment(comment);
|
|
606
626
|
const now = new Date().toISOString();
|
|
@@ -608,8 +628,8 @@ export class CriticalPathEngine {
|
|
|
608
628
|
const event: CommentAddedEvent = {
|
|
609
629
|
id: `evt_${Math.random().toString(36).substring(2, 9)}`,
|
|
610
630
|
name: 'comment.created',
|
|
611
|
-
aggregateId:
|
|
612
|
-
aggregateType: '
|
|
631
|
+
aggregateId: created.id,
|
|
632
|
+
aggregateType: 'Comment',
|
|
613
633
|
occurredAt: now,
|
|
614
634
|
payload: { taskId: comment.taskId, comment: created }
|
|
615
635
|
};
|
|
@@ -619,6 +639,151 @@ export class CriticalPathEngine {
|
|
|
619
639
|
return created;
|
|
620
640
|
}
|
|
621
641
|
|
|
642
|
+
async updateComment(id: string, updates: Partial<Comment>): Promise<Comment | null> {
|
|
643
|
+
const existing = await this.store.getComment(id);
|
|
644
|
+
if (!existing) return null;
|
|
645
|
+
|
|
646
|
+
const updated = await this.store.updateComment(id, updates);
|
|
647
|
+
if (!updated) return null;
|
|
648
|
+
|
|
649
|
+
const now = new Date().toISOString();
|
|
650
|
+
const event: CommentUpdatedEvent = {
|
|
651
|
+
id: `evt_${Math.random().toString(36).substring(2, 9)}`,
|
|
652
|
+
name: 'comment.updated',
|
|
653
|
+
aggregateId: updated.id,
|
|
654
|
+
aggregateType: 'Comment',
|
|
655
|
+
occurredAt: now,
|
|
656
|
+
payload: { comment: updated, previous: existing }
|
|
657
|
+
};
|
|
658
|
+
await this.events.publish(event);
|
|
659
|
+
|
|
660
|
+
this.dispatchWebhook('comment.updated', { comment: updated });
|
|
661
|
+
return updated;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
async deleteComment(id: string): Promise<boolean> {
|
|
665
|
+
const existing = await this.store.getComment(id);
|
|
666
|
+
if (!existing) return false;
|
|
667
|
+
|
|
668
|
+
const deleted = await this.store.deleteComment(id);
|
|
669
|
+
if (deleted) {
|
|
670
|
+
const now = new Date().toISOString();
|
|
671
|
+
const event: CommentDeletedEvent = {
|
|
672
|
+
id: `evt_${Math.random().toString(36).substring(2, 9)}`,
|
|
673
|
+
name: 'comment.deleted',
|
|
674
|
+
aggregateId: id,
|
|
675
|
+
aggregateType: 'Comment',
|
|
676
|
+
occurredAt: now,
|
|
677
|
+
payload: { taskId: existing.taskId, commentId: id }
|
|
678
|
+
};
|
|
679
|
+
await this.events.publish(event);
|
|
680
|
+
|
|
681
|
+
this.dispatchWebhook('comment.deleted', { commentId: id, taskId: existing.taskId });
|
|
682
|
+
}
|
|
683
|
+
return deleted;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// --- Attachments ---
|
|
687
|
+
async getAttachments(filter?: { taskId?: string; projectId?: string; commentId?: string }): Promise<Attachment[]> {
|
|
688
|
+
return this.store.getAttachments(filter);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
async getAttachment(id: string): Promise<Attachment | null> {
|
|
692
|
+
return this.store.getAttachment(id);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
async createAttachment(attachment: Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Attachment> {
|
|
696
|
+
validateAttachmentUrl(attachment.url);
|
|
697
|
+
const created = await this.store.createAttachment(attachment);
|
|
698
|
+
const now = new Date().toISOString();
|
|
699
|
+
|
|
700
|
+
const event: AttachmentCreatedEvent = {
|
|
701
|
+
id: `evt_${Math.random().toString(36).substring(2, 9)}`,
|
|
702
|
+
name: 'attachment.created',
|
|
703
|
+
aggregateId: created.id,
|
|
704
|
+
aggregateType: 'Attachment',
|
|
705
|
+
occurredAt: now,
|
|
706
|
+
payload: { attachment: created }
|
|
707
|
+
};
|
|
708
|
+
await this.events.publish(event);
|
|
709
|
+
|
|
710
|
+
this.dispatchWebhook('attachment.created', { attachment: created });
|
|
711
|
+
return created;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
async deleteAttachment(id: string): Promise<boolean> {
|
|
715
|
+
const existing = await this.store.getAttachment(id);
|
|
716
|
+
if (!existing) return false;
|
|
717
|
+
|
|
718
|
+
if (existing.storageKey && this.fileStorage) {
|
|
719
|
+
try {
|
|
720
|
+
await this.fileStorage.delete(existing.storageKey);
|
|
721
|
+
} catch {
|
|
722
|
+
// Silently continue if underlying file is already gone
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const deleted = await this.store.deleteAttachment(id);
|
|
727
|
+
if (deleted) {
|
|
728
|
+
const now = new Date().toISOString();
|
|
729
|
+
const event: AttachmentDeletedEvent = {
|
|
730
|
+
id: `evt_${Math.random().toString(36).substring(2, 9)}`,
|
|
731
|
+
name: 'attachment.deleted',
|
|
732
|
+
aggregateId: id,
|
|
733
|
+
aggregateType: 'Attachment',
|
|
734
|
+
occurredAt: now,
|
|
735
|
+
payload: { attachmentId: id, storageKey: existing.storageKey, url: existing.url }
|
|
736
|
+
};
|
|
737
|
+
await this.events.publish(event);
|
|
738
|
+
|
|
739
|
+
this.dispatchWebhook('attachment.deleted', { attachmentId: id, taskId: existing.taskId, projectId: existing.projectId });
|
|
740
|
+
}
|
|
741
|
+
return deleted;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
async uploadAttachmentFile(
|
|
745
|
+
input: UploadFileInput & {
|
|
746
|
+
taskId?: string;
|
|
747
|
+
projectId?: string;
|
|
748
|
+
commentId?: string;
|
|
749
|
+
uploaderId: string;
|
|
750
|
+
uploaderType?: 'user' | 'agent' | 'system';
|
|
751
|
+
metadata?: Record<string, unknown>;
|
|
752
|
+
}
|
|
753
|
+
): Promise<Attachment> {
|
|
754
|
+
if (!this.fileStorage) {
|
|
755
|
+
throw new Error('No FileStorageAdapter configured in CriticalPathEngine. Pass "fileStorage" in config to enable direct file uploads.');
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const uploadResult = await this.fileStorage.upload({
|
|
759
|
+
filename: input.filename,
|
|
760
|
+
data: input.data,
|
|
761
|
+
mimeType: input.mimeType,
|
|
762
|
+
pathPrefix: input.pathPrefix || (input.projectId ? `projects/${input.projectId}` : input.taskId ? `tasks/${input.taskId}` : undefined)
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
return this.createAttachment({
|
|
766
|
+
taskId: input.taskId,
|
|
767
|
+
projectId: input.projectId,
|
|
768
|
+
commentId: input.commentId,
|
|
769
|
+
uploaderId: input.uploaderId,
|
|
770
|
+
uploaderType: input.uploaderType || 'user',
|
|
771
|
+
filename: input.filename,
|
|
772
|
+
mimeType: uploadResult.mimeType,
|
|
773
|
+
sizeBytes: uploadResult.sizeBytes,
|
|
774
|
+
url: uploadResult.url,
|
|
775
|
+
storageKey: uploadResult.storageKey,
|
|
776
|
+
metadata: input.metadata
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
async getPresignedAttachmentUploadUrl(options: PresignedUrlOptions): Promise<PresignedUploadResult> {
|
|
781
|
+
if (!this.fileStorage || !this.fileStorage.getPresignedUploadUrl) {
|
|
782
|
+
throw new Error('Presigned uploads are not supported by the configured FileStorageAdapter.');
|
|
783
|
+
}
|
|
784
|
+
return this.fileStorage.getPresignedUploadUrl(options);
|
|
785
|
+
}
|
|
786
|
+
|
|
622
787
|
// --- Teams ---
|
|
623
788
|
async getTeams(): Promise<Team[]> {
|
|
624
789
|
return this.store.getTeams();
|
package/src/index.test.ts
CHANGED
|
@@ -226,4 +226,36 @@ describe('CriticalPathEngine Core Tests', () => {
|
|
|
226
226
|
const doneTask = await engine.updateTask(task.id, { status: 'done' });
|
|
227
227
|
expect(doneTask?.status).toBe('done');
|
|
228
228
|
});
|
|
229
|
+
|
|
230
|
+
it('validates attachment URLs to prevent massive data URIs', async () => {
|
|
231
|
+
const engine = new CriticalPathEngine();
|
|
232
|
+
const proj = await engine.createProject({ key: 'ATT', name: 'Attachment Project' });
|
|
233
|
+
const task = await engine.createTask({ projectId: proj.id, title: 'Task with attachment', status: 'todo' });
|
|
234
|
+
|
|
235
|
+
// Valid HTTPS URL
|
|
236
|
+
const validAtt = await engine.createAttachment({
|
|
237
|
+
taskId: task.id,
|
|
238
|
+
uploaderId: 'user_1',
|
|
239
|
+
filename: 'spec.pdf',
|
|
240
|
+
mimeType: 'application/pdf',
|
|
241
|
+
sizeBytes: 1024,
|
|
242
|
+
url: 'https://storage.googleapis.com/bucket/spec.pdf'
|
|
243
|
+
});
|
|
244
|
+
expect(validAtt.id).toBeDefined();
|
|
245
|
+
expect(validAtt.url).toBe('https://storage.googleapis.com/bucket/spec.pdf');
|
|
246
|
+
|
|
247
|
+
// Invalid large data URI (>2048 chars)
|
|
248
|
+
const largeDataUri = `data:application/pdf;base64,${'A'.repeat(3000)}`;
|
|
249
|
+
await expect(
|
|
250
|
+
engine.createAttachment({
|
|
251
|
+
taskId: task.id,
|
|
252
|
+
uploaderId: 'user_1',
|
|
253
|
+
filename: 'huge.pdf',
|
|
254
|
+
mimeType: 'application/pdf',
|
|
255
|
+
sizeBytes: 3000,
|
|
256
|
+
url: largeDataUri
|
|
257
|
+
})
|
|
258
|
+
).rejects.toThrow('Attachment URL cannot be a large data URI');
|
|
259
|
+
});
|
|
229
260
|
});
|
|
261
|
+
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FileStorageAdapter,
|
|
3
|
+
UploadFileInput,
|
|
4
|
+
UploadFileResult,
|
|
5
|
+
PresignedUrlOptions,
|
|
6
|
+
PresignedUploadResult
|
|
7
|
+
} from '../types/index.js';
|
|
8
|
+
|
|
9
|
+
export interface StoredFile {
|
|
10
|
+
storageKey: string;
|
|
11
|
+
data: Uint8Array;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
sizeBytes: number;
|
|
14
|
+
url: string;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class InMemoryFileStore implements FileStorageAdapter {
|
|
19
|
+
private files = new Map<string, StoredFile>();
|
|
20
|
+
private publicBaseUrl: string;
|
|
21
|
+
|
|
22
|
+
constructor(options: { publicBaseUrl?: string; publicUrlBase?: string } = {}) {
|
|
23
|
+
this.publicBaseUrl = options.publicUrlBase || options.publicBaseUrl || 'memory://attachments';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async upload(input: UploadFileInput): Promise<UploadFileResult> {
|
|
27
|
+
const prefix = input.pathPrefix ? `${input.pathPrefix.replace(/\/+$/, '')}/` : '';
|
|
28
|
+
const randomId = Math.random().toString(36).substring(2, 9);
|
|
29
|
+
const sanitizedFilename = input.filename.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
30
|
+
const storageKey = `${prefix}${Date.now()}_${randomId}_${sanitizedFilename}`;
|
|
31
|
+
|
|
32
|
+
let buffer: Uint8Array;
|
|
33
|
+
if (typeof input.data === 'string') {
|
|
34
|
+
buffer = new TextEncoder().encode(input.data);
|
|
35
|
+
} else if (input.data instanceof Uint8Array) {
|
|
36
|
+
buffer = input.data;
|
|
37
|
+
} else if (input.data instanceof ArrayBuffer) {
|
|
38
|
+
buffer = new Uint8Array(input.data);
|
|
39
|
+
} else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(input.data)) {
|
|
40
|
+
buffer = new Uint8Array(input.data);
|
|
41
|
+
} else {
|
|
42
|
+
buffer = new Uint8Array();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const mimeType = input.mimeType || 'application/octet-stream';
|
|
46
|
+
const sizeBytes = buffer.byteLength;
|
|
47
|
+
const url = `${this.publicBaseUrl}/${storageKey}`;
|
|
48
|
+
|
|
49
|
+
this.files.set(storageKey, {
|
|
50
|
+
storageKey,
|
|
51
|
+
data: buffer,
|
|
52
|
+
mimeType,
|
|
53
|
+
sizeBytes,
|
|
54
|
+
url,
|
|
55
|
+
createdAt: new Date().toISOString()
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
storageKey,
|
|
60
|
+
url,
|
|
61
|
+
sizeBytes,
|
|
62
|
+
mimeType
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async delete(storageKey: string): Promise<boolean> {
|
|
67
|
+
return this.files.delete(storageKey);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async getDownloadUrl(storageKey: string): Promise<string> {
|
|
71
|
+
const file = this.files.get(storageKey);
|
|
72
|
+
if (!file) {
|
|
73
|
+
throw new Error(`File with storageKey "${storageKey}" not found`);
|
|
74
|
+
}
|
|
75
|
+
return file.url;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async getPresignedUploadUrl(options: PresignedUrlOptions): Promise<PresignedUploadResult> {
|
|
79
|
+
const storageKey = options.storageKey;
|
|
80
|
+
const uploadUrl = `${this.publicBaseUrl}/upload/${encodeURIComponent(storageKey)}`;
|
|
81
|
+
return {
|
|
82
|
+
uploadUrl,
|
|
83
|
+
storageKey,
|
|
84
|
+
method: 'PUT',
|
|
85
|
+
headers: options.contentType ? { 'Content-Type': options.contentType } : {}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getFile(storageKey: string): StoredFile | undefined {
|
|
90
|
+
return this.files.get(storageKey);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
clear(): void {
|
|
94
|
+
this.files.clear();
|
|
95
|
+
}
|
|
96
|
+
}
|