proteum 2.1.0 → 2.1.1
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 +121 -7
- package/agents/framework/AGENTS.md +133 -886
- package/agents/project/AGENTS.md +70 -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/deploy/web.ts +1 -2
- package/cli/commands/dev.ts +96 -1
- package/cli/commands/doctor.ts +8 -74
- package/cli/commands/explain.ts +8 -186
- 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/paths.ts +16 -1
- package/cli/presentation/commands.ts +59 -5
- package/cli/presentation/devSession.ts +5 -0
- package/cli/runtime/commands.ts +60 -1
- 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 +1511 -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 +91 -0
- package/common/dev/proteumManifest.ts +135 -0
- package/common/dev/requestTrace.ts +109 -0
- package/common/env/proteumEnv.ts +284 -0
- package/common/router/index.ts +4 -22
- package/docs/dev-commands.md +86 -0
- package/docs/request-tracing.md +122 -0
- package/package.json +1 -2
- 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 +27 -4
- 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 +151 -0
- 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
|
@@ -13,6 +13,8 @@ export const proteumCommandNames = [
|
|
|
13
13
|
'check',
|
|
14
14
|
'doctor',
|
|
15
15
|
'explain',
|
|
16
|
+
'trace',
|
|
17
|
+
'command',
|
|
16
18
|
] as const;
|
|
17
19
|
|
|
18
20
|
export type TProteumCommandName = (typeof proteumCommandNames)[number];
|
|
@@ -45,7 +47,7 @@ export const proteumRecommendedFlow: TRow[] = [
|
|
|
45
47
|
export const proteumCommandGroups: Array<{ title: string; names: TProteumCommandName[] }> = [
|
|
46
48
|
{ title: 'Daily workflow', names: ['dev', 'refresh', 'build'] },
|
|
47
49
|
{ title: 'Quality gates', names: ['typecheck', 'lint', 'check'] },
|
|
48
|
-
{ title: 'Manifest and contracts', names: ['doctor', 'explain'] },
|
|
50
|
+
{ title: 'Manifest and contracts', names: ['doctor', 'explain', 'trace', 'command'] },
|
|
49
51
|
{ title: 'Project scaffolding', names: ['init'] },
|
|
50
52
|
];
|
|
51
53
|
|
|
@@ -170,20 +172,72 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
170
172
|
name: 'explain',
|
|
171
173
|
category: 'Manifest and contracts',
|
|
172
174
|
summary: 'Explain the generated Proteum manifest.',
|
|
173
|
-
usage: 'proteum explain [--all|--app|--conventions|--env|--services|--controllers|--routes|--layouts|--diagnostics] [--json]',
|
|
175
|
+
usage: 'proteum explain [--all|--app|--conventions|--env|--services|--controllers|--commands|--routes|--layouts|--diagnostics] [--json]',
|
|
174
176
|
bestFor:
|
|
175
|
-
'Inspecting how source files became generated routes, controllers, layouts, services, and diagnostics without reading compiler internals.',
|
|
177
|
+
'Inspecting how source files became generated routes, controllers, commands, layouts, services, and diagnostics without reading compiler internals.',
|
|
176
178
|
examples: [
|
|
177
179
|
{ description: 'Show the default human summary', command: 'proteum explain' },
|
|
178
180
|
{
|
|
179
|
-
description: 'Inspect generated routes and
|
|
180
|
-
command: 'proteum explain --routes --controllers',
|
|
181
|
+
description: 'Inspect generated routes, controllers, and commands together',
|
|
182
|
+
command: 'proteum explain --routes --controllers --commands',
|
|
181
183
|
},
|
|
182
184
|
{ description: 'Emit the selected manifest sections as JSON', command: 'proteum explain --routes --json' },
|
|
183
185
|
],
|
|
184
186
|
notes: ['Legacy positional section selection remains supported, for example `proteum explain routes services`.'],
|
|
185
187
|
status: 'stable',
|
|
186
188
|
},
|
|
189
|
+
trace: {
|
|
190
|
+
name: 'trace',
|
|
191
|
+
category: 'Manifest and contracts',
|
|
192
|
+
summary: 'Inspect live in-memory request traces from a running Proteum dev server.',
|
|
193
|
+
usage: 'proteum trace [latest|show <requestId>|requests|arm|export <requestId>] [--port <port>|--url <baseUrl>] [--json]',
|
|
194
|
+
bestFor:
|
|
195
|
+
'Debugging route resolution, context creation, SSR payloads, renders, and runtime errors without attaching a debugger.',
|
|
196
|
+
examples: [
|
|
197
|
+
{ description: 'Show the latest request trace', command: 'proteum trace latest' },
|
|
198
|
+
{ description: 'List recent trace summaries', command: 'proteum trace requests' },
|
|
199
|
+
{ description: 'Arm the next request for deep capture', command: 'proteum trace arm --capture deep' },
|
|
200
|
+
{ description: 'Export a request trace to disk', command: 'proteum trace export <requestId>' },
|
|
201
|
+
{ description: 'Target a custom dev base URL directly', command: 'proteum trace latest --url http://127.0.0.1:3010' },
|
|
202
|
+
],
|
|
203
|
+
notes: [
|
|
204
|
+
'This command talks to the running app over the dev-only `__proteum/trace` HTTP endpoints.',
|
|
205
|
+
'Traces are stored in a bounded in-memory buffer with payload summarization and sensitive-field redaction.',
|
|
206
|
+
'Use `--port` when the app is not running on the router port declared in `PORT`, or `--url` when the host itself is non-standard.',
|
|
207
|
+
],
|
|
208
|
+
status: 'experimental',
|
|
209
|
+
},
|
|
210
|
+
command: {
|
|
211
|
+
name: 'command',
|
|
212
|
+
category: 'Manifest and contracts',
|
|
213
|
+
summary: 'Run a dev-only app command from /commands or against an existing dev instance.',
|
|
214
|
+
usage: 'proteum command <path> [--port <port>|--url <baseUrl>] [--json]',
|
|
215
|
+
bestFor:
|
|
216
|
+
'Internal testing, debugging, and one-off service execution that should not be exposed as a normal controller or route.',
|
|
217
|
+
examples: [
|
|
218
|
+
{
|
|
219
|
+
description: 'Run a local command through a temporary bundled dev server',
|
|
220
|
+
command: 'proteum command proteum/diagnostics/ping',
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
description: 'Run a command against an existing dev server',
|
|
224
|
+
command: 'proteum command proteum/diagnostics/ping --port 3101',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
description: 'Emit the command execution as JSON',
|
|
228
|
+
command: 'proteum command proteum/diagnostics/ping --json',
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
notes: [
|
|
232
|
+
'Commands live under `./commands/**/*.ts` and default-export a class that extends `{ Commands }` from `@server/app/commands`.',
|
|
233
|
+
'Methods are addressed by file path plus method name, mirroring controller path generation.',
|
|
234
|
+
'Proteum creates `./commands/tsconfig.json` and `.proteum/server/commands.d.ts` so `/commands` gets a command-specific alias/type project.',
|
|
235
|
+
'Prefer `extends Commands` directly inside `/commands`; importing the app class is still supported through a generated command-only `@/server/index` type alias.',
|
|
236
|
+
'Without `--port` or `--url`, Proteum refreshes generated artifacts, builds the dev output, starts a temporary local dev server, runs the command, and exits.',
|
|
237
|
+
'With `--port` or `--url`, Proteum talks to the running app over the dev-only `__proteum/commands` HTTP endpoints.',
|
|
238
|
+
],
|
|
239
|
+
status: 'experimental',
|
|
240
|
+
},
|
|
187
241
|
};
|
|
188
242
|
|
|
189
243
|
export const isLikelyProteumAppRoot = (workdir: string) =>
|
|
@@ -43,6 +43,8 @@ export const renderDevSession = async ({
|
|
|
43
43
|
{ label: 'root', value: appRoot },
|
|
44
44
|
{ label: 'router', value: `http://localhost:${routerPort}` },
|
|
45
45
|
{ label: 'hmr', value: `http://localhost:${devEventPort}/__proteum_hmr` },
|
|
46
|
+
{ label: 'trace', value: `proteum trace latest --port ${routerPort}` },
|
|
47
|
+
{ label: 'trace deep', value: `proteum trace arm --capture deep --port ${routerPort}` },
|
|
46
48
|
{ label: 'hotkeys', value: 'Ctrl+R reload, Ctrl+C stop' },
|
|
47
49
|
],
|
|
48
50
|
{ minLabelWidth: 12, maxLabelWidth: 12 },
|
|
@@ -52,9 +54,11 @@ export const renderDevSession = async ({
|
|
|
52
54
|
export const renderServerReadyBanner = async ({
|
|
53
55
|
appName,
|
|
54
56
|
publicUrl,
|
|
57
|
+
routerPort,
|
|
55
58
|
}: {
|
|
56
59
|
appName: string;
|
|
57
60
|
publicUrl: string;
|
|
61
|
+
routerPort: number;
|
|
58
62
|
}) =>
|
|
59
63
|
renderInk(({ Box, Text }) => {
|
|
60
64
|
const createElement = React.createElement;
|
|
@@ -66,5 +70,6 @@ export const renderServerReadyBanner = async ({
|
|
|
66
70
|
createElement(Text, { bold: true, color: 'green' }, appName),
|
|
67
71
|
createElement(Text, { bold: true }, publicUrl),
|
|
68
72
|
createElement(Text, { dimColor: true }, 'SSR server is listening for requests and hot reloads.'),
|
|
73
|
+
createElement(Text, { dimColor: true }, `Trace latest: proteum trace latest --port ${routerPort}`),
|
|
69
74
|
);
|
|
70
75
|
});
|
package/cli/runtime/commands.ts
CHANGED
|
@@ -153,6 +153,7 @@ class ExplainCommand extends ProteumCommand {
|
|
|
153
153
|
public env = Option.Boolean('--env', false, { description: 'Include the env section.' });
|
|
154
154
|
public services = Option.Boolean('--services', false, { description: 'Include the services section.' });
|
|
155
155
|
public controllers = Option.Boolean('--controllers', false, { description: 'Include the controllers section.' });
|
|
156
|
+
public commands = Option.Boolean('--commands', false, { description: 'Include the commands section.' });
|
|
156
157
|
public routes = Option.Boolean('--routes', false, { description: 'Include the routes section.' });
|
|
157
158
|
public layouts = Option.Boolean('--layouts', false, { description: 'Include the layouts section.' });
|
|
158
159
|
public diagnostics = Option.Boolean('--diagnostics', false, {
|
|
@@ -169,6 +170,7 @@ class ExplainCommand extends ProteumCommand {
|
|
|
169
170
|
env: this.env,
|
|
170
171
|
services: this.services,
|
|
171
172
|
controllers: this.controllers,
|
|
173
|
+
commands: this.commands,
|
|
172
174
|
routes: this.routes,
|
|
173
175
|
layouts: this.layouts,
|
|
174
176
|
diagnostics: this.diagnostics,
|
|
@@ -177,7 +179,7 @@ class ExplainCommand extends ProteumCommand {
|
|
|
177
179
|
applyLegacyBooleanArgs(
|
|
178
180
|
'explain',
|
|
179
181
|
this.legacyArgs,
|
|
180
|
-
['json', 'all', 'app', 'conventions', 'env', 'services', 'controllers', 'routes', 'layouts', 'diagnostics'],
|
|
182
|
+
['json', 'all', 'app', 'conventions', 'env', 'services', 'controllers', 'commands', 'routes', 'layouts', 'diagnostics'],
|
|
181
183
|
args,
|
|
182
184
|
);
|
|
183
185
|
this.setCliArgs(args);
|
|
@@ -185,6 +187,59 @@ class ExplainCommand extends ProteumCommand {
|
|
|
185
187
|
}
|
|
186
188
|
}
|
|
187
189
|
|
|
190
|
+
class TraceCommand extends ProteumCommand {
|
|
191
|
+
public static paths = [['trace']];
|
|
192
|
+
|
|
193
|
+
public static usage = buildUsage('trace');
|
|
194
|
+
|
|
195
|
+
public port = Option.String('--port', { description: 'Override the router port used to query the running dev server.' });
|
|
196
|
+
public url = Option.String('--url', { description: 'Override the full base URL used to query the running dev server.' });
|
|
197
|
+
public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
|
|
198
|
+
public capture = Option.String('--capture', { description: 'Capture mode used by `proteum trace arm`.' });
|
|
199
|
+
public output = Option.String('--output', { description: 'Output filepath used by `proteum trace export`.' });
|
|
200
|
+
public args = Option.Rest();
|
|
201
|
+
|
|
202
|
+
public async execute() {
|
|
203
|
+
const [action = 'latest', id = ''] = this.args;
|
|
204
|
+
|
|
205
|
+
this.setCliArgs({
|
|
206
|
+
action,
|
|
207
|
+
id,
|
|
208
|
+
port: this.port ?? '',
|
|
209
|
+
url: this.url ?? '',
|
|
210
|
+
json: this.json,
|
|
211
|
+
capture: this.capture ?? '',
|
|
212
|
+
output: this.output ?? '',
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
await runCommandModule(() => import('../commands/trace'));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
class CommandCommand extends ProteumCommand {
|
|
220
|
+
public static paths = [['command']];
|
|
221
|
+
|
|
222
|
+
public static usage = buildUsage('command');
|
|
223
|
+
|
|
224
|
+
public port = Option.String('--port', { description: 'Target an existing dev server on the given port.' });
|
|
225
|
+
public url = Option.String('--url', { description: 'Target an existing dev server at the given base URL.' });
|
|
226
|
+
public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
|
|
227
|
+
public args = Option.Rest();
|
|
228
|
+
|
|
229
|
+
public async execute() {
|
|
230
|
+
const [path = ''] = this.args;
|
|
231
|
+
|
|
232
|
+
this.setCliArgs({
|
|
233
|
+
path,
|
|
234
|
+
port: this.port ?? '',
|
|
235
|
+
url: this.url ?? '',
|
|
236
|
+
json: this.json,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
await runCommandModule(() => import('../commands/command'));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
188
243
|
export const registeredCommands = {
|
|
189
244
|
init: InitCommand,
|
|
190
245
|
dev: DevCommand,
|
|
@@ -195,6 +250,8 @@ export const registeredCommands = {
|
|
|
195
250
|
check: CheckCommand,
|
|
196
251
|
doctor: DoctorCommand,
|
|
197
252
|
explain: ExplainCommand,
|
|
253
|
+
trace: TraceCommand,
|
|
254
|
+
command: CommandCommand,
|
|
198
255
|
} as const;
|
|
199
256
|
|
|
200
257
|
export const createCli = (version: string) => {
|
|
@@ -216,6 +273,8 @@ export const createCli = (version: string) => {
|
|
|
216
273
|
clipanion.register(CheckCommand);
|
|
217
274
|
clipanion.register(DoctorCommand);
|
|
218
275
|
clipanion.register(ExplainCommand);
|
|
276
|
+
clipanion.register(TraceCommand);
|
|
277
|
+
clipanion.register(CommandCommand);
|
|
219
278
|
|
|
220
279
|
return clipanion;
|
|
221
280
|
};
|
package/cli/tsconfig.json
CHANGED
|
@@ -29,9 +29,12 @@
|
|
|
29
29
|
"outDir": "./bin",
|
|
30
30
|
|
|
31
31
|
"paths": {
|
|
32
|
+
"@client/*": [ "../client/*" ],
|
|
32
33
|
"@cli/*": [ "./*" ],
|
|
33
34
|
"@cli/app": [ "./app" ],
|
|
34
|
-
"@cli": [ "./" ]
|
|
35
|
+
"@cli": [ "./" ],
|
|
36
|
+
"@common/*": [ "../common/*" ],
|
|
37
|
+
"@server/*": [ "../server/*" ]
|
|
35
38
|
},
|
|
36
39
|
},
|
|
37
40
|
|
package/cli/utils/check.ts
CHANGED
|
@@ -5,7 +5,7 @@ import cli from '..';
|
|
|
5
5
|
import Compiler from '../compiler';
|
|
6
6
|
import { runProcess } from './runProcess';
|
|
7
7
|
|
|
8
|
-
const tsconfigPaths = ['client/tsconfig.json', 'server/tsconfig.json'];
|
|
8
|
+
const tsconfigPaths = ['client/tsconfig.json', 'server/tsconfig.json', 'commands/tsconfig.json'];
|
|
9
9
|
const eslintConfigPaths = ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs'];
|
|
10
10
|
|
|
11
11
|
const resolveInstalledBinary = (name: string) => {
|
package/client/app/component.tsx
CHANGED
|
@@ -21,10 +21,17 @@ export default function App({ context }: { context: ClientContext }) {
|
|
|
21
21
|
const curLayout = context.page?.layout;
|
|
22
22
|
const [layout, setLayout] = React.useState<Layout | false | undefined>(curLayout);
|
|
23
23
|
const [apiData, setApiData] = React.useState<{ [k: string]: any } | null>(context.page?.data || {});
|
|
24
|
+
const shouldEnableDevProfiler = __DEV__ && typeof window !== 'undefined' && window.dev;
|
|
25
|
+
const [isDevProfilerMounted, setDevProfilerMounted] = React.useState(false);
|
|
24
26
|
|
|
25
27
|
// TODO: context.page is always provided in the context on the client side
|
|
26
28
|
if (context.app.side === 'client') context.app.setLayout = setLayout;
|
|
27
29
|
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
if (!shouldEnableDevProfiler) return;
|
|
32
|
+
setDevProfilerMounted(true);
|
|
33
|
+
}, [shouldEnableDevProfiler]);
|
|
34
|
+
|
|
28
35
|
const layoutProps: LayoutProps = {
|
|
29
36
|
...context,
|
|
30
37
|
context,
|
|
@@ -32,22 +39,19 @@ export default function App({ context }: { context: ClientContext }) {
|
|
|
32
39
|
menu: undefined,
|
|
33
40
|
children: undefined,
|
|
34
41
|
};
|
|
42
|
+
const DevProfiler = shouldEnableDevProfiler
|
|
43
|
+
? ((require('@client/dev/profiler') as typeof import('@client/dev/profiler')).default as React.ComponentType)
|
|
44
|
+
: null;
|
|
35
45
|
|
|
36
46
|
return (
|
|
37
47
|
<ReactClientContext.Provider value={context}>
|
|
38
48
|
<DialogManager />
|
|
49
|
+
{DevProfiler && isDevProfilerMounted ? <DevProfiler /> : null}
|
|
39
50
|
|
|
40
51
|
{!layout ? (
|
|
41
|
-
|
|
42
|
-
{/* TODO: move to app, because here, we're not aware that the router service has been defined */}
|
|
43
|
-
<RouterComponent service={context.Router} />
|
|
44
|
-
</>
|
|
52
|
+
<RouterComponent service={context.Router} />
|
|
45
53
|
) : (
|
|
46
|
-
|
|
47
|
-
{' '}
|
|
48
|
-
{/* Same as router/components/Page.tsx */}
|
|
49
|
-
<layout.Component {...layoutProps} />
|
|
50
|
-
</>
|
|
54
|
+
<layout.Component {...layoutProps} />
|
|
51
55
|
)}
|
|
52
56
|
</ReactClientContext.Provider>
|
|
53
57
|
);
|