Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions apps/docs/app/Route/Architecture.elm
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ view app _ =
[ Html.text "Shared annotators (OIDC phase detection, CORS, DPoP, PAR), diagnosis engine, event store, and export/redaction logic. Used by both the browser extension and VS Code extension." ]
, Html.dt [] [ Html.text "@wolfcola/devtools-bridge" ]
, Html.dd []
[ Html.text "SDK adapter for emitting events from DaVinci, Journey, and OIDC clients. Depends on devtools-types." ]
[ Html.text "SDK adapter for emitting events from DaVinci, Journey, and OIDC clients. Connects to the browser extension or standalone debugger. Depends on devtools-types." ]
, Html.dt [] [ Html.text "@wolfcola/devtools-standalone" ]
, Html.dd []
[ Html.text "Standalone Electron debugger with WebSocket server and MCP integration. Uses devtools-core for event processing and devtools-ui for the Elm panel." ]
, Html.dt [] [ Html.text "@wolfcola/devtools-ui" ]
, Html.dd []
[ Html.text "Elm UI components for Timeline, Flow, and Learn views. Provides the panel interface with inspector tabs, playback controls, and diagnosis display." ]
Expand Down Expand Up @@ -132,19 +135,20 @@ view app _ =
viewDiagram : Html.Html (PagesMsg Msg)
viewDiagram =
Svg.svg
[ SvgAttr.viewBox "0 0 900 480"
[ SvgAttr.viewBox "0 0 900 580"
, SvgAttr.width "900"
, SvgAttr.height "480"
, SvgAttr.height "580"
, SvgAttr.style "max-width: 100%; height: auto;"
]
[ -- OIDC DevTools group
svgGroup 20 20 520 440 "OIDC DevTools"
svgGroup 20 20 520 540 "OIDC DevTools"
, svgBox 180 60 200 50 "devtools-types"
, svgBox 40 160 200 50 "devtools-core"
, svgBox 300 160 200 50 "devtools-bridge"
, svgBox 40 270 200 50 "devtools-ui"
, svgBox 40 370 200 50 "devtools-extension"
, svgBox 300 370 200 50 "vscode-extension"
, svgBox 300 470 200 50 "devtools-standalone"

-- Tree-Shake Tools group
, svgGroup 570 20 310 200 "Tree-Shake Tools"
Expand All @@ -171,6 +175,9 @@ viewDiagram =
-- Arrows: devtools-core -> vscode-extension
, svgArrow 200 210 380 370

-- Arrows: devtools-core -> devtools-standalone
, svgArrow 200 210 380 470

-- Arrows: treeshake-check -> eslint-plugin-treeshake
, svgArrow 720 110 720 160
]
Expand Down
6 changes: 6 additions & 0 deletions apps/docs/app/Route/Index.elm
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ viewPackageGrid =
, route = Route.Packages__Slug_ { slug = "dead-export-finder" }
, tag = "Published"
}
, viewPackageCard
{ name = "@wolfcola/devtools-standalone"
, description = "Standalone Electron debugger with WebSocket server and MCP integration"
, route = Route.Packages__Slug_ { slug = "devtools-standalone" }
, tag = "New"
}
]


Expand Down
6 changes: 6 additions & 0 deletions apps/docs/content/contributing/repository-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The wolfcola-devtools repository is a pnpm workspace monorepo. All publishable p
| `@wolfcola/devtools-core` | `packages/devtools-core` | Shared annotators, diagnosis engine, event store |
| `@wolfcola/devtools-ui` | `packages/devtools-ui` | Elm UI components for Timeline, Flow, and Learn views |
| `@wolfcola/devtools-extension` | `packages/devtools-extension` | Browser extension for Chrome and Firefox |
| `@wolfcola/devtools-standalone` | `packages/devtools-standalone` | Standalone Electron debugger with WebSocket and MCP |
| `oidc-devtools` | `packages/vscode-extension` | VS Code extension with CDP connection |
| `@wolfcola/dead-export-finder` | `packages/dead-export-finder` | CLI to find unused exports across monorepo boundaries |
| `@wolfcola/changeset-sync-manifest` | `packages/changeset-sync-manifest` | Syncs package version from changesets to manifest files |
Expand Down Expand Up @@ -60,6 +61,11 @@ devtools-extension
├── devtools-ui (Elm)
└── devtools-types

