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,221 @@
1
+ import { Builtins, Cli, Option } from 'clipanion';
2
+
3
+ import type { TArgsObject } from '../context';
4
+ import { applyLegacyBooleanArgs, assertNoLegacyArgs } from './argv';
5
+ import { buildUsage, ProteumCommand, runCommandModule } from './command';
6
+
7
+ class InitCommand extends ProteumCommand {
8
+ public static paths = [['init']];
9
+
10
+ public static usage = buildUsage('init');
11
+
12
+ public legacyArgs = Option.Rest();
13
+
14
+ public async execute() {
15
+ assertNoLegacyArgs('init', this.legacyArgs);
16
+ this.setCliArgs();
17
+ await runCommandModule(() => import('../commands/init'));
18
+ }
19
+ }
20
+
21
+ class DevCommand extends ProteumCommand {
22
+ public static paths = [['dev']];
23
+
24
+ public static usage = buildUsage('dev');
25
+
26
+ public port = Option.String('--port', { description: 'Override the router port.' });
27
+ public cache = Option.Boolean('--cache', true, { description: 'Enable filesystem caching.' });
28
+ public legacyArgs = Option.Rest();
29
+
30
+ public async execute() {
31
+ assertNoLegacyArgs('dev', this.legacyArgs);
32
+ this.setCliArgs({ port: this.port ?? '', cache: this.cache });
33
+ await runCommandModule(() => import('../commands/dev'));
34
+ }
35
+ }
36
+
37
+ class RefreshCommand extends ProteumCommand {
38
+ public static paths = [['refresh']];
39
+
40
+ public static usage = buildUsage('refresh');
41
+
42
+ public legacyArgs = Option.Rest();
43
+
44
+ public async execute() {
45
+ assertNoLegacyArgs('refresh', this.legacyArgs);
46
+ this.setCliArgs();
47
+ await runCommandModule(() => import('../commands/refresh'));
48
+ }
49
+ }
50
+
51
+ class BuildCommand extends ProteumCommand {
52
+ public static paths = [['build']];
53
+
54
+ public static usage = buildUsage('build');
55
+
56
+ public port = Option.String('--port', { description: 'Override the router port.' });
57
+ public prod = Option.Boolean('--prod', false, { description: 'Build in production mode.' });
58
+ public cache = Option.Boolean('--cache', false, { description: 'Enable filesystem caching during the build.' });
59
+ public analyze = Option.Boolean('--analyze', false, { description: 'Emit the client bundle analysis report.' });
60
+ public strict = Option.Boolean('--strict', false, {
61
+ description: 'Refresh generated typings and fail the build if TypeScript reports any error.',
62
+ });
63
+ public legacyArgs = Option.Rest();
64
+
65
+ public async execute() {
66
+ const args = {
67
+ port: this.port ?? '',
68
+ dev: false,
69
+ prod: this.prod,
70
+ cache: this.cache,
71
+ analyze: this.analyze,
72
+ strict: this.strict,
73
+ } satisfies TArgsObject;
74
+
75
+ applyLegacyBooleanArgs('build', this.legacyArgs, ['prod', 'cache', 'analyze', 'strict'], args);
76
+ this.setCliArgs(args);
77
+ await runCommandModule(() => import('../commands/build'));
78
+ }
79
+ }
80
+
81
+ class TypecheckCommand extends ProteumCommand {
82
+ public static paths = [['typecheck']];
83
+
84
+ public static usage = buildUsage('typecheck');
85
+
86
+ public legacyArgs = Option.Rest();
87
+
88
+ public async execute() {
89
+ assertNoLegacyArgs('typecheck', this.legacyArgs);
90
+ this.setCliArgs();
91
+ await runCommandModule(() => import('../commands/typecheck'));
92
+ }
93
+ }
94
+
95
+ class LintCommand extends ProteumCommand {
96
+ public static paths = [['lint']];
97
+
98
+ public static usage = buildUsage('lint');
99
+
100
+ public fix = Option.Boolean('--fix', false, { description: 'Apply fixable lint changes.' });
101
+ public legacyArgs = Option.Rest();
102
+
103
+ public async execute() {
104
+ const args = { fix: this.fix } satisfies TArgsObject;
105
+
106
+ applyLegacyBooleanArgs('lint', this.legacyArgs, ['fix'], args);
107
+ this.setCliArgs(args);
108
+ await runCommandModule(() => import('../commands/lint'));
109
+ }
110
+ }
111
+
112
+ class CheckCommand extends ProteumCommand {
113
+ public static paths = [['check']];
114
+
115
+ public static usage = buildUsage('check');
116
+
117
+ public legacyArgs = Option.Rest();
118
+
119
+ public async execute() {
120
+ assertNoLegacyArgs('check', this.legacyArgs);
121
+ this.setCliArgs();
122
+ await runCommandModule(() => import('../commands/check'));
123
+ }
124
+ }
125
+
126
+ class DoctorCommand extends ProteumCommand {
127
+ public static paths = [['doctor']];
128
+
129
+ public static usage = buildUsage('doctor');
130
+
131
+ public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
132
+ public strict = Option.Boolean('--strict', false, { description: 'Exit with failure if any diagnostics exist.' });
133
+ public legacyArgs = Option.Rest();
134
+
135
+ public async execute() {
136
+ const args = { json: this.json, strict: this.strict } satisfies TArgsObject;
137
+
138
+ applyLegacyBooleanArgs('doctor', this.legacyArgs, ['json', 'strict'], args);
139
+ this.setCliArgs(args);
140
+ await runCommandModule(() => import('../commands/doctor'));
141
+ }
142
+ }
143
+
144
+ class ExplainCommand extends ProteumCommand {
145
+ public static paths = [['explain']];
146
+
147
+ public static usage = buildUsage('explain');
148
+
149
+ public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
150
+ public all = Option.Boolean('--all', false, { description: 'Include every explain section.' });
151
+ public app = Option.Boolean('--app', false, { description: 'Include the app section.' });
152
+ public conventions = Option.Boolean('--conventions', false, { description: 'Include the conventions section.' });
153
+ public env = Option.Boolean('--env', false, { description: 'Include the env section.' });
154
+ public services = Option.Boolean('--services', false, { description: 'Include the services section.' });
155
+ public controllers = Option.Boolean('--controllers', false, { description: 'Include the controllers section.' });
156
+ public routes = Option.Boolean('--routes', false, { description: 'Include the routes section.' });
157
+ public layouts = Option.Boolean('--layouts', false, { description: 'Include the layouts section.' });
158
+ public diagnostics = Option.Boolean('--diagnostics', false, {
159
+ description: 'Include the diagnostics section.',
160
+ });
161
+ public legacyArgs = Option.Rest();
162
+
163
+ public async execute() {
164
+ const args = {
165
+ json: this.json,
166
+ all: this.all,
167
+ app: this.app,
168
+ conventions: this.conventions,
169
+ env: this.env,
170
+ services: this.services,
171
+ controllers: this.controllers,
172
+ routes: this.routes,
173
+ layouts: this.layouts,
174
+ diagnostics: this.diagnostics,
175
+ } satisfies TArgsObject;
176
+
177
+ applyLegacyBooleanArgs(
178
+ 'explain',
179
+ this.legacyArgs,
180
+ ['json', 'all', 'app', 'conventions', 'env', 'services', 'controllers', 'routes', 'layouts', 'diagnostics'],
181
+ args,
182
+ );
183
+ this.setCliArgs(args);
184
+ await runCommandModule(() => import('../commands/explain'));
185
+ }
186
+ }
187
+
188
+ export const registeredCommands = {
189
+ init: InitCommand,
190
+ dev: DevCommand,
191
+ refresh: RefreshCommand,
192
+ build: BuildCommand,
193
+ typecheck: TypecheckCommand,
194
+ lint: LintCommand,
195
+ check: CheckCommand,
196
+ doctor: DoctorCommand,
197
+ explain: ExplainCommand,
198
+ } as const;
199
+
200
+ export const createCli = (version: string) => {
201
+ const clipanion = new Cli({
202
+ binaryLabel: 'Proteum',
203
+ binaryName: 'proteum',
204
+ binaryVersion: version,
205
+ });
206
+
207
+ clipanion.register(Builtins.HelpCommand);
208
+ clipanion.register(Builtins.VersionCommand);
209
+ clipanion.register(Builtins.DefinitionsCommand);
210
+ clipanion.register(InitCommand);
211
+ clipanion.register(DevCommand);
212
+ clipanion.register(RefreshCommand);
213
+ clipanion.register(BuildCommand);
214
+ clipanion.register(TypecheckCommand);
215
+ clipanion.register(LintCommand);
216
+ clipanion.register(CheckCommand);
217
+ clipanion.register(DoctorCommand);
218
+ clipanion.register(ExplainCommand);
219
+
220
+ return clipanion;
221
+ };
@@ -0,0 +1,7 @@
1
+ // The CLI still boots through ts-node in CommonJS mode, but Ink ships as ESM-only.
2
+ // Use Node's native dynamic import so presentation code can depend on Ink safely.
3
+ const nativeDynamicImport = new Function('specifier', 'return import(specifier)') as <T = unknown>(
4
+ specifier: string,
5
+ ) => Promise<T>;
6
+
7
+ export const importEsm = <T = unknown>(specifier: string) => nativeDynamicImport(specifier) as Promise<T>;
@@ -0,0 +1,15 @@
1
+ import cli from '../context';
2
+
3
+ export const isVerbose = () => cli.verbose === true;
4
+
5
+ export const logVerbose = (...args: unknown[]) => {
6
+ if (!isVerbose()) return;
7
+
8
+ console.info(...args);
9
+ };
10
+
11
+ export const logVerboseWarn = (...args: unknown[]) => {
12
+ if (!isVerbose()) return;
13
+
14
+ console.warn(...args);
15
+ };
@@ -5,6 +5,7 @@
5
5
  // Npm
