proteum 2.0.0 → 2.1.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.
Files changed (94) hide show
  1. package/AGENTS.md +13 -1
  2. package/README.md +375 -0
  3. package/agents/framework/AGENTS.md +917 -0
  4. package/agents/project/AGENTS.md +138 -0
  5. package/agents/{codex → project}/CODING_STYLE.md +3 -2
  6. package/agents/project/client/AGENTS.md +108 -0
  7. package/agents/{codex → project}/client/pages/AGENTS.md +8 -8
  8. package/agents/{codex → project}/server/routes/AGENTS.md +2 -1
  9. package/agents/project/server/services/AGENTS.md +170 -0
  10. package/agents/{codex → project}/tests/AGENTS.md +1 -0
  11. package/cli/app/config.ts +3 -2
  12. package/cli/app/index.ts +6 -66
  13. package/cli/bin.js +7 -2
  14. package/cli/commands/build.ts +94 -27
  15. package/cli/commands/check.ts +15 -1
  16. package/cli/commands/dev.ts +288 -132
  17. package/cli/commands/doctor.ts +108 -0
  18. package/cli/commands/explain.ts +226 -0
  19. package/cli/commands/init.ts +76 -70
  20. package/cli/commands/lint.ts +18 -1
  21. package/cli/commands/refresh.ts +16 -6
  22. package/cli/commands/typecheck.ts +14 -1
  23. package/cli/compiler/artifacts/controllers.ts +150 -0
  24. package/cli/compiler/artifacts/discovery.ts +132 -0
  25. package/cli/compiler/artifacts/manifest.ts +267 -0
  26. package/cli/compiler/artifacts/routing.ts +315 -0
  27. package/cli/compiler/artifacts/services.ts +480 -0
  28. package/cli/compiler/artifacts/shared.ts +12 -0
  29. package/cli/compiler/client/identite.ts +2 -1
  30. package/cli/compiler/client/index.ts +13 -3
  31. package/cli/compiler/common/controllers.ts +23 -28
  32. package/cli/compiler/common/files/style.ts +3 -4
  33. package/cli/compiler/common/generatedRouteModules.ts +333 -19
  34. package/cli/compiler/common/proteumManifest.ts +133 -0
  35. package/cli/compiler/index.ts +33 -896
  36. package/cli/compiler/server/index.ts +21 -4
  37. package/cli/context.ts +71 -0
  38. package/cli/index.ts +39 -181
  39. package/cli/presentation/commands.ts +208 -0
  40. package/cli/presentation/compileReporter.ts +65 -0
  41. package/cli/presentation/devSession.ts +70 -0
  42. package/cli/presentation/help.ts +193 -0
  43. package/cli/presentation/ink.ts +69 -0
  44. package/cli/presentation/layout.ts +83 -0
  45. package/cli/runtime/argv.ts +49 -0
  46. package/cli/runtime/command.ts +25 -0
  47. package/cli/runtime/commands.ts +221 -0
  48. package/cli/runtime/importEsm.ts +7 -0
  49. package/cli/runtime/verbose.ts +15 -0
  50. package/cli/utils/agents.ts +5 -4
  51. package/cli/utils/keyboard.ts +12 -6
  52. package/client/app/index.ts +0 -6
  53. package/client/services/router/index.tsx +1 -1
  54. package/client/services/router/response/index.tsx +2 -2
  55. package/common/dev/serverHotReload.ts +12 -0
  56. package/common/router/index.ts +3 -2
  57. package/common/router/layouts.ts +1 -1
  58. package/common/router/pageSetup.ts +1 -0
  59. package/package.json +10 -8
  60. package/prettier/router-registration-plugin.cjs +52 -0
  61. package/prettier.config.cjs +1 -0
  62. package/scripts/cleanup-generated-controllers.ts +2 -2
  63. package/scripts/fix-reference-app-typing.ts +2 -2
  64. package/scripts/format-router-registrations.ts +119 -0
  65. package/scripts/migrate-explicit-controllers-and-request.ts +423 -0
  66. package/scripts/refactor-server-controllers.ts +19 -18
  67. package/scripts/refactor-server-runtime-aliases.ts +1 -1
  68. package/server/app/commands.ts +309 -25
  69. package/server/app/container/config.ts +1 -1
  70. package/server/app/container/index.ts +2 -2
  71. package/server/app/controller/index.ts +13 -4
  72. package/server/app/index.ts +53 -37
  73. package/server/app/service/container.ts +26 -28
  74. package/server/app/service/index.ts +10 -20
  75. package/server/app.tsconfig.json +9 -2
  76. package/server/index.ts +32 -1
  77. package/server/services/auth/index.ts +234 -15
  78. package/server/services/auth/router/index.ts +39 -7
  79. package/server/services/auth/router/request.ts +40 -8
  80. package/server/services/disks/index.ts +1 -1
  81. package/server/services/prisma/Facet.ts +2 -2
  82. package/server/services/prisma/index.ts +22 -5
  83. package/server/services/prisma/mariadb.ts +47 -0
  84. package/server/services/router/http/index.ts +9 -1
  85. package/server/services/router/index.ts +10 -4
  86. package/server/services/router/response/index.ts +26 -6
  87. package/types/auth-check-rules.test.ts +51 -0
  88. package/types/controller-request-context.test.ts +55 -0
  89. package/types/service-config.test.ts +39 -0
  90. package/agents/codex/AGENTS.md +0 -95
  91. package/agents/codex/client/AGENTS.md +0 -102
  92. package/agents/codex/server/services/AGENTS.md +0 -137
  93. package/server/services/models.7z +0 -0
  94. /package/agents/{codex → project}/agents.md.zip +0 -0
