@fractary/core 0.3.2 → 0.4.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.
Files changed (122) hide show
  1. package/dist/__tests__/factories.test.d.ts +5 -0
  2. package/dist/__tests__/factories.test.d.ts.map +1 -0
  3. package/dist/__tests__/factories.test.js +66 -0
  4. package/dist/__tests__/factories.test.js.map +1 -0
  5. package/dist/auth/__tests__/create-token-provider.test.d.ts +5 -0
  6. package/dist/auth/__tests__/create-token-provider.test.d.ts.map +1 -0
  7. package/dist/auth/__tests__/create-token-provider.test.js +104 -0
  8. package/dist/auth/__tests__/create-token-provider.test.js.map +1 -0
  9. package/dist/auth/__tests__/github-app-auth.test.d.ts +5 -0
  10. package/dist/auth/__tests__/github-app-auth.test.d.ts.map +1 -0
  11. package/dist/auth/__tests__/github-app-auth.test.js +293 -0
  12. package/dist/auth/__tests__/github-app-auth.test.js.map +1 -0
  13. package/dist/auth/__tests__/static-token-provider.test.d.ts +5 -0
  14. package/dist/auth/__tests__/static-token-provider.test.d.ts.map +1 -0
  15. package/dist/auth/__tests__/static-token-provider.test.js +54 -0
  16. package/dist/auth/__tests__/static-token-provider.test.js.map +1 -0
  17. package/dist/auth/github-app-auth.d.ts +109 -0
  18. package/dist/auth/github-app-auth.d.ts.map +1 -0
  19. package/dist/auth/github-app-auth.js +262 -0
  20. package/dist/auth/github-app-auth.js.map +1 -0
  21. package/dist/auth/github-app-token-provider.d.ts +59 -0
  22. package/dist/auth/github-app-token-provider.d.ts.map +1 -0
  23. package/dist/auth/github-app-token-provider.js +68 -0
  24. package/dist/auth/github-app-token-provider.js.map +1 -0
  25. package/dist/auth/index.d.ts +45 -0
  26. package/dist/auth/index.d.ts.map +1 -0
  27. package/dist/auth/index.js +74 -0
  28. package/dist/auth/index.js.map +1 -0
  29. package/dist/auth/static-token-provider.d.ts +35 -0
  30. package/dist/auth/static-token-provider.d.ts.map +1 -0
  31. package/dist/auth/static-token-provider.js +45 -0
  32. package/dist/auth/static-token-provider.js.map +1 -0
  33. package/dist/auth/types.d.ts +49 -0
  34. package/dist/auth/types.d.ts.map +1 -0
  35. package/dist/auth/types.js +8 -0
  36. package/dist/auth/types.js.map +1 -0
  37. package/dist/common/yaml-config.d.ts +10 -0
  38. package/dist/common/yaml-config.d.ts.map +1 -1
  39. package/dist/common/yaml-config.js.map +1 -1
  40. package/dist/config/__tests__/loader.test.d.ts +5 -0
  41. package/dist/config/__tests__/loader.test.d.ts.map +1 -0
  42. package/dist/config/__tests__/loader.test.js +129 -0
  43. package/dist/config/__tests__/loader.test.js.map +1 -0
  44. package/dist/config/index.d.ts +8 -0
  45. package/dist/config/index.d.ts.map +1 -0
  46. package/dist/config/index.js +27 -0
  47. package/dist/config/index.js.map +1 -0
  48. package/dist/config/loader.d.ts +126 -0
  49. package/dist/config/loader.d.ts.map +1 -0
  50. package/dist/config/loader.js +277 -0
  51. package/dist/config/loader.js.map +1 -0
  52. package/dist/docs/index.d.ts +5 -0
  53. package/dist/docs/index.d.ts.map +1 -1
  54. package/dist/docs/index.js +6 -1
  55. package/dist/docs/index.js.map +1 -1
  56. package/dist/docs/manager.d.ts +27 -0
  57. package/dist/docs/manager.d.ts.map +1 -1
  58. package/dist/docs/manager.js +168 -15
  59. package/dist/docs/manager.js.map +1 -1
  60. package/dist/docs/type-registry.d.ts +123 -0
  61. package/dist/docs/type-registry.d.ts.map +1 -0
  62. package/dist/docs/type-registry.js +393 -0
  63. package/dist/docs/type-registry.js.map +1 -0
  64. package/dist/docs/types.d.ts +93 -0
  65. package/dist/docs/types.d.ts.map +1 -1
  66. package/dist/factories.d.ts +89 -0
  67. package/dist/factories.d.ts.map +1 -0
  68. package/dist/factories.js +228 -0
  69. package/dist/factories.js.map +1 -0
  70. package/dist/file/factory.d.ts +41 -0
  71. package/dist/file/factory.d.ts.map +1 -0
  72. package/dist/file/factory.js +237 -0
  73. package/dist/file/factory.js.map +1 -0
  74. package/dist/file/gcs.d.ts +66 -0
  75. package/dist/file/gcs.d.ts.map +1 -0
  76. package/dist/file/gcs.js +226 -0
  77. package/dist/file/gcs.js.map +1 -0
  78. package/dist/file/gdrive.d.ts +78 -0
  79. package/dist/file/gdrive.d.ts.map +1 -0
  80. package/dist/file/gdrive.js +302 -0
  81. package/dist/file/gdrive.js.map +1 -0
  82. package/dist/file/index.d.ts +13 -1
  83. package/dist/file/index.d.ts.map +1 -1
  84. package/dist/file/index.js +25 -1
  85. package/dist/file/index.js.map +1 -1
  86. package/dist/file/manager.d.ts +83 -2
  87. package/dist/file/manager.d.ts.map +1 -1
  88. package/dist/file/manager.js +125 -4
  89. package/dist/file/manager.js.map +1 -1
  90. package/dist/file/r2.d.ts +56 -0
  91. package/dist/file/r2.d.ts.map +1 -0
  92. package/dist/file/r2.js +96 -0
  93. package/dist/file/r2.js.map +1 -0
  94. package/dist/file/s3.d.ts +61 -0
  95. package/dist/file/s3.d.ts.map +1 -0
  96. package/dist/file/s3.js +258 -0
  97. package/dist/file/s3.js.map +1 -0
  98. package/dist/file/types.d.ts +145 -2
  99. package/dist/file/types.d.ts.map +1 -1
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +6 -0
  103. package/dist/index.js.map +1 -1
  104. package/dist/logs/index.d.ts +1 -0
  105. package/dist/logs/index.d.ts.map +1 -1
  106. package/dist/logs/index.js +3 -1
  107. package/dist/logs/index.js.map +1 -1
  108. package/dist/logs/manager.d.ts +29 -2
  109. package/dist/logs/manager.d.ts.map +1 -1
  110. package/dist/logs/manager.js +48 -7
  111. package/dist/logs/manager.js.map +1 -1
  112. package/dist/logs/type-registry.d.ts +180 -0
  113. package/dist/logs/type-registry.d.ts.map +1 -0
  114. package/dist/logs/type-registry.js +421 -0
  115. package/dist/logs/type-registry.js.map +1 -0
  116. package/dist/logs/type-registry.test.d.ts +5 -0
  117. package/dist/logs/type-registry.test.d.ts.map +1 -0
  118. package/dist/logs/type-registry.test.js +671 -0
  119. package/dist/logs/type-registry.test.js.map +1 -0
  120. package/dist/logs/types.d.ts +2 -0
  121. package/dist/logs/types.d.ts.map +1 -1
  122. package/package.json +62 -8
