error-mom 0.2.0 → 0.3.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/dist/cli.js +133 -22
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import { Command } from "commander";
|
|
|
10
10
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
11
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
12
|
import { z } from "zod";
|
|
13
|
-
var VERSION = "0.
|
|
13
|
+
var VERSION = "0.3.0";
|
|
14
14
|
var CONFIG_DIR = join(homedir(), ".error-mom");
|
|
15
15
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
16
16
|
var program = new Command().name("error-mom").description("Query and operate a self-hosted Error Mom incident desk").version(VERSION);
|
|
@@ -112,17 +112,18 @@ program.command("init").description("Create/select a project, install the SDK, a
|
|
|
112
112
|
const setupPath = await writeSetup(framework);
|
|
113
113
|
await writeFile(
|
|
114
114
|
join(process.cwd(), ".error-mom.json"),
|
|
115
|
-
`${JSON.stringify({ server: config.server, projectId: project.id, projectName: project.name, framework }, null, 2)}
|
|
115
|
+
`${JSON.stringify({ server: config.server, projectId: project.id, projectName: project.name, framework: framework.id }, null, 2)}
|
|
116
116
|
`
|
|
117
117
|
);
|
|
118
118
|
await appendEnvironment(framework, config.server, project.ingestKey);
|
|
119
119
|
print({
|
|
120
120
|
installed: !options.skipInstall,
|
|
121
121
|
project: { id: project.id, name: project.name, slug: project.slug },
|
|
122
|
-
framework,
|
|
122
|
+
framework: framework.id,
|
|
123
123
|
setupFile: setupPath,
|
|
124
124
|
verified: false,
|
|
125
|
-
|
|
125
|
+
wiring: framework.wiring,
|
|
126
|
+
nextAction: `Wire it up: ${framework.wiring} For handlers where a framework catches errors itself (queue/cron jobs, webhooks, MCP tools), wrap each with errorMom.wrap(fn, { culprit: "<name>" }). Then run error-mom doctor --project-key <key>.`
|
|
126
127
|
});
|
|
127
128
|
});
|
|
128
129
|
program.command("mcp").description("Run Error Mom tools over MCP stdio for coding agents").action(async () => {
|
|
@@ -243,14 +244,125 @@ async function readPackageJson(cwd) {
|
|
|
243
244
|
);
|
|
244
245
|
}
|
|
245
246
|
}
|
|
247
|
+
var FRAMEWORKS = [
|
|
248
|
+
[
|
|
249
|
+
"next",
|
|
250
|
+
{
|
|
251
|
+
id: "next",
|
|
252
|
+
envStyle: "next",
|
|
253
|
+
wiring: "Import the setup file from the root layout for client errors; the generated instrumentation.ts already reports server errors (API routes, SSR, server actions)."
|
|
254
|
+
}
|
|
255
|
+
],
|
|
256
|
+
[
|
|
257
|
+
"@tauri-apps/api",
|
|
258
|
+
{
|
|
259
|
+
id: "tauri",
|
|
260
|
+
envStyle: "vite",
|
|
261
|
+
wiring: "Import the setup file first in the webview entry (main.tsx or equivalent). If the app spawns Node sidecar processes, also call initErrorMom from @kenkaiiii/error-mom/node at each sidecar entry so backend/LLM errors are reported too. Rust-side panics are not captured."
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
[
|
|
265
|
+
"electron",
|
|
266
|
+
{
|
|
267
|
+
id: "electron",
|
|
268
|
+
envStyle: "node",
|
|
269
|
+
wiring: "Call initErrorMom from @kenkaiiii/error-mom/node at the TOP of the main process entry, and import @kenkaiiii/error-mom (browser build) first in each renderer entry. Both report to the same project."
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
[
|
|
273
|
+
"astro",
|
|
274
|
+
{
|
|
275
|
+
id: "astro",
|
|
276
|
+
envStyle: "vite",
|
|
277
|
+
wiring: "Load the setup file as a client script in the base layout so it runs on every page. For SSR/API routes, add src/middleware.ts that wraps next() with errorMom.wrap using @kenkaiiii/error-mom/node."
|
|
278
|
+
}
|
|
279
|
+
],
|
|
280
|
+
[
|
|
281
|
+
"@sveltejs/kit",
|
|
282
|
+
{
|
|
283
|
+
id: "sveltekit",
|
|
284
|
+
envStyle: "vite",
|
|
285
|
+
wiring: "Import the setup file in hooks.client.ts and export handleError from BOTH hooks.client.ts and hooks.server.ts calling errorMom.captureError(error); the server hook uses @kenkaiiii/error-mom/node. SvelteKit catches load/endpoint errors, so handleError is its official reporting hook."
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
[
|
|
289
|
+
"nuxt",
|
|
290
|
+
{
|
|
291
|
+
id: "nuxt",
|
|
292
|
+
envStyle: "vite",
|
|
293
|
+
wiring: "Create a client plugin (plugins/error-mom.client.ts) importing the setup file, and a nitro plugin hooking 'error' with @kenkaiiii/error-mom/node for server-side errors."
|
|
294
|
+
}
|
|
295
|
+
],
|
|
296
|
+
[
|
|
297
|
+
"@remix-run/react",
|
|
298
|
+
{
|
|
299
|
+
id: "remix",
|
|
300
|
+
envStyle: "node",
|
|
301
|
+
wiring: "Import the setup file in entry.client.tsx, and export handleError from entry.server.tsx calling errorMom.captureError(error). Remix catches loader/action errors and handleError is its official reporting hook."
|
|
302
|
+
}
|
|
303
|
+
],
|
|
304
|
+
[
|
|
305
|
+
"@angular/core",
|
|
306
|
+
{
|
|
307
|
+
id: "angular",
|
|
308
|
+
envStyle: "node",
|
|
309
|
+
wiring: "Import the setup file in main.ts and provide a custom ErrorHandler that calls errorMom.captureError(error). Angular catches component errors in its own handler."
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
[
|
|
313
|
+
"express",
|
|
314
|
+
{
|
|
315
|
+
id: "express",
|
|
316
|
+
envStyle: "node",
|
|
317
|
+
wiring: "Import the setup file at the TOP of the server entry, and add a final error middleware: (err, req, res, next) => { errorMom.captureError(err, { culprit: `${req.method} ${req.path}` }); next(err); }. Express catches route errors, so the middleware is where they surface."
|
|
318
|
+
}
|
|
319
|
+
],
|
|
320
|
+
[
|
|
321
|
+
"fastify",
|
|
322
|
+
{
|
|
323
|
+
id: "fastify",
|
|
324
|
+
envStyle: "node",
|
|
325
|
+
wiring: "Import the setup file at the TOP of the server entry, and call errorMom.captureError(error) inside setErrorHandler before replying. Fastify catches handler errors there."
|
|
326
|
+
}
|
|
327
|
+
],
|
|
328
|
+
[
|
|
329
|
+
"hono",
|
|
330
|
+
{
|
|
331
|
+
id: "hono",
|
|
332
|
+
envStyle: "node",
|
|
333
|
+
wiring: "Import the setup file at the TOP of the server entry, and call errorMom.captureError(err) inside app.onError. Hono catches handler errors there."
|
|
334
|
+
}
|
|
335
|
+
],
|
|
336
|
+
[
|
|
337
|
+
"@nestjs/core",
|
|
338
|
+
{
|
|
339
|
+
id: "nestjs",
|
|
340
|
+
envStyle: "node",
|
|
341
|
+
wiring: "Import the setup file at the TOP of main.ts, and add a global exception filter that calls errorMom.captureError(exception) before delegating to the base filter."
|
|
342
|
+
}
|
|
343
|
+
],
|
|
344
|
+
[
|
|
345
|
+
"vite",
|
|
346
|
+
{
|
|
347
|
+
id: "vite",
|
|
348
|
+
envStyle: "vite",
|
|
349
|
+
wiring: "Import the setup file first in the app entry (main.tsx or equivalent)."
|
|
350
|
+
}
|
|
351
|
+
]
|
|
352
|
+
];
|
|
246
353
|
function detectFramework(packageJson) {
|
|
247
354
|
const dependencies = {
|
|
248
355
|
...packageJson.dependencies ?? {},
|
|
249
356
|
...packageJson.devDependencies ?? {}
|
|
250
357
|
};
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
358
|
+
for (const [dependency, info] of FRAMEWORKS) {
|
|
359
|
+
if (dependencies[dependency]) return info;
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
id: "node",
|
|
363
|
+
envStyle: "node",
|
|
364
|
+
wiring: "Import the setup file at the TOP of the main entry point, before anything else."
|
|
365
|
+
};
|
|
254
366
|
}
|
|
255
367
|
function detectPackageManager(cwd) {
|
|
256
368
|
if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
@@ -271,25 +383,24 @@ function installSdk(packageManager) {
|
|
|
271
383
|
async function writeSetup(framework) {
|
|
272
384
|
const sourceDirectory = existsSync(join(process.cwd(), "src")) ? "src" : ".";
|
|
273
385
|
const relativePath = join(sourceDirectory, "error-mom.ts");
|
|
274
|
-
if (framework === "next") await writeNextInstrumentation(sourceDirectory);
|
|
275
|
-
const environment = framework === "next" ? "process.env.NEXT_PUBLIC_" : framework === "vite" ? "import.meta.env.VITE_" : "process.env.";
|
|
276
|
-
const moduleName = framework === "node" ? "@kenkaiiii/error-mom/node" : "@kenkaiiii/error-mom";
|
|
277
|
-
const contents = `${framework === "next" ? '"use client";\n\n' : ""}import { initErrorMom } from "${moduleName}";
|
|
386
|
+
if (framework.id === "next") await writeNextInstrumentation(sourceDirectory);
|
|
387
|
+
const environment = framework.envStyle === "next" ? "process.env.NEXT_PUBLIC_" : framework.envStyle === "vite" ? "import.meta.env.VITE_" : "process.env.";
|
|
388
|
+
const moduleName = framework.envStyle === "node" ? "@kenkaiiii/error-mom/node" : "@kenkaiiii/error-mom";
|
|
389
|
+
const contents = `${framework.id === "next" ? '"use client";\n\n' : ""}import { initErrorMom } from "${moduleName}";
|
|
278
390
|
|
|
279
391
|
const server = ${environment}ERROR_MOM_SERVER;
|
|
280
392
|
const projectKey = ${environment}ERROR_MOM_PROJECT_KEY;
|
|
281
393
|
const release = ${environment}ERROR_MOM_RELEASE;
|
|
282
394
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
});
|
|
395
|
+
export const errorMom =
|
|
396
|
+
server && projectKey
|
|
397
|
+
? initErrorMom({
|
|
398
|
+
server,
|
|
399
|
+
projectKey,
|
|
400
|
+
environment: ${environment}ERROR_MOM_ENVIRONMENT ?? "production",
|
|
401
|
+
...(release ? { release } : {}),
|
|
402
|
+
})
|
|
403
|
+
: undefined;
|
|
293
404
|
`;
|
|
294
405
|
await writeFile(join(process.cwd(), relativePath), contents);
|
|
295
406
|
return relativePath;
|
|
@@ -324,7 +435,7 @@ export const onRequestError: Instrumentation.onRequestError = async (
|
|
|
324
435
|
await writeFile(file, contents);
|
|
325
436
|
}
|
|
326
437
|
async function appendEnvironment(framework, server, key) {
|
|
327
|
-
const prefix = framework === "next" ? "NEXT_PUBLIC_" : framework === "vite" ? "VITE_" : "";
|
|
438
|
+
const prefix = framework.envStyle === "next" ? "NEXT_PUBLIC_" : framework.envStyle === "vite" ? "VITE_" : "";
|
|
328
439
|
const file = join(process.cwd(), ".env.local");
|
|
329
440
|
const existing = existsSync(file) ? await readFile(file, "utf8") : "";
|
|
330
441
|
const lines = [
|