bitfab 0.54.0 → 0.54.2

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.
@@ -100,7 +100,7 @@ function encodeRequestBody(body) {
100
100
  }
101
101
 
102
102
  // src/version.generated.ts
103
- var __version__ = "0.54.0";
103
+ var __version__ = "0.54.2";
104
104
  var __packageName__ = "bitfab";
105
105
 
106
106
  // src/constants.ts
@@ -123,6 +123,193 @@ var MixedTracingError = class extends Error {
123
123
  }
124
124
  };
125
125
 
126
+ // src/gitCommand.ts
127
+ var EXIT_GRACE_MS = 500;
128
+ function isUnrefable(value) {
129
+ return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
130
+ }
131
+ function unrefStream(stream) {
132
+ if (isUnrefable(stream)) {
133
+ stream.unref();
134
+ }
135
+ }
136
+ function terminate(child) {
137
+ if (child.pid && process.platform !== "win32") {
138
+ try {
139
+ process.kill(-child.pid, "SIGTERM");
140
+ return;
141
+ } catch {
142
+ child.kill("SIGTERM");
143
+ return;
144
+ }
145
+ }
146
+ child.kill("SIGTERM");
147
+ }
148
+ async function gitRunner(options) {
149
+ let spawn;
150
+ try {
151
+ ;
152
+ ({ spawn } = await import("child_process"));
153
+ } catch {
154
+ return null;
155
+ }
156
+ return (dir, args, env) => new Promise((resolve) => {
157
+ let child;
158
+ try {
159
+ child = spawn("git", args, {
160
+ cwd: dir,
161
+ detached: process.platform !== "win32",
162
+ stdio: ["ignore", "pipe", "pipe"],
163
+ ...env ? { env: { ...process.env, ...env } } : {}
164
+ });
165
+ } catch {
166
+ resolve(null);
167
+ return;
168
+ }
169
+ const chunks = [];
170
+ let size = 0;
171
+ let overflow = false;
172
+ let exitCode = null;
173
+ let done = false;
174
+ const timers = [];
175
+ const schedule = (callback, ms) => {
176
+ const timer = setTimeout(callback, ms);
177
+ if (!options.keepProcessAlive) {
178
+ timer.unref();
179
+ }
180
+ timers.push(timer);
181
+ };
182
+ const finish = () => {
183
+ if (done) {
184
+ return;
185
+ }
186
+ done = true;
187
+ for (const timer of timers) {
188
+ clearTimeout(timer);
189
+ }
190
+ child.stdout?.destroy();
191
+ child.stderr?.destroy();
192
+ resolve(
193
+ exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null
194
+ );
195
+ };
196
+ child.stdout?.on("data", (chunk) => {
197
+ size += chunk.length;
198
+ if (size > options.maxBuffer) {
199
+ overflow = true;
200
+ terminate(child);
201
+ return;
202
+ }
203
+ chunks.push(chunk);
204
+ });
205
+ child.stderr?.resume();
206
+ child.on("error", () => {
207
+ exitCode = null;
208
+ finish();
209
+ });
210
+ child.on("exit", (code) => {
211
+ exitCode = code;
212
+ schedule(finish, EXIT_GRACE_MS);
213
+ });
214
+ child.on("close", (code) => {
215
+ exitCode = code ?? exitCode;
216
+ finish();
217
+ });
218
+ schedule(() => terminate(child), options.timeoutMs);
219
+ if (!options.keepProcessAlive) {
220
+ child.unref();
221
+ unrefStream(child.stdout);
222
+ unrefStream(child.stderr);
223
+ }
224
+ });
225
+ }
226
+
227
+ // src/gitState.ts
228
+ var GIT_TIMEOUT_MS = 3e4;
229
+ var GIT_MAX_BUFFER = 1024 * 1024;
230
+ var DISABLE_ENV = "BITFAB_DISABLE_GIT_STATE";
231
+ var SHA_PATTERN = /^[0-9a-f]{40}$/;
232
+ function sha(value) {
233
+ const trimmed = value?.trim();
234
+ return trimmed && SHA_PATTERN.test(trimmed) ? trimmed : null;
235
+ }
236
+ function text(value) {
237
+ const trimmed = value?.trim();
238
+ return trimmed ? trimmed : null;
239
+ }
240
+ function isEmptyGitState(state) {
241
+ return Object.values(state).every((value) => value === null);
242
+ }
243
+ async function resolveGitState(cwd) {
244
+ const git = await gitRunner({
245
+ timeoutMs: GIT_TIMEOUT_MS,
246
+ maxBuffer: GIT_MAX_BUFFER,
247
+ keepProcessAlive: true
248
+ });
249
+ if (!git) {
250
+ return null;
251
+ }
252
+ const run = async (args, env) => (await git(cwd, args, env))?.trim() ?? null;
253
+ const [refs, email, branch] = await Promise.all([
254
+ run(["rev-parse", "--show-toplevel", "HEAD", "HEAD^{tree}"]),
255
+ run(["config", "user.email"]),
256
+ run(["symbolic-ref", "--short", "-q", "HEAD"])
257
+ ]);
258
+ const [root, commitSha, baseSha] = (refs ?? "").split("\n");
259
+ if (!root) {
260
+ return null;
261
+ }
262
+ const state = {
263
+ githubEmail: text(email),
264
+ branch: text(branch),
265
+ commitSha: sha(commitSha),
266
+ baseSha: sha(baseSha),
267
+ experimentSha: await resolveWorkingTreeSha(run, root.trim())
268
+ };
269
+ return isEmptyGitState(state) ? null : state;
270
+ }
271
+ async function resolveWorkingTreeSha(run, root) {
272
+ let indexPath;
273
+ let cleanup;
274
+ try {
275
+ const { mkdtemp, rm } = await import("fs/promises");
276
+ const { join } = await import("path");
277
+ const { tmpdir } = await import("os");
278
+ const dir = await mkdtemp(join(tmpdir(), "bitfab-git-"));
279
+ indexPath = join(dir, "index");
280
+ cleanup = () => rm(dir, { recursive: true, force: true });
281
+ } catch {
282
+ return null;
283
+ }
284
+ try {
285
+ const env = { GIT_INDEX_FILE: indexPath };
286
+ if (await run(["read-tree", "HEAD"], env) === null) {
287
+ return null;
288
+ }
289
+ if (await run(["add", "-A", "--", root], env) === null) {
290
+ return null;
291
+ }
292
+ return sha(await run(["write-tree"], env));
293
+ } catch {
294
+ return null;
295
+ } finally {
296
+ await cleanup().catch(() => {
297
+ });
298
+ }
299
+ }
300
+ function resolvedGitState() {
301
+ if (typeof process === "undefined" || process.env?.[DISABLE_ENV]) {
302
+ return Promise.resolve(null);
303
+ }
304
+ let cwd;
305
+ try {
306
+ cwd = process.cwd?.() ?? ".";
307
+ } catch {
308
+ return Promise.resolve(null);
309
+ }
310
+ return resolveGitState(cwd).catch(() => null);
311
+ }
312
+
126
313
  // src/replayContext.ts