@@ -3,66 +3,187 @@
3
3
  * @fractary/core - File Manager
4
4
  *
5
5
  * Unified interface for file storage operations.
6
+ * Supports multiple storage backends: local, S3, R2, GCS, Google Drive.
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
9
  exports.FileManager = void 0;
9
10
  const local_1 = require("./local");
11
+ const factory_1 = require("./factory");
10
12
  /**
11
13
  * File Manager - Unified interface for file operations
14
+ *
15
+ * Provides a consistent API for file operations across different storage backends.
16
+ * Supports local filesystem, AWS S3, Cloudflare R2, Google Cloud Storage,
17
+ * and Google Drive.
18
+ *
19
+ * @example
20
+ * // Local storage (default)
21
+ * const localManager = new FileManager({ basePath: '.fractary/files' });
22
+ *
23
+ * @example
24
+ * // S3 storage with configuration
25
+ * const s3Manager = new FileManager({
26
+ * storageConfig: {
27
+ * type: 's3',
28
+ * bucket: 'my-bucket',
29
+ * region: 'us-east-1',
30
+ * prefix: 'files/',
31
+ * auth: { profile: 'default' }
32
+ * }
33
+ * });
34
+ *
35
+ * @example
36
+ * // Custom storage backend
37
+ * const customManager = new FileManager({
38
+ * storage: myCustomStorage
39
+ * });
12
40
  */
