@mastra/daytona 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # @mastra/daytona
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added Azure Blob sandbox mount support via blobfuse2 in @mastra/e2b and @mastra/daytona. `sandbox.mount(azureBlobFilesystem, '/data')` now works for Azure containers, matching the existing s3fs (S3) and gcsfuse (GCS) integration. Supports authentication via accountKey, sasToken, connectionString, or managed identity/default credentials, and preserves AzureBlobFilesystem prefixes when mounting. ([#15874](https://github.com/mastra-ai/mastra/pull/15874))
8
+
9
+ ```ts
10
+ import { E2BSandbox } from '@mastra/e2b';
11
+ import { AzureBlobFilesystem } from '@mastra/azure/blob';
12
+
13
+ const azureFs = new AzureBlobFilesystem({ container: 'my-data', connectionString: '...' });
14
+ const sandbox = new E2BSandbox();
15
+ await sandbox.mount(azureFs, '/data');
16
+ // Sandbox processes can now read/write /data/* directly against the Azure container.
17
+ ```
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies [[`6db978c`](https://github.com/mastra-ai/mastra/commit/6db978c42e94e75540a504f7230086f0b5cd35f9), [`512a013`](https://github.com/mastra-ai/mastra/commit/512a013f285aa9c0aa8f08a35b2ce09f9938b017), [`e9becde`](https://github.com/mastra-ai/mastra/commit/e9becdeed9176b9f8392e557bde12b933f99cf7a), [`703a443`](https://github.com/mastra-ai/mastra/commit/703a44390c587d9c0b8ae94ec4edd8afb2a74044), [`808df1b`](https://github.com/mastra-ai/mastra/commit/808df1b39358b5f10b7317107e42b1fda7c87185)]:
22
+ - @mastra/core@1.29.1
23
+
24
+ ## 0.4.0-alpha.0
25
+
26
+ ### Minor Changes
27
+
28
+ - Added Azure Blob sandbox mount support via blobfuse2 in @mastra/e2b and @mastra/daytona. `sandbox.mount(azureBlobFilesystem, '/data')` now works for Azure containers, matching the existing s3fs (S3) and gcsfuse (GCS) integration. Supports authentication via accountKey, sasToken, connectionString, or managed identity/default credentials, and preserves AzureBlobFilesystem prefixes when mounting. ([#15874](https://github.com/mastra-ai/mastra/pull/15874))
29
+
30
+ ```ts
31
+ import { E2BSandbox } from '@mastra/e2b';
32
+ import { AzureBlobFilesystem } from '@mastra/azure/blob';
33
+
34
+ const azureFs = new AzureBlobFilesystem({ container: 'my-data', connectionString: '...' });
35
+ const sandbox = new E2BSandbox();
36
+ await sandbox.mount(azureFs, '/data');
37
+ // Sandbox processes can now read/write /data/* directly against the Azure container.
38
+ ```
39
+
40
+ ### Patch Changes
41
+
42
+ - Updated dependencies [[`512a013`](https://github.com/mastra-ai/mastra/commit/512a013f285aa9c0aa8f08a35b2ce09f9938b017), [`e9becde`](https://github.com/mastra-ai/mastra/commit/e9becdeed9176b9f8392e557bde12b933f99cf7a)]:
43
+ - @mastra/core@1.29.1-alpha.2
44
+
3
45
  ## 0.3.0
4
46
 
5
47
  ### Minor Changes
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Daytona cloud sandbox provider for [Mastra](https://mastra.ai) workspaces.
4
4
 
5
- Implements the `WorkspaceSandbox` interface using [Daytona](https://www.daytona.io/) sandboxes. Supports multiple runtimes, resource configuration, volumes, snapshots, streaming output, sandbox reconnection, and filesystem mounting (S3, GCS).
5
+ Implements the `WorkspaceSandbox` interface using [Daytona](https://www.daytona.io/) sandboxes. Supports multiple runtimes, resource configuration, volumes, snapshots, streaming output, sandbox reconnection, and filesystem mounting (S3, GCS, Azure Blob).
6
6
 
7
7
  ## Install
8
8
 
@@ -10,7 +10,7 @@ Implements the `WorkspaceSandbox` interface using [Daytona](https://www.daytona.
10
10
  pnpm add @mastra/daytona @mastra/core
11
11
 
12
12
  # For filesystem mounting (optional)
13
- pnpm add @mastra/s3 @mastra/gcs
13
+ pnpm add @mastra/s3 @mastra/gcs @mastra/azure
14
14
  ```
15
15
 
16
16
  ## Usage
@@ -101,7 +101,7 @@ console.log(result.stdout); // "session 1"
101
101
 
102
102
  ### Filesystem mounting
103
103
 
104
- Mount S3 or GCS buckets as local directories inside the sandbox.
104
+ Mount S3, GCS, or Azure Blob containers as local directories inside the sandbox.
105
105
 
106
106
  #### Via workspace mounts config
107
107
 
@@ -112,6 +112,7 @@ import { Workspace } from '@mastra/core/workspace';
112
112
  import { DaytonaSandbox } from '@mastra/daytona';
113
113
  import { GCSFilesystem } from '@mastra/gcs';
114
114
  import { S3Filesystem } from '@mastra/s3';
115
+ import { AzureBlobFilesystem } from '@mastra/azure/blob';
115
116
 
116
117
  const workspace = new Workspace({
117
118
  mounts: {
@@ -127,6 +128,11 @@ const workspace = new Workspace({
127
128
  projectId: 'my-project-id',
128
129
  credentials: JSON.parse(process.env.GCS_SERVICE_ACCOUNT_KEY!),
129
130
  }),
131
+ '/azure-data': new AzureBlobFilesystem({
132
+ container: process.env.AZURE_STORAGE_CONTAINER!,
133
+ connectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
134
+ prefix: 'workspace/data',
135
+ }),
130
136
  },
131
137
  sandbox: new DaytonaSandbox({ language: 'python' }),
132
138
  });
@@ -194,6 +200,21 @@ await sandbox.mount(
194
200
  );
195
201
  ```
196
202
 
203
+ #### Azure Blob
204
+
205
+ ```typescript
206
+ import { AzureBlobFilesystem } from '@mastra/azure/blob';
207
+
208
+ await sandbox.mount(
209
+ new AzureBlobFilesystem({
210
+ container: process.env.AZURE_STORAGE_CONTAINER!,
211
+ connectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
212
+ prefix: 'workspace/data',
213
+ }),
214
+ '/data',
215
+ );
216
+ ```
217
+
197
218
  ### Network isolation
198
219
 
199
220
  Restrict outbound network access:
@@ -270,7 +291,7 @@ console.log(response.text);
270
291
 
271
292
  ## Mount Configuration
272
293
 
273
- Pass `S3Filesystem` or `GCSFilesystem` instances via the workspace `mounts` config or directly to `sandbox.mount()`.
294
+ Pass `S3Filesystem`, `GCSFilesystem`, or `AzureBlobFilesystem` instances via the workspace `mounts` config or directly to `sandbox.mount()`.
274
295
 
275
296
  ### S3 environment variables
276
297
 
@@ -289,9 +310,16 @@ Pass `S3Filesystem` or `GCSFilesystem` instances via the workspace `mounts` conf
289
310
  | `GCS_BUCKET` | Bucket name |
290
311
  | `GCS_SERVICE_ACCOUNT_KEY` | Service account key JSON (full JSON string, not a path) |
291
312
 
313
+ ### Azure Blob environment variables
314
+
315
+ | Variable | Description |
316
+ | --------------------------------- | ------------------------- |
317
+ | `AZURE_STORAGE_CONTAINER` | Container name |
318
+ | `AZURE_STORAGE_CONNECTION_STRING` | Storage connection string |
319
+
292
320
  ### Reducing cold start latency with a snapshot
293
321
 
294
- By default, `s3fs` and `gcsfuse` are installed at first mount via `apt`, which adds startup time. To eliminate this, prebake them into a Daytona snapshot and pass the snapshot name via the `snapshot` option.
322
+ By default, `s3fs`, `gcsfuse`, and `blobfuse2` are installed at first mount, which adds startup time. To eliminate this, prebake them into a Daytona snapshot and pass the snapshot name via the `snapshot` option.
295
323
 
296
324
  Create the snapshot once:
297
325
 
@@ -321,6 +349,8 @@ await daytona.snapshot.create(
321
349
  );
322
350
  ```
323
351
 
352
+ If you use Azure Blob mounts, also pre-install `blobfuse2` in the snapshot using Azure's supported package for your base image. See Azure's [BlobFuse2 installation guide](https://learn.microsoft.com/en-us/azure/storage/blobs/blobfuse2-how-to-deploy) for supported install options.
353
+
324
354
  Then use the snapshot name in your sandbox config:
325
355
 
326
356
  ```typescript
package/dist/index.cjs CHANGED
@@ -268,6 +268,250 @@ Sandbox network response: ${checkOutput}` : "")
268
268
  throw new Error(`Failed to mount GCS bucket: ${result.stderr || result.stdout}`);
269
269
  }
270
270
  }
271
+ var SAFE_CONTAINER_NAME = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
272
+ var BLOBFUSE2_GITHUB_DEB = "https://github.com/Azure/azure-storage-fuse/releases/download/blobfuse2-2.5.1/blobfuse2-2.5.1-Ubuntu-22.04.x86_64.deb";
273
+ function validateContainerName(name) {
274
+ if (!SAFE_CONTAINER_NAME.test(name) || name.includes("--")) {
275
+ throw new Error(
276
+ `Invalid Azure container name: "${name}". Container names must be 3-63 lowercase alphanumeric characters or hyphens, with no consecutive hyphens.`
277
+ );
278
+ }
279
+ }
280
+ function parseConnectionString(cs) {
281
+ const out = {};
282
+ for (const part of cs.split(";")) {
283
+ const eq = part.indexOf("=");
284
+ if (eq === -1) continue;
285
+ const key = part.slice(0, eq).trim();
286
+ const value = part.slice(eq + 1).trim();
287
+ if (!value) continue;
288
+ if (key === "AccountName") out.accountName = value;
289
+ else if (key === "AccountKey") out.accountKey = value;
290
+ else if (key === "SharedAccessSignature") out.sasToken = value;
291
+ else if (key === "BlobEndpoint") out.endpoint = value;
292
+ else if (key === "EndpointSuffix") out.endpointSuffix = value;
293
+ else if (key === "DefaultEndpointsProtocol") out.protocol = value;
294
+ }
295
+ if (!out.endpoint && out.accountName) {
296
+ out.endpoint = `${out.protocol || "https"}://${out.accountName}.blob.${out.endpointSuffix || "core.windows.net"}`;
297
+ }
298
+ return out;
299
+ }
300
+ function yamlString(value) {
301
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
302
+ }
303
+ function parseOsRelease(output) {
304
+ const values = {};
305
+ for (const line of output.split("\n")) {
306
+ const eq = line.indexOf("=");
307
+ if (eq === -1) continue;
308
+ const key = line.slice(0, eq);
309
+ const value = line.slice(eq + 1).trim().replace(/^"|"$/g, "");
310
+ values[key] = value;
311
+ }
312
+ return values;
313
+ }
314
+ function resolveMicrosoftAptRepos(osReleaseOutput) {
315
+ const osRelease = parseOsRelease(osReleaseOutput);
316
+ const distroId = osRelease.ID || "ubuntu";
317
+ const codename = osRelease.VERSION_CODENAME || (distroId === "debian" ? "bookworm" : "jammy");
318
+ const versionId = osRelease.VERSION_ID || (distroId === "debian" ? "12" : "22.04");
319
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(codename)) {
320
+ throw new Error(`Invalid distro codename for blobfuse2 repo: "${codename}"`);
321
+ }
322
+ if (!/^\d+(?:\.\d+)?$/.test(versionId)) {
323
+ throw new Error(`Invalid distro version for blobfuse2 repo: "${versionId}"`);
324
+ }
325
+ if (distroId === "debian") {
326
+ const repos = [
327
+ { repoUrl: `https://packages.microsoft.com/debian/${versionId.split(".")[0]}/prod`, suite: codename }
328
+ ];
329
+ if (versionId.split(".")[0] !== "12" || codename !== "bookworm") {
330
+ repos.push({ repoUrl: "https://packages.microsoft.com/debian/12/prod", suite: "bookworm" });
331
+ }
332
+ return repos;
333
+ }
334
+ if (distroId === "ubuntu") {
335
+ const repos = [{ repoUrl: `https://packages.microsoft.com/ubuntu/${versionId}/prod`, suite: codename }];
336
+ if (versionId !== "24.04" || codename !== "noble") {
337
+ repos.push({ repoUrl: "https://packages.microsoft.com/ubuntu/24.04/prod", suite: "noble" });
338
+ }
339
+ if (versionId !== "22.04" || codename !== "jammy") {
340
+ repos.push({ repoUrl: "https://packages.microsoft.com/ubuntu/22.04/prod", suite: "jammy" });
341
+ }
342
+ return repos;
343
+ }
344
+ throw new Error(`Unsupported distro for blobfuse2 runtime installation: "${distroId}"`);
345
+ }
346
+ function resolveAuth(config) {
347
+ let accountName = config.accountName;
348
+ let accountKey = config.accountKey;
349
+ let sasToken = config.sasToken;
350
+ let endpoint = config.endpoint;
351
+ if (config.connectionString) {
352
+ const parsed = parseConnectionString(config.connectionString);
353
+ accountName = accountName ?? parsed.accountName;
354
+ accountKey = accountKey ?? parsed.accountKey;
355
+ sasToken = sasToken ?? parsed.sasToken;
356
+ endpoint = endpoint ?? parsed.endpoint;
357
+ }
358
+ let mode;
359
+ if (config.useDefaultCredential) {
360
+ mode = "msi";
361
+ } else if (sasToken) {
362
+ mode = "sas";
363
+ } else if (accountKey) {
364
+ mode = "key";
365
+ } else {
366
+ throw new Error(
367
+ "Azure Blob mount requires credentials: provide connectionString, accountKey + accountName, sasToken + accountName, or useDefaultCredential."
368
+ );
369
+ }
370
+ if (!accountName) {
371
+ throw new Error("Azure Blob mount requires an accountName (either explicitly or via connectionString).");
372
+ }
373
+ if (endpoint) {
374
+ validateEndpoint(endpoint);
375
+ }
376
+ return { mode, accountName, accountKey, sasToken, endpoint };
377
+ }
378
+ function buildBlobfuseConfig(container, auth, cachePath, readOnly) {
379
+ const lines = [
380
+ "allow-other: true",
381
+ "foreground: false",
382
+ `read-only: ${readOnly ? "true" : "false"}`,
383
+ "logging:",
384
+ " type: silent",
385
+ "components:",
386
+ " - libfuse",
387
+ " - file_cache",
388
+ " - attr_cache",
389
+ " - azstorage",
390
+ "libfuse:",
391
+ " attribute-expiration-sec: 240",
392
+ " entry-expiration-sec: 240",
393
+ " negative-entry-expiration-sec: 120",
394
+ "file_cache:",
395
+ ` path: ${yamlString(cachePath)}`,
396
+ " timeout-sec: 120",
397
+ "attr_cache:",
398
+ " timeout-sec: 7200",
399
+ "azstorage:",
400
+ ` mode: ${auth.mode}`,
401
+ ` account-name: ${yamlString(auth.accountName)}`,
402
+ ` container: ${yamlString(container)}`
403
+ ];
404
+ if (auth.mode === "key" && auth.accountKey) {
405
+ lines.push(` account-key: ${yamlString(auth.accountKey)}`);
406
+ } else if (auth.mode === "sas" && auth.sasToken) {
407
+ lines.push(` sas: ${yamlString(auth.sasToken)}`);
408
+ }
409
+ if (auth.endpoint) {
410
+ lines.push(` endpoint: ${yamlString(auth.endpoint.replace(/\/$/, ""))}`);
411
+ }
412
+ return lines.join("\n") + "\n";
413
+ }
414
+ async function mountAzure(mountPath, config, ctx) {
415
+ const { run, writeFile, logger } = ctx;
416
+ validateContainerName(config.container);
417
+ const auth = resolveAuth(config);
418
+ const prefix = config.prefix ? validatePrefix(config.prefix) : void 0;
419
+ const quotedMountPath = shellQuote(mountPath);
420
+ const curlCheck = await run('which curl 2>/dev/null || echo "not found"', 3e4);
421
+ if (curlCheck.stdout.includes("not found")) {
422
+ const curlInstall = await run("sudo apt-get update -qq 2>&1 && sudo apt-get install -y curl 2>&1", 12e4);
423
+ if (curlInstall.exitCode !== 0) {
424
+ throw new Error(
425
+ `Failed to install curl for Azure Blob reachability check: ${curlInstall.stderr || curlInstall.stdout}`
426
+ );
427
+ }
428
+ }
429
+ const probeUrl = auth.endpoint ? auth.endpoint.replace(/\/$/, "") : `https://${auth.accountName}.blob.core.windows.net`;
430
+ const connectivityCheck = await run(`curl -sS --max-time 5 ${shellQuote(probeUrl)} 2>&1`, 1e4);
431
+ const checkOutput = connectivityCheck.stdout.trim();
432
+ if (connectivityCheck.exitCode !== 0 || checkOutput.toLowerCase().includes("restricted") || checkOutput.toLowerCase().includes("blocked")) {
433
+ throw new Error(
434
+ `Cannot reach ${probeUrl} from this sandbox. Azure Blob mounting requires network access to the storage endpoint, which may be blocked on Daytona's restricted tiers. Upgrade to a tier with unrestricted internet access, or contact Daytona support to remove the network restriction.` + (checkOutput ? `
435
+
436
+ Sandbox network response: ${checkOutput}` : "")
437
+ );
438
+ }
439
+ const checkResult = await run('which blobfuse2 2>/dev/null || echo "not found"', 3e4);
440
+ if (checkResult.stdout.includes("not found")) {
441
+ logger.warn(`${LOG_PREFIX} blobfuse2 not found, attempting runtime installation...`);
442
+ logger.info(`${LOG_PREFIX} Tip: For faster startup, pre-install blobfuse2 in your sandbox image`);
443
+ await run("sudo apt-get update -qq 2>&1", 6e4);
444
+ const prepResult = await run("sudo apt-get install -y curl gnupg 2>&1", 12e4);
445
+ if (prepResult.exitCode !== 0) {
446
+ throw new Error(
447
+ `Failed to install blobfuse2 prerequisites (curl, gnupg): ${prepResult.stderr || prepResult.stdout}`
448
+ );
449
+ }
450
+ const osReleaseResult = await run("cat /etc/os-release 2>/dev/null || true", 3e4);
451
+ const repos = resolveMicrosoftAptRepos(osReleaseResult.stdout);
452
+ const repoSetup = await run(
453
+ "sudo mkdir -p /etc/apt/keyrings && curl --retry 3 --retry-all-errors --retry-delay 2 -fsSL https://packages.microsoft.com/keys/microsoft.asc -o /tmp/ms-key.asc && sudo gpg --batch --yes --dearmor -o /etc/apt/keyrings/microsoft.gpg /tmp/ms-key.asc",
454
+ 3e4
455
+ );
456
+ let installResult;
457
+ if (repoSetup.exitCode === 0) {
458
+ for (const { repoUrl, suite } of repos) {
459
+ await run(
460
+ `echo "deb [signed-by=/etc/apt/keyrings/microsoft.gpg] ${repoUrl} ${suite} main" | sudo tee /etc/apt/sources.list.d/microsoft-prod.list`,
461
+ 3e4
462
+ );
463
+ await run("sudo apt-get update -qq 2>&1 || true", 6e4);
464
+ installResult = await run("sudo apt-get install -y blobfuse2 fuse3 2>&1", 12e4);
465
+ if (installResult.exitCode === 0) break;
466
+ logger.warn(`${LOG_PREFIX} blobfuse2 install failed for ${repoUrl} ${suite}, trying fallback if available`);
467
+ }
468
+ } else {
469
+ logger.warn(`${LOG_PREFIX} Failed to set up Microsoft apt repository, trying GitHub release fallback`);
470
+ }
471
+ let verifyResult = await run("which blobfuse2 && blobfuse2 --version", 3e4);
472
+ if (verifyResult.exitCode !== 0) {
473
+ installResult = await run(
474
+ `sudo apt-get update -qq 2>&1 || true && sudo apt-get install -y fuse3 ca-certificates curl 2>&1 && curl -L --retry 3 --retry-all-errors --retry-delay 2 -fSLo /tmp/blobfuse2.deb ${BLOBFUSE2_GITHUB_DEB} && sudo dpkg -i /tmp/blobfuse2.deb 2>&1 && sudo bash -c 'lib=$(find /usr/lib -name "libfuse3.so.3.*" | head -1); [ -z "$lib" ] || ln -sf "$lib" /usr/lib/x86_64-linux-gnu/libfuse3.so.3'`,
475
+ 18e4
476
+ );
477
+ verifyResult = await run("which blobfuse2 && blobfuse2 --version", 3e4);
478
+ }
479
+ if (!installResult || verifyResult.exitCode !== 0) {
480
+ throw new Error(
481
+ `Failed to install blobfuse2: ${verifyResult.stderr || verifyResult.stdout || installResult?.stderr || installResult?.stdout || "unknown error"}`
482
+ );
483
+ }
484
+ }
485
+ const idResult = await run("id -u && id -g", 3e4);
486
+ const [uid, gid] = idResult.stdout.trim().split("\n");
487
+ const validUidGid = uid && gid && /^\d+$/.test(uid) && /^\d+$/.test(gid);
488
+ await run(
489
+ `sudo chmod a+rw /dev/fuse 2>/dev/null || true; sudo bash -c 'grep -q "^user_allow_other" /etc/fuse.conf 2>/dev/null || echo "user_allow_other" >> /etc/fuse.conf' 2>/dev/null || true`
490
+ );
491
+ const mountHash = crypto.createHash("md5").update(mountPath).digest("hex").slice(0, 8);
492
+ const configPath = `/tmp/.blobfuse2-config-${mountHash}.yaml`;
493
+ const cachePath = `/tmp/blobfuse2-cache-${mountHash}`;
494
+ const yaml = buildBlobfuseConfig(config.container, auth, cachePath, !!config.readOnly);
495
+ await run(`sudo rm -f ${shellQuote(configPath)}`, 3e4);
496
+ await writeFile(configPath, yaml);
497
+ await run(`chmod 600 ${shellQuote(configPath)}`, 3e4);
498
+ await run(`sudo rm -rf ${shellQuote(cachePath)} && mkdir -p ${shellQuote(cachePath)}`, 3e4);
499
+ if (validUidGid) {
500
+ await run(`sudo chown ${uid}:${gid} ${shellQuote(cachePath)} 2>/dev/null || true`, 3e4);
501
+ }
502
+ const prefixFlags = prefix ? ` --virtual-directory=true --subdirectory=${shellQuote(prefix)}` : "";
503
+ const mountCmd = `blobfuse2 mount ${quotedMountPath} --config-file=${shellQuote(configPath)}${prefixFlags}`;
504
+ logger.debug(`${LOG_PREFIX} Mounting Azure Blob:`, mountCmd);
505
+ const result = await run(mountCmd, 6e4);
506
+ logger.debug(`${LOG_PREFIX} blobfuse2 result:`, {
507
+ exitCode: result.exitCode,
508
+ stdout: result.stdout,
509
+ stderr: result.stderr
510
+ });
511
+ if (result.exitCode !== 0) {
512
+ throw new Error(`Failed to mount Azure Blob container: ${result.stderr || result.stdout}`);
513
+ }
514
+ }
271
515
  var DaytonaProcessHandle = class extends workspace.ProcessHandle {
272
516
  pid;
273
517
  _cmdId;
@@ -840,6 +1084,11 @@ var DaytonaSandbox = class _DaytonaSandbox extends workspace.MastraSandbox {
840
1084
  await mountGCS(mountPath, config, mountCtx);
841
1085
  this.logger.debug(`${LOG_PREFIX} Mounted GCS bucket at ${mountPath}`);
842
1086
  break;
1087
+ case "azure-blob":
1088
+ this.logger.debug(`${LOG_PREFIX} Mounting Azure Blob at "${mountPath}"...`);
1089
+ await mountAzure(mountPath, config, mountCtx);
1090
+ this.logger.debug(`${LOG_PREFIX} Mounted Azure Blob container at ${mountPath}`);
1091
+ break;
843
1092
  default: {
844
1093
  const error = `Unsupported mount type: ${config.type}`;
845
1094
  this.mounts.set(mountPath, { filesystem, state: "unsupported", config, error });
@@ -909,7 +1158,7 @@ var DaytonaSandbox = class _DaytonaSandbox extends workspace.MastraSandbox {
909
1158
  try {
910
1159
  const mountsResult = await runCommand(
911
1160
  sandbox,
912
- `grep -E 'fuse\\.(s3fs|gcsfuse)' /proc/mounts | awk '{print $2}'`,
1161
+ `grep -E 'fuse\\.(s3fs|gcsfuse|blobfuse2)' /proc/mounts | awk '{print $2}'`,
913
1162
  { timeout: MOUNT_COMMAND_TIMEOUT_MS }
914
1163
  );
915
1164
  currentMounts = mountsResult.output.trim().split("\n").filter((p) => p.length > 0);