From 6bfba4893c85fb2905023d859343633566f3c852 Mon Sep 17 00:00:00 2001 From: Ryan Bas Date: Wed, 13 May 2026 16:58:51 -0600 Subject: [PATCH 1/2] docs: update documentation to match current codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rewrite devtools-extension guide with network-first detection, all 10 inspector tabs, diagnosis engine rules, import/export, snapshots, playback, and Learn view layouts - Fix vscode-extension guide: remove nonexistent CodeLens, correct command names, add debug config and troubleshooting - Fix devtools-bridge API docs: add per-bridge signatures with distinct client interfaces (Subscribable, JourneySubscribable, OidcSubscribable) - Fix root README: attachDevToolsBridge → attachDaVinciBridge - Add dead-export-finder and changeset-sync-manifest to package tables, architecture diagram, sidebar, and homepage grid - Add dead-export-finder docs page and package READMEs - Rewrite apps/docs README from stub to full site documentation - Update getting-started to lead with network-first detection - Update repository-structure with missing packages Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 14 +- apps/docs/README.md | 61 +++++- apps/docs/app/Route/Architecture.elm | 79 ++++++-- apps/docs/app/Route/Index.elm | 6 + apps/docs/app/Shared.elm | 1 + apps/docs/content/contributing/code-style.md | 2 +- .../contributing/repository-structure.md | 8 + apps/docs/content/docs/devtools-extension.md | 176 ++++++++++++++++-- apps/docs/content/docs/getting-started.md | 34 +++- apps/docs/content/docs/vscode-extension.md | 92 ++++++--- .../content/packages/dead-export-finder.md | 71 +++++++ apps/docs/content/packages/devtools-bridge.md | 70 ++++++- packages/changeset-sync-manifest/README.md | 35 ++++ packages/dead-export-finder/README.md | 103 ++++++++++ 14 files changed, 680 insertions(+), 72 deletions(-) create mode 100644 apps/docs/content/packages/dead-export-finder.md create mode 100644 packages/changeset-sync-manifest/README.md create mode 100644 packages/dead-export-finder/README.md diff --git a/README.md b/README.md index 904847c..9a303cd 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,13 @@ Analyze and enforce tree-shakeability across your packages — catch bundle-bloa | [`treeshake-check`](packages/treeshake-check) | CLI & library — checks whether a package can be fully tree-shaken by Rollup | [![npm](https://img.shields.io/npm/v/@wolfcola/treeshake-check)](https://www.npmjs.com/package/@wolfcola/treeshake-check) | | [`eslint-plugin-treeshake`](packages/eslint-plugin-treeshake) | ESLint plugin that flags code patterns known to break tree-shaking | [![npm](https://img.shields.io/npm/v/@wolfcola/eslint-plugin-treeshake)](https://www.npmjs.com/package/@wolfcola/eslint-plugin-treeshake) | +### Utilities + +| Package | Description | npm | +| ------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| [`dead-export-finder`](packages/dead-export-finder) | CLI to find unused exports across monorepo package boundaries | [![npm](https://img.shields.io/npm/v/@wolfcola/dead-export-finder)](https://www.npmjs.com/package/@wolfcola/dead-export-finder) | +| [`changeset-sync-manifest`](packages/changeset-sync-manifest) | Syncs package version from changesets to manifest files | private | + --- ## Quick start @@ -104,10 +111,13 @@ pnpm add @wolfcola/devtools-bridge ```ts import { davinci } from '@forgerock/davinci-client'; -import { attachDevToolsBridge } from '@wolfcola/devtools-bridge'; +import { attachDaVinciBridge } from '@wolfcola/devtools-bridge'; const client = await davinci({ config }); -attachDevToolsBridge(client, config); +const handle = attachDaVinciBridge(client, config); + +// When done: +handle.detach(); ``` The bridge is a no-op when the extension is not installed. diff --git a/apps/docs/README.md b/apps/docs/README.md index 7e59600..c6ee5c4 100644 --- a/apps/docs/README.md +++ b/apps/docs/README.md @@ -1 +1,60 @@ -# README +# @wolfcola/docs-site + +The documentation site for wolfcola devtools, built with [elm-pages](https://elm-pages.com/). + +## Development + +```bash +pnpm --filter @wolfcola/docs-site dev +``` + +Opens a local dev server with hot reload. + +## Build + +```bash +pnpm --filter @wolfcola/docs-site build +``` + +Generates a static site in `dist/` using the Netlify adapter. The site is served under the `/devtools/` base path. + +## Content + +Documentation is authored as Markdown files in the `content/` directory: + +| Directory | Section | Description | +| ----------------------- | ------------ | ---------------------------------------------------- | +| `content/docs/` | Guides | Getting started, extension usage, integration guides | +| `content/packages/` | Packages | API reference for each published package | +| `content/contributing/` | Contributing | Development setup, code style, release process | + +Each Markdown file has YAML frontmatter with `title`, `description`, `section`, and `order` fields used for navigation and search indexing. + +## Architecture + +- **elm-pages** — static site generator with file-based routing +- **Elm** — all page logic, layout, search, and theme toggle +- **Vite** — bundler (configured via `elm-pages.config.mjs`) +- **Netlify** — deployment adapter +- **Prism.js** — syntax highlighting for code blocks + +### Adding a new page + +1. Create a Markdown file in the appropriate `content/` subdirectory +2. Add frontmatter with `title`, `description`, `section`, and `order` +3. Add a sidebar link in `app/Shared.elm` under the matching section +4. The route is automatically generated from the directory and filename + +### Key files + +| File | Purpose | +| ---------------------------------- | ------------------------------------------------- | +| `app/Shared.elm` | Layout, header, sidebar, search, theme toggle | +| `app/Route/Index.elm` | Home page with package grid | +| `app/Route/Architecture.elm` | Architecture diagram (SVG) | +| `app/Route/Docs/Slug_.elm` | Dynamic guide page renderer | +| `app/Route/Packages/Slug_.elm` | Dynamic package page renderer | +| `app/Route/Contributing/Slug_.elm` | Dynamic contributing page renderer | +| `src/MarkdownRenderer.elm` | Custom Markdown renderer with callout support | +| `src/Search.elm` | Full-text search index and matching | +| `style.css` | Stylesheet with CSS custom properties for theming | diff --git a/apps/docs/app/Route/Architecture.elm b/apps/docs/app/Route/Architecture.elm index 8239a82..6b24ad2 100644 --- a/apps/docs/app/Route/Architecture.elm +++ b/apps/docs/app/Route/Architecture.elm @@ -86,20 +86,44 @@ view app _ = ] , Html.div [ Attr.class "architecture-diagram" ] [ viewDiagram ] - , Html.h2 [] [ Html.text "Package Relationships" ] + , Html.h2 [] [ Html.text "OIDC DevTools" ] , Html.dl [] [ Html.dt [] [ Html.text "@wolfcola/devtools-types" ] , Html.dd [] - [ Html.text "Effect Schema definitions for AuthEvent and FlowState. Shared foundation used by devtools-bridge." ] + [ Html.text "Effect Schema definitions for AuthEvent and FlowState. The shared foundation that all other OIDC packages depend on." ] + , Html.dt [] [ Html.text "@wolfcola/devtools-core" ] + , Html.dd [] + [ 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.dt [] [ Html.text "@wolfcola/treeshake-check" ] + , 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." ] + , Html.dt [] [ Html.text "@wolfcola/devtools-extension" ] + , Html.dd [] + [ Html.text "Chrome and Firefox browser extension. Bundles devtools-core and devtools-ui into a DevTools panel with network-first OIDC detection." ] + , Html.dt [] [ Html.text "oidc-devtools (VS Code)" ] + , Html.dd [] + [ Html.text "VS Code extension that connects via Chrome DevTools Protocol (CDP) for live auth traffic capture and flow visualization." ] + ] + , Html.h2 [] [ Html.text "Tree-Shake Tools" ] + , Html.dl [] + [ Html.dt [] [ Html.text "@wolfcola/treeshake-check" ] , Html.dd [] [ Html.text "CLI & library to verify packages are tree-shakeable by Rollup. Standalone package." ] , Html.dt [] [ Html.text "@wolfcola/eslint-plugin-treeshake" ] , Html.dd [] - [ Html.text "ESLint plugin that flags tree-breaking patterns. Can use treeshake-check for verification." ] + [ Html.text "ESLint plugin that flags tree-breaking patterns. Can use treeshake-check for bundle-level verification." ] + ] + , Html.h2 [] [ Html.text "Utilities" ] + , Html.dl [] + [ Html.dt [] [ Html.text "@wolfcola/dead-export-finder" ] + , Html.dd [] + [ Html.text "CLI to find unused exports across monorepo package boundaries. Uses oxc-parser for fast AST analysis." ] + , Html.dt [] [ Html.text "@wolfcola/changeset-sync-manifest" ] + , Html.dd [] + [ Html.text "Syncs package version from changesets to manifest files. Used in the CI release workflow." ] ] ] } @@ -108,28 +132,47 @@ view app _ = viewDiagram : Html.Html (PagesMsg Msg) viewDiagram = Svg.svg - [ SvgAttr.viewBox "0 0 700 360" - , SvgAttr.width "700" - , SvgAttr.height "360" + [ SvgAttr.viewBox "0 0 900 480" + , SvgAttr.width "900" + , SvgAttr.height "480" , SvgAttr.style "max-width: 100%; height: auto;" ] [ -- OIDC DevTools group - svgGroup 20 20 320 300 "OIDC DevTools" - , svgBox 60 80 240 60 "devtools-types" - , svgBox 60 200 240 60 "devtools-bridge" + svgGroup 20 20 520 440 "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" -- Tree-Shake Tools group - , svgGroup 370 20 310 300 "Tree-Shake Tools" - , svgBox 400 80 240 60 "treeshake-check" - , svgBox 400 200 240 60 "eslint-plugin-treeshake" + , svgGroup 570 20 310 200 "Tree-Shake Tools" + , svgBox 600 60 240 50 "treeshake-check" + , svgBox 600 160 240 50 "eslint-plugin-treeshake" + + -- Utilities group + , svgGroup 570 250 310 210 "Utilities" + , svgBox 600 290 240 50 "dead-export-finder" + , svgBox 600 390 240 50 "changeset-sync-manifest" + + -- Arrows: devtools-types -> devtools-core + , svgArrow 230 110 180 160 + + -- Arrows: devtools-types -> devtools-bridge + , svgArrow 330 110 370 160 + + -- Arrows: devtools-core -> devtools-extension + , svgArrow 140 210 140 270 - -- Arrows - , svgArrow 180 140 180 200 + -- Arrows: devtools-ui -> devtools-extension + , svgArrow 140 320 140 370 - -- devtools-types -> devtools-bridge - , svgArrow 520 160 520 200 + -- Arrows: devtools-core -> vscode-extension + , svgArrow 200 210 380 370 - -- treeshake-check -> eslint-plugin-treeshake (optional dependency) + -- Arrows: treeshake-check -> eslint-plugin-treeshake + , svgArrow 720 110 720 160 ] diff --git a/apps/docs/app/Route/Index.elm b/apps/docs/app/Route/Index.elm index 83f0334..0a89006 100644 --- a/apps/docs/app/Route/Index.elm +++ b/apps/docs/app/Route/Index.elm @@ -119,6 +119,12 @@ viewPackageGrid = , route = Route.Packages__Slug_ { slug = "devtools-types" } , tag = "Published" } + , viewPackageCard + { name = "@wolfcola/dead-export-finder" + , description = "CLI to find unused exports across monorepo package boundaries" + , route = Route.Packages__Slug_ { slug = "dead-export-finder" } + , tag = "Published" + } ] diff --git a/apps/docs/app/Shared.elm b/apps/docs/app/Shared.elm index b9e922f..21247a9 100644 --- a/apps/docs/app/Shared.elm +++ b/apps/docs/app/Shared.elm @@ -296,6 +296,7 @@ viewSidebar model toMsg = , ( Route.Packages__Slug_ { slug = "eslint-plugin-treeshake" }, "eslint-plugin-treeshake" ) , ( Route.Packages__Slug_ { slug = "devtools-bridge" }, "devtools-bridge" ) , ( Route.Packages__Slug_ { slug = "devtools-types" }, "devtools-types" ) + , ( Route.Packages__Slug_ { slug = "dead-export-finder" }, "dead-export-finder" ) ] , viewSidebarSection "Guides" [ ( Route.Docs__Slug_ { slug = "getting-started" }, "Getting Started" ) diff --git a/apps/docs/content/contributing/code-style.md b/apps/docs/content/contributing/code-style.md index 19971ec..5311d8c 100644 --- a/apps/docs/content/contributing/code-style.md +++ b/apps/docs/content/contributing/code-style.md @@ -7,7 +7,7 @@ order: 3 # Code Style -This repository uses two primary languages: Effect TypeScript for all runtime packages and Elm for the documentation site. Each has its own conventions. +This repository uses two primary languages: Effect TypeScript for all runtime packages and Elm for both the DevTools panel UI (`devtools-ui`) and the documentation site. Each has its own conventions. ## Effect TypeScript Conventions diff --git a/apps/docs/content/contributing/repository-structure.md b/apps/docs/content/contributing/repository-structure.md index 938cfbf..2b2059b 100644 --- a/apps/docs/content/contributing/repository-structure.md +++ b/apps/docs/content/contributing/repository-structure.md @@ -21,6 +21,8 @@ The wolfcola-devtools repository is a pnpm workspace monorepo. All publishable p | `@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 | | `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 | | `@wolfcola/docs-site` | `apps/docs` | This documentation site (elm-pages) | ## Root Files @@ -72,6 +74,12 @@ treeshake-check eslint-plugin-treeshake (standalone, optional dep on treeshake-check) + +dead-export-finder + (standalone) + +changeset-sync-manifest + (standalone) ``` The `devtools-types` package is the shared foundation. It defines the `AuthEvent` and `FlowState` schemas that the bridge, browser extension, and VS Code extension all depend on. diff --git a/apps/docs/content/docs/devtools-extension.md b/apps/docs/content/docs/devtools-extension.md index 2aedf6d..2e3ea0e 100644 --- a/apps/docs/content/docs/devtools-extension.md +++ b/apps/docs/content/docs/devtools-extension.md @@ -17,7 +17,7 @@ Install from the [Chrome Web Store](https://chrome.google.com/webstore). Search ### Firefox -Install from [Firefox Add-ons](https://addons.mozilla.org). The extension supports Firefox 115+ (ESR) and all modern Firefox releases. +Install from [Firefox Add-ons](https://addons.mozilla.org). The extension supports Firefox 128+ and all modern Firefox releases. ### Manual Installation (Development) @@ -30,11 +30,24 @@ pnpm install pnpm --filter @wolfcola/devtools-extension build ``` -Then load the unpacked extension from `packages/devtools-extension/` in your browser's extension management page (the `manifest.json` is in the package root). +Then load the unpacked extension from `packages/devtools-extension/dist/` in your browser's extension management page. + +## Network-First Detection + +The extension works **without the `@wolfcola/devtools-bridge` SDK**. It uses a network observer in the service worker that automatically detects OIDC-related traffic by: + +1. **URL pattern matching** against common auth endpoint patterns (`/authorize`, `/token`, `/userinfo`, `/revoke`, `/introspect`, `/par`, `/jwks`, `/.well-known/openid-configuration`, etc.) +2. **Well-known discovery** — when a `.well-known/openid-configuration` response is seen, the extension parses it and matches all discovered endpoints going forward +3. **CORS detection** — identifies status-zero failures and missing headers on auth requests +4. **Static asset filtering** — ignores JS, CSS, images, and fonts + +When the `@wolfcola/devtools-bridge` SDK is also present, the extension receives richer events (SDK node state, session diffs, config data) in addition to network events. + +Network-first detection means you can open the OIDC DevTools panel on any page that talks to an OIDC provider and immediately see annotated traffic, even without instrumenting your app. ## Using the DevTools Panel -Once installed, open your browser DevTools (F12 or Cmd+Opt+I) and look for the **OIDC DevTools** tab. The panel activates automatically when the inspected page includes the `@wolfcola/devtools-bridge` SDK. +Open your browser DevTools (F12 or Cmd+Opt+I) and look for the **OIDC DevTools** tab. ## Views @@ -42,17 +55,27 @@ The extension provides three views, accessible via tabs at the top of the panel. ### Timeline -The Timeline view shows a chronological list of every `AuthEvent` emitted by the bridge. Each event displays: +The Timeline view shows a chronological table of every `AuthEvent` captured. Each row displays: -- **Event type** (e.g. `sdk:node-change`, `session:cookie`, `sdk:oidc-state`) +- **Type badge** — `NET` (network), `SDK` (bridge event), `SES` (session diff), or `CFG` (config) +- **Status code** — HTTP status for network events +- **OIDC phase tag** — the detected phase (`discovery`, `authorize`, `token`, `par`, `userinfo`, etc.) - **Timestamp** relative to the page load -- **Payload** expandable JSON tree with the full event data -Use the filter bar at the top to narrow events by type or search within payloads. +Clicking a row opens the Inspector panel on the right with detailed information about that event. + +A **graph sidebar** on the right shows SDK node transitions as a vertical rail when bridge events are present. ### Flow -The Flow view renders the current OIDC flow as a state diagram. Each node represents a `FlowState`, and edges represent the transitions triggered by `AuthEvent` objects. This is especially useful for visualizing complex DaVinci orchestration flows that involve multiple steps and decision nodes. +The Flow view renders the current authentication flow as a visual diagram. Each node represents an SDK state, and edges show transitions triggered by events. + +Features include: + +- **Node rail** — vertical sequence of SDK nodes with status indicators +- **Detail cards** — expanded information for the selected node +- **Time-travel playback** — Prev/Play/Pause/Reset controls that replay SDK node transitions with timing that mirrors the real elapsed time (clamped between 300ms and 1500ms per step) +- **Flow Health banner** — a summary strip showing the overall diagnosis for the flow (error count, warning count) Color coding indicates the state of each node: @@ -62,19 +85,142 @@ Color coding indicates the state of each node: ### Learn -The Learn view provides contextual documentation for the OIDC concepts involved in the current flow. When you select an event in the Timeline or a node in the Flow view, the Learn panel shows: +The Learn view provides a canvas-based lifecycle visualization that adapts to the detected authentication pattern. The layout is automatically chosen based on the events captured: -- What the event or state represents in the OIDC spec -- Common issues and troubleshooting tips -- Links to the relevant RFC sections +| Layout | Detected when | +| --------------- | ------------------------------------------------------ | +| **DaVinci** | DaVinci SDK node events are present | +| **Journey** | Journey step events are present | +| **OIDC + PAR** | OIDC events with a `par` phase are present | +| **OIDC + DPoP** | OIDC events with DPoP proofs are present | +| **OIDC (Code)** | Default fallback for standard authorization code flows | + +The canvas supports pan, zoom, and card expansion for exploring the lifecycle stages. The Learn view content is bundled with the extension and works offline. +## Inspector Tabs + +When you select an event in the Timeline, the Inspector panel shows context-aware tabs. Only tabs relevant to the selected event are displayed. + +### Diagnosis + +Appears at the top when issues are detected. Shows diagnosis entries with severity (error, warning, info), a title, description, and numbered remediation steps. + +### Headers + +Available for network events. Shows the request URL, HTTP method, and request/response headers. JWT values in `Authorization` headers are automatically decoded inline. If the network event was triggered by an SDK node, a "Caused By" link navigates to the originating event. + +### Payload + +Available for network events that have a request or response body. Shows the parsed body as a JSON tree with a copy-to-clipboard button. + +### Cookies + +Available for network events. Extracts cookies from the request `Cookie` header and response `Set-Cookie` headers. + +### CORS + +Shows CORS detection results. Green indicates no issues; red shows the specific CORS failure reason (status-zero, missing `Access-Control-Allow-Origin`, wildcard with credentials, etc.). + +### SDK State + +Available for DaVinci SDK events. Shows the node status transition (e.g. `start` to `continue`), HTTP status, node metadata (name, description, event name), interaction IDs, error details, and authorization data. + +### Collectors + +Available for SDK events with collector data. Lists each collector object with individual copy buttons and a "Copy all" button. + +### Session + +Available for session diff events. Shows the storage key, and the before/after values color-coded for easy comparison. + +### Config + +Available for SDK config events. Displays the raw SDK configuration as a JSON tree. + +### OIDC + +Available for events with OIDC semantic annotations. Shows the detected phase, grant type, client ID, state parameter, PKCE status, DPoP status, token presence, PAR request URI, and any OIDC error details. + +## Diagnosis Engine + +The extension includes a built-in diagnosis engine that automatically detects issues in captured flows. Diagnosis rules run on both individual events and the overall flow. + +### CORS Rules + +- **Preflight rejection** — network failure with status zero +- **Missing Allow-Origin** — server omits `Access-Control-Allow-Origin` +- **Wildcard with credentials** — `*` origin combined with `credentials: include` +- **Credentials not allowed** — cookies sent but server denies credentials + +### Token and Session Rules + +- **Missing interaction token** — node transition without `interactionToken` +- **Session not found** — session expired or missing on server + +### Flow Config Rules + +- **Node error** — DaVinci node returned error/failure status +- **Connector error** — DaVinci connector HTTP error +- **Policy not found** — flow policy ID does not exist + +### OIDC Rules + +- **State mismatch** — state parameter differs between request and callback +- **Missing PKCE** — authorization request without PKCE challenge +- **Missing PKCE verifier** — token request without `code_verifier` +- **Nonce missing** — missing nonce when `openid` scope is requested +- **Redirect URI mismatch** — redirect URI not registered at the authorization server +- **Implicit flow detected** — `response_type=token` (discouraged) +- **Expired authorization code** — code reuse detected (single-use violation) + +### DPoP Rules + +- **Invalid structure** — DPoP proof JWT missing required claims (`htm`, `htu`, `iat`, `jti`) +- **Method mismatch** — `htm` claim does not match HTTP method +- **URI mismatch** — `htu` claim does not match request URL +- **Nonce required** — server requires DPoP nonce but none provided +- **Missing proof** — token endpoint request without DPoP header + +### PAR Rules + +- **Missing request_uri** — PAR response missing `request_uri` +- **Inline params with request_uri** — both `request_uri` and inline parameters present (conflict) + +Each diagnosis entry includes a severity level, a human-readable title and description, and numbered remediation steps. + +## Import and Export + +### Export + +Click the export button in the toolbar to save the current flow. Two formats are available: + +- **JSON** — full `FlowExport` object with automatic sensitive data redaction (tokens, passwords, credentials, cookies are replaced with `` placeholders) +- **Markdown** — human-readable report including a diagnosis summary + +### Import + +Click the import button and paste a previously exported JSON string to load a saved flow. + +## Snapshots + +Save up to 5 flow snapshots to local storage for later comparison. Use the snapshot toolbar to save, load, and delete snapshots. + +## Theme + +The extension supports light and dark mode via the theme toggle in the toolbar. The preference is persisted and applies immediately. + ## Troubleshooting If the OIDC DevTools tab does not appear: 1. Make sure the extension is enabled in your browser's extension manager -2. Verify that the inspected page includes the `@wolfcola/devtools-bridge` package -3. Close and reopen DevTools — the panel registers on DevTools initialization -4. Check the browser console for errors from the extension background script +2. Close and reopen DevTools — the panel registers on DevTools initialization +3. Check the browser console for errors from the extension background script + +If no events appear: + +1. Navigate to a page that performs OIDC authentication +2. The extension detects auth traffic automatically via network observation +3. For richer SDK events, add the `@wolfcola/devtools-bridge` package to your app diff --git a/apps/docs/content/docs/getting-started.md b/apps/docs/content/docs/getting-started.md index 9f5aead..1833023 100644 --- a/apps/docs/content/docs/getting-started.md +++ b/apps/docs/content/docs/getting-started.md @@ -9,6 +9,28 @@ order: 1 Install the wolfcola devtools packages you need. +## OIDC DevTools + +### Browser Extension (No SDK Required) + +Install the browser extension from the [Chrome Web Store](https://chrome.google.com/webstore) or [Firefox Add-ons](https://addons.mozilla.org). The extension uses **network-first detection** to automatically identify and annotate OIDC traffic without any code changes to your app. + +Network-first detection works by matching URLs against common auth endpoint patterns and parsing `.well-known/openid-configuration` responses. No SDK integration is needed for basic flow visibility. + +### Bridge SDK (Optional, Richer Events) + +For deeper visibility into SDK state (node transitions, session diffs, config data), install the bridge: + +```bash +npm install @wolfcola/devtools-bridge +``` + +The bridge provides adapters for Ping Identity SDKs: DaVinci (`@forgerock/davinci-client`), Journey, and OIDC (`@forgerock/oidc-client`). See the integration guides for setup details. + +### VS Code Extension + +Install the VS Code extension for in-editor flow inspection via CDP. See the [VS Code Extension](/docs/vscode-extension) guide. + ## Tree-Shake Verification ```bash @@ -27,15 +49,17 @@ Or point it at a specific package: npx treeshake-check --cwd packages/my-lib ``` -## OIDC DevTools - -Install the bridge SDK to emit events from your OIDC client: +## Dead Export Detection ```bash -npm install @wolfcola/devtools-bridge +npm install -D @wolfcola/dead-export-finder ``` -The bridge provides adapters for Ping Identity SDKs: DaVinci (`@forgerock/davinci-client`), Journey, and OIDC (`@forgerock/oidc-client`). See the integration guides for setup details. +Scan your monorepo for unused exports: + +```bash +npx dead-export-finder +``` ## Next Steps diff --git a/apps/docs/content/docs/vscode-extension.md b/apps/docs/content/docs/vscode-extension.md index fced252..f94b294 100644 --- a/apps/docs/content/docs/vscode-extension.md +++ b/apps/docs/content/docs/vscode-extension.md @@ -7,7 +7,7 @@ order: 3 # VS Code Extension -The wolfcola DevTools VS Code extension brings OIDC flow inspection directly into your editor. It connects to a running browser via the Chrome DevTools Protocol (CDP) and streams `AuthEvent` data into a VS Code panel. +The wolfcola DevTools VS Code extension brings OIDC flow inspection directly into your editor. It connects to a running browser via the Chrome DevTools Protocol (CDP) and streams auth events into VS Code. ## Installation @@ -24,9 +24,9 @@ Alternatively, install from the command line: code --install-extension ryanbasmajian.oidc-devtools ``` -## CDP WebSocket Connection +## CDP Connection -The extension requires a WebSocket connection to a browser running with remote debugging enabled. +The extension requires a WebSocket connection to a Chromium-based browser running with remote debugging enabled. ### Starting Chrome with CDP @@ -50,37 +50,87 @@ Open VS Code settings and set the CDP endpoint: } ``` -The extension will auto-discover available pages and connect to the first one that has the `@wolfcola/devtools-bridge` SDK active. +The extension auto-discovers available page targets and connects to the first one with auth-related activity. + +The CDP connection requires the browser to be started with the `--remote-debugging-port` flag. Without it, the extension cannot connect. ## Features -### Live Event Stream +### Live Network Capture -The extension sidebar shows a live feed of `AuthEvent` objects as they are emitted. Events are color-coded by type and can be expanded to view the full JSON payload. +When a capture session is active, the extension uses the CDP `Network` domain to intercept HTTP traffic. Auth-related requests are identified using the same network observer and OIDC annotation pipeline as the browser extension — URL pattern matching, well-known discovery, DPoP detection, and PAR detection all work identically. -### Flow State Visualization +### SDK Event Injection -A webview panel renders the current `FlowState` as an interactive diagram, similar to the browser extension's Flow view. You can pan, zoom, and click nodes to inspect their data. +If the inspected page includes `@wolfcola/devtools-bridge`, the extension captures bridge events via CDP script injection. This provides SDK node state, session diffs, and config data without needing the browser extension installed. -### CodeLens Integration +### Timeline Tree View -When the extension detects that your workspace contains `@wolfcola/devtools-bridge` import statements, it adds CodeLens annotations above bridge attachment calls (e.g. `attachDaVinciBridge()`) showing the connection status and last event received. +The sidebar shows a native VS Code tree view of captured events. Each item displays: -### Diagnostics +- Status icon (success, error, in-progress) +- OIDC phase badge +- Duration -The extension reports issues as VS Code diagnostics: +Click an event to reveal details in the Flow webview or to select it for inspection. -- Missing or misconfigured bridge initialization -- Schema validation failures on captured events -- Connection drops or CDP endpoint issues +### Flow Webview Panel -The CDP connection requires the browser to be started with the `--remote-debugging-port` flag. Without it, the extension cannot connect. +A webview panel renders the same Elm-based flow visualization as the browser extension, adapted to follow the active VS Code color theme. The panel receives real-time event updates during an active capture session. + +### Diagnosis + +The extension runs the same diagnosis engine as the browser extension. Issues are detected automatically when events are processed — CORS problems, missing PKCE, expired tokens, DPoP validation failures, and more. + +### Status Bar + +A status bar item at the bottom of the VS Code window shows: + +- Connection state (disconnected, connecting, connected) +- Live event count during an active capture + +### Export + +Export the captured flow as a new VS Code document in either format: + +- **JSON** — full flow data with automatic sensitive data redaction +- **Markdown** — human-readable report with diagnosis summary ## Commands -The extension contributes the following commands to the Command Palette: +The extension contributes the following commands to the Command Palette (Ctrl+Shift+P / Cmd+Shift+P): + +| Command | Description | +| -------------------------------- | ------------------------------------------------------------ | +| **OIDC DevTools: Start Capture** | Connect to the CDP endpoint and begin capturing auth traffic | +| **OIDC DevTools: Stop Capture** | Disconnect and stop the capture session | +| **OIDC DevTools: Clear Events** | Clear the timeline and event store | +| **OIDC DevTools: Export Flow** | Export the current flow as JSON or Markdown | +| **OIDC DevTools: Select Event** | Reveal the flow panel and highlight a specific event | + +## Debug Configuration + +The extension registers an `oidc-devtools` debug configuration type, allowing you to add capture sessions to your `launch.json`: + +```json +{ + "type": "oidc-devtools", + "request": "attach", + "name": "Capture OIDC Flow", + "port": 9222 +} +``` + +## Troubleshooting + +### Extension cannot connect + +- Verify the browser was started with `--remote-debugging-port=9222` +- Check that no other process is using port 9222 +- Try navigating to `http://localhost:9222/json` in a browser to verify CDP is responding + +### No events captured -- **OIDC DevTools: Connect** — Connect to the configured CDP endpoint -- **OIDC DevTools: Disconnect** — Close the CDP connection -- **OIDC DevTools: Show Flow** — Open the flow visualization panel -- **OIDC DevTools: Clear Events** — Clear the event stream +- Make sure the inspected page performs OIDC authentication +- Check the Output panel (View > Output) and select "OIDC DevTools" for diagnostic logs +- Verify the page is not using a service worker that intercepts network requests before CDP can observe them diff --git a/apps/docs/content/packages/dead-export-finder.md b/apps/docs/content/packages/dead-export-finder.md new file mode 100644 index 0000000..6432058 --- /dev/null +++ b/apps/docs/content/packages/dead-export-finder.md @@ -0,0 +1,71 @@ +--- +title: '@wolfcola/dead-export-finder' +description: 'CLI to find unused exports across monorepo package boundaries' +section: packages +order: 5 +--- + +# @wolfcola/dead-export-finder + +A CLI tool that scans a monorepo to find exports that are never imported by any other package. Useful for identifying dead code that can be safely removed. + +## Installation + +```bash +npm install -D @wolfcola/dead-export-finder +``` + +## CLI Usage + +```bash +npx dead-export-finder [options] +``` + +Run from the monorepo root. The tool auto-detects workspace packages from `pnpm-workspace.yaml` or `package.json` workspaces. + +### Options + +| Option | Alias | Description | +| ------------ | ----- | --------------------------------------------------- | +| `--packages` | `-p` | Scope analysis to specific packages (repeatable) | +| `--ignore` | `-i` | Glob patterns to exclude from scanning (repeatable) | +| `--verbose` | `-v` | Print timing information and parse warnings | + +### Examples + +```bash +# Scan all packages in the monorepo +npx dead-export-finder + +# Scope to specific packages +npx dead-export-finder -p @wolfcola/devtools-core -p @wolfcola/devtools-types + +# Ignore test files +npx dead-export-finder -i "**/*.test.ts" -i "**/*.spec.ts" + +# Verbose output with timing +npx dead-export-finder --verbose +``` + +## How It Works + +1. Detects the monorepo workspace layout +2. Scans all TypeScript and JavaScript files in each package +3. Parses exported symbols from each file using `oxc-parser` +4. Parses imported symbols from each file +5. Builds an export dependency graph across package boundaries +6. Reports exports that are not imported anywhere + +The tool handles parse errors gracefully, emitting warnings instead of failing. The exit code is 1 if any dead exports are found, making it suitable for CI gates. + +## CI Integration + +```json +{ + "scripts": { + "check:dead-exports": "dead-export-finder" + } +} +``` + +This tool analyzes cross-package imports only. Exports used within the same package are not flagged. diff --git a/apps/docs/content/packages/devtools-bridge.md b/apps/docs/content/packages/devtools-bridge.md index 860daea..21d5fb8 100644 --- a/apps/docs/content/packages/devtools-bridge.md +++ b/apps/docs/content/packages/devtools-bridge.md @@ -33,21 +33,19 @@ handle.detach(); ## Bridge Functions -All bridge functions share the same signature pattern: +All bridge functions return a `BridgeHandle` with a single `detach()` method. When called outside a browser environment (SSR), they return a no-op handle. Events are only dispatched when `window.__PING_DEVTOOLS_EXTENSION__` is present (the extension sets this marker). + +### `attachDaVinciBridge(client, config?, devtoolsOptions?)` ```typescript -function attachXxxBridge( +function attachDaVinciBridge( client: Subscribable, config?: object, devtoolsOptions?: DevtoolsOptions, ): BridgeHandle; ``` -They return a `BridgeHandle` with a single `detach()` method. When called outside a browser environment (SSR), they return a no-op handle. - -### `attachDaVinciBridge(client, config?, devtoolsOptions?)` - -Attaches to a DaVinci `Subscribable` client. The client must expose `subscribe(listener)` and `getNode()` methods. On each subscription callback the bridge: +Attaches to a DaVinci client. The client must implement the `Subscribable` interface with `subscribe(listener)` and `getNode()` methods. On each subscription callback the bridge: 1. Decodes the node using an internal `DaVinciNodeSchema` (via `Schema.decodeUnknownOption`) 2. Skips if the node status has not changed from the previous emission @@ -59,7 +57,15 @@ The bridge only emits events when `window.__PING_DEVTOOLS_EXTENSION__` is presen ### `attachJourneyBridge(client, config?, devtoolsOptions?)` -Attaches to a Journey `Subscribable` client that exposes `subscribe(listener)` and `getState()`. Monitors RTK Query state at `journeyReducer.mutations`. For each fulfilled or rejected mutation entry that has not been emitted yet: +```typescript +function attachJourneyBridge( + client: JourneySubscribable, + config?: object, + devtoolsOptions?: DevtoolsOptions, +): BridgeHandle; +``` + +Attaches to a Journey client that implements `subscribe(listener)` and `getState()`. Monitors RTK Query state at `journeyReducer.mutations`. For each fulfilled or rejected mutation entry that has not been emitted yet: - **Fulfilled:** Decodes the step payload and maps it to `JourneyData` with `stepType` of `'Step'`, `'LoginSuccess'`, or `'LoginFailure'` based on the presence of `authId`, `successUrl`, or neither - **Rejected:** Emits a `LoginFailure` event with the extracted error message @@ -68,7 +74,15 @@ Emits `sdk:journey-step` events. Automatically trims stale mutation IDs from the ### `attachOidcBridge(client, config?, devtoolsOptions?)` -Attaches to an OIDC `Subscribable` client that exposes `subscribe(listener)` and `getState()`. Monitors RTK Query state at `oidc.mutations`. Maps mutation endpoint names to OIDC phases: +```typescript +function attachOidcBridge( + client: OidcSubscribable, + config?: { clientId?: string } & object, + devtoolsOptions?: DevtoolsOptions, +): BridgeHandle; +``` + +Attaches to an OIDC client that implements `subscribe(listener)` and `getState()`. Monitors RTK Query state at `oidc.mutations`. Maps mutation endpoint names to OIDC phases: | Endpoint | Phase | | ----------------- | ----------- | @@ -81,6 +95,44 @@ Attaches to an OIDC `Subscribable` client that exposes `subscribe(listener)` and Emits `sdk:oidc-state` events with `OidcData` containing `phase`, `status` (`'success'` or `'error'`), `clientId`, and error details when applicable. +## Client Interfaces + +The bridge functions expect clients that implement specific structural interfaces. These are not exported — they are satisfied structurally by the Ping Identity SDKs. + +### `Subscribable` (DaVinci) + +```typescript +interface Subscribable { + subscribe: (listener: () => void) => () => void; + getNode: () => unknown; + cache?: { + getCache: (requestId: string) => unknown; + }; +} +``` + +### `JourneySubscribable` + +```typescript +interface JourneySubscribable { + subscribe: (listener: () => void) => () => void; + getState: () => unknown; +} +``` + +The state must contain `journeyReducer.mutations` with RTK Query mutation entries. + +### `OidcSubscribable` + +```typescript +interface OidcSubscribable { + subscribe: (listener: () => void) => () => void; + getState: () => unknown; +} +``` + +The state must contain `oidc.mutations` with RTK Query mutation entries. + ## Event Emission ### `emitAuthEvent(event, options?)` diff --git a/packages/changeset-sync-manifest/README.md b/packages/changeset-sync-manifest/README.md new file mode 100644 index 0000000..71d64de --- /dev/null +++ b/packages/changeset-sync-manifest/README.md @@ -0,0 +1,35 @@ +# @wolfcola/changeset-sync-manifest + +Copies the `version` field from `package.json` into `manifest.json` in the same directory. Used after `changeset version` to keep the browser extension manifest version in sync with the npm package version. + +## Usage + +```bash +sync-manifest +``` + +Where `` is the package directory containing both `package.json` and `manifest.json`. + +### Example + +```bash +sync-manifest packages/devtools-extension +``` + +Reads `packages/devtools-extension/package.json`, extracts the `version` field, and writes it into `packages/devtools-extension/manifest.json`. + +## Integration + +Typically wired into the changeset version workflow: + +```json +{ + "scripts": { + "version": "changeset version && sync-manifest packages/devtools-extension" + } +} +``` + +## License + +MIT diff --git a/packages/dead-export-finder/README.md b/packages/dead-export-finder/README.md new file mode 100644 index 0000000..731446f --- /dev/null +++ b/packages/dead-export-finder/README.md @@ -0,0 +1,103 @@ +# @wolfcola/dead-export-finder + +Find unused exports across monorepo package boundaries. Scans all workspace packages, parses exports and imports with [oxc-parser](https://oxc.rs/), and reports exports that are never imported by any other package. + +## Installation + +```bash +npm install -D @wolfcola/dead-export-finder +``` + +## CLI Usage + +```bash +dead-export-finder [options] +``` + +Run from the monorepo root. The tool auto-detects workspace packages from `pnpm-workspace.yaml` or `package.json` workspaces. + +### Options + +| Option | Alias | Description | +| ------------------- | ----- | ----------------------------------------------------- | +| `--packages ` | `-p` | Scope analysis to specific package names (repeatable) | +| `--ignore ` | `-i` | Glob patterns to exclude from scanning (repeatable) | +| `--verbose` | `-v` | Print timing, file counts, and parse warnings | + +### Examples + +```bash +# Scan all packages +dead-export-finder + +# Scope to specific packages +dead-export-finder -p @wolfcola/devtools-core -p @wolfcola/devtools-types + +# Ignore test files +dead-export-finder -i "**/*.test.ts" -i "**/*.spec.ts" + +# Verbose output +dead-export-finder --verbose +``` + +Exit code is `1` when dead exports are found, `0` when clean. + +## Programmatic API + +All services are exported for use in custom tooling: + +```typescript +import { + WorkspaceDetector, + WorkspaceDetectorLive, + FileScanner, + FileScannerLive, + ExportParser, + ExportParserLive, + ImportParser, + ImportParserLive, + ExportGraph, + ExportGraphLive, + Reporter, + ReporterLive, +} from '@wolfcola/dead-export-finder'; +``` + +Each service follows the `Context.Service` + `Live` layer pattern from Effect. + +### Types + +```typescript +import type { + PackageInfo, + ExportedSymbol, + ImportedSymbol, + DeadExport, + AnalysisResult, +} from '@wolfcola/dead-export-finder'; +``` + +### Errors + +```typescript +import { + WorkspaceNotFoundError, + ParseError, + EntryPointResolutionError, +} from '@wolfcola/dead-export-finder'; +``` + +## How It Works + +1. **Workspace detection** — reads `pnpm-workspace.yaml` or `package.json` workspaces to find all packages +2. **File scanning** — finds all `.ts`, `.tsx`, `.js`, `.jsx` files in each package, respecting `.gitignore` and `--ignore` globs +3. **Export parsing** — uses `oxc-parser` to extract all exported symbols from each file +4. **Import parsing** — uses `oxc-parser` to extract all imported symbols from each file +5. **Graph analysis** — builds a cross-package dependency graph and identifies exports with zero imports +6. **Reporting** — formats results grouped by package with file paths relative to package root + +Parse errors are handled gracefully as warnings — the tool continues with remaining files. + +## License + +MIT From 456072fa58255e43c6e0d16dd4001ee9fe6ce2e7 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 23:06:25 +0000 Subject: [PATCH 2/2] docs: address review feedback for PR #50 --- apps/docs/app/Route/Architecture.elm | 2 +- apps/docs/content/packages/dead-export-finder.md | 10 +++++----- packages/dead-export-finder/README.md | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/docs/app/Route/Architecture.elm b/apps/docs/app/Route/Architecture.elm index 6b24ad2..9f4f764 100644 --- a/apps/docs/app/Route/Architecture.elm +++ b/apps/docs/app/Route/Architecture.elm @@ -123,7 +123,7 @@ view app _ = [ Html.text "CLI to find unused exports across monorepo package boundaries. Uses oxc-parser for fast AST analysis." ] , Html.dt [] [ Html.text "@wolfcola/changeset-sync-manifest" ] , Html.dd [] - [ Html.text "Syncs package version from changesets to manifest files. Used in the CI release workflow." ] + [ Html.text "Internal CI tool that syncs package version from changesets to manifest files. Not documented on the docs site." ] ] ] } diff --git a/apps/docs/content/packages/dead-export-finder.md b/apps/docs/content/packages/dead-export-finder.md index 6432058..09024d8 100644 --- a/apps/docs/content/packages/dead-export-finder.md +++ b/apps/docs/content/packages/dead-export-finder.md @@ -25,11 +25,11 @@ Run from the monorepo root. The tool auto-detects workspace packages from `pnpm- ### Options -| Option | Alias | Description | -| ------------ | ----- | --------------------------------------------------- | -| `--packages` | `-p` | Scope analysis to specific packages (repeatable) | -| `--ignore` | `-i` | Glob patterns to exclude from scanning (repeatable) | -| `--verbose` | `-v` | Print timing information and parse warnings | +| Option | Alias | Description | +| ------------------- | ----- | --------------------------------------------------- | +| `--packages ` | `-p` | Scope analysis to specific packages (repeatable) | +| `--ignore` | `-i` | Glob patterns to exclude from scanning (repeatable) | +| `--verbose` | `-v` | Print timing, file counts, and parse warnings | ### Examples diff --git a/packages/dead-export-finder/README.md b/packages/dead-export-finder/README.md index 731446f..3c6551a 100644 --- a/packages/dead-export-finder/README.md +++ b/packages/dead-export-finder/README.md @@ -74,6 +74,7 @@ import type { ImportedSymbol, DeadExport, AnalysisResult, + WorkspaceResult, } from '@wolfcola/dead-export-finder'; ```