@celsian/vura-cli 0.5.2 → 0.5.3
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/dist/commands/dev.js
CHANGED
|
@@ -263,7 +263,7 @@ export async function startStandaloneServer(manifest, opts) {
|
|
|
263
263
|
catch { /* not installed — keep default */ }
|
|
264
264
|
const result = await esbuild({
|
|
265
265
|
stdin: {
|
|
266
|
-
contents: generateClientPageEntry(`./${basename(absPath)}`, page.mode),
|
|
266
|
+
contents: generateClientPageEntry(`./${basename(absPath)}`, page.mode, { dev: true }),
|
|
267
267
|
resolveDir: dirname(absPath),
|
|
268
268
|
sourcefile: '__vura-client-entry__.js',
|
|
269
269
|
loader: 'js',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiRoute, PageRoute, RouteManifest } from '@celsian/vura-core';
|
|
2
|
-
export type RuntimeProfile = 'static' | 'cold' | 'hot' | 'task-cold' | 'cron-cold' | 'task-hot' | 'cron-hot';
|
|
2
|
+
export type RuntimeProfile = 'static' | 'cold' | 'hot' | 'streaming-hot' | 'task-cold' | 'cron-cold' | 'task-hot' | 'cron-hot';
|
|
3
3
|
export interface RuntimeRouteInspection {
|
|
4
4
|
type: 'api' | 'page';
|
|
5
5
|
pattern: string;
|
|
@@ -6,19 +6,24 @@ function configNumber(config, key) {
|
|
|
6
6
|
const value = config[key];
|
|
7
7
|
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
8
8
|
}
|
|
9
|
+
function prefersHotTask(config) {
|
|
10
|
+
return ['runtime', 'placement', 'target'].some((key) => configString(config, key) === 'hot')
|
|
11
|
+
|| config.hot === true;
|
|
12
|
+
}
|
|
9
13
|
export function taskNameFromPattern(urlPattern) {
|
|
10
14
|
return urlPattern.replace(/^\/api\//, '').replace(/\//g, '.');
|
|
11
15
|
}
|
|
12
16
|
export function profileForApiRoute(route) {
|
|
13
17
|
if (route.kind === 'hot')
|
|
14
|
-
return 'hot';
|
|
18
|
+
return route.hasWebsocket ? 'streaming-hot' : 'hot';
|
|
15
19
|
if (route.kind === 'task')
|
|
16
|
-
return 'task-cold';
|
|
20
|
+
return prefersHotTask(route.config) ? 'task-hot' : 'task-cold';
|
|
17
21
|
return 'cold';
|
|
18
22
|
}
|
|
19
23
|
export function cronProfileForApiRoute(route) {
|
|
20
|
-
if (route.kind === 'task' && configString(route.config, 'schedule'))
|
|
21
|
-
return 'cron-cold';
|
|
24
|
+
if (route.kind === 'task' && configString(route.config, 'schedule')) {
|
|
25
|
+
return profileForApiRoute(route) === 'task-hot' ? 'cron-hot' : 'cron-cold';
|
|
26
|
+
}
|
|
22
27
|
return null;
|
|
23
28
|
}
|
|
24
29
|
export function profileForPageRoute(page) {
|
|
@@ -27,9 +32,12 @@ export function profileForPageRoute(page) {
|
|
|
27
32
|
return 'static';
|
|
28
33
|
}
|
|
29
34
|
function backingTargetForApiRoute(route) {
|
|
30
|
-
|
|
35
|
+
const profile = profileForApiRoute(route);
|
|
36
|
+
if (profile === 'hot' || profile === 'streaming-hot')
|
|
31
37
|
return 'hot server';
|
|
32
|
-
if (
|
|
38
|
+
if (profile === 'task-hot')
|
|
39
|
+
return 'hot task runtime';
|
|
40
|
+
if (profile === 'task-cold')
|
|
33
41
|
return 'serverless task function';
|
|
34
42
|
return 'serverless function';
|
|
35
43
|
}
|
|
@@ -71,7 +79,9 @@ function inspectApiRoute(route) {
|
|
|
71
79
|
filePath: route.filePath,
|
|
72
80
|
sourceIntent: `schedule:${schedule}`,
|
|
73
81
|
effectiveProfile: cronProfile,
|
|
74
|
-
backingTarget:
|
|
82
|
+
backingTarget: cronProfile === 'cron-hot'
|
|
83
|
+
? 'control-plane scheduler to hot task runtime'
|
|
84
|
+
: 'control-plane scheduler to task function',
|
|
75
85
|
methods: route.methods,
|
|
76
86
|
schedule,
|
|
77
87
|
hasWebsocket: false,
|
|
@@ -100,6 +110,7 @@ export function inspectRuntime(manifest) {
|
|
|
100
110
|
static: 0,
|
|
101
111
|
cold: 0,
|
|
102
112
|
hot: 0,
|
|
113
|
+
'streaming-hot': 0,
|
|
103
114
|
'task-cold': 0,
|
|
104
115
|
'cron-cold': 0,
|
|
105
116
|
'task-hot': 0,
|
|
@@ -134,37 +145,43 @@ export function adviseRuntime(manifest) {
|
|
|
134
145
|
pattern: route.urlPattern,
|
|
135
146
|
type: 'api',
|
|
136
147
|
currentProfile,
|
|
137
|
-
recommendation: 'hot',
|
|
148
|
+
recommendation: 'streaming-hot',
|
|
138
149
|
severity: route.kind === 'hot' ? 'info' : 'warn',
|
|
139
150
|
reason: route.kind === 'hot'
|
|
140
|
-
? 'WebSocket route is correctly placed on hot runtime.'
|
|
141
|
-
: 'WebSocket exports require hot runtime to handle upgrades.',
|
|
151
|
+
? 'WebSocket route is correctly placed on streaming-hot runtime.'
|
|
152
|
+
: 'WebSocket exports require streaming-hot runtime to handle upgrades.',
|
|
142
153
|
});
|
|
143
154
|
}
|
|
144
155
|
if (route.kind === 'task') {
|
|
156
|
+
const taskProfile = profileForApiRoute(route);
|
|
145
157
|
advice.push({
|
|
146
158
|
pattern: route.urlPattern,
|
|
147
159
|
type: 'api',
|
|
148
160
|
currentProfile,
|
|
149
|
-
recommendation:
|
|
161
|
+
recommendation: taskProfile,
|
|
150
162
|
severity: 'info',
|
|
151
|
-
reason:
|
|
152
|
-
? '
|
|
153
|
-
:
|
|
163
|
+
reason: taskProfile === 'task-hot'
|
|
164
|
+
? 'Task route is pinned to hot task runtime for long-running or stateful work.'
|
|
165
|
+
: schedule
|
|
166
|
+
? 'Scheduled task is a task-cold worker with cron-cold dispatch.'
|
|
167
|
+
: 'Task route is a task-cold worker for manual or API-triggered jobs.',
|
|
154
168
|
nextCommand: `vura tasks run ${taskNameFromPattern(route.urlPattern)}`,
|
|
155
169
|
});
|
|
156
170
|
if (schedule) {
|
|
171
|
+
const cronProfile = cronProfileForApiRoute(route) ?? 'cron-cold';
|
|
157
172
|
advice.push({
|
|
158
173
|
pattern: route.urlPattern,
|
|
159
174
|
type: 'api',
|
|
160
|
-
currentProfile:
|
|
161
|
-
recommendation:
|
|
175
|
+
currentProfile: cronProfile,
|
|
176
|
+
recommendation: cronProfile,
|
|
162
177
|
severity: 'info',
|
|
163
|
-
reason:
|
|
178
|
+
reason: cronProfile === 'cron-hot'
|
|
179
|
+
? `Cron schedule ${schedule} dispatches to the hot task target.`
|
|
180
|
+
: `Cron schedule ${schedule} dispatches to the task-cold target.`,
|
|
164
181
|
nextCommand: 'vura tasks list',
|
|
165
182
|
});
|
|
166
183
|
}
|
|
167
|
-
if (typeof timeout === 'number' && timeout > 60_000) {
|
|
184
|
+
if (typeof timeout === 'number' && timeout > 60_000 && taskProfile !== 'task-hot') {
|
|
168
185
|
advice.push({
|
|
169
186
|
pattern: route.urlPattern,
|
|
170
187
|
type: 'api',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celsian/vura-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Vura CLI — build and deploy full-stack apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
"!dist/**/*.map"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@celsian/vura-core": "0.5.
|
|
18
|
+
"@celsian/vura-core": "0.5.3",
|
|
19
19
|
"esbuild": "^0.28.1",
|
|
20
20
|
"what-framework": "^0.11.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@celsian/vura-adapter-vura": "0.5.
|
|
23
|
+
"@celsian/vura-adapter-vura": "0.5.3",
|
|
24
24
|
"ws": "^8.0.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependenciesMeta": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@celsian/vura-adapter-vura": "0.5.
|
|
35
|
+
"@celsian/vura-adapter-vura": "0.5.3",
|
|
36
36
|
"@types/ws": "^8.18.1",
|
|
37
37
|
"ws": "^8.21.0"
|
|
38
38
|
},
|