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.
Files changed (95) hide show
  1. package/AGENTS.md +44 -98
  2. package/README.md +143 -10
  3. package/agents/framework/AGENTS.md +146 -886
  4. package/agents/project/AGENTS.md +73 -127
  5. package/agents/project/client/AGENTS.md +22 -93
  6. package/agents/project/client/pages/AGENTS.md +24 -26
  7. package/agents/project/server/routes/AGENTS.md +10 -8
  8. package/agents/project/server/services/AGENTS.md +22 -159
  9. package/agents/project/tests/AGENTS.md +11 -8
  10. package/cli/app/config.ts +7 -20
  11. package/cli/bin.js +8 -0
  12. package/cli/commands/command.ts +243 -0
  13. package/cli/commands/commandLocalRunner.js +198 -0
  14. package/cli/commands/create.ts +5 -0
  15. package/cli/commands/deploy/web.ts +1 -2
  16. package/cli/commands/dev.ts +98 -2
  17. package/cli/commands/doctor.ts +8 -74
  18. package/cli/commands/explain.ts +8 -186
  19. package/cli/commands/init.ts +2 -94
  20. package/cli/commands/trace.ts +228 -0
  21. package/cli/compiler/artifacts/commands.ts +217 -0
  22. package/cli/compiler/artifacts/manifest.ts +35 -21
  23. package/cli/compiler/artifacts/services.ts +300 -1
  24. package/cli/compiler/client/index.ts +43 -8
  25. package/cli/compiler/common/commands.ts +175 -0
  26. package/cli/compiler/common/index.ts +1 -1
  27. package/cli/compiler/common/proteumManifest.ts +15 -114
  28. package/cli/compiler/index.ts +25 -2
  29. package/cli/compiler/server/index.ts +31 -6
  30. package/cli/index.ts +1 -4
  31. package/cli/paths.ts +16 -1
  32. package/cli/presentation/commands.ts +104 -14
  33. package/cli/presentation/devSession.ts +22 -3
  34. package/cli/presentation/proteum_logo_400x400_square_icon.txt +400 -0
  35. package/cli/runtime/commands.ts +121 -4
  36. package/cli/scaffold/index.ts +720 -0
  37. package/cli/scaffold/templates.ts +344 -0
  38. package/cli/scaffold/types.ts +26 -0
  39. package/cli/tsconfig.json +4 -1
  40. package/cli/utils/check.ts +1 -1
  41. package/client/app/component.tsx +13 -9
  42. package/client/dev/profiler/index.tsx +2511 -0
  43. package/client/dev/profiler/noop.tsx +5 -0
  44. package/client/dev/profiler/runtime.noop.ts +116 -0
  45. package/client/dev/profiler/runtime.ts +840 -0
  46. package/client/services/router/components/router.tsx +30 -2
  47. package/client/services/router/index.tsx +27 -3
  48. package/client/services/router/request/api.ts +133 -17
  49. package/commands/proteum/diagnostics.ts +11 -0
  50. package/common/dev/commands.ts +50 -0
  51. package/common/dev/diagnostics.ts +298 -0
  52. package/common/dev/profiler.ts +92 -0
  53. package/common/dev/proteumManifest.ts +135 -0
  54. package/common/dev/requestTrace.ts +115 -0
  55. package/common/env/proteumEnv.ts +284 -0
  56. package/common/router/index.ts +4 -22
  57. package/docs/dev-commands.md +93 -0
  58. package/docs/diagnostics.md +88 -0
  59. package/docs/request-tracing.md +132 -0
  60. package/eslint.js +11 -6
  61. package/package.json +3 -3
  62. package/server/app/commands.ts +35 -370
  63. package/server/app/commandsManager.ts +393 -0
  64. package/server/app/container/config.ts +11 -49
  65. package/server/app/container/console/index.ts +2 -3
  66. package/server/app/container/index.ts +5 -2
  67. package/server/app/container/trace/index.ts +364 -0
  68. package/server/app/devCommands.ts +192 -0
  69. package/server/app/devDiagnostics.ts +53 -0
  70. package/server/app/index.ts +29 -6
  71. package/server/index.ts +0 -1
  72. package/server/services/auth/index.ts +525 -61
  73. package/server/services/auth/router/index.ts +106 -7
  74. package/server/services/cron/CronTask.ts +73 -5
  75. package/server/services/cron/index.ts +34 -11
  76. package/server/services/fetch/index.ts +3 -10
  77. package/server/services/prisma/index.ts +66 -4
  78. package/server/services/router/http/index.ts +173 -6
  79. package/server/services/router/index.ts +200 -12
  80. package/server/services/router/request/api.ts +30 -1
  81. package/server/services/router/response/index.ts +83 -10
  82. package/server/services/router/response/page/document.tsx +16 -0
  83. package/server/services/router/response/page/index.tsx +27 -1
  84. package/skills/clean-project-code/SKILL.md +7 -2
  85. package/test-results/.last-run.json +4 -0
  86. package/types/aliases.d.ts +6 -0
  87. package/types/global/utils.d.ts +7 -14
  88. package/Rte.zip +0 -0
  89. package/agents/project/agents.md.zip +0 -0
  90. package/doc/TODO.md +0 -71
  91. package/doc/front/router.md +0 -27
  92. package/doc/workspace/workspace.png +0 -0
  93. package/doc/workspace/workspace2.png +0 -0
  94. package/doc/workspace/workspace_26.01.22.png +0 -0
  95. package/server/services/router/http/session.ts.old +0 -40
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "proteum",
3
3
  "description": "LLM-first Opinionated Typescript Framework for web applications.",
