@blaxel/core 0.2.55 → 0.2.56-dev.23
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/client/sdk.gen.js +2 -36
- package/dist/cjs/common/sentry.js +227 -131
- package/dist/cjs/common/settings.js +3 -3
- package/dist/cjs/common/version.js +6 -0
- package/dist/cjs/types/client/sdk.gen.d.ts +1 -11
- package/dist/cjs/types/client/types.gen.d.ts +0 -48
- package/dist/cjs/types/common/sentry.d.ts +1 -3
- package/dist/cjs/types/common/version.d.ts +2 -0
- package/dist/cjs/types/sandbox/client/sdk.gen.d.ts +3 -3
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/client/sdk.gen.js +2 -36
- package/dist/cjs-browser/common/sentry-browser.js +27 -0
- package/dist/cjs-browser/common/sentry.js +306 -11
- package/dist/cjs-browser/common/settings.js +3 -3
- package/dist/cjs-browser/common/version.js +6 -0
- package/dist/cjs-browser/types/client/sdk.gen.d.ts +1 -11
- package/dist/cjs-browser/types/client/types.gen.d.ts +0 -48
- package/dist/cjs-browser/types/common/sentry.d.ts +1 -3
- package/dist/cjs-browser/types/common/version.d.ts +2 -0
- package/dist/cjs-browser/types/sandbox/client/sdk.gen.d.ts +3 -3
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/client/sdk.gen.js +0 -32
- package/dist/esm/common/sentry.js +227 -98
- package/dist/esm/common/settings.js +3 -3
- package/dist/esm/common/version.js +3 -0
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/client/sdk.gen.js +0 -32
- package/dist/esm-browser/common/sentry-browser.js +22 -0
- package/dist/esm-browser/common/sentry.js +306 -11
- package/dist/esm-browser/common/settings.js +3 -3
- package/dist/esm-browser/common/version.js +3 -0
- package/package.json +2 -4
|
@@ -1206,38 +1206,6 @@ export const deleteSandboxPreviewToken = (options) => {
|
|
|
1206
1206
|
...options
|
|
1207
1207
|
});
|
|
1208
1208
|
};
|
|
1209
|
-
/**
|
|
1210
|
-
* Start Sandbox
|
|
1211
|
-
* Starts a Sandbox by name.
|
|
1212
|
-
*/
|
|
1213
|
-
export const startSandbox = (options) => {
|
|
1214
|
-
return (options.client ?? _heyApiClient).put({
|
|
1215
|
-
security: [
|
|
1216
|
-
{
|
|
1217
|
-
scheme: 'bearer',
|
|
1218
|
-
type: 'http'
|
|
1219
|
-
}
|
|
1220
|
-
],
|
|
1221
|
-
url: '/sandboxes/{sandboxName}/start',
|
|
1222
|
-
...options
|
|
1223
|
-
});
|
|
1224
|
-
};
|
|
1225
|
-
/**
|
|
1226
|
-
* Stop Sandbox
|
|
1227
|
-
* Stops a Sandbox by name.
|
|
1228
|
-
*/
|
|
1229
|
-
export const stopSandbox = (options) => {
|
|
1230
|
-
return (options.client ?? _heyApiClient).put({
|
|
1231
|
-
security: [
|
|
1232
|
-
{
|
|
1233
|
-
scheme: 'bearer',
|
|
1234
|
-
type: 'http'
|
|
1235
|
-
}
|
|
1236
|
-
],
|
|
1237
|
-
url: '/sandboxes/{sandboxName}/stop',
|
|
1238
|
-
...options
|
|
1239
|
-
});
|
|
1240
|
-
};
|
|
1241
1209
|
/**
|
|
1242
1210
|
* Get workspace service accounts
|
|
1243
1211
|
* Returns a list of all service accounts in the workspace.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Browser/Edge-compatible exports for Sentry
|
|
3
|
+
// In browser/edge environments, @sentry/node is not available
|
|
4
|
+
// All functions are no-ops
|
|
5
|
+
/**
|
|
6
|
+
* Initialize Sentry - no-op in browser/edge environments.
|
|
7
|
+
*/
|
|
8
|
+
export function initSentry() {
|
|
9
|
+
// No-op in browser/edge environments
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Flush pending Sentry events - no-op in browser/edge environments.
|
|
13
|
+
*/
|
|
14
|
+
export async function flushSentry(_timeout = 2000) {
|
|
15
|
+
// No-op in browser/edge environments
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if Sentry is initialized - always returns false in browser/edge environments.
|
|
19
|
+
*/
|
|
20
|
+
export function isSentryInitialized() {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
@@ -1,22 +1,317 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { settings } from "./settings.js";
|
|
2
|
+
// Lightweight Sentry client using fetch - only captures SDK errors
|
|
3
|
+
let sentryInitialized = false;
|
|
4
|
+
const capturedExceptions = new Set();
|
|
5
|
+
let handlersRegistered = false;
|
|
6
|
+
// Parsed DSN components
|
|
7
|
+
let sentryConfig = null;
|
|
8
|
+
// SDK path patterns to identify errors originating from our SDK
|
|
9
|
+
const SDK_PATTERNS = [
|
|
10
|
+
"@blaxel/",
|
|
11
|
+
"blaxel-sdk",
|
|
12
|
+
"/node_modules/@blaxel/",
|
|
13
|
+
"/@blaxel/core/",
|
|
14
|
+
"/@blaxel/telemetry/",
|
|
15
|
+
];
|
|
5
16
|
/**
|
|
6
|
-
*
|
|
17
|
+
* Check if an error originated from the SDK based on its stack trace.
|
|
18
|
+
* Returns true if the stack trace contains any SDK-related paths.
|
|
19
|
+
*/
|
|
20
|
+
function isFromSDK(error) {
|
|
21
|
+
const stack = error.stack || "";
|
|
22
|
+
return SDK_PATTERNS.some((pattern) => stack.includes(pattern));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse a Sentry DSN into its components.
|
|
26
|
+
* DSN format: https://{public_key}@{host}/{project_id}
|
|
27
|
+
*/
|
|
28
|
+
function parseDsn(dsn) {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(dsn);
|
|
31
|
+
const publicKey = url.username;
|
|
32
|
+
const host = url.host;
|
|
33
|
+
const projectId = url.pathname.slice(1); // Remove leading slash
|
|
34
|
+
if (!publicKey || !host || !projectId) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return { publicKey, host, projectId };
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate a UUID v4
|
|
45
|
+
*/
|
|
46
|
+
function generateEventId() {
|
|
47
|
+
return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
48
|
+
const r = (Math.random() * 16) | 0;
|
|
49
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
50
|
+
return v.toString(16);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert an Error to a Sentry event payload.
|
|
55
|
+
*/
|
|
56
|
+
function errorToSentryEvent(error) {
|
|
57
|
+
const frames = parseStackTrace(error.stack || "");
|
|
58
|
+
return {
|
|
59
|
+
event_id: generateEventId(),
|
|
60
|
+
timestamp: Date.now() / 1000,
|
|
61
|
+
platform: "javascript",
|
|
62
|
+
level: "error",
|
|
63
|
+
environment: settings.env,
|
|
64
|
+
release: `sdk-typescript@${settings.version}`,
|
|
65
|
+
tags: {
|
|
66
|
+
"blaxel.workspace": settings.workspace,
|
|
67
|
+
"blaxel.version": settings.version,
|
|
68
|
+
"blaxel.commit": settings.commit,
|
|
69
|
+
},
|
|
70
|
+
exception: {
|
|
71
|
+
values: [
|
|
72
|
+
{
|
|
73
|
+
type: error.name,
|
|
74
|
+
value: error.message,
|
|
75
|
+
stacktrace: {
|
|
76
|
+
frames,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Parse a stack trace string into Sentry-compatible frames.
|
|
85
|
+
*/
|
|
86
|
+
function parseStackTrace(stack) {
|
|
87
|
+
const lines = stack.split("\n").slice(1); // Skip first line (error message)
|
|
88
|
+
const frames = [];
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
// Match patterns like "at functionName (filename:line:col)" or "at filename:line:col"
|
|
91
|
+
const match = line.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);
|
|
92
|
+
if (match) {
|
|
93
|
+
frames.unshift({
|
|
94
|
+
function: match[1] || "<anonymous>",
|
|
95
|
+
filename: match[2],
|
|
96
|
+
lineno: parseInt(match[3], 10),
|
|
97
|
+
colno: parseInt(match[4], 10),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return frames;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Send an event to Sentry using fetch.
|
|
105
|
+
*/
|
|
106
|
+
async function sendToSentry(event) {
|
|
107
|
+
if (!sentryConfig)
|
|
108
|
+
return;
|
|
109
|
+
const { publicKey, host, projectId } = sentryConfig;
|
|
110
|
+
const envelopeUrl = `https://${host}/api/${projectId}/envelope/`;
|
|
111
|
+
// Create envelope header
|
|
112
|
+
const envelopeHeader = JSON.stringify({
|
|
113
|
+
event_id: event.event_id,
|
|
114
|
+
sent_at: new Date().toISOString(),
|
|
115
|
+
dsn: `https://${publicKey}@${host}/${projectId}`,
|
|
116
|
+
});
|
|
117
|
+
// Create item header
|
|
118
|
+
const itemHeader = JSON.stringify({
|
|
119
|
+
type: "event",
|
|
120
|
+
content_type: "application/json",
|
|
121
|
+
});
|
|
122
|
+
// Create envelope body
|
|
123
|
+
const envelope = `${envelopeHeader}\n${itemHeader}\n${JSON.stringify(event)}`;
|
|
124
|
+
try {
|
|
125
|
+
await fetch(envelopeUrl, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
headers: {
|
|
128
|
+
"Content-Type": "application/x-sentry-envelope",
|
|
129
|
+
"X-Sentry-Auth": `Sentry sentry_version=7, sentry_client=blaxel-sdk/${settings.version}, sentry_key=${publicKey}`,
|
|
130
|
+
},
|
|
131
|
+
body: envelope,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Silently fail - error reporting should never break the SDK
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Queue for pending events
|
|
139
|
+
const pendingEvents = [];
|
|
140
|
+
let flushPromise = null;
|
|
141
|
+
/**
|
|
142
|
+
* Register browser/edge environment error handlers.
|
|
143
|
+
* Separated to isolate dynamic globalThis access.
|
|
144
|
+
*/
|
|
145
|
+
function registerBrowserHandlers() {
|
|
146
|
+
const g = globalThis;
|
|
147
|
+
if (g && typeof g.addEventListener === "function") {
|
|
148
|
+
g.addEventListener("error", (event) => {
|
|
149
|
+
const e = event;
|
|
150
|
+
if (e.error instanceof Error && isFromSDK(e.error)) {
|
|
151
|
+
captureException(e.error);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
g.addEventListener("unhandledrejection", (event) => {
|
|
155
|
+
const e = event;
|
|
156
|
+
const error = e.reason instanceof Error ? e.reason : new Error(String(e.reason));
|
|
157
|
+
if (isFromSDK(error)) {
|
|
158
|
+
captureException(error);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Initialize the lightweight Sentry client for SDK error tracking.
|
|
7
165
|
*/
|
|
8
166
|
export function initSentry() {
|
|
9
|
-
|
|
167
|
+
try {
|
|
168
|
+
// Check if tracking is disabled
|
|
169
|
+
if (!settings.tracking) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const dsn = settings.sentryDsn;
|
|
173
|
+
if (!dsn) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Parse DSN
|
|
177
|
+
sentryConfig = parseDsn(dsn);
|
|
178
|
+
if (!sentryConfig) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Only allow dev/prod environments
|
|
182
|
+
if (settings.env !== "dev" && settings.env !== "prod") {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
sentryInitialized = true;
|
|
186
|
+
// Register error handlers only once
|
|
187
|
+
if (!handlersRegistered) {
|
|
188
|
+
handlersRegistered = true;
|
|
189
|
+
// Node.js specific handlers
|
|
190
|
+
if (typeof process !== "undefined" && typeof process.on === "function") {
|
|
191
|
+
// For SIGTERM/SIGINT, flush before exit
|
|
192
|
+
const signalHandler = (signal) => {
|
|
193
|
+
flushSentry(500)
|
|
194
|
+
.catch(() => {
|
|
195
|
+
// Silently fail
|
|
196
|
+
})
|
|
197
|
+
.finally(() => {
|
|
198
|
+
process.exit(signal === "SIGTERM" ? 143 : 130);
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
// Uncaught exception handler - only capture SDK errors
|
|
202
|
+
const uncaughtExceptionHandler = (error) => {
|
|
203
|
+
if (isFromSDK(error)) {
|
|
204
|
+
captureException(error);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
// Unhandled rejection handler - only capture SDK errors
|
|
208
|
+
const unhandledRejectionHandler = (reason) => {
|
|
209
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
210
|
+
if (isFromSDK(error)) {
|
|
211
|
+
captureException(error);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
process.on("SIGTERM", () => signalHandler("SIGTERM"));
|
|
215
|
+
process.on("SIGINT", () => signalHandler("SIGINT"));
|
|
216
|
+
process.on("uncaughtException", uncaughtExceptionHandler);
|
|
217
|
+
process.on("unhandledRejection", unhandledRejectionHandler);
|
|
218
|
+
// Intercept console.error to capture SDK errors that are caught and logged
|
|
219
|
+
const originalConsoleError = console.error;
|
|
220
|
+
console.error = function (...args) {
|
|
221
|
+
originalConsoleError.apply(console, args);
|
|
222
|
+
for (const arg of args) {
|
|
223
|
+
if (arg instanceof Error && isFromSDK(arg)) {
|
|
224
|
+
captureException(arg);
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Browser/Edge environment handlers
|
|
232
|
+
registerBrowserHandlers();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
// Silently fail - Sentry initialization should never break the SDK
|
|
238
|
+
if (settings.env !== "production") {
|
|
239
|
+
console.error("[Blaxel SDK] Error initializing Sentry:", error);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Capture an exception to Sentry.
|
|
245
|
+
* Only errors originating from SDK code will be captured.
|
|
246
|
+
*
|
|
247
|
+
* @param error - The error to capture
|
|
248
|
+
*/
|
|
249
|
+
function captureException(error) {
|
|
250
|
+
if (!sentryInitialized || !sentryConfig) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
// Double-check that error is from SDK (defense in depth)
|
|
254
|
+
if (!isFromSDK(error)) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
// Create a unique identifier for this exception to avoid duplicates
|
|
259
|
+
const errorKey = `${error.name}:${error.message}:${error.stack?.slice(0, 200)}`;
|
|
260
|
+
if (capturedExceptions.has(errorKey)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
capturedExceptions.add(errorKey);
|
|
264
|
+
// Clean up old exception keys to prevent memory leak
|
|
265
|
+
if (capturedExceptions.size > 1000) {
|
|
266
|
+
capturedExceptions.clear();
|
|
267
|
+
}
|
|
268
|
+
// Convert error to Sentry event and queue it
|
|
269
|
+
const event = errorToSentryEvent(error);
|
|
270
|
+
pendingEvents.push(event);
|
|
271
|
+
// Send immediately (fire and forget)
|
|
272
|
+
sendToSentry(event).catch(() => {
|
|
273
|
+
// Silently fail
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Silently fail - error capturing should never break the SDK
|
|
278
|
+
}
|
|
10
279
|
}
|
|
11
280
|
/**
|
|
12
|
-
* Flush pending Sentry events
|
|
281
|
+
* Flush pending Sentry events.
|
|
282
|
+
* This should be called before the process exits to ensure all events are sent.
|
|
283
|
+
*
|
|
284
|
+
* @param timeout - Maximum time in milliseconds to wait for flush (default: 2000)
|
|
13
285
|
*/
|
|
14
|
-
export async function flushSentry(
|
|
15
|
-
|
|
286
|
+
export async function flushSentry(timeout = 2000) {
|
|
287
|
+
if (!sentryInitialized || pendingEvents.length === 0) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
// If already flushing, wait for it
|
|
291
|
+
if (flushPromise) {
|
|
292
|
+
await flushPromise;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
// Send all pending events
|
|
297
|
+
const eventsToSend = [...pendingEvents];
|
|
298
|
+
pendingEvents.length = 0;
|
|
299
|
+
flushPromise = Promise.race([
|
|
300
|
+
Promise.all(eventsToSend.map((event) => sendToSentry(event))).then(() => { }),
|
|
301
|
+
new Promise((resolve) => setTimeout(resolve, timeout)),
|
|
302
|
+
]);
|
|
303
|
+
await flushPromise;
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Silently fail
|
|
307
|
+
}
|
|
308
|
+
finally {
|
|
309
|
+
flushPromise = null;
|
|
310
|
+
}
|
|
16
311
|
}
|
|
17
312
|
/**
|
|
18
|
-
* Check if Sentry is initialized
|
|
313
|
+
* Check if Sentry is initialized and available.
|
|
19
314
|
*/
|
|
20
315
|
export function isSentryInitialized() {
|
|
21
|
-
return
|
|
316
|
+
return sentryInitialized;
|
|
22
317
|
}
|
|
@@ -3,9 +3,9 @@ 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.
|
|
7
|
-
const BUILD_COMMIT = "
|
|
8
|
-
const BUILD_SENTRY_DSN = "
|
|
6
|
+
const BUILD_VERSION = "0.2.56-dev.23";
|
|
7
|
+
const BUILD_COMMIT = "d54548dc9e764e57728f9eda7721d5e50f11573a";
|
|
8
|
+
const BUILD_SENTRY_DSN = "";
|
|
9
9
|
// Cache for config.yaml tracking value
|
|
10
10
|
let configTrackingValue = null;
|
|
11
11
|
let configTrackingLoaded = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blaxel/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.56-dev.23",
|
|
4
4
|
"description": "Blaxel Core SDK for TypeScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Blaxel, INC (https://blaxel.ai)",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@hey-api/client-fetch": "^0.10.0",
|
|
55
55
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
56
|
+
"@sentry/node": "^10.27.0",
|
|
56
57
|
"axios": "^1.9.0",
|
|
57
58
|
"dotenv": "^16.5.0",
|
|
58
59
|
"form-data": "^4.0.2",
|
|
@@ -63,9 +64,6 @@
|
|
|
63
64
|
"yaml": "^2.7.1",
|
|
64
65
|
"zod": "^3.24.3"
|
|
65
66
|
},
|
|
66
|
-
"optionalDependencies": {
|
|
67
|
-
"@sentry/node": "^10.27.0"
|
|
68
|
-
},
|
|
69
67
|
"devDependencies": {
|
|
70
68
|
"@eslint/js": "^9.26.0",
|
|
71
69
|
"@testing-library/dom": "^9.3.0",
|