@jayfong/x-server 2.104.0 → 2.105.0
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/lib/_cjs/cli/api_generator.js +8 -8
- package/lib/_cjs/cli/build_util.js +2 -29
- package/lib/_cjs/cli/cli.js +4 -12
- package/lib/_cjs/cli/deploy_util.js +4 -4
- package/lib/_cjs/cli/env_util.js +0 -1
- package/lib/_cjs/cli/template_util.js +13 -23
- package/lib/_cjs/cli/templates/models.ts +20 -10
- package/lib/cli/api_generator.d.ts +4 -4
- package/lib/cli/api_generator.js +2 -2
- package/lib/cli/build_util.d.ts +0 -2
- package/lib/cli/build_util.js +2 -29
- package/lib/cli/cli.js +2 -11
- package/lib/cli/deploy_util.js +1 -1
- package/lib/cli/env_util.js +0 -1
- package/lib/cli/template_util.d.ts +0 -1
- package/lib/cli/template_util.js +4 -14
- package/lib/cli/templates/models.ts +20 -10
- package/package.json +4 -3
|
@@ -4,7 +4,7 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
|
|
|
4
4
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
5
5
|
exports.__esModule = true;
|
|
6
6
|
exports.ApiGenerator = void 0;
|
|
7
|
-
var
|
|
7
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
8
8
|
var _debug = _interopRequireDefault(require("debug"));
|
|
9
9
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
10
10
|
var _tsMorph = _interopRequireWildcard(require("ts-morph"));
|
|
@@ -32,9 +32,9 @@ class ApiGenerator {
|
|
|
32
32
|
}
|
|
33
33
|
async start() {
|
|
34
34
|
this.debug('启动项目...');
|
|
35
|
-
const tsConfigPath =
|
|
36
|
-
const handlersPath =
|
|
37
|
-
const entryFile =
|
|
35
|
+
const tsConfigPath = _nodePath.default.join(this.cwd, 'tsconfig.json');
|
|
36
|
+
const handlersPath = _nodePath.default.join(this.cwd, 'node_modules/.x/handlers.ts');
|
|
37
|
+
const entryFile = _nodePath.default.join(this.cwd, 'src/generated/handlers.ts');
|
|
38
38
|
|
|
39
39
|
// 仅使用 ts-morph 初始化项目
|
|
40
40
|
const moProject = new _tsMorph.default.Project({
|
|
@@ -62,7 +62,7 @@ class ApiGenerator {
|
|
|
62
62
|
const categorySourceFilePath = categorySourceFile.fileName;
|
|
63
63
|
|
|
64
64
|
// 忽略仅开发时生效的路由
|
|
65
|
-
if (/@dev[
|
|
65
|
+
if (/@dev[/.]/.test(categorySourceFilePath)) continue;
|
|
66
66
|
|
|
67
67
|
// 支持 include, exclude
|
|
68
68
|
if (this.options.include?.length) {
|
|
@@ -148,11 +148,11 @@ class ApiGenerator {
|
|
|
148
148
|
}
|
|
149
149
|
this.debug('写入文件...');
|
|
150
150
|
const prefix = this.options.name ? `${this.options.name}_` : '';
|
|
151
|
-
await Promise.all([_fsExtra.default.outputJSON(
|
|
151
|
+
await Promise.all([_fsExtra.default.outputJSON(_nodePath.default.join(this.cwd, `temp/${prefix}api.json`), apiData, {
|
|
152
152
|
spaces: 2
|
|
153
|
-
}), _fsExtra.default.outputJSON(
|
|
153
|
+
}), _fsExtra.default.outputJSON(_nodePath.default.join(this.cwd, `temp/${prefix}yapi.json`), this.apiDataToYApiData(apiData), {
|
|
154
154
|
spaces: 2
|
|
155
|
-
}), _fsExtra.default.outputJSON(
|
|
155
|
+
}), _fsExtra.default.outputJSON(_nodePath.default.join(this.cwd, `temp/${prefix}openapi31.json`), this.apiDataToOpenAPI31Data(apiData), {
|
|
156
156
|
spaces: 2
|
|
157
157
|
})]);
|
|
158
158
|
}
|
|
@@ -9,7 +9,6 @@ var _compressing = _interopRequireDefault(require("compressing"));
|
|
|
9
9
|
var esbuild = _interopRequireWildcard(require("esbuild"));
|
|
10
10
|
var _execa = _interopRequireDefault(require("execa"));
|
|
11
11
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
12
|
-
var _globby = _interopRequireDefault(require("globby"));
|
|
13
12
|
var _vtils = require("vtils");
|
|
14
13
|
class BuildUtil {
|
|
15
14
|
static async build(options) {
|
|
@@ -132,7 +131,7 @@ class BuildUtil {
|
|
|
132
131
|
|
|
133
132
|
// 支持仅开发时生效的路由
|
|
134
133
|
build.onLoad({
|
|
135
|
-
filter: /@dev[
|
|
134
|
+
filter: /@dev[/.]/
|
|
136
135
|
}, async () => {
|
|
137
136
|
return {
|
|
138
137
|
contents: 'module.exports = {}',
|
|
@@ -156,9 +155,7 @@ class BuildUtil {
|
|
|
156
155
|
});
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
|
-
},
|
|
160
|
-
// @ts-ignore
|
|
161
|
-
macrosPlugin()],
|
|
158
|
+
}, macrosPlugin()],
|
|
162
159
|
loader: {
|
|
163
160
|
// 兼容 x-text-render 在服务端使用
|
|
164
161
|
// dev 时用 css_register 兼容
|
|
@@ -180,30 +177,6 @@ class BuildUtil {
|
|
|
180
177
|
const distMultipleSchemaDir = _nodePath.default.join(distDir, _nodePath.default.basename(multipleSchemaDir));
|
|
181
178
|
await _fsExtra.default.copy(multipleSchemaDir, distMultipleSchemaDir);
|
|
182
179
|
}
|
|
183
|
-
if (options.noPrismaEngine) {
|
|
184
|
-
const prismaEngineFiles = await (0, _globby.default)('libquery_engine-*', {
|
|
185
|
-
cwd: distDir,
|
|
186
|
-
onlyFiles: true,
|
|
187
|
-
absolute: true
|
|
188
|
-
});
|
|
189
|
-
await Promise.all(prismaEngineFiles.map(file => _fsExtra.default.remove(file)));
|
|
190
|
-
} else {
|
|
191
|
-
// 复制查询引擎
|
|
192
|
-
const libqueryEngineFiles = await (0, _globby.default)('libquery_engine-*', {
|
|
193
|
-
cwd: _nodePath.default.join(options.cwd, 'node_modules/.prisma/client'),
|
|
194
|
-
ignore: ['libquery_engine-{darwin,windows}*'],
|
|
195
|
-
onlyFiles: true,
|
|
196
|
-
absolute: true
|
|
197
|
-
});
|
|
198
|
-
const prismaCliBinaryTargets = options.prismaCliBinaryTargets?.split(',') || [];
|
|
199
|
-
for (const libqueryEngineFile of libqueryEngineFiles) {
|
|
200
|
-
const libqueryEngineFileBaseName = _nodePath.default.basename(libqueryEngineFile);
|
|
201
|
-
if (prismaCliBinaryTargets.length && prismaCliBinaryTargets.every(prismaCliBinaryTarget => !libqueryEngineFile.includes(prismaCliBinaryTarget))) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
await _fsExtra.default.copyFile(libqueryEngineFile, _nodePath.default.join(distDir, libqueryEngineFileBaseName));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
180
|
}
|
|
208
181
|
|
|
209
182
|
// 写入 pkg
|
package/lib/_cjs/cli/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
5
5
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
6
|
-
var
|
|
6
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
7
7
|
var _chokidar = _interopRequireDefault(require("chokidar"));
|
|
8
8
|
var _execa = _interopRequireDefault(require("execa"));
|
|
9
9
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
@@ -96,7 +96,7 @@ _yargs.default.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
await _template_util.TemplateUtil.init(process.cwd());
|
|
99
|
-
const xsignoreFile =
|
|
99
|
+
const xsignoreFile = _nodePath.default.join(process.cwd(), '.xsignore');
|
|
100
100
|
const xsignoreContent = (await _fsExtra.default.pathExists(xsignoreFile)) ? (await _fsExtra.default.readFile(xsignoreFile, 'utf-8')).trim().split(/[\r\n]+/g).filter(v => v && !v.startsWith('#')) : [];
|
|
101
101
|
const watcher = _chokidar.default.watch(['src', '.env', '.env*'], {
|
|
102
102
|
cwd: process.cwd(),
|
|
@@ -167,12 +167,6 @@ _yargs.default.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
167
167
|
describe: '构建时排除的文件',
|
|
168
168
|
type: 'string',
|
|
169
169
|
array: true
|
|
170
|
-
})
|
|
171
|
-
// 注意:不要加 no 前缀,其会自动处理
|
|
172
|
-
.positional('prisma-engine', {
|
|
173
|
-
describe: '是否包含 Prisma 引擎',
|
|
174
|
-
type: 'boolean',
|
|
175
|
-
default: true
|
|
176
170
|
}).positional('empty-dist-dir', {
|
|
177
171
|
describe: '是否清空构建目录',
|
|
178
172
|
type: 'boolean',
|
|
@@ -225,8 +219,6 @@ _yargs.default.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
225
219
|
onlyCode: true
|
|
226
220
|
});
|
|
227
221
|
}),
|
|
228
|
-
prismaCliBinaryTargets: envMap.PRISMA_CLI_BINARY_TARGETS,
|
|
229
|
-
noPrismaEngine: argv['prisma-engine'] === false,
|
|
230
222
|
noEmptyDistDir: argv['empty-dist-dir'] === false,
|
|
231
223
|
pm2MaxMemoryRestart: deployEnv.MEMORY,
|
|
232
224
|
pm2CronRestart: deployEnv.CRON,
|
|
@@ -306,7 +298,7 @@ _yargs.default.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
306
298
|
|
|
307
299
|
// 多 schema 文件兼容
|
|
308
300
|
// https://www.prisma.io/docs/orm/prisma-schema/overview/location#how-to-use-existing-prisma-cli-commands-with-multiple-prisma-schema-files
|
|
309
|
-
const schemaDir =
|
|
301
|
+
const schemaDir = _nodePath.default.join(process.cwd(), 'src/db/schema');
|
|
310
302
|
const isMultipleFiles = await _fsExtra.default.pathExists(schemaDir);
|
|
311
303
|
const schemaArg = isMultipleFiles ? 'src/db' : 'src/db/schema.prisma';
|
|
312
304
|
await (0, _execa.default)('tnpx', ['prisma', ...argv._.slice(1), '--schema', schemaArg], {
|
|
@@ -377,7 +369,7 @@ _yargs.default.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
377
369
|
channel: '_',
|
|
378
370
|
cb: async channel => {
|
|
379
371
|
if (channel && argv.file) {
|
|
380
|
-
await _fsExtra.default.writeFile(
|
|
372
|
+
await _fsExtra.default.writeFile(_nodePath.default.join(process.cwd(), argv.file), channel);
|
|
381
373
|
}
|
|
382
374
|
console.log(channel || '');
|
|
383
375
|
}
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
4
|
exports.__esModule = true;
|
|
5
5
|
exports.DeployUtil = void 0;
|
|
6
|
-
var
|
|
6
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
7
7
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
8
8
|
var _nodeSsh = require("node-ssh");
|
|
9
9
|
var _vtils = require("vtils");
|
|
10
10
|
class DeployUtil {
|
|
11
11
|
static async deploy(options) {
|
|
12
|
-
const pkgContent = await _fsExtra.default.readJson(
|
|
13
|
-
const appFile =
|
|
12
|
+
const pkgContent = await _fsExtra.default.readJson(_nodePath.default.join(options.cwd, 'package.json'));
|
|
13
|
+
const appFile = _nodePath.default.join(options.cwd, `temp${options.channel ? `/${options.channel}` : ''}/app.${pkgContent.version}.tgz`);
|
|
14
14
|
if (!(await _fsExtra.default.pathExists(appFile))) {
|
|
15
15
|
throw new Error('请先构建');
|
|
16
16
|
}
|
|
@@ -32,7 +32,7 @@ class DeployUtil {
|
|
|
32
32
|
onStdout: buf => console.log(buf.toString()),
|
|
33
33
|
onStderr: buf => console.log(buf.toString())
|
|
34
34
|
});
|
|
35
|
-
const remoteAppFile = `${options.dir}/app_files/${appName}/${options.channel || 'dist'}/${
|
|
35
|
+
const remoteAppFile = `${options.dir}/app_files/${appName}/${options.channel || 'dist'}/${_nodePath.default.basename(appFile)}`;
|
|
36
36
|
await ssh.putFile(appFile, remoteAppFile);
|
|
37
37
|
await ssh.execCommand((0, _vtils.dedent)`
|
|
38
38
|
set -ex
|
package/lib/_cjs/cli/env_util.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
4
|
exports.__esModule = true;
|
|
5
5
|
exports.TemplateUtil = void 0;
|
|
6
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
6
7
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
7
8
|
var _globby = _interopRequireDefault(require("globby"));
|
|
8
|
-
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
var _vscodeGenerateIndexStandalone = require("vscode-generate-index-standalone");
|
|
10
10
|
var _vtils = require("vtils");
|
|
11
11
|
class TemplateUtil {
|
|
@@ -20,10 +20,9 @@ class TemplateUtil {
|
|
|
20
20
|
* 初始化辅助包。
|
|
21
21
|
*/
|
|
22
22
|
static async initHelperPackage(cwd) {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const hasDb = await _fsExtra.default.pathExists(_path.default.join(cwd, 'src/db/schema.prisma'));
|
|
23
|
+
const fromDir = _nodePath.default.join(__dirname, 'templates');
|
|
24
|
+
const toDir = _nodePath.default.join(cwd, 'node_modules/.x');
|
|
25
|
+
const hasDb = await _fsExtra.default.pathExists(_nodePath.default.join(cwd, 'src/db/schema.prisma'));
|
|
27
26
|
const fromFiles = await (0, _globby.default)('*', {
|
|
28
27
|
cwd: fromDir,
|
|
29
28
|
onlyFiles: true,
|
|
@@ -37,7 +36,7 @@ class TemplateUtil {
|
|
|
37
36
|
await _fsExtra.default.writeFile(toFile, 'export {}');
|
|
38
37
|
} else {
|
|
39
38
|
let fromFileContent = await _fsExtra.default.readFile(fromFile, 'utf-8');
|
|
40
|
-
fromFileContent = fromFileContent.replaceAll('
|
|
39
|
+
fromFileContent = fromFileContent.replaceAll('../../src', _nodePath.default.relative(toDir, `${cwd}/src`));
|
|
41
40
|
await _fsExtra.default.writeFile(toFile, fromFileContent);
|
|
42
41
|
}
|
|
43
42
|
}));
|
|
@@ -52,8 +51,8 @@ class TemplateUtil {
|
|
|
52
51
|
* 初始化任务。
|
|
53
52
|
*/
|
|
54
53
|
static async initTasks(cwd) {
|
|
55
|
-
const tasksDir =
|
|
56
|
-
const tasksIndexFile =
|
|
54
|
+
const tasksDir = _nodePath.default.join(cwd, 'src/tasks');
|
|
55
|
+
const tasksIndexFile = _nodePath.default.join(tasksDir, 'index.ts');
|
|
57
56
|
if (!(await _fsExtra.default.pathExists(tasksIndexFile))) {
|
|
58
57
|
await _fsExtra.default.outputFile(tasksIndexFile, (0, _vtils.dedent)`
|
|
59
58
|
// @index(['./**/*.ts', '!**/*.test.ts', '!**/_*'], f => \`export * from '\${f.path}'\`)
|
|
@@ -66,16 +65,16 @@ class TemplateUtil {
|
|
|
66
65
|
* 初始化模型。
|
|
67
66
|
*/
|
|
68
67
|
static async initModels(cwd) {
|
|
69
|
-
const modelsDir =
|
|
70
|
-
const indexFile =
|
|
71
|
-
const indexFile2 =
|
|
72
|
-
const prismaClientFile =
|
|
68
|
+
const modelsDir = _nodePath.default.join(cwd, 'src/models');
|
|
69
|
+
const indexFile = _nodePath.default.join(modelsDir, 'index.ts');
|
|
70
|
+
const indexFile2 = _nodePath.default.join(cwd, 'node_modules/.x/models.ts');
|
|
71
|
+
const prismaClientFile = _nodePath.default.join(cwd, 'node_modules/.x/prisma/internal/prismaNamespace.ts');
|
|
73
72
|
const prismaClientFileContent = await _fsExtra.default.readFile(prismaClientFile, 'utf8');
|
|
74
|
-
const modelNames = [...prismaClientFileContent.match(/(?<=const ModelName
|
|
73
|
+
const modelNames = [...prismaClientFileContent.match(/(?<=const ModelName).+?(?=\})/s)[0].matchAll(/(\S+?):/g)].map(match => (0, _vtils.camelCase)(match[1]));
|
|
75
74
|
await Promise.all(modelNames.map(async modelName => {
|
|
76
75
|
const model_name = (0, _vtils.snakeCase)(modelName);
|
|
77
76
|
const ModelName = (0, _vtils.upperFirst)(modelName);
|
|
78
|
-
const modelFile =
|
|
77
|
+
const modelFile = _nodePath.default.join(modelsDir, `${model_name}.ts`);
|
|
79
78
|
if (!(await _fsExtra.default.pathExists(modelFile))) {
|
|
80
79
|
await _fsExtra.default.outputFile(modelFile, (0, _vtils.dedent)`
|
|
81
80
|
import { ${ModelName}BaseModel } from '@jayfong/x-server'
|
|
@@ -98,14 +97,5 @@ class TemplateUtil {
|
|
|
98
97
|
replaceFile: true
|
|
99
98
|
});
|
|
100
99
|
}
|
|
101
|
-
static getPrismaClientTypeFile() {
|
|
102
|
-
// const prismaClientFile = path.join(
|
|
103
|
-
// cwd,
|
|
104
|
-
// 'node_modules/.prisma/client/index.d.ts',
|
|
105
|
-
// )
|
|
106
|
-
// 用 require.resolve 以兼容 pnpm
|
|
107
|
-
const prismaClientFile = require.resolve('@prisma/client/package.json').replace('@prisma/client/package.json', '.prisma/client/index.d.ts');
|
|
108
|
-
return prismaClientFile;
|
|
109
|
-
}
|
|
110
100
|
}
|
|
111
101
|
exports.TemplateUtil = TemplateUtil;
|
|
@@ -1,23 +1,33 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
1
2
|
import { x } from '@jayfong/x-server';
|
|
2
|
-
import {
|
|
3
|
+
import { PrismaMariaDb } from '@prisma/adapter-mariadb';
|
|
4
|
+
import { type Prisma, PrismaClient } from './prisma/client';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
const dbUri = new URL(process.env.DATABASE_URL!);
|
|
7
|
+
const adapter = new PrismaMariaDb({
|
|
8
|
+
host: dbUri.hostname,
|
|
9
|
+
port: +dbUri.port,
|
|
10
|
+
user: dbUri.username,
|
|
11
|
+
password: dbUri.password,
|
|
12
|
+
database: dbUri.pathname.slice(1),
|
|
13
|
+
});
|
|
14
|
+
export const prismaClient = new PrismaClient({ adapter });
|
|
5
15
|
|
|
6
16
|
x.dispose.add(() => prismaClient.$disconnect());
|
|
7
17
|
|
|
8
18
|
type ModelName =
|
|
9
|
-
// @index('
|
|
19
|
+
// @index('./prisma/internal/prismaNamespace.ts', /(?<=const ModelName).+?(?=\})/s, /(\S+?):/g, (m, _) => `| '${_.camel(m[1])}'`)
|
|
10
20
|
'';
|
|
11
21
|
// @endindex
|
|
12
22
|
|
|
13
|
-
function
|
|
23
|
+
function _makeBaseModel<TModelName extends ModelName>(name: TModelName) {
|
|
14
24
|
return class BaseModel {
|
|
15
25
|
public query = prismaClient[name];
|
|
16
26
|
|
|
17
27
|
public transactionClient: Prisma.TransactionClient | null = null;
|
|
18
28
|
|
|
19
29
|
public transactionify = (tx: Prisma.TransactionClient) => {
|
|
20
|
-
// @ts-
|
|
30
|
+
// @ts-expect-error
|
|
21
31
|
return new (class extends this.constructor {
|
|
22
32
|
public query = tx[name];
|
|
23
33
|
|
|
@@ -37,10 +47,10 @@ function makeBaseModel<TModelName extends ModelName>(name: TModelName) {
|
|
|
37
47
|
};
|
|
38
48
|
}
|
|
39
49
|
|
|
40
|
-
// @index('
|
|
50
|
+
// @index('./prisma/internal/prismaNamespace.ts', /(?<=const ModelName).+?(?=\})/s, /(\S+?):/g, (m, _) => `export const ${m[1]}BaseModel = _makeBaseModel('${_.camel(m[1])}')`)
|
|
41
51
|
// @endindex
|
|
42
52
|
|
|
43
|
-
export * from '
|
|
53
|
+
export * from './prisma/client';
|
|
44
54
|
|
|
45
55
|
export const startTransaction = <T>(
|
|
46
56
|
cb: (
|
|
@@ -49,11 +59,11 @@ export const startTransaction = <T>(
|
|
|
49
59
|
},
|
|
50
60
|
) => Promise<T>,
|
|
51
61
|
): Promise<T> => {
|
|
52
|
-
return prismaClient.$transaction(async
|
|
62
|
+
return prismaClient.$transaction(async _tx => {
|
|
53
63
|
const _models = require('../../src/models');
|
|
54
|
-
const
|
|
64
|
+
const _cache = Object.create(null);
|
|
55
65
|
return cb({
|
|
56
|
-
// @index('
|
|
66
|
+
// @index('./prisma/internal/prismaNamespace.ts', /(?<=const ModelName).+?(?=\})/s, /(\S+?):/g, (m, _) => `get ${_.camel(m[1])}() { return _cache.${_.camel(m[1])} || (_cache.${_.camel(m[1])} = _models.${_.camel(m[1])}Model.transactionify(_tx)) }, `)
|
|
57
67
|
// @endindex
|
|
58
68
|
});
|
|
59
69
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import createDebug from 'debug';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import type { JSONSchema4 } from 'json-schema';
|
|
3
|
+
import type { OpenAPIV3_1 } from 'openapi-types';
|
|
4
4
|
import { ts } from 'ts-morph';
|
|
5
|
-
import { LiteralUnion } from 'vtils/types';
|
|
6
|
-
import {
|
|
5
|
+
import type { LiteralUnion } from 'vtils/types';
|
|
6
|
+
import type { XHandler } from '../core/types';
|
|
7
7
|
/** 注释 */
|
|
8
8
|
type Comment = {
|
|
9
9
|
existing: boolean;
|
package/lib/cli/api_generator.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from 'path';
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import createDebug from 'debug';
|
|
3
3
|
import fs from 'fs-extra';
|
|
4
4
|
import mo, { ts } from 'ts-morph';
|
|
@@ -57,7 +57,7 @@ export class ApiGenerator {
|
|
|
57
57
|
const categorySourceFilePath = categorySourceFile.fileName;
|
|
58
58
|
|
|
59
59
|
// 忽略仅开发时生效的路由
|
|
60
|
-
if (/@dev[
|
|
60
|
+
if (/@dev[/.]/.test(categorySourceFilePath)) continue;
|
|
61
61
|
|
|
62
62
|
// 支持 include, exclude
|
|
63
63
|
if (this.options.include?.length) {
|
package/lib/cli/build_util.d.ts
CHANGED
package/lib/cli/build_util.js
CHANGED
|
@@ -3,7 +3,6 @@ import compressing from 'compressing';
|
|
|
3
3
|
import * as esbuild from 'esbuild';
|
|
4
4
|
import exec from 'execa';
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
|
-
import globby from 'globby';
|
|
7
6
|
import { dedent, uniq } from 'vtils';
|
|
8
7
|
export class BuildUtil {
|
|
9
8
|
static async build(options) {
|
|
@@ -126,7 +125,7 @@ export class BuildUtil {
|
|
|
126
125
|
|
|
127
126
|
// 支持仅开发时生效的路由
|
|
128
127
|
build.onLoad({
|
|
129
|
-
filter: /@dev[
|
|
128
|
+
filter: /@dev[/.]/
|
|
130
129
|
}, async () => {
|
|
131
130
|
return {
|
|
132
131
|
contents: 'module.exports = {}',
|
|
@@ -150,9 +149,7 @@ export class BuildUtil {
|
|
|
150
149
|
});
|
|
151
150
|
}
|
|
152
151
|
}
|
|
153
|
-
},
|
|
154
|
-
// @ts-ignore
|
|
155
|
-
macrosPlugin()],
|
|
152
|
+
}, macrosPlugin()],
|
|
156
153
|
loader: {
|
|
157
154
|
// 兼容 x-text-render 在服务端使用
|
|
158
155
|
// dev 时用 css_register 兼容
|
|
@@ -174,30 +171,6 @@ export class BuildUtil {
|
|
|
174
171
|
const distMultipleSchemaDir = path.join(distDir, path.basename(multipleSchemaDir));
|
|
175
172
|
await fs.copy(multipleSchemaDir, distMultipleSchemaDir);
|
|
176
173
|
}
|
|
177
|
-
if (options.noPrismaEngine) {
|
|
178
|
-
const prismaEngineFiles = await globby('libquery_engine-*', {
|
|
179
|
-
cwd: distDir,
|
|
180
|
-
onlyFiles: true,
|
|
181
|
-
absolute: true
|
|
182
|
-
});
|
|
183
|
-
await Promise.all(prismaEngineFiles.map(file => fs.remove(file)));
|
|
184
|
-
} else {
|
|
185
|
-
// 复制查询引擎
|
|
186
|
-
const libqueryEngineFiles = await globby('libquery_engine-*', {
|
|
187
|
-
cwd: path.join(options.cwd, 'node_modules/.prisma/client'),
|
|
188
|
-
ignore: ['libquery_engine-{darwin,windows}*'],
|
|
189
|
-
onlyFiles: true,
|
|
190
|
-
absolute: true
|
|
191
|
-
});
|
|
192
|
-
const prismaCliBinaryTargets = options.prismaCliBinaryTargets?.split(',') || [];
|
|
193
|
-
for (const libqueryEngineFile of libqueryEngineFiles) {
|
|
194
|
-
const libqueryEngineFileBaseName = path.basename(libqueryEngineFile);
|
|
195
|
-
if (prismaCliBinaryTargets.length && prismaCliBinaryTargets.every(prismaCliBinaryTarget => !libqueryEngineFile.includes(prismaCliBinaryTarget))) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
await fs.copyFile(libqueryEngineFile, path.join(distDir, libqueryEngineFileBaseName));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
174
|
}
|
|
202
175
|
|
|
203
176
|
// 写入 pkg
|
package/lib/cli/cli.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import path from 'path';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import chokidar from 'chokidar';
|
|
4
4
|
import execa from 'execa';
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
6
|
import { generateManyIndex } from 'vscode-generate-index-standalone';
|
|
7
|
-
import { castArray, debounce } from 'vtils';
|
|
8
|
-
import { StringTemplate } from 'vtils';
|
|
9
7
|
import * as vtils from 'vtils';
|
|
8
|
+
import { castArray, debounce, StringTemplate } from 'vtils';
|
|
10
9
|
import yargs from 'yargs';
|
|
11
10
|
import { ApiGenerator } from "./api_generator";
|
|
12
11
|
import { BuildUtil } from "./build_util";
|
|
@@ -164,12 +163,6 @@ yargs.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
164
163
|
describe: '构建时排除的文件',
|
|
165
164
|
type: 'string',
|
|
166
165
|
array: true
|
|
167
|
-
})
|
|
168
|
-
// 注意:不要加 no 前缀,其会自动处理
|
|
169
|
-
.positional('prisma-engine', {
|
|
170
|
-
describe: '是否包含 Prisma 引擎',
|
|
171
|
-
type: 'boolean',
|
|
172
|
-
default: true
|
|
173
166
|
}).positional('empty-dist-dir', {
|
|
174
167
|
describe: '是否清空构建目录',
|
|
175
168
|
type: 'boolean',
|
|
@@ -222,8 +215,6 @@ yargs.command('dev', '开始开发', _ => _.positional('index', {
|
|
|
222
215
|
onlyCode: true
|
|
223
216
|
});
|
|
224
217
|
}),
|
|
225
|
-
prismaCliBinaryTargets: envMap.PRISMA_CLI_BINARY_TARGETS,
|
|
226
|
-
noPrismaEngine: argv['prisma-engine'] === false,
|
|
227
218
|
noEmptyDistDir: argv['empty-dist-dir'] === false,
|
|
228
219
|
pm2MaxMemoryRestart: deployEnv.MEMORY,
|
|
229
220
|
pm2CronRestart: deployEnv.CRON,
|
package/lib/cli/deploy_util.js
CHANGED
package/lib/cli/env_util.js
CHANGED
package/lib/cli/template_util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import fs from 'fs-extra';
|
|
2
3
|
import globby from 'globby';
|
|
3
|
-
import path from 'path';
|
|
4
4
|
import { generateManyIndex } from 'vscode-generate-index-standalone';
|
|
5
5
|
import { camelCase, dedent, snakeCase, upperFirst } from 'vtils';
|
|
6
6
|
export class TemplateUtil {
|
|
@@ -15,7 +15,6 @@ export class TemplateUtil {
|
|
|
15
15
|
* 初始化辅助包。
|
|
16
16
|
*/
|
|
17
17
|
static async initHelperPackage(cwd) {
|
|
18
|
-
const prismaClientFile = TemplateUtil.getPrismaClientTypeFile();
|
|
19
18
|
const fromDir = path.join(__dirname, 'templates');
|
|
20
19
|
const toDir = path.join(cwd, 'node_modules/.x');
|
|
21
20
|
const hasDb = await fs.pathExists(path.join(cwd, 'src/db/schema.prisma'));
|
|
@@ -32,7 +31,7 @@ export class TemplateUtil {
|
|
|
32
31
|
await fs.writeFile(toFile, 'export {}');
|
|
33
32
|
} else {
|
|
34
33
|
let fromFileContent = await fs.readFile(fromFile, 'utf-8');
|
|
35
|
-
fromFileContent = fromFileContent.replaceAll('
|
|
34
|
+
fromFileContent = fromFileContent.replaceAll('../../src', path.relative(toDir, `${cwd}/src`));
|
|
36
35
|
await fs.writeFile(toFile, fromFileContent);
|
|
37
36
|
}
|
|
38
37
|
}));
|
|
@@ -64,9 +63,9 @@ export class TemplateUtil {
|
|
|
64
63
|
const modelsDir = path.join(cwd, 'src/models');
|
|
65
64
|
const indexFile = path.join(modelsDir, 'index.ts');
|
|
66
65
|
const indexFile2 = path.join(cwd, 'node_modules/.x/models.ts');
|
|
67
|
-
const prismaClientFile =
|
|
66
|
+
const prismaClientFile = path.join(cwd, 'node_modules/.x/prisma/internal/prismaNamespace.ts');
|
|
68
67
|
const prismaClientFileContent = await fs.readFile(prismaClientFile, 'utf8');
|
|
69
|
-
const modelNames = [...prismaClientFileContent.match(/(?<=const ModelName
|
|
68
|
+
const modelNames = [...prismaClientFileContent.match(/(?<=const ModelName).+?(?=\})/s)[0].matchAll(/(\S+?):/g)].map(match => camelCase(match[1]));
|
|
70
69
|
await Promise.all(modelNames.map(async modelName => {
|
|
71
70
|
const model_name = snakeCase(modelName);
|
|
72
71
|
const ModelName = upperFirst(modelName);
|
|
@@ -93,13 +92,4 @@ export class TemplateUtil {
|
|
|
93
92
|
replaceFile: true
|
|
94
93
|
});
|
|
95
94
|
}
|
|
96
|
-
static getPrismaClientTypeFile() {
|
|
97
|
-
// const prismaClientFile = path.join(
|
|
98
|
-
// cwd,
|
|
99
|
-
// 'node_modules/.prisma/client/index.d.ts',
|
|
100
|
-
// )
|
|
101
|
-
// 用 require.resolve 以兼容 pnpm
|
|
102
|
-
const prismaClientFile = require.resolve('@prisma/client/package.json').replace('@prisma/client/package.json', '.prisma/client/index.d.ts');
|
|
103
|
-
return prismaClientFile;
|
|
104
|
-
}
|
|
105
95
|
}
|
|
@@ -1,23 +1,33 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
1
2
|
import { x } from '@jayfong/x-server';
|
|
2
|
-
import {
|
|
3
|
+
import { PrismaMariaDb } from '@prisma/adapter-mariadb';
|
|
4
|
+
import { type Prisma, PrismaClient } from './prisma/client';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
const dbUri = new URL(process.env.DATABASE_URL!);
|
|
7
|
+
const adapter = new PrismaMariaDb({
|
|
8
|
+
host: dbUri.hostname,
|
|
9
|
+
port: +dbUri.port,
|
|
10
|
+
user: dbUri.username,
|
|
11
|
+
password: dbUri.password,
|
|
12
|
+
database: dbUri.pathname.slice(1),
|
|
13
|
+
});
|
|
14
|
+
export const prismaClient = new PrismaClient({ adapter });
|
|
5
15
|
|
|
6
16
|
x.dispose.add(() => prismaClient.$disconnect());
|
|
7
17
|
|
|
8
18
|
type ModelName =
|
|
9
|
-
// @index('
|
|
19
|
+
// @index('./prisma/internal/prismaNamespace.ts', /(?<=const ModelName).+?(?=\})/s, /(\S+?):/g, (m, _) => `| '${_.camel(m[1])}'`)
|
|
10
20
|
'';
|
|
11
21
|
// @endindex
|
|
12
22
|
|
|
13
|
-
function
|
|
23
|
+
function _makeBaseModel<TModelName extends ModelName>(name: TModelName) {
|
|
14
24
|
return class BaseModel {
|
|
15
25
|
public query = prismaClient[name];
|
|
16
26
|
|
|
17
27
|
public transactionClient: Prisma.TransactionClient | null = null;
|
|
18
28
|
|
|
19
29
|
public transactionify = (tx: Prisma.TransactionClient) => {
|
|
20
|
-
// @ts-
|
|
30
|
+
// @ts-expect-error
|
|
21
31
|
return new (class extends this.constructor {
|
|
22
32
|
public query = tx[name];
|
|
23
33
|
|
|
@@ -37,10 +47,10 @@ function makeBaseModel<TModelName extends ModelName>(name: TModelName) {
|
|
|
37
47
|
};
|
|
38
48
|
}
|
|
39
49
|
|
|
40
|
-
// @index('
|
|
50
|
+
// @index('./prisma/internal/prismaNamespace.ts', /(?<=const ModelName).+?(?=\})/s, /(\S+?):/g, (m, _) => `export const ${m[1]}BaseModel = _makeBaseModel('${_.camel(m[1])}')`)
|
|
41
51
|
// @endindex
|
|
42
52
|
|
|
43
|
-
export * from '
|
|
53
|
+
export * from './prisma/client';
|
|
44
54
|
|
|
45
55
|
export const startTransaction = <T>(
|
|
46
56
|
cb: (
|
|
@@ -49,11 +59,11 @@ export const startTransaction = <T>(
|
|
|
49
59
|
},
|
|
50
60
|
) => Promise<T>,
|
|
51
61
|
): Promise<T> => {
|
|
52
|
-
return prismaClient.$transaction(async
|
|
62
|
+
return prismaClient.$transaction(async _tx => {
|
|
53
63
|
const _models = require('../../src/models');
|
|
54
|
-
const
|
|
64
|
+
const _cache = Object.create(null);
|
|
55
65
|
return cb({
|
|
56
|
-
// @index('
|
|
66
|
+
// @index('./prisma/internal/prismaNamespace.ts', /(?<=const ModelName).+?(?=\})/s, /(\S+?):/g, (m, _) => `get ${_.camel(m[1])}() { return _cache.${_.camel(m[1])} || (_cache.${_.camel(m[1])} = _models.${_.camel(m[1])}Model.transactionify(_tx)) }, `)
|
|
57
67
|
// @endindex
|
|
58
68
|
});
|
|
59
69
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jayfong/x-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.105.0",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "lib/_cjs/index.js",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"@fastify/formbody": "^7.4.0",
|
|
28
28
|
"@fastify/multipart": "^7.7.0",
|
|
29
29
|
"@fastify/websocket": "^8.1.0",
|
|
30
|
-
"@prisma/
|
|
30
|
+
"@prisma/adapter-mariadb": "^6.17.0",
|
|
31
|
+
"@prisma/client": "^6.17.0",
|
|
31
32
|
"@types/busboy": "^0.3.2",
|
|
32
33
|
"@types/http-errors": "^1.8.2",
|
|
33
34
|
"@types/jsonwebtoken": "^8.5.8",
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
"pino-pretty": "^10.0.1",
|
|
66
67
|
"pinyin-pro": "^3.26.0",
|
|
67
68
|
"pirates": "^4.0.6",
|
|
68
|
-
"prisma": "^6.
|
|
69
|
+
"prisma": "^6.17.0",
|
|
69
70
|
"select-run": "^1.1.2",
|
|
70
71
|
"supports-color": "^8",
|
|
71
72
|
"svg-captcha": "^1.4.0",
|