@edgebasejs/core 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +15 -0
  2. package/dist/core/src/access-rules/column-security.d.ts +80 -0
  3. package/dist/core/src/access-rules/column-security.d.ts.map +1 -0
  4. package/dist/core/src/access-rules/column-security.js +191 -0
  5. package/dist/core/src/access-rules/column-security.js.map +1 -0
  6. package/dist/core/src/access-rules/engine.d.ts.map +1 -1
  7. package/dist/core/src/access-rules/engine.js +2 -1
  8. package/dist/core/src/access-rules/engine.js.map +1 -1
  9. package/dist/core/src/audit/audit-manager.d.ts +108 -0
  10. package/dist/core/src/audit/audit-manager.d.ts.map +1 -0
  11. package/dist/core/src/audit/audit-manager.js +265 -0
  12. package/dist/core/src/audit/audit-manager.js.map +1 -0
  13. package/dist/core/src/encryption/encryption-manager.d.ts +97 -0
  14. package/dist/core/src/encryption/encryption-manager.d.ts.map +1 -0
  15. package/dist/core/src/encryption/encryption-manager.js +224 -0
  16. package/dist/core/src/encryption/encryption-manager.js.map +1 -0
  17. package/dist/core/src/index.d.ts +12 -0
  18. package/dist/core/src/index.d.ts.map +1 -1
  19. package/dist/core/src/index.js +12 -0
  20. package/dist/core/src/index.js.map +1 -1
  21. package/dist/core/src/realtime/change-notifier.d.ts +50 -0
  22. package/dist/core/src/realtime/change-notifier.d.ts.map +1 -0
  23. package/dist/core/src/realtime/change-notifier.js +145 -0
  24. package/dist/core/src/realtime/change-notifier.js.map +1 -0
  25. package/dist/core/src/realtime/message-types.d.ts +39 -0
  26. package/dist/core/src/realtime/message-types.d.ts.map +1 -0
  27. package/dist/core/src/realtime/message-types.js +5 -0
  28. package/dist/core/src/realtime/message-types.js.map +1 -0
  29. package/dist/core/src/realtime/subscription-manager.d.ts +67 -0
  30. package/dist/core/src/realtime/subscription-manager.d.ts.map +1 -0
  31. package/dist/core/src/realtime/subscription-manager.js +229 -0
  32. package/dist/core/src/realtime/subscription-manager.js.map +1 -0
  33. package/dist/core/src/search/search-manager.d.ts +93 -0
  34. package/dist/core/src/search/search-manager.d.ts.map +1 -0
  35. package/dist/core/src/search/search-manager.js +258 -0
  36. package/dist/core/src/search/search-manager.js.map +1 -0
  37. package/dist/core/src/storage/file-manager.d.ts +138 -0
  38. package/dist/core/src/storage/file-manager.d.ts.map +1 -0
  39. package/dist/core/src/storage/file-manager.js +224 -0
  40. package/dist/core/src/storage/file-manager.js.map +1 -0
  41. package/dist/core/src/sync/batch-processor.d.ts +97 -0
  42. package/dist/core/src/sync/batch-processor.d.ts.map +1 -0
  43. package/dist/core/src/sync/batch-processor.js +313 -0
  44. package/dist/core/src/sync/batch-processor.js.map +1 -0
  45. package/dist/core/src/sync/csv-processor.d.ts +66 -0
  46. package/dist/core/src/sync/csv-processor.d.ts.map +1 -0
  47. package/dist/core/src/sync/csv-processor.js +223 -0
  48. package/dist/core/src/sync/csv-processor.js.map +1 -0
  49. package/dist/core/src/sync/sync-engine.d.ts +22 -0
  50. package/dist/core/src/sync/sync-engine.d.ts.map +1 -1
  51. package/dist/core/src/sync/sync-engine.js +123 -10
  52. package/dist/core/src/sync/sync-engine.js.map +1 -1
  53. package/dist/core/src/sync/transaction-manager.d.ts +83 -0
  54. package/dist/core/src/sync/transaction-manager.d.ts.map +1 -0
  55. package/dist/core/src/sync/transaction-manager.js +227 -0
  56. package/dist/core/src/sync/transaction-manager.js.map +1 -0
  57. package/dist/core/src/webhooks/webhook-manager.d.ts +137 -0
  58. package/dist/core/src/webhooks/webhook-manager.d.ts.map +1 -0
  59. package/dist/core/src/webhooks/webhook-manager.js +334 -0
  60. package/dist/core/src/webhooks/webhook-manager.js.map +1 -0
  61. package/dist/index.d.ts +0 -1
  62. package/dist/index.js +0 -1
  63. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-manager.d.ts","sourceRoot":"","sources":["../../../../src/search/search-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,OAAO,CAAuC;gBAE1C,EAAE,EAAE,cAAc;IAI9B;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAIvC;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCtD;;OAEG;YACW,kBAAkB;IAuChC;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBnD;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;IA0FzD;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAetD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3C,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAoBF;;OAEG;IACH,oBAAoB,IAAI,WAAW,EAAE;IAIrC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAGlC"}
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Full-text search manager using SQLite FTS5
3
+ * Handles search index creation, updating, and querying
4
+ */
5
+ /**
6
+ * Search manager for full-text search
7
+ */
8
+ export class SearchManager {
9
+ constructor(db) {
10
+ this.indexes = new Map();
11
+ this.db = db;
12
+ }
13
+ /**
14
+ * Register a search index for an entity
15
+ */
16
+ registerIndex(index) {
17
+ this.indexes.set(index.entity, index);
18
+ }
19
+ /**
20
+ * Create FTS5 virtual table for an entity
21
+ */
22
+ async createSearchIndex(entity) {
23
+ const index = this.indexes.get(entity);
24
+ if (!index) {
25
+ throw new Error(`No search index configured for entity: ${entity}`);
26
+ }
27
+ const ftsTableName = `${entity}_fts`;
28
+ // Build FTS5 options
29
+ const ftsOptions = [];
30
+ // Add columns
31
+ ftsOptions.push(...index.columns);
32
+ // Add tokenizer
33
+ if (index.tokenize) {
34
+ ftsOptions.push(`tokenize='${index.tokenize}'`);
35
+ }
36
+ else {
37
+ ftsOptions.push(`tokenize='porter unicode61'`); // Default: porter stemming + unicode
38
+ }
39
+ // Add prefix indexes for autocomplete
40
+ if (index.prefix && index.prefix.length > 0) {
41
+ ftsOptions.push(`prefix='${index.prefix.join(' ')}'`);
42
+ }
43
+ // Contentless option (smaller index, no snippet support)
44
+ if (index.contentless) {
45
+ ftsOptions.push(`content=''`);
46
+ }
47
+ else {
48
+ ftsOptions.push(`content='${entity}'`);
49
+ }
50
+ // Create FTS5 virtual table
51
+ const createSQL = `CREATE VIRTUAL TABLE IF NOT EXISTS ${ftsTableName} USING fts5(${ftsOptions.join(', ')})`;
52
+ await this.db.run(createSQL, []);
53
+ // Create triggers to keep FTS index in sync with main table
54
+ await this.createSyncTriggers(entity, index);
55
+ }
56
+ /**
57
+ * Create triggers to automatically update FTS index
58
+ */
59
+ async createSyncTriggers(entity, index) {
60
+ const ftsTableName = `${entity}_fts`;
61
+ const columns = index.columns.join(', ');
62
+ const columnValues = index.columns.map((col) => `NEW.${col}`).join(', ');
63
+ // Insert trigger
64
+ await this.db.run(`CREATE TRIGGER IF NOT EXISTS ${entity}_fts_insert
65
+ AFTER INSERT ON ${entity}
66
+ BEGIN
67
+ INSERT INTO ${ftsTableName} (rowid, ${columns})
68
+ VALUES (NEW.rowid, ${columnValues});
69
+ END`, []);
70
+ // Update trigger
71
+ await this.db.run(`CREATE TRIGGER IF NOT EXISTS ${entity}_fts_update
72
+ AFTER UPDATE ON ${entity}
73
+ BEGIN
74
+ UPDATE ${ftsTableName}
75
+ SET ${index.columns.map((col) => `${col} = NEW.${col}`).join(', ')}
76
+ WHERE rowid = NEW.rowid;
77
+ END`, []);
78
+ // Delete trigger
79
+ await this.db.run(`CREATE TRIGGER IF NOT EXISTS ${entity}_fts_delete
80
+ AFTER DELETE ON ${entity}
81
+ BEGIN
82
+ DELETE FROM ${ftsTableName} WHERE rowid = OLD.rowid;
83
+ END`, []);
84
+ }
85
+ /**
86
+ * Rebuild search index from scratch
87
+ */
88
+ async rebuildIndex(entity) {
89
+ const index = this.indexes.get(entity);
90
+ if (!index) {
91
+ throw new Error(`No search index configured for entity: ${entity}`);
92
+ }
93
+ const ftsTableName = `${entity}_fts`;
94
+ // Clear existing FTS data
95
+ await this.db.run(`DELETE FROM ${ftsTableName}`, []);
96
+ // Rebuild from main table
97
+ const columns = index.columns.join(', ');
98
+ const insertSQL = `
99
+ INSERT INTO ${ftsTableName} (rowid, ${columns})
100
+ SELECT rowid, ${columns} FROM ${entity}
101
+ `;
102
+ await this.db.run(insertSQL, []);
103
+ // Get count
104
+ const result = await this.db.getOne(`SELECT COUNT(*) as count FROM ${ftsTableName}`, []);
105
+ return result?.count || 0;
106
+ }
107
+ /**
108
+ * Search for records
109
+ */
110
+ async search(query) {
111
+ const index = this.indexes.get(query.entity);
112
+ if (!index) {
113
+ throw new Error(`No search index configured for entity: ${query.entity}`);
114
+ }
115
+ const ftsTableName = `${query.entity}_fts`;
116
+ const limit = query.limit || 20;
117
+ const offset = query.offset || 0;
118
+ // Build FTS5 query
119
+ const ftsQuery = this.buildFTSQuery(query.query, query.columns);
120
+ // Build SQL with optional ranking and highlighting
121
+ let sql = `
122
+ SELECT
123
+ ${query.entity}.id,
124
+ ${query.entity}.*
125
+ `;
126
+ if (query.rank) {
127
+ sql += `, ${ftsTableName}.rank as _rank`;
128
+ }
129
+ if (query.highlight) {
130
+ // Use snippet function for highlighting
131
+ const snippetColumns = (query.columns || index.columns).map((col) => {
132
+ return `snippet(${ftsTableName}, ${index.columns.indexOf(col)}, '<mark>', '</mark>', '...', 32)`;
133
+ });
134
+ sql += `, ${snippetColumns[0]} as _snippet`;
135
+ }
136
+ sql += `
137
+ FROM ${ftsTableName}
138
+ JOIN ${query.entity} ON ${ftsTableName}.rowid = ${query.entity}.rowid
139
+ WHERE ${ftsTableName} MATCH ?
140
+ `;
141
+ if (query.rank) {
142
+ sql += ` ORDER BY ${ftsTableName}.rank`;
143
+ }
144
+ sql += ` LIMIT ? OFFSET ?`;
145
+ const results = await this.db.getAll(sql, [ftsQuery, limit + 1, offset]);
146
+ // Check if there are more results
147
+ const hasMore = results.length > limit;
148
+ const trimmedResults = hasMore ? results.slice(0, limit) : results;
149
+ // Get total count
150
+ const countSQL = `
151
+ SELECT COUNT(*) as total
152
+ FROM ${ftsTableName}
153
+ WHERE ${ftsTableName} MATCH ?
154
+ `;
155
+ const countResult = await this.db.getOne(countSQL, [ftsQuery]);
156
+ const total = countResult?.total || 0;
157
+ // Format results
158
+ const formattedResults = trimmedResults.map((row) => {
159
+ const result = {
160
+ id: row.id,
161
+ };
162
+ if (query.rank) {
163
+ result.rank = row._rank;
164
+ }
165
+ if (query.highlight) {
166
+ result.snippet = row._snippet;
167
+ }
168
+ // Add all other columns
169
+ for (const key in row) {
170
+ if (key !== '_rank' && key !== '_snippet' && key !== 'rowid') {
171
+ result[key] = row[key];
172
+ }
173
+ }
174
+ return result;
175
+ });
176
+ return {
177
+ results: formattedResults,
178
+ total,
179
+ hasMore,
180
+ };
181
+ }
182
+ /**
183
+ * Build FTS5 query string from user query
184
+ */
185
+ buildFTSQuery(query, columns) {
186
+ // Escape special FTS5 characters
187
+ let escapedQuery = query.replace(/["']/g, '');
188
+ // If specific columns are specified, use column filter
189
+ if (columns && columns.length > 0) {
190
+ const columnQueries = columns.map((col) => `${col}:${escapedQuery}`);
191
+ return columnQueries.join(' OR ');
192
+ }
193
+ // Support phrase queries (quoted strings)
194
+ if (query.includes('"')) {
195
+ return query;
196
+ }
197
+ // Support prefix matching with *
198
+ if (!query.endsWith('*')) {
199
+ const words = escapedQuery.split(/\s+/).filter((w) => w.length > 0);
200
+ // Add prefix matching to last word for autocomplete
201
+ if (words.length > 0) {
202
+ words[words.length - 1] += '*';
203
+ }
204
+ return words.join(' ');
205
+ }
206
+ return escapedQuery;
207
+ }
208
+ /**
209
+ * Delete search index
210
+ */
211
+ async deleteSearchIndex(entity) {
212
+ const ftsTableName = `${entity}_fts`;
213
+ // Drop triggers
214
+ await this.db.run(`DROP TRIGGER IF EXISTS ${entity}_fts_insert`, []);
215
+ await this.db.run(`DROP TRIGGER IF EXISTS ${entity}_fts_update`, []);
216
+ await this.db.run(`DROP TRIGGER IF EXISTS ${entity}_fts_delete`, []);
217
+ // Drop FTS table
218
+ await this.db.run(`DROP TABLE IF EXISTS ${ftsTableName}`, []);
219
+ // Remove from registered indexes
220
+ this.indexes.delete(entity);
221
+ }
222
+ /**
223
+ * Optimize search index (FTS5 optimize)
224
+ */
225
+ async optimizeIndex(entity) {
226
+ const ftsTableName = `${entity}_fts`;
227
+ await this.db.run(`INSERT INTO ${ftsTableName}(${ftsTableName}) VALUES('optimize')`, []);
228
+ }
229
+ /**
230
+ * Get search index statistics
231
+ */
232
+ async getIndexStats(entity) {
233
+ const ftsTableName = `${entity}_fts`;
234
+ const countResult = await this.db.getOne(`SELECT COUNT(*) as count FROM ${ftsTableName}`, []);
235
+ const documentCount = countResult?.count || 0;
236
+ // Get index size (approximate)
237
+ const sizeResult = await this.db.getOne(`SELECT page_count * page_size as size FROM pragma_page_count('${ftsTableName}'), pragma_page_size()`, []);
238
+ const indexSize = sizeResult?.size || 0;
239
+ return {
240
+ entity,
241
+ documentCount,
242
+ indexSize,
243
+ };
244
+ }
245
+ /**
246
+ * Get all registered indexes
247
+ */
248
+ getRegisteredIndexes() {
249
+ return Array.from(this.indexes.values());
250
+ }
251
+ /**
252
+ * Check if an entity has a search index
253
+ */
254
+ hasIndex(entity) {
255
+ return this.indexes.has(entity);
256
+ }
257
+ }
258
+ //# sourceMappingURL=search-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-manager.js","sourceRoot":"","sources":["../../../../src/search/search-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * File storage manager for Cloudflare R2
3
+ * Handles upload, download, and file metadata management
4
+ */
5
+ import type { User } from '@edgebasejs/types';
6
+ export interface R2Bucket {
7
+ put(key: string, value: ReadableStream | ArrayBuffer | string, options?: R2PutOptions): Promise<R2Object>;
8
+ get(key: string, options?: R2GetOptions): Promise<R2ObjectBody | null>;
9
+ delete(key: string): Promise<void>;
10
+ head(key: string): Promise<R2Object | null>;
11
+ list(options?: R2ListOptions): Promise<R2Objects>;
12
+ }
13
+ export interface R2PutOptions {
14
+ httpMetadata?: R2HTTPMetadata;
15
+ customMetadata?: Record<string, string>;
16
+ }
17
+ export interface R2GetOptions {
18
+ range?: {
19
+ offset?: number;
20
+ length?: number;
21
+ };
22
+ }
23
+ export interface R2ListOptions {
24
+ prefix?: string;
25
+ limit?: number;
26
+ cursor?: string;
27
+ }
28
+ export interface R2HTTPMetadata {
29
+ contentType?: string;
30
+ contentLanguage?: string;
31
+ contentDisposition?: string;
32
+ contentEncoding?: string;
33
+ cacheControl?: string;
34
+ }
35
+ export interface R2Object {
36
+ key: string;
37
+ version: string;
38
+ size: number;
39
+ etag: string;
40
+ httpMetadata?: R2HTTPMetadata;
41
+ customMetadata?: Record<string, string>;
42
+ uploaded: Date;
43
+ }
44
+ export interface R2ObjectBody extends R2Object {
45
+ body: ReadableStream;
46
+ arrayBuffer(): Promise<ArrayBuffer>;
47
+ text(): Promise<string>;
48
+ json<T>(): Promise<T>;
49
+ blob(): Promise<Blob>;
50
+ }
51
+ export interface R2Objects {
52
+ objects: R2Object[];
53
+ truncated: boolean;
54
+ cursor?: string;
55
+ }
56
+ export interface FileMetadata {
57
+ id: string;
58
+ key: string;
59
+ fileName: string;
60
+ mimeType: string;
61
+ size: number;
62
+ userId: string;
63
+ bucket: string;
64
+ entityType?: string;
65
+ entityId?: string;
66
+ isPublic: boolean;
67
+ uploadedAt: number;
68
+ expiresAt?: number;
69
+ checksum?: string;
70
+ }
71
+ export interface UploadOptions {
72
+ fileName: string;
73
+ mimeType: string;
74
+ size: number;
75
+ entityType?: string;
76
+ entityId?: string;
77
+ isPublic?: boolean;
78
+ expiresIn?: number;
79
+ maxSize?: number;
80
+ }
81
+ export interface FileDatabase {
82
+ run(sql: string, params: any[]): Promise<any>;
83
+ getOne(sql: string, params: any[]): Promise<any>;
84
+ getAll(sql: string, params: any[]): Promise<any[]>;
85
+ }
86
+ /**
87
+ * File storage manager
88
+ */
89
+ export declare class FileStorageManager {
90
+ private bucket;
91
+ private db;
92
+ private maxFileSize;
93
+ private allowedMimeTypes?;
94
+ constructor(bucket: R2Bucket, db: FileDatabase, options?: {
95
+ maxFileSize?: number;
96
+ allowedMimeTypes?: string[];
97
+ });
98
+ /**
99
+ * Upload a file to R2
100
+ */
101
+ uploadFile(user: User, file: ReadableStream | ArrayBuffer | string, options: UploadOptions): Promise<FileMetadata>;
102
+ /**
103
+ * Download a file from R2
104
+ */
105
+ downloadFile(fileId: string, user: User): Promise<R2ObjectBody | null>;
106
+ /**
107
+ * Delete a file
108
+ */
109
+ deleteFile(fileId: string, user: User): Promise<void>;
110
+ /**
111
+ * Get file metadata
112
+ */
113
+ getFileMetadata(fileId: string): Promise<FileMetadata | null>;
114
+ /**
115
+ * List files for a user
116
+ */
117
+ listFiles(user: User, options?: {
118
+ entityType?: string;
119
+ entityId?: string;
120
+ limit?: number;
121
+ offset?: number;
122
+ }): Promise<FileMetadata[]>;
123
+ /**
124
+ * Generate a signed URL for temporary access
125
+ * Note: R2 doesn't support presigned URLs natively yet, so this returns a direct URL
126
+ * In production, you'd implement token-based access or use Workers to proxy requests
127
+ */
128
+ generateSignedUrl(fileId: string, user: User, expiresIn?: number): Promise<string>;
129
+ /**
130
+ * Verify a signed URL token
131
+ */
132
+ verifyToken(fileId: string, token: string): Promise<boolean>;
133
+ /**
134
+ * Clean up expired files
135
+ */
136
+ cleanupExpiredFiles(): Promise<number>;
137
+ }
138
+ //# sourceMappingURL=file-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-manager.d.ts","sourceRoot":"","sources":["../../../../src/storage/file-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * File storage manager for Cloudflare R2
3
+ * Handles upload, download, and file metadata management
4
+ */
5
+ /**
6
+ * File storage manager
7
+ */
8
+ export class FileStorageManager {
9
+ constructor(bucket, db, options) {
10
+ this.bucket = bucket;
11
+ this.db = db;
12
+ this.maxFileSize = options?.maxFileSize || 100 * 1024 * 1024; // 100MB default
13
+ this.allowedMimeTypes = options?.allowedMimeTypes;
14
+ }
15
+ /**
16
+ * Upload a file to R2
17
+ */
18
+ async uploadFile(user, file, options) {
19
+ // Validate file size
20
+ if (options.size > (options.maxSize || this.maxFileSize)) {
21
+ throw new Error(`File size (${options.size} bytes) exceeds maximum allowed size (${options.maxSize || this.maxFileSize} bytes)`);
22
+ }
23
+ // Validate MIME type
24
+ if (this.allowedMimeTypes && !this.allowedMimeTypes.includes(options.mimeType)) {
25
+ throw new Error(`File type ${options.mimeType} is not allowed`);
26
+ }
27
+ const fileId = `${user.id}_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
28
+ const key = `${user.id}/${fileId}/${options.fileName}`;
29
+ const now = Date.now();
30
+ // Upload to R2
31
+ await this.bucket.put(key, file, {
32
+ httpMetadata: {
33
+ contentType: options.mimeType,
34
+ contentDisposition: `attachment; filename="${options.fileName}"`,
35
+ },
36
+ customMetadata: {
37
+ userId: user.id,
38
+ uploadedAt: now.toString(),
39
+ ...(options.entityType ? { entityType: options.entityType } : {}),
40
+ ...(options.entityId ? { entityId: options.entityId } : {}),
41
+ },
42
+ });
43
+ // Save metadata to database
44
+ const metadata = {
45
+ id: fileId,
46
+ key,
47
+ fileName: options.fileName,
48
+ mimeType: options.mimeType,
49
+ size: options.size,
50
+ userId: user.id,
51
+ bucket: 'default',
52
+ entityType: options.entityType,
53
+ entityId: options.entityId,
54
+ isPublic: options.isPublic || false,
55
+ uploadedAt: now,
56
+ expiresAt: options.expiresIn ? now + options.expiresIn * 1000 : undefined,
57
+ };
58
+ await this.db.run(`INSERT INTO files (id, key, file_name, mime_type, size, user_id, bucket, entity_type, entity_id, is_public, uploaded_at, expires_at)
59
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
60
+ metadata.id,
61
+ metadata.key,
62
+ metadata.fileName,
63
+ metadata.mimeType,
64
+ metadata.size,
65
+ metadata.userId,
66
+ metadata.bucket,
67
+ metadata.entityType || null,
68
+ metadata.entityId || null,
69
+ metadata.isPublic ? 1 : 0,
70
+ metadata.uploadedAt,
71
+ metadata.expiresAt || null,
72
+ ]);
73
+ return metadata;
74
+ }
75
+ /**
76
+ * Download a file from R2
77
+ */
78
+ async downloadFile(fileId, user) {
79
+ // Get file metadata
80
+ const metadata = await this.getFileMetadata(fileId);
81
+ if (!metadata) {
82
+ return null;
83
+ }
84
+ // Check permissions
85
+ if (!metadata.isPublic && metadata.userId !== user.id) {
86
+ throw new Error('Access denied');
87
+ }
88
+ // Check if expired
89
+ if (metadata.expiresAt && metadata.expiresAt < Date.now()) {
90
+ throw new Error('File has expired');
91
+ }
92
+ // Download from R2
93
+ return await this.bucket.get(metadata.key);
94
+ }
95
+ /**
96
+ * Delete a file
97
+ */
98
+ async deleteFile(fileId, user) {
99
+ // Get file metadata
100
+ const metadata = await this.getFileMetadata(fileId);
101
+ if (!metadata) {
102
+ throw new Error('File not found');
103
+ }
104
+ // Check permissions
105
+ if (metadata.userId !== user.id) {
106
+ throw new Error('Access denied');
107
+ }
108
+ // Delete from R2
109
+ await this.bucket.delete(metadata.key);
110
+ // Delete metadata from database
111
+ await this.db.run('DELETE FROM files WHERE id = ?', [fileId]);
112
+ }
113
+ /**
114
+ * Get file metadata
115
+ */
116
+ async getFileMetadata(fileId) {
117
+ const row = await this.db.getOne('SELECT * FROM files WHERE id = ?', [fileId]);
118
+ if (!row) {
119
+ return null;
120
+ }
121
+ return {
122
+ id: row.id,
123
+ key: row.key,
124
+ fileName: row.file_name,
125
+ mimeType: row.mime_type,
126
+ size: row.size,
127
+ userId: row.user_id,
128
+ bucket: row.bucket,
129
+ entityType: row.entity_type,
130
+ entityId: row.entity_id,
131
+ isPublic: row.is_public === 1,
132
+ uploadedAt: row.uploaded_at,
133
+ expiresAt: row.expires_at,
134
+ checksum: row.checksum,
135
+ };
136
+ }
137
+ /**
138
+ * List files for a user
139
+ */
140
+ async listFiles(user, options) {
141
+ let query = 'SELECT * FROM files WHERE user_id = ?';
142
+ const params = [user.id];
143
+ if (options?.entityType) {
144
+ query += ' AND entity_type = ?';
145
+ params.push(options.entityType);
146
+ }
147
+ if (options?.entityId) {
148
+ query += ' AND entity_id = ?';
149
+ params.push(options.entityId);
150
+ }
151
+ query += ' ORDER BY uploaded_at DESC';
152
+ if (options?.limit) {
153
+ query += ' LIMIT ?';
154
+ params.push(options.limit);
155
+ }
156
+ if (options?.offset) {
157
+ query += ' OFFSET ?';
158
+ params.push(options.offset);
159
+ }
160
+ const rows = await this.db.getAll(query, params);
161
+ return rows.map((row) => ({
162
+ id: row.id,
163
+ key: row.key,
164
+ fileName: row.file_name,
165
+ mimeType: row.mime_type,
166
+ size: row.size,
167
+ userId: row.user_id,
168
+ bucket: row.bucket,
169
+ entityType: row.entity_type,
170
+ entityId: row.entity_id,
171
+ isPublic: row.is_public === 1,
172
+ uploadedAt: row.uploaded_at,
173
+ expiresAt: row.expires_at,
174
+ checksum: row.checksum,
175
+ }));
176
+ }
177
+ /**
178
+ * Generate a signed URL for temporary access
179
+ * Note: R2 doesn't support presigned URLs natively yet, so this returns a direct URL
180
+ * In production, you'd implement token-based access or use Workers to proxy requests
181
+ */
182
+ async generateSignedUrl(fileId, user, expiresIn = 3600) {
183
+ const metadata = await this.getFileMetadata(fileId);
184
+ if (!metadata) {
185
+ throw new Error('File not found');
186
+ }
187
+ // Check permissions
188
+ if (!metadata.isPublic && metadata.userId !== user.id) {
189
+ throw new Error('Access denied');
190
+ }
191
+ // Generate a temporary access token (stored in database)
192
+ const token = `${fileId}_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
193
+ const expiresAt = Date.now() + expiresIn * 1000;
194
+ await this.db.run('INSERT INTO file_access_tokens (token, file_id, user_id, expires_at, created_at) VALUES (?, ?, ?, ?, ?)', [token, fileId, user.id, expiresAt, Date.now()]);
195
+ // Return URL with token
196
+ return `/files/download/${fileId}?token=${token}`;
197
+ }
198
+ /**
199
+ * Verify a signed URL token
200
+ */
201
+ async verifyToken(fileId, token) {
202
+ const row = await this.db.getOne('SELECT * FROM file_access_tokens WHERE token = ? AND file_id = ? AND expires_at > ?', [token, fileId, Date.now()]);
203
+ return !!row;
204
+ }
205
+ /**
206
+ * Clean up expired files
207
+ */
208
+ async cleanupExpiredFiles() {
209
+ const expiredFiles = await this.db.getAll('SELECT * FROM files WHERE expires_at IS NOT NULL AND expires_at < ?', [
210
+ Date.now(),
211
+ ]);
212
+ for (const file of expiredFiles) {
213
+ try {
214
+ await this.bucket.delete(file.key);
215
+ await this.db.run('DELETE FROM files WHERE id = ?', [file.id]);
216
+ }
217
+ catch (error) {
218
+ console.error(`Failed to delete expired file ${file.id}:`, error);
219
+ }
220
+ }
221
+ return expiredFiles.length;
222
+ }
223
+ }
224
+ //# sourceMappingURL=file-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-manager.js","sourceRoot":"","sources":["../../../../src/storage/file-manager.ts"],"names":[],"mappings":"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"}