epos 1.1.9 → 1.2.1

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 CHANGED
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "name": "epos",
3
- "version": "1.1.9",
3
+ "version": "1.2.1",
4
4
  "author": "imkost",
5
5
  "description": "",
6
6
  "keywords": [],
7
7
  "license": "MIT",
8
8
  "type": "module",
9
+ "scripts": {
10
+ "dev": "node ./src/kit/kit-bin.js"
11
+ },
12
+ "bin": {
13
+ "epos": "./src/kit/kit-bin.js"
14
+ },
9
15
  "exports": {
10
16
  ".": {
11
17
  "types": "./src/types/types.d.ts"
@@ -13,11 +19,10 @@
13
19
  "./plugin-vite": "./src/plugin-vite.js",
14
20
  "./plugin-esbuild": "./src/plugin-esbuild.js"
15
21
  },
16
- "bin": {
17
- "epos": "./src/kit/kit-bin.js"
18
- },
19
22
  "devDependencies": {
20
23
  "chokidar": "^4.0.3",
24
+ "glob": "^11.0.1",
25
+ "ignore": "^7.0.3",
21
26
  "js-yaml": "^4.1.0",
22
27
  "mime": "^4.0.6",
23
28
  "prettier": "^3.4.2",
@@ -14,7 +14,7 @@ const {
14
14
  useLocalStore,
15
15
  useObserver,
16
16
  useStaticRendering,
17
- } = self.mobxReact
17
+ } = Self.mobxReact
18
18
 
19
19
  export {
20
20
  MobXProviderContext,
@@ -67,7 +67,7 @@ const {
67
67
  untracked,
68
68
  values,
69
69
  when,
70
- } = self.mobx
70
+ } = Self.mobx
71
71
 
72
72
  export {
73
73
  $mobx,
@@ -1,4 +1,4 @@
1
- const reactDomClient = self.reactDomClient
1
+ const reactDomClient = Self.reactDomClient
2
2
  const { createRoot, hydrateRoot, version } = reactDomClient
3
3
 
4
4
  export default reactDomClient
@@ -1,4 +1,4 @@
1
- const reactDom = self.reactDom
1
+ const reactDom = Self.reactDom
2
2
  const {
3
3
  __DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
4
4
  createPortal,
@@ -1,4 +1,4 @@
1
- const reactJsxRuntime = self.reactJsxRuntime
1
+ const reactJsxRuntime = Self.reactJsxRuntime
2
2
  const { Fragment, jsx, jsxs } = reactJsxRuntime
3
3
 
4
4
  export default reactJsxRuntime
@@ -1,4 +1,4 @@
1
- const react = self.react
1
+ const react = Self.react
2
2
  const {
3
3
  Children,
4
4
  Component,
@@ -1,106 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import $fs from 'node:fs/promises'
4
- import $path from 'path'
5
- import $http from 'node:http'
6
- import $mime from 'mime'
7
- import $yaml from 'js-yaml'
8
- import $chokidar from 'chokidar'
9
- import * as $ws from 'ws'
3
+ import $server from './kit-server.js'
10
4
 
11
- const $server = {
12
- async init() {
13
- const dir = process.cwd()
14
- const dirs = await this._findManifestDirs(dir)
15
- await this._start(dirs)
16
-
17
- const server = $http.createServer(async (req, res) => {
18
- const pkgName = req.url.split('/')[1]
19
- const dir = dirs.find(({ name }) => name === pkgName)
20
- if (!dir) {
21
- res.writeHead(404, { 'Content-Type': 'text/plain' })
22
- res.end('404: File Not Found')
23
- return
24
- }
25
- const path = req.url.split('/').slice(2).join('/')
26
- const filePath = $path.join(dir.dir, path)
27
- const contentType = $mime.getType(filePath) || 'application/octet-stream'
28
-
29
- try {
30
- const data = await $fs.readFile(filePath)
31
- res.writeHead(200, { 'Content-Type': contentType })
32
- res.end(data)
33
- } catch (e) {
34
- if (e.code === 'ENOENT') {
35
- res.writeHead(404, { 'Content-Type': 'text/plain' })
36
- res.end('404: File Not Found')
37
- } else {
38
- res.writeHead(500, { 'Content-Type': 'text/plain' })
39
- res.end('500: Internal Server Error')
40
- }
41
- }
42
- })
43
-
44
- const PORT = 3098
45
- server.listen(PORT, () => {
46
- console.log(`Server running at http://localhost:${PORT}/`)
47
- })
48
- },
49
-
50
- async _findManifestDirs(dir) {
51
- const results = []
52
- const variants = ['epos.json', 'epos.yaml', 'epos.yml']
53
- const entries = await $fs.readdir(dir, { withFileTypes: true })
54
-
55
- const manifestEntry = entries.find(e => e.isFile() && variants.includes(e.name))
56
- if (manifestEntry) {
57
- const path = $path.join(dir, manifestEntry.name)
58
- const content = await $fs.readFile(path, 'utf-8')
59
- const isJson = path.endsWith('.json')
60
- const manifest = isJson ? JSON.parse(content) : $yaml.load(content)
61
- if (!manifest.name) throw new Error(`no name in ${path}`)
62
- results.push({ name: manifest.name, dir })
63
- }
64
-
65
- for (const entry of entries) {
66
- if (!entry.isDirectory()) continue
67
- if (entry.name.startsWith('.')) continue
68
- if (entry.name === 'node_modules') continue
69
- const subDir = $path.join(dir, entry.name)
70
- const subResults = await this._findManifestDirs(subDir)
71
- results.push(...subResults)
72
- }
73
-
74
- return results
75
- },
76
-
77
- async _start(dirs, port = 3099) {
78
- const wss = new $ws.WebSocketServer({ port }, () => {
79
- console.log(`WebSocket server started on ws://localhost:${port}`)
80
- })
81
-
82
- const manifestDirs = dirs
83
-
84
- manifestDirs.forEach(({ dir, name }) => {
85
- const watcher = $chokidar.watch(dir, {
86
- ignored: /(node_modules|\.git)/,
87
- ignoreInitial: true,
88
- })
89
-
90
- const broadcast = path => {
91
- console.log('change', path)
92
- const data = JSON.stringify({ name, path: $path.relative(dir, path) })
93
- for (const client of wss.clients) {
94
- if (client.readyState !== 1) continue
95
- client.send(data)
96
- }
97
- }
98
-
99
- watcher.on('add', p => broadcast(p))
100
- watcher.on('change', p => broadcast(p))
101
- watcher.on('unlink', p => broadcast(p))
102
- })
103
- },
104
- }
105
-
106
- $server.init()
5
+ run: (async () => {
6
+ const dir = process.argv[2] || process.cwd()
7
+ await $server.init(dir)
8
+ })()
@@ -0,0 +1,131 @@
1
+ import $fs from 'node:fs/promises'
2
+ import $path from 'path'
3
+ import $http from 'node:http'
4
+ import $mime from 'mime'
5
+ import $yaml from 'js-yaml'
6
+ import $chokidar from 'chokidar'
7
+ import * as $ws from 'ws'
8
+
9
+ const $server = {
10
+ async init(dir = '/Users/imkost/z/epos') {
11
+ this._dir = dir
12
+ this._wsPort = 2217
13
+ this._httpPort = 2218
14
+ this._maxFiles = 10_000
15
+ this._pkgs = {} // { [path]: { name, dir, watcher } }
16
+ await this._start()
17
+ },
18
+
19
+ async _start() {
20
+ const watcherReady = Promise.withResolvers()
21
+ const httpServerReady = Promise.withResolvers()
22
+
23
+ const wss = new $ws.WebSocketServer({ port: this._wsPort })
24
+ const watcher = $chokidar.watch(this._dir, { ignored: this._ignored })
25
+
26
+ // initial scan
27
+ let isInitialScan = true
28
+ let initialFileCount = 0
29
+ watcher.on('all', async (event, path) => {
30
+ if (!isInitialScan) return
31
+ initialFileCount += 1
32
+ if (initialFileCount < this._maxFiles) return
33
+ console.error('⛔ too many files')
34
+ console.error(`More than ${this._maxFiles} files in the directory.`)
35
+ console.error(`Please point to a directory with less files.`)
36
+ process.exit()
37
+ })
38
+ watcher.on('ready', () => {
39
+ isInitialScan = false
40
+ watcherReady.resolve()
41
+ })
42
+
43
+ // watch added manifest files
44
+ const variants = new Set(['epos.json', 'epos.yaml', 'epos.yml'])
45
+ watcher.on('add', async path => {
46
+ const isEposManifest = variants.has($path.basename(path))
47
+ if (!isEposManifest) return
48
+ const pkg = await this._createPkgWatcher(path, wss)
49
+ if (!pkg) return
50
+ this._pkgs[path] = pkg
51
+ })
52
+
53
+ // watch removed manifest files
54
+ watcher.on('unlink', path => {
55
+ if (!this._pkgs[path]) return
56
+ this._pkgs[path].watcher.close()
57
+ delete this._pkgs[path]
58
+ })
59
+
60
+ // static server
61
+ const httpServer = $http.createServer(async (req, res) => {
62
+ const pkgName = req.url.split('/')[1]
63
+ const pkg = Object.values(this._pkgs).find(p => p.name === pkgName)
64
+ if (!pkg) {
65
+ res.writeHead(404, { 'Content-Type': 'text/plain' })
66
+ res.end('404: File Not Found')
67
+ return
68
+ }
69
+
70
+ const filePath = $path.join(pkg.dir, req.url.split('/').slice(2).join('/'))
71
+ const contentType = $mime.getType(filePath) || 'application/octet-stream'
72
+ try {
73
+ const data = await $fs.readFile(filePath)
74
+ res.writeHead(200, { 'Content-Type': contentType })
75
+ res.end(data)
76
+ } catch (e) {
77
+ if (e.code === 'ENOENT') {
78
+ res.writeHead(404, { 'Content-Type': 'text/plain' })
79
+ res.end('404: File Not Found')
80
+ } else {
81
+ res.writeHead(500, { 'Content-Type': 'text/plain' })
82
+ res.end('500: Internal Server Error')
83
+ }
84
+ }
85
+ })
86
+ httpServer.listen(this._httpPort, () => {
87
+ httpServerReady.resolve()
88
+ })
89
+
90
+ await watcherReady.promise
91
+ await httpServerReady.promise
92
+
93
+ console.log('⚡ running')
94
+ },
95
+
96
+ async _createPkgWatcher(manifestPath, wss) {
97
+ const isJson = manifestPath.endsWith('.json')
98
+ const content = await $fs.readFile(manifestPath, 'utf-8')
99
+ const manifest = isJson ? JSON.parse(content) : $yaml.load(content)
100
+ const pkgName = manifest.name
101
+ if (!pkgName) return null
102
+
103
+ const dir = $path.dirname(manifestPath)
104
+ const watcher = $chokidar.watch(dir, {
105
+ ignored: this._ignored,
106
+ ignoreInitial: true,
107
+ })
108
+
109
+ watcher.on('all', (event, path) => {
110
+ const data = JSON.stringify({ name: pkgName, path: $path.relative(dir, path) })
111
+ for (const client of wss.clients) {
112
+ if (client.readyState !== 1) continue
113
+ client.send(data)
114
+ }
115
+ })
116
+
117
+ return {
118
+ watcher,
119
+ name: pkgName,
120
+ dir,
121
+ }
122
+ },
123
+
124
+ _ignored(path) {
125
+ if (path.includes('node_modules')) return true
126
+ if ($path.basename(path).startsWith('.')) return true
127
+ return false
128
+ },
129
+ }
130
+
131
+ export default $server
@@ -1,103 +1,61 @@
1
- declare var Self: {
2
- // base
1
+ declare var self: EposSelf
2
+ declare var Self: EposSelf
3
+
4
+ interface EposSelf {
3
5
  name: string
4
- state: { [key: string]: any }
5
- storage: EposStorage
6
+ state: Record<string, any>
7
+ tabId: number
8
+ browser: Record<string, any>
9
+ root: HTMLElement
10
+ shadow: ShadowRoot
11
+
6
12
  on: (event: string, callback: (...args: any[]) => any) => void
7
13
  off: (event: string, callback?: (...args: any[]) => any) => void
8
14
  send: (event: string, ...args: any[]) => Promise<any>
9
15
  call: (event: string, ...args: any[]) => Promise<any>
10
- tabId: number
11
- browser: { [key: string]: any }
12
- is: { tab: boolean; popup: boolean; sidePanel: boolean; background: boolean }
13
- use: (packageName: string) => any
14
-
15
- // ui
16
+ use: (pkgName: string) => any
17
+ fetch: (url: string, opts?: object) => Promise<object>
16
18
  render: (what: any, container?: HTMLElement | ShadowRoot) => void
17
- portal: (vnode: Object, container: HTMLElement | ShadowRoot) => void
18
- component: EposComponent
19
- root: HTMLElement
20
- shadow: ShadowRoot
21
-
22
- // unit
23
- unit: (name: string, schema: EposUnitSchema) => Function
24
-
25
- // files
26
- files: EposFiles
27
-
28
- // libs
29
- react: Object
30
- reactJsxRuntime: Object
31
- reactDom: Object
32
- reactDomClient: Object
33
- mobx: Object
34
- mobxReact: Object
19
+ portal: (vnode: object, container: HTMLElement | ShadowRoot) => void
20
+
21
+ unit<T extends Record<string, unknown> & { create?: (...args: any[]) => any }>(
22
+ name: string,
23
+ schema: T,
24
+ ): T['create'] extends (...args: infer P) => any ? (...args: P) => T : () => T
25
+
26
+ is: {
27
+ tab: boolean
28
+ popup: boolean
29
+ sidePanel: boolean
30
+ background: boolean
31
+ }
32
+
33
+ component: {
34
+ (render: Function): any
35
+ (name: string, render: Function): any
36
+ (schema: Record<string, any>): any
37
+ (name: string, schema: Record<string, any>): any
38
+ }
39
+
40
+ storage: {
41
+ get(key: string): Promise<any>
42
+ set(key: string, value: any): Promise<void>
43
+ keys(): Promise<string[]>
44
+ remove(key: string): Promise<void>
45
+ clear(): Promise<void>
46
+ connect(name: string): Omit<EposSelf['storage'], 'connect'>
47
+ }
48
+
49
+ files: {
50
+ get: (name: string) => Promise<Blob>
51
+ url: (name: string) => Promise<string>
52
+ text: (name: string) => Promise<string>
53
+ }
54
+
55
+ react: object
56
+ reactJsxRuntime: object
57
+ reactDom: object
58
+ reactDomClient: object
59
+ mobx: object
60
+ mobxReact: object
35
61
  }
36
-
37
- // base
38
- declare var state: typeof Self.state
39
- declare var storage: typeof Self.storage
40
- declare var on: typeof Self.on
41
- declare var off: typeof Self.off
42
- declare var send: typeof Self.send
43
- declare var call: typeof Self.call
44
- declare var is: typeof Self.is
45
- declare var tabId: typeof Self.tabId
46
- declare var browser: typeof Self.browser
47
- declare var use: typeof Self.use
48
-
49
- // ui
50
- declare var render: typeof Self.render
51
- declare var portal: typeof Self.portal
52
- declare var component: typeof Self.component
53
- declare var root: typeof Self.root
54
- declare var shadow: typeof Self.shadow
55
-
56
- // unit
57
- declare var unit: typeof Self.unit
58
-
59
- // files
60
- declare var files: typeof Self.files
61
-
62
- // libs
63
- declare var react: typeof Self.react
64
- declare var reactJsxRuntime: typeof Self.reactJsxRuntime
65
- declare var reactDom: typeof Self.reactDom
66
- declare var reactDomClient: typeof Self.reactDomClient
67
- declare var mobx: typeof Self.mobx
68
- declare var mobxReact: typeof Self.mobxReact
69
-
70
- type EposStorage = EposStorageBase & {
71
- connect: (name: string) => EposStorageBase
72
- }
73
-
74
- type EposStorageBase = {
75
- get: (key: string) => Promise<any>
76
- set: (key: string, value: any) => Promise<void>
77
- keys: () => Promise<string[]>
78
- remove: (key: string) => Promise<void>
79
- clear: () => Promise<void>
80
- }
81
-
82
- // type EposComponent = {
83
- // (name: number, schema: EposComponentSchema): any
84
- // (name: number, render: Function): any
85
- // (schema: EposComponentSchema): any
86
- // (render: Function): any
87
- // }
88
- type EposComponent = (name: number) => any
89
-
90
- type EposComponentSchema = {}
91
-
92
- type EposUnitSchema = {}
93
-
94
- type EposFiles = {
95
- get: (name: string) => Promise<Blob>
96
- url: (name: string) => Promise<string>
97
- text: (name: string) => Promise<string>
98
- }
99
-
100
- // declare function unit<T extends { constructor: (...args: any[]) => void }>(
101
- // name: string,
102
- // definition: T & ThisType<T>,
103
- // ): (...args: Parameters<T['constructor']>) => T