proteum 2.1.0 → 2.1.2
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/AGENTS.md +44 -98
- package/README.md +143 -10
- package/agents/framework/AGENTS.md +146 -886
- package/agents/project/AGENTS.md +73 -127
- package/agents/project/client/AGENTS.md +22 -93
- package/agents/project/client/pages/AGENTS.md +24 -26
- package/agents/project/server/routes/AGENTS.md +10 -8
- package/agents/project/server/services/AGENTS.md +22 -159
- package/agents/project/tests/AGENTS.md +11 -8
- package/cli/app/config.ts +7 -20
- package/cli/bin.js +8 -0
- package/cli/commands/command.ts +243 -0
- package/cli/commands/commandLocalRunner.js +198 -0
- package/cli/commands/create.ts +5 -0
- package/cli/commands/deploy/web.ts +1 -2
- package/cli/commands/dev.ts +98 -2
- package/cli/commands/doctor.ts +8 -74
- package/cli/commands/explain.ts +8 -186
- package/cli/commands/init.ts +2 -94
- package/cli/commands/trace.ts +228 -0
- package/cli/compiler/artifacts/commands.ts +217 -0
- package/cli/compiler/artifacts/manifest.ts +35 -21
- package/cli/compiler/artifacts/services.ts +300 -1
- package/cli/compiler/client/index.ts +43 -8
- package/cli/compiler/common/commands.ts +175 -0
- package/cli/compiler/common/index.ts +1 -1
- package/cli/compiler/common/proteumManifest.ts +15 -114
- package/cli/compiler/index.ts +25 -2
- package/cli/compiler/server/index.ts +31 -6
- package/cli/index.ts +1 -4
- package/cli/paths.ts +16 -1
- package/cli/presentation/commands.ts +104 -14
- package/cli/presentation/devSession.ts +22 -3
- package/cli/presentation/proteum_logo_400x400_square_icon.txt +400 -0
- package/cli/runtime/commands.ts +121 -4
- package/cli/scaffold/index.ts +720 -0
- package/cli/scaffold/templates.ts +344 -0
- package/cli/scaffold/types.ts +26 -0
- package/cli/tsconfig.json +4 -1
- package/cli/utils/check.ts +1 -1
- package/client/app/component.tsx +13 -9
- package/client/dev/profiler/index.tsx +2511 -0
- package/client/dev/profiler/noop.tsx +5 -0
- package/client/dev/profiler/runtime.noop.ts +116 -0
- package/client/dev/profiler/runtime.ts +840 -0
- package/client/services/router/components/router.tsx +30 -2
- package/client/services/router/index.tsx +27 -3
- package/client/services/router/request/api.ts +133 -17
- package/commands/proteum/diagnostics.ts +11 -0
- package/common/dev/commands.ts +50 -0
- package/common/dev/diagnostics.ts +298 -0
- package/common/dev/profiler.ts +92 -0
- package/common/dev/proteumManifest.ts +135 -0
- package/common/dev/requestTrace.ts +115 -0
- package/common/env/proteumEnv.ts +284 -0
- package/common/router/index.ts +4 -22
- package/docs/dev-commands.md +93 -0
- package/docs/diagnostics.md +88 -0
- package/docs/request-tracing.md +132 -0
- package/eslint.js +11 -6
- package/package.json +3 -3
- package/server/app/commands.ts +35 -370
- package/server/app/commandsManager.ts +393 -0
- package/server/app/container/config.ts +11 -49
- package/server/app/container/console/index.ts +2 -3
- package/server/app/container/index.ts +5 -2
- package/server/app/container/trace/index.ts +364 -0
- package/server/app/devCommands.ts +192 -0
- package/server/app/devDiagnostics.ts +53 -0
- package/server/app/index.ts +29 -6
- package/server/index.ts +0 -1
- package/server/services/auth/index.ts +525 -61
- package/server/services/auth/router/index.ts +106 -7
- package/server/services/cron/CronTask.ts +73 -5
- package/server/services/cron/index.ts +34 -11
- package/server/services/fetch/index.ts +3 -10
- package/server/services/prisma/index.ts +66 -4
- package/server/services/router/http/index.ts +173 -6
- package/server/services/router/index.ts +200 -12
- package/server/services/router/request/api.ts +30 -1
- package/server/services/router/response/index.ts +83 -10
- package/server/services/router/response/page/document.tsx +16 -0
- package/server/services/router/response/page/index.tsx +27 -1
- package/skills/clean-project-code/SKILL.md +7 -2
- package/test-results/.last-run.json +4 -0
- package/types/aliases.d.ts +6 -0
- package/types/global/utils.d.ts +7 -14
- package/Rte.zip +0 -0
- package/agents/project/agents.md.zip +0 -0
- package/doc/TODO.md +0 -71
- package/doc/front/router.md +0 -27
- package/doc/workspace/workspace.png +0 -0
- package/doc/workspace/workspace2.png +0 -0
- package/doc/workspace/workspace_26.01.22.png +0 -0
- package/server/services/router/http/session.ts.old +0 -40
|
@@ -27,6 +27,24 @@ const hmrClientEntry = path.join(cli.paths.core.root, 'client', 'dev', 'hmr.ts')
|
|
|
27
27
|
const normalizeModulePath = (value?: string) => (value || '').replace(/\\/g, '/');
|
|
28
28
|
const resolveFromAppOrCore = (app: App, request: string) =>
|
|
29
29
|
require.resolve(request, { paths: [app.paths.root, cli.paths.core.root] });
|
|
30
|
+
const rewriteFrameworkAliasTargets = (app: App, aliases: Record<string, string | string[]>) => {
|
|
31
|
+
const installedCoreRoot = normalizeModulePath(path.join(app.paths.root, 'node_modules', 'proteum'));
|
|
32
|
+
const activeCoreRoot = normalizeModulePath(cli.paths.core.root);
|
|
33
|
+
|
|
34
|
+
if (installedCoreRoot === activeCoreRoot) return aliases;
|
|
35
|
+
|
|
36
|
+
const rewriteCandidate = (candidate: string) =>
|
|
37
|
+
normalizeModulePath(candidate).startsWith(installedCoreRoot + '/')
|
|
38
|
+
? activeCoreRoot + normalizeModulePath(candidate).substring(installedCoreRoot.length)
|
|
39
|
+
: candidate;
|
|
40
|
+
|
|
41
|
+
return Object.fromEntries(
|
|
42
|
+
Object.entries(aliases).map(([alias, value]) => [
|
|
43
|
+
alias,
|
|
44
|
+
Array.isArray(value) ? value.map(rewriteCandidate) : rewriteCandidate(value),
|
|
45
|
+
]),
|
|
46
|
+
);
|
|
47
|
+
};
|
|
30
48
|
|
|
31
49
|
const getModulePath = (module: Module) => {
|
|
32
50
|
const resource = typeof module.nameForCondition === 'function' ? module.nameForCondition() : undefined;
|
|
@@ -58,6 +76,8 @@ export default function createCompiler(
|
|
|
58
76
|
logVerbose(`Creating compiler for client (${mode}).`);
|
|
59
77
|
const dev = mode === 'dev';
|
|
60
78
|
const outputPath = app.outputPath(outputTarget);
|
|
79
|
+
const installedCoreRoot = path.join(app.paths.root, 'node_modules', 'proteum');
|
|
80
|
+
const frameworkRoots = [cli.paths.core.root, installedCoreRoot];
|
|
61
81
|
|
|
62
82
|
const commonConfig = createCommonConfig(app, 'client', mode, outputTarget);
|
|
63
83
|
|
|
@@ -73,11 +93,12 @@ export default function createCompiler(
|
|
|
73
93
|
|
|
74
94
|
// Convert tsconfig paths into bundler aliases.
|
|
75
95
|
const { aliases } = app.aliases.client.forWebpack({ modulesPath: app.paths.root + '/node_modules' });
|
|
96
|
+
const resolvedAliases = rewriteFrameworkAliasTargets(app, aliases);
|
|
76
97
|
|
|
77
98
|
// We're not supposed in any case to import server libs from client
|
|
78
|
-
delete
|
|
79
|
-
delete
|
|
80
|
-
const rspackAliases = toRspackAliases(
|
|
99
|
+
delete resolvedAliases['@server'];
|
|
100
|
+
delete resolvedAliases['@/server'];
|
|
101
|
+
const rspackAliases = toRspackAliases(resolvedAliases);
|
|
81
102
|
rspackAliases['@/client/router$'] = cli.paths.core.root + '/client/router.ts';
|
|
82
103
|
rspackAliases['preact/jsx-runtime$'] = resolveFromAppOrCore(app, 'preact/jsx-runtime');
|
|
83
104
|
rspackAliases['react/jsx-runtime$'] = resolveFromAppOrCore(app, 'preact/jsx-runtime');
|
|
@@ -133,16 +154,16 @@ export default function createCompiler(
|
|
|
133
154
|
test: ssrScriptPattern,
|
|
134
155
|
include: [
|
|
135
156
|
app.paths.root + '/client',
|
|
136
|
-
cli.paths.core.root + '/client',
|
|
137
157
|
app.paths.client.generated,
|
|
138
158
|
|
|
139
159
|
app.paths.root + '/common',
|
|
140
|
-
cli.paths.core.root + '/common',
|
|
141
160
|
app.paths.common.generated,
|
|
142
161
|
|
|
143
162
|
app.paths.root + '/server',
|
|
144
|
-
cli.paths.core.root + '/server',
|
|
145
163
|
app.paths.server.generated,
|
|
164
|
+
...frameworkRoots.map((rootPath) => rootPath + '/client'),
|
|
165
|
+
...frameworkRoots.map((rootPath) => rootPath + '/common'),
|
|
166
|
+
...frameworkRoots.map((rootPath) => rootPath + '/server'),
|
|
146
167
|
],
|
|
147
168
|
loader: path.join(
|
|
148
169
|
cli.paths.core.root,
|
|
@@ -157,17 +178,18 @@ export default function createCompiler(
|
|
|
157
178
|
test: regex.scripts,
|
|
158
179
|
include: [
|
|
159
180
|
app.paths.root + '/client',
|
|
160
|
-
cli.paths.core.root + '/client',
|
|
161
181
|
app.paths.client.generated,
|
|
162
182
|
|
|
163
183
|
app.paths.root + '/common',
|
|
164
|
-
cli.paths.core.root + '/common',
|
|
165
184
|
app.paths.common.generated,
|
|
166
185
|
|
|
167
186
|
// Prisma 7 generates browser-safe TypeScript entrypoints under var/prisma.
|
|
168
187
|
app.paths.root + '/var/prisma',
|
|
169
188
|
|
|
170
189
|
app.paths.server.generated + '/models.ts',
|
|
190
|
+
...frameworkRoots.map((rootPath) => rootPath + '/client'),
|
|
191
|
+
...frameworkRoots.map((rootPath) => rootPath + '/common'),
|
|
192
|
+
...frameworkRoots.map((rootPath) => rootPath + '/server'),
|
|
171
193
|
],
|
|
172
194
|
rules: require('../common/scripts')({ app, side: 'client', dev }),
|
|
173
195
|
},
|
|
@@ -199,6 +221,19 @@ export default function createCompiler(
|
|
|
199
221
|
plugins: [
|
|
200
222
|
...(commonConfig.plugins || []),
|
|
201
223
|
|
|
224
|
+
...(dev
|
|
225
|
+
? []
|
|
226
|
+
: [
|
|
227
|
+
new rspack.NormalModuleReplacementPlugin(
|
|
228
|
+
/^@client\/dev\/profiler$/,
|
|
229
|
+
cli.paths.core.root + '/client/dev/profiler/noop.tsx',
|
|
230
|
+
),
|
|
231
|
+
new rspack.NormalModuleReplacementPlugin(
|
|
232
|
+
/^@client\/dev\/profiler\/runtime$/,
|
|
233
|
+
cli.paths.core.root + '/client/dev/profiler/runtime.noop.ts',
|
|
234
|
+
),
|
|
235
|
+
]),
|
|
236
|
+
|
|
202
237
|
// Extract CSS in dev too so SSR emits the same stylesheet links as production.
|
|
203
238
|
new rspack.CssExtractRspackPlugin({}),
|
|
204
239
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
|
|
5
|
+
export type TCommandSourceLocation = { line: number; column: number };
|
|
6
|
+
|
|
7
|
+
export type TCommandMethodMeta = {
|
|
8
|
+
name: string;
|
|
9
|
+
path: string;
|
|
10
|
+
sourceLocation: TCommandSourceLocation;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type TCommandFileMeta = {
|
|
14
|
+
importPath: string;
|
|
15
|
+
filepath: string;
|
|
16
|
+
className: string;
|
|
17
|
+
commandBasePath: string;
|
|
18
|
+
methods: TCommandMethodMeta[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type TCommandSearchDir = { importPrefix: string; root: string };
|
|
22
|
+
|
|
23
|
+
const getCommandSegments = (relativePath: string) => {
|
|
24
|
+
const segments = relativePath
|
|
25
|
+
.replace(/\.ts$/, '')
|
|
26
|
+
.split('/')
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
|
|
29
|
+
if (segments[segments.length - 1] === 'index') {
|
|
30
|
+
segments.pop();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return segments;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getCommandBasePathFromFilepath = (filepath: string, root: string) =>
|
|
37
|
+
getCommandSegments(path.relative(root, filepath).replace(/\\/g, '/')).join('/');
|
|
38
|
+
|
|
39
|
+
const getGeneratedClassName = (filepath: string) => {
|
|
40
|
+
const filename = path.basename(filepath, '.ts').replace(/[^A-Za-z0-9_$]+/g, '_');
|
|
41
|
+
const normalized = filename.length ? filename : 'Commands';
|
|
42
|
+
|
|
43
|
+
return normalized[0].toUpperCase() + normalized.substring(1);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const buildImportPath = (searchDir: TCommandSearchDir, filepath: string) =>
|
|
47
|
+
searchDir.importPrefix + path.relative(searchDir.root, filepath).replace(/\\/g, '/').replace(/\.ts$/, '');
|
|
48
|
+
|
|
49
|
+
const findCommandFiles = (dir: string): string[] => {
|
|
50
|
+
if (!fs.existsSync(dir)) return [];
|
|
51
|
+
|
|
52
|
+
const files: string[] = [];
|
|
53
|
+
|
|
54
|
+
for (const dirent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
55
|
+
const filepath = path.join(dir, dirent.name);
|
|
56
|
+
|
|
57
|
+
if (dirent.isDirectory()) {
|
|
58
|
+
files.push(...findCommandFiles(filepath));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!dirent.isFile()) continue;
|
|
63
|
+
if (!dirent.name.endsWith('.ts')) continue;
|
|
64
|
+
if (dirent.name.endsWith('.d.ts')) continue;
|
|
65
|
+
|
|
66
|
+
files.push(filepath);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return files;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const parseSourceFile = (filepath: string, code: string) =>
|
|
73
|
+
ts.createSourceFile(
|
|
74
|
+
filepath,
|
|
75
|
+
code,
|
|
76
|
+
ts.ScriptTarget.Latest,
|
|
77
|
+
true,
|
|
78
|
+
filepath.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const getNodeLocation = (sourceFile: ts.SourceFile, node: ts.Node): TCommandSourceLocation => {
|
|
82
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
83
|
+
|
|
84
|
+
return { line: line + 1, column: character + 1 };
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const hasModifier = (node: ts.Node, kind: ts.SyntaxKind) =>
|
|
88
|
+
!!node.modifiers?.some((modifier) => modifier.kind === kind);
|
|
89
|
+
|
|
90
|
+
const getDefaultExportClass = (sourceFile: ts.SourceFile) => {
|
|
91
|
+
const classes = new Map<string, ts.ClassDeclaration>();
|
|
92
|
+
|
|
93
|
+
for (const statement of sourceFile.statements) {
|
|
94
|
+
if (ts.isClassDeclaration(statement) && statement.name) {
|
|
95
|
+
classes.set(statement.name.text, statement);
|
|
96
|
+
|
|
97
|
+
if (hasModifier(statement, ts.SyntaxKind.DefaultKeyword)) {
|
|
98
|
+
return statement;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const statement of sourceFile.statements) {
|
|
104
|
+
if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue;
|
|
105
|
+
|
|
106
|
+
if (ts.isIdentifier(statement.expression)) {
|
|
107
|
+
return classes.get(statement.expression.text);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return undefined;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const getExportedString = (sourceFile: ts.SourceFile, exportName: string) => {
|
|
115
|
+
for (const statement of sourceFile.statements) {
|
|
116
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
117
|
+
if (!hasModifier(statement, ts.SyntaxKind.ExportKeyword)) continue;
|
|
118
|
+
|
|
119
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
120
|
+
if (!ts.isIdentifier(declaration.name)) continue;
|
|
121
|
+
if (declaration.name.text !== exportName) continue;
|
|
122
|
+
if (!declaration.initializer || !ts.isStringLiteral(declaration.initializer)) continue;
|
|
123
|
+
|
|
124
|
+
return declaration.initializer.text;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return undefined;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const indexCommands = (searchDirs: TCommandSearchDir[]) => {
|
|
132
|
+
const commands: TCommandFileMeta[] = [];
|
|
133
|
+
|
|
134
|
+
for (const searchDir of searchDirs) {
|
|
135
|
+
const commandFiles = findCommandFiles(searchDir.root);
|
|
136
|
+
|
|
137
|
+
for (const filepath of commandFiles.sort((a, b) => a.localeCompare(b))) {
|
|
138
|
+
const code = fs.readFileSync(filepath, 'utf8');
|
|
139
|
+
const sourceFile = parseSourceFile(filepath, code);
|
|
140
|
+
|
|
141
|
+
const commandPathOverride = getExportedString(sourceFile, 'commandPath');
|
|
142
|
+
const defaultClass = getDefaultExportClass(sourceFile);
|
|
143
|
+
|
|
144
|
+
if (!defaultClass) continue;
|
|
145
|
+
|
|
146
|
+
const className = defaultClass.name?.text || getGeneratedClassName(filepath);
|
|
147
|
+
const commandBasePath = commandPathOverride || getCommandBasePathFromFilepath(filepath, searchDir.root);
|
|
148
|
+
const methods: TCommandMethodMeta[] = [];
|
|
149
|
+
|
|
150
|
+
for (const member of defaultClass.members) {
|
|
151
|
+
if (!ts.isMethodDeclaration(member)) continue;
|
|
152
|
+
if (!member.body) continue;
|
|
153
|
+
if (!member.name || !ts.isIdentifier(member.name)) continue;
|
|
154
|
+
|
|
155
|
+
methods.push({
|
|
156
|
+
name: member.name.text,
|
|
157
|
+
path: [commandBasePath, member.name.text].filter(Boolean).join('/'),
|
|
158
|
+
sourceLocation: getNodeLocation(sourceFile, member.name),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!methods.length) continue;
|
|
163
|
+
|
|
164
|
+
commands.push({
|
|
165
|
+
filepath,
|
|
166
|
+
importPath: buildImportPath(searchDir, filepath),
|
|
167
|
+
className,
|
|
168
|
+
commandBasePath,
|
|
169
|
+
methods,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return commands.sort((a, b) => a.filepath.localeCompare(b.filepath));
|
|
175
|
+
};
|
|
@@ -80,7 +80,7 @@ export default function createCommonConfig(
|
|
|
80
80
|
APP_NAME: JSON.stringify(app.identity.web.title),
|
|
81
81
|
APP_OUTPUT_DIR: JSON.stringify(path.basename(app.outputPath(outputTarget))),
|
|
82
82
|
PROTEUM_DEV_EVENT_PORT: JSON.stringify(dev ? (app.devEventPort ?? null) : null),
|
|
83
|
-
|
|
83
|
+
PROTEUM_PORT_OVERRIDE: JSON.stringify(app.routerPortOverride ?? null),
|
|
84
84
|
}),
|
|
85
85
|
|
|
86
86
|
...(dev ? [] : []),
|
|
@@ -2,120 +2,21 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
|
|
4
4
|
import writeIfChanged from '../writeIfChanged';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export type TProteumManifestService = {
|
|
21
|
-
kind: 'service' | 'ref';
|
|
22
|
-
id?: string;
|
|
23
|
-
registeredName: string;
|
|
24
|
-
metaName?: string;
|
|
25
|
-
parent: string;
|
|
26
|
-
priority: number;
|
|
27
|
-
importPath?: string;
|
|
28
|
-
sourceDir?: string;
|
|
29
|
-
metasFilepath?: string;
|
|
30
|
-
refTo?: string;
|
|
31
|
-
scope: TProteumManifestScope;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export type TProteumManifestController = {
|
|
35
|
-
className: string;
|
|
36
|
-
importPath: string;
|
|
37
|
-
filepath: string;
|
|
38
|
-
sourceLocation: TProteumManifestSourceLocation;
|
|
39
|
-
routeBasePath: string;
|
|
40
|
-
methodName: string;
|
|
41
|
-
inputCallsCount: number;
|
|
42
|
-
hasInput: boolean;
|
|
43
|
-
routePath: string;
|
|
44
|
-
httpPath: string;
|
|
45
|
-
clientAccessor: string;
|
|
46
|
-
scope: TProteumManifestScope;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export type TProteumManifestRoute = {
|
|
50
|
-
kind: 'client-page' | 'client-error' | 'server-route';
|
|
51
|
-
methodName: string;
|
|
52
|
-
serviceLocalName: string;
|
|
53
|
-
filepath: string;
|
|
54
|
-
sourceLocation: TProteumManifestSourceLocation;
|
|
55
|
-
targetResolution: TProteumManifestRouteTargetResolution;
|
|
56
|
-
path?: string;
|
|
57
|
-
pathRaw?: string;
|
|
58
|
-
code?: number;
|
|
59
|
-
codeRaw?: string;
|
|
60
|
-
optionKeys: string[];
|
|
61
|
-
normalizedOptionKeys: string[];
|
|
62
|
-
invalidOptionKeys: string[];
|
|
63
|
-
reservedOptionKeys: string[];
|
|
64
|
-
optionsRaw?: string;
|
|
65
|
-
hasSetup: boolean;
|
|
66
|
-
chunkId?: string;
|
|
67
|
-
chunkFilepath?: string;
|
|
68
|
-
scope: TProteumManifestScope;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export type TProteumManifestLayout = {
|
|
72
|
-
chunkId: string;
|
|
73
|
-
filepath: string;
|
|
74
|
-
importPath: string;
|
|
75
|
-
depth: number;
|
|
76
|
-
scope: TProteumManifestScope;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export type TProteumManifest = {
|
|
80
|
-
version: 1;
|
|
81
|
-
app: {
|
|
82
|
-
root: string;
|
|
83
|
-
coreRoot: string;
|
|
84
|
-
identityFilepath: string;
|
|
85
|
-
identity: {
|
|
86
|
-
name: string;
|
|
87
|
-
identifier: string;
|
|
88
|
-
description: string;
|
|
89
|
-
language?: string;
|
|
90
|
-
locale?: string;
|
|
91
|
-
title?: string;
|
|
92
|
-
titleSuffix?: string;
|
|
93
|
-
fullTitle?: string;
|
|
94
|
-
webDescription?: string;
|
|
95
|
-
version?: string;
|
|
96
|
-
};
|
|
97
|
-
};
|
|
98
|
-
conventions: {
|
|
99
|
-
routeSetupOptionKeys: string[];
|
|
100
|
-
reservedRouteSetupKeys: string[];
|
|
101
|
-
};
|
|
102
|
-
env: {
|
|
103
|
-
sourceFilepath: string;
|
|
104
|
-
loadedTopLevelKeys: string[];
|
|
105
|
-
requiredTopLevelKeys: string[];
|
|
106
|
-
};
|
|
107
|
-
services: {
|
|
108
|
-
app: TProteumManifestService[];
|
|
109
|
-
routerPlugins: TProteumManifestService[];
|
|
110
|
-
};
|
|
111
|
-
controllers: TProteumManifestController[];
|
|
112
|
-
routes: {
|
|
113
|
-
client: TProteumManifestRoute[];
|
|
114
|
-
server: TProteumManifestRoute[];
|
|
115
|
-
};
|
|
116
|
-
layouts: TProteumManifestLayout[];
|
|
117
|
-
diagnostics: TProteumManifestDiagnostic[];
|
|
118
|
-
};
|
|
5
|
+
import type { TProteumManifest } from '@common/dev/proteumManifest';
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
TProteumManifest,
|
|
9
|
+
TProteumManifestCommand,
|
|
10
|
+
TProteumManifestController,
|
|
11
|
+
TProteumManifestDiagnostic,
|
|
12
|
+
TProteumManifestDiagnosticLevel,
|
|
13
|
+
TProteumManifestLayout,
|
|
14
|
+
TProteumManifestRoute,
|
|
15
|
+
TProteumManifestRouteTargetResolution,
|
|
16
|
+
TProteumManifestScope,
|
|
17
|
+
TProteumManifestService,
|
|
18
|
+
TProteumManifestSourceLocation,
|
|
19
|
+
} from '@common/dev/proteumManifest';
|
|
119
20
|
|
|
120
21
|
export const getProteumManifestPath = (appRoot: string) => path.join(appRoot, '.proteum', 'manifest.json');
|
|
121
22
|
|
package/cli/compiler/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { writeClientManifest } from './common/clientManifest';
|
|
|
16
16
|
import { logVerbose } from '../runtime/verbose';
|
|
17
17
|
import { createCompileReporter, type TCompileReporter } from '../presentation/compileReporter';
|
|
18
18
|
import { generateRoutingArtifacts } from './artifacts/routing';
|
|
19
|
+
import { generateCommandArtifacts } from './artifacts/commands';
|
|
19
20
|
import { generateControllerArtifacts } from './artifacts/controllers';
|
|
20
21
|
import { generateServiceArtifacts } from './artifacts/services';
|
|
21
22
|
import { writeCurrentProteumManifest } from './artifacts/manifest';
|
|
@@ -32,6 +33,7 @@ export default class Compiler {
|
|
|
32
33
|
public compiling: { [compiler: string]: Promise<void> } = {};
|
|
33
34
|
private recentCompilationResults: { [compiler: string]: TRecentCompilationResult } = {};
|
|
34
35
|
private recentModifiedFiles: { [compiler: string]: string[] } = {};
|
|
36
|
+
private manualModifiedFiles: { [compiler: string]: Set<string> } = {};
|
|
35
37
|
private refreshingGeneratedArtifacts?: Promise<void>;
|
|
36
38
|
private compileReporter?: TCompileReporter;
|
|
37
39
|
|
|
@@ -140,11 +142,13 @@ export default class Compiler {
|
|
|
140
142
|
this.refreshingGeneratedArtifacts = (async () => {
|
|
141
143
|
const services = generateServiceArtifacts();
|
|
142
144
|
const controllers = generateControllerArtifacts();
|
|
145
|
+
const commands = generateCommandArtifacts();
|
|
143
146
|
const { clientRoutes, serverRoutes, layouts } = generateRoutingArtifacts();
|
|
144
147
|
|
|
145
148
|
writeCurrentProteumManifest({
|
|
146
149
|
services,
|
|
147
150
|
controllers,
|
|
151
|
+
commands,
|
|
148
152
|
routes: { client: clientRoutes, server: serverRoutes },
|
|
149
153
|
layouts,
|
|
150
154
|
});
|
|
@@ -172,6 +176,21 @@ export default class Compiler {
|
|
|
172
176
|
return recentCompilationResults;
|
|
173
177
|
}
|
|
174
178
|
|
|
179
|
+
public noteManualModifiedFiles(compilerNames: string[] | string, filepaths: string[]) {
|
|
180
|
+
const normalizedCompilerNames = Array.isArray(compilerNames) ? compilerNames : [compilerNames];
|
|
181
|
+
const normalizedFilepaths = filepaths.map((filepath) => normalizePath(path.resolve(filepath)));
|
|
182
|
+
|
|
183
|
+
for (const compilerName of normalizedCompilerNames) {
|
|
184
|
+
const pendingFiles = this.manualModifiedFiles[compilerName] || new Set<string>();
|
|
185
|
+
|
|
186
|
+
for (const filepath of normalizedFilepaths) {
|
|
187
|
+
pendingFiles.add(filepath);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.manualModifiedFiles[compilerName] = pendingFiles;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
175
194
|
public async create() {
|
|
176
195
|
await this.warmupApp();
|
|
177
196
|
|
|
@@ -204,9 +223,13 @@ export default class Compiler {
|
|
|
204
223
|
compiler.hooks.compile.tap(name, (compilation) => {
|
|
205
224
|
this.callbacks.before && this.callbacks.before(compiler);
|
|
206
225
|
|
|
207
|
-
|
|
208
|
-
|
|
226
|
+
const compilerModifiedFiles = [...(compiler.modifiedFiles ? [...compiler.modifiedFiles] : [])].map((filepath) =>
|
|
227
|
+
normalizePath(path.resolve(filepath)),
|
|
209
228
|
);
|
|
229
|
+
const manualModifiedFiles = [...(this.manualModifiedFiles[name] || [])];
|
|
230
|
+
delete this.manualModifiedFiles[name];
|
|
231
|
+
|
|
232
|
+
this.recentModifiedFiles[name] = [...new Set([...compilerModifiedFiles, ...manualModifiedFiles])];
|
|
210
233
|
|
|
211
234
|
this.compiling[name] = new Promise((resolve) => (finished = resolve));
|
|
212
235
|
|
|
@@ -49,6 +49,25 @@ const getDevGeneratedRuntimeEntries = (app: App) => ({
|
|
|
49
49
|
__proteum_dev_routes: [app.paths.server.generated + '/routes.ts'],
|
|
50
50
|
__proteum_dev_controllers: [app.paths.server.generated + '/controllers.ts'],
|
|
51
51
|
});
|
|
52
|
+
const normalizeModulePath = (value?: string) => (value || '').replace(/\\/g, '/');
|
|
53
|
+
const rewriteFrameworkAliasTargets = (app: App, aliases: Record<string, string | string[]>) => {
|
|
54
|
+
const installedCoreRoot = normalizeModulePath(app.paths.root + '/node_modules/proteum');
|
|
55
|
+
const activeCoreRoot = normalizeModulePath(cli.paths.core.root);
|
|
56
|
+
|
|
57
|
+
if (installedCoreRoot === activeCoreRoot) return aliases;
|
|
58
|
+
|
|
59
|
+
const rewriteCandidate = (candidate: string) =>
|
|
60
|
+
normalizeModulePath(candidate).startsWith(installedCoreRoot + '/')
|
|
61
|
+
? activeCoreRoot + normalizeModulePath(candidate).substring(installedCoreRoot.length)
|
|
62
|
+
: candidate;
|
|
63
|
+
|
|
64
|
+
return Object.fromEntries(
|
|
65
|
+
Object.entries(aliases).map(([alias, value]) => [
|
|
66
|
+
alias,
|
|
67
|
+
Array.isArray(value) ? value.map(rewriteCandidate) : rewriteCandidate(value),
|
|
68
|
+
]),
|
|
69
|
+
);
|
|
70
|
+
};
|
|
52
71
|
|
|
53
72
|
/*----------------------------------
|
|
54
73
|
- CONFIG
|
|
@@ -61,14 +80,17 @@ export default function createCompiler(
|
|
|
61
80
|
debug && console.info(`Creating compiler for server (${mode}).`);
|
|
62
81
|
const dev = mode === 'dev';
|
|
63
82
|
const outputPath = app.outputPath(outputTarget);
|
|
83
|
+
const installedCoreRoot = app.paths.root + '/node_modules/proteum';
|
|
84
|
+
const frameworkRoots = [cli.paths.core.root, installedCoreRoot];
|
|
64
85
|
|
|
65
86
|
const commonConfig = createCommonConfig(app, 'server', mode, outputTarget);
|
|
66
87
|
const { aliases } = app.aliases.server.forWebpack({ modulesPath: app.paths.root + '/node_modules' });
|
|
88
|
+
const resolvedAliases = rewriteFrameworkAliasTargets(app, aliases);
|
|
67
89
|
|
|
68
90
|
// We're not supposed in any case to import client services from server
|
|
69
|
-
delete
|
|
70
|
-
delete
|
|
71
|
-
const rspackAliases = toRspackAliases(
|
|
91
|
+
delete resolvedAliases['@client/services'];
|
|
92
|
+
delete resolvedAliases['@/client/services'];
|
|
93
|
+
const rspackAliases = toRspackAliases(resolvedAliases);
|
|
72
94
|
rspackAliases['@/client/router$'] = cli.paths.core.root + '/client/router.ts';
|
|
73
95
|
|
|
74
96
|
debug &&
|
|
@@ -154,20 +176,23 @@ export default function createCompiler(
|
|
|
154
176
|
test: regex.scripts,
|
|
155
177
|
include: [
|
|
156
178
|
app.paths.root + '/client',
|
|
157
|
-
cli.paths.core.root + '/client',
|
|
158
179
|
app.paths.client.generated,
|
|
159
180
|
|
|
160
181
|
app.paths.root + '/common',
|
|
161
|
-
cli.paths.core.root + '/common',
|
|
162
182
|
app.paths.common.generated,
|
|
163
183
|
|
|
164
184
|
// Prisma 7 generates TypeScript entrypoints under var/prisma.
|
|
165
185
|
app.paths.root + '/var/prisma',
|
|
166
186
|
|
|
187
|
+
app.paths.root + '/commands',
|
|
188
|
+
|
|
167
189
|
// Dossiers server uniquement pour le bundle server
|
|
168
190
|
app.paths.root + '/server',
|
|
169
|
-
cli.paths.core.root + '/server',
|
|
170
191
|
app.paths.server.generated,
|
|
192
|
+
...frameworkRoots.map((rootPath) => rootPath + '/commands'),
|
|
193
|
+
...frameworkRoots.map((rootPath) => rootPath + '/client'),
|
|
194
|
+
...frameworkRoots.map((rootPath) => rootPath + '/common'),
|
|
195
|
+
...frameworkRoots.map((rootPath) => rootPath + '/server'),
|
|
171
196
|
|
|
172
197
|
// Complle 5HTP modules so they can refer to the framework instance and aliases
|
|
173
198
|
// Temp disabled because compile issue on vercel
|
package/cli/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
process.traceDeprecation = true;
|
|
2
2
|
|
|
3
|
-
import fs from 'fs';
|
|
4
3
|
import { Cli } from 'clipanion';
|
|
5
4
|
|
|
6
5
|
import cli from './context';
|
|
@@ -9,12 +8,10 @@ import { renderCliOverview, renderCommandHelp, resolveCustomHelpRequest } from '
|
|
|
9
8
|
import { normalizeHelpArgv, normalizeLegacyArgv } from './runtime/argv';
|
|
10
9
|
import { createCli, registeredCommands } from './runtime/commands';
|
|
11
10
|
|
|
12
|
-
const hasInitScaffold = () => fs.existsSync(`${cli.paths.core.cli}/skeleton`);
|
|
13
|
-
|
|
14
11
|
export const runCli = async (argv: string[] = process.argv.slice(2)) => {
|
|
15
12
|
const normalizedArgv = normalizeHelpArgv(normalizeLegacyArgv(argv), proteumCommandNames);
|
|
16
13
|
const clipanion = createCli(String(cli.packageJson.version || ''));
|
|
17
|
-
const initAvailable =
|
|
14
|
+
const initAvailable = true;
|
|
18
15
|
const helpRequest = resolveCustomHelpRequest(normalizedArgv);
|
|
19
16
|
|
|
20
17
|
if (helpRequest.kind === 'overview') {
|
package/cli/paths.ts
CHANGED
|
@@ -43,13 +43,28 @@ export const staticAssetName = /*isDebug ? '[name].[ext].[hash:8]' :*/ '[hash:8]
|
|
|
43
43
|
|
|
44
44
|
const pathInfosDefaultOpts = { shortenExtensions: ['ts', 'js', 'tsx', 'jsx'], trimIndex: true };
|
|
45
45
|
|
|
46
|
+
const safeRealpath = (filepath: string) => {
|
|
47
|
+
try {
|
|
48
|
+
return fs.realpathSync(filepath);
|
|
49
|
+
} catch {
|
|
50
|
+
return path.resolve(filepath);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
46
54
|
const resolveCoreRoot = (appRoot: string) => {
|
|
55
|
+
const currentPackageRoot = path.resolve(__dirname, '..');
|
|
56
|
+
const currentBin = path.join(currentPackageRoot, 'cli', 'bin.js');
|
|
57
|
+
const invokedScript = process.argv[1] ? safeRealpath(process.argv[1]) : '';
|
|
58
|
+
const invokedCurrentPackage = invokedScript === safeRealpath(currentBin);
|
|
59
|
+
|
|
60
|
+
if (invokedCurrentPackage) return currentPackageRoot;
|
|
61
|
+
|
|
47
62
|
const localInstall = path.join(appRoot, 'node_modules', 'proteum');
|
|
48
63
|
if (fs.existsSync(localInstall)) return localInstall;
|
|
49
64
|
|
|
50
65
|
// When running `npx`/global installs, there may be no local `node_modules/proteum` yet.
|
|
51
66
|
// Fall back to the installed package root (this file lives in `<root>/cli`).
|
|
52
|
-
return
|
|
67
|
+
return currentPackageRoot;
|
|
53
68
|
};
|
|
54
69
|
|
|
55
70
|
const normalizeImportPath = (value: string) => value.replace(/\\/g, '/');
|