jax-hono 1.0.19 → 1.0.21

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/README.md CHANGED
@@ -1,32 +1,32 @@
1
- # Jax-hono
2
-
3
- Jax 是本项目的轻量框架层。完整说明见 [docs/jax.md](docs/jax.md)。
4
-
5
- 给 Codex、Claude 等代码代理看的维护说明见 [docs/agent.md](docs/agent.md)。
6
-
7
- 维护 Jax 内部代码时按目录职责放置文件:
8
-
9
- ```txt
10
- core/ Hono runtime、生命周期、Controller/Service
11
- middleware/ 框架中间件
12
- plugins/ 插件定义、内置插件配置、内置插件实现
13
- build/ 代码生成/扫描注册
14
- helpers/ 框架辅助函数
15
- utils/ 纯工具函数
16
- errors/ 统一错误类型
17
- types/ 框架公共类型
18
- ```
19
-
20
- `.jax-hono` 目录只存在于调用项目中,不放在 `jax-hono` 包内,也不会从包内链接到某个项目。
21
-
22
- 需要 `bun --compile` 的项目可以用 setup 包裹 Bun 构建命令:
23
-
24
- ```powershell
25
- bun node_modules/jax-hono/setup.ts src/index.ts -- bun build src/index.ts --compile --production --target=bun-windows-x64 --outfile dist/app.exe
26
- ```
27
-
28
- setup 会在执行命令期间临时把入口里对 `jax-hono` 的导入切到项目生成入口,命令结束后恢复源码。业务入口仍然写:
29
-
30
- ```ts
31
- import { config, createApp } from 'jax-hono';
32
- ```
1
+ # Jax-hono
2
+
3
+ Jax 是本项目的轻量框架层。完整说明见 [docs/jax.md](docs/jax.md)。
4
+
5
+ 给 Codex、Claude 等代码代理看的维护说明见 [docs/agent.md](docs/agent.md)。
6
+
7
+ 维护 Jax 内部代码时按目录职责放置文件:
8
+
9
+ ```txt
10
+ core/ Hono runtime、生命周期、Controller/Service
11
+ middleware/ 框架中间件
12
+ plugins/ 插件定义、内置插件配置、内置插件实现
13
+ build/ 代码生成/扫描注册
14
+ helpers/ 框架辅助函数
15
+ utils/ 纯工具函数
16
+ errors/ 统一错误类型
17
+ types/ 框架公共类型
18
+ ```
19
+
20
+ `.jax-hono` 目录只存在于调用项目中,不放在 `jax-hono` 包内,也不会从包内链接到某个项目。
21
+
22
+ 需要 `bun --compile` 的项目可以用 setup 包裹 Bun 构建命令:
23
+
24
+ ```powershell
25
+ bun node_modules/jax-hono/setup.ts src/index.ts -- bun build src/index.ts --compile --production --target=bun-windows-x64 --outfile dist/app.exe
26
+ ```
27
+
28
+ setup 会在执行命令期间临时把入口里对 `jax-hono` 的导入切到项目生成入口,命令结束后恢复源码。业务入口仍然写:
29
+
30
+ ```ts
31
+ import { config, createApp } from 'jax-hono';
32
+ ```
package/bin/jax.js CHANGED
@@ -1,66 +1,66 @@
1
- #!/usr/bin/env node
2
-
3
- import { spawn } from "node:child_process";
4
- import { existsSync } from "node:fs";
5
- import path from "node:path";
6
- import { fileURLToPath } from "node:url";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const cliPath = path.join(__dirname, "jax.ts");
11
-
12
- function getBunCommand() {
13
- const candidates = [];
14
-
15
- if (process.env.BUN_INSTALL) {
16
- candidates.push(
17
- path.join(
18
- process.env.BUN_INSTALL,
19
- "bin",
20
- process.platform === "win32" ? "bun.exe" : "bun",
21
- ),
22
- );
23
- }
24
-
25
- if (process.platform === "win32") {
26
- const nodeDir = path.dirname(process.execPath);
27
- candidates.push(
28
- path.join(nodeDir, "bun.exe"),
29
- path.join(nodeDir, "node_modules", "bun", "bin", "bun.exe"),
30
- );
31
- }
32
-
33
- for (const candidate of candidates) {
34
- if (existsSync(candidate)) {
35
- return candidate;
36
- }
37
- }
38
-
39
- return "bun";
40
- }
41
-
42
- const child = spawn(getBunCommand(), [cliPath, ...process.argv.slice(2)], {
43
- stdio: "inherit",
44
- windowsHide: true,
45
- });
46
-
47
- child.on("error", (error) => {
48
- if (error.code === "ENOENT") {
49
- console.error(
50
- "未找到 Bun。请从 https://bun.sh 安装 Bun,或确认 bun 已加入 PATH。",
51
- );
52
- process.exit(1);
53
- }
54
-
55
- console.error(error.message);
56
- process.exit(1);
57
- });
58
-
59
- child.on("exit", (code, signal) => {
60
- if (signal) {
61
- process.kill(process.pid, signal);
62
- return;
63
- }
64
-
65
- process.exit(code ?? 0);
66
- });
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from "node:child_process";
4
+ import { existsSync } from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const cliPath = path.join(__dirname, "jax.ts");
11
+
12
+ function getBunCommand() {
13
+ const candidates = [];
14
+
15
+ if (process.env.BUN_INSTALL) {
16
+ candidates.push(
17
+ path.join(
18
+ process.env.BUN_INSTALL,
19
+ "bin",
20
+ process.platform === "win32" ? "bun.exe" : "bun",
21
+ ),
22
+ );
23
+ }
24
+
25
+ if (process.platform === "win32") {
26
+ const nodeDir = path.dirname(process.execPath);
27
+ candidates.push(
28
+ path.join(nodeDir, "bun.exe"),
29
+ path.join(nodeDir, "node_modules", "bun", "bin", "bun.exe"),
30
+ );
31
+ }
32
+
33
+ for (const candidate of candidates) {
34
+ if (existsSync(candidate)) {
35
+ return candidate;
36
+ }
37
+ }
38
+
39
+ return "bun";
40
+ }
41
+
42
+ const child = spawn(getBunCommand(), [cliPath, ...process.argv.slice(2)], {
43
+ stdio: "inherit",
44
+ windowsHide: true,
45
+ });
46
+
47
+ child.on("error", (error) => {
48
+ if (error.code === "ENOENT") {
49
+ console.error(
50
+ "未找到 Bun。请从 https://bun.sh 安装 Bun,或确认 bun 已加入 PATH。",
51
+ );
52
+ process.exit(1);
53
+ }
54
+
55
+ console.error(error.message);
56
+ process.exit(1);
57
+ });
58
+
59
+ child.on("exit", (code, signal) => {
60
+ if (signal) {
61
+ process.kill(process.pid, signal);
62
+ return;
63
+ }
64
+
65
+ process.exit(code ?? 0);
66
+ });
package/bin/jax.ts CHANGED
@@ -1,5 +1,5 @@
1
- #!/usr/bin/env bun
2
-
1
+ #!/usr/bin/env bun
2
+
3
3
  import { cac } from "cac";