13
41
  class FileManager {
14
42
  storage;
15
43
  constructor(config) {
16
- this.storage = config.storage || new local_1.LocalStorage(config.basePath);
44
+ // Priority: storageConfig > storage > LocalStorage with basePath
45
+ if (config?.storageConfig) {
46
+ this.storage = (0, factory_1.createStorage)(config.storageConfig);
47
+ }
48
+ else if (config?.storage) {
49
+ this.storage = config.storage;
50
+ }
51
+ else {
52
+ const basePath = config?.basePath || '.fractary/files';
53
+ this.storage = new local_1.LocalStorage(basePath);
54
+ }
55
+ }
56
+ /**
57
+ * Validate a file path for security issues
58
+ *
59
+ * @param path - Path to validate
60
+ * @throws Error if path is invalid or contains security issues
61
+ */
62
+ validatePath(path) {
63
+ if (!path || path.trim() === '') {
64
+ throw new Error('Path cannot be empty');
65
+ }
66
+ // Check for directory traversal sequences
67
+ if (path.includes('..')) {
68
+ throw new Error('Path cannot contain directory traversal sequences (..)');
69
+ }
70
+ // Check for null bytes (potential security issue)
71
+ if (path.includes('\0')) {
72
+ throw new Error('Path cannot contain null bytes');
73
+ }
74
+ // Check for absolute paths on Windows
75
+ if (/^[a-zA-Z]:/.test(path)) {
76
+ throw new Error('Absolute Windows paths are not allowed');
77
+ }
78
+ // Check for absolute Unix paths (starting with /)
79
+ if (path.startsWith('/')) {
80
+ throw new Error('Absolute paths are not allowed');
81
+ }
17
82
  }
18
83
  /**
19
84
  * Write file content
85
+ *
86
+ * @param path - Path/identifier for the file
87
+ * @param content - Content to write
88
+ * @returns URI or path where the content was written
20
89
  */
21
90
  async write(path, content) {
91
+ this.validatePath(path);
22
92
  return this.storage.write(path, content);
23
93
  }
24
94
  /**
25
95
  * Read file content
96
+ *
97
+ * @param path - Path/identifier for the file
98
+ * @returns File content or null if not found
26
99
  */
27
100
  async read(path) {
101
+ this.validatePath(path);
28
102
  return this.storage.read(path);
29
103
  }
30
104
  /**
31
105
  * Check if file exists
106
+ *
107
+ * @param path - Path/identifier for the file
108
+ * @returns True if the file exists
32
109
  */
33
110
  async exists(path) {
111
+ this.validatePath(path);
34
112
  return this.storage.exists(path);
35
113
  }
36
114
  /**
37
115
  * List files (optionally with prefix)
116
+ *
117
+ * @param prefix - Optional prefix to filter results
118
+ * @returns List of file paths/identifiers
38
119
  */
39
120
  async list(prefix) {
121
+ if (prefix) {
122
+ this.validatePath(prefix);
123
+ }
40
124
  return this.storage.list(prefix);
41
125
  }
42
126
  /**
43
127
  * Delete file
128
+ *
129
+ * @param path - Path/identifier for the file
44
130
  */
45
131
  async delete(path) {
132
+ this.validatePath(path);
46
133
  return this.storage.delete(path);
47
134
  }
48
135
  /**
49
136
  * Copy file from one location to another
137
+ *
138
+ * @param sourcePath - Source path/identifier
139
+ * @param destPath - Destination path/identifier
140
+ * @returns URI or path where the content was copied
50
141
  */
51
142
  async copy(sourcePath, destPath) {
52
- const content = await this.read(sourcePath);
143
+ this.validatePath(sourcePath);
144
+ this.validatePath(destPath);
145
+ const content = await this.storage.read(sourcePath);
53
146
  if (!content) {
54
147
  throw new Error(`Source file not found: ${sourcePath}`);
55
148
  }
56
- return this.write(destPath, content);
149
+ return this.storage.write(destPath, content);
57
150
  }
58
151
  /**
59
152
  * Move file from one location to another
153
+ *
154
+ * @param sourcePath - Source path/identifier
155
+ * @param destPath - Destination path/identifier
156
+ * @returns URI or path where the content was moved
60
157
  */
61
158
  async move(sourcePath, destPath) {
159
+ this.validatePath(sourcePath);
160
+ this.validatePath(destPath);
62
161
  const result = await this.copy(sourcePath, destPath);
63
- await this.delete(sourcePath);
162
+ await this.storage.delete(sourcePath);
64
163
  return result;
65
164
  }
165
+ /**
166
+ * Get a URL for the file (if supported by the storage backend)
167
+ *
168
+ * @param path - Path/identifier for the file
169
+ * @param expiresIn - Expiration time in seconds (for presigned URLs)
170
+ * @returns URL or null if not supported
171
+ */
172
+ async getUrl(path, expiresIn) {
173
+ this.validatePath(path);
174
+ if (this.storage.getUrl) {
175
+ return this.storage.getUrl(path, expiresIn);
176
+ }
177
+ return null;
178
+ }
179
+ /**
180
+ * Get the underlying storage backend
181
+ *
182
+ * @returns The storage instance
183
+ */
184
+ getStorage() {
185
+ return this.storage;
186
+ }
66
187
  }
