@blaxel/core 0.3.30-preview.323 → 0.3.30
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/lazyInit.js +8 -0
- package/dist/cjs/common/posthog.js +256 -0
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/types/common/posthog.d.ts +51 -0
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/lazyInit.js +8 -0
- package/dist/cjs-browser/common/posthog.js +256 -0
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/types/common/posthog.d.ts +51 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/lazyInit.js +8 -0
- package/dist/esm/common/posthog.js +250 -0
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/lazyInit.js +8 -0
- package/dist/esm-browser/common/posthog.js +250 -0
- package/dist/esm-browser/common/settings.js +2 -2
- package/package.json +2 -2
|
@@ -37,6 +37,7 @@ exports.ensureAutoloaded = ensureAutoloaded;
|
|
|
37
37
|
const client_gen_js_1 = require("../client/client.gen.js");
|
|
38
38
|
const client_gen_js_2 = require("../sandbox/client/client.gen.js");
|
|
39
39
|
const controlPlaneFetch_js_1 = require("./controlPlaneFetch.js");
|
|
40
|
+
const posthog_js_1 = require("./posthog.js");
|
|
40
41
|
const sentry_js_1 = require("./sentry.js");
|
|
41
42
|
const settings_js_1 = require("./settings.js");
|
|
42
43
|
let autoloaded = false;
|
|
@@ -74,6 +75,13 @@ function ensureAutoloaded() {
|
|
|
74
75
|
client_gen_js_2.client.setConfig({ baseUrl: settings_js_1.settings.baseUrl });
|
|
75
76
|
// Initialize Sentry for SDK error tracking.
|
|
76
77
|
(0, sentry_js_1.initSentry)();
|
|
78
|
+
// Track SDK installation (fires once per new version).
|
|
79
|
+
try {
|
|
80
|
+
(0, posthog_js_1.trackSDKInstalled)();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Silently ignore - telemetry should never break the SDK
|
|
84
|
+
}
|
|
77
85
|
// Background H2 connection warming (Node.js only)
|
|
78
86
|
const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
79
87
|
/* eslint-disable */
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POSTHOG_FLUSH_BUDGET_MS = void 0;
|
|
4
|
+
exports.mergeTelemetryState = mergeTelemetryState;
|
|
5
|
+
exports.createSDKInstallTracker = createSDKInstallTracker;
|
|
6
|
+
exports.trackSDKInstalled = trackSDKInstalled;
|
|
7
|
+
const node_js_1 = require("../common/node.js");
|
|
8
|
+
const settings_js_1 = require("./settings.js");
|
|
9
|
+
// PostHog API key injected at build time via build:replace-imports
|
|
10
|
+
const BUILD_POSTHOG_KEY = "";
|
|
11
|
+
// PostHog API endpoint
|
|
12
|
+
const POSTHOG_HOST = "https://us.i.posthog.com";
|
|
13
|
+
/**
|
|
14
|
+
* How long a capture may stay outstanding.
|
|
15
|
+
*
|
|
16
|
+
* Node keeps the event loop alive while a fetch is pending, so this is what a
|
|
17
|
+
* short-lived script waits for before it can exit. A capture against
|
|
18
|
+
* us.i.posthog.com takes ~250-350ms end to end (DNS + TLS handshake + POST), so
|
|
19
|
+
* a second covers the happy path with headroom. The ceiling matters because a
|
|
20
|
+
* version is only recorded after a successful delivery: when the endpoint is
|
|
21
|
+
* unreachable every later run tries again, and networks that silently drop
|
|
22
|
+
* traffic rather than refusing it would otherwise pay the full timeout each
|
|
23
|
+
* time.
|
|
24
|
+
*/
|
|
25
|
+
exports.POSTHOG_FLUSH_BUDGET_MS = 1000;
|
|
26
|
+
/** The single per-language entry this SDK owns in the shared telemetry file. */
|
|
27
|
+
const SDK_STATE_KEY = "typescript";
|
|
28
|
+
let telemetryState = null;
|
|
29
|
+
/**
|
|
30
|
+
* Get the PostHog API key (injected at build time).
|
|
31
|
+
*/
|
|
32
|
+
function getPosthogKey() {
|
|
33
|
+
const key = BUILD_POSTHOG_KEY;
|
|
34
|
+
// If the placeholder was not replaced, treat as empty
|
|
35
|
+
if (!key || key.startsWith("__BUILD_")) {
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
return key;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the telemetry file path.
|
|
42
|
+
*/
|
|
43
|
+
function getTelemetryPath() {
|
|
44
|
+
if (node_js_1.os === null || node_js_1.path === null) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return node_js_1.path.join(node_js_1.os.homedir(), ".blaxel", "telemetry.json");
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Load telemetry state from disk.
|
|
56
|
+
*/
|
|
57
|
+
function loadTelemetryState() {
|
|
58
|
+
if (telemetryState !== null) {
|
|
59
|
+
return telemetryState;
|
|
60
|
+
}
|
|
61
|
+
telemetryState = { distinct_id: "", sdks: {} };
|
|
62
|
+
if (node_js_1.fs === null) {
|
|
63
|
+
return telemetryState;
|
|
64
|
+
}
|
|
65
|
+
const telemetryPath = getTelemetryPath();
|
|
66
|
+
if (!telemetryPath) {
|
|
67
|
+
return telemetryState;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const data = node_js_1.fs.readFileSync(telemetryPath, "utf8");
|
|
71
|
+
const parsed = JSON.parse(data);
|
|
72
|
+
telemetryState = {
|
|
73
|
+
...parsed,
|
|
74
|
+
distinct_id: parsed.distinct_id || "",
|
|
75
|
+
sdks: parsed.sdks || {},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// File doesn't exist or is invalid - use defaults
|
|
80
|
+
}
|
|
81
|
+
return telemetryState;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Combine this process's telemetry snapshot with what is on disk right now.
|
|
85
|
+
*
|
|
86
|
+
* `~/.blaxel/telemetry.json` is shared with the CLI and the Python SDK, and
|
|
87
|
+
* each of them caches it in memory for the lifetime of its process. Writing
|
|
88
|
+
* this snapshot back wholesale would roll back anything the others recorded in
|
|
89
|
+
* the meantime, which makes them re-send their "Installed" event on every later
|
|
90
|
+
* run. Anything already on disk is at least as fresh as what is held here, so
|
|
91
|
+
* it wins, except for the fields this process actually owns.
|
|
92
|
+
*/
|
|
93
|
+
function mergeTelemetryState(onDisk, ours) {
|
|
94
|
+
const merged = { ...ours, ...onDisk };
|
|
95
|
+
// Only re-assert the one language entry this process owns. Writing back the
|
|
96
|
+
// whole cached map would roll back a newer version another SDK recorded
|
|
97
|
+
// after this process started, and that SDK would then re-send its
|
|
98
|
+
// "Installed" event.
|
|
99
|
+
const onDiskSdks = typeof onDisk.sdks === "object" && onDisk.sdks !== null ? onDisk.sdks : {};
|
|
100
|
+
const ownVersion = ours.sdks?.[SDK_STATE_KEY];
|
|
101
|
+
merged.sdks = {
|
|
102
|
+
...onDiskSdks,
|
|
103
|
+
...(ownVersion ? { [SDK_STATE_KEY]: ownVersion } : {}),
|
|
104
|
+
};
|
|
105
|
+
// distinct_id is shared by every writer, so the first one persisted wins.
|
|
106
|
+
// Replacing it would split the same user across two PostHog identities.
|
|
107
|
+
const onDiskId = typeof onDisk.distinct_id === "string" ? onDisk.distinct_id : "";
|
|
108
|
+
merged.distinct_id = onDiskId || ours.distinct_id;
|
|
109
|
+
return merged;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Save telemetry state to disk, preserving concurrent writes from the CLI and
|
|
113
|
+
* the other SDK.
|
|
114
|
+
*/
|
|
115
|
+
function saveTelemetryState(state) {
|
|
116
|
+
if (node_js_1.fs === null || node_js_1.path === null || node_js_1.os === null) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const telemetryPath = getTelemetryPath();
|
|
120
|
+
if (!telemetryPath) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const dir = node_js_1.path.dirname(telemetryPath);
|
|
125
|
+
if (!node_js_1.fs.existsSync(dir)) {
|
|
126
|
+
node_js_1.fs.mkdirSync(dir, { recursive: true });
|
|
127
|
+
}
|
|
128
|
+
// Re-read immediately before writing rather than trusting the snapshot
|
|
129
|
+
// loaded when this process started.
|
|
130
|
+
let onDisk = {};
|
|
131
|
+
try {
|
|
132
|
+
const parsed = JSON.parse(node_js_1.fs.readFileSync(telemetryPath, "utf8"));
|
|
133
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
134
|
+
onDisk = parsed;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// No readable file yet - this process's state is all there is.
|
|
139
|
+
}
|
|
140
|
+
const merged = mergeTelemetryState(onDisk, state);
|
|
141
|
+
node_js_1.fs.writeFileSync(telemetryPath, JSON.stringify(merged, null, 2), {
|
|
142
|
+
mode: 0o600,
|
|
143
|
+
});
|
|
144
|
+
// Adopt the persisted identity so events match what other writers use.
|
|
145
|
+
if (typeof merged.distinct_id === "string" && merged.distinct_id) {
|
|
146
|
+
state.distinct_id = merged.distinct_id;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Silently fail
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Generate a UUID v4 without external dependencies.
|
|
155
|
+
*/
|
|
156
|
+
function generateUUID() {
|
|
157
|
+
const bytes = new Uint8Array(16);
|
|
158
|
+
crypto.getRandomValues(bytes);
|
|
159
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
|
|
160
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10
|
|
161
|
+
const hex = Array.from(bytes)
|
|
162
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
163
|
+
.join("");
|
|
164
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get or create a persistent distinct ID for PostHog events.
|
|
168
|
+
*/
|
|
169
|
+
function getDistinctID() {
|
|
170
|
+
const state = loadTelemetryState();
|
|
171
|
+
if (state.distinct_id) {
|
|
172
|
+
return state.distinct_id;
|
|
173
|
+
}
|
|
174
|
+
state.distinct_id = generateUUID();
|
|
175
|
+
saveTelemetryState(state);
|
|
176
|
+
return state.distinct_id;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create an SDK install tracker. Exported from this internal module so delivery
|
|
180
|
+
* and deduplication behavior can be tested without build-time credentials.
|
|
181
|
+
*/
|
|
182
|
+
function createSDKInstallTracker(options) {
|
|
183
|
+
const pendingVersions = new Set();
|
|
184
|
+
return function track() {
|
|
185
|
+
const apiKey = options.getApiKey();
|
|
186
|
+
if (!apiKey || !options.isTrackingEnabled() || !options.isNode()) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const version = options.getVersion();
|
|
190
|
+
if (!version ||
|
|
191
|
+
version === "unknown" ||
|
|
192
|
+
version === "__BUILD_VERSION__") {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const state = options.loadState();
|
|
196
|
+
const stateKey = SDK_STATE_KEY;
|
|
197
|
+
if (state.sdks?.[stateKey] === version || pendingVersions.has(version)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
pendingVersions.add(version);
|
|
201
|
+
return (async () => {
|
|
202
|
+
try {
|
|
203
|
+
const payload = {
|
|
204
|
+
api_key: apiKey,
|
|
205
|
+
event: "Installed SDK",
|
|
206
|
+
distinct_id: options.getDistinctId(),
|
|
207
|
+
timestamp: new Date().toISOString(),
|
|
208
|
+
properties: {
|
|
209
|
+
language: "typescript",
|
|
210
|
+
sdk: "core",
|
|
211
|
+
version,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
const response = await options.fetch(`${POSTHOG_HOST}/capture/`, {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: { "Content-Type": "application/json" },
|
|
217
|
+
body: JSON.stringify(payload),
|
|
218
|
+
signal: options.getSignal(),
|
|
219
|
+
});
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
state.sdks ??= {};
|
|
224
|
+
state.sdks[stateKey] = version;
|
|
225
|
+
options.saveState(state);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Telemetry must never break the SDK. A later call may retry.
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
pendingVersions.delete(version);
|
|
232
|
+
}
|
|
233
|
+
})();
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const sdkInstallTracker = createSDKInstallTracker({
|
|
237
|
+
getApiKey: getPosthogKey,
|
|
238
|
+
isTrackingEnabled: () => settings_js_1.settings.tracking,
|
|
239
|
+
getVersion: () => settings_js_1.settings.version,
|
|
240
|
+
isNode: () => typeof process !== "undefined" && Boolean(process.versions?.node),
|
|
241
|
+
loadState: loadTelemetryState,
|
|
242
|
+
saveState: saveTelemetryState,
|
|
243
|
+
getDistinctId: getDistinctID,
|
|
244
|
+
fetch: (...args) => globalThis.fetch(...args),
|
|
245
|
+
getSignal: () => typeof AbortSignal !== "undefined" &&
|
|
246
|
+
typeof AbortSignal.timeout === "function"
|
|
247
|
+
? AbortSignal.timeout(exports.POSTHOG_FLUSH_BUDGET_MS)
|
|
248
|
+
: undefined,
|
|
249
|
+
});
|
|
250
|
+
/**
|
|
251
|
+
* Track SDK installation. Fires "Installed SDK" once per new version.
|
|
252
|
+
* Called during SDK autoload.
|
|
253
|
+
*/
|
|
254
|
+
function trackSDKInstalled() {
|
|
255
|
+
void sdkInstallTracker();
|
|
256
|
+
}
|
|
@@ -30,8 +30,8 @@ function missingCredentialsMessage() {
|
|
|
30
30
|
return "No Blaxel credentials found. Set the BL_API_KEY and BL_WORKSPACE environment variables, or run `bl login`.";
|
|
31
31
|
}
|
|
32
32
|
// Build info - these placeholders are replaced at build time by build:replace-imports
|
|
33
|
-
const BUILD_VERSION = "0.3.30
|
|
34
|
-
const BUILD_COMMIT = "
|
|
33
|
+
const BUILD_VERSION = "0.3.30";
|
|
34
|
+
const BUILD_COMMIT = "e88b0db8a85b1db102dfedce7af3e5f5ebae1f52";
|
|
35
35
|
const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
|
|
36
36
|
const BLAXEL_API_VERSION = "2026-09-22";
|
|
37
37
|
// Bun < 1.3.11 never sends connection-level WINDOW_UPDATE: the pooled h2
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long a capture may stay outstanding.
|
|
3
|
+
*
|
|
4
|
+
* Node keeps the event loop alive while a fetch is pending, so this is what a
|
|
5
|
+
* short-lived script waits for before it can exit. A capture against
|
|
6
|
+
* us.i.posthog.com takes ~250-350ms end to end (DNS + TLS handshake + POST), so
|
|
7
|
+
* a second covers the happy path with headroom. The ceiling matters because a
|
|
8
|
+
* version is only recorded after a successful delivery: when the endpoint is
|
|
9
|
+
* unreachable every later run tries again, and networks that silently drop
|
|
10
|
+
* traffic rather than refusing it would otherwise pay the full timeout each
|
|
11
|
+
* time.
|
|
12
|
+
*/
|
|
13
|
+
export declare const POSTHOG_FLUSH_BUDGET_MS = 1000;
|
|
14
|
+
type TelemetryState = {
|
|
15
|
+
distinct_id: string;
|
|
16
|
+
cli?: string;
|
|
17
|
+
sdks?: Record<string, string>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Combine this process's telemetry snapshot with what is on disk right now.
|
|
21
|
+
*
|
|
22
|
+
* `~/.blaxel/telemetry.json` is shared with the CLI and the Python SDK, and
|
|
23
|
+
* each of them caches it in memory for the lifetime of its process. Writing
|
|
24
|
+
* this snapshot back wholesale would roll back anything the others recorded in
|
|
25
|
+
* the meantime, which makes them re-send their "Installed" event on every later
|
|
26
|
+
* run. Anything already on disk is at least as fresh as what is held here, so
|
|
27
|
+
* it wins, except for the fields this process actually owns.
|
|
28
|
+
*/
|
|
29
|
+
export declare function mergeTelemetryState(onDisk: Record<string, unknown>, ours: TelemetryState): Record<string, unknown>;
|
|
30
|
+
type SDKInstallTrackerOptions = {
|
|
31
|
+
getApiKey: () => string;
|
|
32
|
+
isTrackingEnabled: () => boolean;
|
|
33
|
+
getVersion: () => string;
|
|
34
|
+
isNode: () => boolean;
|
|
35
|
+
loadState: () => TelemetryState;
|
|
36
|
+
saveState: (state: TelemetryState) => void;
|
|
37
|
+
getDistinctId: () => string;
|
|
38
|
+
fetch: typeof globalThis.fetch;
|
|
39
|
+
getSignal: () => AbortSignal | undefined;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Create an SDK install tracker. Exported from this internal module so delivery
|
|
43
|
+
* and deduplication behavior can be tested without build-time credentials.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createSDKInstallTracker(options: SDKInstallTrackerOptions): () => Promise<void> | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Track SDK installation. Fires "Installed SDK" once per new version.
|
|
48
|
+
* Called during SDK autoload.
|
|
49
|
+
*/
|
|
50
|
+
export declare function trackSDKInstalled(): void;
|
|
51
|
+
export {};
|