@vmz/vmz 0.0.4 → 0.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.
- package/dist/build-assemble.d.ts +52 -0
- package/dist/build-assemble.js +191 -0
- package/dist/cdn-policy.d.ts +22 -4
- package/dist/cdn-policy.js +109 -10
- package/dist/cli.js +106 -24
- package/dist/delivery-profile.d.ts +74 -0
- package/dist/delivery-profile.js +279 -0
- package/dist/dev-session.js +2 -1
- package/dist/document-build.js +9 -4
- package/dist/document-enrich.js +8 -0
- package/dist/embedded-packaging.d.ts +22 -0
- package/dist/embedded-packaging.js +113 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/locale-check.js +11 -8
- package/dist/locale-cmd.js +2 -2
- package/dist/locale-route-emit.d.ts +34 -0
- package/dist/locale-route-emit.js +134 -0
- package/dist/locale-router.d.ts +20 -0
- package/dist/locale-router.js +68 -0
- package/dist/log.d.ts +2 -2
- package/dist/log.js +11 -3
- package/dist/pack.d.ts +40 -0
- package/dist/pack.js +108 -0
- package/dist/plugin-host.d.ts +1 -1
- package/dist/plugin-host.js +2 -2
- package/dist/production-test-pack.d.ts +0 -14
- package/dist/production-test-pack.js +23 -28
- package/dist/release-pack.js +12 -3
- package/dist/server-artifact.d.ts +140 -0
- package/dist/server-artifact.js +205 -0
- package/dist/server-language-backend.d.ts +89 -0
- package/dist/server-language-backend.js +121 -0
- package/dist/static-emit.d.ts +10 -1
- package/dist/static-emit.js +140 -26
- package/package.json +12 -12
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P4 ServerArtifact — compiled route decision tree + public ServerRoute contracts
|
|
3
|
+
* + internal capability units + selected runtime adapter. Web Standards Fetch entry.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SERVER_ARTIFACT_SCHEMA = "vmz.server.artifact.v0";
|
|
6
|
+
export declare const HTTP_CONTRACT_SCHEMA = "vmz.http.contract.v0";
|
|
7
|
+
export declare const SERVER_RUNTIME_ADAPTER_SCHEMA = "vmz.server.runtime_adapter.v0";
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} outDir
|
|
10
|
+
* @param {{
|
|
11
|
+
* profileId?: string | null,
|
|
12
|
+
* assembly?: string | null,
|
|
13
|
+
* serverRuntime?: string | null,
|
|
14
|
+
* packDigest?: string | null,
|
|
15
|
+
* }} [opts]
|
|
16
|
+
*/
|
|
17
|
+
export declare function emitServerArtifact(outDir: any, opts?: {}): {
|
|
18
|
+
artifact: {
|
|
19
|
+
schema: string;
|
|
20
|
+
profileId: any;
|
|
21
|
+
assembly: any;
|
|
22
|
+
selectedRuntime: string;
|
|
23
|
+
entry: {
|
|
24
|
+
kind: string;
|
|
25
|
+
standards: string[];
|
|
26
|
+
rpcPath: string;
|
|
27
|
+
};
|
|
28
|
+
httpContract: {
|
|
29
|
+
schema: string;
|
|
30
|
+
digest: string;
|
|
31
|
+
};
|
|
32
|
+
publicRoutes: {
|
|
33
|
+
verb: string;
|
|
34
|
+
path: string;
|
|
35
|
+
moduleId: string;
|
|
36
|
+
method: string;
|
|
37
|
+
className: string;
|
|
38
|
+
visibility: string;
|
|
39
|
+
kind: string;
|
|
40
|
+
}[];
|
|
41
|
+
internalCapabilities: any[];
|
|
42
|
+
middlewareUnits: any[];
|
|
43
|
+
routeDecisionTree: ({
|
|
44
|
+
id: string;
|
|
45
|
+
match: {
|
|
46
|
+
method: string;
|
|
47
|
+
path: string;
|
|
48
|
+
};
|
|
49
|
+
action: string;
|
|
50
|
+
target: {
|
|
51
|
+
moduleId: string;
|
|
52
|
+
method: string;
|
|
53
|
+
};
|
|
54
|
+
visibility: string;
|
|
55
|
+
} | {
|
|
56
|
+
id: string;
|
|
57
|
+
match: {
|
|
58
|
+
method: string;
|
|
59
|
+
path: string;
|
|
60
|
+
};
|
|
61
|
+
action: string;
|
|
62
|
+
visibility: string;
|
|
63
|
+
})[];
|
|
64
|
+
deploymentSchema: any;
|
|
65
|
+
packDigest: any;
|
|
66
|
+
adapters: {
|
|
67
|
+
node: {
|
|
68
|
+
kind: string;
|
|
69
|
+
status: string;
|
|
70
|
+
entry: string;
|
|
71
|
+
};
|
|
72
|
+
worker: {
|
|
73
|
+
kind: string;
|
|
74
|
+
status: string;
|
|
75
|
+
entry: string;
|
|
76
|
+
};
|
|
77
|
+
deno: {
|
|
78
|
+
kind: string;
|
|
79
|
+
status: string;
|
|
80
|
+
entry: string;
|
|
81
|
+
};
|
|
82
|
+
bun: {
|
|
83
|
+
kind: string;
|
|
84
|
+
status: string;
|
|
85
|
+
entry: string;
|
|
86
|
+
};
|
|
87
|
+
'rust-host': {
|
|
88
|
+
kind: string;
|
|
89
|
+
status: string;
|
|
90
|
+
entry: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
path: string;
|
|
95
|
+
httpContractDigest: string;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* @param {Record<string, any>} artifact
|
|
99
|
+
* @param {string} adapterId
|
|
100
|
+
*/
|
|
101
|
+
export declare function projectServerRuntimeAdapter(artifact: any, adapterId: any): {
|
|
102
|
+
host: string;
|
|
103
|
+
invoke: string;
|
|
104
|
+
status: string;
|
|
105
|
+
schema: string;
|
|
106
|
+
adapterId: string;
|
|
107
|
+
artifactDigest: any;
|
|
108
|
+
httpContractDigest: any;
|
|
109
|
+
spaFallback: boolean;
|
|
110
|
+
entry: any;
|
|
111
|
+
publicRouteCount: any;
|
|
112
|
+
internalCapabilityCount: any;
|
|
113
|
+
} | {
|
|
114
|
+
host: string;
|
|
115
|
+
invoke: string;
|
|
116
|
+
status: string;
|
|
117
|
+
note: string;
|
|
118
|
+
schema: string;
|
|
119
|
+
adapterId: string;
|
|
120
|
+
artifactDigest: any;
|
|
121
|
+
httpContractDigest: any;
|
|
122
|
+
spaFallback: boolean;
|
|
123
|
+
entry: any;
|
|
124
|
+
publicRouteCount: any;
|
|
125
|
+
internalCapabilityCount: any;
|
|
126
|
+
} | {
|
|
127
|
+
host: string;
|
|
128
|
+
invoke: string;
|
|
129
|
+
status: string;
|
|
130
|
+
note: string;
|
|
131
|
+
consumes: string[];
|
|
132
|
+
schema: string;
|
|
133
|
+
adapterId: string;
|
|
134
|
+
artifactDigest: any;
|
|
135
|
+
httpContractDigest: any;
|
|
136
|
+
spaFallback: boolean;
|
|
137
|
+
entry: any;
|
|
138
|
+
publicRouteCount: any;
|
|
139
|
+
internalCapabilityCount: any;
|
|
140
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P4 ServerArtifact — compiled route decision tree + public ServerRoute contracts
|
|
3
|
+
* + internal capability units + selected runtime adapter. Web Standards Fetch entry.
|
|
4
|
+
*/
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { SERVER_RUNTIMES } from './delivery-profile.js';
|
|
10
|
+
export const SERVER_ARTIFACT_SCHEMA = 'vmz.server.artifact.v0';
|
|
11
|
+
export const HTTP_CONTRACT_SCHEMA = 'vmz.http.contract.v0';
|
|
12
|
+
export const SERVER_RUNTIME_ADAPTER_SCHEMA = 'vmz.server.runtime_adapter.v0';
|
|
13
|
+
const DEFAULT_RPC_PATH = '/__vmz/rpc';
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} outDir
|
|
16
|
+
* @param {{
|
|
17
|
+
* profileId?: string | null,
|
|
18
|
+
* assembly?: string | null,
|
|
19
|
+
* serverRuntime?: string | null,
|
|
20
|
+
* packDigest?: string | null,
|
|
21
|
+
* }} [opts]
|
|
22
|
+
*/
|
|
23
|
+
export function emitServerArtifact(outDir, opts = {}) {
|
|
24
|
+
const deployment = readJson(path.join(outDir, 'vmz-deployment.json')) || { schema: null, units: [] };
|
|
25
|
+
const routes = readJson(path.join(outDir, 'vmz-routes.json'));
|
|
26
|
+
const routeRows = Array.isArray(routes) ? routes : [];
|
|
27
|
+
const selectedRuntime = normalizeRuntime(opts.serverRuntime);
|
|
28
|
+
const units = Array.isArray(deployment.units) ? deployment.units : [];
|
|
29
|
+
const publicRoutes = routeRows.map((r) => ({
|
|
30
|
+
verb: String(r.verb || 'GET').toUpperCase(),
|
|
31
|
+
path: String(r.path || ''),
|
|
32
|
+
moduleId: String(r.moduleId || ''),
|
|
33
|
+
method: String(r.method || ''),
|
|
34
|
+
className: r.className != null ? String(r.className) : null,
|
|
35
|
+
visibility: 'public',
|
|
36
|
+
kind: 'server-route',
|
|
37
|
+
}));
|
|
38
|
+
const publicKeys = new Set(publicRoutes.map((r) => `${r.moduleId}::${r.method}`));
|
|
39
|
+
/** @type {Array<Record<string, unknown>>} */
|
|
40
|
+
const internalCapabilities = [];
|
|
41
|
+
for (const u of units) {
|
|
42
|
+
const moduleId = u.serverModuleId != null ? String(u.serverModuleId) : '';
|
|
43
|
+
if (!moduleId)
|
|
44
|
+
continue;
|
|
45
|
+
const caps = Array.isArray(u.capabilities) ? u.capabilities.map(String) : [];
|
|
46
|
+
for (const method of caps) {
|
|
47
|
+
const key = `${moduleId}::${method}`;
|
|
48
|
+
if (publicKeys.has(key))
|
|
49
|
+
continue;
|
|
50
|
+
internalCapabilities.push({
|
|
51
|
+
chunkId: String(u.chunkId || ''),
|
|
52
|
+
moduleId,
|
|
53
|
+
method,
|
|
54
|
+
visibility: 'internal',
|
|
55
|
+
kind: 'capability',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const routeDecisionTree = [
|
|
60
|
+
{
|
|
61
|
+
id: 'rpc',
|
|
62
|
+
match: { method: 'POST', path: DEFAULT_RPC_PATH },
|
|
63
|
+
action: 'invoke-rpc',
|
|
64
|
+
visibility: 'internal-transport',
|
|
65
|
+
},
|
|
66
|
+
...publicRoutes.map((r, i) => ({
|
|
67
|
+
id: `public-route-${i}`,
|
|
68
|
+
match: { method: r.verb, path: r.path },
|
|
69
|
+
action: 'invoke-server-route',
|
|
70
|
+
target: { moduleId: r.moduleId, method: r.method },
|
|
71
|
+
visibility: 'public',
|
|
72
|
+
})),
|
|
73
|
+
];
|
|
74
|
+
const httpContractBody = {
|
|
75
|
+
schema: HTTP_CONTRACT_SCHEMA,
|
|
76
|
+
rpcPath: DEFAULT_RPC_PATH,
|
|
77
|
+
publicRoutes: publicRoutes.map((r) => ({
|
|
78
|
+
verb: r.verb,
|
|
79
|
+
path: r.path,
|
|
80
|
+
moduleId: r.moduleId,
|
|
81
|
+
method: r.method,
|
|
82
|
+
})),
|
|
83
|
+
internalCapabilityCount: internalCapabilities.length,
|
|
84
|
+
entry: 'fetch',
|
|
85
|
+
};
|
|
86
|
+
const httpContractDigest = sha256Hex(canonicalJson(httpContractBody));
|
|
87
|
+
const artifact = {
|
|
88
|
+
schema: SERVER_ARTIFACT_SCHEMA,
|
|
89
|
+
profileId: opts.profileId || null,
|
|
90
|
+
assembly: opts.assembly || null,
|
|
91
|
+
selectedRuntime,
|
|
92
|
+
entry: {
|
|
93
|
+
kind: 'fetch',
|
|
94
|
+
standards: ['Request', 'Response', 'Streams', 'AbortSignal'],
|
|
95
|
+
rpcPath: DEFAULT_RPC_PATH,
|
|
96
|
+
},
|
|
97
|
+
httpContract: {
|
|
98
|
+
schema: HTTP_CONTRACT_SCHEMA,
|
|
99
|
+
digest: httpContractDigest,
|
|
100
|
+
},
|
|
101
|
+
publicRoutes,
|
|
102
|
+
internalCapabilities,
|
|
103
|
+
middlewareUnits: [],
|
|
104
|
+
routeDecisionTree,
|
|
105
|
+
deploymentSchema: deployment.schema || null,
|
|
106
|
+
packDigest: opts.packDigest || null,
|
|
107
|
+
adapters: {
|
|
108
|
+
node: { kind: 'node-http', status: 'runtime', entry: 'handleNodeRequest' },
|
|
109
|
+
worker: { kind: 'fetch', status: 'runtime', entry: 'handleFetchRequest' },
|
|
110
|
+
deno: { kind: 'fetch', status: 'projected', entry: 'handleFetchRequest' },
|
|
111
|
+
bun: { kind: 'fetch', status: 'projected', entry: 'handleFetchRequest' },
|
|
112
|
+
'rust-host': { kind: 'contract-projection', status: 'projected', entry: 'fetch' },
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
artifact.artifactDigest = sha256Hex(canonicalJson({ ...artifact, artifactDigest: undefined }));
|
|
116
|
+
const vmzDir = path.join(outDir, '_vmz');
|
|
117
|
+
mkdirSync(vmzDir, { recursive: true });
|
|
118
|
+
const file = path.join(vmzDir, 'server-artifact.json');
|
|
119
|
+
writeFileSync(file, `${JSON.stringify(artifact, null, 2)}\n`, 'utf8');
|
|
120
|
+
const adapterDir = path.join(vmzDir, 'adapters');
|
|
121
|
+
mkdirSync(adapterDir, { recursive: true });
|
|
122
|
+
for (const adapterId of ['worker', 'rust-host']) {
|
|
123
|
+
const projection = projectServerRuntimeAdapter(artifact, adapterId);
|
|
124
|
+
const dir = path.join(adapterDir, adapterId);
|
|
125
|
+
mkdirSync(dir, { recursive: true });
|
|
126
|
+
writeFileSync(path.join(dir, 'adapter.json'), `${JSON.stringify(projection, null, 2)}\n`, 'utf8');
|
|
127
|
+
}
|
|
128
|
+
return { artifact, path: file, httpContractDigest };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* @param {Record<string, any>} artifact
|
|
132
|
+
* @param {string} adapterId
|
|
133
|
+
*/
|
|
134
|
+
export function projectServerRuntimeAdapter(artifact, adapterId) {
|
|
135
|
+
const id = String(adapterId || '').trim();
|
|
136
|
+
if (!SERVER_RUNTIMES.includes(id) && id !== 'worker') {
|
|
137
|
+
throw new Error(`projectServerRuntimeAdapter: unknown adapter ${id}`);
|
|
138
|
+
}
|
|
139
|
+
const base = {
|
|
140
|
+
schema: SERVER_RUNTIME_ADAPTER_SCHEMA,
|
|
141
|
+
adapterId: id,
|
|
142
|
+
artifactDigest: artifact.artifactDigest,
|
|
143
|
+
httpContractDigest: artifact.httpContract?.digest || null,
|
|
144
|
+
spaFallback: false,
|
|
145
|
+
entry: artifact.entry,
|
|
146
|
+
publicRouteCount: Array.isArray(artifact.publicRoutes) ? artifact.publicRoutes.length : 0,
|
|
147
|
+
internalCapabilityCount: Array.isArray(artifact.internalCapabilities)
|
|
148
|
+
? artifact.internalCapabilities.length
|
|
149
|
+
: 0,
|
|
150
|
+
};
|
|
151
|
+
if (id === 'node') {
|
|
152
|
+
return { ...base, host: 'node:http', invoke: 'handleNodeRequest', status: 'runtime' };
|
|
153
|
+
}
|
|
154
|
+
if (id === 'worker' || id === 'deno' || id === 'bun') {
|
|
155
|
+
return {
|
|
156
|
+
...base,
|
|
157
|
+
host: 'fetch',
|
|
158
|
+
invoke: 'handleFetchRequest',
|
|
159
|
+
status: id === 'worker' ? 'runtime' : 'projected',
|
|
160
|
+
note: id === 'worker'
|
|
161
|
+
? 'Fetch entry; live thin gated via worker-shaped subprocess host'
|
|
162
|
+
: 'Fetch contract projection; live runtime not gated',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// rust-host
|
|
166
|
+
return {
|
|
167
|
+
...base,
|
|
168
|
+
host: 'rust-fetch-consumer',
|
|
169
|
+
invoke: 'fetch',
|
|
170
|
+
status: 'projected',
|
|
171
|
+
note: 'contract projection only — live Rust host binary parity not gated',
|
|
172
|
+
consumes: ['server-artifact.json', 'vmz-routes.json', 'vmz-deployment.json'],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function normalizeRuntime(raw) {
|
|
176
|
+
const v = String(raw || 'node').trim();
|
|
177
|
+
return SERVER_RUNTIMES.includes(v) ? v : 'node';
|
|
178
|
+
}
|
|
179
|
+
function readJson(file) {
|
|
180
|
+
if (!existsSync(file))
|
|
181
|
+
return null;
|
|
182
|
+
try {
|
|
183
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function canonicalJson(value) {
|
|
190
|
+
return JSON.stringify(sortKeys(value));
|
|
191
|
+
}
|
|
192
|
+
function sortKeys(value) {
|
|
193
|
+
if (Array.isArray(value))
|
|
194
|
+
return value.map(sortKeys);
|
|
195
|
+
if (value && typeof value === 'object') {
|
|
196
|
+
const out = {};
|
|
197
|
+
for (const k of Object.keys(value).sort())
|
|
198
|
+
out[k] = sortKeys(value[k]);
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
function sha256Hex(text) {
|
|
204
|
+
return crypto.createHash('sha256').update(text, 'utf8').digest('hex');
|
|
205
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Language DSL backends (lang on `<script server>`).
|
|
3
|
+
* Author surface is a VMZ DSL flavor — not full target-language source.
|
|
4
|
+
*/
|
|
5
|
+
/** @typedef {'ts' | 'rust' | 'python' | 'java'} ServerLangId */
|
|
6
|
+
export declare const SERVER_LANG_IDS: readonly string[];
|
|
7
|
+
/** @type {Record<string, ServerLangId>} */
|
|
8
|
+
export declare const SERVER_LANG_ALIASES: Readonly<{
|
|
9
|
+
ts: "ts";
|
|
10
|
+
typescript: "ts";
|
|
11
|
+
rust: "rust";
|
|
12
|
+
python: "python";
|
|
13
|
+
java: "java";
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {{
|
|
17
|
+
* langId: ServerLangId,
|
|
18
|
+
* aliases: string[],
|
|
19
|
+
* compatibleRuntimes: string[],
|
|
20
|
+
* implemented: boolean,
|
|
21
|
+
* artifactRoot: string,
|
|
22
|
+
* }} ServerLanguageBackendMeta
|
|
23
|
+
*/
|
|
24
|
+
/** @type {Record<ServerLangId, ServerLanguageBackendMeta>} */
|
|
25
|
+
export declare const SERVER_LANGUAGE_BACKENDS: Readonly<{
|
|
26
|
+
ts: {
|
|
27
|
+
langId: string;
|
|
28
|
+
aliases: string[];
|
|
29
|
+
compatibleRuntimes: string[];
|
|
30
|
+
implemented: boolean;
|
|
31
|
+
artifactRoot: string;
|
|
32
|
+
};
|
|
33
|
+
rust: {
|
|
34
|
+
langId: string;
|
|
35
|
+
aliases: string[];
|
|
36
|
+
compatibleRuntimes: string[];
|
|
37
|
+
implemented: boolean;
|
|
38
|
+
artifactRoot: string;
|
|
39
|
+
};
|
|
40
|
+
python: {
|
|
41
|
+
langId: string;
|
|
42
|
+
aliases: string[];
|
|
43
|
+
compatibleRuntimes: string[];
|
|
44
|
+
implemented: boolean;
|
|
45
|
+
artifactRoot: string;
|
|
46
|
+
};
|
|
47
|
+
java: {
|
|
48
|
+
langId: string;
|
|
49
|
+
aliases: string[];
|
|
50
|
+
compatibleRuntimes: string[];
|
|
51
|
+
implemented: boolean;
|
|
52
|
+
artifactRoot: string;
|
|
53
|
+
};
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve author `lang` attr (or null/undefined for default TS).
|
|
57
|
+
* @param {string | null | undefined} raw
|
|
58
|
+
* @returns {{
|
|
59
|
+
* ok: true, langId: ServerLangId, backend: ServerLanguageBackendMeta
|
|
60
|
+
* } | {
|
|
61
|
+
* ok: false, code: string, message: string
|
|
62
|
+
* }}
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveServerLanguage(raw: any): {
|
|
65
|
+
ok: boolean;
|
|
66
|
+
code: string;
|
|
67
|
+
message: string;
|
|
68
|
+
langId?: undefined;
|
|
69
|
+
backend?: undefined;
|
|
70
|
+
} | {
|
|
71
|
+
ok: boolean;
|
|
72
|
+
langId: any;
|
|
73
|
+
backend: any;
|
|
74
|
+
code?: undefined;
|
|
75
|
+
message?: undefined;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* @param {ServerLangId} langId
|
|
79
|
+
* @param {string | null | undefined} serverRuntime
|
|
80
|
+
*/
|
|
81
|
+
export declare function assertLangRuntimePair(langId: any, serverRuntime: any): {
|
|
82
|
+
ok: boolean;
|
|
83
|
+
code: string;
|
|
84
|
+
message: string;
|
|
85
|
+
} | {
|
|
86
|
+
ok: boolean;
|
|
87
|
+
code?: undefined;
|
|
88
|
+
message?: undefined;
|
|
89
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Language DSL backends (lang on `<script server>`).
|
|
3
|
+
* Author surface is a VMZ DSL flavor — not full target-language source.
|
|
4
|
+
*/
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
/** @typedef {'ts' | 'rust' | 'python' | 'java'} ServerLangId */
|
|
7
|
+
export const SERVER_LANG_IDS = Object.freeze(['ts', 'rust', 'python', 'java']);
|
|
8
|
+
/** @type {Record<string, ServerLangId>} */
|
|
9
|
+
export const SERVER_LANG_ALIASES = Object.freeze({
|
|
10
|
+
ts: 'ts',
|
|
11
|
+
typescript: 'ts',
|
|
12
|
+
rust: 'rust',
|
|
13
|
+
python: 'python',
|
|
14
|
+
java: 'java',
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {{
|
|
18
|
+
* langId: ServerLangId,
|
|
19
|
+
* aliases: string[],
|
|
20
|
+
* compatibleRuntimes: string[],
|
|
21
|
+
* implemented: boolean,
|
|
22
|
+
* artifactRoot: string,
|
|
23
|
+
* }} ServerLanguageBackendMeta
|
|
24
|
+
*/
|
|
25
|
+
/** @type {Record<ServerLangId, ServerLanguageBackendMeta>} */
|
|
26
|
+
export const SERVER_LANGUAGE_BACKENDS = Object.freeze({
|
|
27
|
+
ts: {
|
|
28
|
+
langId: 'ts',
|
|
29
|
+
aliases: ['ts', 'typescript'],
|
|
30
|
+
compatibleRuntimes: ['node', 'worker', 'deno', 'bun'],
|
|
31
|
+
implemented: true,
|
|
32
|
+
artifactRoot: 'dist/#server',
|
|
33
|
+
},
|
|
34
|
+
rust: {
|
|
35
|
+
langId: 'rust',
|
|
36
|
+
aliases: ['rust'],
|
|
37
|
+
compatibleRuntimes: ['rust-host'],
|
|
38
|
+
implemented: true,
|
|
39
|
+
artifactRoot: 'target/vmz/server-rust',
|
|
40
|
+
},
|
|
41
|
+
python: {
|
|
42
|
+
langId: 'python',
|
|
43
|
+
aliases: ['python'],
|
|
44
|
+
compatibleRuntimes: ['python-host'],
|
|
45
|
+
implemented: false,
|
|
46
|
+
artifactRoot: 'target/vmz/server-python',
|
|
47
|
+
},
|
|
48
|
+
java: {
|
|
49
|
+
langId: 'java',
|
|
50
|
+
aliases: ['java'],
|
|
51
|
+
compatibleRuntimes: ['jvm-host'],
|
|
52
|
+
implemented: false,
|
|
53
|
+
artifactRoot: 'target/vmz/server-java',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Resolve author `lang` attr (or null/undefined for default TS).
|
|
58
|
+
* @param {string | null | undefined} raw
|
|
59
|
+
* @returns {{
|
|
60
|
+
* ok: true, langId: ServerLangId, backend: ServerLanguageBackendMeta
|
|
61
|
+
* } | {
|
|
62
|
+
* ok: false, code: string, message: string
|
|
63
|
+
* }}
|
|
64
|
+
*/
|
|
65
|
+
export function resolveServerLanguage(raw) {
|
|
66
|
+
const trimmed = raw == null ? '' : String(raw).trim();
|
|
67
|
+
if (!trimmed) {
|
|
68
|
+
return { ok: true, langId: 'ts', backend: SERVER_LANGUAGE_BACKENDS.ts };
|
|
69
|
+
}
|
|
70
|
+
const langId = SERVER_LANG_ALIASES[trimmed];
|
|
71
|
+
if (!langId) {
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
code: 'vmz::server::unknown_language',
|
|
75
|
+
message: `unknown script language \`${trimmed}\`; use ts|typescript|rust|python|java`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const backend = SERVER_LANGUAGE_BACKENDS[langId];
|
|
79
|
+
if (!backend.implemented) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
code: 'vmz::server::language_backend_unimplemented',
|
|
83
|
+
message: `\`<script server lang="${langId}">\` is registered but not implemented yet`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return { ok: true, langId, backend };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* @param {ServerLangId} langId
|
|
90
|
+
* @param {string | null | undefined} serverRuntime
|
|
91
|
+
*/
|
|
92
|
+
export function assertLangRuntimePair(langId, serverRuntime) {
|
|
93
|
+
const backend = SERVER_LANGUAGE_BACKENDS[langId];
|
|
94
|
+
if (!backend) {
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
code: 'vmz::server::unknown_language',
|
|
98
|
+
message: `unknown langId ${langId}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (langId === 'ts') {
|
|
102
|
+
// TS stays compatible with existing node/worker defaults; rust-host rejects ts.
|
|
103
|
+
if (serverRuntime === 'rust-host' || serverRuntime === 'python-host' || serverRuntime === 'jvm-host') {
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
code: 'vmz::server::lang_runtime_mismatch',
|
|
107
|
+
message: `lang=ts is incompatible with serverRuntime=${serverRuntime}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return { ok: true };
|
|
111
|
+
}
|
|
112
|
+
const rt = String(serverRuntime || '').trim();
|
|
113
|
+
if (!backend.compatibleRuntimes.includes(rt)) {
|
|
114
|
+
return {
|
|
115
|
+
ok: false,
|
|
116
|
+
code: 'vmz::server::lang_runtime_mismatch',
|
|
117
|
+
message: `lang=${langId} requires serverRuntime in [${backend.compatibleRuntimes.join('|')}] (got ${rt || '(none)'})`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return { ok: true };
|
|
121
|
+
}
|
package/dist/static-emit.d.ts
CHANGED
|
@@ -29,11 +29,13 @@ export declare function emitWebStatic(distDir: any, opts?: {}): Promise<{
|
|
|
29
29
|
chunkId: any;
|
|
30
30
|
htmlPath: any;
|
|
31
31
|
classification: any;
|
|
32
|
+
localeId: any;
|
|
32
33
|
seo: {
|
|
33
34
|
title: any;
|
|
34
35
|
description: any;
|
|
35
36
|
canonical: any;
|
|
36
37
|
robots: any;
|
|
38
|
+
alternates: any;
|
|
37
39
|
};
|
|
38
40
|
}[];
|
|
39
41
|
skipped: any[];
|
|
@@ -75,7 +77,14 @@ export declare function emitWebStatic(distDir: any, opts?: {}): Promise<{
|
|
|
75
77
|
};
|
|
76
78
|
})[];
|
|
77
79
|
errorDocuments: any;
|
|
78
|
-
routes: any;
|
|
80
|
+
routes: any[];
|
|
81
|
+
localeCache: {
|
|
82
|
+
strategy: string;
|
|
83
|
+
varyAcceptLanguage: boolean;
|
|
84
|
+
defaultLocale: any;
|
|
85
|
+
routeCount: number;
|
|
86
|
+
locales: any[];
|
|
87
|
+
};
|
|
79
88
|
};
|
|
80
89
|
cdnAdapters: {
|
|
81
90
|
'local-static': {
|