@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.
Files changed (58) hide show
  1. package/package.json +22 -32
  2. package/src/cli.ts +24 -0
  3. package/src/commands/config.ts +130 -0
  4. package/src/commands/deploy.ts +182 -123
  5. package/src/commands/dev.ts +10 -0
  6. package/src/commands/host.ts +130 -139
  7. package/src/commands/index.ts +6 -8
  8. package/src/commands/secret.ts +364 -56
  9. package/src/commands/status.ts +41 -0
  10. package/src/components/DeployAnimation.tsx +92 -0
  11. package/src/components/DeploymentLogsPane.tsx +79 -0
  12. package/src/components/Header.tsx +57 -0
  13. package/src/components/HelpModal.tsx +64 -0
  14. package/src/components/SystemLogsPane.tsx +78 -0
  15. package/src/config/index.ts +181 -0
  16. package/src/lib/bundle/function.ts +125 -0
  17. package/src/lib/bundle/index.ts +3 -0
  18. package/src/lib/bundle/react.ts +149 -0
  19. package/src/lib/deploy.ts +103 -0
  20. package/src/lib/server.ts +160 -0
  21. package/src/lib/vite.ts +120 -0
  22. package/src/lib/watcher.ts +274 -0
  23. package/src/ui.tsx +363 -0
  24. package/tsconfig.json +30 -0
  25. package/scripts/install-server.js +0 -199
  26. package/src/commands/api.ts +0 -16
  27. package/src/commands/auth.ts +0 -54
  28. package/src/commands/create.ts +0 -43
  29. package/src/commands/dev/function/index.ts +0 -221
  30. package/src/commands/dev/function/utils.ts +0 -99
  31. package/src/commands/dev/index.tsx +0 -126
  32. package/src/commands/dev/logging-manager.ts +0 -87
  33. package/src/commands/dev/server/index.ts +0 -48
  34. package/src/commands/dev/server/utils.ts +0 -37
  35. package/src/commands/dev/ui/components/scroll-area.tsx +0 -141
  36. package/src/commands/dev/ui/components/tab-bar.tsx +0 -67
  37. package/src/commands/dev/ui/index.tsx +0 -71
  38. package/src/commands/dev/ui/logging-context.tsx +0 -76
  39. package/src/commands/dev/ui/tabs/functions-tab.tsx +0 -35
  40. package/src/commands/dev/ui/tabs/server-tab.tsx +0 -36
  41. package/src/commands/dev/ui/tabs/vite-tab.tsx +0 -35
  42. package/src/commands/dev/ui/use-logging.tsx +0 -34
  43. package/src/commands/dev/vite/index.ts +0 -54
  44. package/src/commands/dev/vite/utils.ts +0 -71
  45. package/src/commands/profile.ts +0 -189
  46. package/src/index.ts +0 -346
  47. package/src/lib/api.ts +0 -189
  48. package/src/lib/bundle/function/index.ts +0 -46
  49. package/src/lib/bundle/react/index.ts +0 -2
  50. package/src/lib/bundle/react/spa.ts +0 -77
  51. package/src/lib/bundle/react/ssr/client.ts +0 -93
  52. package/src/lib/bundle/react/ssr/config.ts +0 -77
  53. package/src/lib/bundle/react/ssr/index.ts +0 -4
  54. package/src/lib/bundle/react/ssr/props.ts +0 -71
  55. package/src/lib/bundle/react/ssr/server.ts +0 -83
  56. package/src/lib/config.ts +0 -347
  57. package/src/lib/deployment.ts +0 -244
  58. package/src/lib/update-server.ts +0 -262
