jax-hono 1.0.20 → 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 +32 -32
- package/bin/jax.js +66 -66
- package/bin/jax.ts +8 -8
- package/build/build.ts +19 -19
- package/build/generate-config.ts +122 -122
- package/build/generate-registry.ts +902 -902
- package/build/generated-path.ts +20 -20
- package/config.ts +68 -68
- package/core/api-controller.ts +290 -290
- package/core/app.ts +207 -207
- package/core/controller.ts +85 -85
- package/core/generated.ts +73 -73
- package/core/hono.ts +63 -63
- package/core/service.ts +44 -44
- package/docs/agent.md +164 -164
- package/docs/jax.md +326 -326
- package/helpers/config.ts +23 -23
- package/helpers/crud.ts +27 -27
- package/helpers/index.ts +4 -4
- package/helpers/route.ts +7 -7
- package/index.ts +121 -121
- package/middleware/api-response.ts +44 -44
- package/middleware/jwt.ts +90 -90
- package/middleware/request-log.ts +3 -3
- package/package.json +129 -124
- package/plugins/config.ts +8 -8
- package/plugins/define.ts +5 -5
- package/plugins/mongoose/index.ts +57 -57
- package/plugins/mongoose/model.ts +322 -322
- package/plugins/mongoose/schema.ts +30 -30
- package/plugins/session/index.ts +86 -86
- package/setup.ts +105 -105
- package/types/config.ts +9 -9
- package/types/context.ts +9 -9
- package/types/index.ts +2 -2
- package/utils/array.ts +7 -7
- package/utils/async.ts +47 -47
- package/utils/crypto.ts +6 -6
- package/utils/http.ts +106 -0
- package/utils/index.ts +3 -2
- package/utils/regexp.ts +14 -14
- package/utils/transform.ts +3 -3
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { Schema, type SchemaDefinitionProperty } from 'mongoose';
|
|
2
|
-
import dayjs from 'dayjs';
|
|
3
|
-
|
|
4
|
-
export const date = (format = 'YYYY-MM-DD HH:mm:ss'): SchemaDefinitionProperty<Date> =>
|
|
5
|
-
({
|
|
6
|
-
type: Date,
|
|
7
|
-
get: (value?: Date) => (value ? dayjs(value).format(format) : value)
|
|
8
|
-
}) as SchemaDefinitionProperty<Date>;
|
|
9
|
-
|
|
10
|
-
export const dateWithDefault = (
|
|
11
|
-
defaultValue: DateConstructor | (() => Date | number | string),
|
|
12
|
-
format = 'YYYY-MM-DD HH:mm:ss'
|
|
13
|
-
): SchemaDefinitionProperty<Date> =>
|
|
14
|
-
({
|
|
15
|
-
type: Date,
|
|
16
|
-
get: (value?: Date) => (value ? dayjs(value).format(format) : value),
|
|
17
|
-
default: defaultValue
|
|
18
|
-
}) as SchemaDefinitionProperty<Date>;
|
|
19
|
-
|
|
20
|
-
export function rankSetter(value: unknown) {
|
|
21
|
-
return value !== '' && value !== undefined && value !== null ? Number(value) : null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export const rankedFields = {
|
|
26
|
-
rank: { type: Number, set: (value: string) => (value != '' ? Number(value) : null) }, // 序号
|
|
27
|
-
isTop: { type: Boolean, default: false }, // 是否置顶,序号设置后自动置顶
|
|
28
|
-
// rank: { type: Number, set: rankSetter },
|
|
29
|
-
// isTop: { type: Boolean, default: false }
|
|
30
|
-
};
|
|
1
|
+
import { Schema, type SchemaDefinitionProperty } from 'mongoose';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
|
|
4
|
+
export const date = (format = 'YYYY-MM-DD HH:mm:ss'): SchemaDefinitionProperty<Date> =>
|
|
5
|
+
({
|
|
6
|
+
type: Date,
|
|
7
|
+
get: (value?: Date) => (value ? dayjs(value).format(format) : value)
|
|
8
|
+
}) as SchemaDefinitionProperty<Date>;
|
|
9
|
+
|
|
10
|
+
export const dateWithDefault = (
|
|
11
|
+
defaultValue: DateConstructor | (() => Date | number | string),
|
|
12
|
+
format = 'YYYY-MM-DD HH:mm:ss'
|
|
13
|
+
): SchemaDefinitionProperty<Date> =>
|
|
14
|
+
({
|
|
15
|
+
type: Date,
|
|
16
|
+
get: (value?: Date) => (value ? dayjs(value).format(format) : value),
|
|
17
|
+
default: defaultValue
|
|
18
|
+
}) as SchemaDefinitionProperty<Date>;
|
|
19
|
+
|
|
20
|
+
export function rankSetter(value: unknown) {
|
|
21
|
+
return value !== '' && value !== undefined && value !== null ? Number(value) : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export const rankedFields = {
|
|
26
|
+
rank: { type: Number, set: (value: string) => (value != '' ? Number(value) : null) }, // 序号
|
|
27
|
+
isTop: { type: Boolean, default: false }, // 是否置顶,序号设置后自动置顶
|
|
28
|
+
// rank: { type: Number, set: rankSetter },
|
|
29
|
+
// isTop: { type: Boolean, default: false }
|
|
30
|
+
};
|
package/plugins/session/index.ts
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import { useSession, useSessionStorage } from '@hono/session';
|
|
2
|
-
import type { Session, SessionData, SessionOptions, Storage } from '@hono/session';
|
|
3
|
-
import type { Context } from 'hono';
|
|
4
|
-
import { definePlugin } from '../define';
|
|
5
|
-
|
|
6
|
-
export type JaxSessionData = SessionData;
|
|
7
|
-
|
|
8
|
-
export type SessionStorageFactory<Data extends SessionData = JaxSessionData> = (
|
|
9
|
-
c: Context
|
|
10
|
-
) => Storage<Data>;
|
|
11
|
-
|
|
12
|
-
export type SessionPluginOptions<Data extends SessionData = JaxSessionData> =
|
|
13
|
-
SessionOptions<Data> & {
|
|
14
|
-
/**
|
|
15
|
-
* Optional backing storage. When omitted, @hono/session keeps session data
|
|
16
|
-
* inside the encrypted cookie.
|
|
17
|
-
*/
|
|
18
|
-
storage?: Storage<Data> | SessionStorageFactory<Data>;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
declare module 'hono' {
|
|
22
|
-
interface ContextVariableMap {
|
|
23
|
-
session: Session<JaxSessionData>;
|
|
24
|
-
sessionStorage?: Storage<JaxSessionData>;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const DEFAULT_SESSION_DURATION = {
|
|
29
|
-
// 会话的有效时间以秒为单位。超过该时间后,会话将失效,需要重新认证才能继续使用。
|
|
30
|
-
absolute: 60 * 60 * 24 * 7 // 7天
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const DEFAULT_SESSION_OPTIONS: SessionPluginOptions = {
|
|
34
|
-
secret: 'jax-session',
|
|
35
|
-
duration: DEFAULT_SESSION_DURATION
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
function isSessionPluginOptions(options: unknown): options is SessionPluginOptions {
|
|
39
|
-
return Boolean(options && typeof options === 'object' && !Array.isArray(options));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function resolveSessionOptions(config: unknown, options: unknown): SessionPluginOptions {
|
|
43
|
-
const configOptions = readConfigSessionOptions(config);
|
|
44
|
-
const pluginOptions = isSessionPluginOptions(options) ? options : {};
|
|
45
|
-
const duration: NonNullable<SessionPluginOptions['duration']> = {
|
|
46
|
-
absolute: DEFAULT_SESSION_DURATION.absolute,
|
|
47
|
-
...configOptions.duration,
|
|
48
|
-
...pluginOptions.duration
|
|
49
|
-
};
|
|
50
|
-
const { storage, ...sessionOptions } = {
|
|
51
|
-
...DEFAULT_SESSION_OPTIONS,
|
|
52
|
-
...configOptions,
|
|
53
|
-
...pluginOptions,
|
|
54
|
-
duration
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
...sessionOptions,
|
|
59
|
-
storage
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function readConfigSessionOptions(config: unknown): SessionPluginOptions {
|
|
64
|
-
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
65
|
-
return {};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const session = (config as { session?: unknown }).session;
|
|
69
|
-
|
|
70
|
-
return isSessionPluginOptions(session) ? session : {};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export default definePlugin({
|
|
74
|
-
setup(ctx, options) {
|
|
75
|
-
const { storage, ...sessionOptions } = resolveSessionOptions(ctx.config, options);
|
|
76
|
-
|
|
77
|
-
if (storage) {
|
|
78
|
-
ctx.app.use(useSessionStorage(storage));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
ctx.app.use(useSession(sessionOptions));
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
export type { Session, SessionData, SessionOptions, Storage };
|
|
86
|
-
export { useSession, useSessionStorage };
|
|
1
|
+
import { useSession, useSessionStorage } from '@hono/session';
|
|
2
|
+
import type { Session, SessionData, SessionOptions, Storage } from '@hono/session';
|
|
3
|
+
import type { Context } from 'hono';
|
|
4
|
+
import { definePlugin } from '../define';
|
|
5
|
+
|
|
6
|
+
export type JaxSessionData = SessionData;
|
|
7
|
+
|
|
8
|
+
export type SessionStorageFactory<Data extends SessionData = JaxSessionData> = (
|
|
9
|
+
c: Context
|
|
10
|
+
) => Storage<Data>;
|
|
11
|
+
|
|
12
|
+
export type SessionPluginOptions<Data extends SessionData = JaxSessionData> =
|
|
13
|
+
SessionOptions<Data> & {
|
|
14
|
+
/**
|
|
15
|
+
* Optional backing storage. When omitted, @hono/session keeps session data
|
|
16
|
+
* inside the encrypted cookie.
|
|
17
|
+
*/
|
|
18
|
+
storage?: Storage<Data> | SessionStorageFactory<Data>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
declare module 'hono' {
|
|
22
|
+
interface ContextVariableMap {
|
|
23
|
+
session: Session<JaxSessionData>;
|
|
24
|
+
sessionStorage?: Storage<JaxSessionData>;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DEFAULT_SESSION_DURATION = {
|
|
29
|
+
// 会话的有效时间以秒为单位。超过该时间后,会话将失效,需要重新认证才能继续使用。
|
|
30
|
+
absolute: 60 * 60 * 24 * 7 // 7天
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DEFAULT_SESSION_OPTIONS: SessionPluginOptions = {
|
|
34
|
+
secret: 'jax-session',
|
|
35
|
+
duration: DEFAULT_SESSION_DURATION
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function isSessionPluginOptions(options: unknown): options is SessionPluginOptions {
|
|
39
|
+
return Boolean(options && typeof options === 'object' && !Array.isArray(options));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolveSessionOptions(config: unknown, options: unknown): SessionPluginOptions {
|
|
43
|
+
const configOptions = readConfigSessionOptions(config);
|
|
44
|
+
const pluginOptions = isSessionPluginOptions(options) ? options : {};
|
|
45
|
+
const duration: NonNullable<SessionPluginOptions['duration']> = {
|
|
46
|
+
absolute: DEFAULT_SESSION_DURATION.absolute,
|
|
47
|
+
...configOptions.duration,
|
|
48
|
+
...pluginOptions.duration
|
|
49
|
+
};
|
|
50
|
+
const { storage, ...sessionOptions } = {
|
|
51
|
+
...DEFAULT_SESSION_OPTIONS,
|
|
52
|
+
...configOptions,
|
|
53
|
+
...pluginOptions,
|
|
54
|
+
duration
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...sessionOptions,
|
|
59
|
+
storage
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function readConfigSessionOptions(config: unknown): SessionPluginOptions {
|
|
64
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const session = (config as { session?: unknown }).session;
|
|
69
|
+
|
|
70
|
+
return isSessionPluginOptions(session) ? session : {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default definePlugin({
|
|
74
|
+
setup(ctx, options) {
|
|
75
|
+
const { storage, ...sessionOptions } = resolveSessionOptions(ctx.config, options);
|
|
76
|
+
|
|
77
|
+
if (storage) {
|
|
78
|
+
ctx.app.use(useSessionStorage(storage));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ctx.app.use(useSession(sessionOptions));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export type { Session, SessionData, SessionOptions, Storage };
|
|
86
|
+
export { useSession, useSessionStorage };
|
package/setup.ts
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import { generateConfig } from "./build/generate-config";
|
|
2
|
-
import { generateRegistry } from "./build/generate-registry";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
5
|
-
import { cwd } from "node:process";
|
|
6
|
-
import { dirname, relative, resolve } from "node:path";
|
|
7
|
-
|
|
8
|
-
function toImportSpecifier(fromDir: string, targetPath: string) {
|
|
9
|
-
const relativePath = relative(fromDir, targetPath).replaceAll("\\", "/");
|
|
10
|
-
|
|
11
|
-
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function escapeRegExp(value: string) {
|
|
15
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function createGeneratedEntrySource(source: string, generatedImportPath: string) {
|
|
19
|
-
const generatedPattern = escapeRegExp(generatedImportPath);
|
|
20
|
-
const sideEffectGeneratedImport = new RegExp(
|
|
21
|
-
`^\\s*import\\s+["']${generatedPattern}(?:/index(?:\\.ts)?)?["'];?\\r?\\n`,
|
|
22
|
-
"m",
|
|
23
|
-
);
|
|
24
|
-
const withoutSideEffectImport = source.replace(sideEffectGeneratedImport, "");
|
|
25
|
-
const jaxImport = /from\s+["']jax-hono["']/;
|
|
26
|
-
|
|
27
|
-
if (jaxImport.test(withoutSideEffectImport)) {
|
|
28
|
-
return withoutSideEffectImport.replace(jaxImport, `from "${generatedImportPath}"`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const generatedImport = new RegExp(`from\\s+["']${generatedPattern}(?:/index(?:\\.ts)?)?["']`);
|
|
32
|
-
|
|
33
|
-
if (generatedImport.test(withoutSideEffectImport)) {
|
|
34
|
-
return withoutSideEffectImport;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
throw new Error('Entry file must import from "jax-hono" so setup can switch it to the generated Jax entry.');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function setupJax() {
|
|
41
|
-
generateConfig();
|
|
42
|
-
generateRegistry();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function runCommand(command: string[]) {
|
|
46
|
-
const [cmd, ...args] = command;
|
|
47
|
-
const proc = Bun.spawn([cmd, ...args], {
|
|
48
|
-
cwd: cwd(),
|
|
49
|
-
stdin: "inherit",
|
|
50
|
-
stdout: "inherit",
|
|
51
|
-
stderr: "inherit",
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return await proc.exited;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export async function setupJaxBuild(entryFile: string, command: string[] = []) {
|
|
58
|
-
setupJax();
|
|
59
|
-
|
|
60
|
-
const projectDir = cwd();
|
|
61
|
-
const entry = resolve(projectDir, entryFile);
|
|
62
|
-
const generatedEntry = resolve(projectDir, ".jax-hono", "index.ts");
|
|
63
|
-
|
|
64
|
-
if (!existsSync(generatedEntry)) {
|
|
65
|
-
throw new Error(".jax-hono/index.ts was not generated. Check setup output.");
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const importPath = toImportSpecifier(dirname(entry), generatedEntry).replace(/\/index\.ts$/, "");
|
|
69
|
-
const source = await readFile(entry, "utf8");
|
|
70
|
-
const nextSource = createGeneratedEntrySource(source, importPath);
|
|
71
|
-
|
|
72
|
-
if (command.length === 0) {
|
|
73
|
-
console.log(`Jax generated entry is ready for ${relative(projectDir, entry)}.`);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (nextSource !== source) {
|
|
78
|
-
await writeFile(entry, nextSource);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
return await runCommand(command);
|
|
83
|
-
} finally {
|
|
84
|
-
if (nextSource !== source) {
|
|
85
|
-
await writeFile(entry, source);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (import.meta.main) {
|
|
91
|
-
const args = Bun.argv.slice(2);
|
|
92
|
-
const entryFile = args[0];
|
|
93
|
-
const commandArgs = args.slice(1);
|
|
94
|
-
const command = commandArgs[0] === "--" ? commandArgs.slice(1) : commandArgs;
|
|
95
|
-
|
|
96
|
-
if (entryFile) {
|
|
97
|
-
const exitCode = await setupJaxBuild(entryFile, command);
|
|
98
|
-
|
|
99
|
-
if (typeof exitCode === "number") {
|
|
100
|
-
process.exit(exitCode);
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
setupJax();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
1
|
+
import { generateConfig } from "./build/generate-config";
|
|
2
|
+
import { generateRegistry } from "./build/generate-registry";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
5
|
+
import { cwd } from "node:process";
|
|
6
|
+
import { dirname, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
function toImportSpecifier(fromDir: string, targetPath: string) {
|
|
9
|
+
const relativePath = relative(fromDir, targetPath).replaceAll("\\", "/");
|
|
10
|
+
|
|
11
|
+
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function escapeRegExp(value: string) {
|
|
15
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createGeneratedEntrySource(source: string, generatedImportPath: string) {
|
|
19
|
+
const generatedPattern = escapeRegExp(generatedImportPath);
|
|
20
|
+
const sideEffectGeneratedImport = new RegExp(
|
|
21
|
+
`^\\s*import\\s+["']${generatedPattern}(?:/index(?:\\.ts)?)?["'];?\\r?\\n`,
|
|
22
|
+
"m",
|
|
23
|
+
);
|
|
24
|
+
const withoutSideEffectImport = source.replace(sideEffectGeneratedImport, "");
|
|
25
|
+
const jaxImport = /from\s+["']jax-hono["']/;
|
|
26
|
+
|
|
27
|
+
if (jaxImport.test(withoutSideEffectImport)) {
|
|
28
|
+
return withoutSideEffectImport.replace(jaxImport, `from "${generatedImportPath}"`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const generatedImport = new RegExp(`from\\s+["']${generatedPattern}(?:/index(?:\\.ts)?)?["']`);
|
|
32
|
+
|
|
33
|
+
if (generatedImport.test(withoutSideEffectImport)) {
|
|
34
|
+
return withoutSideEffectImport;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
throw new Error('Entry file must import from "jax-hono" so setup can switch it to the generated Jax entry.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function setupJax() {
|
|
41
|
+
generateConfig();
|
|
42
|
+
generateRegistry();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function runCommand(command: string[]) {
|
|
46
|
+
const [cmd, ...args] = command;
|
|
47
|
+
const proc = Bun.spawn([cmd, ...args], {
|
|
48
|
+
cwd: cwd(),
|
|
49
|
+
stdin: "inherit",
|
|
50
|
+
stdout: "inherit",
|
|
51
|
+
stderr: "inherit",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return await proc.exited;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function setupJaxBuild(entryFile: string, command: string[] = []) {
|
|
58
|
+
setupJax();
|
|
59
|
+
|
|
60
|
+
const projectDir = cwd();
|
|
61
|
+
const entry = resolve(projectDir, entryFile);
|
|
62
|
+
const generatedEntry = resolve(projectDir, ".jax-hono", "index.ts");
|
|
63
|
+
|
|
64
|
+
if (!existsSync(generatedEntry)) {
|
|
65
|
+
throw new Error(".jax-hono/index.ts was not generated. Check setup output.");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const importPath = toImportSpecifier(dirname(entry), generatedEntry).replace(/\/index\.ts$/, "");
|
|
69
|
+
const source = await readFile(entry, "utf8");
|
|
70
|
+
const nextSource = createGeneratedEntrySource(source, importPath);
|
|
71
|
+
|
|
72
|
+
if (command.length === 0) {
|
|
73
|
+
console.log(`Jax generated entry is ready for ${relative(projectDir, entry)}.`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (nextSource !== source) {
|
|
78
|
+
await writeFile(entry, nextSource);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
return await runCommand(command);
|
|
83
|
+
} finally {
|
|
84
|
+
if (nextSource !== source) {
|
|
85
|
+
await writeFile(entry, source);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (import.meta.main) {
|
|
91
|
+
const args = Bun.argv.slice(2);
|
|
92
|
+
const entryFile = args[0];
|
|
93
|
+
const commandArgs = args.slice(1);
|
|
94
|
+
const command = commandArgs[0] === "--" ? commandArgs.slice(1) : commandArgs;
|
|
95
|
+
|
|
96
|
+
if (entryFile) {
|
|
97
|
+
const exitCode = await setupJaxBuild(entryFile, command);
|
|
98
|
+
|
|
99
|
+
if (typeof exitCode === "number") {
|
|
100
|
+
process.exit(exitCode);
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
setupJax();
|
|
104
|
+
}
|
|
105
|
+
}
|
package/types/config.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { SessionPluginOptions } from '../plugins/session';
|
|
2
|
-
|
|
3
|
-
export type JaxConfig = {
|
|
4
|
-
rootDir: string;
|
|
5
|
-
port: number;
|
|
6
|
-
env: string;
|
|
7
|
-
|
|
8
|
-
session?: SessionPluginOptions;
|
|
9
|
-
};
|
|
1
|
+
import type { SessionPluginOptions } from '../plugins/session';
|
|
2
|
+
|
|
3
|
+
export type JaxConfig = {
|
|
4
|
+
rootDir: string;
|
|
5
|
+
port: number;
|
|
6
|
+
env: string;
|
|
7
|
+
|
|
8
|
+
session?: SessionPluginOptions;
|
|
9
|
+
};
|
package/types/context.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { GeneratedModels, GeneratedServices } from '../core/generated';
|
|
2
|
-
|
|
3
|
-
export type JaxState = Record<string, unknown>;
|
|
4
|
-
|
|
5
|
-
export type JaxContextVariables = {
|
|
6
|
-
model: GeneratedModels;
|
|
7
|
-
service: GeneratedServices;
|
|
8
|
-
state: JaxState;
|
|
9
|
-
};
|
|
1
|
+
import type { GeneratedModels, GeneratedServices } from '../core/generated';
|
|
2
|
+
|
|
3
|
+
export type JaxState = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
export type JaxContextVariables = {
|
|
6
|
+
model: GeneratedModels;
|
|
7
|
+
service: GeneratedServices;
|
|
8
|
+
state: JaxState;
|
|
9
|
+
};
|
package/types/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './context';
|
|
2
|
-
export type { JaxConfig } from './config';
|
|
1
|
+
export * from './context';
|
|
2
|
+
export type { JaxConfig } from './config';
|
package/utils/array.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export function arrayFrom<T>(value: T | T[] | null | undefined): T[] {
|
|
2
|
-
if (value === null || value === undefined || value === '') {
|
|
3
|
-
return [];
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
return Array.isArray(value) ? value : [value];
|
|
7
|
-
}
|
|
1
|
+
export function arrayFrom<T>(value: T | T[] | null | undefined): T[] {
|
|
2
|
+
if (value === null || value === undefined || value === '') {
|
|
3
|
+
return [];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return Array.isArray(value) ? value : [value];
|
|
7
|
+
}
|
package/utils/async.ts
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import pLimit from "p-limit";
|
|
2
|
-
|
|
3
|
-
export { pLimit };
|
|
4
|
-
|
|
5
|
-
export type QueueErrorHandler<T, R> = (
|
|
6
|
-
error: unknown,
|
|
7
|
-
item: T,
|
|
8
|
-
index: number,
|
|
9
|
-
) => Promise<R | T> | R | T;
|
|
10
|
-
|
|
11
|
-
export interface QueueOptions<T, R> {
|
|
12
|
-
concurrency?: number;
|
|
13
|
-
continueOnError?: boolean;
|
|
14
|
-
onError?: QueueErrorHandler<T, R>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function queue<T, R>(
|
|
18
|
-
data: readonly T[],
|
|
19
|
-
fn: (item: T, index: number) => Promise<R> | R,
|
|
20
|
-
options: number | QueueOptions<T, R> = {},
|
|
21
|
-
) {
|
|
22
|
-
const config =
|
|
23
|
-
typeof options === "number" ? { concurrency: options } : options;
|
|
24
|
-
const concurrency = config.concurrency ?? 50;
|
|
25
|
-
const continueOnError = config.continueOnError ?? true;
|
|
26
|
-
const limit = pLimit(concurrency);
|
|
27
|
-
|
|
28
|
-
const input = data.map((item, index) => {
|
|
29
|
-
return limit(async () => {
|
|
30
|
-
try {
|
|
31
|
-
return await fn(item, index);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
if (!continueOnError) {
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
console.error("[queue] task failed:", error);
|
|
38
|
-
|
|
39
|
-
return config.onError ? config.onError(error, item, index) : item;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const result = await Promise.all(input);
|
|
45
|
-
|
|
46
|
-
return result;
|
|
47
|
-
}
|
|
1
|
+
import pLimit from "p-limit";
|
|
2
|
+
|
|
3
|
+
export { pLimit };
|
|
4
|
+
|
|
5
|
+
export type QueueErrorHandler<T, R> = (
|
|
6
|
+
error: unknown,
|
|
7
|
+
item: T,
|
|
8
|
+
index: number,
|
|
9
|
+
) => Promise<R | T> | R | T;
|
|
10
|
+
|
|
11
|
+
export interface QueueOptions<T, R> {
|
|
12
|
+
concurrency?: number;
|
|
13
|
+
continueOnError?: boolean;
|
|
14
|
+
onError?: QueueErrorHandler<T, R>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function queue<T, R>(
|
|
18
|
+
data: readonly T[],
|
|
19
|
+
fn: (item: T, index: number) => Promise<R> | R,
|
|
20
|
+
options: number | QueueOptions<T, R> = {},
|
|
21
|
+
) {
|
|
22
|
+
const config =
|
|
23
|
+
typeof options === "number" ? { concurrency: options } : options;
|
|
24
|
+
const concurrency = config.concurrency ?? 50;
|
|
25
|
+
const continueOnError = config.continueOnError ?? true;
|
|
26
|
+
const limit = pLimit(concurrency);
|
|
27
|
+
|
|
28
|
+
const input = data.map((item, index) => {
|
|
29
|
+
return limit(async () => {
|
|
30
|
+
try {
|
|
31
|
+
return await fn(item, index);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (!continueOnError) {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.error("[queue] task failed:", error);
|
|
38
|
+
|
|
39
|
+
return config.onError ? config.onError(error, item, index) : item;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const result = await Promise.all(input);
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
package/utils/crypto.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
export function md5(value: string) {
|
|
4
|
-
return createHash('md5').update(value).digest('hex');
|
|
5
|
-
}
|
|
6
|
-
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export function md5(value: string) {
|
|
4
|
+
return createHash('md5').update(value).digest('hex');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
7
|
export function createToken(byteLength = 24) {
|
|
8
8
|
return randomBytes(byteLength).toString('hex');
|
|
9
9
|
}
|