127
314
  var replayContextStorage = null;
128
315
  var REPLAY_CONTEXT_STORAGE_SYMBOL = /* @__PURE__ */ Symbol.for("bitfab.replayContextStorage");
@@ -2325,6 +2512,10 @@ var HttpClient = class {
2325
2512
  if (onlyWithAssertions) {
2326
2513
  payload.onlyWithAssertions = true;
2327
2514
  }
2515
+ const git = await resolvedGitState();
2516
+ if (git && !isEmptyGitState(git)) {
2517
+ payload.git = git;
2518
+ }
2328
2519
  const timeout = includeDbBranchLease ? REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS : 3e4;
2329
2520
  return this.request("/api/sdk/replay/start", payload, {
2330
2521
  timeout
@@ -2489,6 +2680,7 @@ export {
2489
2680
  readEnv,
2490
2681
  BitfabError,
2491
2682
  MixedTracingError,
2683
+ gitRunner,
2492
2684
  replayContextReady,
2493
2685
  getReplayContext,
2494
2686
  runWithReplayContext,
@@ -2508,4 +2700,4 @@ export {
2508
2700
  parseRetryAfterMs,
2509
2701
  HttpClient
2510
2702
  };
2511
- //# sourceMappingURL=chunk-SEHWHFUY.js.map
2703
+ //# sourceMappingURL=chunk-GMHABKGI.js.map