@tothalex/nulljs 0.0.48 → 0.0.53
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/package.json +22 -32
- package/src/cli.ts +24 -0
- package/src/commands/config.ts +130 -0
- package/src/commands/deploy.ts +182 -123
- package/src/commands/dev.ts +10 -0
- package/src/commands/host.ts +130 -139
- package/src/commands/index.ts +6 -8
- package/src/commands/secret.ts +364 -56
- package/src/commands/status.ts +41 -0
- package/src/components/DeployAnimation.tsx +92 -0
- package/src/components/DeploymentLogsPane.tsx +79 -0
- package/src/components/Header.tsx +57 -0
- package/src/components/HelpModal.tsx +64 -0
- package/src/components/SystemLogsPane.tsx +78 -0
- package/src/config/index.ts +181 -0
- package/src/lib/bundle/function.ts +125 -0
- package/src/lib/bundle/index.ts +3 -0
- package/src/lib/bundle/react.ts +149 -0
- package/src/lib/deploy.ts +103 -0
- package/src/lib/server.ts +160 -0
- package/src/lib/vite.ts +120 -0
- package/src/lib/watcher.ts +274 -0
- package/src/ui.tsx +363 -0
- package/tsconfig.json +30 -0
- package/scripts/install-server.js +0 -199
- package/src/commands/api.ts +0 -16
- package/src/commands/auth.ts +0 -54
- package/src/commands/create.ts +0 -43
- package/src/commands/dev/function/index.ts +0 -221
- package/src/commands/dev/function/utils.ts +0 -99
- package/src/commands/dev/index.tsx +0 -126
- package/src/commands/dev/logging-manager.ts +0 -87
- package/src/commands/dev/server/index.ts +0 -48
- package/src/commands/dev/server/utils.ts +0 -37
- package/src/commands/dev/ui/components/scroll-area.tsx +0 -141
- package/src/commands/dev/ui/components/tab-bar.tsx +0 -67
- package/src/commands/dev/ui/index.tsx +0 -71
- package/src/commands/dev/ui/logging-context.tsx +0 -76
- package/src/commands/dev/ui/tabs/functions-tab.tsx +0 -35
- package/src/commands/dev/ui/tabs/server-tab.tsx +0 -36
- package/src/commands/dev/ui/tabs/vite-tab.tsx +0 -35
- package/src/commands/dev/ui/use-logging.tsx +0 -34
- package/src/commands/dev/vite/index.ts +0 -54
- package/src/commands/dev/vite/utils.ts +0 -71
- package/src/commands/profile.ts +0 -189
- package/src/index.ts +0 -346
- package/src/lib/api.ts +0 -189
- package/src/lib/bundle/function/index.ts +0 -46
- package/src/lib/bundle/react/index.ts +0 -2
- package/src/lib/bundle/react/spa.ts +0 -77
- package/src/lib/bundle/react/ssr/client.ts +0 -93
- package/src/lib/bundle/react/ssr/config.ts +0 -77
- package/src/lib/bundle/react/ssr/index.ts +0 -4
- package/src/lib/bundle/react/ssr/props.ts +0 -71
- package/src/lib/bundle/react/ssr/server.ts +0 -83
- package/src/lib/config.ts +0 -347
- package/src/lib/deployment.ts +0 -244
- package/src/lib/update-server.ts +0 -262
package/src/lib/config.ts
DELETED
|
@@ -1,347 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
readFileSync,
|
|
3
|
-
writeFileSync,
|
|
4
|
-
existsSync,
|
|
5
|
-
mkdirSync,
|
|
6
|
-
readdirSync,
|
|
7
|
-
unlinkSync
|
|
8
|
-
} from 'node:fs'
|
|
9
|
-
import { join, dirname } from 'node:path'
|
|
10
|
-
import chalk from 'chalk'
|
|
11
|
-
|
|
12
|
-
type NulljsConfig = {
|
|
13
|
-
key?: {
|
|
14
|
-
private: string
|
|
15
|
-
public: string
|
|
16
|
-
}
|
|
17
|
-
api?: string
|
|
18
|
-
dev?: {
|
|
19
|
-
apiPort?: number
|
|
20
|
-
gatewayPort?: number
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const findProjectRoot = (startPath: string = process.cwd()): string => {
|
|
25
|
-
let currentPath = startPath
|
|
26
|
-
while (currentPath !== dirname(currentPath)) {
|
|
27
|
-
if (existsSync(join(currentPath, 'package.json'))) {
|
|
28
|
-
return currentPath
|
|
29
|
-
}
|
|
30
|
-
currentPath = dirname(currentPath)
|
|
31
|
-
}
|
|
32
|
-
return startPath
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const configPath = join(findProjectRoot(), '.nulljs', 'config.json')
|
|
36
|
-
export const profilesDir = join(findProjectRoot(), '.nulljs', 'profiles')
|
|
37
|
-
export const activeProfilePath = join(findProjectRoot(), '.nulljs', 'active-profile')
|
|
38
|
-
|
|
39
|
-
export const loadConfig = (): NulljsConfig => {
|
|
40
|
-
if (!existsSync(configPath)) {
|
|
41
|
-
return {}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const configContent = readFileSync(configPath, 'utf8')
|
|
46
|
-
return JSON.parse(configContent) as NulljsConfig
|
|
47
|
-
} catch (error) {
|
|
48
|
-
console.error('Failed to parse config file:', error)
|
|
49
|
-
return {}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const saveConfig = (config: NulljsConfig): void => {
|
|
54
|
-
try {
|
|
55
|
-
// Ensure the directory exists
|
|
56
|
-
const configDir = dirname(configPath)
|
|
57
|
-
if (!existsSync(configDir)) {
|
|
58
|
-
mkdirSync(configDir, { recursive: true })
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const configContent = JSON.stringify(config, null, 2)
|
|
62
|
-
writeFileSync(configPath, configContent, 'utf8')
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.error('Failed to save config file:', error)
|
|
65
|
-
throw error
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const updateConfig = (partialConfig: Partial<NulljsConfig>): void => {
|
|
70
|
-
const currentConfig = loadConfig()
|
|
71
|
-
const updatedConfig = { ...currentConfig, ...partialConfig }
|
|
72
|
-
|
|
73
|
-
saveConfig(updatedConfig)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Profile-related functions (must be defined before other functions use them)
|
|
77
|
-
export const getActiveProfile = (): string | null => {
|
|
78
|
-
if (!existsSync(activeProfilePath)) {
|
|
79
|
-
return null
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
return readFileSync(activeProfilePath, 'utf8').trim()
|
|
83
|
-
} catch {
|
|
84
|
-
return null
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export const setActiveProfile = (profileName: string): void => {
|
|
89
|
-
const configDir = dirname(activeProfilePath)
|
|
90
|
-
if (!existsSync(configDir)) {
|
|
91
|
-
mkdirSync(configDir, { recursive: true })
|
|
92
|
-
}
|
|
93
|
-
writeFileSync(activeProfilePath, profileName, 'utf8')
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export const getProfilePath = (profileName: string): string => {
|
|
97
|
-
return join(profilesDir, `${profileName}.json`)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export const loadProfile = (profileName: string): NulljsConfig => {
|
|
101
|
-
const profilePath = getProfilePath(profileName)
|
|
102
|
-
if (!existsSync(profilePath)) {
|
|
103
|
-
return {}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const profileContent = readFileSync(profilePath, 'utf8')
|
|
108
|
-
return JSON.parse(profileContent) as NulljsConfig
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error(`Failed to parse profile '${profileName}':`, error)
|
|
111
|
-
return {}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export const saveProfile = (profileName: string, config: NulljsConfig): void => {
|
|
116
|
-
try {
|
|
117
|
-
if (!existsSync(profilesDir)) {
|
|
118
|
-
mkdirSync(profilesDir, { recursive: true })
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const profilePath = getProfilePath(profileName)
|
|
122
|
-
const configContent = JSON.stringify(config, null, 2)
|
|
123
|
-
writeFileSync(profilePath, configContent, 'utf8')
|
|
124
|
-
} catch (error) {
|
|
125
|
-
console.error(`Failed to save profile '${profileName}':`, error)
|
|
126
|
-
throw error
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export const profileExists = (profileName: string): boolean => {
|
|
131
|
-
return existsSync(getProfilePath(profileName))
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export const loadConfigWithProfile = (): NulljsConfig => {
|
|
135
|
-
const activeProfile = getActiveProfile()
|
|
136
|
-
|
|
137
|
-
if (activeProfile && profileExists(activeProfile)) {
|
|
138
|
-
return loadProfile(activeProfile)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return loadConfig()
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export const saveConfigWithProfile = (config: NulljsConfig, profileName?: string): void => {
|
|
145
|
-
if (profileName) {
|
|
146
|
-
saveProfile(profileName, config)
|
|
147
|
-
setActiveProfile(profileName)
|
|
148
|
-
} else {
|
|
149
|
-
const activeProfile = getActiveProfile()
|
|
150
|
-
if (activeProfile && profileExists(activeProfile)) {
|
|
151
|
-
saveProfile(activeProfile, config)
|
|
152
|
-
} else {
|
|
153
|
-
saveConfig(config)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export const updateConfigWithProfile = (
|
|
159
|
-
partialConfig: Partial<NulljsConfig>,
|
|
160
|
-
profileName?: string
|
|
161
|
-
): void => {
|
|
162
|
-
if (profileName) {
|
|
163
|
-
const currentConfig = loadProfile(profileName)
|
|
164
|
-
const updatedConfig = { ...currentConfig, ...partialConfig }
|
|
165
|
-
saveProfile(profileName, updatedConfig)
|
|
166
|
-
setActiveProfile(profileName)
|
|
167
|
-
} else {
|
|
168
|
-
const activeProfile = getActiveProfile()
|
|
169
|
-
if (activeProfile && profileExists(activeProfile)) {
|
|
170
|
-
const currentConfig = loadProfile(activeProfile)
|
|
171
|
-
const updatedConfig = { ...currentConfig, ...partialConfig }
|
|
172
|
-
saveProfile(activeProfile, updatedConfig)
|
|
173
|
-
} else {
|
|
174
|
-
updateConfig(partialConfig)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Functions that use profile-related functions
|
|
180
|
-
export const saveKeys = (privateKey: string, publicKey: string, profileName?: string): void => {
|
|
181
|
-
updateConfigWithProfile(
|
|
182
|
-
{
|
|
183
|
-
key: {
|
|
184
|
-
private: privateKey,
|
|
185
|
-
public: publicKey
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
profileName
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export const saveApiUrl = (apiUrl: string, profileName?: string): void => {
|
|
193
|
-
updateConfigWithProfile({ api: apiUrl }, profileName)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export const loadPrivateKey = async () => {
|
|
197
|
-
let base64Key = process.env.NULLJS_PRIVATE_KEY
|
|
198
|
-
|
|
199
|
-
if (!base64Key) {
|
|
200
|
-
const config = loadConfigWithProfile()
|
|
201
|
-
if (!config.key?.private) {
|
|
202
|
-
throw new Error('Private key not found in config file or environment variable')
|
|
203
|
-
}
|
|
204
|
-
base64Key = config.key.private
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const keyBuffer = Uint8Array.from(atob(base64Key), (c) => c.charCodeAt(0))
|
|
208
|
-
|
|
209
|
-
return await crypto.subtle.importKey(
|
|
210
|
-
'pkcs8',
|
|
211
|
-
keyBuffer,
|
|
212
|
-
{
|
|
213
|
-
name: 'Ed25519',
|
|
214
|
-
namedCurve: 'Ed25519'
|
|
215
|
-
},
|
|
216
|
-
false,
|
|
217
|
-
['sign']
|
|
218
|
-
)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export const getApiUrl = (): string => {
|
|
222
|
-
const config = loadConfigWithProfile()
|
|
223
|
-
return config.api || 'http://localhost:3000/api'
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export const API = getApiUrl()
|
|
227
|
-
|
|
228
|
-
export type DevConfig = {
|
|
229
|
-
apiPort: number
|
|
230
|
-
gatewayPort: number
|
|
231
|
-
publicKey: string | undefined
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export const getDevConfig = () => {
|
|
235
|
-
const config = loadConfigWithProfile()
|
|
236
|
-
return {
|
|
237
|
-
apiPort: config.dev?.apiPort || 3000,
|
|
238
|
-
gatewayPort: config.dev?.gatewayPort || 3001,
|
|
239
|
-
publicKey: config.key?.public
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export const getProjectRoot = () => findProjectRoot()
|
|
244
|
-
|
|
245
|
-
export const getCloudPath = () => join(findProjectRoot(), '.nulljs')
|
|
246
|
-
|
|
247
|
-
export const listProfiles = (): string[] => {
|
|
248
|
-
if (!existsSync(profilesDir)) {
|
|
249
|
-
return []
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
return readdirSync(profilesDir)
|
|
254
|
-
.filter((file) => file.endsWith('.json'))
|
|
255
|
-
.map((file) => file.replace('.json', ''))
|
|
256
|
-
} catch {
|
|
257
|
-
return []
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export const deleteProfile = (profileName: string): boolean => {
|
|
262
|
-
const profilePath = getProfilePath(profileName)
|
|
263
|
-
if (!existsSync(profilePath)) {
|
|
264
|
-
return false
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
unlinkSync(profilePath)
|
|
269
|
-
|
|
270
|
-
const activeProfile = getActiveProfile()
|
|
271
|
-
if (activeProfile === profileName) {
|
|
272
|
-
if (existsSync(activeProfilePath)) {
|
|
273
|
-
unlinkSync(activeProfilePath)
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return true
|
|
278
|
-
} catch {
|
|
279
|
-
return false
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export const requireActiveProfile = (): { profileName: string; config: NulljsConfig } => {
|
|
284
|
-
const activeProfile = getActiveProfile()
|
|
285
|
-
|
|
286
|
-
if (!activeProfile) {
|
|
287
|
-
console.error(chalk.red('❌ No active profile selected.'))
|
|
288
|
-
console.error(chalk.gray(' Create a profile: nulljs profile create <name>'))
|
|
289
|
-
console.error(chalk.gray(' Or switch to existing: nulljs profile use <name>'))
|
|
290
|
-
process.exit(1)
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (!profileExists(activeProfile)) {
|
|
294
|
-
console.error(chalk.red(`❌ Active profile '${activeProfile}' does not exist.`))
|
|
295
|
-
console.error(chalk.gray(' Available profiles:'))
|
|
296
|
-
const profiles = listProfiles()
|
|
297
|
-
if (profiles.length > 0) {
|
|
298
|
-
profiles.forEach((profile) => console.error(chalk.gray(` - ${profile}`)))
|
|
299
|
-
console.error(chalk.gray(' Switch to an existing profile: nulljs profile use <name>'))
|
|
300
|
-
} else {
|
|
301
|
-
console.error(chalk.gray(' Create your first profile: nulljs profile create <name>'))
|
|
302
|
-
}
|
|
303
|
-
process.exit(1)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const config = loadProfile(activeProfile)
|
|
307
|
-
return { profileName: activeProfile, config }
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export const requireProfileConfiguration = (
|
|
311
|
-
requiredFields: Array<'api' | 'key' | 'dev'> = ['api', 'key']
|
|
312
|
-
): { profileName: string; config: NulljsConfig } => {
|
|
313
|
-
const { profileName, config } = requireActiveProfile()
|
|
314
|
-
|
|
315
|
-
const missing: string[] = []
|
|
316
|
-
|
|
317
|
-
if (requiredFields.includes('api') && !config.api) {
|
|
318
|
-
missing.push('API URL')
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (requiredFields.includes('key') && (!config.key?.private || !config.key?.public)) {
|
|
322
|
-
missing.push('authentication keys')
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (requiredFields.includes('dev') && !config.dev) {
|
|
326
|
-
missing.push('dev configuration')
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (missing.length > 0) {
|
|
330
|
-
console.error(chalk.red(`❌ Profile '${profileName}' is missing required configuration:`))
|
|
331
|
-
missing.forEach((field) => console.error(chalk.yellow(` - ${field}`)))
|
|
332
|
-
console.error('')
|
|
333
|
-
console.error(chalk.gray(' Configure your profile:'))
|
|
334
|
-
if (missing.includes('API URL')) {
|
|
335
|
-
console.error(chalk.gray(' nulljs api <url>'))
|
|
336
|
-
}
|
|
337
|
-
if (missing.includes('authentication keys')) {
|
|
338
|
-
console.error(chalk.gray(' nulljs auth'))
|
|
339
|
-
}
|
|
340
|
-
if (missing.includes('dev configuration')) {
|
|
341
|
-
console.error(chalk.gray(' Check your .nulljs/profiles/<profile>.json file'))
|
|
342
|
-
}
|
|
343
|
-
process.exit(1)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
return { profileName, config }
|
|
347
|
-
}
|
package/src/lib/deployment.ts
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import { basename } from 'path'
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import { build } from 'vite'
|
|
5
|
-
import { createHash } from 'crypto'
|
|
6
|
-
import type { OutputAsset, OutputChunk, RollupOutput } from 'rollup'
|
|
7
|
-
import chalk from 'chalk'
|
|
8
|
-
|
|
9
|
-
import { functionConfig, spaClientConfig, ssrConfigConfig } from './bundle'
|
|
10
|
-
import { createDeployment } from './api'
|
|
11
|
-
import { getCloudPath } from './config'
|
|
12
|
-
|
|
13
|
-
export const isReact = (file: string) => file.endsWith('.tsx')
|
|
14
|
-
export const isAsset = (file: string) => file.endsWith('.css')
|
|
15
|
-
export const isTypescript = (file: string) => file.endsWith('.ts')
|
|
16
|
-
export const isJavaScript = (file: string) => file.endsWith('.js')
|
|
17
|
-
export const getFileName = (path: string) => basename(path)
|
|
18
|
-
|
|
19
|
-
export const isOutputAsset = (output: OutputAsset | OutputChunk): output is OutputAsset => {
|
|
20
|
-
return output.type === 'asset'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const isOutputChunk = (output: OutputAsset | OutputChunk): output is OutputChunk => {
|
|
24
|
-
return output.type === 'chunk'
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type DeploymentType = 'react' | 'function'
|
|
28
|
-
|
|
29
|
-
export type Deployment = {
|
|
30
|
-
name: string
|
|
31
|
-
type: DeploymentType
|
|
32
|
-
assets: Array<{
|
|
33
|
-
fileName: string
|
|
34
|
-
code: string
|
|
35
|
-
}>
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Persistent cache utilities
|
|
39
|
-
const getCachePath = (): string => {
|
|
40
|
-
const nulljsPath = getCloudPath()
|
|
41
|
-
return join(nulljsPath, 'deployment-cache.json')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const loadDeploymentCache = (): Map<string, string> => {
|
|
45
|
-
const cachePath = getCachePath()
|
|
46
|
-
|
|
47
|
-
if (!existsSync(cachePath)) {
|
|
48
|
-
return new Map()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const cacheContent = readFileSync(cachePath, 'utf-8')
|
|
53
|
-
const cacheObject = JSON.parse(cacheContent)
|
|
54
|
-
return new Map(Object.entries(cacheObject))
|
|
55
|
-
} catch {
|
|
56
|
-
// If cache is corrupted, start fresh
|
|
57
|
-
return new Map()
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const saveDeploymentCache = (cache: Map<string, string>): void => {
|
|
62
|
-
const cachePath = getCachePath()
|
|
63
|
-
const nulljsPath = getCloudPath()
|
|
64
|
-
|
|
65
|
-
// Ensure .nulljs directory exists
|
|
66
|
-
if (!existsSync(nulljsPath)) {
|
|
67
|
-
require('fs').mkdirSync(nulljsPath, { recursive: true })
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const cacheObject = Object.fromEntries(cache)
|
|
71
|
-
writeFileSync(cachePath, JSON.stringify(cacheObject, null, 2), 'utf-8')
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Load cache on startup
|
|
75
|
-
let deploymentHashCache = loadDeploymentCache()
|
|
76
|
-
|
|
77
|
-
const generateDeploymentHash = (deployment: Deployment): string => {
|
|
78
|
-
const assetsString = deployment.assets
|
|
79
|
-
.map((asset) => `${asset.fileName}:${asset.code}`)
|
|
80
|
-
.sort()
|
|
81
|
-
.join('|')
|
|
82
|
-
|
|
83
|
-
return createHash('sha256').update(assetsString).digest('hex')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const getCachedHash = (deploymentName: string, type: DeploymentType): string | null => {
|
|
87
|
-
const cacheKey = `${type}-${deploymentName}`
|
|
88
|
-
return deploymentHashCache.get(cacheKey) || null
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const saveCachedHash = (deploymentName: string, type: DeploymentType, hash: string): void => {
|
|
92
|
-
const cacheKey = `${type}-${deploymentName}`
|
|
93
|
-
deploymentHashCache.set(cacheKey, hash)
|
|
94
|
-
saveDeploymentCache(deploymentHashCache)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const hasDeploymentChanged = (
|
|
98
|
-
deployment: Deployment,
|
|
99
|
-
force: boolean = false,
|
|
100
|
-
logger: any = console
|
|
101
|
-
): boolean => {
|
|
102
|
-
if (force) {
|
|
103
|
-
logger.log(`Force flag set for ${deployment.name}, deploying...`)
|
|
104
|
-
return true
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const currentHash = generateDeploymentHash(deployment)
|
|
108
|
-
const cachedHash = getCachedHash(deployment.name, deployment.type)
|
|
109
|
-
|
|
110
|
-
if (!cachedHash) {
|
|
111
|
-
logger.log(`No cached build found for ${deployment.name}, deploying...`)
|
|
112
|
-
return true
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const hasChanged = currentHash !== cachedHash
|
|
116
|
-
|
|
117
|
-
if (hasChanged) {
|
|
118
|
-
logger.log(`Build changed for ${deployment.name}, deploying...`)
|
|
119
|
-
} else {
|
|
120
|
-
logger.log(`No changes detected for ${deployment.name}, skipping deployment`)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return hasChanged
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export type DeploymentResult = {
|
|
127
|
-
deployed: boolean
|
|
128
|
-
cached: boolean
|
|
129
|
-
error?: Error
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export const deployFunction = async (
|
|
133
|
-
path: string,
|
|
134
|
-
logger: any = console,
|
|
135
|
-
force: boolean = false
|
|
136
|
-
): Promise<DeploymentResult> => {
|
|
137
|
-
const file = basename(path)
|
|
138
|
-
|
|
139
|
-
const deployment: Deployment = {
|
|
140
|
-
name: file,
|
|
141
|
-
type: 'function',
|
|
142
|
-
assets: []
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
const functionBuild = (await build(functionConfig(path))) as RollupOutput
|
|
147
|
-
|
|
148
|
-
const handler = functionBuild.output.find(
|
|
149
|
-
(output) => output.fileName === 'handler.js'
|
|
150
|
-
) as OutputChunk
|
|
151
|
-
|
|
152
|
-
if (!handler) {
|
|
153
|
-
logger.log(chalk.yellow(`Handler not found for ${deployment.name}`))
|
|
154
|
-
return { deployed: false, cached: false, error: new Error('Handler not found') }
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
deployment.assets.push({
|
|
158
|
-
fileName: handler.fileName,
|
|
159
|
-
code: handler.code
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
if (!hasDeploymentChanged(deployment, force, logger)) {
|
|
163
|
-
return { deployed: false, cached: true }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
await createDeployment(deployment, logger)
|
|
167
|
-
|
|
168
|
-
const hash = generateDeploymentHash(deployment)
|
|
169
|
-
saveCachedHash(deployment.name, deployment.type, hash)
|
|
170
|
-
|
|
171
|
-
return { deployed: true, cached: false }
|
|
172
|
-
} catch (error) {
|
|
173
|
-
logger.error ? logger.error(error) : logger.log(`Error: ${error}`)
|
|
174
|
-
return { deployed: false, cached: false, error: error as Error }
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export const deployPage = async (path: string) => {
|
|
179
|
-
const file = basename(path)
|
|
180
|
-
|
|
181
|
-
const deployment: Deployment = {
|
|
182
|
-
name: file,
|
|
183
|
-
type: 'react',
|
|
184
|
-
assets: []
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// const serverBuild = (await build(ssrServerConfig(path))) as RollupOutput
|
|
188
|
-
// const server = serverBuild.output.pop() as OutputChunk
|
|
189
|
-
//
|
|
190
|
-
// deployment.assets.push({
|
|
191
|
-
// fileName: 'server.js',
|
|
192
|
-
// code: server.code
|
|
193
|
-
// })
|
|
194
|
-
|
|
195
|
-
const configBuild = (await build(ssrConfigConfig(path))) as RollupOutput
|
|
196
|
-
const config = configBuild.output.pop() as OutputChunk
|
|
197
|
-
|
|
198
|
-
deployment.assets.push({
|
|
199
|
-
fileName: 'config.js',
|
|
200
|
-
code: config.code
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
// const propsBuild = (await build(ssrPropsConfig(path))) as RollupOutput
|
|
204
|
-
// const props = propsBuild.output.pop() as OutputChunk
|
|
205
|
-
//
|
|
206
|
-
// deployment.assets.push({
|
|
207
|
-
// fileName: 'props.js',
|
|
208
|
-
// code: props.code
|
|
209
|
-
// })
|
|
210
|
-
|
|
211
|
-
const clientConfig = spaClientConfig(path)
|
|
212
|
-
const clientBuild = (await build(clientConfig)) as RollupOutput
|
|
213
|
-
|
|
214
|
-
for (const clientAsset of clientBuild.output) {
|
|
215
|
-
const fileName = getFileName(clientAsset.fileName)
|
|
216
|
-
|
|
217
|
-
if (isOutputChunk(clientAsset)) {
|
|
218
|
-
deployment.assets.push({
|
|
219
|
-
fileName,
|
|
220
|
-
code: clientAsset.code
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (isOutputAsset(clientAsset)) {
|
|
225
|
-
deployment.assets.push({
|
|
226
|
-
fileName,
|
|
227
|
-
code: clientAsset.source as string
|
|
228
|
-
})
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!hasDeploymentChanged(deployment)) {
|
|
233
|
-
return // Skip deployment if no changes
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
await createDeployment(deployment)
|
|
238
|
-
const hash = generateDeploymentHash(deployment)
|
|
239
|
-
saveCachedHash(deployment.name, deployment.type, hash)
|
|
240
|
-
} catch (error) {
|
|
241
|
-
console.error(error)
|
|
242
|
-
throw error // Re-throw the error so it propagates to the caller
|
|
243
|
-
}
|
|
244
|
-
}
|