npm package: @lmstech/monitor
Description: Lightweight monitoring package for Next.js apps. Captures server logs, client errors, uncaught exceptions, and unhandled rejections — sends everything to the Observatory dashboard.
Latest version: 0.1.1

# @lmstech/monitor

Lightweight monitoring package for Next.js apps. Captures server logs, client errors, uncaught exceptions, and unhandled rejections — sends everything to the Observatory dashboard.

If `MONITOR_URL` and `MONITOR_KEY` aren't set, the entire package is inert. No patching, no listeners, no network calls.

## Setup in a consuming app

Four files, nine lines.

### 1. `instrumentation.ts` (project root)

```ts
export async function register() {
  const { init } = await import("@lmstech/monitor/server");
  init({ app: "my-app", env: "production", version: process.env.COMMIT_SHA });
}
```

### 2. `app/api/monitor/route.ts`

```ts
export { POST } from "@lmstech/monitor/server";
```

### 3. `app/layout.tsx`

```tsx
import { Monitor } from "@lmstech/monitor/client";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Monitor app="my-app" env="production">
          {children}
        </Monitor>
      </body>
    </html>
  );
}
```

### 4. Environment variables

```bash
MONITOR_URL=https://your-dashboard.vercel.app
MONITOR_KEY=your-api-key
COMMIT_SHA=abc123  # typically set by CI (GITHUB_SHA in GitHub Actions)
```

Don't set these in local dev. The package stays invisible when they're absent.

## Custom logging

### Server-side

```ts
import { log } from "@lmstech/monitor/server";

log({ level: "info", message: "Payment processed", meta: { userId: "123" } });
```

### Client-side

```tsx
import { useMonitor } from "@lmstech/monitor/client";

const { log } = useMonitor();
log({ level: "error", message: "Checkout failed", meta: { step: "payment" } });
```

`useMonitor()` must be called inside the `<Monitor>` provider tree.

## Developing the package

Everything runs from the **repo root**.

```bash
pnpm pkg:build       # clean build (tsc)
pnpm pkg:publish     # build + publish to npm
```

The build compiles `src/` to `dist/` using `tsconfig.build.json`. No bundler — just tsc.

### Testing

```bash
cd packages/monitor
pnpm test            # run tests once
pnpm test:watch      # watch mode
pnpm typecheck       # type-check without emitting
```

### Package structure

```
src/
  types.ts              # all public types (EventLevel, LogPayload, InitOptions, etc.)
  server/
    index.ts            # exports: init, log, POST
    init.ts             # console.error patching, process handlers, startup event
    log.ts              # custom server-side log()
    route.ts            # POST handler for client-side proxy
    batch.ts            # in-memory queue, 5s / 50-event flush
    send.ts             # fire-and-forget fetch to /api/ingest
  client/
    index.ts            # exports: Monitor, useMonitor
    context.tsx          # React context for app/env
    monitor.tsx          # error + unhandledrejection listeners, sendBeacon
    use-monitor.ts       # hook for custom client-side logging
  shared/
    serialize.ts         # safe meta serialization (circular refs, depth/size limits)
```

Two entry points: `@lmstech/monitor/server` and `@lmstech/monitor/client`.

## Publishing

1. Bump the version in `packages/monitor/package.json`.
2. From the repo root: `pnpm pkg:publish`.

That's it. The script builds first, then publishes `dist/` to npm.

**First time only:** make sure you're logged in (`npm login`) and the `@lmstech` npm org exists with public access. The publish script uses `--access public` for the scoped package.