4
- "version": "2.1.0",
4
+ "version": "2.1.2",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/proteum.git",
7
7
  "license": "MIT",
@@ -23,6 +23,7 @@
23
23
  "@tailwindcss/postcss": "^4.1.17",
24
24
  "accepts": "^1.3.7",
25
25
  "ansi-to-html": "^0.7.1",
26
+ "apexcharts": "^5.10.4",
26
27
  "autoprefixer": "^10.4.21",
27
28
  "aws-sdk": "^2.1415.0",
28
29
  "bowser": "^2.11.0",
@@ -41,7 +42,6 @@
41
42
  "eslint-plugin-react": "^7.37.5",
42
43
  "eslint-plugin-react-hooks": "^7.0.1",
43
44
  "express": "^4.17.1",
44
- "express-csp-header": "^5.0.0",
45
45
  "express-fileupload": "^1.2.1",
46
46
  "fast-safe-stringify": "^2.1.1",
47
47
  "favicons": "^7.2.0",
@@ -69,8 +69,8 @@
69
69
  "preact": "^10.27.1",
70
70
  "preact-render-to-string": "^6.6.1",
71
71
  "prompts": "^2.4.2",
72
+ "react-apexcharts": "^2.1.0",
72
73
  "replace-once": "^1.0.0",
73
- "request": "^2.88.2",
74
74
  "responsive-loader": "^3.1.2",
75
75
  "serialize-javascript": "^6.0.2",
76
76
  "sharp": "^0.34.3",
@@ -2,395 +2,60 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
- // Npm
6
- import { Cli, Command as ClipanionCommand, Option, UsageError } from 'clipanion';
7
-
8
- // Core
9
- import type { Application } from './index';
10
- import Service from '@server/app/service';
11
- import { InputError, NotFound } from '@common/errors';
5
+ import { Command as ClipanionCommand, Option, UsageError } from 'clipanion';
6
+ import type CurrentCommandApplication from '@/server/index';
12
7
 
13
8
  /*----------------------------------
14
9
  - TYPES
15
10
  ----------------------------------*/
16
11
 