4
4
  import { $ } from "bun";
5
5
  import path from "node:path";
@@ -41,12 +41,12 @@ cli
41
41
  const shouldUseNodeModules =
42
42
  existsSync(path.join(cwd, "package.json")) ||
43
43
  existsSync(path.join(cwd, "node_modules"));
44
- const targetRoot = shouldUseNodeModules
45
- ? path.join(cwd, "node_modules")
46
- : cwd;
47
- const targetName = shouldUseNodeModules ? "jax-hono" : "jax";
48
- const targetDir = path.resolve(targetRoot, targetName);
49
-
44
+ const targetRoot = shouldUseNodeModules
45
+ ? path.join(cwd, "node_modules")
46
+ : cwd;
47
+ const targetName = shouldUseNodeModules ? "jax-hono" : "jax";
48
+ const targetDir = path.resolve(targetRoot, targetName);
49
+
50
50
  if (shouldUseNodeModules) {
51
51
  await mkdir(targetRoot, { recursive: true });
52
52
  }
package/build/build.ts CHANGED
@@ -1,19 +1,19 @@
1
- import { setupJax } from '../setup'
2
-
3
- setupJax()
4
-
5
- const result = await Bun.build({
6
- entrypoints: ['src/index.ts'],
7
- outdir: 'dist',
8
- target: 'bun',
9
- })
10
-
11
- if (!result.success) {
12
- for (const log of result.logs) {
13
- console.error(log)
14
- }
15
-
16
- process.exit(1)
17
- }
18
-
19
- console.log('Build completed.')
1
+ import { setupJax } from '../setup'
2
+
3
+ setupJax()
4
+
5
+ const result = await Bun.build({
6
+ entrypoints: ['src/index.ts'],
7
+ outdir: 'dist',
8
+ target: 'bun',
9
+ })
10
+
11
+ if (!result.success) {
12
+ for (const log of result.logs) {
13
+ console.error(log)
14
+ }
15
+
16
+ process.exit(1)
17
+ }
18
+
19
+ console.log('Build completed.')
@@ -1,122 +1,122 @@
1
- import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
2
- import { cwd } from 'node:process'
3
- import { join, parse, relative } from 'node:path'
4
- import { ensureGeneratedDir, generatedDir, projectDir } from './generated-path'
5
-
6
- const srcDir = join(cwd(), 'src')
7
- const configDir = join(srcDir, 'config')
8
- const typesFile = join(srcDir, 'types/index.ts')
9
- const outputFile = join(generatedDir, 'config.ts')
10
- const envStages = new Set([
11
- 'default',
12
- 'local',
13
- 'dev',
14
- 'development',
15
- 'test',
16
- 'staging',
17
- 'pre',
18
- 'uat',
19
- 'prod',
20
- 'production',
21
- ])
22
-
23
- function toImportName(fileName: string, index: number) {
24
- return `config${index}_${parse(fileName).name.replace(/[^a-zA-Z0-9_$]/g, '_')}`
25
- }
26
-
27
- function getStage(fileName: string) {
28
- const stage = parse(fileName).name.split('.').at(-1)
29
-
30
- if (stage && envStages.has(stage)) {
31
- return stage
32
- }
33
-
34
- return 'base'
35
- }
36
-
37
- function getImportPath(fileName: string) {
38
- const { dir, name } = parse(fileName)
39
- const path = join(configDir, dir, name).replaceAll('\\', '/')
40
-
41
- return path
42
- }
43
-
44
- function getConfigFiles() {
45
- if (!existsSync(configDir)) {
46
- return []
47
- }
48
-
49
- return readdirSync(configDir)
50
- .filter((fileName) => /^config\.[^.]+\.ts$/.test(fileName))
51
- .sort((left, right) => {
52
- const stageWeight: Record<string, number> = {
53
- base: 0,
54
- default: 1,
55
- }
56
-
57
- const diff = (stageWeight[getStage(left)] ?? 2) - (stageWeight[getStage(right)] ?? 2)
58
-
59
- if (diff !== 0) {
60
- return diff
61
- }
62
-
63
- return left.localeCompare(right)
64
- })
65
- }
66
-
67
- function hasProjectConfigType() {
68
- if (!existsSync(typesFile)) {
69
- return false
70
- }
71
-
72
- const source = readFileSync(typesFile, 'utf8')
73
-
74
- return /\bexport\s+(?:type|interface)\s+ProjectConfig\b/.test(source)
75
- }
76
-
77
- export function generateConfig() {
78
- const files = getConfigFiles()
79
- const defaultConfigIndex = files.findIndex((fileName) => getStage(fileName) === 'default')
80
- const imports = files.map((fileName, index) => {
81
- return `import ${toImportName(fileName, index)} from '${getImportPath(fileName)}'`
82
- })
83
- const modules = files.map((fileName, index) => {
84
- return ` { name: '${fileName}', stage: '${getStage(fileName)}', config: ${toImportName(fileName, index)} },`
85
- })
86
- const hasProjectTypes = hasProjectConfigType()
87
- const typeImports = hasProjectTypes ? [`import type { ProjectConfig } from '${join(srcDir, 'types').replaceAll('\\', '/')}'`] : []
88
- const projectConfigType = hasProjectTypes
89
- ? 'export type { ProjectConfig }'
90
- : defaultConfigIndex === -1
91
- ? 'export type ProjectConfig = Record<string, unknown>'
92
- : `export type ProjectConfig = typeof ${toImportName(files[defaultConfigIndex], defaultConfigIndex)}`
93
- const content = `${[...typeImports, ...imports].join('\n')}
94
-
95
- export const configModules = [
96
- ${modules.join('\n')}
97
- ] as const
98
-
99
- ${projectConfigType}
100
-
101
- declare module 'jax-hono/core/generated' {
102
- interface JaxGenerated {
103
- config: ProjectConfig
104
- }
105
- }
106
-
107
- export default configModules
108
- `
109
-
110
- ensureGeneratedDir()
111
-
112
- if (existsSync(outputFile) && readFileSync(outputFile, 'utf8') === content) {
113
- return
114
- }
115
-
116
- writeFileSync(outputFile, content)
117
- console.log(`Generated ${relative(projectDir, outputFile)} with ${files.length} config file(s).`)
118
- }
119
-
120
- if (import.meta.main) {
121
- generateConfig()
122
- }
1
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
2
+ import { cwd } from 'node:process'
3
+ import { join, parse, relative } from 'node:path'
4
+ import { ensureGeneratedDir, generatedDir, projectDir } from './generated-path'
5
+
6
+ const srcDir = join(cwd(), 'src')
7
+ const configDir = join(srcDir, 'config')
8
+ const typesFile = join(srcDir, 'types/index.ts')
9
+ const outputFile = join(generatedDir, 'config.ts')
10
+ const envStages = new Set([
11
+ 'default',
12
+ 'local',
13
+ 'dev',
14
+ 'development',
15
+ 'test',
16
+ 'staging',
17
+ 'pre',
18
+ 'uat',
19
+ 'prod',
20
+ 'production',
21
+ ])
22
+
23
+ function toImportName(fileName: string, index: number) {
24
+ return `config${index}_${parse(fileName).name.replace(/[^a-zA-Z0-9_$]/g, '_')}`
25
+ }
26
+
27
+ function getStage(fileName: string) {
28
+ const stage = parse(fileName).name.split('.').at(-1)
29
+
30
+ if (stage && envStages.has(stage)) {
31
+ return stage
32
+ }
33
+
34
+ return 'base'
35
+ }
36
+
37
+ function getImportPath(fileName: string) {
38
+ const { dir, name } = parse(fileName)
39
+ const path = join(configDir, dir, name).replaceAll('\\', '/')
40
+
41
+ return path
42
+ }
43
+
44
+ function getConfigFiles() {
45
+ if (!existsSync(configDir)) {
46
+ return []
47
+ }
48
+
49
+ return readdirSync(configDir)
50
+ .filter((fileName) => /^config\.[^.]+\.ts$/.test(fileName))
51
+ .sort((left, right) => {
52
+ const stageWeight: Record<string, number> = {
53
+ base: 0,
54
+ default: 1,
55
+ }
56
+
57
+ const diff = (stageWeight[getStage(left)] ?? 2) - (stageWeight[getStage(right)] ?? 2)
58
+
59
+ if (diff !== 0) {
60
+ return diff
61
+ }
62
+
63
+ return left.localeCompare(right)
64
+ })
65
+ }
66
+
67
+ function hasProjectConfigType() {
68
+ if (!existsSync(typesFile)) {
69
+ return false
70
+ }
71
+
72
+ const source = readFileSync(typesFile, 'utf8')
73
+
74
+ return /\bexport\s+(?:type|interface)\s+ProjectConfig\b/.test(source)
75
+ }
76
+
77
+ export function generateConfig() {
78
+ const files = getConfigFiles()
79
+ const defaultConfigIndex = files.findIndex((fileName) => getStage(fileName) === 'default')
80
+ const imports = files.map((fileName, index) => {
81
+ return `import ${toImportName(fileName, index)} from '${getImportPath(fileName)}'`
82
+ })
83
+ const modules = files.map((fileName, index) => {
84
+ return ` { name: '${fileName}', stage: '${getStage(fileName)}', config: ${toImportName(fileName, index)} },`
85
+ })
86
+ const hasProjectTypes = hasProjectConfigType()
87
+ const typeImports = hasProjectTypes ? [`import type { ProjectConfig } from '${join(srcDir, 'types').replaceAll('\\', '/')}'`] : []
88
+ const projectConfigType = hasProjectTypes
89
+ ? 'export type { ProjectConfig }'
90
+ : defaultConfigIndex === -1
91
+ ? 'export type ProjectConfig = Record<string, unknown>'
92
+ : `export type ProjectConfig = typeof ${toImportName(files[defaultConfigIndex], defaultConfigIndex)}`
93
+ const content = `${[...typeImports, ...imports].join('\n')}
94
+
95
+ export const configModules = [
96
+ ${modules.join('\n')}
97
+ ] as const
98
+
99
+ ${projectConfigType}
100
+
101
+ declare module 'jax-hono/core/generated' {
102
+ interface JaxGenerated {
103
+ config: ProjectConfig
104
+ }
105
+ }
106
+
107
+ export default configModules
108
+ `
109
+
110
+ ensureGeneratedDir()
111
+
112
+ if (existsSync(outputFile) && readFileSync(outputFile, 'utf8') === content) {
113
+ return
114
+ }
115
+
116
+ writeFileSync(outputFile, content)
117
+ console.log(`Generated ${relative(projectDir, outputFile)} with ${files.length} config file(s).`)
118
+ }
119
+
120
+ if (import.meta.main) {
121
+ generateConfig()
122
+ }