-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathportless.ts
More file actions
116 lines (97 loc) · 3.04 KB
/
portless.ts
File metadata and controls
116 lines (97 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { spawnSync } from 'node:child_process'
import { readFile } from 'node:fs/promises'
import { basename, join } from 'node:path'
import process from 'node:process'
import { x } from 'tinyexec'
const DEFAULT_PORTLESS_NAME = 'nuxt-app'
export async function ensurePortlessAvailable(cwd: string) {
try {
await runPortless(cwd, ['--version'])
}
catch (error) {
if (typeof error === 'object' && error && 'code' in error && error.code === 'ENOENT') {
throw new Error('Portless is required for `--portless`. Install it from https://portless.sh')
}
throw createPortlessError('check portless availability', error)
}
}
export async function resolvePortlessURL(cwd: string, name: string) {
try {
await runPortless(cwd, ['proxy', 'start'])
const result = await runPortless(cwd, ['get', '--no-worktree', name])
return result.stdout.trim()
}
catch (error) {
throw createPortlessError('resolve the portless URL', error)
}
}
export async function registerPortlessAlias(cwd: string, name: string, port: number) {
try {
await runPortless(cwd, ['alias', name, `${port}`])
}
catch (error) {
throw createPortlessError(`register the portless alias for port ${port}`, error)
}
}
export async function removePortlessAlias(cwd: string, name: string) {
try {
await runPortless(cwd, ['alias', '--remove', name])
}
catch (error) {
throw createPortlessError(`remove the portless alias for ${name}`, error)
}
}
export function registerPortlessExitCleanup(cwd: string, name: string) {
let disposed = false
const cleanup = () => {
if (disposed) {
return
}
disposed = true
process.off('exit', cleanup)
runPortlessSync(cwd, ['alias', '--remove', name])
}
process.on('exit', cleanup)
return () => {
disposed = true
process.off('exit', cleanup)
}
}
function createPortlessError(action: string, error: unknown) {
const message = typeof error === 'object' && error && 'stderr' in error && typeof error.stderr === 'string' && error.stderr.trim()
? error.stderr.trim()
: error instanceof Error && error.message
? error.message
: 'Unknown portless error'
return new Error(`Failed to ${action}: ${message}`)
}
export async function resolvePortlessName(cwd: string) {
const packageName = await readFile(join(cwd, 'package.json'), 'utf8')
.then(contents => JSON.parse(contents))
.then(pkg => typeof pkg.name === 'string' ? pkg.name : undefined)
.catch(() => undefined)
return normalizePortlessName(packageName || basename(cwd))
}
function normalizePortlessName(value: string) {
const normalizedValue = value
.toLowerCase()
.replace(/[^a-z0-9-]+/g, '-')
.replace(/-+/g, '-')
.replace(/^-+|-+$/g, '')
return normalizedValue || DEFAULT_PORTLESS_NAME
}
function runPortless(cwd: string, args: string[]) {
return x('portless', args, {
throwOnError: true,
nodeOptions: {
cwd,
stdio: 'pipe',
},
})
}
function runPortlessSync(cwd: string, args: string[]) {
spawnSync('portless', args, {
cwd,
stdio: 'ignore',
})
}