@blaxel/core 0.2.71-dev.101 → 0.2.71-dev.106
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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/common/autoload.js +64 -0
- package/dist/cjs/common/h2fetch.js +208 -0
- package/dist/cjs/common/h2pool.js +137 -0
- package/dist/cjs/common/h2warm.js +54 -0
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/sandbox/action.js +33 -0
- package/dist/cjs/sandbox/drive/drive.js +3 -3
- package/dist/cjs/sandbox/filesystem/filesystem.js +1 -2
- package/dist/cjs/sandbox/interpreter.js +12 -2
- package/dist/cjs/sandbox/process/process.js +2 -2
- package/dist/cjs/sandbox/sandbox.js +84 -10
- package/dist/cjs/types/common/autoload.d.ts +5 -0
- package/dist/cjs/types/common/h2fetch.d.ts +22 -0
- package/dist/cjs/types/common/h2pool.d.ts +38 -0
- package/dist/cjs/types/common/h2warm.d.ts +2 -0
- package/dist/cjs/types/sandbox/action.d.ts +8 -1
- package/dist/cjs/types/sandbox/interpreter.d.ts +1 -0
- package/dist/cjs/types/sandbox/sandbox.d.ts +6 -0
- package/dist/cjs/types/sandbox/types.d.ts +2 -0
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/autoload.js +64 -0
- package/dist/cjs-browser/common/h2fetch.js +4 -0
- package/dist/cjs-browser/common/h2pool.js +4 -0
- package/dist/cjs-browser/common/h2warm.js +2 -0
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/sandbox/action.js +33 -0
- package/dist/cjs-browser/sandbox/drive/drive.js +3 -3
- package/dist/cjs-browser/sandbox/filesystem/filesystem.js +1 -2
- package/dist/cjs-browser/sandbox/interpreter.js +12 -2
- package/dist/cjs-browser/sandbox/process/process.js +2 -2
- package/dist/cjs-browser/sandbox/sandbox.js +84 -10
- package/dist/cjs-browser/types/common/autoload.d.ts +5 -0
- package/dist/cjs-browser/types/common/h2fetch.d.ts +22 -0
- package/dist/cjs-browser/types/common/h2pool.d.ts +38 -0
- package/dist/cjs-browser/types/common/h2warm.d.ts +2 -0
- package/dist/cjs-browser/types/sandbox/action.d.ts +8 -1
- package/dist/cjs-browser/types/sandbox/interpreter.d.ts +1 -0
- package/dist/cjs-browser/types/sandbox/sandbox.d.ts +6 -0
- package/dist/cjs-browser/types/sandbox/types.d.ts +2 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/autoload.js +30 -0
- package/dist/esm/common/h2fetch.js +203 -0
- package/dist/esm/common/h2pool.js +101 -0
- package/dist/esm/common/h2warm.js +48 -0
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm/sandbox/action.js +33 -0
- package/dist/esm/sandbox/drive/drive.js +3 -3
- package/dist/esm/sandbox/filesystem/filesystem.js +1 -2
- package/dist/esm/sandbox/interpreter.js +12 -2
- package/dist/esm/sandbox/process/process.js +2 -2
- package/dist/esm/sandbox/sandbox.js +51 -10
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/autoload.js +30 -0
- package/dist/esm-browser/common/h2fetch.js +4 -0
- package/dist/esm-browser/common/h2pool.js +4 -0
- package/dist/esm-browser/common/h2warm.js +2 -0
- package/dist/esm-browser/common/settings.js +2 -2
- package/dist/esm-browser/sandbox/action.js +33 -0
- package/dist/esm-browser/sandbox/drive/drive.js +3 -3
- package/dist/esm-browser/sandbox/filesystem/filesystem.js +1 -2
- package/dist/esm-browser/sandbox/interpreter.js +12 -2
- package/dist/esm-browser/sandbox/process/process.js +2 -2
- package/dist/esm-browser/sandbox/sandbox.js +51 -10
- package/package.json +1 -1
|
@@ -21,6 +21,28 @@ for (const interceptor of responseInterceptors) {
|
|
|
21
21
|
}
|
|
22
22
|
// Initialize Sentry for SDK error tracking immediately when module loads
|
|
23
23
|
initSentry();
|
|
24
|
+
// Background H2 connection warming (Node.js only)
|
|
25
|
+
const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
26
|
+
/* eslint-disable */
|
|
27
|
+
const isBrowser = typeof globalThis !== "undefined" && globalThis?.window !== undefined;
|
|
28
|
+
if (isNode && !isBrowser) {
|
|
29
|
+
try {
|
|
30
|
+
// Pre-warm edge H2 for the configured region so the first
|
|
31
|
+
// SandboxInstance.create() gets an instant session via the pool.
|
|
32
|
+
// The control-plane client (api.blaxel.ai) stays on regular fetch
|
|
33
|
+
// which already benefits from undici's built-in connection pooling.
|
|
34
|
+
const region = settings.region;
|
|
35
|
+
if (region) {
|
|
36
|
+
import("./h2pool.js").then(({ h2Pool }) => {
|
|
37
|
+
const edgeSuffix = settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
|
|
38
|
+
h2Pool.warm(`any.${region}.${edgeSuffix}`);
|
|
39
|
+
}).catch(() => { });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Silently ignore warming failures
|
|
44
|
+
}
|
|
45
|
+
}
|
|
24
46
|
// Allow to set custom configuration for browser environment
|
|
25
47
|
export function initialize(config) {
|
|
26
48
|
settings.setConfig(config);
|
|
@@ -34,3 +56,11 @@ export function initialize(config) {
|
|
|
34
56
|
export function authenticate() {
|
|
35
57
|
return settings.authenticate();
|
|
36
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Close all pooled H2 connections. Call this for explicit cleanup
|
|
61
|
+
* (e.g. in test teardown or before process exit).
|
|
62
|
+
*/
|
|
63
|
+
export async function closeConnections() {
|
|
64
|
+
const { h2Pool } = await import("./h2pool.js");
|
|
65
|
+
h2Pool.closeAll();
|
|
66
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Browser stub - H2 fetch is Node.js only, falls back to global fetch
|
|
2
|
+
export function createH2Fetch(session) { return (input) => globalThis.fetch(input); }
|
|
3
|
+
export function createPoolBackedH2Fetch(pool, domain) { return (input) => globalThis.fetch(input); }
|
|
4
|
+
export function h2RequestDirect(session, url, init) { return globalThis.fetch(url, init); }
|
|
@@ -3,8 +3,8 @@ import { authentication } from "../authentication/index.js";
|
|
|
3
3
|
import { env } from "../common/env.js";
|
|
4
4
|
import { fs, os, path } from "../common/node.js";
|
|
5
5
|
// Build info - these placeholders are replaced at build time by build:replace-imports
|
|
6
|
-
const BUILD_VERSION = "0.2.71-dev.
|
|
7
|
-
const BUILD_COMMIT = "
|
|
6
|
+
const BUILD_VERSION = "0.2.71-dev.106";
|
|
7
|
+
const BUILD_COMMIT = "0375f5738bbf782c01805d63ce304cafc0e20ca2";
|
|
8
8
|
const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
|
|
9
9
|
// Cache for config.yaml tracking value
|
|
10
10
|
let configTrackingValue = null;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { createClient } from "@hey-api/client-fetch";
|
|
2
|
+
import { interceptors } from "../client/interceptors.js";
|
|
3
|
+
import { responseInterceptors } from "../client/responseInterceptor.js";
|
|
4
|
+
import { createH2Fetch, h2RequestDirect } from "../common/h2fetch.js";
|
|
2
5
|
import { getForcedUrl, getGlobalUniqueHash } from "../common/internal.js";
|
|
3
6
|
import { settings } from "../common/settings.js";
|
|
4
7
|
import { client as defaultClient } from "./client/client.gen.js";
|
|
@@ -28,6 +31,7 @@ export class ResponseError extends Error {
|
|
|
28
31
|
}
|
|
29
32
|
export class SandboxAction {
|
|
30
33
|
sandbox;
|
|
34
|
+
_h2Client = null;
|
|
31
35
|
constructor(sandbox) {
|
|
32
36
|
this.sandbox = sandbox;
|
|
33
37
|
}
|
|
@@ -54,8 +58,37 @@ export class SandboxAction {
|
|
|
54
58
|
headers: this.sandbox.headers,
|
|
55
59
|
});
|
|
56
60
|
}
|
|
61
|
+
const session = this.sandbox.h2Session;
|
|
62
|
+
if (session && !session.closed && !session.destroyed) {
|
|
63
|
+
if (!this._h2Client) {
|
|
64
|
+
this._h2Client = createClient({
|
|
65
|
+
fetch: createH2Fetch(session),
|
|
66
|
+
});
|
|
67
|
+
for (const interceptor of interceptors) {
|
|
68
|
+
// @ts-expect-error - Interceptor is not typed
|
|
69
|
+
this._h2Client.interceptors.request.use(interceptor);
|
|
70
|
+
}
|
|
71
|
+
for (const interceptor of responseInterceptors) {
|
|
72
|
+
this._h2Client.interceptors.response.use(interceptor);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return this._h2Client;
|
|
76
|
+
}
|
|
77
|
+
// Invalidate cached H2 client when session is no longer usable
|
|
78
|
+
this._h2Client = null;
|
|
57
79
|
return defaultClient;
|
|
58
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Routes through the H2 session when available, falling back to
|
|
83
|
+
* globalThis.fetch. Uses a direct H2 path that avoids Request allocation.
|
|
84
|
+
*/
|
|
85
|
+
h2Fetch(input, init) {
|
|
86
|
+
const session = this.sandbox.h2Session;
|
|
87
|
+
if (session && !session.closed && !session.destroyed) {
|
|
88
|
+
return h2RequestDirect(session, input.toString(), init);
|
|
89
|
+
}
|
|
90
|
+
return globalThis.fetch(input, init);
|
|
91
|
+
}
|
|
59
92
|
get forcedUrl() {
|
|
60
93
|
if (this.sandbox.forceUrl)
|
|
61
94
|
return this.sandbox.forceUrl;
|
|
@@ -14,7 +14,7 @@ export class SandboxDrive extends SandboxAction {
|
|
|
14
14
|
mountPath: request.mountPath,
|
|
15
15
|
drivePath: request.drivePath || "/",
|
|
16
16
|
};
|
|
17
|
-
const response = await
|
|
17
|
+
const response = await this.h2Fetch(`${this.url}/drives/mount`, {
|
|
18
18
|
method: 'POST',
|
|
19
19
|
headers: {
|
|
20
20
|
...headers,
|
|
@@ -37,7 +37,7 @@ export class SandboxDrive extends SandboxAction {
|
|
|
37
37
|
const normalizedPath = mountPath.startsWith('/') ? mountPath : `/${mountPath}`;
|
|
38
38
|
// Remove leading slash for URL (DELETE /drives/mnt/test not /drives//mnt/test)
|
|
39
39
|
const urlPath = normalizedPath.substring(1);
|
|
40
|
-
const response = await
|
|
40
|
+
const response = await this.h2Fetch(`${this.url}/drives/mount/${urlPath}`, {
|
|
41
41
|
method: 'DELETE',
|
|
42
42
|
headers,
|
|
43
43
|
});
|
|
@@ -52,7 +52,7 @@ export class SandboxDrive extends SandboxAction {
|
|
|
52
52
|
*/
|
|
53
53
|
async list() {
|
|
54
54
|
const headers = this.sandbox.forceUrl ? this.sandbox.headers : settings.headers;
|
|
55
|
-
const response = await
|
|
55
|
+
const response = await this.h2Fetch(`${this.url}/drives/mount`, {
|
|
56
56
|
method: 'GET',
|
|
57
57
|
headers,
|
|
58
58
|
});
|
|
@@ -98,8 +98,7 @@ export class SandboxFileSystem extends SandboxAction {
|
|
|
98
98
|
if (this.forcedUrl) {
|
|
99
99
|
url = `${this.forcedUrl.toString()}/filesystem/${path}`;
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
const response = await fetch(url, {
|
|
101
|
+
const response = await this.h2Fetch(url, {
|
|
103
102
|
method: 'PUT',
|
|
104
103
|
headers: {
|
|
105
104
|
...settings.headers,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { h2RequestDirect } from "../common/h2fetch.js";
|
|
1
2
|
import { logger } from "../common/logger.js";
|
|
2
3
|
import { settings } from "../common/settings.js";
|
|
3
4
|
import { SandboxInstance } from "./sandbox.js";
|
|
@@ -23,6 +24,7 @@ export class CodeInterpreter extends SandboxInstance {
|
|
|
23
24
|
spec: base.spec,
|
|
24
25
|
status: base.status,
|
|
25
26
|
events: base.events,
|
|
27
|
+
h2Session: base.h2Session,
|
|
26
28
|
};
|
|
27
29
|
return new CodeInterpreter(config);
|
|
28
30
|
}
|
|
@@ -80,6 +82,7 @@ export class CodeInterpreter extends SandboxInstance {
|
|
|
80
82
|
spec: baseInstance.spec,
|
|
81
83
|
status: baseInstance.status,
|
|
82
84
|
events: baseInstance.events,
|
|
85
|
+
h2Session: baseInstance.h2Session,
|
|
83
86
|
};
|
|
84
87
|
// Preserve forceUrl and headers from input if it was a dict-like object
|
|
85
88
|
if (sandbox && typeof sandbox === "object" && !Array.isArray(sandbox)) {
|
|
@@ -98,6 +101,13 @@ export class CodeInterpreter extends SandboxInstance {
|
|
|
98
101
|
get _jupyterUrl() {
|
|
99
102
|
return this.process.url;
|
|
100
103
|
}
|
|
104
|
+
_fetch(input, init) {
|
|
105
|
+
const session = this._sandboxConfig.h2Session;
|
|
106
|
+
if (session && !session.closed && !session.destroyed) {
|
|
107
|
+
return h2RequestDirect(session, input.toString(), init);
|
|
108
|
+
}
|
|
109
|
+
return globalThis.fetch(input, init);
|
|
110
|
+
}
|
|
101
111
|
static OutputMessage = class {
|
|
102
112
|
text;
|
|
103
113
|
timestamp;
|
|
@@ -257,7 +267,7 @@ export class CodeInterpreter extends SandboxInstance {
|
|
|
257
267
|
}, readTimeout * 1000);
|
|
258
268
|
}
|
|
259
269
|
try {
|
|
260
|
-
const response = await
|
|
270
|
+
const response = await this._fetch(`${this._jupyterUrl}/port/8888/execute`, {
|
|
261
271
|
method: "POST",
|
|
262
272
|
headers: {
|
|
263
273
|
...headers,
|
|
@@ -356,7 +366,7 @@ export class CodeInterpreter extends SandboxInstance {
|
|
|
356
366
|
}, requestTimeout * 1000);
|
|
357
367
|
}
|
|
358
368
|
try {
|
|
359
|
-
const response = await
|
|
369
|
+
const response = await this._fetch(`${this._jupyterUrl}/port/8888/contexts`, {
|
|
360
370
|
method: "POST",
|
|
361
371
|
headers: {
|
|
362
372
|
...headers,
|
|
@@ -18,7 +18,7 @@ export class SandboxProcess extends SandboxAction {
|
|
|
18
18
|
const done = (async () => {
|
|
19
19
|
try {
|
|
20
20
|
const headers = this.sandbox.forceUrl ? this.sandbox.headers : settings.headers;
|
|
21
|
-
const stream = await
|
|
21
|
+
const stream = await this.h2Fetch(`${this.url}/process/${identifier}/logs/stream`, {
|
|
22
22
|
method: 'GET',
|
|
23
23
|
signal: controller.signal,
|
|
24
24
|
headers,
|
|
@@ -120,7 +120,7 @@ export class SandboxProcess extends SandboxAction {
|
|
|
120
120
|
async execWithStreaming(processRequest, options) {
|
|
121
121
|
const headers = this.sandbox.forceUrl ? this.sandbox.headers : settings.headers;
|
|
122
122
|
const controller = new AbortController();
|
|
123
|
-
const response = await
|
|
123
|
+
const response = await this.h2Fetch(`${this.url}/process`, {
|
|
124
124
|
method: 'POST',
|
|
125
125
|
signal: controller.signal,
|
|
126
126
|
headers: {
|
|
@@ -21,6 +21,8 @@ export class SandboxInstance {
|
|
|
21
21
|
codegen;
|
|
22
22
|
system;
|
|
23
23
|
drives;
|
|
24
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
25
|
+
h2Session;
|
|
24
26
|
constructor(sandbox) {
|
|
25
27
|
this.sandbox = sandbox;
|
|
26
28
|
this.process = new SandboxProcess(sandbox);
|
|
@@ -31,6 +33,7 @@ export class SandboxInstance {
|
|
|
31
33
|
this.codegen = new SandboxCodegen(sandbox);
|
|
32
34
|
this.system = new SandboxSystem(sandbox);
|
|
33
35
|
this.drives = new SandboxDrive(sandbox);
|
|
36
|
+
this.h2Session = null;
|
|
34
37
|
}
|
|
35
38
|
get metadata() {
|
|
36
39
|
return this.sandbox.metadata;
|
|
@@ -47,6 +50,27 @@ export class SandboxInstance {
|
|
|
47
50
|
get lastUsedAt() {
|
|
48
51
|
return this.sandbox.lastUsedAt;
|
|
49
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Warm and attach an H2 session based on the sandbox's region.
|
|
55
|
+
* Shared by create(), get(), list(), and update helpers.
|
|
56
|
+
*/
|
|
57
|
+
static async attachH2Session(instance) {
|
|
58
|
+
const region = instance.spec?.region;
|
|
59
|
+
if (!region)
|
|
60
|
+
return instance;
|
|
61
|
+
const edgeSuffix = settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
|
|
62
|
+
const edgeDomain = `any.${region}.${edgeSuffix}`;
|
|
63
|
+
try {
|
|
64
|
+
const { h2Pool } = await import("../common/h2pool.js");
|
|
65
|
+
const h2Session = await h2Pool.get(edgeDomain);
|
|
66
|
+
instance.h2Session = h2Session;
|
|
67
|
+
instance.sandbox.h2Session = h2Session;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// H2 warming is best-effort; fall back to regular fetch
|
|
71
|
+
}
|
|
72
|
+
return instance;
|
|
73
|
+
}
|
|
50
74
|
get expiresIn() {
|
|
51
75
|
return this.sandbox.expiresIn;
|
|
52
76
|
}
|
|
@@ -128,11 +152,24 @@ export class SandboxInstance {
|
|
|
128
152
|
}
|
|
129
153
|
sandbox.spec.runtime.image = sandbox.spec.runtime.image || defaultImage;
|
|
130
154
|
sandbox.spec.runtime.memory = sandbox.spec.runtime.memory || defaultMemory;
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
155
|
+
const edgeSuffix = settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
|
|
156
|
+
const edgeDomain = sandbox.spec?.region ? `any.${sandbox.spec.region}.${edgeSuffix}` : null;
|
|
157
|
+
// Kick off warming so h2Pool.get() can join it during the API call
|
|
158
|
+
if (edgeDomain) {
|
|
159
|
+
import("../common/h2pool.js").then(({ h2Pool }) => h2Pool.warm(edgeDomain)).catch(() => { });
|
|
160
|
+
}
|
|
161
|
+
const [{ data }, h2Session] = await Promise.all([
|
|
162
|
+
createSandbox({
|
|
163
|
+
body: sandbox,
|
|
164
|
+
throwOnError: true,
|
|
165
|
+
}),
|
|
166
|
+
edgeDomain ? import("../common/h2pool.js").then(({ h2Pool }) => h2Pool.get(edgeDomain)).catch(() => null) : Promise.resolve(null),
|
|
167
|
+
]);
|
|
168
|
+
// Inject the H2 session into the config so subsystems can use it
|
|
169
|
+
const config = { ...data, h2Session };
|
|
170
|
+
const instance = new SandboxInstance(config);
|
|
171
|
+
instance.h2Session = h2Session;
|
|
172
|
+
// Note: H2 session already attached via Promise.all above, no need for attachH2Session()
|
|
136
173
|
// TODO remove this part once we have a better way to handle this
|
|
137
174
|
if (safe) {
|
|
138
175
|
try {
|
|
@@ -149,11 +186,13 @@ export class SandboxInstance {
|
|
|
149
186
|
},
|
|
150
187
|
throwOnError: true,
|
|
151
188
|
});
|
|
152
|
-
|
|
189
|
+
const instance = new SandboxInstance(data);
|
|
190
|
+
return SandboxInstance.attachH2Session(instance);
|
|
153
191
|
}
|
|
154
192
|
static async list() {
|
|
155
193
|
const { data } = await listSandboxes({ throwOnError: true });
|
|
156
|
-
|
|
194
|
+
const instances = data.map((sandbox) => new SandboxInstance(sandbox));
|
|
195
|
+
return Promise.all(instances.map((instance) => SandboxInstance.attachH2Session(instance)));
|
|
157
196
|
}
|
|
158
197
|
static async delete(sandboxName) {
|
|
159
198
|
const { data } = await deleteSandbox({
|
|
@@ -165,6 +204,8 @@ export class SandboxInstance {
|
|
|
165
204
|
return data;
|
|
166
205
|
}
|
|
167
206
|
async delete() {
|
|
207
|
+
// Don't close the H2 session — it's shared via h2Pool
|
|
208
|
+
this.h2Session = null;
|
|
168
209
|
return await SandboxInstance.delete(this.metadata.name);
|
|
169
210
|
}
|
|
170
211
|
static async updateMetadata(sandboxName, metadata) {
|
|
@@ -176,7 +217,7 @@ export class SandboxInstance {
|
|
|
176
217
|
throwOnError: true,
|
|
177
218
|
});
|
|
178
219
|
const instance = new SandboxInstance(data);
|
|
179
|
-
return instance;
|
|
220
|
+
return SandboxInstance.attachH2Session(instance);
|
|
180
221
|
}
|
|
181
222
|
static async updateTtl(sandboxName, ttl) {
|
|
182
223
|
const sandbox = await SandboxInstance.get(sandboxName);
|
|
@@ -187,7 +228,7 @@ export class SandboxInstance {
|
|
|
187
228
|
throwOnError: true,
|
|
188
229
|
});
|
|
189
230
|
const instance = new SandboxInstance(data);
|
|
190
|
-
return instance;
|
|
231
|
+
return SandboxInstance.attachH2Session(instance);
|
|
191
232
|
}
|
|
192
233
|
static async updateLifecycle(sandboxName, lifecycle) {
|
|
193
234
|
const sandbox = await SandboxInstance.get(sandboxName);
|
|
@@ -198,7 +239,7 @@ export class SandboxInstance {
|
|
|
198
239
|
throwOnError: true,
|
|
199
240
|
});
|
|
200
241
|
const instance = new SandboxInstance(data);
|
|
201
|
-
return instance;
|
|
242
|
+
return SandboxInstance.attachH2Session(instance);
|
|
202
243
|
}
|
|
203
244
|
static async createIfNotExists(sandbox) {
|
|
204
245
|
try {
|