@tothalex/nulljs 0.0.53 → 0.0.57
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/dist/cli.js +2553 -0
- package/package.json +8 -5
- package/src/cli.ts +0 -24
- package/src/commands/config.ts +0 -130
- package/src/commands/deploy.ts +0 -219
- package/src/commands/dev.ts +0 -10
- package/src/commands/host.ts +0 -330
- package/src/commands/index.ts +0 -6
- package/src/commands/secret.ts +0 -387
- package/src/commands/status.ts +0 -41
- package/src/components/DeployAnimation.tsx +0 -92
- package/src/components/DeploymentLogsPane.tsx +0 -79
- package/src/components/Header.tsx +0 -57
- package/src/components/HelpModal.tsx +0 -64
- package/src/components/SystemLogsPane.tsx +0 -78
- package/src/config/index.ts +0 -181
- package/src/lib/bundle/external.ts +0 -23
- package/src/lib/bundle/function.ts +0 -125
- package/src/lib/bundle/index.ts +0 -5
- package/src/lib/bundle/react.ts +0 -149
- package/src/lib/bundle/types.ts +0 -4
- package/src/lib/deploy.ts +0 -103
- package/src/lib/server.ts +0 -160
- package/src/lib/vite.ts +0 -120
- package/src/lib/watcher.ts +0 -274
- package/src/ui.tsx +0 -363
- package/tsconfig.json +0 -30
package/src/ui.tsx
DELETED
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
import { createCliRenderer } from '@opentui/core'
|
|
3
|
-
import { createRoot } from '@opentui/react'
|
|
4
|
-
import {
|
|
5
|
-
getSystemLogs,
|
|
6
|
-
searchDeploymentLogs,
|
|
7
|
-
type LogEntry,
|
|
8
|
-
type SystemLogEntry
|
|
9
|
-
} from '@nulljs/api'
|
|
10
|
-
|
|
11
|
-
import { startServer, type BinarySource } from './lib/server'
|
|
12
|
-
import { startWatcher, forceDeployAll } from './lib/watcher'
|
|
13
|
-
import { startViteServer, stopViteServer } from './lib/vite'
|
|
14
|
-
import { getOrCreateLocalDevConfig, type Config } from './config'
|
|
15
|
-
import { DeploymentLogsPane } from './components/DeploymentLogsPane'
|
|
16
|
-
import { SystemLogsPane } from './components/SystemLogsPane'
|
|
17
|
-
import { DeployAnimation, type DeployedFunction } from './components/DeployAnimation'
|
|
18
|
-
import { Header } from './components/Header'
|
|
19
|
-
import { HelpModal } from './components/HelpModal'
|
|
20
|
-
|
|
21
|
-
type WatcherEvent = {
|
|
22
|
-
type: 'deploy' | 'change'
|
|
23
|
-
deployed?: DeployedFunction[]
|
|
24
|
-
filePath?: string
|
|
25
|
-
success?: boolean
|
|
26
|
-
skipped?: boolean
|
|
27
|
-
error?: string
|
|
28
|
-
affectedCount?: number
|
|
29
|
-
timestamp: Date
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const App = (props: {
|
|
33
|
-
config: Config
|
|
34
|
-
binarySource: BinarySource
|
|
35
|
-
functionCount: number
|
|
36
|
-
viteRunning: boolean
|
|
37
|
-
onWatcherEvent: (handler: (event: WatcherEvent) => void) => void
|
|
38
|
-
onForceDeploy: () => Promise<void>
|
|
39
|
-
}) => {
|
|
40
|
-
const [error, setError] = useState<string | null>(null)
|
|
41
|
-
const [loading, setLoading] = useState(true)
|
|
42
|
-
const [deploymentLogs, setDeploymentLogs] = useState<LogEntry[]>([])
|
|
43
|
-
const [systemLogs, setSystemLogs] = useState<SystemLogEntry[]>([])
|
|
44
|
-
const [activeTab, setActiveTab] = useState<'deployment' | 'system'>('system')
|
|
45
|
-
const [autoScroll, setAutoScroll] = useState(true)
|
|
46
|
-
const [jumpTrigger, setJumpTrigger] = useState(0)
|
|
47
|
-
const [watcherStatus, setWatcherStatus] = useState<WatcherEvent | null>(null)
|
|
48
|
-
const [showKeyBindings, setShowKeyBindings] = useState(false)
|
|
49
|
-
const [isDeploying, setIsDeploying] = useState(false)
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
props.onWatcherEvent((event) => {
|
|
53
|
-
console.error('DEBUG: received watcher event:', event.type, event.deployed?.length)
|
|
54
|
-
setWatcherStatus(event)
|
|
55
|
-
})
|
|
56
|
-
}, [props.onWatcherEvent])
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
const fn = async () => {
|
|
60
|
-
try {
|
|
61
|
-
setLoading(true)
|
|
62
|
-
setError(null)
|
|
63
|
-
|
|
64
|
-
const [deploymentLogsData, systemLogsData] = await Promise.all([
|
|
65
|
-
searchDeploymentLogs(props.config.key.public, { limit: 100 }, props.config.api),
|
|
66
|
-
getSystemLogs(props.config.key.public, { limit: 100 }, props.config.api)
|
|
67
|
-
])
|
|
68
|
-
|
|
69
|
-
setDeploymentLogs(deploymentLogsData)
|
|
70
|
-
setSystemLogs(systemLogsData)
|
|
71
|
-
} catch (err) {
|
|
72
|
-
setError(err instanceof Error ? err.message : String(err))
|
|
73
|
-
console.error('Failed to fetch logs:', err)
|
|
74
|
-
} finally {
|
|
75
|
-
setLoading(false)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
fn()
|
|
80
|
-
}, [props.config.key.public, props.config.api])
|
|
81
|
-
|
|
82
|
-
// Poll for new logs every 2 seconds
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
const interval = setInterval(async () => {
|
|
85
|
-
if (loading) return
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const [newDeploymentLogs, newSystemLogs] = await Promise.all([
|
|
89
|
-
searchDeploymentLogs(props.config.key.public, { limit: 100 }, props.config.api),
|
|
90
|
-
getSystemLogs(props.config.key.public, { limit: 100 }, props.config.api)
|
|
91
|
-
])
|
|
92
|
-
|
|
93
|
-
// Only update if we have new logs
|
|
94
|
-
if (newDeploymentLogs.length > 0) {
|
|
95
|
-
setDeploymentLogs(newDeploymentLogs)
|
|
96
|
-
}
|
|
97
|
-
if (newSystemLogs.length > 0) {
|
|
98
|
-
setSystemLogs(newSystemLogs)
|
|
99
|
-
}
|
|
100
|
-
} catch (err) {
|
|
101
|
-
console.error('Failed to poll for new logs:', err)
|
|
102
|
-
}
|
|
103
|
-
}, 2000)
|
|
104
|
-
|
|
105
|
-
return () => clearInterval(interval)
|
|
106
|
-
}, [loading, props.config.key.public, props.config.api])
|
|
107
|
-
|
|
108
|
-
useEffect(() => {
|
|
109
|
-
const handleKeyPress = (data: Buffer) => {
|
|
110
|
-
const key = data.toString()
|
|
111
|
-
|
|
112
|
-
// Number keys to jump to specific panel
|
|
113
|
-
if (key === '1') {
|
|
114
|
-
setActiveTab('system')
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
if (key === '2') {
|
|
118
|
-
setActiveTab('deployment')
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Tab key cycles between panels
|
|
123
|
-
if (key === '\t') {
|
|
124
|
-
setActiveTab((prev) => (prev === 'system' ? 'deployment' : 'system'))
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// h/l for vim-style navigation
|
|
129
|
-
if (key === 'h') {
|
|
130
|
-
setActiveTab('system')
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
if (key === 'l') {
|
|
134
|
-
setActiveTab('deployment')
|
|
135
|
-
return
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// g - jump to top and disable auto-scroll
|
|
139
|
-
if (key === 'g') {
|
|
140
|
-
setAutoScroll(false)
|
|
141
|
-
setJumpTrigger((prev) => prev + 1)
|
|
142
|
-
return
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Shift+G - jump to bottom and enable auto-scroll
|
|
146
|
-
if (key === 'G') {
|
|
147
|
-
setAutoScroll(true)
|
|
148
|
-
setJumpTrigger((prev) => prev + 1)
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// ? - toggle key bindings modal
|
|
153
|
-
if (key === '?') {
|
|
154
|
-
setShowKeyBindings((prev) => !prev)
|
|
155
|
-
return
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ESC - close key bindings modal
|
|
159
|
-
if (key === '\x1b') {
|
|
160
|
-
setShowKeyBindings(false)
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// d - force deploy all
|
|
165
|
-
if (key === 'd' && !isDeploying) {
|
|
166
|
-
setIsDeploying(true)
|
|
167
|
-
props.onForceDeploy().finally(() => {
|
|
168
|
-
setIsDeploying(false)
|
|
169
|
-
})
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
process.stdin.setRawMode(true)
|
|
175
|
-
process.stdin.on('data', handleKeyPress)
|
|
176
|
-
|
|
177
|
-
return () => {
|
|
178
|
-
process.stdin.setRawMode(false)
|
|
179
|
-
process.stdin.off('data', handleKeyPress)
|
|
180
|
-
}
|
|
181
|
-
}, [isDeploying, props.onForceDeploy])
|
|
182
|
-
|
|
183
|
-
if (error) {
|
|
184
|
-
return (
|
|
185
|
-
<box flexGrow={1} flexDirection="column" padding={1}>
|
|
186
|
-
<text>
|
|
187
|
-
<span fg="red">Error: {error}</span>
|
|
188
|
-
</text>
|
|
189
|
-
</box>
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return (
|
|
194
|
-
<box flexDirection="column">
|
|
195
|
-
<Header
|
|
196
|
-
activeTab={activeTab}
|
|
197
|
-
functionCount={props.functionCount}
|
|
198
|
-
viteRunning={props.viteRunning}
|
|
199
|
-
isDeploying={isDeploying}
|
|
200
|
-
binarySource={props.binarySource}
|
|
201
|
-
/>
|
|
202
|
-
|
|
203
|
-
<box paddingTop={1} flexDirection="column">
|
|
204
|
-
{activeTab === 'system' ? (
|
|
205
|
-
<SystemLogsPane
|
|
206
|
-
logs={systemLogs}
|
|
207
|
-
loading={loading}
|
|
208
|
-
autoScroll={autoScroll}
|
|
209
|
-
jumpTrigger={jumpTrigger}
|
|
210
|
-
/>
|
|
211
|
-
) : (
|
|
212
|
-
<DeploymentLogsPane
|
|
213
|
-
logs={deploymentLogs}
|
|
214
|
-
loading={loading}
|
|
215
|
-
autoScroll={autoScroll}
|
|
216
|
-
jumpTrigger={jumpTrigger}
|
|
217
|
-
/>
|
|
218
|
-
)}
|
|
219
|
-
{watcherStatus?.type === 'deploy' &&
|
|
220
|
-
watcherStatus.deployed &&
|
|
221
|
-
watcherStatus.deployed.length > 0 && (
|
|
222
|
-
<DeployAnimation
|
|
223
|
-
deployed={watcherStatus.deployed}
|
|
224
|
-
onComplete={() => {
|
|
225
|
-
console.error('DEBUG: animation complete')
|
|
226
|
-
setWatcherStatus(null)
|
|
227
|
-
}}
|
|
228
|
-
/>
|
|
229
|
-
)}
|
|
230
|
-
</box>
|
|
231
|
-
|
|
232
|
-
<HelpModal visible={showKeyBindings} />
|
|
233
|
-
</box>
|
|
234
|
-
)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const main = async () => {
|
|
238
|
-
let serverInfo: Awaited<ReturnType<typeof startServer>> | null = null
|
|
239
|
-
let viteInfo: Awaited<ReturnType<typeof startViteServer>> | null = null
|
|
240
|
-
let stopWatcher: (() => void) | null = null
|
|
241
|
-
let isCleaningUp = false
|
|
242
|
-
|
|
243
|
-
const cleanup = async (exitAfter = true) => {
|
|
244
|
-
if (isCleaningUp) return
|
|
245
|
-
isCleaningUp = true
|
|
246
|
-
|
|
247
|
-
if (stopWatcher) {
|
|
248
|
-
stopWatcher()
|
|
249
|
-
stopWatcher = null
|
|
250
|
-
}
|
|
251
|
-
if (viteInfo) {
|
|
252
|
-
await stopViteServer(viteInfo)
|
|
253
|
-
viteInfo = null
|
|
254
|
-
}
|
|
255
|
-
if (serverInfo) {
|
|
256
|
-
const pid = serverInfo.process.pid
|
|
257
|
-
serverInfo = null
|
|
258
|
-
try {
|
|
259
|
-
// Kill the server process and its children
|
|
260
|
-
process.kill(pid, 'SIGTERM')
|
|
261
|
-
} catch {
|
|
262
|
-
// Process might already be dead
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (exitAfter) {
|
|
266
|
-
process.exit(0)
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
process.on('SIGINT', () => cleanup(true))
|
|
271
|
-
process.on('SIGTERM', () => cleanup(true))
|
|
272
|
-
process.on('exit', () => cleanup(false))
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
serverInfo = await startServer()
|
|
276
|
-
|
|
277
|
-
const devConfig = await getOrCreateLocalDevConfig()
|
|
278
|
-
|
|
279
|
-
const srcPath = process.cwd() + '/src'
|
|
280
|
-
|
|
281
|
-
viteInfo = await startViteServer({
|
|
282
|
-
srcDir: srcPath,
|
|
283
|
-
onLog: (_msg, _level) => {}
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
let watcherEventHandler: ((event: WatcherEvent) => void) | null = null
|
|
287
|
-
let pendingEvents: WatcherEvent[] = []
|
|
288
|
-
let functionCount = 0
|
|
289
|
-
|
|
290
|
-
const sendEvent = (event: WatcherEvent) => {
|
|
291
|
-
if (watcherEventHandler) {
|
|
292
|
-
watcherEventHandler(event)
|
|
293
|
-
} else {
|
|
294
|
-
pendingEvents.push(event)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const renderer = await createCliRenderer()
|
|
299
|
-
const root = createRoot(renderer)
|
|
300
|
-
|
|
301
|
-
const handleForceDeploy = async () => {
|
|
302
|
-
const deployResults: DeployedFunction[] = []
|
|
303
|
-
|
|
304
|
-
await forceDeployAll(srcPath, {
|
|
305
|
-
onDeploy: (filePath, success, error) => {
|
|
306
|
-
deployResults.push({ name: filePath, success, error })
|
|
307
|
-
}
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
if (deployResults.length > 0) {
|
|
311
|
-
sendEvent({
|
|
312
|
-
type: 'deploy',
|
|
313
|
-
deployed: deployResults,
|
|
314
|
-
timestamp: new Date()
|
|
315
|
-
})
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Start watcher after renderer is ready
|
|
320
|
-
stopWatcher = await startWatcher(srcPath, {
|
|
321
|
-
silent: true,
|
|
322
|
-
onReady: (count) => {
|
|
323
|
-
functionCount = count
|
|
324
|
-
},
|
|
325
|
-
onDeployBatch: (results) => {
|
|
326
|
-
sendEvent({
|
|
327
|
-
type: 'deploy',
|
|
328
|
-
deployed: results.map((r) => ({
|
|
329
|
-
name: r.name,
|
|
330
|
-
success: r.success,
|
|
331
|
-
error: r.error
|
|
332
|
-
})),
|
|
333
|
-
timestamp: new Date()
|
|
334
|
-
})
|
|
335
|
-
}
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
root.render(
|
|
339
|
-
<App
|
|
340
|
-
config={devConfig}
|
|
341
|
-
binarySource={serverInfo.binarySource}
|
|
342
|
-
functionCount={functionCount}
|
|
343
|
-
viteRunning={viteInfo !== null}
|
|
344
|
-
onWatcherEvent={(handler) => {
|
|
345
|
-
watcherEventHandler = handler
|
|
346
|
-
// Flush any pending events
|
|
347
|
-
if (pendingEvents.length > 0) {
|
|
348
|
-
for (const event of pendingEvents) {
|
|
349
|
-
handler(event)
|
|
350
|
-
}
|
|
351
|
-
pendingEvents = []
|
|
352
|
-
}
|
|
353
|
-
}}
|
|
354
|
-
onForceDeploy={handleForceDeploy}
|
|
355
|
-
/>
|
|
356
|
-
)
|
|
357
|
-
} catch (error) {
|
|
358
|
-
console.error('Failed to start server:', error)
|
|
359
|
-
cleanup()
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
main()
|
package/tsconfig.json
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
// Environment setup & latest features
|
|
4
|
-
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "Preserve",
|
|
7
|
-
"moduleDetection": "force",
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"jsxImportSource": "@opentui/react",
|
|
10
|
-
"allowJs": true,
|
|
11
|
-
|
|
12
|
-
// Bundler mode
|
|
13
|
-
"moduleResolution": "bundler",
|
|
14
|
-
"allowImportingTsExtensions": true,
|
|
15
|
-
"verbatimModuleSyntax": true,
|
|
16
|
-
"noEmit": true,
|
|
17
|
-
|
|
18
|
-
// Best practices
|
|
19
|
-
"strict": true,
|
|
20
|
-
"skipLibCheck": true,
|
|
21
|
-
"noFallthroughCasesInSwitch": true,
|
|
22
|
-
"noUncheckedIndexedAccess": true,
|
|
23
|
-
"noImplicitOverride": true,
|
|
24
|
-
|
|
25
|
-
// Some stricter flags (disabled by default)
|
|
26
|
-
"noUnusedLocals": false,
|
|
27
|
-
"noUnusedParameters": false,
|
|
28
|
-
"noPropertyAccessFromIndexSignature": false
|
|
29
|
-
}
|
|
30
|
-
}
|