[READ-ONLY] a fast, modern browser for the npm registry
at main 113 lines 2.9 kB view raw
1#!/usr/bin/env node 2import process from 'node:process' 3import { spawn } from 'node:child_process' 4import { styleText } from 'node:util' 5import * as p from '@clack/prompts' 6import { defineCommand, runMain } from 'citty' 7import { serve } from 'srvx' 8import { createConnectorApp, generateToken, CONNECTOR_VERSION } from './server.ts' 9import { getNpmUser } from './npm-client.ts' 10import { initLogger, showToken, logInfo, logWarning, logError } from './logger.ts' 11 12const DEFAULT_PORT = 31415 13const DEFAULT_FRONTEND_URL = 'https://npmx.dev/' 14const DEV_FRONTEND_URL = 'http://127.0.0.1:3000/' 15 16async function runNpmLogin(): Promise<boolean> { 17 return new Promise(resolve => { 18 const child = spawn('npm', ['login'], { 19 stdio: 'inherit', 20 shell: true, 21 }) 22 23 child.on('close', code => { 24 resolve(code === 0) 25 }) 26 27 child.on('error', () => { 28 resolve(false) 29 }) 30 }) 31} 32 33const main = defineCommand({ 34 meta: { 35 name: 'npmx-connector', 36 version: CONNECTOR_VERSION, 37 description: 'Local connector for npmx.dev', 38 }, 39 args: { 40 port: { 41 type: 'string', 42 description: 'Port to listen on', 43 default: String(DEFAULT_PORT), 44 }, 45 }, 46 async run({ args }) { 47 const port = Number.parseInt(args.port as string, 10) || DEFAULT_PORT 48 const frontendUrl = 49 process.env.NPMX_CLI_DEV === 'true' ? DEV_FRONTEND_URL : DEFAULT_FRONTEND_URL 50 51 initLogger() 52 53 // Warning message and accept prompt 54 logWarning( 55 `This allows ${styleText('underline', 'npmx.dev')} to access your npm cli and any authenticated contexts.`, 56 ) 57 const accept = await p.confirm({ 58 message: 'Do you accept?', 59 initialValue: true, 60 }) 61 62 if (!accept || p.isCancel(accept)) { 63 logError('Connector setup cancelled.') 64 process.exit(0) 65 } 66 67 // Check npm authentication before starting 68 logInfo('Checking npm authentication...') 69 let npmUser = await getNpmUser() 70 71 if (!npmUser) { 72 logWarning('Not logged in to npm. Starting npm login...') 73 // oxlint-disable-next-line no-console -- deliberate spacing 74 console.log() 75 76 const loginSuccess = await runNpmLogin() 77 78 // oxlint-disable-next-line no-console -- deliberate spacing 79 console.log() 80 81 if (!loginSuccess) { 82 logWarning('npm login failed or was cancelled.') 83 process.exit(1) 84 } 85 86 // Check again after login 87 npmUser = await getNpmUser() 88 if (!npmUser) { 89 logWarning('Still not authenticated after login attempt.') 90 process.exit(1) 91 } 92 } 93 94 logInfo(`Authenticated as: ${npmUser}`) 95 96 const token = generateToken() 97 showToken(token, port, frontendUrl) 98 99 const app = createConnectorApp(token) 100 101 const server = serve({ 102 port, 103 hostname: '127.0.0.1', 104 fetch: app.fetch, 105 }) 106 107 await server.ready() 108 109 logInfo('Waiting for connection... (Press Ctrl+C to stop)') 110 }, 111}) 112 113runMain(main)