@bigbertha/sdk 0.2.1 → 0.4.0

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/README.md CHANGED
@@ -90,12 +90,15 @@ Options: `release`, `url`, `uploadKey`, `keepMaps`.
90
90
 
91
91
  ```ts
92
92
  import { init } from "@bigbertha/sdk/node"
93
- init() // reads BERTHA_KEY, BERTHA_URL, BERTHA_RELEASE and NODE_ENV
93
+ init() // reads BERTHA_KEY, BERTHA_URL, BERTHA_RELEASE, BERTHA_COMMIT and NODE_ENV
94
94
  ```
95
95
 
96
96
  `init` reports uncaught exceptions and unhandled rejections, flushes, then exits as Node
97
97
  would (`handlers: false` turns that off). It also sends a heartbeat every 20 minutes so
98
- bertha can tell "no errors" from "not running" (`heartbeat: false`).
98
+ bertha can tell "no errors" from "not running" (`heartbeat: false`). The heartbeat names
99
+ the commit the process runs, from `commit`, `BERTHA_COMMIT` or the host's own variable
100
+ (Heroku's `HEROKU_SLUG_COMMIT` with dyno metadata on, Render, Railway, Vercel, GitHub
101
+ Actions), so a release that no `bertha deploy` recorded still points at its code.
99
102
 
100
103
  Code that Node runs as-is needs no source maps: the SDK reads the lines around each
