forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1import './node-pty.d.ts'
2
3export interface ConnectorConfig {
4 port: number
5 host: string
6}
7
8export interface ConnectorSession {
9 token: string
10 connectedAt: number
11 npmUser: string | null
12 /** Base64 data URL of the user's avatar */
13 avatar: string | null
14}
15
16export type OperationType =
17 | 'org:add-user'
18 | 'org:rm-user'
19 | 'org:set-role'
20 | 'team:create'
21 | 'team:destroy'
22 | 'team:add-user'
23 | 'team:rm-user'
24 | 'access:grant'
25 | 'access:revoke'
26 | 'owner:add'
27 | 'owner:rm'
28 | 'package:init'
29
30export type OperationStatus =
31 | 'pending'
32 | 'approved'
33 | 'running'
34 | 'completed'
35 | 'failed'
36 | 'cancelled'
37
38export interface OperationResult {
39 stdout: string
40 stderr: string
41 exitCode: number
42 /** True if the operation failed due to missing/invalid OTP */
43 requiresOtp?: boolean
44 /** True if the operation failed due to authentication failure (not logged in or token expired) */
45 authFailure?: boolean
46 /** URLs detected in the command output (stdout + stderr) */
47 urls?: string[]
48}
49
50export interface PendingOperation {
51 id: string
52 type: OperationType
53 params: Record<string, string>
54 description: string
55 command: string
56 status: OperationStatus
57 createdAt: number
58 result?: OperationResult
59 /** ID of operation this depends on (must complete successfully first) */
60 dependsOn?: string
61 /** Auth URL detected during interactive execution (set while operation is still running) */
62 authUrl?: string
63}
64
65export interface ConnectorState {
66 session: ConnectorSession
67 operations: PendingOperation[]
68}
69
70export interface ApiResponse<T = unknown> {
71 success: boolean
72 data?: T
73 error?: string
74}
75
76// -- Connector API contract (shared by real + mock server) -------------------
77
78export type OrgRole = 'developer' | 'admin' | 'owner'
79
80export type AccessPermission = 'read-only' | 'read-write'
81
82/** POST /connect response data */
83export interface ConnectResponseData {
84 npmUser: string | null
85 avatar: string | null
86 connectedAt: number
87}
88
89/** GET /state response data */
90export interface StateResponseData {
91 npmUser: string | null
92 avatar: string | null
93 operations: PendingOperation[]
94}
95
96/** POST /execute response data */
97export interface ExecuteResponseData {
98 results: Array<{ id: string; result: OperationResult }>
99 otpRequired?: boolean
100 authFailure?: boolean
101 urls?: string[]
102}
103
104/** POST /approve-all response data */
105export interface ApproveAllResponseData {
106 approved: number
107}
108
109/** DELETE /operations/all response data */
110export interface ClearOperationsResponseData {
111 removed: number
112}
113
114/** Request body for POST /operations */
115export interface CreateOperationBody {
116 type: OperationType
117 params: Record<string, string>
118 description: string
119 command: string
120 dependsOn?: string
121}
122
123/**
124 * Connector API endpoint contract. Both server.ts and mock-app.ts must
125 * conform to these shapes, enforced via `satisfies` and `AssertEndpointsImplemented`.
126 */
127export interface ConnectorEndpoints {
128 'POST /connect': { body: { token: string }; data: ConnectResponseData }
129 'GET /state': { body: never; data: StateResponseData }
130 'POST /operations': { body: CreateOperationBody; data: PendingOperation }
131 'POST /operations/batch': { body: CreateOperationBody[]; data: PendingOperation[] }
132 'DELETE /operations': { body: never; data: void }
133 'DELETE /operations/all': { body: never; data: ClearOperationsResponseData }
134 'POST /approve': { body: never; data: PendingOperation }
135 'POST /approve-all': { body: never; data: ApproveAllResponseData }
136 'POST /retry': { body: never; data: PendingOperation }
137 'POST /execute': {
138 body: { otp?: string; interactive?: boolean; openUrls?: boolean }
139 data: ExecuteResponseData
140 }
141 'GET /org/:org/users': { body: never; data: Record<string, OrgRole> }
142 'GET /org/:org/teams': { body: never; data: string[] }
143 'GET /team/:scopeTeam/users': { body: never; data: string[] }
144 'GET /package/:pkg/collaborators': { body: never; data: Record<string, AccessPermission> }
145 'GET /user/packages': { body: never; data: Record<string, AccessPermission> }
146 'GET /user/orgs': { body: never; data: string[] }
147}
148
149/** Compile-time check that a server implements exactly the ConnectorEndpoints keys. */
150type IsExact<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false
151export type AssertEndpointsImplemented<Implemented extends string> =
152 IsExact<Implemented, keyof ConnectorEndpoints> extends true
153 ? true
154 : {
155 error: 'Endpoint mismatch'
156 missing: Exclude<keyof ConnectorEndpoints, Implemented>
157 extra: Exclude<Implemented, keyof ConnectorEndpoints>
158 }