@mastra/files-sdk 0.0.0 → 0.2.0-alpha.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 CHANGED
@@ -1 +1,26 @@
1
1
  # @mastra/files-sdk
2
+
3
+ ## 0.2.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added @mastra/files-sdk workspace filesystem provider — a unified storage adapter backed by [FilesSDK](https://files-sdk.dev). Supports any FilesSDK adapter (S3, R2, GCS, Azure Blob, Vercel Blob, local filesystem, and more) through a single `FilesSDKFilesystem` class that implements the `WorkspaceFilesystem` interface. ([#17027](https://github.com/mastra-ai/mastra/pull/17027))
8
+
9
+ **Usage**
10
+
11
+ ```ts
12
+ import { Files } from 'files-sdk';
13
+ import { s3 } from 'files-sdk/s3';
14
+ import { FilesSDKFilesystem } from '@mastra/files-sdk';
15
+
16
+ const files = new Files({ adapter: s3({ bucket: 'my-bucket', region: 'us-east-1' }) });
17
+
18
+ const filesystem = new FilesSDKFilesystem({ files });
19
+ ```
20
+
21
+ Swap adapters without changing code — just replace `s3()` with `r2()`, `gcs()`, `azure()`, `fs()`, etc.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [[`c35b962`](https://github.com/mastra-ai/mastra/commit/c35b9625c7e854fcfdeee226a3338a750d0ff211), [`4084113`](https://github.com/mastra-ai/mastra/commit/408411370fc48a822e8b616b3b63f9409774e0e9)]:
26
+ - @mastra/core@1.37.0-alpha.8
@@ -0,0 +1,81 @@
1
+ import type { FileContent, FileStat, FileEntry, ReadOptions, WriteOptions, ListOptions, RemoveOptions, CopyOptions, FilesystemIcon, FilesystemInfo, ProviderStatus, MastraFilesystemOptions } from '@mastra/core/workspace';
2
+ import { MastraFilesystem } from '@mastra/core/workspace';
3
+ import type { Files } from 'files-sdk';
4
+ export interface FilesSDKFilesystemOptions extends MastraFilesystemOptions {
5
+ /** Pre-configured FilesSDK `Files` instance. */
6
+ files: Files;
7
+ /** Unique filesystem ID (auto-generated if not provided). */
8
+ id?: string;
9
+ /** Human-friendly display name for UI. */
10
+ displayName?: string;
11
+ /** Icon identifier for UI. */
12
+ icon?: FilesystemIcon;
13
+ /** Description shown in UI / instructions. */
14
+ description?: string;
15
+ /** Mount as read-only — all write operations will throw. */
16
+ readOnly?: boolean;
17
+ }
18
+ /**
19
+ * Workspace filesystem adapter backed by [FilesSDK](https://files-sdk.dev).
20
+ *
21
+ * Accepts a pre-configured `Files` instance so users choose their own adapter
22
+ * (S3, R2, GCS, Azure, local fs, etc.) and this class bridges it to the
23
+ * Mastra `WorkspaceFilesystem` interface.
24
+ *
25
+ * Object-storage semantics are bridged to the POSIX-like interface:
26
+ * - `mkdir` is a no-op (directories don't exist in object storage)
27
+ * - `readdir` uses `list()` with prefix filtering to synthesize directory entries
28
+ * - `rmdir` lists all keys under a prefix and batch-deletes them
29
+ */
30
+ export declare class FilesSDKFilesystem extends MastraFilesystem {
31
+ readonly id: string;
32
+ readonly name = "FilesSDKFilesystem";
33
+ readonly provider = "files-sdk";
34
+ status: ProviderStatus;
35
+ readonly readOnly?: boolean;
36
+ readonly icon?: FilesystemIcon;
37
+ readonly displayName?: string;
38
+ readonly description?: string;
39
+ private readonly _files;
40
+ constructor(options: FilesSDKFilesystemOptions);
41
+ /** The underlying FilesSDK instance, for escape-hatch access. */
42
+ get files(): Files;
43
+ init(): Promise<void>;
44
+ getInfo(): FilesystemInfo;
45
+ getInstructions(): string;
46
+ readFile(path: string, options?: ReadOptions): Promise<string | Buffer>;
47
+ writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void>;
48
+ /**
49
+ * Append content to a file.
50
+ *
51
+ * **Not atomic.** Object storage has no native append, so this is implemented
52
+ * as a read-modify-write: the existing object is downloaded, the new content
53
+ * is concatenated, and the result is uploaded as a new object. Concurrent
54
+ * appends to the same key may overwrite each other. This limitation is
55
+ * inherent to object storage, not specific to FilesSDK, and matches the
56
+ * behavior of the sibling S3, GCS, and Azure workspace providers.
57
+ */
58
+ appendFile(path: string, content: FileContent): Promise<void>;
59
+ deleteFile(path: string, options?: RemoveOptions): Promise<void>;
60
+ copyFile(src: string, dest: string, options?: CopyOptions): Promise<void>;
61
+ moveFile(src: string, dest: string, options?: CopyOptions): Promise<void>;
62
+ mkdir(_path: string, _options?: {
63
+ recursive?: boolean;
64
+ }): Promise<void>;
65
+ rmdir(path: string, options?: RemoveOptions): Promise<void>;
66
+ readdir(path: string, options?: ListOptions): Promise<FileEntry[]>;
67
+ exists(path: string): Promise<boolean>;
68
+ stat(path: string): Promise<FileStat>;
69
+ private assertWritable;
70
+ /** Check if a key prefix has any children (i.e. acts like a directory). */
71
+ private isDirectory;
72
+ /**
73
+ * Check whether `key` refers to a real stored file (not an empty leftover
74
+ * directory). Uses prefix listing constrained to the exact key, which only
75
+ * matches actually-stored objects across all adapters.
76
+ */
77
+ private isFile;
78
+ /** Convert a FilesSDK StoredFile to a Mastra FileStat. */
79
+ private storedFileToStat;
80
+ }
81
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/filesystem/index.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,427 @@
1
+ 'use strict';
2
+
3
+ var workspace = require('@mastra/core/workspace');
4
+
5
+ // src/filesystem/index.ts
6
+ function toKey(path) {
7
+ let start = 0;
8
+ while (start < path.length && path.charCodeAt(start) === 47) start++;
9
+ let end = path.length;
10
+ while (end > start && path.charCodeAt(end - 1) === 47) end--;
11
+ const key = path.slice(start, end);
12
+ if (key === "." || key === "./") return "";
13
+ return key;
14
+ }
15
+ function basename(key) {
16
+ const idx = key.lastIndexOf("/");
17
+ return idx === -1 ? key : key.slice(idx + 1);
18
+ }
19
+ function hasFilesSDKCode(err, code, depth = 0) {
20
+ if (depth > 5 || !err || typeof err !== "object") return false;
21
+ const e = err;
22
+ if (e.code === code) return true;
23
+ if (e.cause) return hasFilesSDKCode(e.cause, code, depth + 1);
24
+ return false;
25
+ }
26
+ function isNotFoundError(err) {
27
+ return hasFilesSDKCode(err, "NotFound");
28
+ }
29
+ function isUnauthorizedError(err) {
30
+ return hasFilesSDKCode(err, "Unauthorized");
31
+ }
32
+ function generateId() {
33
+ return `files-sdk-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
34
+ }
35
+ function toBody(content) {
36
+ if (typeof content === "string") return content;
37
+ if (Buffer.isBuffer(content)) return new Uint8Array(content);
38
+ return content;
39
+ }
40
+ var MIME_TYPES = {
41
+ ".txt": "text/plain",
42
+ ".md": "text/markdown",
43
+ ".markdown": "text/markdown",
44
+ ".html": "text/html",
45
+ ".htm": "text/html",
46
+ ".css": "text/css",
47
+ ".csv": "text/csv",
48
+ ".xml": "text/xml",
49
+ ".js": "text/javascript",
50
+ ".mjs": "text/javascript",
51
+ ".ts": "text/typescript",
52
+ ".tsx": "text/typescript",
53
+ ".jsx": "text/javascript",
54
+ ".json": "application/json",
55
+ ".yaml": "text/yaml",
56
+ ".yml": "text/yaml",
57
+ ".py": "text/x-python",
58
+ ".rb": "text/x-ruby",
59
+ ".sh": "text/x-shellscript",
60
+ ".bash": "text/x-shellscript",
61
+ ".png": "image/png",
62
+ ".jpg": "image/jpeg",
63
+ ".jpeg": "image/jpeg",
64
+ ".gif": "image/gif",
65
+ ".svg": "image/svg+xml",
66
+ ".webp": "image/webp",
67
+ ".ico": "image/x-icon",
68
+ ".pdf": "application/pdf",
69
+ ".zip": "application/zip",
70
+ ".gz": "application/gzip",
71
+ ".tar": "application/x-tar"
72
+ };
73
+ function getMimeType(path) {
74
+ const dot = path.lastIndexOf(".");
75
+ if (dot === -1) return "application/octet-stream";
76
+ return MIME_TYPES[path.slice(dot).toLowerCase()] ?? "application/octet-stream";
77
+ }
78
+ var FilesSDKFilesystem = class extends workspace.MastraFilesystem {
79
+ id;
80
+ name = "FilesSDKFilesystem";
81
+ provider = "files-sdk";
82
+ status = "pending";
83
+ readOnly;
84
+ icon;
85
+ displayName;
86
+ description;
87
+ _files;
88
+ constructor(options) {
89
+ super({ name: "FilesSDKFilesystem", ...options });
90
+ this._files = options.files;
91
+ this.id = options.id ?? generateId();
92
+ this.readOnly = options.readOnly;
93
+ this.icon = options.icon;
94
+ this.displayName = options.displayName;
95
+ this.description = options.description;
96
+ }
97
+ /** The underlying FilesSDK instance, for escape-hatch access. */
98
+ get files() {
99
+ return this._files;
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // Lifecycle
103
+ // ---------------------------------------------------------------------------
104
+ async init() {
105
+ try {
106
+ await this._files.list({ limit: 1 });
107
+ } catch (err) {
108
+ if (isUnauthorizedError(err)) {
109
+ throw new Error("Access denied \u2014 check credentials and storage permissions");
110
+ }
111
+ throw err;
112
+ }
113
+ }
114
+ // destroy() — default no-op is fine; FilesSDK has no explicit teardown.
115
+ getInfo() {
116
+ return {
117
+ id: this.id,
118
+ name: this.name,
119
+ provider: this.provider,
120
+ status: this.status,
121
+ error: this.error,
122
+ readOnly: this.readOnly,
123
+ icon: this.icon,
124
+ metadata: {
125
+ adapter: this._files.adapter?.name ?? "unknown"
126
+ }
127
+ };
128
+ }
129
+ getInstructions() {
130
+ const adapterName = this._files.adapter?.name ?? "unknown";
131
+ const parts = [`Unified storage via FilesSDK (${adapterName} adapter).`];
132
+ if (this.readOnly) parts.push("Mounted read-only.");
133
+ parts.push("Persistent storage \u2014 files are retained across sessions.");
134
+ return parts.join(" ");
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // File operations
138
+ // ---------------------------------------------------------------------------
139
+ async readFile(path, options) {
140
+ await this.ensureReady();
141
+ const key = toKey(path);
142
+ try {
143
+ const file = await this._files.download(key);
144
+ const buf = Buffer.from(await file.arrayBuffer());
145
+ if (options?.encoding) return buf.toString(options.encoding);
146
+ return buf;
147
+ } catch (err) {
148
+ if (isNotFoundError(err)) throw new workspace.FileNotFoundError(path);
149
+ throw err;
150
+ }
151
+ }
152
+ async writeFile(path, content, options) {
153
+ await this.ensureReady();
154
+ this.assertWritable("writeFile");
155
+ const key = toKey(path);
156
+ if (options?.overwrite === false && await this.isFile(key)) {
157
+ throw new workspace.FileExistsError(path);
158
+ }
159
+ const body = toBody(content);
160
+ await this._files.upload(key, body, {
161
+ contentType: options?.mimeType ?? getMimeType(path)
162
+ });
163
+ }
164
+ /**
165
+ * Append content to a file.
166
+ *
167
+ * **Not atomic.** Object storage has no native append, so this is implemented
168
+ * as a read-modify-write: the existing object is downloaded, the new content
169
+ * is concatenated, and the result is uploaded as a new object. Concurrent
170
+ * appends to the same key may overwrite each other. This limitation is
171
+ * inherent to object storage, not specific to FilesSDK, and matches the
172
+ * behavior of the sibling S3, GCS, and Azure workspace providers.
173
+ */
174
+ async appendFile(path, content) {
175
+ await this.ensureReady();
176
+ this.assertWritable("appendFile");
177
+ const key = toKey(path);
178
+ let existing = Buffer.alloc(0);
179
+ try {
180
+ const file = await this._files.download(key);
181
+ existing = Buffer.from(await file.arrayBuffer());
182
+ } catch (err) {
183
+ if (!isNotFoundError(err)) throw err;
184
+ }
185
+ const append = typeof content === "string" ? Buffer.from(content) : toBody(content);
186
+ const merged = Buffer.concat([existing, Buffer.isBuffer(append) ? append : Buffer.from(append)]);
187
+ await this._files.upload(key, new Uint8Array(merged), {
188
+ contentType: getMimeType(path)
189
+ });
190
+ }
191
+ async deleteFile(path, options) {
192
+ await this.ensureReady();
193
+ this.assertWritable("deleteFile");
194
+ const key = toKey(path);
195
+ if (await this.isDirectory(key)) {
196
+ await this.rmdir(path, { recursive: true, force: options?.force });
197
+ return;
198
+ }
199
+ if (!options?.force && !await this.isFile(key)) {
200
+ throw new workspace.FileNotFoundError(path);
201
+ }
202
+ try {
203
+ await this._files.delete(key);
204
+ } catch (err) {
205
+ if (options?.force) return;
206
+ if (isNotFoundError(err)) throw new workspace.FileNotFoundError(path);
207
+ throw err;
208
+ }
209
+ }
210
+ async copyFile(src, dest, options) {
211
+ await this.ensureReady();
212
+ this.assertWritable("copyFile");
213
+ const fromKey = toKey(src);
214
+ const toKey_ = toKey(dest);
215
+ if (options?.overwrite === false && await this.isFile(toKey_)) {
216
+ throw new workspace.FileExistsError(dest);
217
+ }
218
+ try {
219
+ await this._files.copy(fromKey, toKey_);
220
+ } catch (err) {
221
+ if (isNotFoundError(err)) throw new workspace.FileNotFoundError(src);
222
+ throw err;
223
+ }
224
+ }
225
+ async moveFile(src, dest, options) {
226
+ await this.copyFile(src, dest, options);
227
+ await this.deleteFile(src, { force: true });
228
+ }
229
+ // ---------------------------------------------------------------------------
230
+ // Directory operations
231
+ // ---------------------------------------------------------------------------
232
+ async mkdir(_path, _options) {
233
+ await this.ensureReady();
234
+ this.assertWritable("mkdir");
235
+ }
236
+ async rmdir(path, options) {
237
+ await this.ensureReady();
238
+ this.assertWritable("rmdir");
239
+ const key = toKey(path);
240
+ const prefix = key ? `${key}/` : "";
241
+ const allKeys = [];
242
+ let cursor;
243
+ do {
244
+ const result = await this._files.list({ prefix, cursor, limit: 1e3 });
245
+ for (const item of result.items) {
246
+ allKeys.push(item.key);
247
+ }
248
+ cursor = result.cursor;
249
+ } while (cursor);
250
+ if (allKeys.length === 0) return;
251
+ if (!options?.recursive) {
252
+ throw new workspace.DirectoryNotEmptyError(path);
253
+ }
254
+ await this._files.delete(allKeys);
255
+ }
256
+ async readdir(path, options) {
257
+ await this.ensureReady();
258
+ const key = toKey(path);
259
+ const prefix = key ? `${key}/` : "";
260
+ const entries = [];
261
+ const seenDirs = /* @__PURE__ */ new Set();
262
+ let cursor;
263
+ const maxDepth = options?.maxDepth;
264
+ const recursive = options?.recursive ?? false;
265
+ const extensions = options?.extension ? Array.isArray(options.extension) ? options.extension : [options.extension] : void 0;
266
+ do {
267
+ const result = await this._files.list({ prefix, cursor, limit: 1e3 });
268
+ for (const item of result.items) {
269
+ const relativePath = prefix ? item.key.slice(prefix.length) : item.key;
270
+ if (!relativePath) continue;
271
+ const segments = relativePath.split("/");
272
+ if (segments.length === 1) {
273
+ const name = segments[0];
274
+ if (extensions) {
275
+ const ext = name.lastIndexOf(".") !== -1 ? name.slice(name.lastIndexOf(".")) : "";
276
+ if (!extensions.includes(ext)) continue;
277
+ }
278
+ entries.push({
279
+ name,
280
+ type: "file",
281
+ size: item.size
282
+ });
283
+ } else if (!recursive) {
284
+ const dirName = segments[0];
285
+ if (!seenDirs.has(dirName)) {
286
+ seenDirs.add(dirName);
287
+ entries.push({
288
+ name: dirName,
289
+ type: "directory"
290
+ });
291
+ }
292
+ } else {
293
+ for (let i = 1; i < segments.length; i++) {
294
+ const dirPath = segments.slice(0, i).join("/");
295
+ const dirDepth = i;
296
+ if (maxDepth !== void 0 && dirDepth > maxDepth) continue;
297
+ if (!seenDirs.has(dirPath)) {
298
+ seenDirs.add(dirPath);
299
+ entries.push({
300
+ name: dirPath,
301
+ type: "directory"
302
+ });
303
+ }
304
+ }
305
+ if (maxDepth !== void 0 && segments.length > maxDepth) continue;
306
+ const name = relativePath;
307
+ if (extensions) {
308
+ const ext = name.lastIndexOf(".") !== -1 ? name.slice(name.lastIndexOf(".")) : "";
309
+ if (!extensions.includes(ext)) continue;
310
+ }
311
+ entries.push({
312
+ name,
313
+ type: "file",
314
+ size: item.size
315
+ });
316
+ }
317
+ }
318
+ cursor = result.cursor;
319
+ } while (cursor);
320
+ return entries;
321
+ }
322
+ // ---------------------------------------------------------------------------
323
+ // Path operations
324
+ // ---------------------------------------------------------------------------
325
+ async exists(path) {
326
+ await this.ensureReady();
327
+ const key = toKey(path);
328
+ if (!key) return true;
329
+ if (await this.isDirectory(key)) return true;
330
+ return this.isFile(key);
331
+ }
332
+ async stat(path) {
333
+ await this.ensureReady();
334
+ const key = toKey(path);
335
+ if (!key) {
336
+ const now = /* @__PURE__ */ new Date();
337
+ return {
338
+ name: "/",
339
+ path: "/",
340
+ type: "directory",
341
+ size: 0,
342
+ createdAt: now,
343
+ modifiedAt: now
344
+ };
345
+ }
346
+ try {
347
+ const file = await this._files.head(key);
348
+ return this.storedFileToStat(file, path);
349
+ } catch (err) {
350
+ if (!isNotFoundError(err)) throw err;
351
+ }
352
+ if (await this.isDirectory(key)) {
353
+ const now = /* @__PURE__ */ new Date();
354
+ return {
355
+ name: basename(key),
356
+ path,
357
+ type: "directory",
358
+ size: 0,
359
+ createdAt: now,
360
+ modifiedAt: now
361
+ };
362
+ }
363
+ throw new workspace.FileNotFoundError(path);
364
+ }
365
+ // ---------------------------------------------------------------------------
366
+ // Private helpers
367
+ // ---------------------------------------------------------------------------
368
+ assertWritable(operation) {
369
+ if (this.readOnly) {
370
+ throw new workspace.WorkspaceReadOnlyError(operation);
371
+ }
372
+ }
373
+ /** Check if a key prefix has any children (i.e. acts like a directory). */
374
+ async isDirectory(key) {
375
+ if (!key) return true;
376
+ const prefix = `${key}/`;
377
+ const result = await this._files.list({ prefix, limit: 1 });
378
+ return result.items.length > 0;
379
+ }
380
+ /**
381
+ * Check whether `key` refers to a real stored file (not an empty leftover
382
+ * directory). Uses prefix listing constrained to the exact key, which only
383
+ * matches actually-stored objects across all adapters.
384
+ */
385
+ async isFile(key) {
386
+ if (!key) return false;
387
+ const result = await this._files.list({ prefix: key, limit: 10 });
388
+ return result.items.some((item) => item.key === key);
389
+ }
390
+ /** Convert a FilesSDK StoredFile to a Mastra FileStat. */
391
+ storedFileToStat(file, path) {
392
+ return {
393
+ name: basename(file.key ?? path),
394
+ path,
395
+ type: "file",
396
+ size: file.size ?? 0,
397
+ createdAt: file.lastModified ? new Date(file.lastModified) : /* @__PURE__ */ new Date(),
398
+ modifiedAt: file.lastModified ? new Date(file.lastModified) : /* @__PURE__ */ new Date(),
399
+ mimeType: file.type || void 0
400
+ };
401
+ }
402
+ };
403
+
404
+ // src/provider.ts
405
+ var filesSDKFilesystemProvider = {
406
+ id: "files-sdk",
407
+ name: "FilesSDK (Unified Storage)",
408
+ description: "Unified storage via FilesSDK \u2014 supports S3, R2, GCS, Azure, Vercel Blob, local filesystem, and more",
409
+ configSchema: {
410
+ type: "object",
411
+ required: ["files"],
412
+ properties: {
413
+ files: { type: "object", description: "Pre-configured FilesSDK Files instance" },
414
+ id: { type: "string", description: "Unique filesystem ID" },
415
+ displayName: { type: "string", description: "Human-friendly display name" },
416
+ icon: { type: "string", description: "Icon identifier for UI" },
417
+ description: { type: "string", description: "Description for UI" },
418
+ readOnly: { type: "boolean", description: "Mount as read-only", default: false }
419
+ }
420
+ },
421
+ createFilesystem: (config) => new FilesSDKFilesystem(config)
422
+ };
423
+
424
+ exports.FilesSDKFilesystem = FilesSDKFilesystem;
425
+ exports.filesSDKFilesystemProvider = filesSDKFilesystemProvider;
426
+ //# sourceMappingURL=index.cjs.map
427
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/filesystem/index.ts","../src/provider.ts"],"names":["MastraFilesystem","FileNotFoundError","FileExistsError","DirectoryNotEmptyError","WorkspaceReadOnlyError"],"mappings":";;;;;AAkDA,SAAS,MAAM,IAAA,EAAsB;AAInC,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,OAAO,QAAQ,IAAA,CAAK,MAAA,IAAU,KAAK,UAAA,CAAW,KAAK,MAAM,EAAA,EAAc,KAAA,EAAA;AACvE,EAAA,IAAI,MAAM,IAAA,CAAK,MAAA;AACf,EAAA,OAAO,MAAM,KAAA,IAAS,IAAA,CAAK,WAAW,GAAA,GAAM,CAAC,MAAM,EAAA,EAAI,GAAA,EAAA;AACvD,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,KAAA,EAAO,GAAG,CAAA;AACjC,EAAA,IAAI,GAAA,KAAQ,GAAA,IAAO,GAAA,KAAQ,IAAA,EAAM,OAAO,EAAA;AACxC,EAAA,OAAO,GAAA;AACT;AAKA,SAAS,SAAS,GAAA,EAAqB;AACrC,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,WAAA,CAAY,GAAG,CAAA;AAC/B,EAAA,OAAO,QAAQ,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,MAAM,CAAC,CAAA;AAC7C;AAUA,SAAS,eAAA,CAAgB,GAAA,EAAc,IAAA,EAAc,KAAA,GAAQ,CAAA,EAAY;AACvE,EAAA,IAAI,QAAQ,CAAA,IAAK,CAAC,OAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,KAAA;AACzD,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,IAAA,KAAS,IAAA,EAAM,OAAO,IAAA;AAC5B,EAAA,IAAI,CAAA,CAAE,OAAO,OAAO,eAAA,CAAgB,EAAE,KAAA,EAAO,IAAA,EAAM,QAAQ,CAAC,CAAA;AAC5D,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,gBAAgB,GAAA,EAAuB;AAC9C,EAAA,OAAO,eAAA,CAAgB,KAAK,UAAU,CAAA;AACxC;AAEA,SAAS,oBAAoB,GAAA,EAAuB;AAClD,EAAA,OAAO,eAAA,CAAgB,KAAK,cAAc,CAAA;AAC5C;AAEA,SAAS,UAAA,GAAqB;AAC5B,EAAA,OAAO,aAAa,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA;AACvF;AAKA,SAAS,OAAO,OAAA,EAA2C;AACzD,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,OAAA;AACxC,EAAA,IAAI,OAAO,QAAA,CAAS,OAAO,GAAG,OAAO,IAAI,WAAW,OAAO,CAAA;AAC3D,EAAA,OAAO,OAAA;AACT;AAKA,IAAM,UAAA,GAAqC;AAAA,EACzC,MAAA,EAAQ,YAAA;AAAA,EACR,KAAA,EAAO,eAAA;AAAA,EACP,WAAA,EAAa,eAAA;AAAA,EACb,OAAA,EAAS,WAAA;AAAA,EACT,MAAA,EAAQ,WAAA;AAAA,EACR,MAAA,EAAQ,UAAA;AAAA,EACR,MAAA,EAAQ,UAAA;AAAA,EACR,MAAA,EAAQ,UAAA;AAAA,EACR,KAAA,EAAO,iBAAA;AAAA,EACP,MAAA,EAAQ,iBAAA;AAAA,EACR,KAAA,EAAO,iBAAA;AAAA,EACP,MAAA,EAAQ,iBAAA;AAAA,EACR,MAAA,EAAQ,iBAAA;AAAA,EACR,OAAA,EAAS,kBAAA;AAAA,EACT,OAAA,EAAS,WAAA;AAAA,EACT,MAAA,EAAQ,WAAA;AAAA,EACR,KAAA,EAAO,eAAA;AAAA,EACP,KAAA,EAAO,aAAA;AAAA,EACP,KAAA,EAAO,oBAAA;AAAA,EACP,OAAA,EAAS,oBAAA;AAAA,EACT,MAAA,EAAQ,WAAA;AAAA,EACR,MAAA,EAAQ,YAAA;AAAA,EACR,OAAA,EAAS,YAAA;AAAA,EACT,MAAA,EAAQ,WAAA;AAAA,EACR,MAAA,EAAQ,eAAA;AAAA,EACR,OAAA,EAAS,YAAA;AAAA,EACT,MAAA,EAAQ,cAAA;AAAA,EACR,MAAA,EAAQ,iBAAA;AAAA,EACR,MAAA,EAAQ,iBAAA;AAAA,EACR,KAAA,EAAO,kBAAA;AAAA,EACP,MAAA,EAAQ;AACV,CAAA;AAEA,SAAS,YAAY,IAAA,EAAsB;AACzC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAChC,EAAA,IAAI,GAAA,KAAQ,IAAI,OAAO,0BAAA;AACvB,EAAA,OAAO,WAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,WAAA,EAAa,CAAA,IAAK,0BAAA;AACtD;AAkBO,IAAM,kBAAA,GAAN,cAAiCA,0BAAA,CAAiB;AAAA,EAC9C,EAAA;AAAA,EACA,IAAA,GAAO,oBAAA;AAAA,EACP,QAAA,GAAW,WAAA;AAAA,EACpB,MAAA,GAAyB,SAAA;AAAA,EAEhB,QAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EAEQ,MAAA;AAAA,EAEjB,YAAY,OAAA,EAAoC;AAC9C,IAAA,KAAA,CAAM,EAAE,IAAA,EAAM,oBAAA,EAAsB,GAAG,SAAS,CAAA;AAEhD,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,KAAA;AACtB,IAAA,IAAA,CAAK,EAAA,GAAK,OAAA,CAAQ,EAAA,IAAM,UAAA,EAAW;AACnC,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,QAAA;AACxB,IAAA,IAAA,CAAK,OAAO,OAAA,CAAQ,IAAA;AACpB,IAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,WAAA;AAC3B,IAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,WAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,KAAA,GAAe;AACjB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAMA,MAAe,IAAA,GAAsB;AAEnC,IAAA,IAAI;AACF,MAAA,MAAM,KAAK,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,GAAG,CAAA;AAAA,IACrC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,mBAAA,CAAoB,GAAG,CAAA,EAAG;AAC5B,QAAA,MAAM,IAAI,MAAM,gEAA2D,CAAA;AAAA,MAC7E;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAIA,OAAA,GAA0B;AACxB,IAAA,OAAO;AAAA,MACL,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,QAAA,EAAU;AAAA,QACR,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,OAAA,EAAS,IAAA,IAAQ;AAAA;AACxC,KACF;AAAA,EACF;AAAA,EAEA,eAAA,GAA0B;AACxB,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,MAAA,CAAO,OAAA,EAAS,IAAA,IAAQ,SAAA;AACjD,IAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,8BAAA,EAAiC,WAAW,CAAA,UAAA,CAAY,CAAA;AACvE,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,KAAA,CAAM,IAAA,CAAK,oBAAoB,CAAA;AAClD,IAAA,KAAA,CAAM,KAAK,+DAA0D,CAAA;AACrE,IAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAA,CAAS,IAAA,EAAc,OAAA,EAAiD;AAC5E,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AAEtB,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,CAAO,SAAS,GAAG,CAAA;AAC3C,MAAA,MAAM,MAAM,MAAA,CAAO,IAAA,CAAK,MAAM,IAAA,CAAK,aAAa,CAAA;AAChD,MAAA,IAAI,SAAS,QAAA,EAAU,OAAO,GAAA,CAAI,QAAA,CAAS,QAAQ,QAAQ,CAAA;AAC3D,MAAA,OAAO,GAAA;AAAA,IACT,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,gBAAgB,GAAG,CAAA,EAAG,MAAM,IAAIC,4BAAkB,IAAI,CAAA;AAC1D,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SAAA,CAAU,IAAA,EAAc,OAAA,EAAsB,OAAA,EAAuC;AACzF,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,eAAe,WAAW,CAAA;AAC/B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AAKtB,IAAA,IAAI,SAAS,SAAA,KAAc,KAAA,IAAU,MAAM,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,EAAI;AAC5D,MAAA,MAAM,IAAIC,0BAAgB,IAAI,CAAA;AAAA,IAChC;AAEA,IAAA,MAAM,IAAA,GAAO,OAAO,OAAO,CAAA;AAC3B,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,GAAA,EAAK,IAAA,EAAM;AAAA,MAClC,WAAA,EAAa,OAAA,EAAS,QAAA,IAAY,WAAA,CAAY,IAAI;AAAA,KACnD,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,UAAA,CAAW,IAAA,EAAc,OAAA,EAAqC;AAClE,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,eAAe,YAAY,CAAA;AAChC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AAGtB,IAAA,IAAI,QAAA,GAAW,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA;AAC7B,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,CAAO,SAAS,GAAG,CAAA;AAC3C,MAAA,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,MAAM,IAAA,CAAK,aAAa,CAAA;AAAA,IACjD,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,CAAC,eAAA,CAAgB,GAAG,CAAA,EAAG,MAAM,GAAA;AAAA,IAEnC;AAEA,IAAA,MAAM,MAAA,GAAS,OAAO,OAAA,KAAY,QAAA,GAAW,OAAO,IAAA,CAAK,OAAO,CAAA,GAAI,MAAA,CAAO,OAAO,CAAA;AAClF,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,CAAC,UAAU,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,GAAI,MAAA,GAAS,MAAA,CAAO,IAAA,CAAK,MAAoB,CAAC,CAAC,CAAA;AAE7G,IAAA,MAAM,KAAK,MAAA,CAAO,MAAA,CAAO,KAAK,IAAI,UAAA,CAAW,MAAM,CAAA,EAAG;AAAA,MACpD,WAAA,EAAa,YAAY,IAAI;AAAA,KAC9B,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,UAAA,CAAW,IAAA,EAAc,OAAA,EAAwC;AACrE,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,eAAe,YAAY,CAAA;AAChC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AAKtB,IAAA,IAAI,MAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,EAAG;AAC/B,MAAA,MAAM,IAAA,CAAK,MAAM,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,CAAA;AACjE,MAAA;AAAA,IACF;AAMA,IAAA,IAAI,CAAC,SAAS,KAAA,IAAS,CAAE,MAAM,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,EAAI;AAChD,MAAA,MAAM,IAAID,4BAAkB,IAAI,CAAA;AAAA,IAClC;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA;AAAA,IAC9B,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,SAAS,KAAA,EAAO;AACpB,MAAA,IAAI,gBAAgB,GAAG,CAAA,EAAG,MAAM,IAAIA,4BAAkB,IAAI,CAAA;AAC1D,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,CAAS,GAAA,EAAa,IAAA,EAAc,OAAA,EAAsC;AAC9E,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,eAAe,UAAU,CAAA;AAC9B,IAAA,MAAM,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,IAAA,MAAM,MAAA,GAAS,MAAM,IAAI,CAAA;AAEzB,IAAA,IAAI,SAAS,SAAA,KAAc,KAAA,IAAU,MAAM,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,EAAI;AAC/D,MAAA,MAAM,IAAIC,0BAAgB,IAAI,CAAA;AAAA,IAChC;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,MAAM,CAAA;AAAA,IACxC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,gBAAgB,GAAG,CAAA,EAAG,MAAM,IAAID,4BAAkB,GAAG,CAAA;AACzD,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,CAAS,GAAA,EAAa,IAAA,EAAc,OAAA,EAAsC;AAG9E,IAAA,MAAM,IAAA,CAAK,QAAA,CAAS,GAAA,EAAK,IAAA,EAAM,OAAO,CAAA;AACtC,IAAA,MAAM,KAAK,UAAA,CAAW,GAAA,EAAK,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAA,CAAM,KAAA,EAAe,QAAA,EAAmD;AAC5E,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,eAAe,OAAO,CAAA;AAAA,EAE7B;AAAA,EAEA,MAAM,KAAA,CAAM,IAAA,EAAc,OAAA,EAAwC;AAChE,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,eAAe,OAAO,CAAA;AAC3B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,MAAM,MAAA,GAAS,GAAA,GAAM,CAAA,EAAG,GAAG,CAAA,CAAA,CAAA,GAAM,EAAA;AAGjC,IAAA,MAAM,UAAoB,EAAC;AAC3B,IAAA,IAAI,MAAA;AAEJ,IAAA,GAAG;AACD,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,GAAA,EAAM,CAAA;AACrE,MAAA,KAAA,MAAW,IAAA,IAAQ,OAAO,KAAA,EAAO;AAC/B,QAAA,OAAA,CAAQ,IAAA,CAAK,KAAK,GAAG,CAAA;AAAA,MACvB;AACA,MAAA,MAAA,GAAS,MAAA,CAAO,MAAA;AAAA,IAClB,CAAA,QAAS,MAAA;AAET,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AAG1B,IAAA,IAAI,CAAC,SAAS,SAAA,EAAW;AACvB,MAAA,MAAM,IAAIE,iCAAuB,IAAI,CAAA;AAAA,IACvC;AAGA,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AAAA,EAClC;AAAA,EAEA,MAAM,OAAA,CAAQ,IAAA,EAAc,OAAA,EAA6C;AACvE,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AACtB,IAAA,MAAM,MAAA,GAAS,GAAA,GAAM,CAAA,EAAG,GAAG,CAAA,CAAA,CAAA,GAAM,EAAA;AAEjC,IAAA,MAAM,UAAuB,EAAC;AAC9B,IAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AAEjC,IAAA,IAAI,MAAA;AACJ,IAAA,MAAM,WAAW,OAAA,EAAS,QAAA;AAC1B,IAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,KAAA;AACxC,IAAA,MAAM,UAAA,GAAa,OAAA,EAAS,SAAA,GACxB,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,SAAS,CAAA,GAC7B,OAAA,CAAQ,SAAA,GACR,CAAC,OAAA,CAAQ,SAAS,CAAA,GACpB,MAAA;AAEJ,IAAA,GAAG;AACD,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,GAAA,EAAM,CAAA;AAErE,MAAA,KAAA,MAAW,IAAA,IAAQ,OAAO,KAAA,EAAO;AAG/B,QAAA,MAAM,YAAA,GAAe,SAAS,IAAA,CAAK,GAAA,CAAI,MAAM,MAAA,CAAO,MAAM,IAAI,IAAA,CAAK,GAAA;AACnE,QAAA,IAAI,CAAC,YAAA,EAAc;AAEnB,QAAA,MAAM,QAAA,GAAW,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA;AAEvC,QAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAEzB,UAAA,MAAM,IAAA,GAAO,SAAS,CAAC,CAAA;AAGvB,UAAA,IAAI,UAAA,EAAY;AACd,YAAA,MAAM,GAAA,GAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,KAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAC,CAAA,GAAI,EAAA;AAC/E,YAAA,IAAI,CAAC,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AAAA,UACjC;AAEA,UAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,YACX,IAAA;AAAA,YACA,IAAA,EAAM,MAAA;AAAA,YACN,MAAM,IAAA,CAAK;AAAA,WACZ,CAAA;AAAA,QACH,CAAA,MAAA,IAAW,CAAC,SAAA,EAAW;AAErB,UAAA,MAAM,OAAA,GAAU,SAAS,CAAC,CAAA;AAC1B,UAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA,EAAG;AAC1B,YAAA,QAAA,CAAS,IAAI,OAAO,CAAA;AACpB,YAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,cACX,IAAA,EAAM,OAAA;AAAA,cACN,IAAA,EAAM;AAAA,aACP,CAAA;AAAA,UACH;AAAA,QACF,CAAA,MAAO;AAGL,UAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,YAAA,MAAM,UAAU,QAAA,CAAS,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA;AAC7C,YAAA,MAAM,QAAA,GAAW,CAAA;AACjB,YAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,GAAW,QAAA,EAAU;AACnD,YAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA,EAAG;AAC1B,cAAA,QAAA,CAAS,IAAI,OAAO,CAAA;AACpB,cAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,gBACX,IAAA,EAAM,OAAA;AAAA,gBACN,IAAA,EAAM;AAAA,eACP,CAAA;AAAA,YACH;AAAA,UACF;AAGA,UAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,CAAS,MAAA,GAAS,QAAA,EAAU;AAE1D,UAAA,MAAM,IAAA,GAAO,YAAA;AACb,UAAA,IAAI,UAAA,EAAY;AACd,YAAA,MAAM,GAAA,GAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,KAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAC,CAAA,GAAI,EAAA;AAC/E,YAAA,IAAI,CAAC,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AAAA,UACjC;AAEA,UAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,YACX,IAAA;AAAA,YACA,IAAA,EAAM,MAAA;AAAA,YACN,MAAM,IAAA,CAAK;AAAA,WACZ,CAAA;AAAA,QACH;AAAA,MACF;AAEA,MAAA,MAAA,GAAS,MAAA,CAAO,MAAA;AAAA,IAClB,CAAA,QAAS,MAAA;AAET,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,IAAA,EAAgC;AAC3C,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AAGtB,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AAQjB,IAAA,IAAI,MAAM,IAAA,CAAK,WAAA,CAAY,GAAG,GAAG,OAAO,IAAA;AAOxC,IAAA,OAAO,IAAA,CAAK,OAAO,GAAG,CAAA;AAAA,EACxB;AAAA,EAEA,MAAM,KAAK,IAAA,EAAiC;AAC1C,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAI,CAAA;AAGtB,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,GAAA;AAAA,QACN,IAAA,EAAM,GAAA;AAAA,QACN,IAAA,EAAM,WAAA;AAAA,QACN,IAAA,EAAM,CAAA;AAAA,QACN,SAAA,EAAW,GAAA;AAAA,QACX,UAAA,EAAY;AAAA,OACd;AAAA,IACF;AAGA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,GAAG,CAAA;AACvC,MAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,IAAA,EAAM,IAAI,CAAA;AAAA,IACzC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,CAAC,eAAA,CAAgB,GAAG,CAAA,EAAG,MAAM,GAAA;AAAA,IACnC;AAGA,IAAA,IAAI,MAAM,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,EAAG;AAC/B,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,SAAS,GAAG,CAAA;AAAA,QAClB,IAAA;AAAA,QACA,IAAA,EAAM,WAAA;AAAA,QACN,IAAA,EAAM,CAAA;AAAA,QACN,SAAA,EAAW,GAAA;AAAA,QACX,UAAA,EAAY;AAAA,OACd;AAAA,IACF;AAEA,IAAA,MAAM,IAAIF,4BAAkB,IAAI,CAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,SAAA,EAAyB;AAC9C,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,MAAM,IAAIG,iCAAuB,SAAS,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,YAAY,GAAA,EAA+B;AACvD,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,IAAA,MAAM,MAAA,GAAS,GAAG,GAAG,CAAA,CAAA,CAAA;AACrB,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA,EAAG,CAAA;AAC1D,IAAA,OAAO,MAAA,CAAO,MAAM,MAAA,GAAS,CAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,OAAO,GAAA,EAA+B;AAClD,IAAA,IAAI,CAAC,KAAK,OAAO,KAAA;AACjB,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,EAAE,MAAA,EAAQ,GAAA,EAAK,KAAA,EAAO,EAAA,EAAI,CAAA;AAChE,IAAA,OAAO,OAAO,KAAA,CAAM,IAAA,CAAK,CAAA,IAAA,KAAQ,IAAA,CAAK,QAAQ,GAAG,CAAA;AAAA,EACnD;AAAA;AAAA,EAGQ,gBAAA,CAAiB,MAAqB,IAAA,EAAwB;AACpE,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,QAAA,CAAS,IAAA,CAAK,GAAA,IAAO,IAAI,CAAA;AAAA,MAC/B,IAAA;AAAA,MACA,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,KAAK,IAAA,IAAQ,CAAA;AAAA,MACnB,SAAA,EAAW,KAAK,YAAA,GAAe,IAAI,KAAK,IAAA,CAAK,YAAY,CAAA,mBAAI,IAAI,IAAA,EAAK;AAAA,MACtE,UAAA,EAAY,KAAK,YAAA,GAAe,IAAI,KAAK,IAAA,CAAK,YAAY,CAAA,mBAAI,IAAI,IAAA,EAAK;AAAA,MACvE,QAAA,EAAU,KAAK,IAAA,IAAQ;AAAA,KACzB;AAAA,EACF;AACF;;;AC1kBO,IAAM,0BAAA,GAA4E;AAAA,EACvF,EAAA,EAAI,WAAA;AAAA,EACJ,IAAA,EAAM,4BAAA;AAAA,EACN,WAAA,EAAa,0GAAA;AAAA,EACb,YAAA,EAAc;AAAA,IACZ,IAAA,EAAM,QAAA;AAAA,IACN,QAAA,EAAU,CAAC,OAAO,CAAA;AAAA,IAClB,UAAA,EAAY;AAAA,MACV,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,wCAAA,EAAyC;AAAA,MAC/E,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,sBAAA,EAAuB;AAAA,MAC1D,WAAA,EAAa,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,6BAAA,EAA8B;AAAA,MAC1E,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,wBAAA,EAAyB;AAAA,MAC9D,WAAA,EAAa,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,oBAAA,EAAqB;AAAA,MACjE,UAAU,EAAE,IAAA,EAAM,WAAW,WAAA,EAAa,oBAAA,EAAsB,SAAS,KAAA;AAAM;AACjF,GACF;AAAA,EACA,gBAAA,EAAkB,CAAA,MAAA,KAAU,IAAI,kBAAA,CAAmB,MAAM;AAC3D","file":"index.cjs","sourcesContent":["import type {\n FileContent,\n FileStat,\n FileEntry,\n ReadOptions,\n WriteOptions,\n ListOptions,\n RemoveOptions,\n CopyOptions,\n FilesystemIcon,\n FilesystemInfo,\n ProviderStatus,\n MastraFilesystemOptions,\n} from '@mastra/core/workspace';\nimport {\n MastraFilesystem,\n FileNotFoundError,\n FileExistsError,\n DirectoryNotEmptyError,\n WorkspaceReadOnlyError,\n} from '@mastra/core/workspace';\nimport type { Files, StoredFile as SDKStoredFile } from 'files-sdk';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface FilesSDKFilesystemOptions extends MastraFilesystemOptions {\n /** Pre-configured FilesSDK `Files` instance. */\n files: Files;\n /** Unique filesystem ID (auto-generated if not provided). */\n id?: string;\n /** Human-friendly display name for UI. */\n displayName?: string;\n /** Icon identifier for UI. */\n icon?: FilesystemIcon;\n /** Description shown in UI / instructions. */\n description?: string;\n /** Mount as read-only — all write operations will throw. */\n readOnly?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize a POSIX-style path to an object-storage key.\n * Strips leading slashes, resolves `.`/`./` to empty string.\n */\nfunction toKey(path: string): string {\n // Strip leading slashes (avoid regex backtracking concerns flagged by CodeQL\n // — these are character-class loops that are linear, but explicit indexing\n // sidesteps any analyzer false positives).\n let start = 0;\n while (start < path.length && path.charCodeAt(start) === 47 /* \"/\" */) start++;\n let end = path.length;\n while (end > start && path.charCodeAt(end - 1) === 47) end--;\n const key = path.slice(start, end);\n if (key === '.' || key === './') return '';\n return key;\n}\n\n/**\n * Extract the basename (last path segment) from a key.\n */\nfunction basename(key: string): string {\n const idx = key.lastIndexOf('/');\n return idx === -1 ? key : key.slice(idx + 1);\n}\n\n/**\n * Walk the FilesSDK error code chain.\n *\n * FilesSDK frequently wraps an inner `NotFound` / `Unauthorized` error in an\n * outer `Provider` error (`error.cause` carries the original). Some adapters\n * may wrap multiple levels deep, so we walk the cause chain and return any\n * matching code found along the way.\n */\nfunction hasFilesSDKCode(err: unknown, code: string, depth = 0): boolean {\n if (depth > 5 || !err || typeof err !== 'object') return false;\n const e = err as { code?: unknown; cause?: unknown };\n if (e.code === code) return true;\n if (e.cause) return hasFilesSDKCode(e.cause, code, depth + 1);\n return false;\n}\n\nfunction isNotFoundError(err: unknown): boolean {\n return hasFilesSDKCode(err, 'NotFound');\n}\n\nfunction isUnauthorizedError(err: unknown): boolean {\n return hasFilesSDKCode(err, 'Unauthorized');\n}\n\nfunction generateId(): string {\n return `files-sdk-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * Convert FileContent (string | Buffer | Uint8Array) to a body acceptable by files-sdk.\n */\nfunction toBody(content: FileContent): string | Uint8Array {\n if (typeof content === 'string') return content;\n if (Buffer.isBuffer(content)) return new Uint8Array(content);\n return content;\n}\n\n/**\n * Infer MIME type from a file path extension.\n */\nconst MIME_TYPES: Record<string, string> = {\n '.txt': 'text/plain',\n '.md': 'text/markdown',\n '.markdown': 'text/markdown',\n '.html': 'text/html',\n '.htm': 'text/html',\n '.css': 'text/css',\n '.csv': 'text/csv',\n '.xml': 'text/xml',\n '.js': 'text/javascript',\n '.mjs': 'text/javascript',\n '.ts': 'text/typescript',\n '.tsx': 'text/typescript',\n '.jsx': 'text/javascript',\n '.json': 'application/json',\n '.yaml': 'text/yaml',\n '.yml': 'text/yaml',\n '.py': 'text/x-python',\n '.rb': 'text/x-ruby',\n '.sh': 'text/x-shellscript',\n '.bash': 'text/x-shellscript',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.ico': 'image/x-icon',\n '.pdf': 'application/pdf',\n '.zip': 'application/zip',\n '.gz': 'application/gzip',\n '.tar': 'application/x-tar',\n};\n\nfunction getMimeType(path: string): string {\n const dot = path.lastIndexOf('.');\n if (dot === -1) return 'application/octet-stream';\n return MIME_TYPES[path.slice(dot).toLowerCase()] ?? 'application/octet-stream';\n}\n\n// ---------------------------------------------------------------------------\n// FilesSDKFilesystem\n// ---------------------------------------------------------------------------\n\n/**\n * Workspace filesystem adapter backed by [FilesSDK](https://files-sdk.dev).\n *\n * Accepts a pre-configured `Files` instance so users choose their own adapter\n * (S3, R2, GCS, Azure, local fs, etc.) and this class bridges it to the\n * Mastra `WorkspaceFilesystem` interface.\n *\n * Object-storage semantics are bridged to the POSIX-like interface:\n * - `mkdir` is a no-op (directories don't exist in object storage)\n * - `readdir` uses `list()` with prefix filtering to synthesize directory entries\n * - `rmdir` lists all keys under a prefix and batch-deletes them\n */\nexport class FilesSDKFilesystem extends MastraFilesystem {\n readonly id: string;\n readonly name = 'FilesSDKFilesystem';\n readonly provider = 'files-sdk';\n status: ProviderStatus = 'pending';\n\n readonly readOnly?: boolean;\n readonly icon?: FilesystemIcon;\n readonly displayName?: string;\n readonly description?: string;\n\n private readonly _files: Files;\n\n constructor(options: FilesSDKFilesystemOptions) {\n super({ name: 'FilesSDKFilesystem', ...options });\n\n this._files = options.files;\n this.id = options.id ?? generateId();\n this.readOnly = options.readOnly;\n this.icon = options.icon;\n this.displayName = options.displayName;\n this.description = options.description;\n }\n\n /** The underlying FilesSDK instance, for escape-hatch access. */\n get files(): Files {\n return this._files;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n override async init(): Promise<void> {\n // Verify connectivity by listing at most 1 key\n try {\n await this._files.list({ limit: 1 });\n } catch (err) {\n if (isUnauthorizedError(err)) {\n throw new Error('Access denied — check credentials and storage permissions');\n }\n throw err;\n }\n }\n\n // destroy() — default no-op is fine; FilesSDK has no explicit teardown.\n\n getInfo(): FilesystemInfo {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n error: this.error,\n readOnly: this.readOnly,\n icon: this.icon,\n metadata: {\n adapter: this._files.adapter?.name ?? 'unknown',\n },\n };\n }\n\n getInstructions(): string {\n const adapterName = this._files.adapter?.name ?? 'unknown';\n const parts = [`Unified storage via FilesSDK (${adapterName} adapter).`];\n if (this.readOnly) parts.push('Mounted read-only.');\n parts.push('Persistent storage — files are retained across sessions.');\n return parts.join(' ');\n }\n\n // ---------------------------------------------------------------------------\n // File operations\n // ---------------------------------------------------------------------------\n\n async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {\n await this.ensureReady();\n const key = toKey(path);\n\n try {\n const file = await this._files.download(key);\n const buf = Buffer.from(await file.arrayBuffer());\n if (options?.encoding) return buf.toString(options.encoding);\n return buf;\n } catch (err) {\n if (isNotFoundError(err)) throw new FileNotFoundError(path);\n throw err;\n }\n }\n\n async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('writeFile');\n const key = toKey(path);\n\n // Respect overwrite option (default: true). Use isFile() rather than\n // _files.exists() so leftover empty directories (some adapters) don't\n // incorrectly trigger FileExistsError.\n if (options?.overwrite === false && (await this.isFile(key))) {\n throw new FileExistsError(path);\n }\n\n const body = toBody(content);\n await this._files.upload(key, body, {\n contentType: options?.mimeType ?? getMimeType(path),\n });\n }\n\n /**\n * Append content to a file.\n *\n * **Not atomic.** Object storage has no native append, so this is implemented\n * as a read-modify-write: the existing object is downloaded, the new content\n * is concatenated, and the result is uploaded as a new object. Concurrent\n * appends to the same key may overwrite each other. This limitation is\n * inherent to object storage, not specific to FilesSDK, and matches the\n * behavior of the sibling S3, GCS, and Azure workspace providers.\n */\n async appendFile(path: string, content: FileContent): Promise<void> {\n await this.ensureReady();\n this.assertWritable('appendFile');\n const key = toKey(path);\n\n // Read-modify-write (object storage has no native append)\n let existing = Buffer.alloc(0);\n try {\n const file = await this._files.download(key);\n existing = Buffer.from(await file.arrayBuffer());\n } catch (err) {\n if (!isNotFoundError(err)) throw err;\n // File doesn't exist yet — start fresh\n }\n\n const append = typeof content === 'string' ? Buffer.from(content) : toBody(content);\n const merged = Buffer.concat([existing, Buffer.isBuffer(append) ? append : Buffer.from(append as Uint8Array)]);\n\n await this._files.upload(key, new Uint8Array(merged), {\n contentType: getMimeType(path),\n });\n }\n\n async deleteFile(path: string, options?: RemoveOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('deleteFile');\n const key = toKey(path);\n\n // If the path is a directory, recursively delete (matches sibling\n // filesystems like S3/GCS). Object storage has no first-class directories,\n // so callers calling deleteFile on a prefix expect it to clean up.\n if (await this.isDirectory(key)) {\n await this.rmdir(path, { recursive: true, force: options?.force });\n return;\n }\n\n // Some FilesSDK adapters (notably the local `fs` adapter) silently succeed\n // when deleting a non-existent key instead of raising `NotFound`. Match the\n // shared filesystem contract (and S3/GCS behavior) by checking existence\n // first when `force` is not set.\n if (!options?.force && !(await this.isFile(key))) {\n throw new FileNotFoundError(path);\n }\n\n try {\n await this._files.delete(key);\n } catch (err) {\n if (options?.force) return;\n if (isNotFoundError(err)) throw new FileNotFoundError(path);\n throw err;\n }\n }\n\n async copyFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('copyFile');\n const fromKey = toKey(src);\n const toKey_ = toKey(dest);\n\n if (options?.overwrite === false && (await this.isFile(toKey_))) {\n throw new FileExistsError(dest);\n }\n\n try {\n await this._files.copy(fromKey, toKey_);\n } catch (err) {\n if (isNotFoundError(err)) throw new FileNotFoundError(src);\n throw err;\n }\n }\n\n async moveFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n // Object storage has no atomic rename. Mirrors the S3/GCS pattern:\n // copy first; if that succeeds, force-delete the source.\n await this.copyFile(src, dest, options);\n await this.deleteFile(src, { force: true });\n }\n\n // ---------------------------------------------------------------------------\n // Directory operations\n // ---------------------------------------------------------------------------\n\n async mkdir(_path: string, _options?: { recursive?: boolean }): Promise<void> {\n await this.ensureReady();\n this.assertWritable('mkdir');\n // No-op: object storage creates \"directories\" implicitly on file write.\n }\n\n async rmdir(path: string, options?: RemoveOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('rmdir');\n const key = toKey(path);\n const prefix = key ? `${key}/` : '';\n\n // List all keys under the prefix\n const allKeys: string[] = [];\n let cursor: string | undefined;\n\n do {\n const result = await this._files.list({ prefix, cursor, limit: 1000 });\n for (const item of result.items) {\n allKeys.push(item.key);\n }\n cursor = result.cursor;\n } while (cursor);\n\n if (allKeys.length === 0) return;\n\n // Non-recursive: fail if directory is not empty\n if (!options?.recursive) {\n throw new DirectoryNotEmptyError(path);\n }\n\n // Batch delete all keys\n await this._files.delete(allKeys);\n }\n\n async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n await this.ensureReady();\n const key = toKey(path);\n const prefix = key ? `${key}/` : '';\n\n const entries: FileEntry[] = [];\n const seenDirs = new Set<string>();\n\n let cursor: string | undefined;\n const maxDepth = options?.maxDepth;\n const recursive = options?.recursive ?? false;\n const extensions = options?.extension\n ? Array.isArray(options.extension)\n ? options.extension\n : [options.extension]\n : undefined;\n\n do {\n const result = await this._files.list({ prefix, cursor, limit: 1000 });\n\n for (const item of result.items) {\n // item.key is relative to the Files instance's prefix.\n // We need to get the portion after our directory prefix.\n const relativePath = prefix ? item.key.slice(prefix.length) : item.key;\n if (!relativePath) continue;\n\n const segments = relativePath.split('/');\n\n if (segments.length === 1) {\n // Direct child (file)\n const name = segments[0]!;\n\n // Extension filter\n if (extensions) {\n const ext = name.lastIndexOf('.') !== -1 ? name.slice(name.lastIndexOf('.')) : '';\n if (!extensions.includes(ext)) continue;\n }\n\n entries.push({\n name,\n type: 'file',\n size: item.size,\n });\n } else if (!recursive) {\n // Non-recursive: synthesize a directory entry for the first segment only.\n const dirName = segments[0]!;\n if (!seenDirs.has(dirName)) {\n seenDirs.add(dirName);\n entries.push({\n name: dirName,\n type: 'directory',\n });\n }\n } else {\n // Recursive: emit every intermediate directory along the path, then the file.\n // For \"a/b/c/file.txt\": emit \"a\", \"a/b\", \"a/b/c\" as directories, then the file.\n for (let i = 1; i < segments.length; i++) {\n const dirPath = segments.slice(0, i).join('/');\n const dirDepth = i; // number of segments in dirPath\n if (maxDepth !== undefined && dirDepth > maxDepth) continue;\n if (!seenDirs.has(dirPath)) {\n seenDirs.add(dirPath);\n entries.push({\n name: dirPath,\n type: 'directory',\n });\n }\n }\n\n // Depth check for the file itself\n if (maxDepth !== undefined && segments.length > maxDepth) continue;\n\n const name = relativePath;\n if (extensions) {\n const ext = name.lastIndexOf('.') !== -1 ? name.slice(name.lastIndexOf('.')) : '';\n if (!extensions.includes(ext)) continue;\n }\n\n entries.push({\n name,\n type: 'file',\n size: item.size,\n });\n }\n }\n\n cursor = result.cursor;\n } while (cursor);\n\n return entries;\n }\n\n // ---------------------------------------------------------------------------\n // Path operations\n // ---------------------------------------------------------------------------\n\n async exists(path: string): Promise<boolean> {\n await this.ensureReady();\n const key = toKey(path);\n\n // Root always exists\n if (!key) return true;\n\n // Check as directory first (any key under this prefix). Doing the prefix\n // list before the per-key check matters for adapters like FilesSDK's `fs`\n // that leave empty parent directories on disk after their contents are\n // deleted — those would otherwise report true via `_files.exists` even\n // though no objects exist there. Object-store semantics: a \"directory\"\n // exists iff it has children.\n if (await this.isDirectory(key)) return true;\n\n // Check as a real stored file. We deliberately avoid `_files.exists(key)`\n // here because some adapters (e.g. the local `fs` adapter) consider an\n // empty leftover directory to exist as a key, which would break\n // object-store semantics. A prefix list constrained to the exact key only\n // matches actually-stored files.\n return this.isFile(key);\n }\n\n async stat(path: string): Promise<FileStat> {\n await this.ensureReady();\n const key = toKey(path);\n\n // Root is a directory\n if (!key) {\n const now = new Date();\n return {\n name: '/',\n path: '/',\n type: 'directory',\n size: 0,\n createdAt: now,\n modifiedAt: now,\n };\n }\n\n // Try as file first\n try {\n const file = await this._files.head(key);\n return this.storedFileToStat(file, path);\n } catch (err) {\n if (!isNotFoundError(err)) throw err;\n }\n\n // Try as directory\n if (await this.isDirectory(key)) {\n const now = new Date();\n return {\n name: basename(key),\n path,\n type: 'directory',\n size: 0,\n createdAt: now,\n modifiedAt: now,\n };\n }\n\n throw new FileNotFoundError(path);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private assertWritable(operation: string): void {\n if (this.readOnly) {\n throw new WorkspaceReadOnlyError(operation);\n }\n }\n\n /** Check if a key prefix has any children (i.e. acts like a directory). */\n private async isDirectory(key: string): Promise<boolean> {\n if (!key) return true; // root\n const prefix = `${key}/`;\n const result = await this._files.list({ prefix, limit: 1 });\n return result.items.length > 0;\n }\n\n /**\n * Check whether `key` refers to a real stored file (not an empty leftover\n * directory). Uses prefix listing constrained to the exact key, which only\n * matches actually-stored objects across all adapters.\n */\n private async isFile(key: string): Promise<boolean> {\n if (!key) return false;\n const result = await this._files.list({ prefix: key, limit: 10 });\n return result.items.some(item => item.key === key);\n }\n\n /** Convert a FilesSDK StoredFile to a Mastra FileStat. */\n private storedFileToStat(file: SDKStoredFile, path: string): FileStat {\n return {\n name: basename(file.key ?? path),\n path,\n type: 'file',\n size: file.size ?? 0,\n createdAt: file.lastModified ? new Date(file.lastModified) : new Date(),\n modifiedAt: file.lastModified ? new Date(file.lastModified) : new Date(),\n mimeType: file.type || undefined,\n };\n }\n}\n","/**\n * FilesSDK filesystem provider descriptor for MastraEditor.\n *\n * @example\n * ```typescript\n * import { filesSDKFilesystemProvider } from '@mastra/files-sdk';\n *\n * const editor = new MastraEditor({\n * filesystems: [filesSDKFilesystemProvider],\n * });\n * ```\n */\nimport type { FilesystemProvider } from '@mastra/core/editor';\nimport { FilesSDKFilesystem } from './filesystem';\nimport type { FilesSDKFilesystemOptions } from './filesystem';\n\nexport const filesSDKFilesystemProvider: FilesystemProvider<FilesSDKFilesystemOptions> = {\n id: 'files-sdk',\n name: 'FilesSDK (Unified Storage)',\n description: 'Unified storage via FilesSDK — supports S3, R2, GCS, Azure, Vercel Blob, local filesystem, and more',\n configSchema: {\n type: 'object',\n required: ['files'],\n properties: {\n files: { type: 'object', description: 'Pre-configured FilesSDK Files instance' },\n id: { type: 'string', description: 'Unique filesystem ID' },\n displayName: { type: 'string', description: 'Human-friendly display name' },\n icon: { type: 'string', description: 'Icon identifier for UI' },\n description: { type: 'string', description: 'Description for UI' },\n readOnly: { type: 'boolean', description: 'Mount as read-only', default: false },\n },\n },\n createFilesystem: config => new FilesSDKFilesystem(config),\n};\n"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @mastra/files-sdk - Unified Storage Filesystem Provider
3
+ *
4
+ * A filesystem implementation backed by FilesSDK (https://files-sdk.dev).
5
+ * Works with any FilesSDK adapter: S3, R2, GCS, Azure Blob, Vercel Blob,
6
+ * local filesystem, and more.
7
+ */
8
+ export { FilesSDKFilesystem, type FilesSDKFilesystemOptions } from './filesystem/index.js';
9
+ export { filesSDKFilesystemProvider } from './provider.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,424 @@
1
+ import { MastraFilesystem, FileNotFoundError, FileExistsError, DirectoryNotEmptyError, WorkspaceReadOnlyError } from '@mastra/core/workspace';
2
+
3
+ // src/filesystem/index.ts
4
+ function toKey(path) {
5
+ let start = 0;
6
+ while (start < path.length && path.charCodeAt(start) === 47) start++;
7
+ let end = path.length;
8
+ while (end > start && path.charCodeAt(end - 1) === 47) end--;
9
+ const key = path.slice(start, end);
10
+ if (key === "." || key === "./") return "";
11
+ return key;
12
+ }
13
+ function basename(key) {
14
+ const idx = key.lastIndexOf("/");
15
+ return idx === -1 ? key : key.slice(idx + 1);
16
+ }
17
+ function hasFilesSDKCode(err, code, depth = 0) {
18
+ if (depth > 5 || !err || typeof err !== "object") return false;
19
+ const e = err;
20
+ if (e.code === code) return true;
21
+ if (e.cause) return hasFilesSDKCode(e.cause, code, depth + 1);
22
+ return false;
23
+ }
24
+ function isNotFoundError(err) {
25
+ return hasFilesSDKCode(err, "NotFound");
26
+ }
27
+ function isUnauthorizedError(err) {
28
+ return hasFilesSDKCode(err, "Unauthorized");
29
+ }
30
+ function generateId() {
31
+ return `files-sdk-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
32
+ }
33
+ function toBody(content) {
34
+ if (typeof content === "string") return content;
35
+ if (Buffer.isBuffer(content)) return new Uint8Array(content);
36
+ return content;
37
+ }
38
+ var MIME_TYPES = {
39
+ ".txt": "text/plain",
40
+ ".md": "text/markdown",
41
+ ".markdown": "text/markdown",
42
+ ".html": "text/html",
43
+ ".htm": "text/html",
44
+ ".css": "text/css",
45
+ ".csv": "text/csv",
46
+ ".xml": "text/xml",
47
+ ".js": "text/javascript",
48
+ ".mjs": "text/javascript",
49
+ ".ts": "text/typescript",
50
+ ".tsx": "text/typescript",
51
+ ".jsx": "text/javascript",
52
+ ".json": "application/json",
53
+ ".yaml": "text/yaml",
54
+ ".yml": "text/yaml",
55
+ ".py": "text/x-python",
56
+ ".rb": "text/x-ruby",
57
+ ".sh": "text/x-shellscript",
58
+ ".bash": "text/x-shellscript",
59
+ ".png": "image/png",
60
+ ".jpg": "image/jpeg",
61
+ ".jpeg": "image/jpeg",
62
+ ".gif": "image/gif",
63
+ ".svg": "image/svg+xml",
64
+ ".webp": "image/webp",
65
+ ".ico": "image/x-icon",
66
+ ".pdf": "application/pdf",
67
+ ".zip": "application/zip",
68
+ ".gz": "application/gzip",
69
+ ".tar": "application/x-tar"
70
+ };
71
+ function getMimeType(path) {
72
+ const dot = path.lastIndexOf(".");
73
+ if (dot === -1) return "application/octet-stream";
74
+ return MIME_TYPES[path.slice(dot).toLowerCase()] ?? "application/octet-stream";
75
+ }
76
+ var FilesSDKFilesystem = class extends MastraFilesystem {
77
+ id;
78
+ name = "FilesSDKFilesystem";
79
+ provider = "files-sdk";
80
+ status = "pending";
81
+ readOnly;
82
+ icon;
83
+ displayName;
84
+ description;
85
+ _files;
86
+ constructor(options) {
87
+ super({ name: "FilesSDKFilesystem", ...options });
88
+ this._files = options.files;
89
+ this.id = options.id ?? generateId();
90
+ this.readOnly = options.readOnly;
91
+ this.icon = options.icon;
92
+ this.displayName = options.displayName;
93
+ this.description = options.description;
94
+ }
95
+ /** The underlying FilesSDK instance, for escape-hatch access. */
96
+ get files() {
97
+ return this._files;
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Lifecycle
101
+ // ---------------------------------------------------------------------------
102
+ async init() {
103
+ try {
104
+ await this._files.list({ limit: 1 });
105
+ } catch (err) {
106
+ if (isUnauthorizedError(err)) {
107
+ throw new Error("Access denied \u2014 check credentials and storage permissions");
108
+ }
109
+ throw err;
110
+ }
111
+ }
112
+ // destroy() — default no-op is fine; FilesSDK has no explicit teardown.
113
+ getInfo() {
114
+ return {
115
+ id: this.id,
116
+ name: this.name,
117
+ provider: this.provider,
118
+ status: this.status,
119
+ error: this.error,
120
+ readOnly: this.readOnly,
121
+ icon: this.icon,
122
+ metadata: {
123
+ adapter: this._files.adapter?.name ?? "unknown"
124
+ }
125
+ };
126
+ }
127
+ getInstructions() {
128
+ const adapterName = this._files.adapter?.name ?? "unknown";
129
+ const parts = [`Unified storage via FilesSDK (${adapterName} adapter).`];
130
+ if (this.readOnly) parts.push("Mounted read-only.");
131
+ parts.push("Persistent storage \u2014 files are retained across sessions.");
132
+ return parts.join(" ");
133
+ }
134
+ // ---------------------------------------------------------------------------
135
+ // File operations
136
+ // ---------------------------------------------------------------------------
137
+ async readFile(path, options) {
138
+ await this.ensureReady();
139
+ const key = toKey(path);
140
+ try {
141
+ const file = await this._files.download(key);
142
+ const buf = Buffer.from(await file.arrayBuffer());
143
+ if (options?.encoding) return buf.toString(options.encoding);
144
+ return buf;
145
+ } catch (err) {
146
+ if (isNotFoundError(err)) throw new FileNotFoundError(path);
147
+ throw err;
148
+ }
149
+ }
150
+ async writeFile(path, content, options) {
151
+ await this.ensureReady();
152
+ this.assertWritable("writeFile");
153
+ const key = toKey(path);
154
+ if (options?.overwrite === false && await this.isFile(key)) {
155
+ throw new FileExistsError(path);
156
+ }
157
+ const body = toBody(content);
158
+ await this._files.upload(key, body, {
159
+ contentType: options?.mimeType ?? getMimeType(path)
160
+ });
161
+ }
162
+ /**
163
+ * Append content to a file.
164
+ *
165
+ * **Not atomic.** Object storage has no native append, so this is implemented
166
+ * as a read-modify-write: the existing object is downloaded, the new content
167
+ * is concatenated, and the result is uploaded as a new object. Concurrent
168
+ * appends to the same key may overwrite each other. This limitation is
169
+ * inherent to object storage, not specific to FilesSDK, and matches the
170
+ * behavior of the sibling S3, GCS, and Azure workspace providers.
171
+ */
172
+ async appendFile(path, content) {
173
+ await this.ensureReady();
174
+ this.assertWritable("appendFile");
175
+ const key = toKey(path);
176
+ let existing = Buffer.alloc(0);
177
+ try {
178
+ const file = await this._files.download(key);
179
+ existing = Buffer.from(await file.arrayBuffer());
180
+ } catch (err) {
181
+ if (!isNotFoundError(err)) throw err;
182
+ }
183
+ const append = typeof content === "string" ? Buffer.from(content) : toBody(content);
184
+ const merged = Buffer.concat([existing, Buffer.isBuffer(append) ? append : Buffer.from(append)]);
185
+ await this._files.upload(key, new Uint8Array(merged), {
186
+ contentType: getMimeType(path)
187
+ });
188
+ }
189
+ async deleteFile(path, options) {
190
+ await this.ensureReady();
191
+ this.assertWritable("deleteFile");
192
+ const key = toKey(path);
193
+ if (await this.isDirectory(key)) {
194
+ await this.rmdir(path, { recursive: true, force: options?.force });
195
+ return;
196
+ }
197
+ if (!options?.force && !await this.isFile(key)) {
198
+ throw new FileNotFoundError(path);
199
+ }
200
+ try {
201
+ await this._files.delete(key);
202
+ } catch (err) {
203
+ if (options?.force) return;
204
+ if (isNotFoundError(err)) throw new FileNotFoundError(path);
205
+ throw err;
206
+ }
207
+ }
208
+ async copyFile(src, dest, options) {
209
+ await this.ensureReady();
210
+ this.assertWritable("copyFile");
211
+ const fromKey = toKey(src);
212
+ const toKey_ = toKey(dest);
213
+ if (options?.overwrite === false && await this.isFile(toKey_)) {
214
+ throw new FileExistsError(dest);
215
+ }
216
+ try {
217
+ await this._files.copy(fromKey, toKey_);
218
+ } catch (err) {
219
+ if (isNotFoundError(err)) throw new FileNotFoundError(src);
220
+ throw err;
221
+ }
222
+ }
223
+ async moveFile(src, dest, options) {
224
+ await this.copyFile(src, dest, options);
225
+ await this.deleteFile(src, { force: true });
226
+ }
227
+ // ---------------------------------------------------------------------------
228
+ // Directory operations
229
+ // ---------------------------------------------------------------------------
230
+ async mkdir(_path, _options) {
231
+ await this.ensureReady();
232
+ this.assertWritable("mkdir");
233
+ }
234
+ async rmdir(path, options) {
235
+ await this.ensureReady();
236
+ this.assertWritable("rmdir");
237
+ const key = toKey(path);
238
+ const prefix = key ? `${key}/` : "";
239
+ const allKeys = [];
240
+ let cursor;
241
+ do {
242
+ const result = await this._files.list({ prefix, cursor, limit: 1e3 });
243
+ for (const item of result.items) {
244
+ allKeys.push(item.key);
245
+ }
246
+ cursor = result.cursor;
247
+ } while (cursor);
248
+ if (allKeys.length === 0) return;
249
+ if (!options?.recursive) {
250
+ throw new DirectoryNotEmptyError(path);
251
+ }
252
+ await this._files.delete(allKeys);
253
+ }
254
+ async readdir(path, options) {
255
+ await this.ensureReady();
256
+ const key = toKey(path);
257
+ const prefix = key ? `${key}/` : "";
258
+ const entries = [];
259
+ const seenDirs = /* @__PURE__ */ new Set();
260
+ let cursor;
261
+ const maxDepth = options?.maxDepth;
262
+ const recursive = options?.recursive ?? false;
263
+ const extensions = options?.extension ? Array.isArray(options.extension) ? options.extension : [options.extension] : void 0;
264
+ do {
265
+ const result = await this._files.list({ prefix, cursor, limit: 1e3 });
266
+ for (const item of result.items) {
267
+ const relativePath = prefix ? item.key.slice(prefix.length) : item.key;
268
+ if (!relativePath) continue;
269
+ const segments = relativePath.split("/");
270
+ if (segments.length === 1) {
271
+ const name = segments[0];
272
+ if (extensions) {
273
+ const ext = name.lastIndexOf(".") !== -1 ? name.slice(name.lastIndexOf(".")) : "";
274
+ if (!extensions.includes(ext)) continue;
275
+ }
276
+ entries.push({
277
+ name,
278
+ type: "file",
279
+ size: item.size
280
+ });
281
+ } else if (!recursive) {
282
+ const dirName = segments[0];
283
+ if (!seenDirs.has(dirName)) {
284
+ seenDirs.add(dirName);
285
+ entries.push({
286
+ name: dirName,
287
+ type: "directory"
288
+ });
289
+ }
290
+ } else {
291
+ for (let i = 1; i < segments.length; i++) {
292
+ const dirPath = segments.slice(0, i).join("/");
293
+ const dirDepth = i;
294
+ if (maxDepth !== void 0 && dirDepth > maxDepth) continue;
295
+ if (!seenDirs.has(dirPath)) {
296
+ seenDirs.add(dirPath);
297
+ entries.push({
298
+ name: dirPath,
299
+ type: "directory"
300
+ });
301
+ }
302
+ }
303
+ if (maxDepth !== void 0 && segments.length > maxDepth) continue;
304
+ const name = relativePath;
305
+ if (extensions) {
306
+ const ext = name.lastIndexOf(".") !== -1 ? name.slice(name.lastIndexOf(".")) : "";
307
+ if (!extensions.includes(ext)) continue;
308
+ }
309
+ entries.push({
310
+ name,
311
+ type: "file",
312
+ size: item.size
313
+ });
314
+ }
315
+ }
316
+ cursor = result.cursor;
317
+ } while (cursor);
318
+ return entries;
319
+ }
320
+ // ---------------------------------------------------------------------------
321
+ // Path operations
322
+ // ---------------------------------------------------------------------------
323
+ async exists(path) {
324
+ await this.ensureReady();
325
+ const key = toKey(path);
326
+ if (!key) return true;
327
+ if (await this.isDirectory(key)) return true;
328
+ return this.isFile(key);
329
+ }
330
+ async stat(path) {
331
+ await this.ensureReady();
332
+ const key = toKey(path);
333
+ if (!key) {
334
+ const now = /* @__PURE__ */ new Date();
335
+ return {
336
+ name: "/",
337
+ path: "/",
338
+ type: "directory",
339
+ size: 0,
340
+ createdAt: now,
341
+ modifiedAt: now
342
+ };
343
+ }
344
+ try {
345
+ const file = await this._files.head(key);
346
+ return this.storedFileToStat(file, path);
347
+ } catch (err) {
348
+ if (!isNotFoundError(err)) throw err;
349
+ }
350
+ if (await this.isDirectory(key)) {
351
+ const now = /* @__PURE__ */ new Date();
352
+ return {
353
+ name: basename(key),
354
+ path,
355
+ type: "directory",
356
+ size: 0,
357
+ createdAt: now,
358
+ modifiedAt: now
359
+ };
360
+ }
361
+ throw new FileNotFoundError(path);
362
+ }
363
+ // ---------------------------------------------------------------------------
364
+ // Private helpers
365
+ // ---------------------------------------------------------------------------
366
+ assertWritable(operation) {
367
+ if (this.readOnly) {
368
+ throw new WorkspaceReadOnlyError(operation);
369
+ }
370
+ }
371
+ /** Check if a key prefix has any children (i.e. acts like a directory). */
372
+ async isDirectory(key) {
373
+ if (!key) return true;
374
+ const prefix = `${key}/`;
375
+ const result = await this._files.list({ prefix, limit: 1 });
376
+ return result.items.length > 0;
377
+ }
378
+ /**
379
+ * Check whether `key` refers to a real stored file (not an empty leftover
380
+ * directory). Uses prefix listing constrained to the exact key, which only
381
+ * matches actually-stored objects across all adapters.
382
+ */
383
+ async isFile(key) {
384
+ if (!key) return false;
385
+ const result = await this._files.list({ prefix: key, limit: 10 });
386
+ return result.items.some((item) => item.key === key);
387
+ }
388
+ /** Convert a FilesSDK StoredFile to a Mastra FileStat. */
389
+ storedFileToStat(file, path) {
390
+ return {
391
+ name: basename(file.key ?? path),
392
+ path,
393
+ type: "file",
394
+ size: file.size ?? 0,
395
+ createdAt: file.lastModified ? new Date(file.lastModified) : /* @__PURE__ */ new Date(),
396
+ modifiedAt: file.lastModified ? new Date(file.lastModified) : /* @__PURE__ */ new Date(),
397
+ mimeType: file.type || void 0
398
+ };
399
+ }
400
+ };
401
+
402
+ // src/provider.ts
403
+ var filesSDKFilesystemProvider = {
404
+ id: "files-sdk",
405
+ name: "FilesSDK (Unified Storage)",
406
+ description: "Unified storage via FilesSDK \u2014 supports S3, R2, GCS, Azure, Vercel Blob, local filesystem, and more",
407
+ configSchema: {
408
+ type: "object",
409
+ required: ["files"],
410
+ properties: {
411
+ files: { type: "object", description: "Pre-configured FilesSDK Files instance" },
412
+ id: { type: "string", description: "Unique filesystem ID" },
413
+ displayName: { type: "string", description: "Human-friendly display name" },
414
+ icon: { type: "string", description: "Icon identifier for UI" },
415
+ description: { type: "string", description: "Description for UI" },
416
+ readOnly: { type: "boolean", description: "Mount as read-only", default: false }
417
+ }
418
+ },
419
+ createFilesystem: (config) => new FilesSDKFilesystem(config)
420
+ };
421
+
422
+ export { FilesSDKFilesystem, filesSDKFilesystemProvider };
423
+ //# sourceMappingURL=index.js.map
424
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/filesystem/index.ts","../src/provider.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n FileContent,\n FileStat,\n FileEntry,\n ReadOptions,\n WriteOptions,\n ListOptions,\n RemoveOptions,\n CopyOptions,\n FilesystemIcon,\n FilesystemInfo,\n ProviderStatus,\n MastraFilesystemOptions,\n} from '@mastra/core/workspace';\nimport {\n MastraFilesystem,\n FileNotFoundError,\n FileExistsError,\n DirectoryNotEmptyError,\n WorkspaceReadOnlyError,\n} from '@mastra/core/workspace';\nimport type { Files, StoredFile as SDKStoredFile } from 'files-sdk';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface FilesSDKFilesystemOptions extends MastraFilesystemOptions {\n /** Pre-configured FilesSDK `Files` instance. */\n files: Files;\n /** Unique filesystem ID (auto-generated if not provided). */\n id?: string;\n /** Human-friendly display name for UI. */\n displayName?: string;\n /** Icon identifier for UI. */\n icon?: FilesystemIcon;\n /** Description shown in UI / instructions. */\n description?: string;\n /** Mount as read-only — all write operations will throw. */\n readOnly?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize a POSIX-style path to an object-storage key.\n * Strips leading slashes, resolves `.`/`./` to empty string.\n */\nfunction toKey(path: string): string {\n // Strip leading slashes (avoid regex backtracking concerns flagged by CodeQL\n // — these are character-class loops that are linear, but explicit indexing\n // sidesteps any analyzer false positives).\n let start = 0;\n while (start < path.length && path.charCodeAt(start) === 47 /* \"/\" */) start++;\n let end = path.length;\n while (end > start && path.charCodeAt(end - 1) === 47) end--;\n const key = path.slice(start, end);\n if (key === '.' || key === './') return '';\n return key;\n}\n\n/**\n * Extract the basename (last path segment) from a key.\n */\nfunction basename(key: string): string {\n const idx = key.lastIndexOf('/');\n return idx === -1 ? key : key.slice(idx + 1);\n}\n\n/**\n * Walk the FilesSDK error code chain.\n *\n * FilesSDK frequently wraps an inner `NotFound` / `Unauthorized` error in an\n * outer `Provider` error (`error.cause` carries the original). Some adapters\n * may wrap multiple levels deep, so we walk the cause chain and return any\n * matching code found along the way.\n */\nfunction hasFilesSDKCode(err: unknown, code: string, depth = 0): boolean {\n if (depth > 5 || !err || typeof err !== 'object') return false;\n const e = err as { code?: unknown; cause?: unknown };\n if (e.code === code) return true;\n if (e.cause) return hasFilesSDKCode(e.cause, code, depth + 1);\n return false;\n}\n\nfunction isNotFoundError(err: unknown): boolean {\n return hasFilesSDKCode(err, 'NotFound');\n}\n\nfunction isUnauthorizedError(err: unknown): boolean {\n return hasFilesSDKCode(err, 'Unauthorized');\n}\n\nfunction generateId(): string {\n return `files-sdk-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * Convert FileContent (string | Buffer | Uint8Array) to a body acceptable by files-sdk.\n */\nfunction toBody(content: FileContent): string | Uint8Array {\n if (typeof content === 'string') return content;\n if (Buffer.isBuffer(content)) return new Uint8Array(content);\n return content;\n}\n\n/**\n * Infer MIME type from a file path extension.\n */\nconst MIME_TYPES: Record<string, string> = {\n '.txt': 'text/plain',\n '.md': 'text/markdown',\n '.markdown': 'text/markdown',\n '.html': 'text/html',\n '.htm': 'text/html',\n '.css': 'text/css',\n '.csv': 'text/csv',\n '.xml': 'text/xml',\n '.js': 'text/javascript',\n '.mjs': 'text/javascript',\n '.ts': 'text/typescript',\n '.tsx': 'text/typescript',\n '.jsx': 'text/javascript',\n '.json': 'application/json',\n '.yaml': 'text/yaml',\n '.yml': 'text/yaml',\n '.py': 'text/x-python',\n '.rb': 'text/x-ruby',\n '.sh': 'text/x-shellscript',\n '.bash': 'text/x-shellscript',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.ico': 'image/x-icon',\n '.pdf': 'application/pdf',\n '.zip': 'application/zip',\n '.gz': 'application/gzip',\n '.tar': 'application/x-tar',\n};\n\nfunction getMimeType(path: string): string {\n const dot = path.lastIndexOf('.');\n if (dot === -1) return 'application/octet-stream';\n return MIME_TYPES[path.slice(dot).toLowerCase()] ?? 'application/octet-stream';\n}\n\n// ---------------------------------------------------------------------------\n// FilesSDKFilesystem\n// ---------------------------------------------------------------------------\n\n/**\n * Workspace filesystem adapter backed by [FilesSDK](https://files-sdk.dev).\n *\n * Accepts a pre-configured `Files` instance so users choose their own adapter\n * (S3, R2, GCS, Azure, local fs, etc.) and this class bridges it to the\n * Mastra `WorkspaceFilesystem` interface.\n *\n * Object-storage semantics are bridged to the POSIX-like interface:\n * - `mkdir` is a no-op (directories don't exist in object storage)\n * - `readdir` uses `list()` with prefix filtering to synthesize directory entries\n * - `rmdir` lists all keys under a prefix and batch-deletes them\n */\nexport class FilesSDKFilesystem extends MastraFilesystem {\n readonly id: string;\n readonly name = 'FilesSDKFilesystem';\n readonly provider = 'files-sdk';\n status: ProviderStatus = 'pending';\n\n readonly readOnly?: boolean;\n readonly icon?: FilesystemIcon;\n readonly displayName?: string;\n readonly description?: string;\n\n private readonly _files: Files;\n\n constructor(options: FilesSDKFilesystemOptions) {\n super({ name: 'FilesSDKFilesystem', ...options });\n\n this._files = options.files;\n this.id = options.id ?? generateId();\n this.readOnly = options.readOnly;\n this.icon = options.icon;\n this.displayName = options.displayName;\n this.description = options.description;\n }\n\n /** The underlying FilesSDK instance, for escape-hatch access. */\n get files(): Files {\n return this._files;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n override async init(): Promise<void> {\n // Verify connectivity by listing at most 1 key\n try {\n await this._files.list({ limit: 1 });\n } catch (err) {\n if (isUnauthorizedError(err)) {\n throw new Error('Access denied — check credentials and storage permissions');\n }\n throw err;\n }\n }\n\n // destroy() — default no-op is fine; FilesSDK has no explicit teardown.\n\n getInfo(): FilesystemInfo {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n error: this.error,\n readOnly: this.readOnly,\n icon: this.icon,\n metadata: {\n adapter: this._files.adapter?.name ?? 'unknown',\n },\n };\n }\n\n getInstructions(): string {\n const adapterName = this._files.adapter?.name ?? 'unknown';\n const parts = [`Unified storage via FilesSDK (${adapterName} adapter).`];\n if (this.readOnly) parts.push('Mounted read-only.');\n parts.push('Persistent storage — files are retained across sessions.');\n return parts.join(' ');\n }\n\n // ---------------------------------------------------------------------------\n // File operations\n // ---------------------------------------------------------------------------\n\n async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {\n await this.ensureReady();\n const key = toKey(path);\n\n try {\n const file = await this._files.download(key);\n const buf = Buffer.from(await file.arrayBuffer());\n if (options?.encoding) return buf.toString(options.encoding);\n return buf;\n } catch (err) {\n if (isNotFoundError(err)) throw new FileNotFoundError(path);\n throw err;\n }\n }\n\n async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('writeFile');\n const key = toKey(path);\n\n // Respect overwrite option (default: true). Use isFile() rather than\n // _files.exists() so leftover empty directories (some adapters) don't\n // incorrectly trigger FileExistsError.\n if (options?.overwrite === false && (await this.isFile(key))) {\n throw new FileExistsError(path);\n }\n\n const body = toBody(content);\n await this._files.upload(key, body, {\n contentType: options?.mimeType ?? getMimeType(path),\n });\n }\n\n /**\n * Append content to a file.\n *\n * **Not atomic.** Object storage has no native append, so this is implemented\n * as a read-modify-write: the existing object is downloaded, the new content\n * is concatenated, and the result is uploaded as a new object. Concurrent\n * appends to the same key may overwrite each other. This limitation is\n * inherent to object storage, not specific to FilesSDK, and matches the\n * behavior of the sibling S3, GCS, and Azure workspace providers.\n */\n async appendFile(path: string, content: FileContent): Promise<void> {\n await this.ensureReady();\n this.assertWritable('appendFile');\n const key = toKey(path);\n\n // Read-modify-write (object storage has no native append)\n let existing = Buffer.alloc(0);\n try {\n const file = await this._files.download(key);\n existing = Buffer.from(await file.arrayBuffer());\n } catch (err) {\n if (!isNotFoundError(err)) throw err;\n // File doesn't exist yet — start fresh\n }\n\n const append = typeof content === 'string' ? Buffer.from(content) : toBody(content);\n const merged = Buffer.concat([existing, Buffer.isBuffer(append) ? append : Buffer.from(append as Uint8Array)]);\n\n await this._files.upload(key, new Uint8Array(merged), {\n contentType: getMimeType(path),\n });\n }\n\n async deleteFile(path: string, options?: RemoveOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('deleteFile');\n const key = toKey(path);\n\n // If the path is a directory, recursively delete (matches sibling\n // filesystems like S3/GCS). Object storage has no first-class directories,\n // so callers calling deleteFile on a prefix expect it to clean up.\n if (await this.isDirectory(key)) {\n await this.rmdir(path, { recursive: true, force: options?.force });\n return;\n }\n\n // Some FilesSDK adapters (notably the local `fs` adapter) silently succeed\n // when deleting a non-existent key instead of raising `NotFound`. Match the\n // shared filesystem contract (and S3/GCS behavior) by checking existence\n // first when `force` is not set.\n if (!options?.force && !(await this.isFile(key))) {\n throw new FileNotFoundError(path);\n }\n\n try {\n await this._files.delete(key);\n } catch (err) {\n if (options?.force) return;\n if (isNotFoundError(err)) throw new FileNotFoundError(path);\n throw err;\n }\n }\n\n async copyFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('copyFile');\n const fromKey = toKey(src);\n const toKey_ = toKey(dest);\n\n if (options?.overwrite === false && (await this.isFile(toKey_))) {\n throw new FileExistsError(dest);\n }\n\n try {\n await this._files.copy(fromKey, toKey_);\n } catch (err) {\n if (isNotFoundError(err)) throw new FileNotFoundError(src);\n throw err;\n }\n }\n\n async moveFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n // Object storage has no atomic rename. Mirrors the S3/GCS pattern:\n // copy first; if that succeeds, force-delete the source.\n await this.copyFile(src, dest, options);\n await this.deleteFile(src, { force: true });\n }\n\n // ---------------------------------------------------------------------------\n // Directory operations\n // ---------------------------------------------------------------------------\n\n async mkdir(_path: string, _options?: { recursive?: boolean }): Promise<void> {\n await this.ensureReady();\n this.assertWritable('mkdir');\n // No-op: object storage creates \"directories\" implicitly on file write.\n }\n\n async rmdir(path: string, options?: RemoveOptions): Promise<void> {\n await this.ensureReady();\n this.assertWritable('rmdir');\n const key = toKey(path);\n const prefix = key ? `${key}/` : '';\n\n // List all keys under the prefix\n const allKeys: string[] = [];\n let cursor: string | undefined;\n\n do {\n const result = await this._files.list({ prefix, cursor, limit: 1000 });\n for (const item of result.items) {\n allKeys.push(item.key);\n }\n cursor = result.cursor;\n } while (cursor);\n\n if (allKeys.length === 0) return;\n\n // Non-recursive: fail if directory is not empty\n if (!options?.recursive) {\n throw new DirectoryNotEmptyError(path);\n }\n\n // Batch delete all keys\n await this._files.delete(allKeys);\n }\n\n async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n await this.ensureReady();\n const key = toKey(path);\n const prefix = key ? `${key}/` : '';\n\n const entries: FileEntry[] = [];\n const seenDirs = new Set<string>();\n\n let cursor: string | undefined;\n const maxDepth = options?.maxDepth;\n const recursive = options?.recursive ?? false;\n const extensions = options?.extension\n ? Array.isArray(options.extension)\n ? options.extension\n : [options.extension]\n : undefined;\n\n do {\n const result = await this._files.list({ prefix, cursor, limit: 1000 });\n\n for (const item of result.items) {\n // item.key is relative to the Files instance's prefix.\n // We need to get the portion after our directory prefix.\n const relativePath = prefix ? item.key.slice(prefix.length) : item.key;\n if (!relativePath) continue;\n\n const segments = relativePath.split('/');\n\n if (segments.length === 1) {\n // Direct child (file)\n const name = segments[0]!;\n\n // Extension filter\n if (extensions) {\n const ext = name.lastIndexOf('.') !== -1 ? name.slice(name.lastIndexOf('.')) : '';\n if (!extensions.includes(ext)) continue;\n }\n\n entries.push({\n name,\n type: 'file',\n size: item.size,\n });\n } else if (!recursive) {\n // Non-recursive: synthesize a directory entry for the first segment only.\n const dirName = segments[0]!;\n if (!seenDirs.has(dirName)) {\n seenDirs.add(dirName);\n entries.push({\n name: dirName,\n type: 'directory',\n });\n }\n } else {\n // Recursive: emit every intermediate directory along the path, then the file.\n // For \"a/b/c/file.txt\": emit \"a\", \"a/b\", \"a/b/c\" as directories, then the file.\n for (let i = 1; i < segments.length; i++) {\n const dirPath = segments.slice(0, i).join('/');\n const dirDepth = i; // number of segments in dirPath\n if (maxDepth !== undefined && dirDepth > maxDepth) continue;\n if (!seenDirs.has(dirPath)) {\n seenDirs.add(dirPath);\n entries.push({\n name: dirPath,\n type: 'directory',\n });\n }\n }\n\n // Depth check for the file itself\n if (maxDepth !== undefined && segments.length > maxDepth) continue;\n\n const name = relativePath;\n if (extensions) {\n const ext = name.lastIndexOf('.') !== -1 ? name.slice(name.lastIndexOf('.')) : '';\n if (!extensions.includes(ext)) continue;\n }\n\n entries.push({\n name,\n type: 'file',\n size: item.size,\n });\n }\n }\n\n cursor = result.cursor;\n } while (cursor);\n\n return entries;\n }\n\n // ---------------------------------------------------------------------------\n // Path operations\n // ---------------------------------------------------------------------------\n\n async exists(path: string): Promise<boolean> {\n await this.ensureReady();\n const key = toKey(path);\n\n // Root always exists\n if (!key) return true;\n\n // Check as directory first (any key under this prefix). Doing the prefix\n // list before the per-key check matters for adapters like FilesSDK's `fs`\n // that leave empty parent directories on disk after their contents are\n // deleted — those would otherwise report true via `_files.exists` even\n // though no objects exist there. Object-store semantics: a \"directory\"\n // exists iff it has children.\n if (await this.isDirectory(key)) return true;\n\n // Check as a real stored file. We deliberately avoid `_files.exists(key)`\n // here because some adapters (e.g. the local `fs` adapter) consider an\n // empty leftover directory to exist as a key, which would break\n // object-store semantics. A prefix list constrained to the exact key only\n // matches actually-stored files.\n return this.isFile(key);\n }\n\n async stat(path: string): Promise<FileStat> {\n await this.ensureReady();\n const key = toKey(path);\n\n // Root is a directory\n if (!key) {\n const now = new Date();\n return {\n name: '/',\n path: '/',\n type: 'directory',\n size: 0,\n createdAt: now,\n modifiedAt: now,\n };\n }\n\n // Try as file first\n try {\n const file = await this._files.head(key);\n return this.storedFileToStat(file, path);\n } catch (err) {\n if (!isNotFoundError(err)) throw err;\n }\n\n // Try as directory\n if (await this.isDirectory(key)) {\n const now = new Date();\n return {\n name: basename(key),\n path,\n type: 'directory',\n size: 0,\n createdAt: now,\n modifiedAt: now,\n };\n }\n\n throw new FileNotFoundError(path);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private assertWritable(operation: string): void {\n if (this.readOnly) {\n throw new WorkspaceReadOnlyError(operation);\n }\n }\n\n /** Check if a key prefix has any children (i.e. acts like a directory). */\n private async isDirectory(key: string): Promise<boolean> {\n if (!key) return true; // root\n const prefix = `${key}/`;\n const result = await this._files.list({ prefix, limit: 1 });\n return result.items.length > 0;\n }\n\n /**\n * Check whether `key` refers to a real stored file (not an empty leftover\n * directory). Uses prefix listing constrained to the exact key, which only\n * matches actually-stored objects across all adapters.\n */\n private async isFile(key: string): Promise<boolean> {\n if (!key) return false;\n const result = await this._files.list({ prefix: key, limit: 10 });\n return result.items.some(item => item.key === key);\n }\n\n /** Convert a FilesSDK StoredFile to a Mastra FileStat. */\n private storedFileToStat(file: SDKStoredFile, path: string): FileStat {\n return {\n name: basename(file.key ?? path),\n path,\n type: 'file',\n size: file.size ?? 0,\n createdAt: file.lastModified ? new Date(file.lastModified) : new Date(),\n modifiedAt: file.lastModified ? new Date(file.lastModified) : new Date(),\n mimeType: file.type || undefined,\n };\n }\n}\n","/**\n * FilesSDK filesystem provider descriptor for MastraEditor.\n *\n * @example\n * ```typescript\n * import { filesSDKFilesystemProvider } from '@mastra/files-sdk';\n *\n * const editor = new MastraEditor({\n * filesystems: [filesSDKFilesystemProvider],\n * });\n * ```\n */\nimport type { FilesystemProvider } from '@mastra/core/editor';\nimport { FilesSDKFilesystem } from './filesystem';\nimport type { FilesSDKFilesystemOptions } from './filesystem';\n\nexport const filesSDKFilesystemProvider: FilesystemProvider<FilesSDKFilesystemOptions> = {\n id: 'files-sdk',\n name: 'FilesSDK (Unified Storage)',\n description: 'Unified storage via FilesSDK — supports S3, R2, GCS, Azure, Vercel Blob, local filesystem, and more',\n configSchema: {\n type: 'object',\n required: ['files'],\n properties: {\n files: { type: 'object', description: 'Pre-configured FilesSDK Files instance' },\n id: { type: 'string', description: 'Unique filesystem ID' },\n displayName: { type: 'string', description: 'Human-friendly display name' },\n icon: { type: 'string', description: 'Icon identifier for UI' },\n description: { type: 'string', description: 'Description for UI' },\n readOnly: { type: 'boolean', description: 'Mount as read-only', default: false },\n },\n },\n createFilesystem: config => new FilesSDKFilesystem(config),\n};\n"]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * FilesSDK filesystem provider descriptor for MastraEditor.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { filesSDKFilesystemProvider } from '@mastra/files-sdk';
7
+ *
8
+ * const editor = new MastraEditor({
9
+ * filesystems: [filesSDKFilesystemProvider],
10
+ * });
11
+ * ```
12
+ */
13
+ import type { FilesystemProvider } from '@mastra/core/editor';
14
+ import type { FilesSDKFilesystemOptions } from './filesystem/index.js';
15
+ export declare const filesSDKFilesystemProvider: FilesystemProvider<FilesSDKFilesystemOptions>;
16
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAE9D,eAAO,MAAM,0BAA0B,EAAE,kBAAkB,CAAC,yBAAyB,CAiBpF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/files-sdk",
3
- "version": "0.0.0",
3
+ "version": "0.2.0-alpha.0",
4
4
  "description": "FilesSDK filesystem provider for Mastra workspaces — unified storage across S3, R2, GCS, Azure, Vercel Blob, and more",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,8 +30,8 @@
30
30
  "vitest": "4.1.5",
31
31
  "@internal/lint": "0.0.97",
32
32
  "@internal/types-builder": "0.0.72",
33
- "@mastra/core": "1.37.0-alpha.7",
34
- "@internal/workspace-test-utils": "0.0.41"
33
+ "@internal/workspace-test-utils": "0.0.41",
34
+ "@mastra/core": "1.37.0-alpha.8"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@mastra/core": ">=1.4.0-0 <2.0.0-0"
@@ -57,7 +57,7 @@
57
57
  "build:lib": "pnpm build",
58
58
  "build:watch": "pnpm build --watch",
59
59
  "test:unit": "vitest run --exclude '**/*.integration.test.ts'",
60
- "test:integration": "vitest run ./src/**/*.integration.test.ts",
60
+ "test:cloud": "vitest run ./src/**/*.integration.test.ts",
61
61
  "test:watch": "vitest watch",
62
62
  "lint": "eslint ."
63
63
  }