101
104
  frame in your own files from disk and sends them with the event (`contextLines: false`
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // bertha deploy | bertha sourcemaps upload <dir>
2
2
  import { parseArgs } from "node:util";
3
3
  import { detectRelease, lastCommit, processDirectory, reason } from "./build/index.js";
4
+ import { envCommit } from "./core/env.js";
4
5
  import { VERSION } from "./core/version.js";
5
6
  const HELP = `bertha ${VERSION}
6
7
 
@@ -50,7 +51,9 @@ export async function main(argv, out = console.log) {
50
51
  if (!release)
51
52
  return out("No release found. Pass --release or set BERTHA_RELEASE."), 1;
52
53
  const body = { release, environment: v.env ?? "production" };
53
- const commit = lastCommit();
54
+ // Without a checkout (a host's build step), the host still names the commit.
55
+ const sha = envCommit();
56
+ const commit = lastCommit() ?? (sha ? { sha, message: "", author: "" } : undefined);
54
57
  if (commit)
55
58
  body.commit = commit;
56
59
  try {
@@ -1,2 +1,6 @@
1
1
  export declare function env(name: string): string | undefined;
2
+ /** Where hosts and CI put the commit a process was built from, most specific first. */
3
+ export declare const COMMIT_ENV: string[];
4
+ /** The commit the environment names, if it looks like one. */
5
+ export declare function envCommit(): string | undefined;
2
6
  export declare function firstEnv(...names: string[]): string | undefined;
package/dist/core/env.js CHANGED
@@ -8,6 +8,28 @@ export function env(name) {
8
8
  return undefined;
9
9
  }
10
10
  }
11
+ /** Where hosts and CI put the commit a process was built from, most specific first. */
12
+ export const COMMIT_ENV = [
13
+ "BERTHA_COMMIT",
14
+ "HEROKU_BUILD_COMMIT",
15
+ "HEROKU_SLUG_COMMIT",
16
+ "SOURCE_VERSION",
17
+ "RENDER_GIT_COMMIT",
18
+ "RAILWAY_GIT_COMMIT_SHA",
19
+ "VERCEL_GIT_COMMIT_SHA",
20
+ "CF_PAGES_COMMIT_SHA",
21
+ "GITHUB_SHA",
22
+ "COMMIT_SHA",
23
+ ];
24
+ /** The commit the environment names, if it looks like one. */
25
+ export function envCommit() {
26
+ for (const n of COMMIT_ENV) {
27
+ const v = env(n)?.trim();
28
+ if (v && /^[0-9a-f]{7,64}$/i.test(v))
29
+ return v.toLowerCase();
30
+ }
31
+ return undefined;
32
+ }
11
33
  export function firstEnv(...names) {
12
34
  for (const n of names) {
13
35
  const v = env(n);
@@ -12,7 +12,8 @@ export function parseStack(stack) {
12
12
  if (!m)
13
13
  continue;
14
14
  const [, fn, rawFile, ln, col] = m;
15
- let file = rawFile;
15
+ // `at async /app/x.js:1:2`, an unnamed async frame, has no parentheses to split on.
16
+ let file = fn ? rawFile : rawFile.replace(/^async /, "");
16
17
  // `at eval (eval at f (file.js:1:2), <anonymous>:1:1)`: keep the outer file.
17
18
  const evalAt = /\(eval at .*?\((.+?):\d+:\d+\)/.exec(line);
18
19
  if (evalAt)
@@ -1 +1 @@
1
- export declare const VERSION = "0.2.1";
1
+ export declare const VERSION = "0.4.0";
@@ -1 +1 @@
1
- export const VERSION = "0.2.1";
1
+ export const VERSION = "0.4.0";
@@ -128,6 +128,11 @@ export type IngestFrameContext = {
128
128
  export type IngestHeartbeat = {
129
129
  environment?: string;
130
130
  release?: string;
131
+ /**
132
+ * The commit sha the process was built from, when the host says (Heroku, Render,
133
+ * Vercel…). Fills in the release's commit if no deploy from CI gave one.
134
+ */
135
+ commit?: string;
131
136
  };
132
137
  export type IngestLevel = "fatal" | "error" | "warning";
133
138
  export type IngestRequest = {
@@ -9,13 +9,21 @@ export interface NodeOptions extends Partial<Options> {
9
9
  heartbeat?: boolean;
10
10
  /** Send the source lines around each frame in your code, read from disk. On by default. */
11
11
  contextLines?: boolean;
12
+ /**
13
+ * The commit this process runs, so an agent can read the code that failed. Read from
14
+ * BERTHA_COMMIT or the host's own variable (Heroku, Render, Railway, Vercel, GitHub
15
+ * Actions) unless given; sent with the heartbeat.
16
+ */
17
+ commit?: string;
12
18
  }
13
19
  export declare const HEARTBEAT_MS: number;
14
20
  /** V8 keeps 10 frames, which a framework's own calls can use up before reaching yours. */
15
21
  export declare const STACK_FRAMES = 50;
16
- /** Reads BERTHA_KEY, BERTHA_URL, BERTHA_RELEASE and NODE_ENV unless given. */
22
+ /** Reads BERTHA_KEY, BERTHA_URL, BERTHA_RELEASE, BERTHA_COMMIT and NODE_ENV unless given. */
17
23
  export declare function init(options?: NodeOptions): Client | undefined;
18
- export declare function sendHeartbeat(o: Pick<Options, "url" | "key" | "release" | "environment">): Promise<boolean>;
24
+ export declare function sendHeartbeat(o: Pick<Options, "url" | "key" | "release" | "environment"> & {
25
+ commit?: string;
26
+ }): Promise<boolean>;
19
27
  /**
20
28
  * Wraps a request handler (Node http, Express, Fastify, Hono…): errors it throws
21
29
  * or rejects with are reported with the request, then rethrown.
@@ -4,7 +4,7 @@
4
4
  import { arch, platform } from "node:os";
5
5
  import { gzipSync } from "node:zlib";
6
6
  import { Client } from "../core/client.js";
7
- import { firstEnv } from "../core/env.js";
7
+ import { envCommit, firstEnv } from "../core/env.js";
8
8
  import { getClient, setClient } from "../core/hub.js";
9
9
  import { endpoint, fetchTransport } from "../core/transport.js";
10
10
  import { VERSION } from "../core/version.js";
@@ -17,7 +17,7 @@ const V8_DEFAULT_FRAMES = 10;
17
17
  const EXIT_FLUSH_MS = 2000;
18
18
  let handlersInstalled = false;
19
19
  let heartbeat;
20
- /** Reads BERTHA_KEY, BERTHA_URL, BERTHA_RELEASE and NODE_ENV unless given. */
20
+ /** Reads BERTHA_KEY, BERTHA_URL, BERTHA_RELEASE, BERTHA_COMMIT and NODE_ENV unless given. */
21
21
  export function init(options = {}) {
22
22
  const key = options.key ?? firstEnv("BERTHA_KEY", "NEXT_PUBLIC_BERTHA_KEY");
23
23
  const url = options.url ?? firstEnv("BERTHA_URL", "NEXT_PUBLIC_BERTHA_URL");
@@ -45,7 +45,7 @@ export function init(options = {}) {
45
45
  }
46
46
  if (options.heartbeat !== false) {
47
47
  clearInterval(heartbeat);
48
- const beat = () => void sendHeartbeat(opts);
48
+ const beat = () => void sendHeartbeat({ ...opts, commit: options.commit ?? envCommit() });
49
49
  beat();
50
50
  heartbeat = setInterval(beat, HEARTBEAT_MS);
51
51
  heartbeat.unref();
@@ -83,7 +83,7 @@ export async function sendHeartbeat(o) {
83
83
  const res = await fetch(endpoint(o.url, "heartbeat"), {
84
84
  method: "POST",
85
85
  headers: { authorization: `Bearer ${o.key}`, "content-type": "application/json" },
86
- body: JSON.stringify({ environment: o.environment, release: o.release }),
86
+ body: JSON.stringify({ environment: o.environment, release: o.release, commit: o.commit }),
87
87
  signal: AbortSignal.timeout(10_000),
88
88
  });
89
89
  return res.ok;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigbertha/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Error reporting for bertha: browser, Node, edge and Next.js, with source maps by debug id.",
5
5
  "license": "MIT",
6
6
  "repository": {