67
188
  exports.FileManager = FileManager;
68
189
  //# sourceMappingURL=manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/file/manager.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAGH,mCAAuC;AAEvC;;GAEG;AACH,MAAa,WAAW;IACd,OAAO,CAAU;IAEzB,YAAY,MAAyB;QACnC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,oBAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,IAAY,EAAE,OAAe;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,MAAe;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,QAAgB;QAC7C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,QAAgB;QAC7C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACrD,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA7DD,kCA6DC"}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/file/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fractary/core - R2 Storage Implementation
3
+ *
4
+ * Cloudflare R2 storage backend for file operations.
5
+ * R2 is S3-compatible, so this uses the AWS SDK with R2 endpoint.
6
+ */
7
+ import { Storage, R2StorageConfig } from './types';
8
+ /**
9
+ * Cloudflare R2 storage implementation
10
+ *
11
+ * Uses S3Storage internally with R2-specific endpoint configuration.
12
+ */
13
+ export declare class R2Storage implements Storage {
14
+ private s3Storage;
15
+ private config;
16
+ constructor(config: R2StorageConfig);
17
+ /**
18
+ * Write content to R2
19
+ */
20
+ write(id: string, content: string): Promise<string>;
21
+ /**
22
+ * Read content from R2
23
+ */
24
+ read(id: string): Promise<string | null>;
25
+ /**
26
+ * Check if object exists in R2
27
+ */
28
+ exists(id: string): Promise<boolean>;
29
+ /**
30
+ * List objects in R2 with optional prefix
31
+ */
32
+ list(prefix?: string): Promise<string[]>;
33
+ /**
34
+ * Delete object from R2
35
+ */
36
+ delete(id: string): Promise<void>;
37
+ /**
38
+ * Get a URL for the object
39
+ *
40
+ * R2 supports presigned URLs, and can also use public bucket URLs.
41
+ */
42
+ getUrl(id: string, expiresIn?: number): Promise<string | null>;
43
+ /**
44
+ * Get the bucket name
45
+ */
46
+ getBucket(): string;
47
+ /**
48
+ * Get the account ID
49
+ */
50
+ getAccountId(): string;
51
+ /**
52
+ * Get the configured prefix
53
+ */
54
+ getPrefix(): string | undefined;
55
+ }
56
+ //# sourceMappingURL=r2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/file/r2.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,eAAe,EAAmB,MAAM,SAAS,CAAC;AAGpE;;;;GAIG;AACH,qBAAa,SAAU,YAAW,OAAO;IACvC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;IAoBnC;;OAEG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMzD;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI9C;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1C;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI9C;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,GAAE,MAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI3E;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACH,SAAS,IAAI,MAAM,GAAG,SAAS;CAGhC"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ /**
3
+ * @fractary/core - R2 Storage Implementation
4
+ *
5
+ * Cloudflare R2 storage backend for file operations.
6
+ * R2 is S3-compatible, so this uses the AWS SDK with R2 endpoint.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.R2Storage = void 0;
10
+ const s3_1 = require("./s3");
11
+ /**
12
+ * Cloudflare R2 storage implementation
13
+ *
14
+ * Uses S3Storage internally with R2-specific endpoint configuration.
15
+ */
16
+ class R2Storage {
17
+ s3Storage;
18
+ config;
19
+ constructor(config) {
20
+ this.config = config;
21
+ // Convert R2 config to S3-compatible config
22
+ const s3Config = {
23
+ type: 's3',
24
+ bucket: config.bucket,
25
+ region: 'auto', // R2 uses 'auto' region
26
+ prefix: config.prefix,
27
+ endpoint: `https://${config.accountId}.r2.cloudflarestorage.com`,
28
+ publicUrl: config.publicUrl,
29
+ auth: {
30
+ accessKeyId: config.accessKeyId,
31
+ secretAccessKey: config.secretAccessKey,
32
+ },
33
+ };
34
+ this.s3Storage = new s3_1.S3Storage(s3Config);
35
+ }
36
+ /**
37
+ * Write content to R2
38
+ */
39
+ async write(id, content) {
40
+ const result = await this.s3Storage.write(id, content);
41
+ // Return R2-style URI
42
+ return result.replace('s3://', 'r2://');
43
+ }
44
+ /**
45
+ * Read content from R2
46
+ */
47
+ async read(id) {
48
+ return this.s3Storage.read(id);
49
+ }
50
+ /**
51
+ * Check if object exists in R2
52
+ */
53
+ async exists(id) {
54
+ return this.s3Storage.exists(id);
55
+ }
56
+ /**
57
+ * List objects in R2 with optional prefix
58
+ */
59
+ async list(prefix) {
60
+ return this.s3Storage.list(prefix);
61
+ }
62
+ /**
63
+ * Delete object from R2
64
+ */
65
+ async delete(id) {
66
+ return this.s3Storage.delete(id);
67
+ }
68
+ /**
69
+ * Get a URL for the object
70
+ *
71
+ * R2 supports presigned URLs, and can also use public bucket URLs.
72
+ */
73
+ async getUrl(id, expiresIn = 86400) {
74
+ return this.s3Storage.getUrl(id, expiresIn);
75
+ }
76
+ /**
77
+ * Get the bucket name
78
+ */
79
+ getBucket() {
80
+ return this.config.bucket;
81
+ }
82
+ /**
83
+ * Get the account ID
84
+ */
85
+ getAccountId() {
86
+ return this.config.accountId;
87
+ }
88
+ /**
89
+ * Get the configured prefix
90
+ */
91
+ getPrefix() {
92
+ return this.config.prefix;
93
+ }
94
+ }
95
+ exports.R2Storage = R2Storage;
96
+ //# sourceMappingURL=r2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.js","sourceRoot":"","sources":["../../src/file/r2.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAGH,6BAAiC;AAEjC;;;;GAIG;AACH,MAAa,SAAS;IACZ,SAAS,CAAY;IACrB,MAAM,CAAkB;IAEhC,YAAY,MAAuB;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,4CAA4C;QAC5C,MAAM,QAAQ,GAAoB;YAChC,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,EAAE,wBAAwB;YACxC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,WAAW,MAAM,CAAC,SAAS,2BAA2B;YAChE,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,IAAI,EAAE;gBACJ,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC;SACF,CAAC;QAEF,IAAI,CAAC,SAAS,GAAG,IAAI,cAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,EAAU,EAAE,OAAe;QACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACvD,sBAAsB;QACtB,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,MAAe;QACxB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,YAAoB,KAAK;QAChD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;CACF;AA1FD,8BA0FC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fractary/core - S3 Storage Implementation
3
+ *
4
+ * AWS S3 storage backend for file operations.
5
+ * Uses AWS SDK v3 with lazy loading to avoid hard dependencies.
6
+ */
7
+ import { Storage, S3StorageConfig } from './types';
8
+ /**
9
+ * AWS S3 storage implementation
10
+ */
11
+ export declare class S3Storage implements Storage {
12
+ private config;
13
+ private s3Client;
14
+ constructor(config: S3StorageConfig);
15
+ /**
16
+ * Get or create the S3 client (lazy loaded)
17
+ */
18
+ private getClient;
19
+ /**
20
+ * Get the full S3 key with optional prefix
21
+ */
22
+ private getKey;
23
+ /**
24
+ * Check if an error is a "not found" error
25
+ * AWS SDK v3 uses error.name and error.$metadata.httpStatusCode
26
+ */
27
+ private isNotFoundError;
28
+ /**
29
+ * Write content to S3
30
+ */
31
+ write(id: string, content: string): Promise<string>;
32
+ /**
33
+ * Read content from S3
34
+ */
35
+ read(id: string): Promise<string | null>;
36
+ /**
37
+ * Check if object exists in S3
38
+ */
39
+ exists(id: string): Promise<boolean>;
40
+ /**
41
+ * List objects in S3 with optional prefix
42
+ */
43
+ list(prefix?: string): Promise<string[]>;
44
+ /**
45
+ * Delete object from S3
46
+ */
47
+ delete(id: string): Promise<void>;
48
+ /**
49
+ * Get a presigned URL for the object
50
+ */
51
+ getUrl(id: string, expiresIn?: number): Promise<string | null>;
52
+ /**
53
+ * Get the bucket name
54
+ */
55
+ getBucket(): string;
56
+ /**
57
+ * Get the configured prefix
58
+ */
59
+ getPrefix(): string | undefined;
60
+ }
61
+ //# sourceMappingURL=s3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/file/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAKnD;;GAEG;AACH,qBAAa,SAAU,YAAW,OAAO;IACvC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAyB;gBAE7B,MAAM,EAAE,eAAe;IAInC;;OAEG;YACW,SAAS;IAwCvB;;OAEG;IACH,OAAO,CAAC,MAAM;IAOd;;;OAGG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBzD;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA4B9C;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB1C;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAoC9C;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAavC;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,GAAE,MAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA4B3E;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM,GAAG,SAAS;CAGhC"}
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ /**
3
+ * @fractary/core - S3 Storage Implementation
4
+ *
5
+ * AWS S3 storage backend for file operations.
6
+ * Uses AWS SDK v3 with lazy loading to avoid hard dependencies.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.S3Storage = void 0;
43
+ /**
44
+ * AWS S3 storage implementation
45
+ */
46
+ class S3Storage {
47
+ config;
48
+ s3Client = null;
49
+ constructor(config) {
50
+ this.config = config;
51
+ }
52
+ /**
53
+ * Get or create the S3 client (lazy loaded)
54
+ */
55
+ async getClient() {
56
+ if (this.s3Client) {
57
+ return this.s3Client;
58
+ }
59
+ try {
60
+ // Dynamic import to avoid hard dependency
61
+ const { S3Client } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
62
+ const { fromIni } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/credential-providers')));
63
+ const clientConfig = {
64
+ region: this.config.region,
65
+ };
66
+ // Configure endpoint for S3-compatible services
67
+ if (this.config.endpoint) {
68
+ clientConfig.endpoint = this.config.endpoint;
69
+ clientConfig.forcePathStyle = true;
70
+ }
71
+ // Configure credentials
72
+ if (this.config.auth?.accessKeyId && this.config.auth?.secretAccessKey) {
73
+ clientConfig.credentials = {
74
+ accessKeyId: this.config.auth.accessKeyId,
75
+ secretAccessKey: this.config.auth.secretAccessKey,
76
+ };
77
+ }
78
+ else if (this.config.auth?.profile) {
79
+ clientConfig.credentials = fromIni({ profile: this.config.auth.profile });
80
+ }
81
+ // Otherwise, use default credential chain (IAM role, env vars, etc.)
82
+ this.s3Client = new S3Client(clientConfig);
83
+ return this.s3Client;
84
+ }
85
+ catch (error) {
86
+ throw new Error('AWS SDK not available. Install with: npm install @aws-sdk/client-s3 @aws-sdk/credential-providers');
87
+ }
88
+ }
89
+ /**
90
+ * Get the full S3 key with optional prefix
91
+ */
92
+ getKey(id) {
93
+ if (this.config.prefix) {
94
+ return `${this.config.prefix.replace(/\/$/, '')}/${id}`;
95
+ }
96
+ return id;
97
+ }
98
+ /**
99
+ * Check if an error is a "not found" error
100
+ * AWS SDK v3 uses error.name and error.$metadata.httpStatusCode
101
+ */
102
+ isNotFoundError(error) {
103
+ return (error.name === 'NoSuchKey' ||
104
+ error.name === 'NotFound' ||
105
+ error.$metadata?.httpStatusCode === 404);
106
+ }
107
+ /**
108
+ * Write content to S3
109
+ */
110
+ async write(id, content) {
111
+ const client = await this.getClient();
112
+ const { PutObjectCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
113
+ const key = this.getKey(id);
114
+ const command = new PutObjectCommand({
115
+ Bucket: this.config.bucket,
116
+ Key: key,
117
+ Body: content,
118
+ ContentType: 'text/plain; charset=utf-8',
119
+ });
120
+ await client.send(command);
121
+ return `s3://${this.config.bucket}/${key}`;
122
+ }
123
+ /**
124
+ * Read content from S3
125
+ */
126
+ async read(id) {
127
+ const client = await this.getClient();
128
+ const { GetObjectCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
129
+ const key = this.getKey(id);
130
+ try {
131
+ const command = new GetObjectCommand({
132
+ Bucket: this.config.bucket,
133
+ Key: key,
134
+ });
135
+ const response = await client.send(command);
136
+ // Convert stream to string
137
+ if (response.Body) {
138
+ const bodyContents = await response.Body.transformToString();
139
+ return bodyContents;
140
+ }
141
+ return null;
142
+ }
143
+ catch (error) {
144
+ if (this.isNotFoundError(error)) {
145
+ return null;
146
+ }
147
+ throw error;
148
+ }
149
+ }
150
+ /**
151
+ * Check if object exists in S3
152
+ */
153
+ async exists(id) {
154
+ const client = await this.getClient();
155
+ const { HeadObjectCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
156
+ const key = this.getKey(id);
157
+ try {
158
+ const command = new HeadObjectCommand({
159
+ Bucket: this.config.bucket,
160
+ Key: key,
161
+ });
162
+ await client.send(command);
163
+ return true;
164
+ }
165
+ catch (error) {
166
+ if (this.isNotFoundError(error)) {
167
+ return false;
168
+ }
169
+ throw error;
170
+ }
171
+ }
172
+ /**
173
+ * List objects in S3 with optional prefix
174
+ */
175
+ async list(prefix) {
176
+ const client = await this.getClient();
177
+ const { ListObjectsV2Command } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
178
+ const fullPrefix = prefix ? this.getKey(prefix) : this.config.prefix || '';
179
+ const results = [];
180
+ let continuationToken;
181
+ do {
182
+ const command = new ListObjectsV2Command({
183
+ Bucket: this.config.bucket,
184
+ Prefix: fullPrefix,
185
+ ContinuationToken: continuationToken,
186
+ });
187
+ const response = await client.send(command);
188
+ if (response.Contents) {
189
+ for (const item of response.Contents) {
190
+ if (item.Key) {
191
+ // Remove the configured prefix from the key for consistency
192
+ let key = item.Key;
193
+ if (this.config.prefix && key.startsWith(this.config.prefix)) {
194
+ key = key.slice(this.config.prefix.length).replace(/^\//, '');
195
+ }
196
+ results.push(key);
197
+ }
198
+ }
199
+ }
200
+ continuationToken = response.IsTruncated ? response.NextContinuationToken : undefined;
201
+ } while (continuationToken);
202
+ return results;
203
+ }
204
+ /**
205
+ * Delete object from S3
206
+ */
207
+ async delete(id) {
208
+ const client = await this.getClient();
209
+ const { DeleteObjectCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
210
+ const key = this.getKey(id);
211
+ const command = new DeleteObjectCommand({
212
+ Bucket: this.config.bucket,
213
+ Key: key,
214
+ });
215
+ await client.send(command);
216
+ }
217
+ /**
218
+ * Get a presigned URL for the object
219
+ */
220
+ async getUrl(id, expiresIn = 86400) {
221
+ // If a public URL is configured, use it
222
+ if (this.config.publicUrl) {
223
+ const key = this.getKey(id);
224
+ return `${this.config.publicUrl.replace(/\/$/, '')}/${key}`;
225
+ }
226
+ const client = await this.getClient();
227
+ try {
228
+ const { getSignedUrl } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/s3-request-presigner')));
229
+ const { GetObjectCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3')));
230
+ const key = this.getKey(id);
231
+ const command = new GetObjectCommand({
232
+ Bucket: this.config.bucket,
233
+ Key: key,
234
+ });
235
+ const url = await getSignedUrl(client, command, { expiresIn });
236
+ return url;
237
+ }
238
+ catch (error) {
239
+ // Fall back to S3 URI if presigner not available
240
+ const key = this.getKey(id);
241
+ return `s3://${this.config.bucket}/${key}`;
242
+ }
243
+ }
244
+ /**
245
+ * Get the bucket name
246
+ */
247
+ getBucket() {
248
+ return this.config.bucket;
249
+ }
250
+ /**
251
+ * Get the configured prefix
252
+ */
253
+ getPrefix() {
254
+ return this.config.prefix;
255
+ }
256
+ }
257
+ exports.S3Storage = S3Storage;
258
+ //# sourceMappingURL=s3.js.map