@blaxel/core 0.2.52 → 0.2.53

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.
@@ -6,6 +6,7 @@ const client_gen_js_1 = require("../client/client.gen.js");
6
6
  const interceptors_js_1 = require("../client/interceptors.js");
7
7
  const responseInterceptor_js_1 = require("../client/responseInterceptor.js");
8
8
  const client_gen_js_2 = require("../sandbox/client/client.gen.js");
9
+ const sentry_js_1 = require("./sentry.js");
9
10
  const settings_js_1 = require("./settings.js");
10
11
  client_gen_js_1.client.setConfig({
11
12
  baseUrl: settings_js_1.settings.baseUrl,
@@ -22,6 +23,8 @@ for (const interceptor of responseInterceptor_js_1.responseInterceptors) {
22
23
  client_gen_js_1.client.interceptors.response.use(interceptor);
23
24
  client_gen_js_2.client.interceptors.response.use(interceptor);
24
25
  }
26
+ // Initialize Sentry for SDK error tracking immediately when module loads
27
+ (0, sentry_js_1.initSentry)();
25
28
  // Allow to set custom configuration for browser environment
26
29
  function initialize(config) {
27
30
  settings_js_1.settings.setConfig(config);
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.initSentry = initSentry;
37
+ exports.flushSentry = flushSentry;
38
+ exports.isSentryInitialized = isSentryInitialized;
39
+ const settings_js_1 = require("./settings.js");
40
+ const Sentry = __importStar(require("@sentry/node"));
41
+ const node_1 = require("@sentry/node");
42
+ // Isolated Sentry client for SDK-only error tracking (doesn't interfere with user's Sentry)
43
+ let sentryClient = null;
44
+ const capturedExceptions = new Set();
45
+ let handlersRegistered = false;
46
+ // SDK path patterns to identify errors originating from our SDK
47
+ const SDK_PATTERNS = [
48
+ "@blaxel/",
49
+ "blaxel-sdk",
50
+ "/node_modules/@blaxel/",
51
+ "/@blaxel/core/",
52
+ "/@blaxel/telemetry/",
53
+ ];
54
+ /**
55
+ * Check if an error originated from the SDK based on its stack trace.
56
+ * Returns true if the stack trace contains any SDK-related paths.
57
+ */
58
+ function isFromSDK(error) {
59
+ const stack = error.stack || "";
60
+ return SDK_PATTERNS.some((pattern) => stack.includes(pattern));
61
+ }
62
+ /**
63
+ * Initialize an isolated Sentry client for SDK error tracking.
64
+ * This creates a separate Sentry instance that won't interfere with any
65
+ * Sentry configuration the user might have in their application.
66
+ */
67
+ function initSentry() {
68
+ try {
69
+ // Check if tracking is disabled
70
+ if (!settings_js_1.settings.tracking) {
71
+ return;
72
+ }
73
+ const dsn = settings_js_1.settings.sentryDsn;
74
+ if (!dsn) {
75
+ return;
76
+ }
77
+ // Create an isolated Sentry client that doesn't touch the global scope
78
+ // This allows users to have their own Sentry.init() without conflicts
79
+ sentryClient = new Sentry.NodeClient({
80
+ dsn,
81
+ environment: settings_js_1.settings.env,
82
+ release: `sdk-typescript@${settings_js_1.settings.version}`,
83
+ transport: node_1.makeNodeTransport,
84
+ stackParser: Sentry.defaultStackParser,
85
+ // No integrations - we handle error capturing manually
86
+ integrations: [],
87
+ // Disable traces for the SDK client
88
+ tracesSampleRate: 0,
89
+ // Filter errors before sending - only send SDK errors
90
+ beforeSend(event, hint) {
91
+ if (event.environment !== 'dev' && event.environment !== 'prod') {
92
+ return null;
93
+ }
94
+ const error = hint.originalException;
95
+ if (error instanceof Error) {
96
+ if (!isFromSDK(error)) {
97
+ // Drop errors that don't originate from SDK
98
+ return null;
99
+ }
100
+ }
101
+ return event;
102
+ },
103
+ });
104
+ sentryClient.init();
105
+ // Set SDK-specific tags
106
+ const scope = new Sentry.Scope();
107
+ scope.setTag("blaxel.workspace", settings_js_1.settings.workspace);
108
+ scope.setTag("blaxel.version", settings_js_1.settings.version);
109
+ scope.setTag("blaxel.commit", settings_js_1.settings.commit);
110
+ scope.setClient(sentryClient);
111
+ // Register process handlers for uncaught errors (Node.js only)
112
+ // Only register once to prevent memory leaks
113
+ if (typeof process !== "undefined" &&
114
+ typeof process.on === "function" &&
115
+ !handlersRegistered) {
116
+ handlersRegistered = true;
117
+ // For SIGTERM/SIGINT, flush before exit
118
+ const signalHandler = (signal) => {
119
+ flushSentry(500)
120
+ .catch(() => {
121
+ // Silently fail
122
+ })
123
+ .finally(() => {
124
+ process.exit(signal === "SIGTERM" ? 143 : 130);
125
+ });
126
+ };
127
+ // Uncaught exception handler - only capture SDK errors
128
+ const uncaughtExceptionHandler = (error) => {
129
+ if (isFromSDK(error)) {
130
+ captureException(error);
131
+ }
132
+ // Let the default Node.js behavior handle the process exit
133
+ };
134
+ // Unhandled rejection handler - only capture SDK errors
135
+ const unhandledRejectionHandler = (reason) => {
136
+ const error = reason instanceof Error ? reason : new Error(String(reason));
137
+ if (isFromSDK(error)) {
138
+ captureException(error);
139
+ }
140
+ };
141
+ process.on("SIGTERM", () => signalHandler("SIGTERM"));
142
+ process.on("SIGINT", () => signalHandler("SIGINT"));
143
+ process.on("uncaughtException", uncaughtExceptionHandler);
144
+ process.on("unhandledRejection", unhandledRejectionHandler);
145
+ // Intercept console.error to capture SDK errors that are caught and logged
146
+ const originalConsoleError = console.error;
147
+ console.error = function (...args) {
148
+ // Call the original console.error first
149
+ originalConsoleError.apply(console, args);
150
+ // Check if any argument is an Error from SDK and capture it
151
+ for (const arg of args) {
152
+ if (arg instanceof Error && isFromSDK(arg)) {
153
+ captureException(arg);
154
+ break; // Only capture the first SDK error to avoid duplicates
155
+ }
156
+ }
157
+ };
158
+ }
159
+ }
160
+ catch (error) {
161
+ // Silently fail - Sentry initialization should never break the SDK
162
+ if (settings_js_1.settings.env !== "production") {
163
+ console.error("[Blaxel SDK] Error initializing Sentry:", error);
164
+ }
165
+ }
166
+ }
167
+ /**
168
+ * Capture an exception to the SDK's isolated Sentry client.
169
+ * Only errors originating from SDK code will be captured.
170
+ *
171
+ * @param error - The error to capture
172
+ */
173
+ function captureException(error) {
174
+ if (sentryClient === null) {
175
+ return;
176
+ }
177
+ // Double-check that error is from SDK (defense in depth)
178
+ if (!isFromSDK(error)) {
179
+ return;
180
+ }
181
+ try {
182
+ // Create a unique identifier for this exception to avoid duplicates
183
+ const errorKey = `${error.name}:${error.message}:${error.stack?.slice(0, 200)}`;
184
+ if (capturedExceptions.has(errorKey)) {
185
+ return;
186
+ }
187
+ capturedExceptions.add(errorKey);
188
+ // Clean up old exception keys to prevent memory leak
189
+ if (capturedExceptions.size > 1000) {
190
+ capturedExceptions.clear();
191
+ }
192
+ // Create a scope with SDK tags and capture the exception
193
+ const scope = new Sentry.Scope();
194
+ scope.setTag("blaxel.workspace", settings_js_1.settings.workspace);
195
+ scope.setTag("blaxel.version", settings_js_1.settings.version);
196
+ scope.setTag("blaxel.commit", settings_js_1.settings.commit);
197
+ scope.setClient(sentryClient);
198
+ scope.captureException(error);
199
+ }
200
+ catch {
201
+ // Silently fail - error capturing should never break the SDK
202
+ }
203
+ }
204
+ /**
205
+ * Flush pending Sentry events.
206
+ * This should be called before the process exits to ensure all events are sent.
207
+ *
208
+ * @param timeout - Maximum time in milliseconds to wait for flush (default: 2000)
209
+ */
210
+ async function flushSentry(timeout = 2000) {
211
+ if (sentryClient === null) {
212
+ return;
213
+ }
214
+ try {
215
+ await sentryClient.flush(timeout);
216
+ }
217
+ catch {
218
+ // Silently fail
219
+ }
220
+ }
221
+ /**
222
+ * Check if Sentry is initialized and available.
223
+ */
224
+ function isSentryInitialized() {
225
+ return sentryClient !== null;
226
+ }
@@ -1,27 +1,41 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.settings = void 0;
7
+ const yaml_1 = __importDefault(require("yaml"));
4
8
  const index_js_1 = require("../authentication/index.js");
5
9
  const env_js_1 = require("../common/env.js");
6
- // Function to get package version
7
- function getPackageVersion() {
10
+ const node_js_1 = require("../common/node.js");
11
+ // Build info - these placeholders are replaced at build time by build:replace-imports
12
+ const BUILD_VERSION = "0.2.53";
13
+ const BUILD_COMMIT = "1a161063708104c65ae116d189af51e3b9cc5ef7";
14
+ const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
15
+ // Cache for config.yaml tracking value
16
+ let configTrackingValue = null;
17
+ let configTrackingLoaded = false;
18
+ function getConfigTracking() {
19
+ if (configTrackingLoaded) {
20
+ return configTrackingValue;
21
+ }
22
+ configTrackingLoaded = true;
23
+ if (node_js_1.os === null || node_js_1.fs === null || node_js_1.path === null) {
24
+ return null;
25
+ }
8
26
  try {
9
- // Check if require is available (CommonJS environment)
10
- if (typeof require !== "undefined") {
11
- // Try to require package.json (Node.js only, gracefully fails in browser)
12
- // eslint-disable-next-line @typescript-eslint/no-require-imports
13
- const packageJson = {"version":"0.2.52","commit":"4acd7b5efa6c9e04c5131f55e7a87029c4889b1d"};
14
- return packageJson.version || "unknown";
15
- }
16
- else {
17
- // ESM environment - return unknown
18
- return "unknown";
27
+ const homeDir = node_js_1.os.homedir();
28
+ const config = node_js_1.fs.readFileSync(node_js_1.path.join(homeDir, ".blaxel/config.yaml"), "utf8");
29
+ const configJson = yaml_1.default.parse(config);
30
+ if (typeof configJson.tracking === 'boolean') {
31
+ configTrackingValue = configJson.tracking;
32
+ return configTrackingValue;
19
33
  }
20
34
  }
21
35
  catch {
22
- // Fallback for browser environments or if require fails
23
- return "unknown";
36
+ // If any error, return null
24
37
  }
38
+ return null;
25
39
  }
26
40
  // Function to get OS and architecture
27
41
  function getOsArch() {
@@ -55,30 +69,9 @@ function getOsArch() {
55
69
  }
56
70
  return "browser/unknown";
57
71
  }
58
- // Function to get commit hash
59
- function getCommitHash() {
60
- try {
61
- // Check if require is available (CommonJS environment)
62
- if (typeof require !== "undefined") {
63
- // Try to require package.json and look for commit field (set during build)
64
- // eslint-disable-next-line @typescript-eslint/no-require-imports
65
- const packageJson = {"version":"0.2.52","commit":"4acd7b5efa6c9e04c5131f55e7a87029c4889b1d"};
66
- // Check for commit in various possible locations
67
- const commit = packageJson.commit || packageJson.buildInfo?.commit;
68
- if (commit) {
69
- return commit.length > 7 ? commit.substring(0, 7) : commit;
70
- }
71
- }
72
- }
73
- catch {
74
- // Fallback for browser environments or if require fails
75
- }
76
- return "unknown";
77
- }
78
72
  class Settings {
79
73
  credentials;
80
74
  config;
81
- _version = null;
82
75
  constructor() {
83
76
  this.credentials = (0, index_js_1.authentication)();
84
77
  this.config = {
@@ -133,18 +126,21 @@ class Settings {
133
126
  return this.credentials.token;
134
127
  }
135
128
  get version() {
136
- if (this._version === null) {
137
- this._version = getPackageVersion();
138
- }
139
- return this._version;
129
+ return BUILD_VERSION || "unknown";
130
+ }
131
+ get commit() {
132
+ const commit = BUILD_COMMIT || "unknown";
133
+ return commit.length > 7 ? commit.substring(0, 7) : commit;
134
+ }
135
+ get sentryDsn() {
136
+ return BUILD_SENTRY_DSN || "";
140
137
  }
141
138
  get headers() {
142
139
  const osArch = getOsArch();
143
- const commitHash = getCommitHash();
144
140
  return {
145
141
  "x-blaxel-authorization": this.authorization,
146
142
  "x-blaxel-workspace": this.workspace || "",
147
- "User-Agent": `blaxel/sdk/typescript/${this.version} (${osArch}) blaxel/${commitHash}`,
143
+ "User-Agent": `blaxel/sdk/typescript/${this.version} (${osArch}) blaxel/${this.commit}`,
148
144
  };
149
145
  }
150
146
  get name() {
@@ -171,6 +167,19 @@ class Settings {
171
167
  get loggerType() {
172
168
  return env_js_1.env.BL_LOGGER || "http";
173
169
  }
170
+ get tracking() {
171
+ // Environment variable has highest priority
172
+ if (env_js_1.env.BL_TRACKING !== undefined) {
173
+ return env_js_1.env.BL_TRACKING === "true";
174
+ }
175
+ // Then check config.yaml
176
+ const configValue = getConfigTracking();
177
+ if (configValue !== null) {
178
+ return configValue;
179
+ }
180
+ // Default to true if neither is set
181
+ return true;
182
+ }
174
183
  async authenticate() {
175
184
  await this.credentials.authenticate();
176
185
  }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Initialize an isolated Sentry client for SDK error tracking.
3
+ * This creates a separate Sentry instance that won't interfere with any
4
+ * Sentry configuration the user might have in their application.
5
+ */
6
+ export declare function initSentry(): void;
7
+ /**
8
+ * Flush pending Sentry events.
9
+ * This should be called before the process exits to ensure all events are sent.
10
+ *
11
+ * @param timeout - Maximum time in milliseconds to wait for flush (default: 2000)
12
+ */
13
+ export declare function flushSentry(timeout?: number): Promise<void>;
14
+ /**
15
+ * Check if Sentry is initialized and available.
16
+ */
17
+ export declare function isSentryInitialized(): boolean;
@@ -7,7 +7,6 @@ export type Config = {
7
7
  declare class Settings {
8
8
  credentials: Credentials;
9
9
  config: Config;
10
- private _version;
11
10
  constructor();
12
11
  setConfig(config: Config): void;
13
12
  get env(): string;
@@ -17,6 +16,8 @@ declare class Settings {
17
16
  get authorization(): string;
18
17
  get token(): string;
19
18
  get version(): string;
19
+ get commit(): string;
20
+ get sentryDsn(): string;
20
21
  get headers(): Record<string, string>;
21
22
  get name(): string;
22
23
  get type(): string;
@@ -25,6 +26,7 @@ declare class Settings {
25
26
  get blCloud(): boolean;
26
27
  get generation(): string;
27
28
  get loggerType(): string;
29
+ get tracking(): boolean;
28
30
  authenticate(): Promise<void>;
29
31
  }
30
32
  export declare const settings: Settings;