@bleedingdev/modern-js-renderer-core 0.0.0-bootstrap → 3.9.3-ultramodern.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/LICENSE +21 -0
- package/dist/cjs/abort.js +65 -0
- package/dist/cjs/adapter.js +62 -0
- package/dist/cjs/data/body.js +78 -0
- package/dist/cjs/data/client.js +409 -0
- package/dist/cjs/data/codec.js +168 -0
- package/dist/cjs/data/index.js +125 -0
- package/dist/cjs/data/private.js +77 -0
- package/dist/cjs/data/routes.js +149 -0
- package/dist/cjs/data/server.js +791 -0
- package/dist/cjs/data/static.js +110 -0
- package/dist/cjs/data/tree.js +231 -0
- package/dist/cjs/data/types.js +56 -0
- package/dist/cjs/document.js +184 -0
- package/dist/cjs/entry-client.js +142 -0
- package/dist/cjs/entry-server.js +253 -0
- package/dist/cjs/federation.js +80 -0
- package/dist/cjs/identity.js +120 -0
- package/dist/cjs/index.js +46 -0
- package/dist/cjs/localization.js +48 -0
- package/dist/cjs/router.js +293 -0
- package/dist/cjs/server/assets.js +56 -0
- package/dist/cjs/server/dispatch.js +351 -0
- package/dist/cjs/server/index.js +57 -0
- package/dist/cjs/server/types.js +18 -0
- package/dist/cjs/server/worker.js +73 -0
- package/dist/cjs/session/cache.js +172 -0
- package/dist/cjs/session/index.js +63 -0
- package/dist/cjs/session/request.js +269 -0
- package/dist/cjs/session/types.js +18 -0
- package/dist/esm/abort.mjs +27 -0
- package/dist/esm/adapter.mjs +21 -0
- package/dist/esm/data/body.mjs +40 -0
- package/dist/esm/data/client.mjs +368 -0
- package/dist/esm/data/codec.mjs +112 -0
- package/dist/esm/data/index.mjs +7 -0
- package/dist/esm/data/private.mjs +39 -0
- package/dist/esm/data/routes.mjs +108 -0
- package/dist/esm/data/server.mjs +723 -0
- package/dist/esm/data/static.mjs +51 -0
- package/dist/esm/data/tree.mjs +193 -0
- package/dist/esm/data/types.mjs +6 -0
- package/dist/esm/document.mjs +131 -0
- package/dist/esm/entry-client.mjs +104 -0
- package/dist/esm/entry-server.mjs +215 -0
- package/dist/esm/federation.mjs +36 -0
- package/dist/esm/identity.mjs +63 -0
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/localization.mjs +10 -0
- package/dist/esm/router.mjs +225 -0
- package/dist/esm/server/assets.mjs +15 -0
- package/dist/esm/server/dispatch.mjs +307 -0
- package/dist/esm/server/index.mjs +3 -0
- package/dist/esm/server/types.mjs +0 -0
- package/dist/esm/server/worker.mjs +35 -0
- package/dist/esm/session/cache.mjs +116 -0
- package/dist/esm/session/index.mjs +3 -0
- package/dist/esm/session/request.mjs +231 -0
- package/dist/esm/session/types.mjs +0 -0
- package/dist/esm-node/abort.mjs +28 -0
- package/dist/esm-node/adapter.mjs +22 -0
- package/dist/esm-node/data/body.mjs +41 -0
- package/dist/esm-node/data/client.mjs +369 -0
- package/dist/esm-node/data/codec.mjs +113 -0
- package/dist/esm-node/data/index.mjs +8 -0
- package/dist/esm-node/data/private.mjs +40 -0
- package/dist/esm-node/data/routes.mjs +109 -0
- package/dist/esm-node/data/server.mjs +724 -0
- package/dist/esm-node/data/static.mjs +52 -0
- package/dist/esm-node/data/tree.mjs +194 -0
- package/dist/esm-node/data/types.mjs +7 -0
- package/dist/esm-node/document.mjs +132 -0
- package/dist/esm-node/entry-client.mjs +105 -0
- package/dist/esm-node/entry-server.mjs +216 -0
- package/dist/esm-node/federation.mjs +37 -0
- package/dist/esm-node/identity.mjs +64 -0
- package/dist/esm-node/index.mjs +2 -0
- package/dist/esm-node/localization.mjs +11 -0
- package/dist/esm-node/router.mjs +226 -0
- package/dist/esm-node/server/assets.mjs +16 -0
- package/dist/esm-node/server/dispatch.mjs +308 -0
- package/dist/esm-node/server/index.mjs +4 -0
- package/dist/esm-node/server/types.mjs +1 -0
- package/dist/esm-node/server/worker.mjs +36 -0
- package/dist/esm-node/session/cache.mjs +117 -0
- package/dist/esm-node/session/index.mjs +4 -0
- package/dist/esm-node/session/request.mjs +232 -0
- package/dist/esm-node/session/types.mjs +1 -0
- package/dist/types/abort.d.ts +6 -0
- package/dist/types/adapter.d.ts +195 -0
- package/dist/types/data/body.d.ts +2 -0
- package/dist/types/data/client.d.ts +17 -0
- package/dist/types/data/codec.d.ts +14 -0
- package/dist/types/data/index.d.ts +8 -0
- package/dist/types/data/private.d.ts +6 -0
- package/dist/types/data/routes.d.ts +28 -0
- package/dist/types/data/server.d.ts +59 -0
- package/dist/types/data/static.d.ts +31 -0
- package/dist/types/data/tree.d.ts +3 -0
- package/dist/types/data/types.d.ts +104 -0
- package/dist/types/document.d.ts +76 -0
- package/dist/types/entry-client.d.ts +53 -0
- package/dist/types/entry-server.d.ts +63 -0
- package/dist/types/federation.d.ts +56 -0
- package/dist/types/identity.d.ts +27 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/localization.d.ts +58 -0
- package/dist/types/router.d.ts +201 -0
- package/dist/types/server/assets.d.ts +14 -0
- package/dist/types/server/dispatch.d.ts +11 -0
- package/dist/types/server/index.d.ts +4 -0
- package/dist/types/server/types.d.ts +64 -0
- package/dist/types/server/worker.d.ts +25 -0
- package/dist/types/session/cache.d.ts +25 -0
- package/dist/types/session/index.d.ts +4 -0
- package/dist/types/session/request.d.ts +8 -0
- package/dist/types/session/types.d.ts +48 -0
- package/package.json +159 -4
- package/src/abort.ts +40 -0
- package/src/adapter.ts +255 -0
- package/src/data/body.ts +43 -0
- package/src/data/client.ts +501 -0
- package/src/data/codec.ts +247 -0
- package/src/data/index.ts +8 -0
- package/src/data/private.ts +68 -0
- package/src/data/routes.ts +201 -0
- package/src/data/server.ts +977 -0
- package/src/data/static.ts +105 -0
- package/src/data/tree.ts +244 -0
- package/src/data/types.ts +98 -0
- package/src/document.ts +338 -0
- package/src/entry-client.ts +236 -0
- package/src/entry-server.ts +393 -0
- package/src/federation.ts +111 -0
- package/src/identity.ts +128 -0
- package/src/index.ts +7 -0
- package/src/localization.ts +77 -0
- package/src/router.ts +475 -0
- package/src/server/assets.ts +60 -0
- package/src/server/dispatch.ts +523 -0
- package/src/server/index.ts +16 -0
- package/src/server/types.ts +94 -0
- package/src/server/worker.ts +94 -0
- package/src/session/cache.ts +177 -0
- package/src/session/index.ts +11 -0
- package/src/session/request.ts +324 -0
- package/src/session/types.ts +60 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { identityCacheKey } from "../identity.mjs";
|
|
3
|
+
import { permitsDocumentCache, policyHeaders } from "./cache.mjs";
|
|
4
|
+
function freezeResponsePolicy(policy) {
|
|
5
|
+
if (!Number.isInteger(policy.status) || policy.status < 200 || policy.status > 599) throw new TypeError('A renderer response status must be an integer from 200 to 599.');
|
|
6
|
+
if ('document' !== policy.kind && 'terminal' !== policy.kind) throw new TypeError('A renderer response must identify its document or terminal outcome.');
|
|
7
|
+
const statusText = policy.statusText;
|
|
8
|
+
if (void 0 !== statusText && 'string' != typeof statusText) throw new TypeError('A renderer response status text must be a string.');
|
|
9
|
+
new Response(null, {
|
|
10
|
+
status: policy.status,
|
|
11
|
+
...void 0 === statusText ? {} : {
|
|
12
|
+
statusText
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
if (![
|
|
16
|
+
'no-store',
|
|
17
|
+
'private',
|
|
18
|
+
'public'
|
|
19
|
+
].includes(policy.cache.mode)) throw new TypeError('A renderer response has an unknown cache policy.');
|
|
20
|
+
if ('public' === policy.cache.mode && (!Number.isInteger(policy.cache.maxAgeSeconds) || policy.cache.maxAgeSeconds < 0)) throw new TypeError('A public document cache lifetime must be a nonnegative integer.');
|
|
21
|
+
const headers = policy.headers.map(([name, value])=>{
|
|
22
|
+
new Headers([
|
|
23
|
+
[
|
|
24
|
+
name,
|
|
25
|
+
value
|
|
26
|
+
]
|
|
27
|
+
]);
|
|
28
|
+
return Object.freeze([
|
|
29
|
+
name,
|
|
30
|
+
value
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
kind: policy.kind,
|
|
35
|
+
status: policy.status,
|
|
36
|
+
...void 0 === statusText ? {} : {
|
|
37
|
+
statusText
|
|
38
|
+
},
|
|
39
|
+
headers: Object.freeze(headers),
|
|
40
|
+
cache: Object.freeze({
|
|
41
|
+
...policy.cache
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function createRequestSession(input) {
|
|
46
|
+
identityCacheKey(input.identity);
|
|
47
|
+
if ('node' !== input.platform.kind && 'worker' !== input.platform.kind) throw new TypeError('A renderer request requires an explicit Node or worker binding.');
|
|
48
|
+
const identity = Object.freeze({
|
|
49
|
+
...input.identity
|
|
50
|
+
});
|
|
51
|
+
const platform = Object.freeze({
|
|
52
|
+
...input.platform
|
|
53
|
+
});
|
|
54
|
+
const abortController = new AbortController();
|
|
55
|
+
const disposers = new Set();
|
|
56
|
+
let state = 'matching';
|
|
57
|
+
let policy;
|
|
58
|
+
let committedPolicy;
|
|
59
|
+
let fallback = false;
|
|
60
|
+
let responseCreated = false;
|
|
61
|
+
let hasDocumentBody = false;
|
|
62
|
+
let deliveredResponse;
|
|
63
|
+
let deliveredHeaders;
|
|
64
|
+
let reader;
|
|
65
|
+
let bodyController;
|
|
66
|
+
let cancelPromise;
|
|
67
|
+
let finishPromise;
|
|
68
|
+
let resolveCompletion;
|
|
69
|
+
const completion = new Promise((resolve)=>{
|
|
70
|
+
resolveCompletion = resolve;
|
|
71
|
+
});
|
|
72
|
+
const cancelSource = (reason)=>{
|
|
73
|
+
cancelPromise ??= reader ? reader.cancel(reason).finally(()=>reader?.releaseLock()) : Promise.resolve();
|
|
74
|
+
return cancelPromise;
|
|
75
|
+
};
|
|
76
|
+
const finish = (terminalState, error)=>{
|
|
77
|
+
if (finishPromise) return finishPromise;
|
|
78
|
+
state = terminalState;
|
|
79
|
+
input.request.signal.removeEventListener('abort', onRequestAbort);
|
|
80
|
+
const ownedDisposers = [
|
|
81
|
+
...disposers
|
|
82
|
+
].reverse();
|
|
83
|
+
disposers.clear();
|
|
84
|
+
finishPromise = Promise.resolve().then(async ()=>{
|
|
85
|
+
const cleanupErrors = [];
|
|
86
|
+
let recorded = false;
|
|
87
|
+
if ('completed' !== terminalState) cancelSource(error).catch((cancelError)=>{
|
|
88
|
+
if (!recorded) cleanupErrors.push(cancelError);
|
|
89
|
+
});
|
|
90
|
+
for (const dispose of ownedDisposers)try {
|
|
91
|
+
await dispose();
|
|
92
|
+
} catch (cleanupError) {
|
|
93
|
+
cleanupErrors.push(cleanupError);
|
|
94
|
+
}
|
|
95
|
+
await Promise.resolve();
|
|
96
|
+
recorded = true;
|
|
97
|
+
if ('completed' === terminalState && cleanupErrors.length > 0) state = 'failed';
|
|
98
|
+
const result = Object.freeze({
|
|
99
|
+
state: state,
|
|
100
|
+
fallback,
|
|
101
|
+
...void 0 !== error ? {
|
|
102
|
+
error
|
|
103
|
+
} : {},
|
|
104
|
+
cleanupErrors: Object.freeze(cleanupErrors),
|
|
105
|
+
cacheEligible: 'completed' === state && hasDocumentBody && !fallback && void 0 !== committedPolicy && permitsDocumentCache({
|
|
106
|
+
...committedPolicy,
|
|
107
|
+
headers: deliveredHeaders ? [
|
|
108
|
+
...deliveredHeaders.entries()
|
|
109
|
+
] : committedPolicy.headers
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
resolveCompletion(result);
|
|
113
|
+
return result;
|
|
114
|
+
});
|
|
115
|
+
if ('completed' !== terminalState) {
|
|
116
|
+
abortController.abort(error);
|
|
117
|
+
bodyController?.error(error);
|
|
118
|
+
}
|
|
119
|
+
return finishPromise;
|
|
120
|
+
};
|
|
121
|
+
const abort = (reason = new DOMException('The renderer request was aborted.', 'AbortError'))=>{
|
|
122
|
+
finish('aborted', reason);
|
|
123
|
+
};
|
|
124
|
+
function onRequestAbort() {
|
|
125
|
+
abort(input.request.signal.reason);
|
|
126
|
+
}
|
|
127
|
+
const session = {
|
|
128
|
+
request: input.request,
|
|
129
|
+
identity,
|
|
130
|
+
platform,
|
|
131
|
+
signal: abortController.signal,
|
|
132
|
+
get state () {
|
|
133
|
+
return state;
|
|
134
|
+
},
|
|
135
|
+
get responsePolicy () {
|
|
136
|
+
return policy;
|
|
137
|
+
},
|
|
138
|
+
get committedPolicy () {
|
|
139
|
+
return committedPolicy;
|
|
140
|
+
},
|
|
141
|
+
completion,
|
|
142
|
+
resolveResponse (nextPolicy) {
|
|
143
|
+
if (committedPolicy || finishPromise) throw new Error('Renderer response status and headers are already committed or terminated.');
|
|
144
|
+
policy = freezeResponsePolicy(nextPolicy);
|
|
145
|
+
if ('matching' === state) state = 'ready';
|
|
146
|
+
},
|
|
147
|
+
startRendering () {
|
|
148
|
+
if ('ready' !== state) throw new Error('Resolve the blocking HTTP outcome before starting the renderer.');
|
|
149
|
+
state = 'rendering';
|
|
150
|
+
},
|
|
151
|
+
registerCleanup (dispose) {
|
|
152
|
+
if (finishPromise) throw new Error('Cannot register cleanup after a renderer request terminates.');
|
|
153
|
+
disposers.add(dispose);
|
|
154
|
+
return ()=>{
|
|
155
|
+
disposers.delete(dispose);
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
markFallback () {
|
|
159
|
+
if (finishPromise) throw new Error('Cannot change fallback disposition after a renderer request terminates.');
|
|
160
|
+
fallback = true;
|
|
161
|
+
},
|
|
162
|
+
respond (body) {
|
|
163
|
+
if (responseCreated || committedPolicy || finishPromise) throw new Error('A renderer request has exactly one response body consumer.');
|
|
164
|
+
if (!policy || 'ready' !== state && 'rendering' !== state) throw new Error('Resolve the blocking HTTP outcome before committing a response.');
|
|
165
|
+
if (null !== body && [
|
|
166
|
+
204,
|
|
167
|
+
205,
|
|
168
|
+
304
|
|
169
|
+
].includes(policy.status)) throw new TypeError(`HTTP ${policy.status} cannot contain a renderer response body.`);
|
|
170
|
+
reader = body?.getReader();
|
|
171
|
+
hasDocumentBody = null !== body;
|
|
172
|
+
responseCreated = true;
|
|
173
|
+
committedPolicy = policy;
|
|
174
|
+
state = 'committed';
|
|
175
|
+
const headers = policyHeaders(committedPolicy.headers);
|
|
176
|
+
let wrappedBody = null;
|
|
177
|
+
if (reader) {
|
|
178
|
+
const sourceReader = reader;
|
|
179
|
+
wrappedBody = new ReadableStream({
|
|
180
|
+
start (controller) {
|
|
181
|
+
bodyController = controller;
|
|
182
|
+
},
|
|
183
|
+
async pull (controller) {
|
|
184
|
+
try {
|
|
185
|
+
const next = await sourceReader.read();
|
|
186
|
+
if (finishPromise) return;
|
|
187
|
+
if (!next.done) return void controller.enqueue(next.value);
|
|
188
|
+
sourceReader.releaseLock();
|
|
189
|
+
const result = await finish('completed');
|
|
190
|
+
if (result.cleanupErrors.length > 0) controller.error(new AggregateError(result.cleanupErrors, 'Renderer request cleanup failed.'));
|
|
191
|
+
else controller.close();
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (!finishPromise) {
|
|
194
|
+
await finish('failed', error);
|
|
195
|
+
controller.error(error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
cancel (reason) {
|
|
200
|
+
abort(reason);
|
|
201
|
+
return completion.then(()=>{});
|
|
202
|
+
}
|
|
203
|
+
}, {
|
|
204
|
+
highWaterMark: 0
|
|
205
|
+
});
|
|
206
|
+
} else finish('completed');
|
|
207
|
+
const response = new Response(wrappedBody, {
|
|
208
|
+
status: committedPolicy.status,
|
|
209
|
+
...void 0 === committedPolicy.statusText ? {} : {
|
|
210
|
+
statusText: committedPolicy.statusText
|
|
211
|
+
},
|
|
212
|
+
headers
|
|
213
|
+
});
|
|
214
|
+
deliveredResponse = response;
|
|
215
|
+
deliveredHeaders = response.headers;
|
|
216
|
+
return response;
|
|
217
|
+
},
|
|
218
|
+
ownsResponseBody (response) {
|
|
219
|
+
return void 0 !== deliveredResponse && (response === deliveredResponse || null !== deliveredResponse.body && response.body === deliveredResponse.body);
|
|
220
|
+
},
|
|
221
|
+
fail (error) {
|
|
222
|
+
finish('failed', error);
|
|
223
|
+
},
|
|
224
|
+
abort
|
|
225
|
+
};
|
|
226
|
+
if (input.request.signal.aborted) onRequestAbort();
|
|
227
|
+
else input.request.signal.addEventListener('abort', onRequestAbort, {
|
|
228
|
+
once: true
|
|
229
|
+
});
|
|
230
|
+
return session;
|
|
231
|
+
}
|
|
232
|
+
export { createRequestSession };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "node:module";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settle with the work, or reject once the signal aborts: work that ignores
|
|
3
|
+
* cancellation must not keep its caller alive. A late Response body is
|
|
4
|
+
* cancelled and a late failure observed.
|
|
5
|
+
*/
|
|
6
|
+
export declare function untilAborted<T>(handled: T | Promise<T>, signal: AbortSignal): Promise<T>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { RsbuildPlugin } from '@rsbuild/core';
|
|
2
|
+
import type { Renderer, RendererIdentity } from './identity.js';
|
|
3
|
+
/**
|
|
4
|
+
* Renderer adapters are build-side descriptors. A renderer package exports one
|
|
5
|
+
* from its `./plugin` entry; UltraModern loads only the selected adapter and
|
|
6
|
+
* drives native entries, compilation, artifacts, deployment and scaffolding
|
|
7
|
+
* from its data. Nothing here is imported by application runtime code.
|
|
8
|
+
*/
|
|
9
|
+
export interface RendererBuildProfile<TRenderer extends Renderer = Renderer> {
|
|
10
|
+
renderer: TRenderer;
|
|
11
|
+
status: 'stable' | 'preview';
|
|
12
|
+
protocolVersion: 1;
|
|
13
|
+
minimumNode: '26.10.0';
|
|
14
|
+
hmr: {
|
|
15
|
+
editedBoundary: 'may-reset';
|
|
16
|
+
unaffectedComponents: 'preserved';
|
|
17
|
+
document: 'preserved';
|
|
18
|
+
roots: 'single';
|
|
19
|
+
cleanup: 'exactly-once';
|
|
20
|
+
};
|
|
21
|
+
compiler: {
|
|
22
|
+
name: string;
|
|
23
|
+
version: string;
|
|
24
|
+
};
|
|
25
|
+
hydration: {
|
|
26
|
+
name: string;
|
|
27
|
+
version: string;
|
|
28
|
+
};
|
|
29
|
+
router: {
|
|
30
|
+
name: string;
|
|
31
|
+
version: string;
|
|
32
|
+
coreName: string;
|
|
33
|
+
coreVersion: string;
|
|
34
|
+
};
|
|
35
|
+
sourceExtensions: readonly string[];
|
|
36
|
+
jsxImportSource: string;
|
|
37
|
+
dependencies: Readonly<Record<string, string>>;
|
|
38
|
+
capabilities: {
|
|
39
|
+
worker: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* `true`: Module Federation with SSR. React federates through the React
|
|
42
|
+
* MF plugin; native renderers server-render same-renderer federated
|
|
43
|
+
* components from a native module-federation.config.
|
|
44
|
+
* `'client'`: native same-renderer federated components rendered on the
|
|
45
|
+
* client only.
|
|
46
|
+
*/
|
|
47
|
+
moduleFederation: boolean | 'client';
|
|
48
|
+
rsc: boolean;
|
|
49
|
+
ssg: boolean;
|
|
50
|
+
i18n: boolean;
|
|
51
|
+
svgComponent: boolean;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export interface NativeRendererCompilerOptions {
|
|
55
|
+
/** The selected native infrastructure owns these source-build identities. */
|
|
56
|
+
rendererIdentities(): Readonly<Record<string, RendererIdentity>>;
|
|
57
|
+
/** Rsbuild environment that renders server documents inside a web worker. */
|
|
58
|
+
readonly workerEnvironmentName: string;
|
|
59
|
+
}
|
|
60
|
+
export interface NativeCompilerArtifactContext {
|
|
61
|
+
/** Hash from the completed client compiler, when validating emitted output. */
|
|
62
|
+
readonly compilationHash?: string;
|
|
63
|
+
/** Hydration identity retained with a development snapshot. */
|
|
64
|
+
readonly hydrationBuildId?: string;
|
|
65
|
+
readonly development?: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface ValidatedNativeCompilerArtifact {
|
|
68
|
+
readonly nativeManifest: unknown;
|
|
69
|
+
/** Optional compiler-owned hydration and document cache identity. */
|
|
70
|
+
readonly hydrationBuildId?: string;
|
|
71
|
+
}
|
|
72
|
+
/** The selected compiler owns its artifact ABI; lifecycle consumers keep it opaque. */
|
|
73
|
+
export interface NativeCompilerArtifacts {
|
|
74
|
+
clientManifestFile(entryName: string): string;
|
|
75
|
+
validateClientManifest(value: unknown, identity: RendererIdentity, context: NativeCompilerArtifactContext): Promise<ValidatedNativeCompilerArtifact>;
|
|
76
|
+
isMutableDevelopmentAsset(filename: string, entryNames: readonly string[]): boolean;
|
|
77
|
+
}
|
|
78
|
+
/** Public modules the generated native entries and the host import. */
|
|
79
|
+
export interface NativeRendererRuntime {
|
|
80
|
+
/** The renderer's own reactive runtime package, e.g. `solid-js`. */
|
|
81
|
+
readonly package: string;
|
|
82
|
+
/** The renderer package that owns this adapter and its runtime modules. */
|
|
83
|
+
readonly bootstrap: string;
|
|
84
|
+
readonly entryClient: string;
|
|
85
|
+
readonly entryServer: string;
|
|
86
|
+
readonly router: string;
|
|
87
|
+
readonly i18n?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Exports the renderer's `compilerArtifacts`, which the production server
|
|
90
|
+
* loads to validate compiler module manifests; also proves the installed
|
|
91
|
+
* owner.
|
|
92
|
+
*/
|
|
93
|
+
readonly manifest: string;
|
|
94
|
+
}
|
|
95
|
+
export interface NativeRendererFederation {
|
|
96
|
+
/** Runtime singletons a host and every remote share (`pkg/` for subpaths). */
|
|
97
|
+
readonly shared: readonly string[];
|
|
98
|
+
/** Required providers, with the native import each compilation owns. */
|
|
99
|
+
readonly sharedByEnvironment?: Readonly<Record<'client' | 'server', Readonly<Record<string, string>>>>;
|
|
100
|
+
/** Browser container format, matching the renderer's client chunks. */
|
|
101
|
+
readonly library: 'module';
|
|
102
|
+
/** Whether federated components also render on the server. */
|
|
103
|
+
readonly ssr: boolean;
|
|
104
|
+
}
|
|
105
|
+
export interface RendererWorkerSupport {
|
|
106
|
+
/** Worker documents come from the renderer's native server handler. */
|
|
107
|
+
readonly nativeDocuments: boolean;
|
|
108
|
+
readonly rsc: boolean;
|
|
109
|
+
}
|
|
110
|
+
export interface NativeEntryClientStub {
|
|
111
|
+
/** Ambient declarations the generated client entry needs. */
|
|
112
|
+
readonly declarations: string;
|
|
113
|
+
/** Extra `startNativeClient` fields, as source expressions. */
|
|
114
|
+
readonly fields: Readonly<Record<string, string>>;
|
|
115
|
+
}
|
|
116
|
+
export interface RendererAppSourceOptions {
|
|
117
|
+
appId: string;
|
|
118
|
+
title: string;
|
|
119
|
+
entryName: string;
|
|
120
|
+
sourceExtension: '.tsx' | '.tsrx';
|
|
121
|
+
jsxImportSource: string;
|
|
122
|
+
capabilities: {
|
|
123
|
+
ssr: boolean;
|
|
124
|
+
federation: boolean;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export interface RendererAppSources {
|
|
128
|
+
sourceExtension: '.tsx' | '.tsrx';
|
|
129
|
+
jsxImportSource: string;
|
|
130
|
+
artifacts: {
|
|
131
|
+
path: string;
|
|
132
|
+
content: string;
|
|
133
|
+
}[];
|
|
134
|
+
}
|
|
135
|
+
export interface RendererCreatePackages {
|
|
136
|
+
/** Framework packages the generated application depends on directly. */
|
|
137
|
+
frameworkDependencies: readonly string[];
|
|
138
|
+
dependencies: Record<string, string>;
|
|
139
|
+
devDependencies: Record<string, string>;
|
|
140
|
+
typecheckCommand?: string;
|
|
141
|
+
tsconfig?: Record<string, unknown>;
|
|
142
|
+
}
|
|
143
|
+
export interface RendererCreateSupport {
|
|
144
|
+
/** Deployment templates the adapter admits in generated workspaces. */
|
|
145
|
+
readonly templates?: {
|
|
146
|
+
readonly federation: boolean;
|
|
147
|
+
readonly workers: boolean;
|
|
148
|
+
};
|
|
149
|
+
dependencies(profile: RendererBuildProfile, context: {
|
|
150
|
+
readonly typescriptVersion: string;
|
|
151
|
+
}): RendererCreatePackages;
|
|
152
|
+
generateAppSources(options: RendererAppSourceOptions): RendererAppSources;
|
|
153
|
+
}
|
|
154
|
+
interface RendererAdapterDescriptor<TRenderer extends Renderer> {
|
|
155
|
+
readonly name: TRenderer;
|
|
156
|
+
readonly profile: RendererBuildProfile<TRenderer>;
|
|
157
|
+
readonly routerFrameworks: readonly string[];
|
|
158
|
+
readonly worker: RendererWorkerSupport;
|
|
159
|
+
readonly create?: RendererCreateSupport;
|
|
160
|
+
}
|
|
161
|
+
export interface NativeRendererAdapter<TRenderer extends Renderer = Renderer> extends RendererAdapterDescriptor<TRenderer> {
|
|
162
|
+
readonly kind: 'native';
|
|
163
|
+
readonly runtime: NativeRendererRuntime;
|
|
164
|
+
readonly federation?: NativeRendererFederation;
|
|
165
|
+
readonly entryClient?: NativeEntryClientStub;
|
|
166
|
+
/**
|
|
167
|
+
* Who links the stylesheets of lazy components in a server document.
|
|
168
|
+
* `'renderer'`: the server render links each one beside the markup it
|
|
169
|
+
* renders. `'document'`: the render cannot report which lazy modules it
|
|
170
|
+
* rendered, so the document links every lazy stylesheet up front.
|
|
171
|
+
*/
|
|
172
|
+
readonly lazyStyles: 'renderer' | 'document';
|
|
173
|
+
/** Path of a CommonJS module exporting `(parts) => source` for `?component` SVGs. */
|
|
174
|
+
svgComponentTemplate?(): string;
|
|
175
|
+
/** The renderer compiler; UltraModern applies SVG and ownership policy. */
|
|
176
|
+
compiler(options: NativeRendererCompilerOptions): RsbuildPlugin;
|
|
177
|
+
readonly artifacts: NativeCompilerArtifacts;
|
|
178
|
+
assertSupportedSource?(source: string | false | undefined): Promise<void>;
|
|
179
|
+
}
|
|
180
|
+
/** A renderer composed from an existing plugin stack (React only). */
|
|
181
|
+
export interface ComposedRendererAdapter<TRenderer extends Renderer = Renderer, TPlugin = unknown, TPolicy = unknown> extends RendererAdapterDescriptor<TRenderer> {
|
|
182
|
+
readonly kind: 'composed';
|
|
183
|
+
/** Public modules whose installed owners pin the profile versions. */
|
|
184
|
+
readonly frameworkModules: readonly {
|
|
185
|
+
readonly specifier: string;
|
|
186
|
+
readonly request: string;
|
|
187
|
+
}[];
|
|
188
|
+
compose(consumerPlugins: readonly TPlugin[], policy?: TPolicy): TPlugin;
|
|
189
|
+
}
|
|
190
|
+
export type RendererAdapter<TRenderer extends Renderer = Renderer> = NativeRendererAdapter<TRenderer> | ComposedRendererAdapter<TRenderer>;
|
|
191
|
+
/** Validate an adapter's internal consistency and freeze its descriptor data. */
|
|
192
|
+
export declare function defineRendererAdapter<T extends RendererAdapter>(adapter: T): T;
|
|
193
|
+
/** Third-party runtime packages a generated native application installs. */
|
|
194
|
+
export declare function nativeRendererDependencies(profile: RendererBuildProfile): Record<string, string>;
|
|
195
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type RendererIdentity } from '../identity.js';
|
|
2
|
+
import { type DataOperation, type DecodedDataOutcome } from './types.js';
|
|
3
|
+
export declare function readDataResponse(response: Response, expected: {
|
|
4
|
+
identity: RendererIdentity;
|
|
5
|
+
routeId: string;
|
|
6
|
+
operation: DataOperation;
|
|
7
|
+
}, signal?: AbortSignal): Promise<DecodedDataOutcome>;
|
|
8
|
+
export declare function createDataClient(routeId: string, identity: RendererIdentity, options?: {
|
|
9
|
+
fetch?: typeof globalThis.fetch;
|
|
10
|
+
}): {
|
|
11
|
+
loader(input: {
|
|
12
|
+
request: Request;
|
|
13
|
+
}): Promise<DecodedDataOutcome>;
|
|
14
|
+
action(input: {
|
|
15
|
+
request: Request;
|
|
16
|
+
}): Promise<DecodedDataOutcome>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const DATA_CODEC: 'seroval-json@1.6.8';
|
|
2
|
+
export declare const MAX_DATA_BYTES: number;
|
|
3
|
+
export declare class DataProtocolError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
/** Only explicit loader/action results are public. Request context is not data. */
|
|
7
|
+
export declare function assertPublicData(value: unknown, options?: {
|
|
8
|
+
privateReferences?: WeakSet<object>;
|
|
9
|
+
}): void;
|
|
10
|
+
/** JSON text stays inert when it is placed in a script element. */
|
|
11
|
+
export declare function escapeInlineDataJSON(text: string): string;
|
|
12
|
+
/** JSON text. `serializeInlineData` escapes it when it goes into a document. */
|
|
13
|
+
export declare function serializePublicData(value: unknown): string;
|
|
14
|
+
export declare function parsePublicData(text: string): unknown;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './client.js';
|
|
2
|
+
export * from './codec.js';
|
|
3
|
+
export type { RequestDataPolicy } from './private.js';
|
|
4
|
+
export { createRequestDataPolicy } from './private.js';
|
|
5
|
+
export * from './routes.js';
|
|
6
|
+
export * from './server.js';
|
|
7
|
+
export * from './static.js';
|
|
8
|
+
export * from './types.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface RequestDataPolicy {
|
|
2
|
+
assertRoot(value: unknown): void;
|
|
3
|
+
assertValue(value: unknown): void;
|
|
4
|
+
}
|
|
5
|
+
/** Capture aliases before callbacks, and retain them as request context changes. */
|
|
6
|
+
export declare function createRequestDataPolicy(roots: readonly unknown[]): RequestDataPolicy;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Module references remain build-time strings; adapters import their own views. */
|
|
2
|
+
export interface RouteModuleReferences {
|
|
3
|
+
data?: string;
|
|
4
|
+
clientData?: string;
|
|
5
|
+
loading?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
search?: string;
|
|
8
|
+
head?: string;
|
|
9
|
+
notFound?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Filesystem structure only. Matching and scheduling belong to native routers. */
|
|
12
|
+
export interface FileSystemRouteIR {
|
|
13
|
+
id: string;
|
|
14
|
+
file?: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
index?: boolean;
|
|
17
|
+
isRoot?: boolean;
|
|
18
|
+
modules?: RouteModuleReferences;
|
|
19
|
+
children: FileSystemRouteIR[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Project the structural CLI route shape without retaining source objects,
|
|
23
|
+
* executable handlers, component values, or arbitrary configuration.
|
|
24
|
+
* Input order and conventional path syntax survive the projection unchanged.
|
|
25
|
+
*/
|
|
26
|
+
export declare function projectFileSystemRoutes(routes: unknown): FileSystemRouteIR[];
|
|
27
|
+
/** Convert conventional parameter spelling for TanStack without matching it. */
|
|
28
|
+
export declare function toTanstackPath(pathname: string): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type RendererIdentity } from '../identity.js';
|
|
2
|
+
import { responseHeaders as collectDataHeaders } from '../session/cache.js';
|
|
3
|
+
import type { ResponsePolicy } from '../session/types.js';
|
|
4
|
+
import { type DataHandler, type DataHandlerInput, type DataOperation, type DataOutcome, type DataResponseMetadata, type PublicDataError, type SelectedDataRoute } from './types.js';
|
|
5
|
+
export { collectDataHeaders };
|
|
6
|
+
declare const DEFERRED: unique symbol;
|
|
7
|
+
/**
|
|
8
|
+
* Combine header fields from two sources for one document: list fields
|
|
9
|
+
* (cookies, `Vary`, `Link`, `Server-Timing`, CSP) keep both sources' values,
|
|
10
|
+
* while a singleton field from `primary` replaces the `secondary` one.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mergeHeaderFields(primary: readonly (readonly [string, string])[], secondary: readonly (readonly [string, string])[]): [string, string][];
|
|
13
|
+
/**
|
|
14
|
+
* Opaque result of {@link deferData}. Exported so loaders returning it keep a
|
|
15
|
+
* nameable type under declaration emit (composite/declaration projects).
|
|
16
|
+
*/
|
|
17
|
+
export interface DeferredDataResult {
|
|
18
|
+
[DEFERRED]: true;
|
|
19
|
+
critical: Record<string, unknown>;
|
|
20
|
+
deferred: Record<string, Promise<unknown>>;
|
|
21
|
+
init?: ResponseInit;
|
|
22
|
+
}
|
|
23
|
+
export declare function deferData(critical: Record<string, unknown>, deferred: Record<string, Promise<unknown>>, init?: ResponseInit): DeferredDataResult;
|
|
24
|
+
/** The native router supplies status after resolving its own route outcomes. */
|
|
25
|
+
export declare function mergeDataResponseMetadata(outcomes: readonly DataOutcome[], nativeResponse: {
|
|
26
|
+
status: number;
|
|
27
|
+
statusText?: string;
|
|
28
|
+
}): DataResponseMetadata;
|
|
29
|
+
/** Loader representation headers cannot describe the native HTML document. */
|
|
30
|
+
export declare function dataMetadataToDocumentPolicy(metadata: DataResponseMetadata): ResponsePolicy;
|
|
31
|
+
/** Preserve a native terminal response while adding all matched loader cookies. */
|
|
32
|
+
export declare function mergeDataResponseIntoResponse(response: Response, metadata: DataResponseMetadata): Response;
|
|
33
|
+
export declare function publicDataError(error: unknown, production?: boolean): PublicDataError;
|
|
34
|
+
/** Resolve every status/redirect/header outcome before the document commits headers. */
|
|
35
|
+
export declare function normalizeDataResult(value: unknown, options?: {
|
|
36
|
+
thrown?: boolean;
|
|
37
|
+
production?: boolean;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
}): Promise<DataOutcome>;
|
|
40
|
+
export declare function invokeRouteData<Context>(handler: DataHandler<Context>, input: DataHandlerInput<Context>, options?: {
|
|
41
|
+
production?: boolean;
|
|
42
|
+
privateValues?: readonly unknown[];
|
|
43
|
+
}): Promise<DataOutcome>;
|
|
44
|
+
export declare function createDataResponse(outcome: DataOutcome, identity: RendererIdentity, options: {
|
|
45
|
+
routeId: string;
|
|
46
|
+
operation: DataOperation;
|
|
47
|
+
signal?: AbortSignal;
|
|
48
|
+
production?: boolean;
|
|
49
|
+
onCancel?: (reason: unknown) => void | Promise<void>;
|
|
50
|
+
}): Response;
|
|
51
|
+
export declare function handleDataRequest<Context>(options: {
|
|
52
|
+
request: Request;
|
|
53
|
+
identity: RendererIdentity;
|
|
54
|
+
context: Context;
|
|
55
|
+
selectRoute: (request: Request, requestedRouteId: string, operation: DataOperation) => SelectedDataRoute<Context> | undefined | Promise<SelectedDataRoute<Context> | undefined>;
|
|
56
|
+
production?: boolean;
|
|
57
|
+
/** Additional dispatcher-owned request identities, never public payload. */
|
|
58
|
+
privateValues?: readonly unknown[];
|
|
59
|
+
}): Promise<Response | undefined>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DATA_CONTENT_TYPE, DATA_STREAM_CONTENT_TYPE } from './types.js';
|
|
2
|
+
/** Head marker written into documents produced by static prerendering. */
|
|
3
|
+
export declare const PRERENDERED_DOCUMENT_META = "ultramodern-prerendered";
|
|
4
|
+
/** Directory beside a prerendered document that holds its loader payloads. */
|
|
5
|
+
export declare const STATIC_DATA_DIRECTORY = "__ultramodern-data";
|
|
6
|
+
/** A loader response captured at build time, replayed by the data client. */
|
|
7
|
+
export interface StaticDataPayload {
|
|
8
|
+
status: number;
|
|
9
|
+
contentType: typeof DATA_CONTENT_TYPE | typeof DATA_STREAM_CONTENT_TYPE;
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
/** URL path of one route's loader payload for a search-free document path. */
|
|
13
|
+
export declare function staticDataPayloadPath(pathname: string, routeId: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* The client reads a payload file whole before replaying it. One response
|
|
16
|
+
* wrapped as a JSON string can grow up to six times through escaping; a
|
|
17
|
+
* deferred stream's frames are bounded only one by one, so prerendering
|
|
18
|
+
* checks the whole file against the same limit.
|
|
19
|
+
*/
|
|
20
|
+
export declare const STATIC_DATA_PAYLOAD_MAX_BYTES: number;
|
|
21
|
+
/**
|
|
22
|
+
* Read a captured loader response with a running byte bound. Encoding only
|
|
23
|
+
* grows the body, so a body over the limit fails as soon as it crosses it,
|
|
24
|
+
* before an unbounded deferred stream is buffered.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readStaticDataPayloadBody(response: Response): Promise<string>;
|
|
27
|
+
/** The payload file's text, or an error when the client could not read it. */
|
|
28
|
+
export declare function encodeStaticDataPayload(payload: StaticDataPayload): string;
|
|
29
|
+
export declare function isStaticDataPayload(value: unknown): value is StaticDataPayload;
|
|
30
|
+
/** Whether the current browser document was emitted by static prerendering. */
|
|
31
|
+
export declare function isPrerenderedDocument(): boolean;
|