devtools-standalone
├── devtools-core
├── devtools-ui (Elm)
└── devtools-types

devtools-bridge
└── devtools-types

Expand Down
13 changes: 13 additions & 0 deletions apps/docs/content/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,22 @@ Scan your monorepo for unused exports:
npx dead-export-finder
```

## Standalone Debugger

For environments where a browser extension is not available (Node.js servers, React Native, Electron apps), use the standalone debugger:

```typescript
import { attachDebugger } from '@wolfcola/devtools-bridge';

const handle = await attachDebugger({ name: 'my-app' });
```

<callout type="info">The standalone debugger connects via WebSocket and can auto-launch if installed on your PATH. See the [Standalone Debugger](/docs/standalone-debugger) guide for details.</callout>

## Next Steps

- Read the [Tree-Shaking Guide](/docs/tree-shaking)
- Explore the [Architecture](/architecture)
- Learn about the [DevTools Extension](/docs/devtools-extension)
- Check out the [VS Code Extension](/docs/vscode-extension)
- Try the [Standalone Debugger](/docs/standalone-debugger) for non-browser environments
155 changes: 155 additions & 0 deletions apps/docs/content/docs/standalone-debugger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
title: 'Standalone Debugger'
description: 'Use the standalone Electron debugger for OIDC/OAuth2 debugging without a browser extension'
section: guides
order: 3
---

# Standalone Debugger

The standalone debugger is an Electron desktop app that provides the same OIDC debugging UI as the browser extension, but connects via WebSocket instead of browser APIs. This makes it suitable for:

- **Node.js servers and backend services** — no browser extension available
- **React Native and mobile webviews** — can't install browser extensions
- **Electron apps** — debug your own Electron app's auth flows
- **Any environment** where installing a browser extension is impractical

## Quick Start

### 1. Start the debugger

```bash
# From the monorepo
pnpm --filter @wolfcola/devtools-standalone build
pnpm --filter @wolfcola/devtools-standalone start
```

The debugger opens an Electron window and starts a WebSocket server on `localhost:19417`.

### 2. Connect your app

Install the bridge in your application:

```bash
npm install @wolfcola/devtools-bridge
```

Then call `attachDebugger`:

```typescript
import { attachDebugger } from '@wolfcola/devtools-bridge';

const handle = await attachDebugger({
name: 'my-app',
});

// Events are now forwarded to the standalone debugger.
// When done:
handle.detach();
```

That's it. The bridge connects via WebSocket, installs a fetch interceptor to capture auth-related network requests, and forwards everything to the debugger.

## Configuration

`attachDebugger` accepts these options:

| Option | Type | Default | Purpose |
| ------------ | --------- | ------- | ---------------------------------------------------------- |
| `name` | `string` | — | App name shown in the session list (required) |
| `port` | `number` | `19417` | WebSocket server port |
| `autoLaunch` | `boolean` | `true` | Launch the debugger binary if not already running |
| `network` | `boolean` | `true` | Install fetch interceptor to capture auth-related requests |
| `pid` | `number` | — | Process ID (optional metadata) |
| `framework` | `string` | — | Framework name (optional metadata) |

### Auto-launch

When `autoLaunch` is enabled (the default), the bridge searches your PATH for `wolfcola-devtools`, launches it as a background process, and retries the WebSocket connection with exponential backoff. If the binary isn't found or launch fails, the bridge logs a warning and returns `{ connected: false }`.

### Custom port

```typescript
// Start the debugger on a custom port
// electron dist/src/main.cjs --port 9000

const handle = await attachDebugger({
name: 'my-app',
port: 9000,
});
```

## Node.js HTTP Interceptor

For server-side apps that use Node's `http`/`https` modules instead of `fetch`, install the Node HTTP interceptor separately:

```typescript
import {
attachDebugger,
installNodeHttpInterceptor,
uninstallNodeHttpInterceptor,
} from '@wolfcola/devtools-bridge';

const handle = await attachDebugger({ name: 'my-server', network: false });

installNodeHttpInterceptor((entry) => {
// Forward captured HTTP requests to the debugger
client.sendNetworkEvent(entry);
});