@@ -0,0 +1,315 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+
4
+ import app from '../../app';
5
+ import cli from '../..';
6
+ import writeIfChanged from '../writeIfChanged';
7
+ import { TProteumManifestLayout, TProteumManifestRoute } from '../common/proteumManifest';
8
+ import {
9
+ getGeneratedRouteModuleFilepath,
10
+ indexRouteDefinitions,
11
+ writeGeneratedRouteModule,
12
+ } from '../common/generatedRouteModules';
13
+ import {
14
+ findClientRouteFiles,
15
+ findLayoutFiles,
16
+ findServerRouteFiles,
17
+ readPreloadedRouteChunks,
18
+ } from './discovery';
19
+ import { getGeneratedImportPath, normalizeAbsolutePath, normalizePath } from './shared';
20
+
21
+ type TClientRouteLoader = { filepath: string; chunkId: string; preload: boolean };
22
+
23
+ const cleanupObsoleteGeneratedArtifacts = () => {
24
+ fs.removeSync(path.join(app.paths.root, 'client', '.generated'));
25
+ fs.removeSync(path.join(app.paths.root, 'common', '.generated'));
26
+ fs.removeSync(path.join(app.paths.root, 'server', '.generated'));
27
+ fs.removeSync(path.join(app.paths.root, 'common', 'generated.d.ts'));
28
+ fs.removeSync(path.join(app.paths.root, '.proteum', 'client', '.generated'));
29
+ fs.removeSync(path.join(app.paths.root, '.proteum', 'common', '.generated'));
30
+ fs.removeSync(path.join(app.paths.root, '.proteum', 'server', '.generated'));
31
+ fs.removeSync(path.join(app.paths.client.generated, 'route-modules'));
32
+ fs.removeSync(path.join(app.paths.server.generated, 'route-modules'));
33
+ fs.removeSync(path.join(app.paths.client.generated, 'index.ts'));
34
+ };
35
+
36
+ const getGeneratedClientRouteModuleFilepath = (filepath: string) =>
37
+ getGeneratedRouteModuleFilepath(app.paths.client.generated, app.paths.pages, filepath);
38
+
39
+ const getGeneratedServerRouteModuleFilepath = (filepath: string) =>
40
+ getGeneratedRouteModuleFilepath(app.paths.server.generated, app.paths.root, filepath);
41
+
42
+ const buildClientRouteManifestEntry = (filepath: string): TProteumManifestRoute => {
43
+ const [definition] = indexRouteDefinitions({ side: 'client', sourceFilepath: filepath });
44
+ const pageChunk = cli.paths.getPageChunk(app, filepath);
45
+
46
+ return {
47
+ kind: definition.methodName === 'error' ? 'client-error' : 'client-page',
48
+ methodName: definition.methodName,
49
+ serviceLocalName: definition.serviceLocalName,
50
+ filepath: normalizeAbsolutePath(filepath),
51
+ sourceLocation: definition.sourceLocation,
52
+ targetResolution: definition.targetResolution,
53
+ path: definition.path,
54
+ pathRaw: definition.pathRaw,
55
+ code: definition.code,
56
+ codeRaw: definition.codeRaw,
57
+ optionKeys: definition.optionKeys,
58
+ normalizedOptionKeys: definition.normalizedOptionKeys,
59
+ invalidOptionKeys: definition.invalidOptionKeys,
60
+ reservedOptionKeys: definition.reservedOptionKeys,
61
+ optionsRaw: definition.optionsRaw,
62
+ hasSetup: definition.hasSetup,
63
+ chunkId: pageChunk.chunkId,
64
+ chunkFilepath: normalizePath(pageChunk.filepath),
65
+ scope: 'app',
66
+ };
67
+ };
68
+
69
+ const buildServerRouteManifestEntries = (filepath: string) =>
70
+ indexRouteDefinitions({ side: 'server', sourceFilepath: filepath }).map<TProteumManifestRoute>((definition) => ({
71
+ kind: 'server-route',
72
+ methodName: definition.methodName,
73
+ serviceLocalName: definition.serviceLocalName,
74
+ filepath: normalizeAbsolutePath(filepath),
75
+ sourceLocation: definition.sourceLocation,
76
+ targetResolution: definition.targetResolution,
77
+ path: definition.path,
78
+ pathRaw: definition.pathRaw,
79
+ code: definition.code,
80
+ codeRaw: definition.codeRaw,
81
+ optionKeys: definition.optionKeys,
82
+ normalizedOptionKeys: definition.normalizedOptionKeys,
83
+ invalidOptionKeys: definition.invalidOptionKeys,
84
+ reservedOptionKeys: definition.reservedOptionKeys,
85
+ optionsRaw: definition.optionsRaw,
86
+ hasSetup: definition.hasSetup,
87
+ scope: 'app',
88
+ }));
89
+
90
+ const generateClientRouteWrapperModules = () => {
91
+ const clientRouteFiles = findClientRouteFiles(app.paths.pages).sort((a, b) => a.localeCompare(b));
92
+ const routeSourceFilepaths = new Set(clientRouteFiles.map((filepath) => normalizePath(path.resolve(filepath))));
93
+ const routes = clientRouteFiles.map((filepath) => buildClientRouteManifestEntry(filepath));
94
+
95
+ for (const filepath of clientRouteFiles) {
96
+ const pageChunk = cli.paths.getPageChunk(app, filepath);
97
+
98
+ writeGeneratedRouteModule({
99
+ outputFilepath: getGeneratedClientRouteModuleFilepath(filepath),
100
+ runtime: 'client',
101
+ side: 'client',
102
+ sourceFilepath: filepath,
103
+ clientRoute: { chunkId: pageChunk.chunkId, filepath: pageChunk.filepath },
104
+ routeSourceFilepaths,
105
+ });
106
+
107
+ writeGeneratedRouteModule({
108
+ outputFilepath: getGeneratedServerRouteModuleFilepath(filepath),
109
+ runtime: 'server',
110
+ side: 'client',
111
+ sourceFilepath: filepath,
112
+ clientRoute: { chunkId: pageChunk.chunkId, filepath: pageChunk.filepath },
113
+ routeSourceFilepaths,
114
+ });
115
+ }
116
+
117
+ return routes;
118
+ };
119
+
120
+ const generateServerRouteWrapperModules = () => {
121
+ const serverRouteFiles = findServerRouteFiles(path.join(app.paths.root, 'server', 'routes')).sort((a, b) =>
122
+ a.localeCompare(b),
123
+ );
124
+ const routeSourceFilepaths = new Set(serverRouteFiles.map((filepath) => normalizePath(path.resolve(filepath))));
125
+ const routes = serverRouteFiles.flatMap((filepath) => buildServerRouteManifestEntries(filepath));
126
+
127
+ for (const filepath of serverRouteFiles) {
128
+ writeGeneratedRouteModule({
129
+ outputFilepath: getGeneratedServerRouteModuleFilepath(filepath),
130
+ runtime: 'server',
131
+ side: 'server',
132
+ sourceFilepath: filepath,
133
+ routeSourceFilepaths,
134
+ });
135
+ }
136
+
137
+ return routes;
138
+ };
139
+
140
+ const generateClientRoutesModule = () => {
141
+ const routeLoadersFile = path.join(app.paths.client.generated, 'routes.ts');
142
+ const preloadedChunks = readPreloadedRouteChunks();
143
+
144
+ const routes = findClientRouteFiles(app.paths.pages)
145
+ .sort((a, b) => a.localeCompare(b))
146
+ .map<TClientRouteLoader>((filepath) => {
147
+ const { chunkId } = cli.paths.getPageChunk(app, filepath);
148
+
149
+ return { filepath, chunkId, preload: preloadedChunks.has(chunkId) };
150
+ });
151
+
152
+ const imports: string[] = [];
153
+ const routeEntries: string[] = [];
154
+
155
+ routes.forEach((route, index) => {
156
+ const normalizedImportPath = getGeneratedImportPath(
157
+ app.paths.client.generated,
158
+ getGeneratedClientRouteModuleFilepath(route.filepath),
159
+ );
160
+
161
+ if (route.preload) {
162
+ const localIdentifier = `preloadedRoute${index}`;
163
+ imports.push(`import { __register as ${localIdentifier} } from ${JSON.stringify(normalizedImportPath)};`);
164
+ routeEntries.push(
165
+ ` ${JSON.stringify(route.chunkId)}: () => Promise.resolve({ __register: ${localIdentifier} }),`,
166
+ );
167
+ return;
168
+ }
169
+
170
+ routeEntries.push(
171
+ ` ${JSON.stringify(route.chunkId)}: () => import(/* webpackChunkName: ${JSON.stringify(route.chunkId)} */ ${JSON.stringify(normalizedImportPath)}),`,
172
+ );
173
+ });
174
+
175
+ const content = `/*----------------------------------
176
+ - GENERATED FILE
177
+ ----------------------------------*/
178
+
179
+ // This file is generated by Proteum to avoid rebuilding the page loader map in Babel.
180
+ // Do not edit it manually.
181
+
182
+ ${imports.join('\n')}
183
+ ${imports.length ? '\n' : ''}const routes = {
184
+ ${routeEntries.join('\n')}
185
+ };
186
+
187
+ export default routes;
188
+ `;
189
+
190
+ writeIfChanged(routeLoadersFile, content);
191
+ };
192
+
193
+ const generateClientLayoutsModule = () => {
194
+ const layoutsFile = path.join(app.paths.client.generated, 'layouts.ts');
195
+
196
+ const layouts = findLayoutFiles(app.paths.pages)
197
+ .map<TProteumManifestLayout>((filepath) => {
198
+ const { chunkId } = cli.paths.getLayoutChunk(app, filepath);
199
+ const importPath = getGeneratedImportPath(app.paths.client.generated, filepath);
200
+ const relativePath = normalizePath(path.relative(app.paths.root, filepath));
201
+ const depth = relativePath.split('/').filter(Boolean).length;
202
+
203
+ return {
204
+ filepath: normalizeAbsolutePath(filepath),
205
+ chunkId,
206
+ depth,
207
+ importPath,
208
+ scope: 'app',
209
+ };
210
+ })
211
+ .sort((a, b) => {
212
+ if (b.depth !== a.depth) return b.depth - a.depth;
213
+ return a.filepath.localeCompare(b.filepath);
214
+ });
215
+
216
+ const imports = layouts
217
+ .map((layout, index) => `import * as layoutModule${index} from ${JSON.stringify(layout.importPath)};`)
218
+ .join('\n');
219
+
220
+ const layoutEntries = layouts
221
+ .map((layout, index) => ` ${JSON.stringify(layout.chunkId)}: layoutModule${index},`)
222
+ .join('\n');
223
+
224
+ const orderedLayoutIds = layouts.map((layout) => ` ${JSON.stringify(layout.chunkId)},`).join('\n');
225
+
226
+ const content = `/*----------------------------------
227
+ - GENERATED FILE
228
+ ----------------------------------*/
229
+
230
+ // This file is generated by Proteum from app layout files.
231
+ // Do not edit it manually.
232
+
233
+ ${imports}
234
+ ${imports ? '\n' : ''}const layouts = {
235
+ ${layoutEntries}
236
+ };
237
+
238
+ export const layoutOrder = [
239
+ ${orderedLayoutIds}
240
+ ];
241
+
242
+ export default layouts;
243
+ `;
244
+
245
+ writeIfChanged(layoutsFile, content);
246
+
247
+ return layouts;
248
+ };
249
+
250
+ const generateServerRoutesModule = () => {
251
+ const routeModulesFile = path.join(app.paths.server.generated, 'routes.ts');
252
+ const serverRouteFiles = findServerRouteFiles(path.join(app.paths.root, 'server', 'routes'))
253
+ .sort((a, b) => a.localeCompare(b))
254
+ .map((filepath) => ({
255
+ filepath: normalizePath(path.relative(app.paths.root, filepath)),
256
+ importPath: getGeneratedImportPath(app.paths.server.generated, getGeneratedServerRouteModuleFilepath(filepath)),
257
+ }));
258
+
259
+ const pageRouteFiles = findClientRouteFiles(app.paths.pages)
260
+ .sort((a, b) => a.localeCompare(b))
261
+ .map((filepath) => ({
262
+ filepath: normalizePath(path.relative(app.paths.root, filepath)),
263
+ importPath: getGeneratedImportPath(app.paths.server.generated, getGeneratedServerRouteModuleFilepath(filepath)),
264
+ }));
265
+
266
+ const routeModules = [...serverRouteFiles, ...pageRouteFiles];
267
+
268
+ const imports = routeModules
269
+ .map((routeModule, index) => `const routeModule${index} = require(${JSON.stringify(routeModule.importPath)});`)
270
+ .join('\n');
271
+
272
+ const routeEntries = routeModules
273
+ .map(
274
+ (routeModule, index) => ` {
275
+ filepath: ${JSON.stringify(routeModule.filepath)},
276
+ register: routeModule${index}.__register,
277
+ },`,
278
+ )
279
+ .join('\n');
280
+
281
+ const content = `/*----------------------------------
282
+ - GENERATED FILE
283
+ ----------------------------------*/
284
+
285
+ // This file is generated by Proteum from route registration files.
286
+ // Do not edit it manually.
287
+
288
+ import type { TRouteModule } from "@common/router";
289
+ ${imports ? '\n' + imports : ''}
290
+
291
+ export type TGeneratedRouteModule = {
292
+ filepath: string,
293
+ register?: TRouteModule["__register"],
294
+ }
295
+
296
+ const routeModules: TGeneratedRouteModule[] = [
297
+ ${routeEntries}
298
+ ];
299
+
300
+ export default routeModules;
301
+ `;
302
+
303
+ writeIfChanged(routeModulesFile, content);
304
+ };
305
+
306
+ export const generateRoutingArtifacts = () => {
307
+ cleanupObsoleteGeneratedArtifacts();
308
+ const clientRoutes = generateClientRouteWrapperModules();
309
+ const serverRoutes = generateServerRouteWrapperModules();
310
+ generateServerRoutesModule();
311
+ generateClientRoutesModule();
312
+ const layouts = generateClientLayoutsModule();
313
+
314
+ return { clientRoutes, serverRoutes, layouts };
315
+ };