@mastra/e2b 0.13.0 → 0.14.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/dist/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export { createDefaultMountableTemplate, isNamedTemplateSpec, isDeferredNamedTem
4
4
  export { createRepoTemplate, refreshRepoTemplate, repoTemplateRef, type RepoTemplateOptions, type RepoTemplateRepository, type RepoTemplateIdentity, type RepositoryAccess, type RefreshRepoTemplateResult, } from './utils/repo-template.js';
5
5
  export { type E2BS3MountConfig, type E2BGCSMountConfig, type E2BAzureBlobMountConfig, type E2BMountConfig, } from './sandbox/mounts/index.js';
6
6
  export { e2bSandboxProvider } from './provider.js';
7
+ export { E2BFactorySandbox, type E2BFactorySandboxOptions, type E2BFactorySandboxSettings } from './factory-sandbox.js';
7
8
  export { E2BCodeModeTransport } from './code-mode/transport.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EACL,8BAA8B,EAC9B,mBAAmB,EACnB,2BAA2B,EAC3B,oBAAoB,EACpB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EACL,8BAA8B,EAC9B,mBAAmB,EACnB,2BAA2B,EAC3B,oBAAoB,EACpB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,KAAK,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACrH,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { MastraSandbox, ProcessHandle, SandboxError, SandboxNotReadyError, SandboxProcessManager, UnsupportedStdinCloseError, assertModesUnsupported } from "@mastra/core/workspace";
2
- import { Sandbox, Template } from "e2b";
1
+ import { FactorySandbox, MastraSandbox, ProcessHandle, SandboxError, SandboxNotReadyError, SandboxProcessManager, UnsupportedStdinCloseError, assertModesUnsupported } from "@mastra/core/workspace";
2
+ import { ApiClient, ConnectionConfig, Sandbox, Template } from "e2b";
3
3
  import { createHash } from "crypto";
4
4
  import { execFile } from "child_process";
5
5
  import { promisify } from "util";
@@ -2145,6 +2145,222 @@ const e2bSandboxProvider = {
2145
2145
  createSandbox: (config) => new E2BSandbox(config)
2146
2146
  };
2147
2147
  //#endregion
2148
+ //#region src/factory-sandbox.ts
2149
+ /** Applied when neither the environment setting nor a host default is set. */
2150
+ const DEFAULT_SETTINGS = {
2151
+ cpuCount: 2,
2152
+ memoryMb: 1024,
2153
+ idleTimeoutMinutes: 5
2154
+ };
2155
+ const SETTINGS_SCHEMA = {
2156
+ type: "object",
2157
+ properties: {
2158
+ cpuCount: {
2159
+ type: "integer",
2160
+ title: "CPU",
2161
+ description: "vCPUs for the sandbox template",
2162
+ default: DEFAULT_SETTINGS.cpuCount,
2163
+ minimum: 1,
2164
+ maximum: 8
2165
+ },
2166
+ memoryMb: {
2167
+ type: "integer",
2168
+ title: "Memory (MB)",
2169
+ description: "Memory in MB for the sandbox template",
2170
+ default: DEFAULT_SETTINGS.memoryMb,
2171
+ minimum: 512,
2172
+ maximum: 65536
2173
+ },
2174
+ idleTimeoutMinutes: {
2175
+ type: "integer",
2176
+ title: "Idle timeout (minutes)",
2177
+ description: "Minutes a sandbox stays alive before E2B stops it",
2178
+ default: DEFAULT_SETTINGS.idleTimeoutMinutes,
2179
+ minimum: 1,
2180
+ maximum: 1440
2181
+ }
2182
+ },
2183
+ additionalProperties: false
2184
+ };
2185
+ /**
2186
+ * The settings schema with the provider's effective defaults as `default`:
2187
+ * the built-in values, overridden by the host's `defaults` option. The schema
2188
+ * is what clients show as placeholders, so it must match what the provider
2189
+ * applies when a setting is unset.
2190
+ */
2191
+ function settingsSchema(options) {
2192
+ const { defaults, timeout } = options;
2193
+ const effective = {
2194
+ ...DEFAULT_SETTINGS,
2195
+ ...timeout !== void 0 ? { idleTimeoutMinutes: Math.ceil(timeout / 6e4) } : {},
2196
+ ...defaults
2197
+ };
2198
+ const properties = Object.fromEntries(Object.entries(SETTINGS_SCHEMA.properties).map(([key, property]) => [key, {
2199
+ ...property,
2200
+ default: effective[key]
2201
+ }]));
2202
+ return {
2203
+ ...SETTINGS_SCHEMA,
2204
+ properties
2205
+ };
2206
+ }
2207
+ /** Log entries E2B returns per build-status call. */
2208
+ const BUILD_LOG_PAGE = 100;
2209
+ /** The id of a build that needed no build: the sha-tagged template already existed. */
2210
+ const EXISTING_BUILD = "existing";
2211
+ /**
2212
+ * The E2B host contract for factory: every session sandbox is an
2213
+ * {@link E2BSandbox} whose template is {@link createRepoTemplate} over the
2214
+ * session's repositories, sized by the factory's environment settings. The
2215
+ * `builds` capability starts the same sha-tagged template ahead of any
2216
+ * session and reads its status, logs and history back from E2B.
2217
+ */
2218
+ var E2BFactorySandbox = class extends FactorySandbox {
2219
+ provider = "e2b";
2220
+ settings;
2221
+ builds;
2222
+ #options;
2223
+ #connection;
2224
+ constructor(options = {}) {
2225
+ super();
2226
+ this.#options = options;
2227
+ this.settings = settingsSchema(options);
2228
+ this.#connection = {
2229
+ ...options.domain && { domain: options.domain },
2230
+ ...options.apiUrl && { apiUrl: options.apiUrl },
2231
+ ...options.apiKey && { apiKey: options.apiKey },
2232
+ ...options.accessToken && { accessToken: options.accessToken }
2233
+ };
2234
+ this.builds = {
2235
+ start: (ctx, settings) => this.#startBuild(ctx, settings),
2236
+ get: (_ctx, _settings, buildId) => this.#getBuild(buildId),
2237
+ list: (ctx, settings) => this.#listBuilds(ctx, settings)
2238
+ };
2239
+ }
2240
+ template(ctx, settings) {
2241
+ return createRepoTemplate(this.#templateOptions(ctx, settings));
2242
+ }
2243
+ create(ctx, settings) {
2244
+ const { defaults, ...options } = this.#options;
2245
+ return new E2BSandbox({
2246
+ ...options,
2247
+ id: ctx.sessionId,
2248
+ sandboxId: ctx.sandboxId,
2249
+ template: this.template(ctx, settings),
2250
+ ...ctx.workingDirectory ? { workingDirectory: ctx.workingDirectory } : {},
2251
+ timeout: this.#timeout(settings)
2252
+ });
2253
+ }
2254
+ /** The setting, then the host default, then the host's own `timeout` option, then 5 minutes. */
2255
+ #timeout(settings) {
2256
+ const minutes = settings.idleTimeoutMinutes ?? this.#options.defaults?.idleTimeoutMinutes;
2257
+ if (minutes !== void 0) return minutes * 6e4;
2258
+ return this.#options.timeout ?? DEFAULT_SETTINGS.idleTimeoutMinutes * 6e4;
2259
+ }
2260
+ #templateOptions(ctx, settings) {
2261
+ const { defaults } = this.#options;
2262
+ const { resolveHead: _resolveHead, ...rest } = ctx;
2263
+ return {
2264
+ ...rest,
2265
+ cpuCount: settings.cpuCount ?? defaults?.cpuCount ?? DEFAULT_SETTINGS.cpuCount,
2266
+ memoryMB: settings.memoryMb ?? defaults?.memoryMb ?? DEFAULT_SETTINGS.memoryMb
2267
+ };
2268
+ }
2269
+ async #startBuild(ctx, settings) {
2270
+ const { spec } = await resolveSpecAtHead(this.#templateOptions(ctx, settings));
2271
+ if (await Template.exists(spec.ref, this.#connection)) return {
2272
+ buildId: `${spec.ref}:${EXISTING_BUILD}`,
2273
+ templateId: spec.ref,
2274
+ status: "ready"
2275
+ };
2276
+ const info = await Template.buildInBackground(spec.template, spec.ref, {
2277
+ ...this.#connection,
2278
+ ...spec.buildTags?.length ? { tags: spec.buildTags } : {},
2279
+ ...spec.buildResources
2280
+ });
2281
+ return {
2282
+ buildId: `${info.templateId}:${info.buildId}`,
2283
+ templateId: info.templateId,
2284
+ status: "pending"
2285
+ };
2286
+ }
2287
+ async #getBuild(compositeId) {
2288
+ const { templateId, buildId } = splitBuildId(compositeId);
2289
+ if (buildId === EXISTING_BUILD) return {
2290
+ buildId: compositeId,
2291
+ templateId,
2292
+ status: "ready"
2293
+ };
2294
+ let response = await Template.getBuildStatus({
2295
+ templateId,
2296
+ buildId
2297
+ }, this.#connection);
2298
+ const entries = [...response.logEntries ?? []];
2299
+ while (response.logEntries && response.logEntries.length >= BUILD_LOG_PAGE) {
2300
+ response = await Template.getBuildStatus({
2301
+ templateId,
2302
+ buildId
2303
+ }, {
2304
+ ...this.#connection,
2305
+ logsOffset: entries.length
2306
+ });
2307
+ entries.push(...response.logEntries ?? []);
2308
+ }
2309
+ const logs = entries.length ? entries.map((entry) => entry.toString()) : response.logs?.length ? response.logs : void 0;
2310
+ return {
2311
+ buildId: compositeId,
2312
+ templateId: response.templateID,
2313
+ status: mapStatus(response.status),
2314
+ ...logs ? { logs } : {},
2315
+ ...response.reason?.message ? { error: response.reason.message } : {}
2316
+ };
2317
+ }
2318
+ async #listBuilds(ctx, settings) {
2319
+ const { spec } = await resolveSpecAtHead(this.#templateOptions(ctx, settings));
2320
+ const name = templateNameOf(spec.ref);
2321
+ const client = new ApiClient(new ConnectionConfig(this.#connection));
2322
+ const templates = await client.api.GET("/templates");
2323
+ if (templates.error || !templates.data) throw new Error(`E2B template listing failed: ${describeApiError(templates.error)}`);
2324
+ const template = templates.data.find((t) => t.names.includes(name) || t.aliases.includes(name));
2325
+ if (!template) return [];
2326
+ const detail = await client.api.GET("/templates/{templateID}", { params: { path: { templateID: template.templateID } } });
2327
+ if (detail.error || !detail.data) throw new Error(`E2B template build listing failed: ${describeApiError(detail.error)}`);
2328
+ return detail.data.builds.slice().sort((a, b) => b.createdAt.localeCompare(a.createdAt)).map((build) => ({
2329
+ buildId: `${template.templateID}:${build.buildID}`,
2330
+ templateId: template.templateID,
2331
+ status: mapStatus(build.status),
2332
+ startedAt: build.createdAt,
2333
+ ...build.finishedAt ? { finishedAt: build.finishedAt } : {}
2334
+ }));
2335
+ }
2336
+ };
2337
+ function describeApiError(error) {
2338
+ return error ? JSON.stringify(error) : "empty response";
2339
+ }
2340
+ /** `<templateId>:<buildId>`, split on the last colon because a template ref itself carries one (`name:sha-<head>`). */
2341
+ function splitBuildId(compositeId) {
2342
+ const at = compositeId.lastIndexOf(":");
2343
+ if (at <= 0 || at === compositeId.length - 1) throw new Error(`Invalid E2B build id "${compositeId}": expected "<templateId>:<buildId>"`);
2344
+ return {
2345
+ templateId: compositeId.slice(0, at),
2346
+ buildId: compositeId.slice(at + 1)
2347
+ };
2348
+ }
2349
+ /** The template name of a `name:tag` ref. */
2350
+ function templateNameOf(ref) {
2351
+ const at = ref.lastIndexOf(":");
2352
+ return at > 0 ? ref.slice(0, at) : ref;
2353
+ }
2354
+ function mapStatus(status) {
2355
+ switch (status) {
2356
+ case "waiting": return "pending";
2357
+ case "building": return "building";
2358
+ case "ready": return "ready";
2359
+ case "error": return "failed";
2360
+ default: return "unknown";
2361
+ }
2362
+ }
2363
+ //#endregion
2148
2364
  //#region src/code-mode/transport.ts
2149
2365
  /**
2150
2366
  * Code Mode — E2B transport
@@ -2350,6 +2566,6 @@ var E2BCodeModeTransport = class {
2350
2566
  }
2351
2567
  };
2352
2568
  //#endregion
2353
- export { DEFAULT_NODE_VERSION, E2BCodeModeTransport, E2BProcessManager, E2BSandbox, createDefaultMountableTemplate, createRepoTemplate, e2bSandboxProvider, isDeferredNamedTemplateSpec, isNamedTemplateSpec, refreshRepoTemplate, repoTemplateRef };
2569
+ export { DEFAULT_NODE_VERSION, E2BCodeModeTransport, E2BFactorySandbox, E2BProcessManager, E2BSandbox, createDefaultMountableTemplate, createRepoTemplate, e2bSandboxProvider, isDeferredNamedTemplateSpec, isNamedTemplateSpec, refreshRepoTemplate, repoTemplateRef };
2354
2570
 
2355
2571
  //# sourceMappingURL=index.js.map