// Cleanup
uninstallNodeHttpInterceptor();
handle.detach();
```

The interceptor patches `http.request` and `https.request` to capture request/response data for auth-related URLs.

## Sessions

Each connected app appears as a session in the debugger. Sessions track:

- **Name** — from the `name` option in `attachDebugger`
- **Status** — connected or disconnected
- **Framework** and **PID** — optional metadata
- **Events** — all `AuthEvent` objects received from the app

When an app disconnects and reconnects, the debugger can either preserve or clear the previous session's events (controlled by the "clear on reconnect" setting per session).

## MCP Mode

The standalone debugger can also run as a headless MCP server for AI agent integration:

```bash
electron dist/src/main.cjs --mcp
```

In this mode there is no UI — the debugger communicates via stdio using the Model Context Protocol. This is useful for automated debugging with Claude or other AI assistants. See the [package reference](/packages/devtools-standalone) for the full list of MCP tools.

## Views

The standalone debugger uses the same Elm UI as the browser extension. You get the same three views:

- **Timeline** — chronological list of all auth events
- **Flow** — state diagram of the current OIDC flow
- **Learn** — contextual documentation for OIDC concepts

See the [DevTools Extension](/docs/devtools-extension) guide for details on each view.

## Troubleshooting

**WebSocket connection fails:**

1. Verify the debugger is running: look for the Electron window or check if port 19417 is in use
2. Check that no firewall is blocking localhost connections
3. Try a custom port if 19417 is taken: `--port 9000`

**No events appearing:**

1. Confirm `handle.connected` is `true` after calling `attachDebugger`
2. Verify your app is making auth-related requests (the interceptor filters by URL pattern)
3. Check the browser/Node console for warnings from the bridge

**Auto-launch not working:**

1. Ensure `wolfcola-devtools` is on your PATH
2. Try launching the debugger manually first to rule out startup errors
40 changes: 38 additions & 2 deletions apps/docs/content/packages/devtools-bridge.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: '@wolfcola/devtools-bridge'
description: 'SDK adapter for emitting auth events to the Ping DevTools extension'
description: 'SDK adapter for emitting auth events to the DevTools extension or standalone debugger'
section: packages
order: 3
---

# @wolfcola/devtools-bridge

The devtools bridge connects your OIDC client to the Ping DevTools browser extension. It monitors SDK state changes and emits `AuthEvent` objects via `CustomEvent` on the window, where the extension picks them up.
The devtools bridge connects your OIDC client to Ping DevTools — either the browser extension, the VS Code extension, or the [standalone debugger](/docs/standalone-debugger). It monitors SDK state changes and emits `AuthEvent` objects via `CustomEvent` on the window (for extensions) or WebSocket (for the standalone debugger).

## Installation

Expand Down Expand Up @@ -179,4 +179,40 @@ Call `detach()` to unsubscribe the bridge from the SDK client.

Events are stored on `window.__PING_DEVTOOLS_STATE__` as an array of `AuthEvent` objects. The array is capped at 500 entries; when the limit is exceeded, the oldest entries are removed via `splice`.

## Standalone Debugger — `attachDebugger`

Connects your app to the [standalone Electron debugger](/docs/standalone-debugger) via WebSocket. Works in both browser and Node.js environments.

```typescript
import { attachDebugger } from '@wolfcola/devtools-bridge';

const handle = await attachDebugger({
name: 'my-spa',
port: 19417,
autoLaunch: true,
network: true,
framework: 'react',
});

handle.detach();
```

Returns a `DebuggerHandle`:

```typescript
interface DebuggerHandle {
connected: boolean;
detach(): void;
}
```

**What happens on `attachDebugger()`:**

1. Opens a WebSocket to `ws://localhost:{port}` and sends a handshake
2. If not connected and `autoLaunch` is enabled, finds `wolfcola-devtools` in PATH, spawns it, and retries with exponential backoff
3. If connected and `network` is enabled, installs a fetch interceptor that forwards auth-related requests
4. Returns `{ connected, detach() }`

See the [Standalone Debugger guide](/docs/standalone-debugger) for full configuration options and Node.js HTTP interceptor usage.

<callout type="warning">Always call `handle.detach()` when you are done. Failing to do so may cause memory leaks from lingering subscription listeners.</callout>
Loading
Loading