···3333 - [Available commands](#available-commands)
3434 - [Project structure](#project-structure)
3535 - [Local connector CLI](#local-connector-cli)
3636+ - [Mock connector (for local development)](#mock-connector-for-local-development)
3637- [Code style](#code-style)
3738 - [TypeScript](#typescript)
3839 - [Server API patterns](#server-api-patterns)
···104105pnpm build # Production build
105106pnpm preview # Preview production build
106107108108+# Connector
109109+pnpm npmx-connector # Start the real connector (requires npm login)
110110+pnpm mock-connector # Start the mock connector (no npm login needed)
111111+107112# Code Quality
108113pnpm lint # Run linter (oxlint + oxfmt)
109114pnpm lint:fix # Auto-fix lint issues
···156161```
157162158163The connector will check your npm authentication, generate a connection token, and listen for requests from npmx.dev.
164164+165165+### Mock connector (for local development)
166166+167167+If you're working on admin features (org management, package access controls, operations queue) and don't want to use your real npm account, you can run the mock connector instead:
168168+169169+```bash
170170+pnpm mock-connector
171171+```
172172+173173+This starts a mock connector server pre-populated with sample data (orgs, teams, members, packages). No npm login is required — operations succeed immediately without making real npm CLI calls.
174174+175175+The mock connector prints a connection URL to the terminal, just like the real connector. Click it (or paste the token manually) to connect the UI.
176176+177177+**Options:**
178178+179179+```bash
180180+pnpm mock-connector # default: port 31415, user "mock-user", sample data
181181+pnpm mock-connector --port 9999 # custom port
182182+pnpm mock-connector --user alice # custom username
183183+pnpm mock-connector --empty # start with no pre-populated data
184184+```
185185+186186+**Default sample data:**
187187+188188+- **@nuxt**: 4 members (mock-user, danielroe, pi0, antfu), 3 teams (core, docs, triage)
189189+- **@unjs**: 2 members (mock-user, pi0), 1 team (maintainers)
190190+- **Packages**: @nuxt/kit, @nuxt/schema, @unjs/nitro with team-based access controls
191191+192192+> [!TIP]
193193+> Run `pnpm dev` in a separate terminal to start the Nuxt dev server, then click the connection URL from the mock connector to connect.
159194160195## Code style
161196···7517867527871. Add a fixture file for that package/endpoint
7537882. Update the mock handlers in `test/fixtures/mock-routes.cjs` (client) or `modules/runtime/server/cache.ts` (server)
789789+790790+### Testing connector features
791791+792792+Features that require authentication through the local connector (org management, package collaborators, operations queue) are tested using a mock connector server.
793793+794794+#### Architecture
795795+796796+The mock connector infrastructure is shared between the CLI, E2E tests, and Vitest component tests:
797797+798798+```
799799+cli/src/
800800+├── types.ts # ConnectorEndpoints contract (shared by real + mock)
801801+├── mock-state.ts # MockConnectorStateManager (canonical source)
802802+├── mock-app.ts # H3 mock app + MockConnectorServer class
803803+└── mock-server.ts # CLI entry point (pnpm mock-connector)
804804+805805+test/test-utils/ # Re-exports from cli/src/ for test convenience
806806+test/e2e/helpers/ # E2E-specific wrappers (fixtures, global setup)
807807+```
808808+809809+Both the real server (`cli/src/server.ts`) and the mock server (`cli/src/mock-app.ts`) conform to the `ConnectorEndpoints` interface defined in `cli/src/types.ts`. This ensures the API contract is enforced by TypeScript. When adding a new endpoint, update `ConnectorEndpoints` first, then implement it in both servers.
810810+811811+#### Vitest component tests (`test/nuxt/`)
812812+813813+- Mock the `useConnector` composable with reactive state
814814+- Use `document.body` queries for components using Teleport
815815+- See `test/nuxt/components/HeaderConnectorModal.spec.ts` for an example
816816+817817+```typescript
818818+// Create mock state
819819+const mockState = ref({ connected: false, npmUser: null, ... })
820820+821821+// Mock the composable
822822+vi.mock('~/composables/useConnector', () => ({
823823+ useConnector: () => ({
824824+ isConnected: computed(() => mockState.value.connected),
825825+ // ... other properties
826826+ }),
827827+}))
828828+```
829829+830830+#### Playwright E2E tests (`test/e2e/`)
831831+832832+- A mock HTTP server starts automatically via Playwright's global setup
833833+- Use the `mockConnector` fixture to set up test data and the `gotoConnected` helper to navigate with authentication
834834+835835+```typescript
836836+test('shows org members', async ({ page, gotoConnected, mockConnector }) => {
837837+ // Set up test data
838838+ await mockConnector.setOrgData('@testorg', {
839839+ users: { testuser: 'owner', member1: 'admin' },
840840+ })
841841+842842+ // Navigate with connector authentication
843843+ await gotoConnected('/@testorg')
844844+845845+ // Test assertions
846846+ await expect(page.getByRole('link', { name: '@testuser' })).toBeVisible()
847847+})
848848+```
849849+850850+The mock connector supports test endpoints for state manipulation:
851851+852852+- `/__test__/reset` - Reset all mock state
853853+- `/__test__/org` - Set org users, teams, and team members
854854+- `/__test__/user-orgs` - Set user's organizations
855855+- `/__test__/user-packages` - Set user's packages
856856+- `/__test__/package` - Set package collaborators
754857755858## Submitting changes
756859
+1-1
app/composables/useConnector.ts
···11-import type { PendingOperation, OperationStatus, OperationType } from '../../cli/src/types'
11+import type { PendingOperation, OperationStatus, OperationType } from '#cli/types'
22import { $fetch } from 'ofetch'
3344export interface NewOperation {
···1818 reuseExistingServer: false,
1919 timeout: 60_000,
2020 },
2121+ // Start/stop mock connector server before/after all tests (teardown via returned closure)
2222+ globalSetup: fileURLToPath(new URL('./test/e2e/global-setup.ts', import.meta.url)),
2123 // We currently only test on one browser on one platform
2224 snapshotPathTemplate: '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{ext}',
2325 use: {