17
- type CommandCallback<TArgs extends any[]> = (...args: TArgs) => Promise<any>;
18
-
19
- export type CommandsList = { [commandName: string]: RuntimeCommand };
20
-
21
- export type RuntimeCommand<TArgs extends any[] = any[]> = {
22
- name: string;
23
- description: string;
24
- run?: CommandCallback<TArgs>;
25
- childrens: CommandsList;
26
- };
27
-
28
- /*----------------------------------
29
- - SERVICE TYPES
30
- ----------------------------------*/
31
-
32
- const LogPrefix = `[commands]`;
33
-
34
- export type Config = { debug: boolean };
35
-
36
- export type Hooks = {};
37
-
38
- export type Services = {};
39
-
40
- type TCommandArgumentValue = string | number | boolean;
41
- type TParsedCommandArgs = { [key: string]: TCommandArgumentValue | TCommandArgumentValue[] };
42
-
43
- const commandValuePattern = /^-?(?:\d+|\d*\.\d+)$/;
44
-
45
- const tokenizeCommandString = (commandString: string) => {
46
- const tokens: string[] = [];
47
- let currentToken = '';
48
- let quote: '"' | "'" | undefined;
49
- let escaping = false;
50
-
51
- for (const character of commandString) {
52
- if (escaping) {
53
- currentToken += character;
54
- escaping = false;
55
- continue;
56
- }
57
-
58
- if (character === '\\') {
59
- escaping = true;
60
- continue;
61
- }
62
-
63
- if (quote) {
64
- if (character === quote) {
65
- quote = undefined;
66
- continue;
67
- }
68
-
69
- currentToken += character;
70
- continue;
71
- }
72
-
73
- if (character === '"' || character === "'") {
74
- quote = character;
75
- continue;
76
- }
77
-
78
- if (/\s/.test(character)) {
79
- if (!currentToken) continue;
80
-
81
- tokens.push(currentToken);
82
- currentToken = '';
83
- continue;
84
- }
85
-
86
- currentToken += character;
87
- }
88
-
89
- if (escaping) currentToken += '\\';
90
- if (currentToken) tokens.push(currentToken);
91
-
92
- return tokens;
93
- };
94
-
95
- const isOptionToken = (token: string) => /^-(?!\d+(\.\d+)?$).+/.test(token);
96
-
97
- const normalizeCommandValue = (value: string): TCommandArgumentValue => {
98
- if (value === 'true') return true;
99
- if (value === 'false') return false;
100
- if (commandValuePattern.test(value)) return Number(value);
101
-
102
- return value;
12
+ export type TCommandApplication = {
13
+ env: {
14
+ profile?: string;
15
+ name?: string;
16
+ [key: string]: unknown;
17
+ };
18
+ identity: {
19
+ identifier?: string;
20
+ [key: string]: unknown;
21
+ };
22
+ getRootServices: () => Record<string, unknown>;
23
+ findService?: (serviceId: string) => unknown;
24
+ models?: { client?: any };
25
+ Models?: { client?: any };
103
26
  };
104
27
 
105
- const addParsedArgValue = (args: TParsedCommandArgs, key: string, value: TCommandArgumentValue) => {
106
- const existingValue = args[key];
107
-
108
- if (existingValue === undefined) {
109
- args[key] = value;
110
- return;
111
- }
112
-
113
- args[key] = Array.isArray(existingValue) ? [...existingValue, value] : [existingValue, value];
114
- };
115
-
116
- const parseCommandOptionTokens = (tokens: string[]) => {
117
- const namedArguments: TParsedCommandArgs = {};
118
- const positionalArguments: string[] = [];
119
-
120
- let usePositionalOnly = false;
121
-
122
- for (let index = 0; index < tokens.length; index++) {
123
- const token = tokens[index];
124
-
125
- if (usePositionalOnly) {
126
- positionalArguments.push(token);
127
- continue;
128
- }
129
-
130
- if (token === '--') {
131
- usePositionalOnly = true;
132
- continue;
133
- }
134
-
135
- if (token === '--help' || token === '-h') return { help: true as const, args: namedArguments, positionalArguments };
136
-
137
- if (token.startsWith('--') && token.length > 2) {
138
- const body = token.slice(2);
139
-
140
- if (body.startsWith('no-') && body.length > 3) {
141
- addParsedArgValue(namedArguments, body.slice(3), false);
142
- continue;
143
- }
144
-
145
- const equalsIndex = body.indexOf('=');
146
-
147
- if (equalsIndex >= 0) {
148
- addParsedArgValue(
149
- namedArguments,
150
- body.slice(0, equalsIndex),
151
- normalizeCommandValue(body.slice(equalsIndex + 1)),
152
- );
153
- continue;
154
- }
155
-
156
- const nextToken = tokens[index + 1];
157
-
158
- if (nextToken !== undefined && !isOptionToken(nextToken)) {
159
- addParsedArgValue(namedArguments, body, normalizeCommandValue(nextToken));
160
- index++;
161
- continue;
162
- }
163
-
164
- addParsedArgValue(namedArguments, body, true);
165
- continue;
166
- }
167
-
168
- if (token.startsWith('-') && token.length > 1 && !commandValuePattern.test(token)) {
169
- const body = token.slice(1);
170
- const equalsIndex = body.indexOf('=');
171
-
172
- if (equalsIndex >= 0) {
173
- addParsedArgValue(
174
- namedArguments,
175
- body.slice(0, equalsIndex),
176
- normalizeCommandValue(body.slice(equalsIndex + 1)),
177
- );
178
- continue;
179
- }
180
-
181
- const nextToken = tokens[index + 1];
182
-
183
- if (body.length === 1 && nextToken !== undefined && !isOptionToken(nextToken)) {
184
- addParsedArgValue(namedArguments, body, normalizeCommandValue(nextToken));
185
- index++;
186
- continue;
187
- }
188
-
189
- for (const shortFlag of body) addParsedArgValue(namedArguments, shortFlag, true);
190
-
191
- continue;
192
- }
193
-
194
- positionalArguments.push(token);
195
- }
196
-
197
- return { help: false as const, args: namedArguments, positionalArguments };
28
+ export type TCommandService = {
29
+ [key: string]: unknown;
198
30
  };
199
31
 
200
32
  /*----------------------------------
201
- - SERVICE
33
+ - COMMAND CLASSES
202
34
  ----------------------------------*/
203
- export default class CommandsManager extends Service<Config, Hooks, Application> {
204
- public priority = 2 as 2;
205
-
206
- public commandsIndex: CommandsList = {};
207
-
208
- private runtimeCli?: Cli;
209
-
210
- public command<TArgs extends any[]>(
211
- ...args:
212
- | [name: string, description: string, childrens: RuntimeCommand[]]
213
- | [name: string, description: string, run: CommandCallback<TArgs>, childrens?: RuntimeCommand[]]
214
- ): RuntimeCommand {
215
- let name: string, description: string;
216
- let childrens: RuntimeCommand[] | undefined;
217
- let run: CommandCallback<TArgs> | undefined;
218
-
219
- if (typeof args[2] === 'object') [name, description, childrens] = args;
220
- else [name, description, run, childrens] = args;
221
-
222
- const command: RuntimeCommand = { name, description, run, childrens: childrens ? this.indexFromList(childrens) : {} };
223
-
224
- return command;
225
- }
226
35
 
227
- private indexFromList(list: RuntimeCommand[]): CommandsList {
228
- const index: CommandsList = {};
229
- for (const command of list) index[command.name] = command;
36
+ export abstract class Commands<TApplication extends TCommandApplication = CurrentCommandApplication> {
37
+ public app: CurrentCommandApplication;
230
38
 
231
- return index;
39
+ public constructor(app: CurrentCommandApplication) {
40
+ this.app = app;
232
41
  }
233
42
 
234
- private invalidateRuntimeCli() {
235
- this.runtimeCli = undefined;
43
+ public get services(): CurrentCommandApplication {
44
+ return this.app;
236
45
  }
237
46
 
238
- private createRuntimeCommandClass(command: RuntimeCommand, path: string[]) {
239
- const manager = this;
240
- const usage = ClipanionCommand.Usage({ description: command.description });
241
-
242
- if (command.run === undefined) {
243
- class RuntimeNamespaceCommand extends ClipanionCommand {
244
- public static override paths = [path];
245
- public static override usage = usage;
246
-
247
- public async execute() {
248
- throw new NotFound(`This command isn't runnable.`);
249
- }
250
- }
251
-
252
- Object.defineProperty(RuntimeNamespaceCommand, 'name', {
253
- value: `${path.map((segment) => segment.replace(/[^A-Za-z0-9]/g, '_')).join('_') || 'Root'}NamespaceCommand`,
254
- });
255
-
256
- return RuntimeNamespaceCommand;
257
- }
258
-
259
- class RuntimeRunnableCommand extends ClipanionCommand {
260
- public static override paths = [path];
261
- public static override usage = usage;
262
-
263
- public proxy = Option.Proxy({ name: 'args' });
264
-
265
- public async execute() {
266
- return manager.executeRegisteredCommand(command, path, this.proxy);
267
- }
268
- }
269
-
270
- Object.defineProperty(RuntimeRunnableCommand, 'name', {
271
- value: `${path.map((segment) => segment.replace(/[^A-Za-z0-9]/g, '_')).join('_') || 'Root'}RunnableCommand`,
272
- });
273
-
274
- return RuntimeRunnableCommand;
275
- }
276
-
277
- private createRuntimeCli() {
278
- const cli = new Cli({
279
- binaryName: this.app.identity.identifier || 'app',
280
- enableCapture: false,
281
- });
282
-
283
- const registerCommands = (commands: CommandsList, parentPath: string[] = []) => {
284
- for (const command of Object.values(commands)) {
285
- const path = [...parentPath, command.name];
286
-
287
- cli.register(this.createRuntimeCommandClass(command, path));
288
-
289
- if (Object.keys(command.childrens).length > 0) registerCommands(command.childrens, path);
290
- }
47
+ public get models(): any {
48
+ const app = this.app as {
49
+ models?: { client?: any };
50
+ Models?: { client?: any };
291
51
  };
52
+ const models = app.models?.client ?? app.Models?.client;
292
53
 
293
- registerCommands(this.commandsIndex);
294
-
295
- return cli;
296
- }
297
-
298
- private getRuntimeCli() {
299
- this.runtimeCli ??= this.createRuntimeCli();
54
+ if (!models)
55
+ throw new Error(`${this.constructor.name} tried to access models but no Models service is registered.`);
300
56
 
301
- return this.runtimeCli;
302
- }
303
-
304
- private async executeRegisteredCommand(command: RuntimeCommand, path: string[], proxyTokens: string[]) {
305
- if (command.run === undefined) throw new NotFound(`This command isn't runnable.`);
306
-
307
- const { help, args, positionalArguments } = parseCommandOptionTokens(proxyTokens);
308
-
309
- this.config.debug &&
310
- console.log(LogPrefix, `Run command path: ${path.join(' ')} | Parsed proxy tokens:`, {
311
- proxyTokens,
312
- args,
313
- positionalArguments,
314
- });
315
-
316
- if (help) {
317
- const cli = this.getRuntimeCli();
318
- const runtimeCommand = cli.process(path, Cli.defaultContext);
319
-
320
- return cli.usage(runtimeCommand, { detailed: true });
321
- }
322
-
323
- if (positionalArguments.length > 0) {
324
- throw new UsageError(
325
- `Unexpected positional arguments for "${path.join(' ')}": ${positionalArguments.join(', ')}.`,
326
- );
327
- }
328
-
329
- const argsList = Object.values(args);
330
-
331
- return command.run(...(argsList as Parameters<NonNullable<typeof command.run>>));
332
- }
333
-
334
- private createRuntimeCliApi(cli: Cli) {
335
- return {
336
- binaryLabel: cli.binaryLabel,
337
- binaryName: cli.binaryName,
338
- binaryVersion: cli.binaryVersion,
339
- enableCapture: cli.enableCapture,
340
- enableColors: cli.enableColors,
341
- definitions: () => cli.definitions(),
342
- definition: (commandClass: any) => cli.definition(commandClass),
343
- error: (error: Error, opts?: any) => cli.error(error, opts),
344
- format: (colored?: boolean) => cli.format(colored),
345
- process: (input: string[]) => cli.process(input, Cli.defaultContext),
346
- run: (input: string[]) => cli.run(input, Cli.defaultContext),
347
- usage: (command?: any, opts?: any) => cli.usage(command, opts),
348
- };
349
- }
350
-
351
- /*----------------------------------
352
- - REGISTER
353
- ----------------------------------*/
354
- public fromList(list: RuntimeCommand[]) {
355
- for (const command of list) {
356
- if (this.commandsIndex[command.name] !== undefined)
357
- throw new Error(`Tried to register command "${command.name}", but it already has been defined.`);
358
-
359
- this.commandsIndex[command.name] = command;
360
- }
361
-
362
- this.invalidateRuntimeCli();
363
- }
364
-
365
- /*----------------------------------
366
- - RUN
367
- ----------------------------------*/
368
- public async run(commandString: string) {
369
- const tokens = tokenizeCommandString(commandString);
370
-
371
- this.config.debug && console.log(LogPrefix, `Run command: ${commandString} | Tokens:`, tokens);
372
-
373
- if (tokens.length === 0) throw new NotFound(`Command not found.`);
374
-
375
- const cli = this.getRuntimeCli();
376
-
377
- try {
378
- const command = cli.process(tokens, Cli.defaultContext);
379
-
380
- if (command.help) return cli.usage(command, { detailed: true });
381
-
382
- command.context = Cli.defaultContext;
383
- command.cli = this.createRuntimeCliApi(cli);
384
-
385
- return await command.validateAndExecute();
386
- } catch (error) {
387
- if (error instanceof UsageError) throw new InputError(error.message);
388
-
389
- if (error instanceof Error && ['UnknownSyntaxError', 'AmbiguousSyntaxError'].includes(error.name)) {
390
- throw new NotFound(error.message);
391
- }
392
-
393
- throw error;
394
- }
57
+ return models;
395
58
  }
396
59
  }
60
+
61
+ export { ClipanionCommand as Command, Option, UsageError };