6
6
  import fs from 'fs-extra';
7
7
  import path from 'path';
8
+ import { logVerbose } from '../runtime/verbose';
8
9
 
9
10
  /*----------------------------------
10
11
  - TYPES
@@ -19,7 +20,7 @@ type TAgentLinkDefinition = { projectPath: string; sourcePath: string; ensurePar
19
20
  ----------------------------------*/
20
21
 
21
22
  // Project-local AGENTS entrypoints mapped to their framework-owned source files.
22
- const codexAgentLinkDefinitions: TAgentLinkDefinition[] = [
23
+ const projectAgentLinkDefinitions: TAgentLinkDefinition[] = [
23
24
  { projectPath: 'AGENTS.md', sourcePath: 'AGENTS.md' },
24
25
  { projectPath: 'CODING_STYLE.md', sourcePath: 'CODING_STYLE.md' },
25
26
  { projectPath: path.join('client', 'AGENTS.md'), sourcePath: path.join('client', 'AGENTS.md') },
@@ -37,8 +38,8 @@ const codexAgentLinkDefinitions: TAgentLinkDefinition[] = [
37
38
  ----------------------------------*/
38
39
 
39
40
  export function ensureProjectAgentSymlinks({ appRoot, coreRoot }: TEnsureProjectAgentSymlinksArgs) {
40
- const agentSourceRoot = path.join(coreRoot, 'agents', 'codex');
41
- const agentLinks = codexAgentLinkDefinitions.map((linkDefinition) => ({
41
+ const agentSourceRoot = path.join(coreRoot, 'agents', 'project');
42
+ const agentLinks = projectAgentLinkDefinitions.map((linkDefinition) => ({
42
43
  ...linkDefinition,
43
44
  sourcePath: path.join(agentSourceRoot, linkDefinition.sourcePath),
44
45
  }));
@@ -86,7 +87,7 @@ function ensureSymlinks(appRoot: string, linkDefinitions: TAgentLinkDefinition[]
86
87
  const symlinkTarget = path.relative(projectParentDir, sourceFilepath);
87
88
  fs.symlinkSync(symlinkTarget, projectFilepath);
88
89
 
89
- console.info(`${logPrefix} Created ${path.relative(appRoot, projectFilepath) || '.'} -> ${symlinkTarget}`);
90
+ logVerbose(`${logPrefix} Created ${path.relative(appRoot, projectFilepath) || '.'} -> ${symlinkTarget}`);
90
91
  }
91
92
  }
92
93
 
@@ -4,12 +4,13 @@
4
4
 
5
5
  // npm
6
6
  import readline, { Key } from 'readline';
7
+ import { logVerbose } from '../runtime/verbose';
7
8
 
8
9
  /*----------------------------------
9
10
  - TYPES
10
11
  ----------------------------------*/
11
12
 
12
- type TKeyboardCommand = { remove?: boolean; run: (str: string, chunk: string, key: Key) => void };
13
+ type TKeyboardCommand = { remove?: boolean; run: (str: string, chunk: string, key: Key) => void | Promise<void> };
13
14
 
14
15
  /*----------------------------------
15
16
  - METHODS
@@ -34,14 +35,19 @@ class KeyboardCommands {
34
35
  if (key.meta) str = 'meta+' + str;
35
36
 
36
37
  const kCommand = this.commands[str] || this.commands.fallback;
37
- if (kCommand) {
38
- kCommand.run(str, chunk, key);
39
38
 
40
- if (kCommand.remove) delete this.commands[str];
39
+ try {
40
+ if (kCommand) {
41
+ await kCommand.run(str, chunk, key);
42
+
43
+ if (kCommand.remove) delete this.commands[str];
44
+ }
45
+ } catch (error) {
46
+ console.error(error);
41
47
  }
42
48
 
43
- if (str === 'ctrl+c') {
44
- console.log(`Exiting ...`);
49
+ if (str === 'ctrl+c' && !kCommand) {
50
+ logVerbose(`Exiting ...`);
45
51
  process.exit(0);
46
52
  }
47
53
  });
@@ -56,7 +56,6 @@ export default abstract class Application {
56
56
  public constructor() {}
57
57
 
58
58
  public registerService(service: AnyService) {
59
- console.log(`[app] Register service`, service.constructor?.name);
60
59
  this.servicesList.push(service);
61
60
  }
62
61
 
@@ -69,14 +68,9 @@ export default abstract class Application {
69
68
  public abstract boot(): void;
70
69
 
71
70
  public startServices() {
72
- console.log(`[app] Starting ${this.servicesList.length} services.`);
73
-
74
71
  for (const service of this.servicesList) {
75
- console.log(`[app] Start service`, service);
76
72
  service.start();
77
73
  }
78
-
79
- console.log(`[app] All ${this.servicesList.length} services were started.`);
80
74
  }
81
75
 
82
76
  public bindErrorHandlers() {
@@ -44,7 +44,7 @@ import ClientPage from './response/page';
44
44
  type AppPropsContext = Parameters<typeof App>[0]['context'];
45
45
 
46
46
  // Routes (import __register)
47
- import appRoutes from '@/client/.generated/routes';
47
+ import appRoutes from '@generated/client/routes';
48
48
 
49
49
  /*----------------------------------
50
50
  - CONFIG
@@ -15,8 +15,8 @@ import type ClientResponse from '@client/services/router/response';
15
15
  import ClientRequest from '@client/services/router/request';
16
16
  import ClientPage from '@client/services/router/response/page';
17
17
  import { history } from '@client/services/router/request/history';
18
- import createControllers from '@/common/.generated/controllers';
19
- import type { TControllers } from '@/common/.generated/controllers';
18
+ import createControllers from '@generated/common/controllers';
19
+ import type { TControllers } from '@generated/common/controllers';
20
20
 
21
21
  /*----------------------------------
22
22
  - TYPES
@@ -2,6 +2,7 @@ export const serverHotReloadMessageType = {
2
2
  request: 'proteum:router-reload',
3
3
  succeeded: 'proteum:router-reload-succeeded',
4
4
  failed: 'proteum:router-reload-failed',
5
+ ready: 'proteum:server-ready',
5
6
  } as const;
6
7
 
7
8
  export type TServerHotReloadRequest = { type: typeof serverHotReloadMessageType.request; changedFiles: string[] };
@@ -12,6 +13,11 @@ export type TServerHotReloadResult = {
12
13
  error?: string;
13
14
  };
14
15
 
16
+ export type TServerReadyMessage = {
17
+ type: typeof serverHotReloadMessageType.ready;
18
+ publicUrl: string;
19
+ };
20
+
15
21
  export const isServerHotReloadRequest = (value: unknown): value is TServerHotReloadRequest =>
16
22
  typeof value === 'object' &&
17
23
  value !== null &&
@@ -24,3 +30,9 @@ export const isServerHotReloadResult = (value: unknown): value is TServerHotRelo
24
30
  ((value as TServerHotReloadResult).type === serverHotReloadMessageType.succeeded ||
25
31
  (value as TServerHotReloadResult).type === serverHotReloadMessageType.failed) &&
26
32
  Array.isArray((value as TServerHotReloadResult).changedFiles);
33
+
34
+ export const isServerReadyMessage = (value: unknown): value is TServerReadyMessage =>
35
+ typeof value === 'object' &&
36
+ value !== null &&
37
+ (value as TServerReadyMessage).type === serverHotReloadMessageType.ready &&
38
+ typeof (value as TServerReadyMessage).publicUrl === 'string';
@@ -13,7 +13,7 @@ import type { TAnyRouter, TRouterContext as ServerRouterContext, TRouteHttpMetho
13
13
 
14
14
  import type RouterRequest from './request';
15
15
 
16
- import type { TUserRole } from '@server/services/auth';
16
+ import type { TAuthCheckInput, TAuthTrackingContext } from '@server/services/auth';
17
17
 
18
18
  import type { TAppArrowFunction } from '@common/app';
19
19
 
@@ -86,7 +86,8 @@ export type TRouteOptions = {
86
86
  domain?: string;
87
87
  accept?: string;
88
88
  raw?: boolean; // true to return raw data
89
- auth?: TUserRole | boolean;
89
+ auth?: TAuthCheckInput;
90
+ authTracking?: TAuthTrackingContext;
90
91
  redirectLogged?: string; // Redirect to this route if auth: false and user is logged
91
92
 
92
93
  // Rendering
@@ -11,7 +11,7 @@ import type { TDataProvider, TPageRenderContext } from './response/page';
11
11
 
12
12
  // App
13
13
  import internalLayout from '@client/pages/_layout';
14
- import generatedLayouts, { layoutOrder } from '@/client/.generated/layouts';
14
+ import generatedLayouts, { layoutOrder } from '@generated/client/layouts';
15
15
 
16
16
  /*----------------------------------
17
17
  - CONST
@@ -11,6 +11,7 @@ export const routeSetupOptionKeys = [
11
11
  'accept',
12
12
  'raw',
13
13
  'auth',
14
+ 'authTracking',
14
15
  'redirectLogged',
15
16
  'static',
16
17
  'whenStatic',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "proteum",
3
- "description": "AI-first SSR, SEO, and TypeScript framework optimized for autonomous agent development.",
4
- "version": "2.0.0",
3
+ "description": "LLM-first Opinionated Typescript Framework for web applications.",
4
+ "version": "2.1.0",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/proteum.git",
7
7
  "license": "MIT",
@@ -16,7 +16,9 @@
16
16
  "proteum": "cli/bin.js"
17
17
  },
18
18
  "dependencies": {
19
- "@prisma/client": "^6.5.0",
19
+ "@inkjs/ui": "^2.0.0",
20
+ "@prisma/adapter-mariadb": "7.2.0",
21
+ "@prisma/client": "7.2.0",
20
22
  "@rspack/core": "^1.7.9",
21
23
  "@tailwindcss/postcss": "^4.1.17",
22
24
  "accepts": "^1.3.7",
@@ -25,12 +27,14 @@
25
27
  "aws-sdk": "^2.1415.0",
26
28
  "bowser": "^2.11.0",
27
29
  "cli-highlight": "^2.1.11",
30
+ "clipanion": "^4.0.0-rc.4",
28
31
  "compression": "^1.7.4",
29
32
  "cookie-parser": "^1.4.5",
30
33
  "cors": "^2.8.5",
31
34
  "cron-parser": "^4.0.0",
32
35
  "css-loader": "^6.2.0",
33
36
  "dayjs": "^1.11.5",
37
+ "dotenv": "^17.2.3",
34
38
  "escape-regexp": "^0.0.1",
35
39
  "eslint": "^9.39.4",
36
40
  "eslint-plugin-jsx-a11y": "^6.10.2",
@@ -47,6 +51,7 @@
47
51
  "history": "^5.0.1",
48
52
  "hpp": "^0.2.3",
49
53
  "human-interval": "^2.0.1",
54
+ "ink": "^6.8.0",
50
55
  "intl": "^1.2.5",
51
56
  "iso-639-1": "^2.1.9",
52
57
  "jsonwebtoken": "^8.5.1",
@@ -72,7 +77,6 @@
72
77
  "slugify": "^1.6.6",
73
78
  "source-map-support": "^0.5.21",
74
79
  "stopword": "^3.1.1",
75
- "style-loader": "^4.0.0",
76
80
  "tailwindcss": "^4.1.17",
77
81
  "ts-alias": "^0.0.7",
78
82
  "ts-node": "^10.9.1",
@@ -81,8 +85,8 @@
81
85
  "typescript-eslint": "^8.57.1",
82
86
  "uuid": "^8.3.2",
83
87
  "validator": "^13.7.0",
88
+ "webpack-bundle-analyzer": "^5.2.0",
84
89
  "yaml": "^1.10.2",
85
- "yargs-parser": "^21.1.1",
86
90
  "youch": "^3.3.3",
87
91
  "youch-terminal": "^2.2.3",
88
92
  "zod": "^4.1.5"
@@ -101,8 +105,6 @@
101
105
  "@types/prompts": "^2.0.14",
102
106
  "@types/sharp": "^0.31.1",
103
107
  "@types/universal-analytics": "^0.4.5",
104
- "@types/yargs-parser": "^21.0.0",
105
- "schema-dts": "^1.1.2",
106
- "webpack-bundle-analyzer": "^5.2.0"
108
+ "schema-dts": "^1.1.2"
107
109
  }
108
110
  }
@@ -0,0 +1,52 @@
1
+ const path = require('path');
2
+ const { createRequire } = require('module');
3
+
4
+ const requireFromWorkspace = createRequire(path.join(process.cwd(), 'package.json'));
5
+
6
+ const estreePlugin = (() => {
7
+ try {
8
+ return requireFromWorkspace('prettier/plugins/estree');
9
+ } catch {
10
+ return require('prettier/plugins/estree');
11
+ }
12
+ })();
13
+
14
+ const basePrinter = estreePlugin.printers.estree;
15
+ const ROUTER_REGISTRATION_METHODS = new Set(['page', 'error']);
16
+
17
+ const isRouterRegistrationCall = (node) =>
18
+ node?.type === 'CallExpression' &&
19
+ node.callee?.type === 'MemberExpression' &&
20
+ node.callee.object?.type === 'Identifier' &&
21
+ node.callee.object.name === 'Router' &&
22
+ node.callee.property?.type === 'Identifier' &&
23
+ ROUTER_REGISTRATION_METHODS.has(node.callee.property.name);
24
+
25
+ const printRouterRegistrationCall = (path, print) => {
26
+ const node = path.getValue();
27
+ const parts = [path.call(print, 'callee'), '('];
28
+
29
+ for (const [index] of node.arguments.entries()) {
30
+ if (index > 0) parts.push(', ');
31
+ parts.push(path.call(print, 'arguments', index));
32
+ }
33
+
34
+ parts.push(')');
35
+
36
+ return parts;
37
+ };
38
+
39
+ module.exports = {
40
+ printers: {
41
+ estree: {
42
+ ...basePrinter,
43
+ print(path, options, print) {
44
+ const node = path.getValue();
45
+
46
+ if (isRouterRegistrationCall(node)) return printRouterRegistrationCall(path, print);
47
+
48
+ return basePrinter.print(path, options, print);
49
+ },
50
+ },
51
+ },
52
+ };
@@ -6,4 +6,5 @@ module.exports = {
6
6
  semi: true,
7
7
  trailingComma: 'all',
8
8
  objectWrap: 'preserve',
9
+ plugins: [require.resolve('./prettier/router-registration-plugin.cjs')],
9
10
  };
@@ -14,7 +14,7 @@ const findControllerFiles = (dir: string): string[] => {
14
14
  continue;
15
15
  }
16
16
 
17
- if (dirent.isFile() && dirent.name.endsWith('.controller.ts')) files.push(filepath);
17
+ if (dirent.isFile() && /\.(tsx?|jsx?)$/.test(dirent.name) && !dirent.name.endsWith('.d.ts')) files.push(filepath);
18
18
  }
19
19
 
20
20
  return files;
@@ -25,7 +25,7 @@ if (!repoRoots.length)
25
25
  throw new Error('Usage: ts-node scripts/cleanup-generated-controllers.ts <repo-root> [repo-root...]');
26
26
 
27
27
  for (const repoRoot of repoRoots) {
28
- const controllerFiles = findControllerFiles(path.join(repoRoot, 'server', 'services'));
28
+ const controllerFiles = findControllerFiles(path.join(repoRoot, 'server', 'controllers'));
29
29
  let updated = 0;
30
30
 
31
31
  for (const controllerFile of controllerFiles) {
@@ -196,11 +196,11 @@ const patchCentralFiles = () => {
196
196
  ),
197
197
  );
198
198
 
199
- applyLiteralReplacement(path.join(UNIQUE_ROOT, 'server/services/Domains/search/search.controller.ts'), (source) =>
199
+ applyLiteralReplacement(path.join(UNIQUE_ROOT, 'server/controllers/Domains/search.ts'), (source) =>
200
200
  source.includes(' public async GetLandingSeoCachedSearches() {')
201
201
  ? source
202
202
  : assertReplace(
203
- path.join(UNIQUE_ROOT, 'server/services/Domains/search/search.controller.ts'),
203
+ path.join(UNIQUE_ROOT, 'server/controllers/Domains/search.ts'),
204
204
  source,
205
205
  ` public async GetLandingSeoCachedSearch() {
206
206
  const { Domains } = this.services;