proteum 1.0.3 → 2.0.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.
- package/AGENTS.md +92 -0
- package/agents/codex/AGENTS.md +95 -0
- package/agents/codex/CODING_STYLE.md +71 -0
- package/agents/codex/agents.md.zip +0 -0
- package/agents/codex/client/AGENTS.md +102 -0
- package/agents/codex/client/pages/AGENTS.md +35 -0
- package/agents/codex/server/routes/AGENTS.md +12 -0
- package/agents/codex/server/services/AGENTS.md +137 -0
- package/agents/codex/tests/AGENTS.md +8 -0
- package/cli/app/config.ts +12 -17
- package/cli/app/index.ts +59 -99
- package/cli/bin.js +1 -1
- package/cli/commands/build.ts +23 -12
- package/cli/commands/check.ts +19 -0
- package/cli/commands/deploy/app.ts +4 -8
- package/cli/commands/deploy/web.ts +16 -20
- package/cli/commands/dev.ts +185 -75
- package/cli/commands/devEvents.ts +106 -0
- package/cli/commands/init.ts +63 -57
- package/cli/commands/lint.ts +21 -0
- package/cli/commands/refresh.ts +6 -6
- package/cli/commands/typecheck.ts +18 -0
- package/cli/compiler/client/identite.ts +79 -49
- package/cli/compiler/client/index.ts +132 -214
- package/cli/compiler/common/bundleAnalysis.ts +94 -0
- package/cli/compiler/common/clientManifest.ts +67 -0
- package/cli/compiler/common/controllers.ts +288 -0
- package/cli/compiler/common/files/autres.ts +7 -18
- package/cli/compiler/common/files/images.ts +40 -37
- package/cli/compiler/common/files/style.ts +12 -25
- package/cli/compiler/common/generatedRouteModules.ts +368 -0
- package/cli/compiler/common/index.ts +29 -68
- package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
- package/cli/compiler/common/rspackAliases.ts +13 -0
- package/cli/compiler/common/scripts.ts +37 -0
- package/cli/compiler/index.ts +764 -234
- package/cli/compiler/server/index.ts +52 -77
- package/cli/compiler/writeIfChanged.ts +21 -0
- package/cli/index.ts +65 -90
- package/cli/paths.ts +51 -57
- package/cli/print.ts +17 -11
- package/cli/tsconfig.json +5 -4
- package/cli/utils/agents.ts +100 -0
- package/cli/utils/check.ts +71 -0
- package/cli/utils/index.ts +1 -3
- package/cli/utils/keyboard.ts +8 -25
- package/cli/utils/runProcess.ts +30 -0
- package/client/app/component.tsx +29 -29
- package/client/app/index.ts +36 -57
- package/client/app/service.ts +7 -12
- package/client/app.tsconfig.json +2 -2
- package/client/components/Dialog/Manager.ssr.tsx +40 -0
- package/client/components/Dialog/Manager.tsx +119 -150
- package/client/components/Dialog/status.tsx +3 -3
- package/client/components/index.ts +1 -1
- package/client/components/types.d.ts +1 -3
- package/client/dev/hmr.ts +65 -0
- package/client/global.d.ts +2 -2
- package/client/hooks.ts +6 -9
- package/client/index.ts +2 -1
- package/client/islands/index.ts +7 -0
- package/client/islands/useDeferredModule.ts +199 -0
- package/client/pages/_layout/index.tsx +4 -12
- package/client/pages/useHeader.tsx +14 -21
- package/client/router.ts +27 -0
- package/client/services/router/components/Link.tsx +34 -27
- package/client/services/router/components/Page.tsx +6 -14
- package/client/services/router/components/router.ssr.tsx +36 -0
- package/client/services/router/components/router.tsx +63 -83
- package/client/services/router/index.tsx +185 -220
- package/client/services/router/request/api.ts +97 -119
- package/client/services/router/request/history.ts +2 -2
- package/client/services/router/request/index.ts +13 -12
- package/client/services/router/request/multipart.ts +72 -62
- package/client/services/router/response/index.tsx +68 -61
- package/client/services/router/response/page.ts +28 -32
- package/client/utils/dom.ts +17 -33
- package/common/app/index.ts +3 -3
- package/common/data/chaines/index.ts +22 -23
- package/common/data/dates.ts +35 -70
- package/common/data/markdown.ts +42 -39
- package/common/dev/serverHotReload.ts +26 -0
- package/common/errors/index.tsx +110 -142
- package/common/router/contracts.ts +29 -0
- package/common/router/index.ts +89 -108
- package/common/router/layouts.ts +34 -47
- package/common/router/pageSetup.ts +50 -0
- package/common/router/register.ts +53 -24
- package/common/router/request/api.ts +30 -36
- package/common/router/request/index.ts +2 -8
- package/common/router/response/index.ts +8 -15
- package/common/router/response/page.ts +70 -58
- package/common/utils.ts +1 -1
- package/eslint.js +62 -0
- package/package.json +12 -45
- package/prettier.config.cjs +9 -0
- package/scripts/cleanup-generated-controllers.ts +62 -0
- package/scripts/fix-reference-app-typing.ts +490 -0
- package/scripts/refactor-client-app-imports.ts +244 -0
- package/scripts/refactor-client-pages.ts +587 -0
- package/scripts/refactor-server-controllers.ts +470 -0
- package/scripts/refactor-server-runtime-aliases.ts +360 -0
- package/scripts/restore-client-app-import-files.ts +41 -0
- package/scripts/restore-files-from-git-head.ts +20 -0
- package/scripts/update-codex-agents.ts +35 -0
- package/server/app/commands.ts +35 -64
- package/server/app/container/config.ts +39 -69
- package/server/app/container/console/index.ts +202 -248
- package/server/app/container/index.ts +33 -71
- package/server/app/controller/index.ts +61 -0
- package/server/app/index.ts +39 -105
- package/server/app/service/container.ts +41 -42
- package/server/app/service/index.ts +120 -147
- package/server/context.ts +1 -1
- package/server/index.ts +25 -1
- package/server/services/auth/index.ts +75 -115
- package/server/services/auth/router/index.ts +31 -32
- package/server/services/auth/router/request.ts +14 -16
- package/server/services/cron/CronTask.ts +13 -26
- package/server/services/cron/index.ts +14 -36
- package/server/services/disks/driver.ts +40 -58
- package/server/services/disks/drivers/local/index.ts +79 -90
- package/server/services/disks/drivers/s3/index.ts +116 -163
- package/server/services/disks/index.ts +23 -38
- package/server/services/email/index.ts +45 -104
- package/server/services/email/utils.ts +14 -27
- package/server/services/fetch/index.ts +53 -85
- package/server/services/prisma/Facet.ts +39 -91
- package/server/services/prisma/index.ts +74 -110
- package/server/services/router/generatedRuntime.ts +29 -0
- package/server/services/router/http/index.ts +77 -72
- package/server/services/router/http/multipart.ts +19 -42
- package/server/services/router/index.ts +378 -365
- package/server/services/router/request/api.ts +26 -25
- package/server/services/router/request/index.ts +44 -51
- package/server/services/router/request/service.ts +7 -11
- package/server/services/router/request/validation/zod.ts +111 -148
- package/server/services/router/response/index.ts +110 -125
- package/server/services/router/response/mask/Filter.ts +31 -72
- package/server/services/router/response/mask/index.ts +8 -15
- package/server/services/router/response/mask/selecteurs.ts +11 -25
- package/server/services/router/response/page/clientManifest.ts +25 -0
- package/server/services/router/response/page/document.tsx +199 -127
- package/server/services/router/response/page/index.tsx +89 -94
- package/server/services/router/service.ts +13 -15
- package/server/services/schema/index.ts +17 -26
- package/server/services/schema/request.ts +19 -33
- package/server/services/schema/router/index.ts +8 -11
- package/server/services/security/encrypt/aes/index.ts +15 -35
- package/server/utils/slug.ts +29 -32
- package/skills/clean-project-code/SKILL.md +63 -0
- package/skills/clean-project-code/agents/openai.yaml +4 -0
- package/tsconfig.common.json +4 -3
- package/tsconfig.json +4 -1
- package/types/aliases.d.ts +17 -21
- package/types/controller-input.test.ts +48 -0
- package/types/express-extra.d.ts +6 -0
- package/types/global/constants.d.ts +1 -0
- package/types/global/express-extra.d.ts +6 -0
- package/types/global/modules.d.ts +13 -16
- package/types/global/utils.d.ts +17 -49
- package/types/global/vendors.d.ts +62 -0
- package/types/icons.d.ts +65 -1
- package/types/uuid.d.ts +3 -0
- package/types/vendors.d.ts +62 -0
- package/cli/compiler/common/babel/index.ts +0 -173
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +0 -586
- package/cli/compiler/common/babel/routes/imports.ts +0 -127
- package/cli/compiler/common/babel/routes/routes.ts +0 -1170
- package/client/services/captcha/index.ts +0 -67
- package/client/services/socket/index.ts +0 -147
- package/common/data/rte/nodes.ts +0 -83
- package/common/data/stats.ts +0 -90
- package/common/utils/rte.ts +0 -183
- package/server/services/auth/old.ts +0 -277
- package/server/services/cache/commands.ts +0 -41
- package/server/services/cache/index.ts +0 -297
- package/server/services/cache/service.json +0 -6
- package/server/services/socket/index.ts +0 -162
- package/server/services/socket/scope.ts +0 -226
- package/server/services/socket/service.json +0 -6
- package/server/services_old/SocketClient.ts +0 -92
- package/server/services_old/Token.old.ts +0 -97
package/cli/commands/dev.ts
CHANGED
|
@@ -9,116 +9,226 @@ import { spawn, ChildProcess } from 'child_process';
|
|
|
9
9
|
// Cor elibs
|
|
10
10
|
import cli from '..';
|
|
11
11
|
import Keyboard from '../utils/keyboard';
|
|
12
|
+
import {
|
|
13
|
+
isServerHotReloadResult,
|
|
14
|
+
serverHotReloadMessageType,
|
|
15
|
+
TServerHotReloadRequest,
|
|
16
|
+
} from '../../common/dev/serverHotReload';
|
|
12
17
|
|
|
13
18
|
// Configs
|
|
14
19
|
import Compiler from '../compiler';
|
|
20
|
+
import { createDevEventServer } from './devEvents';
|
|
21
|
+
import { ensureProjectAgentSymlinks } from '../utils/agents';
|
|
15
22
|
|
|
16
23
|
// Core
|
|
17
24
|
import { app, App } from '../app';
|
|
18
25
|
|
|
26
|
+
/*----------------------------------
|
|
27
|
+
- CONSTANTS
|
|
28
|
+
----------------------------------*/
|
|
29
|
+
|
|
30
|
+
// Watch rules shared by the dev compiler and hot reload gate.
|
|
19
31
|
const ignoredWatchPathPatterns = /(node_modules\/(?!proteum\/))|(\.generated\/)|(\.cache\/)/;
|
|
32
|
+
const hotReloadableServerPathPatterns = [
|
|
33
|
+
/^client\/pages\//,
|
|
34
|
+
/^client\/components\//,
|
|
35
|
+
/^client\/islands\//,
|
|
36
|
+
/^server\/routes\//,
|
|
37
|
+
/^server\/services\/.+\.controller\.[jt]sx?$/,
|
|
38
|
+
];
|
|
39
|
+
const hotReloadableRoots = [() => app.paths.root, () => cli.paths.core.root];
|
|
20
40
|
|
|
21
41
|
/*----------------------------------
|
|
22
|
-
-
|
|
42
|
+
- MAIN PROCESS
|
|
23
43
|
----------------------------------*/
|
|
24
|
-
export const run = () =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
export const run = () =>
|
|
45
|
+
new Promise<void>(async () => {
|
|
46
|
+
ensureProjectAgentSymlinks({ appRoot: app.paths.root, coreRoot: cli.paths.core.root });
|
|
47
|
+
|
|
48
|
+
const devEventServer = await createDevEventServer(app.env.router.port + 1);
|
|
49
|
+
app.devEventPort = devEventServer.port;
|
|
50
|
+
console.info(`Proteum dev event server ready on http://localhost:${devEventServer.port}/__proteum_hmr`);
|
|
51
|
+
|
|
52
|
+
const compiler = new Compiler('dev', {
|
|
53
|
+
before: (compiler) => {
|
|
54
|
+
if (compiler.name !== 'server') return;
|
|
55
|
+
|
|
56
|
+
const changedFilesList = compiler.modifiedFiles ? [...compiler.modifiedFiles] : [];
|
|
57
|
+
|
|
58
|
+
if (changedFilesList.length === 0) {
|
|
59
|
+
console.info('Server compilation started. App restart will wait for a successful server build.');
|
|
60
|
+
} else {
|
|
61
|
+
console.info('Need to recompile server because files changed:\n' + changedFilesList.join('\n'));
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
after: () => {},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const multiCompiler = await compiler.create();
|
|
68
|
+
const ignoredOutputPaths = [app.paths.bin, app.paths.dev].map(normalizeWatchPath);
|
|
69
|
+
|
|
70
|
+
multiCompiler.watch(
|
|
71
|
+
{
|
|
72
|
+
// Watching may not work with NFS and machines in VirtualBox
|
|
73
|
+
// Uncomment next line if it is your case (use true or interval in milliseconds)
|
|
74
|
+
//poll: 1000,
|
|
75
|
+
|
|
76
|
+
// Decrease CPU or memory usage in some file systems
|
|
77
|
+
// Ignore updated from:
|
|
78
|
+
// - Node modules except 5HTP core (framework dev mode)
|
|
79
|
+
// - Generated files during runtime (cause infinite loop. Ex: models.d.ts)
|
|
80
|
+
// - Webpack output folders (`./dev`, legacy `./bin`)
|
|
81
|
+
ignored: (watchPath: string) => {
|
|
82
|
+
const normalizedPath = normalizeWatchPath(watchPath);
|
|
83
|
+
return (
|
|
84
|
+
ignoredWatchPathPatterns.test(normalizedPath) ||
|
|
85
|
+
ignoredOutputPaths.some(
|
|
86
|
+
(outputPath) =>
|
|
87
|
+
normalizedPath === outputPath || normalizedPath.startsWith(outputPath + '/'),
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
//aggregateTimeout: 1000,
|
|
93
|
+
},
|
|
94
|
+
async (error, stats) => {
|
|
95
|
+
if (error) {
|
|
96
|
+
compiler.consumeRecentCompilationResults();
|
|
97
|
+
console.error('Error in milticompiler.watch', error, stats?.toString());
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const recentCompilationResults = compiler.consumeRecentCompilationResults();
|
|
102
|
+
const serverResult = recentCompilationResults.server;
|
|
103
|
+
const clientResult = recentCompilationResults.client;
|
|
104
|
+
|
|
105
|
+
let restartedServer = false;
|
|
106
|
+
|
|
107
|
+
if (serverResult?.succeeded === true) {
|
|
108
|
+
const changedFilesList = serverResult.modifiedFiles || [];
|
|
109
|
+
const canHotReloadServer = isServerHotReloadEligible(changedFilesList);
|
|
110
|
+
|
|
111
|
+
if (canHotReloadServer && requestServerHotReload(changedFilesList)) {
|
|
112
|
+
console.log(
|
|
113
|
+
'Watch callback. Server route bundle changed; hot-swapping generated routes without restarting app.',
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
console.log('Watch callback. Reloading app because server bundle changed ...');
|
|
117
|
+
startApp(app);
|
|
118
|
+
restartedServer = true;
|
|
119
|
+
devEventServer.broadcast({ type: 'reload', reason: 'server' });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (serverResult?.succeeded === false) {
|
|
124
|
+
console.log('Watch callback. Server compilation failed; keeping current app instance.');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!restartedServer && clientResult?.succeeded === true) {
|
|
128
|
+
console.log('Watch callback. Client assets updated; server restart skipped.');
|
|
129
|
+
devEventServer.broadcast({ type: 'reload', reason: 'client' });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!restartedServer && clientResult?.succeeded === false) {
|
|
134
|
+
console.log('Watch callback. Client compilation failed; server restart skipped.');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (restartedServer || serverResult?.succeeded === true || serverResult?.succeeded === false) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('Watch callback. No compiler changes were tracked.');
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
Keyboard.input('ctrl+r', async () => {
|
|
147
|
+
console.log('Waiting for compilers to be ready ...', Object.keys(compiler.compiling));
|
|
148
|
+
await Promise.all(Object.values(compiler.compiling));
|
|
149
|
+
|
|
150
|
+
console.log('Reloading app ...');
|
|
151
|
+
startApp(app);
|
|
152
|
+
devEventServer.broadcast({ type: 'reload', reason: 'manual' });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
Keyboard.input('ctrl+c', () => {
|
|
156
|
+
stopApp('CTRL+C Pressed');
|
|
157
|
+
void devEventServer.close();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
28
160
|
|
|
29
|
-
|
|
161
|
+
/*----------------------------------
|
|
162
|
+
- STATE
|
|
163
|
+
----------------------------------*/
|
|
30
164
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
else
|
|
34
|
-
stopApp("Need to recompile because files changed:\n" + changedFilesList.join('\n'));
|
|
165
|
+
// Current server child process used by the dev loop.
|
|
166
|
+
let cp: ChildProcess | undefined = undefined;
|
|
35
167
|
|
|
36
|
-
|
|
37
|
-
|
|
168
|
+
/*----------------------------------
|
|
169
|
+
- HELPERS
|
|
170
|
+
----------------------------------*/
|
|
38
171
|
|
|
172
|
+
async function startApp(app: App) {
|
|
173
|
+
stopApp('Restart asked');
|
|
39
174
|
|
|
40
|
-
|
|
175
|
+
console.info('Launching new server ...');
|
|
176
|
+
cp = spawn('node', ['--preserve-symlinks', app.outputPath('dev') + '/server.js'], {
|
|
177
|
+
// sdin, sdout, sderr
|
|
178
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
41
179
|
});
|
|
42
180
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
multiCompiler.watch({
|
|
47
|
-
|
|
48
|
-
// https://webpack.js.org/configuration/watch/#watchoptions
|
|
49
|
-
// Watching may not work with NFS and machines in VirtualBox
|
|
50
|
-
// Uncomment next line if it is your case (use true or interval in milliseconds)
|
|
51
|
-
//poll: 1000,
|
|
52
|
-
|
|
53
|
-
// Decrease CPU or memory usage in some file systems
|
|
54
|
-
// Ignore updated from:
|
|
55
|
-
// - Node modules except 5HTP core (framework dev mode)
|
|
56
|
-
// - Generated files during runtime (cause infinite loop. Ex: models.d.ts)
|
|
57
|
-
// - Webpack output folders (`./dev`, legacy `./bin`)
|
|
58
|
-
ignored: (watchPath: string) => {
|
|
59
|
-
const normalizedPath = normalizeWatchPath(watchPath);
|
|
60
|
-
return ignoredWatchPathPatterns.test(normalizedPath)
|
|
61
|
-
|| ignoredOutputPaths.some(outputPath =>
|
|
62
|
-
normalizedPath === outputPath
|
|
63
|
-
|| normalizedPath.startsWith(outputPath + '/')
|
|
64
|
-
);
|
|
65
|
-
}
|
|
181
|
+
cp.on('message', (message: unknown) => {
|
|
182
|
+
if (!isServerHotReloadResult(message)) return;
|
|
66
183
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (error) {
|
|
71
|
-
console.error(`Error in milticompiler.watch`, error, stats?.toString());
|
|
184
|
+
if (message.type === serverHotReloadMessageType.succeeded) {
|
|
185
|
+
console.log('Server hot reload applied without restarting app.');
|
|
72
186
|
return;
|
|
73
187
|
}
|
|
74
188
|
|
|
75
|
-
console.
|
|
76
|
-
startApp(app);
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
Keyboard.input('ctrl+r', async () => {
|
|
81
|
-
|
|
82
|
-
console.log(`Waiting for compilers to be ready ...`, Object.keys(compiler.compiling));
|
|
83
|
-
await Promise.all(Object.values(compiler.compiling));
|
|
84
|
-
|
|
85
|
-
console.log(`Reloading app ...`);
|
|
189
|
+
console.error('Server hot reload failed. Restarting app with a fresh process.', message.error || '');
|
|
86
190
|
startApp(app);
|
|
87
|
-
|
|
88
191
|
});
|
|
192
|
+
}
|
|
89
193
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
194
|
+
function stopApp(reason: string) {
|
|
195
|
+
if (cp !== undefined) {
|
|
196
|
+
console.info(`Killing current server instance (ID: ${cp.pid}) for the following reason:`, reason);
|
|
197
|
+
cp.kill();
|
|
198
|
+
cp = undefined;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
94
201
|
|
|
202
|
+
function requestServerHotReload(changedFiles: string[]) {
|
|
203
|
+
if (!cp || !cp.connected) return false;
|
|
95
204
|
|
|
96
|
-
|
|
97
|
-
- APP RUN
|
|
98
|
-
----------------------------------*/
|
|
99
|
-
let cp: ChildProcess | undefined = undefined;
|
|
205
|
+
const message: TServerHotReloadRequest = { type: serverHotReloadMessageType.request, changedFiles };
|
|
100
206
|
|
|
101
|
-
|
|
207
|
+
cp.send(message);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
102
210
|
|
|
103
|
-
|
|
211
|
+
function isServerHotReloadEligible(changedFiles: string[]) {
|
|
212
|
+
if (changedFiles.length === 0) return false;
|
|
104
213
|
|
|
105
|
-
|
|
106
|
-
|
|
214
|
+
return changedFiles.every((changedFile) => {
|
|
215
|
+
const normalizedChangedFile = normalizeWatchPath(changedFile);
|
|
107
216
|
|
|
108
|
-
|
|
109
|
-
|
|
217
|
+
return hotReloadableRoots.some((getRootPath) => {
|
|
218
|
+
const normalizedRootPath = normalizeWatchPath(getRootPath());
|
|
219
|
+
if (
|
|
220
|
+
normalizedChangedFile !== normalizedRootPath &&
|
|
221
|
+
!normalizedChangedFile.startsWith(normalizedRootPath + '/')
|
|
222
|
+
) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
110
225
|
|
|
226
|
+
const relativePath = normalizedChangedFile.substring(normalizedRootPath.length + 1);
|
|
227
|
+
return hotReloadableServerPathPatterns.some((pattern) => pattern.test(relativePath));
|
|
228
|
+
});
|
|
111
229
|
});
|
|
112
230
|
}
|
|
113
231
|
|
|
114
|
-
function stopApp( reason: string ) {
|
|
115
|
-
if (cp !== undefined) {
|
|
116
|
-
console.info(`Killing current server instance (ID: ${cp.pid}) for the following reason:`, reason);
|
|
117
|
-
cp.kill();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
232
|
function normalizeWatchPath(watchPath: string) {
|
|
123
233
|
return path.resolve(watchPath).replace(/\\/g, '/').replace(/\/$/, '');
|
|
124
234
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import http, { type IncomingMessage, type ServerResponse } from 'http';
|
|
2
|
+
|
|
3
|
+
export type TDevEvent = { type: 'reload'; reason: 'server' | 'manual' | 'client' };
|
|
4
|
+
|
|
5
|
+
const devEventsPath = '/__proteum_hmr';
|
|
6
|
+
|
|
7
|
+
export class DevEventServer {
|
|
8
|
+
private readonly clients = new Set<ServerResponse<IncomingMessage>>();
|
|
9
|
+
private readonly server = http.createServer(this.handleRequest.bind(this));
|
|
10
|
+
|
|
11
|
+
public constructor(public port: number) {}
|
|
12
|
+
|
|
13
|
+
public broadcast(event: TDevEvent) {
|
|
14
|
+
const payload = `data: ${JSON.stringify(event)}\n\n`;
|
|
15
|
+
|
|
16
|
+
for (const client of this.clients) {
|
|
17
|
+
client.write(payload);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async close() {
|
|
22
|
+
for (const client of this.clients) {
|
|
23
|
+
client.end();
|
|
24
|
+
}
|
|
25
|
+
this.clients.clear();
|
|
26
|
+
|
|
27
|
+
await new Promise<void>((resolve, reject) => {
|
|
28
|
+
this.server.close((error) => {
|
|
29
|
+
if (error) {
|
|
30
|
+
reject(error);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
resolve();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private handleRequest(request: IncomingMessage, response: ServerResponse<IncomingMessage>) {
|
|
40
|
+
if (request.url !== devEventsPath) {
|
|
41
|
+
response.statusCode = 404;
|
|
42
|
+
response.end();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
response.writeHead(200, {
|
|
47
|
+
'Access-Control-Allow-Origin': '*',
|
|
48
|
+
'Cache-Control': 'no-store',
|
|
49
|
+
Connection: 'keep-alive',
|
|
50
|
+
'Content-Type': 'text/event-stream',
|
|
51
|
+
'X-Accel-Buffering': 'no',
|
|
52
|
+
});
|
|
53
|
+
response.write(': connected\n\n');
|
|
54
|
+
response.socket?.setKeepAlive(true);
|
|
55
|
+
this.clients.add(response);
|
|
56
|
+
|
|
57
|
+
request.on('close', () => {
|
|
58
|
+
this.clients.delete(response);
|
|
59
|
+
response.end();
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public static async create(preferredPort: number) {
|
|
64
|
+
const server = new DevEventServer(preferredPort);
|
|
65
|
+
server.port = await server.listen(preferredPort);
|
|
66
|
+
return server;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private async listen(preferredPort: number) {
|
|
70
|
+
const initialPort = Number.isInteger(preferredPort) ? preferredPort : 0;
|
|
71
|
+
|
|
72
|
+
return await new Promise<number>((resolve, reject) => {
|
|
73
|
+
const tryListen = (port: number) => {
|
|
74
|
+
const onError = (error: NodeJS.ErrnoException) => {
|
|
75
|
+
this.server.off('listening', onListening);
|
|
76
|
+
|
|
77
|
+
if (error.code === 'EADDRINUSE' && port !== 0) {
|
|
78
|
+
tryListen(port + 1);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
reject(error);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const onListening = () => {
|
|
86
|
+
this.server.off('error', onError);
|
|
87
|
+
const address = this.server.address();
|
|
88
|
+
if (!address || typeof address === 'string') {
|
|
89
|
+
reject(new Error('Unable to resolve the dev event server port.'));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
resolve(address.port);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
this.server.once('error', onError);
|
|
97
|
+
this.server.once('listening', onListening);
|
|
98
|
+
this.server.listen(port, '0.0.0.0');
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
tryListen(initialPort);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const createDevEventServer = async (preferredPort: number) => DevEventServer.create(preferredPort);
|
package/cli/commands/init.ts
CHANGED
|
@@ -11,75 +11,81 @@ import replaceOnce from 'replace-once';
|
|
|
11
11
|
|
|
12
12
|
// Cor elibs
|
|
13
13
|
import cli from '..';
|
|
14
|
+
import { ensureProjectAgentSymlinks } from '../utils/agents';
|
|
14
15
|
|
|
15
16
|
// Configs
|
|
16
|
-
const filesToConfig = [
|
|
17
|
-
'package.json',
|
|
18
|
-
'identity.yaml'
|
|
19
|
-
]
|
|
17
|
+
const filesToConfig = ['package.json', 'identity.yaml'];
|
|
20
18
|
|
|
21
19
|
/*----------------------------------
|
|
22
20
|
- COMMANDE
|
|
23
21
|
----------------------------------*/
|
|
24
|
-
export const run = () =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
22
|
+
export const run = () =>
|
|
23
|
+
new Promise<void>(async () => {
|
|
24
|
+
const config = await prompts([
|
|
25
|
+
{
|
|
26
|
+
type: 'text',
|
|
27
|
+
name: 'name',
|
|
28
|
+
message: 'Project name ?',
|
|
29
|
+
initial: 'MyProject',
|
|
30
|
+
validate: (value) =>
|
|
31
|
+
/[a-z0-9\-\.]/i.test(value) || 'Must only include alphanumeric characters, and - . ',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'text',
|
|
35
|
+
name: 'dirname',
|
|
36
|
+
message: 'Folder name ?',
|
|
37
|
+
initial: (value) => value.toLowerCase(),
|
|
38
|
+
validate: (value) =>
|
|
39
|
+
/[a-z0-9\-\.]/.test(value) || 'Must only include lowercase alphanumeric characters, and - . ',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
name: 'description',
|
|
44
|
+
message: 'Briefly describe your project to your mom:',
|
|
45
|
+
initial: 'It will revolutionnize the world',
|
|
46
|
+
validate: (value) =>
|
|
47
|
+
/[a-z0-9\-\. ]/i.test(value) || 'Must only include alphanumeric characters, and - . ',
|
|
48
|
+
},
|
|
49
|
+
{ type: 'toggle', name: 'microservice', message: 'Separate API from the UI servers ?' },
|
|
50
|
+
]);
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
const placeholders = {
|
|
53
|
+
PROJECT_NAME: config.name,
|
|
54
|
+
PACKAGE_NAME: config.name.toLowerCase(),
|
|
55
|
+
PROJECT_DESCRIPTION: config.description,
|
|
56
|
+
};
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
const paths = {
|
|
59
|
+
skeleton: path.join(cli.paths.core.cli, 'skeleton'),
|
|
60
|
+
project: path.join(process.cwd(), config.dirname),
|
|
61
|
+
};
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Replace placeholders
|
|
62
|
-
console.info("Configuring project ...");
|
|
63
|
-
for (const file of filesToConfig) {
|
|
64
|
-
console.log('- ' + file);
|
|
63
|
+
// Copy skeleton to cwd/<project-name>
|
|
64
|
+
console.info('Creating project skeleton ...');
|
|
65
|
+
fs.copySync(paths.skeleton, paths.project);
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
// Sync framework-owned Codex assets into the new project.
|
|
68
|
+
ensureProjectAgentSymlinks({ appRoot: paths.project, coreRoot: cli.paths.core.root });
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
// Replace placeholders
|
|
71
|
+
console.info('Configuring project ...');
|
|
72
|
+
for (const file of filesToConfig) {
|
|
73
|
+
console.log('- ' + file);
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
);
|
|
75
|
-
}
|
|
75
|
+
const filepath = path.join(paths.project, file);
|
|
76
|
+
const content = fs.readFileSync(filepath, 'utf-8');
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
cmd.runSync(`cd "${paths.project}" && npm i`);
|
|
78
|
+
const placeholders_keys = Object.keys(placeholders).map((k) => '{{ ' + k + ' }}');
|
|
79
|
+
const values = Object.values(placeholders);
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
fs.writeFileSync(filepath, replaceOnce(content, placeholders_keys, values));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Npm install
|
|
85
|
+
console.info('Installing packages ...');
|
|
86
|
+
cmd.runSync(`cd "${paths.project}" && npm i`);
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
// Run demo app
|
|
89
|
+
/*console.info("Run demo ...");
|
|
90
|
+
await cli.shell('5htp dev');*/
|
|
91
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import cli from '..';
|
|
2
|
+
import { runAppLint } from '../utils/check';
|
|
3
|
+
|
|
4
|
+
const allowedLintArgs = new Set(['fix']);
|
|
5
|
+
|
|
6
|
+
const validateLintArgs = () => {
|
|
7
|
+
const enabledArgs = Object.entries(cli.args)
|
|
8
|
+
.filter(([name, value]) => name !== 'workdir' && value === true)
|
|
9
|
+
.map(([name]) => name);
|
|
10
|
+
|
|
11
|
+
const invalidArgs = enabledArgs.filter((arg) => !allowedLintArgs.has(arg));
|
|
12
|
+
|
|
13
|
+
if (invalidArgs.length > 0)
|
|
14
|
+
throw new Error(`Unknown lint argument(s): ${invalidArgs.join(', ')}. Allowed values: fix.`);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const run = async (): Promise<void> => {
|
|
18
|
+
validateLintArgs();
|
|
19
|
+
|
|
20
|
+
await runAppLint({ fix: cli.args.fix === true });
|
|
21
|
+
};
|
package/cli/commands/refresh.ts
CHANGED
|
@@ -8,11 +8,11 @@ import Compiler from '../compiler';
|
|
|
8
8
|
/*----------------------------------
|
|
9
9
|
- COMMAND
|
|
10
10
|
----------------------------------*/
|
|
11
|
-
export const run = (): Promise<void> =>
|
|
11
|
+
export const run = (): Promise<void> =>
|
|
12
|
+
new Promise(async (resolve) => {
|
|
13
|
+
const compiler = new Compiler('dev');
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
await compiler.refreshGeneratedTypings();
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
resolve();
|
|
18
|
-
});
|
|
17
|
+
resolve();
|
|
18
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import cli from '..';
|
|
2
|
+
import { refreshGeneratedTypings, runAppTypecheck } from '../utils/check';
|
|
3
|
+
|
|
4
|
+
const validateTypecheckArgs = () => {
|
|
5
|
+
const enabledArgs = Object.entries(cli.args).filter(([name, value]) => name !== 'workdir' && value === true);
|
|
6
|
+
|
|
7
|
+
if (enabledArgs.length > 0)
|
|
8
|
+
throw new Error(
|
|
9
|
+
`Unknown typecheck argument(s): ${enabledArgs.map(([name]) => name).join(', ')}. This command does not accept options.`,
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const run = async (): Promise<void> => {
|
|
14
|
+
validateTypecheckArgs();
|
|
15
|
+
|
|
16
|
+
await refreshGeneratedTypings();
|
|
17
|
+
await runAppTypecheck();
|
|
18
|
+
};
|