launchpd 1.0.3 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +61 -39
- package/bin/cli.js +149 -124
- package/bin/setup.js +42 -40
- package/package.json +4 -4
- package/src/commands/auth.js +516 -522
- package/src/commands/deploy.js +745 -386
- package/src/commands/index.js +14 -7
- package/src/commands/init.js +95 -72
- package/src/commands/list.js +120 -122
- package/src/commands/rollback.js +139 -102
- package/src/commands/status.js +75 -51
- package/src/commands/versions.js +153 -113
- package/src/config.js +32 -31
- package/src/utils/api.js +220 -195
- package/src/utils/credentials.js +88 -85
- package/src/utils/endpoint.js +58 -0
- package/src/utils/errors.js +79 -69
- package/src/utils/expiration.js +49 -47
- package/src/utils/id.js +5 -5
- package/src/utils/ignore.js +35 -36
- package/src/utils/index.js +10 -11
- package/src/utils/localConfig.js +39 -43
- package/src/utils/logger.js +113 -106
- package/src/utils/machineId.js +15 -19
- package/src/utils/metadata.js +113 -87
- package/src/utils/projectConfig.js +48 -45
- package/src/utils/prompt.js +91 -82
- package/src/utils/quota.js +261 -225
- package/src/utils/remoteSource.js +680 -0
- package/src/utils/upload.js +197 -127
- package/src/utils/validator.js +116 -68
package/src/utils/ignore.js
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
* Shared ignore lists for Launchpd CLI
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
// Directories to ignore during scanning, validation, and upload
|
|
7
6
|
export const IGNORE_DIRECTORIES = new Set([
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
])
|
|
7
|
+
'node_modules',
|
|
8
|
+
'.git',
|
|
9
|
+
'.svn',
|
|
10
|
+
'.hg',
|
|
11
|
+
'vendor',
|
|
12
|
+
'composer',
|
|
13
|
+
'.env',
|
|
14
|
+
'.env.local',
|
|
15
|
+
'.env.production',
|
|
16
|
+
'.env.development',
|
|
17
|
+
'dist',
|
|
18
|
+
'build',
|
|
19
|
+
'.next',
|
|
20
|
+
'.nuxt',
|
|
21
|
+
'.svelte-kit',
|
|
22
|
+
'coverage',
|
|
23
|
+
'.cache'
|
|
24
|
+
])
|
|
26
25
|
|
|
27
26
|
// Files to ignore during scanning, validation, and upload
|
|
28
27
|
export const IGNORE_FILES = new Set([
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
])
|
|
28
|
+
'.launchpd.json',
|
|
29
|
+
'package-lock.json',
|
|
30
|
+
'yarn.lock',
|
|
31
|
+
'pnpm-lock.yaml',
|
|
32
|
+
'.DS_Store',
|
|
33
|
+
'Thumbs.db',
|
|
34
|
+
'desktop.ini',
|
|
35
|
+
'.gitignore',
|
|
36
|
+
'.npmignore',
|
|
37
|
+
'README.md',
|
|
38
|
+
'LICENSE'
|
|
39
|
+
])
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
42
|
* Check if a path or filename should be ignored
|
|
@@ -45,9 +44,9 @@ export const IGNORE_FILES = new Set([
|
|
|
45
44
|
* @param {boolean} isDir - Whether the path is a directory
|
|
46
45
|
* @returns {boolean}
|
|
47
46
|
*/
|
|
48
|
-
export function isIgnored(name, isDir = false) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
export function isIgnored (name, isDir = false) {
|
|
48
|
+
if (isDir) {
|
|
49
|
+
return IGNORE_DIRECTORIES.has(name)
|
|
50
|
+
}
|
|
51
|
+
return IGNORE_FILES.has(name) || IGNORE_DIRECTORIES.has(name)
|
|
53
52
|
}
|
package/src/utils/index.js
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
* Utils index - exports all utility functions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './
|
|
7
|
-
export * from './
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
11
|
-
export * from './
|
|
12
|
-
export * from './
|
|
13
|
-
export * from './
|
|
14
|
-
export * from './
|
|
15
|
-
export * from './upload.js';
|
|
5
|
+
export * from './credentials.js'
|
|
6
|
+
export * from './errors.js'
|
|
7
|
+
export * from './expiration.js'
|
|
8
|
+
export * from './id.js'
|
|
9
|
+
export * from './localConfig.js'
|
|
10
|
+
export * from './logger.js'
|
|
11
|
+
export * from './metadata.js'
|
|
12
|
+
export * from './quota.js'
|
|
13
|
+
export * from './prompt.js'
|
|
14
|
+
export * from './upload.js'
|
package/src/utils/localConfig.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import fsp from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import os from 'node:os'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Get the local config directory path
|
|
8
8
|
* ~/.staticlaunch/ on Unix, %USERPROFILE%\.staticlaunch\ on Windows
|
|
9
9
|
*/
|
|
10
|
-
function getConfigDir() {
|
|
11
|
-
|
|
10
|
+
function getConfigDir () {
|
|
11
|
+
return path.join(os.homedir(), '.staticlaunch')
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Get the local deployments file path
|
|
16
16
|
*/
|
|
17
|
-
function getDeploymentsPath() {
|
|
18
|
-
|
|
17
|
+
function getDeploymentsPath () {
|
|
18
|
+
return path.join(getConfigDir(), 'deployments.json')
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Ensure config directory exists
|
|
23
23
|
*/
|
|
24
|
-
async function ensureConfigDir() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
async function ensureConfigDir () {
|
|
25
|
+
const dir = getConfigDir()
|
|
26
|
+
if (!fs.existsSync(dir)) {
|
|
27
|
+
await fsp.mkdir(dir, { recursive: true })
|
|
28
|
+
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Get local deployments data
|
|
33
33
|
* @returns {Promise<{version: number, deployments: Array}>}
|
|
34
34
|
*/
|
|
35
|
-
async function getLocalData() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
35
|
+
async function getLocalData () {
|
|
36
|
+
const filePath = getDeploymentsPath()
|
|
37
|
+
if (!fs.existsSync(filePath)) {
|
|
38
|
+
return { version: 1, deployments: [] }
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const text = await fsp.readFile(filePath, 'utf-8')
|
|
42
|
+
return JSON.parse(text)
|
|
43
|
+
} catch {
|
|
44
|
+
return { version: 1, deployments: [] }
|
|
45
|
+
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -50,36 +50,32 @@ async function getLocalData() {
|
|
|
50
50
|
* This provides quick access to user's own deployments without R2 read
|
|
51
51
|
* @param {object} deployment - Deployment record
|
|
52
52
|
*/
|
|
53
|
-
export async function saveLocalDeployment(deployment) {
|
|
54
|
-
|
|
53
|
+
export async function saveLocalDeployment (deployment) {
|
|
54
|
+
await ensureConfigDir()
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
const data = await getLocalData()
|
|
57
|
+
data.deployments.push(deployment)
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
'utf-8'
|
|
63
|
-
);
|
|
59
|
+
const filePath = getDeploymentsPath()
|
|
60
|
+
const content = JSON.stringify(data, null, 2)
|
|
61
|
+
await fsp.writeFile(filePath, content, 'utf-8')
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
/**
|
|
67
65
|
* Get all local deployments (user's own deployments from this machine)
|
|
68
66
|
* @returns {Promise<Array>} Array of deployment records
|
|
69
67
|
*/
|
|
70
|
-
export async function getLocalDeployments() {
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
export async function getLocalDeployments () {
|
|
69
|
+
const data = await getLocalData()
|
|
70
|
+
return data.deployments
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
/**
|
|
76
74
|
* Clear local deployments history
|
|
77
75
|
*/
|
|
78
|
-
export async function clearLocalDeployments() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
'utf-8'
|
|
84
|
-
);
|
|
76
|
+
export async function clearLocalDeployments () {
|
|
77
|
+
await ensureConfigDir()
|
|
78
|
+
const filePath = getDeploymentsPath()
|
|
79
|
+
const content = JSON.stringify({ version: 1, deployments: [] }, null, 2)
|
|
80
|
+
await fsp.writeFile(filePath, content, 'utf-8')
|
|
85
81
|
}
|
package/src/utils/logger.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
|
-
import ora from 'ora'
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import ora from 'ora'
|
|
3
3
|
|
|
4
4
|
// Store active spinner reference
|
|
5
|
-
let activeSpinner = null
|
|
5
|
+
let activeSpinner = null
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Log a success message
|
|
9
9
|
* @param {string} message
|
|
10
10
|
*/
|
|
11
|
-
export function success(message) {
|
|
12
|
-
|
|
11
|
+
export function success (message) {
|
|
12
|
+
console.log(chalk.green.bold('✓'), chalk.green(message))
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -19,36 +19,38 @@ export function success(message) {
|
|
|
19
19
|
* @param {boolean} options.verbose - Show verbose error details
|
|
20
20
|
* @param {Error} options.cause - Original error for verbose mode
|
|
21
21
|
*/
|
|
22
|
-
export function error(message, options = {}) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
export function error (message, options = {}) {
|
|
23
|
+
console.error(chalk.red.bold('✗'), chalk.red(message))
|
|
24
|
+
if (options.verbose && options.cause) {
|
|
25
|
+
console.error(chalk.gray(' Stack trace:'))
|
|
26
|
+
console.error(
|
|
27
|
+
chalk.gray(' ' + (options.cause.stack || options.cause.message))
|
|
28
|
+
)
|
|
29
|
+
}
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
33
|
* Log an info message
|
|
32
34
|
* @param {string} message
|
|
33
35
|
*/
|
|
34
|
-
export function info(message) {
|
|
35
|
-
|
|
36
|
+
export function info (message) {
|
|
37
|
+
console.log(chalk.blue('ℹ'), chalk.white(message))
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* Log a warning message
|
|
40
42
|
* @param {string} message
|
|
41
43
|
*/
|
|
42
|
-
export function warning(message) {
|
|
43
|
-
|
|
44
|
+
export function warning (message) {
|
|
45
|
+
console.log(chalk.yellow.bold('⚠'), chalk.yellow(message))
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* Log a plain message
|
|
48
50
|
* @param {string} message
|
|
49
51
|
*/
|
|
50
|
-
export function log(message = '') {
|
|
51
|
-
|
|
52
|
+
export function log (message = '') {
|
|
53
|
+
console.log(message)
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -56,8 +58,13 @@ export function log(message = '') {
|
|
|
56
58
|
* @param {any} data
|
|
57
59
|
* @param {string} method - console method to use
|
|
58
60
|
*/
|
|
59
|
-
export function raw(data, method = 'log') {
|
|
60
|
-
|
|
61
|
+
export function raw (data, method = 'log') {
|
|
62
|
+
const allowedMethods = ['log', 'warn', 'error', 'info', 'table', 'dir']
|
|
63
|
+
if (allowedMethods.includes(method)) {
|
|
64
|
+
console[method](data)
|
|
65
|
+
} else {
|
|
66
|
+
console.log(data)
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
/**
|
|
@@ -65,78 +72,78 @@ export function raw(data, method = 'log') {
|
|
|
65
72
|
* @param {string} text - Initial spinner text
|
|
66
73
|
* @returns {object} - Spinner instance with helper methods
|
|
67
74
|
*/
|
|
68
|
-
export function spinner(text) {
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
75
|
+
export function spinner (text) {
|
|
76
|
+
activeSpinner = ora({
|
|
77
|
+
text,
|
|
78
|
+
color: 'cyan',
|
|
79
|
+
spinner: 'dots'
|
|
80
|
+
}).start()
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
/**
|
|
84
|
+
* Update spinner text
|
|
85
|
+
* @param {string} newText
|
|
86
|
+
*/
|
|
87
|
+
update (newText) {
|
|
88
|
+
if (activeSpinner) {
|
|
89
|
+
activeSpinner.text = newText
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Mark spinner as successful and stop
|
|
95
|
+
* @param {string} text - Success message
|
|
96
|
+
*/
|
|
97
|
+
succeed (message) {
|
|
98
|
+
if (activeSpinner) {
|
|
99
|
+
activeSpinner.succeed(chalk.green(message))
|
|
100
|
+
activeSpinner = null
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Mark spinner as failed and stop
|
|
106
|
+
* @param {string} text - Failure message
|
|
107
|
+
*/
|
|
108
|
+
fail (message) {
|
|
109
|
+
if (activeSpinner) {
|
|
110
|
+
activeSpinner.fail(chalk.red(message))
|
|
111
|
+
activeSpinner = null
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Stop spinner with info message
|
|
117
|
+
* @param {string} text - Info message
|
|
118
|
+
*/
|
|
119
|
+
info (message) {
|
|
120
|
+
if (activeSpinner) {
|
|
121
|
+
activeSpinner.info(chalk.blue(message))
|
|
122
|
+
activeSpinner = null
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Stop spinner with warning
|
|
128
|
+
* @param {string} text - Warning message
|
|
129
|
+
*/
|
|
130
|
+
warn (message) {
|
|
131
|
+
if (activeSpinner) {
|
|
132
|
+
activeSpinner.warn(chalk.yellow(message))
|
|
133
|
+
activeSpinner = null
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Stop spinner without any symbol
|
|
139
|
+
*/
|
|
140
|
+
stop () {
|
|
141
|
+
if (activeSpinner) {
|
|
142
|
+
activeSpinner.stop()
|
|
143
|
+
activeSpinner = null
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
/**
|
|
@@ -145,14 +152,14 @@ export function spinner(text) {
|
|
|
145
152
|
* @param {number} decimals - Number of decimal places
|
|
146
153
|
* @returns {string} - Formatted size string
|
|
147
154
|
*/
|
|
148
|
-
export function formatSize(bytes, decimals = 2) {
|
|
149
|
-
|
|
155
|
+
export function formatSize (bytes, decimals = 2) {
|
|
156
|
+
if (bytes === 0) return '0 Bytes'
|
|
150
157
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
158
|
+
const k = 1024
|
|
159
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
|
|
160
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
154
161
|
|
|
155
|
-
|
|
162
|
+
return `${Number.parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
/**
|
|
@@ -161,13 +168,13 @@ export function formatSize(bytes, decimals = 2) {
|
|
|
161
168
|
* @param {string[]} suggestions - Array of suggested actions
|
|
162
169
|
* @param {object} options - Error options
|
|
163
170
|
*/
|
|
164
|
-
export function errorWithSuggestions(message, suggestions = [], options = {}) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
export function errorWithSuggestions (message, suggestions = [], options = {}) {
|
|
172
|
+
error(message, options)
|
|
173
|
+
if (suggestions.length > 0) {
|
|
174
|
+
log('')
|
|
175
|
+
log(chalk.yellow('💡 Suggestions:'))
|
|
176
|
+
suggestions.forEach((suggestion) => {
|
|
177
|
+
log(chalk.gray(` • ${suggestion}`))
|
|
178
|
+
})
|
|
179
|
+
}
|
|
173
180
|
}
|
package/src/utils/machineId.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
import { hostname, platform, arch, userInfo } from 'node:os'
|
|
3
|
-
import { warning } from './logger.js'
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto'
|
|
2
|
+
import { hostname, platform, arch, userInfo } from 'node:os'
|
|
3
|
+
import { warning } from './logger.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Generate a unique machine identifier based on system traits.
|
|
@@ -9,21 +9,17 @@ import { warning } from './logger.js';
|
|
|
9
9
|
*
|
|
10
10
|
* @returns {string} Hex string of the machine ID hash
|
|
11
11
|
*/
|
|
12
|
-
export function getMachineId() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
hostname(),
|
|
16
|
-
platform(),
|
|
17
|
-
arch(),
|
|
18
|
-
userInfo().username
|
|
19
|
-
];
|
|
12
|
+
export function getMachineId () {
|
|
13
|
+
try {
|
|
14
|
+
const parts = [hostname(), platform(), arch(), userInfo().username]
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
16
|
+
const rawId = parts.join('|')
|
|
17
|
+
return createHash('sha256').update(rawId).digest('hex')
|
|
18
|
+
} catch (err) {
|
|
19
|
+
// Fallback if userInfo() fails (e.g. restricted environments)
|
|
20
|
+
// Use a random ID for this session, better than crashing
|
|
21
|
+
warning(`Could not generate stable machine ID: ${err.message}`)
|
|
22
|
+
const randomId = randomBytes(16).toString('hex')
|
|
23
|
+
return `unknown-device-${randomId}`
|
|
24
|
+
}
|
|
29
25
|
}
|