package/src/lib/api.ts DELETED
@@ -1,189 +0,0 @@
1
- import { lookup } from 'mime-types'
2
- import type { Deployment } from './deployment'
3
- import chalk from 'chalk'
4
- import { API, loadPrivateKey } from './config'
5
-
6
- const formDataToString = async (formData: FormData): Promise<string> => {
7
- const entries: string[] = []
8
-
9
- const sortedEntries: [string, FormDataEntryValue][] = Array.from(formData.entries()).sort(
10
- ([a], [b]) => a.localeCompare(b)
11
- )
12
-
13
- for (const [key, value] of sortedEntries) {
14
- if (value instanceof Blob) {
15
- entries.push(`${key}:${value.size}:${value.type}`)
16
- }
17
- }
18
-
19
- return entries.join('|')
20
- }
21
-
22
- export const createDeployment = async (deployment: Deployment, logger: any = console) => {
23
- const form = new FormData()
24
-
25
- if (deployment.type === 'react') {
26
- for (const asset of deployment.assets) {
27
- const mime = lookup(asset.fileName)
28
-
29
- if (!mime) {
30
- throw new Error(chalk.yellow(`Couldn't get the mime type for ${asset.fileName}`))
31
- }
32
-
33
- const buffer = Buffer.from(asset.code)
34
- const blob = new Blob([buffer], { type: mime })
35
-
36
- form.append(asset.fileName, blob)
37
- }
38
-
39
- logger.log(chalk.yellow('Deploying ') + chalk.bgYellow.black(deployment.name))
40
- deployment.assets.forEach((asset) => {
41
- logger.log(`-> ${chalk.blue(asset.fileName)}`)
42
- })
43
-
44
- const privateKey = await loadPrivateKey()
45
-
46
- const sign = await crypto.subtle.sign(
47
- 'Ed25519',
48
- privateKey,
49
- Buffer.from(await formDataToString(form))
50
- )
51
-
52
- const signature = btoa(String.fromCharCode(...new Uint8Array(sign)))
53
-
54
- const response = await fetch(`${API}/deployment/react`, {
55
- headers: {
56
- Authorization: signature
57
- },
58
- method: 'POST',
59
- body: form
60
- })
61
-
62
- if (response.status !== 200) {
63
- throw new Error(
64
- `${chalk.red('Deployment failed')} ${chalk.bgRed.black(response.status)}: ${chalk.red(await response.text())}`
65
- )
66
- }
67
-
68
- logger.log(chalk.green('Deployed ') + chalk.bgGreen.black(deployment.name))
69
- }
70
-
71
- if (deployment.type === 'function') {
72
- const handler = deployment.assets.find((asset) => asset.fileName === 'handler.js')
73
-
74
- if (!handler) {
75
- throw new Error(chalk.yellow(`Handler not found for ${deployment.name}`))
76
- }
77
-
78
- const mime = lookup(handler.fileName)
79
-
80
- if (!mime) {
81
- throw new Error(chalk.yellow(`Couldn't get the mime type for ${handler.fileName}`))
82
- }
83
-
84
- const buffer = Buffer.from(handler.code)
85
- const blob = new Blob([buffer], { type: mime })
86
-
87
- form.append(handler.fileName, blob)
88
-
89
- logger.log(chalk.yellow('Deploying ') + chalk.bgYellow.black(deployment.name))
90
- logger.log(`-> ${chalk.blue(handler.fileName)}`)
91
-
92
- const privateKey = await loadPrivateKey()
93
-
94
- const sign = await crypto.subtle.sign(
95
- 'Ed25519',
96
- privateKey,
97
- Buffer.from(await formDataToString(form))
98
- )
99
-
100
- const signature = btoa(String.fromCharCode(...new Uint8Array(sign)))
101
-
102
- const response = await fetch(`${API}/deployment`, {
103
- headers: {
104
- authorization: signature
105
- },
106
- method: 'POST',
107
- body: form
108
- })
109
-
110
- if (response.status !== 200) {
111
- throw new Error(
112
- `${chalk.red('Deployment failed')} ${chalk.bgRed.black(response.status)}: ${chalk.red(await response.text())}`
113
- )
114
- }
115
-
116
- logger.log(chalk.green('Deployed ') + chalk.bgGreen.black(deployment.name))
117
- }
118
- }
119
-
120
- const createSignatureHeader = async (props: { method: string; url: string; body?: string }) => {
121
- const timestamp = new Date().toISOString()
122
- const privateKey = await loadPrivateKey()
123
-
124
- const raw = `${props.method}-${props.url}-${timestamp}${props.body ? '-' + props.body : ''}`
125
-
126
- const sign = await crypto.subtle.sign('Ed25519', privateKey, Buffer.from(raw))
127
- const signature = btoa(String.fromCharCode(...new Uint8Array(sign)))
128
-
129
- const header: { authorization: string; 'x-time': string; 'x-body'?: string } = {
130
- authorization: signature,
131
- 'x-time': timestamp
132
- }
133
-
134
- if (props.body) {
135
- header['x-body'] = btoa(props.body)
136
- }
137
-
138
- return header
139
- }
140
-
141
- export const fetchSecretKeys = async (): Promise<string[]> => {
142
- const path = `${API}/secrets`
143
-
144
- const headers = await createSignatureHeader({
145
- method: 'GET',
146
- url: path
147
- })
148
-
149
- const response = await fetch(path, {
150
- headers,
151
- method: 'GET'
152
- })
153
-
154
- if (response.status !== 200) {
155
- console.log(chalk.red('Request failed'))
156
- console.log(`${chalk.bgRed.black(response.status)}: ${chalk.red(await response.text())}`)
157
- return []
158
- }
159
-
160
- const data = await response.json()
161
-
162
- return data
163
- }
164
-
165
- export const postSecret = async (props: { key: string; value: string }) => {
166
- const path = `${API}/secrets`
167
- const body = JSON.stringify(props)
168
-
169
- const headers = await createSignatureHeader({
170
- method: 'POST',
171
- url: path,
172
- body
173
- })
174
-
175
- const response = await fetch(path, {
176
- method: 'POST',
177
- headers: {
178
- 'Content-Type': 'application/json',
179
- ...headers
180
- },
181
- body
182
- })
183
-
184
- if (response.status !== 200) {
185
- throw new Error(
186
- `${chalk.red('Request failed')} ${chalk.bgRed.black(response.status)}: ${chalk.red(await response.text())}`
187
- )
188
- }
189
- }
@@ -1,46 +0,0 @@
1
- import type { InlineConfig, Plugin, UserConfig } from 'vite'
2
- import { external } from '../external'
3
- import type { PluginOptions } from '../types'
4
-
5
- const jsFunction = ({ filePath }: PluginOptions): Plugin => {
6
- return {
7
- name: 'nulljs-function-plugin',
8
- apply: 'build',
9
- config: async (config: UserConfig, { command }) => {
10
- if (command !== 'build') {
11
- return config
12
- }
13
-
14
- return {
15
- build: {
16
- rollupOptions: {
17
- input: {
18
- handler: filePath
19
- },
20
- external,
21
- output: {
22
- // preserveModules: false,
23
- entryFileNames: '[name].js'
24
- },
25
- preserveEntrySignatures: 'strict'
26
- }
27
- }
28
- }
29
- }
30
- }
31
- }
32
-
33
- export const functionConfig = (filePath: string): InlineConfig => {
34
- return {
35
- logLevel: 'error',
36
- plugins: [
37
- jsFunction({
38
- filePath
39
- })
40
- ],
41
- build: {
42
- outDir: '/tmp',
43
- minify: false
44
- }
45
- }
46
- }
@@ -1,2 +0,0 @@
1
- export * from './ssr'
2
- export * from './spa'
@@ -1,77 +0,0 @@
1
- import { basename, extname } from 'path'
2
- import type { InlineConfig, Plugin, UserConfig } from 'vite'
3
- import react from '@vitejs/plugin-react'
4
- import tailwindcss from '@tailwindcss/vite'
5
-
6
- import type { PluginOptions } from '../types'
7
-
8
- const jsSpa = ({ filePath }: PluginOptions): Plugin => {
9
- const entry = basename(filePath, extname(filePath))
10
- const virtualPrefix = `virtual:ssr/${entry}.tsx`
11
-
12
- return {
13
- name: 'nulljs-ssr-client-plugin',
14
- apply: 'build',
15
- config: async (config: UserConfig, { command }) => {
16
- if (command !== 'build') {
17
- return config
18
- }
19
-
20
- return {
21
- build: {
22
- rollupOptions: {
23
- input: {
24
- [entry]: virtualPrefix
25
- },
26
- external: ['cloud'],
27
- output: {
28
- entryFileNames: '[name].js'
29
- }
30
- }
31
- },
32
- plugins: [react()]
33
- }
34
- },
35
-
36
- resolveId: (id: string) => {
37
- if (id === virtualPrefix) {
38
- return id
39
- }
40
- return null
41
- },
42
-
43
- load: (id: string) => {
44
- if (id === virtualPrefix) {
45
- const script = `
46
- import { StrictMode } from 'react'
47
- import { createRoot } from 'react-dom/client'
48
-
49
- import { Page } from "${filePath.replace(/\\/g, '\\\\')}";
50
-
51
- createRoot(document.getElementById('root')!).render(
52
- <StrictMode>
53
- <Page />
54
- </StrictMode>
55
- )`
56
-
57
- return script
58
- }
59
- return null
60
- }
61
- }
62
- }
63
-
64
- export const spaClientConfig = (filePath: string): InlineConfig => {
65
- return {
66
- logLevel: 'error',
67
- plugins: [
68
- jsSpa({
69
- filePath
70
- }),
71
- tailwindcss()
72
- ],
73
- build: {
74
- outDir: '/tmp'
75
- }
76
- }
77
- }
@@ -1,93 +0,0 @@
1
- import { basename, extname } from 'path'
2
- import type { InlineConfig, Plugin, UserConfig } from 'vite'
3
- import react from '@vitejs/plugin-react'
4
- import tailwindcss from '@tailwindcss/vite'
5
-
6
- import type { PluginOptions } from '../../types'
7
-
8
- const jsClientSsr = ({ filePath }: PluginOptions): Plugin => {
9
- const entry = basename(filePath, extname(filePath))
10
- const virtualPrefix = `virtual:ssr/${entry}.tsx`
11
-
12
- return {
13
- name: 'nulljs-ssr-client-plugin',
14
- apply: 'build',
15
- config: async (config: UserConfig, { command }) => {
16
- if (command !== 'build') {
17
- return config
18
- }
19
-
20
- return {
21
- build: {
22
- rollupOptions: {
23
- input: {
24
- [entry]: virtualPrefix
25
- },
26
- external: ['cloud'],
27
- output: {
28
- entryFileNames: '[name].js'
29
- }
30
- }
31
- },
32
- plugins: [react()]
33
- }
34
- },
35
-
36
- resolveId: (id: string) => {
37
- if (id === virtualPrefix) {
38
- return id
39
- }
40
- return null
41
- },
42
-
43
- load: (id: string) => {
44
- if (id === virtualPrefix) {
45
- const script = `
46
- import { StrictMode } from 'react'
47
- import { hydrateRoot } from "react-dom/client";
48
- import { Page } from "${filePath.replace(/\\/g, '\\\\')}";
49
-
50
- const domNode = document.getElementById("root");
51
- if (domNode) {
52
- const initialProps = window.__INITIAL_PROPS__ || {};
53
-
54
- hydrateRoot(
55
- domNode,
56
- <StrictMode>
57
- <Page {...initialProps} />
58
- </StrictMode>,
59
- )
60
- }`
61
-
62
- return script
63
- }
64
- return null
65
- },
66
-
67
- generateBundle(_, bundle) {
68
- Object.keys(bundle).forEach((fileName) => {
69
- const chunk = bundle[fileName]
70
- if (chunk.type === 'chunk') {
71
- chunk.code = chunk.code.replace(/import\s+.*?\s+from\s+['"]cloud['"];?\s*/g, '')
72
- chunk.code = chunk.code.replace('import"cloud";', '')
73
- chunk.code = chunk.code.replace(/require\(['"]cloud['"]\);?\s*/g, '')
74
- }
75
- })
76
- }
77
- }
78
- }
79
-
80
- export const ssrClientConfig = (filePath: string): InlineConfig => {
81
- return {
82
- logLevel: 'error',
83
- plugins: [
84
- jsClientSsr({
85
- filePath
86
- }),
87
- tailwindcss()
88
- ],
89
- build: {
90
- outDir: '/tmp'
91
- }
92
- }
93
- }
@@ -1,77 +0,0 @@
1
- import path from 'path'
2
- import type { InlineConfig, Plugin, UserConfig } from 'vite'
3
- import { external } from '../../external'
4
-
5
- import type { PluginOptions } from '../../types'
6
-
7
- const jsConfigSsr = ({ filePath }: PluginOptions): Plugin => {
8
- const entry = path.basename(filePath, path.extname(filePath))
9
- const virtualPrefix = `virtual:ssr/${entry}.ts`
10
-
11
- return {
12
- name: 'nulljs-ssr-props-plugin',
13
- apply: 'build',
14
- config: async (config: UserConfig, { command }) => {
15
- if (command !== 'build') {
16
- return config
17
- }
18
-
19
- return {
20
- build: {
21
- ssr: true,
22
- rollupOptions: {
23
- input: {
24
- [entry]: virtualPrefix
25
- },
26
- external: [...external, 'react', 'react/jsx-runtime'],
27
- output: {
28
- entryFileNames: '[name].js'
29
- },
30
- preserveEntrySignatures: 'strict'
31
- }
32
- }
33
- }
34
- },
35
-
36
- resolveId: (id: string) => {
37
- if (id === virtualPrefix) {
38
- return id
39
- }
40
- return null
41
- },
42
-
43
- load: (id: string) => {
44
- if (id === virtualPrefix) {
45
- const script = `
46
- import { config } from "${filePath.replace(/\\/g, '\\\\')}";
47
-
48
- export default config;
49
- `
50
-
51
- return script
52
- }
53
- return null
54
- },
55
-
56
- transform: (code, id) => {
57
- if (id === filePath) {
58
- const configMatch = code.match(/export const config = \{[^}]*\};/)
59
- return configMatch ? { code: configMatch[0], map: null } : null
60
- }
61
- }
62
- }
63
- }
64
-
65
- export const ssrConfigConfig = (filePath: string): InlineConfig => {
66
- return {
67
- logLevel: 'error',
68
- plugins: [
69
- jsConfigSsr({
70
- filePath
71
- })
72
- ],
73
- build: {
74
- outDir: '/tmp'
75
- }
76
- }
77
- }
@@ -1,4 +0,0 @@
1
- export * from './client'
2
- export * from './server'
3
- export * from './config'
4
- export * from './props'
@@ -1,71 +0,0 @@
1
- import path from 'path'
2
- import type { InlineConfig, Plugin, UserConfig } from 'vite'
3
- import react from '@vitejs/plugin-react-swc'
4
-
5
- import type { PluginOptions } from '../../types'
6
- import { external } from '../../external'
7
-
8
- const jsPagesSsr = ({ filePath }: PluginOptions): Plugin => {
9
- const entry = path.basename(filePath, path.extname(filePath))
10
- const virtualPrefix = `virtual:ssr/${entry}.ts`
11
-
12
- return {
13
- name: 'nulljs-ssr-server-plugin',
14
- apply: 'build',
15
- config: async (config: UserConfig, { command }) => {
16
- if (command !== 'build') {
17
- return config
18
- }
19
-
20
- return {
21
- build: {
22
- ssr: true,
23
- rollupOptions: {
24
- input: {
25
- [entry]: virtualPrefix
26
- },
27
- external,
28
- output: {
29
- entryFileNames: '[name].js'
30
- },
31
- preserveEntrySignatures: 'strict'
32
- }
33
- }
34
- }
35
- },
36
-
37
- resolveId: (id: string) => {
38
- if (id === virtualPrefix) {
39
- return id
40
- }
41
- return null
42
- },
43
-
44
- load: (id: string) => {
45
- if (id === virtualPrefix) {
46
- const script = `
47
- import { props } from "${filePath.replace(/\\/g, '\\\\')}";
48
-
49
- export { props }
50
- `
51
-
52
- return script
53
- }
54
- return null
55
- }
56
- }
57
- }
58
-
59
- export const ssrPropsConfig = (filePath: string): InlineConfig => {
60
- return {
61
- logLevel: 'error',
62
- plugins: [
63
- jsPagesSsr({
64
- filePath
65
- })
66
- ],
67
- build: {
68
- outDir: '/tmp'
69
- }
70
- }
71
- }
@@ -1,83 +0,0 @@
1
- import path from 'path'
2
- import type { InlineConfig, Plugin, UserConfig } from 'vite'
3
- import react from '@vitejs/plugin-react-swc'
4
-
5
- import type { PluginOptions } from '../../types'
6
- import { external } from '../../external'
7
-
8
- const jsPagesSsr = ({ filePath }: PluginOptions): Plugin => {
9
- const entry = path.basename(filePath, path.extname(filePath))
10
- const virtualPrefix = `virtual:ssr/${entry}.tsx`
11
-
12
- return {
13
- name: 'nulljs-ssr-server-plugin',
14
- apply: 'build',
15
- config: async (config: UserConfig, { command }) => {
16
- if (command !== 'build') {
17
- return config
18
- }
19
-
20
- return {
21
- build: {
22
- ssr: true,
23
- rollupOptions: {
24
- input: {
25
- [entry]: virtualPrefix
26
- },
27
- external,
28
- output: {
29
- format: 'iife',
30
- entryFileNames: '[name].js'
31
- }
32
- }
33
- },
34
- ssr: {
35
- target: 'webworker',
36
- noExternal: true
37
- },
38
- plugins: [react()]
39
- }
40
- },
41
-
42
- resolveId: (id: string) => {
43
- if (id === virtualPrefix) {
44
- return id
45
- }
46
- return null
47
- },
48
-
49
- load: (id: string) => {
50
- if (id === virtualPrefix) {
51
- const script = `
52
- import "fast-text-encoding";
53
- import React from "react";
54
- import { renderToString } from "react-dom/server";
55
- import { Page } from "${filePath.replace(/\\/g, '\\\\')}";
56
-
57
- export const Index = (props) => {
58
- const p = props ? JSON.parse(props) : {};
59
-
60
- return renderToString(<Page {...p} />);
61
- }
62
- `
63
-
64
- return script
65
- }
66
- return null
67
- }
68
- }
69
- }
70
-
71
- export const ssrServerConfig = (filePath: string): InlineConfig => {
72
- return {
73
- logLevel: 'error',
74
- plugins: [
75
- jsPagesSsr({
76
- filePath
77
- })
78
- ],
79
- build: {
80
- outDir: '/tmp'
81
- }
82
- }
83
- }