@fluojs/react 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/LICENSE +21 -0
- package/README.ko.md +715 -0
- package/README.md +729 -0
- package/dist/client/errors.d.ts +12 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +19 -0
- package/dist/client/hooks.d.ts +38 -0
- package/dist/client/hooks.d.ts.map +1 -0
- package/dist/client/hooks.js +56 -0
- package/dist/client/link.d.ts +13 -0
- package/dist/client/link.d.ts.map +1 -0
- package/dist/client/link.js +39 -0
- package/dist/client/provider.d.ts +12 -0
- package/dist/client/provider.d.ts.map +1 -0
- package/dist/client/provider.js +54 -0
- package/dist/client/search-params.d.ts +17 -0
- package/dist/client/search-params.d.ts.map +1 -0
- package/dist/client/search-params.js +39 -0
- package/dist/client/snapshot.d.ts +15 -0
- package/dist/client/snapshot.d.ts.map +1 -0
- package/dist/client/snapshot.js +57 -0
- package/dist/client/store.d.ts +26 -0
- package/dist/client/store.d.ts.map +1 -0
- package/dist/client/store.js +138 -0
- package/dist/client/types.d.ts +63 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +1 -0
- package/dist/client.d.ts +9 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +5 -0
- package/dist/decorators.d.ts +80 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +194 -0
- package/dist/experimental/rsc-diagnostics.d.ts +13 -0
- package/dist/experimental/rsc-diagnostics.d.ts.map +1 -0
- package/dist/experimental/rsc-diagnostics.js +58 -0
- package/dist/experimental/rsc-flight-response.d.ts +15 -0
- package/dist/experimental/rsc-flight-response.d.ts.map +1 -0
- package/dist/experimental/rsc-flight-response.js +76 -0
- package/dist/experimental/rsc-manifest.d.ts +13 -0
- package/dist/experimental/rsc-manifest.d.ts.map +1 -0
- package/dist/experimental/rsc-manifest.js +88 -0
- package/dist/experimental/rsc-types.d.ts +118 -0
- package/dist/experimental/rsc-types.d.ts.map +1 -0
- package/dist/experimental/rsc-types.js +50 -0
- package/dist/experimental/rsc.d.ts +11 -0
- package/dist/experimental/rsc.d.ts.map +1 -0
- package/dist/experimental/rsc.js +8 -0
- package/dist/experimental/server-functions-client.d.ts +14 -0
- package/dist/experimental/server-functions-client.d.ts.map +1 -0
- package/dist/experimental/server-functions-client.js +120 -0
- package/dist/experimental/server-functions-configuration.d.ts +17 -0
- package/dist/experimental/server-functions-configuration.d.ts.map +1 -0
- package/dist/experimental/server-functions-configuration.js +68 -0
- package/dist/experimental/server-functions-errors.d.ts +19 -0
- package/dist/experimental/server-functions-errors.d.ts.map +1 -0
- package/dist/experimental/server-functions-errors.js +22 -0
- package/dist/experimental/server-functions-reference.d.ts +22 -0
- package/dist/experimental/server-functions-reference.d.ts.map +1 -0
- package/dist/experimental/server-functions-reference.js +76 -0
- package/dist/experimental/server-functions-serialization.d.ts +37 -0
- package/dist/experimental/server-functions-serialization.d.ts.map +1 -0
- package/dist/experimental/server-functions-serialization.js +158 -0
- package/dist/experimental/server-functions-server.d.ts +14 -0
- package/dist/experimental/server-functions-server.d.ts.map +1 -0
- package/dist/experimental/server-functions-server.js +176 -0
- package/dist/experimental/server-functions-types.d.ts +86 -0
- package/dist/experimental/server-functions-types.d.ts.map +1 -0
- package/dist/experimental/server-functions-types.js +35 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/module.d.ts +40 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +58 -0
- package/dist/render-stream.d.ts +27 -0
- package/dist/render-stream.d.ts.map +1 -0
- package/dist/render-stream.js +135 -0
- package/dist/render.d.ts +50 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +201 -0
- package/dist/server-entry.d.ts +87 -0
- package/dist/server-entry.d.ts.map +1 -0
- package/dist/server-entry.js +126 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/vite/asset-utils.d.ts +57 -0
- package/dist/vite/asset-utils.d.ts.map +1 -0
- package/dist/vite/asset-utils.js +184 -0
- package/dist/vite/create-asset-manifest.d.ts +9 -0
- package/dist/vite/create-asset-manifest.d.ts.map +1 -0
- package/dist/vite/create-asset-manifest.js +127 -0
- package/dist/vite/diagnostics.d.ts +27 -0
- package/dist/vite/diagnostics.d.ts.map +1 -0
- package/dist/vite/diagnostics.js +47 -0
- package/dist/vite/parse-manifest.d.ts +18 -0
- package/dist/vite/parse-manifest.d.ts.map +1 -0
- package/dist/vite/parse-manifest.js +168 -0
- package/dist/vite/types.d.ts +187 -0
- package/dist/vite/types.d.ts.map +1 -0
- package/dist/vite/types.js +59 -0
- package/dist/vite.d.ts +3 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const blockedObjectKeys = new Set(['__proto__', 'constructor', 'prototype']);
|
|
2
|
+
|
|
3
|
+
/** Result of parsing an untrusted value into the Server Function serialization subset. */
|
|
4
|
+
|
|
5
|
+
function isPlainRecord(value) {
|
|
6
|
+
if (typeof value !== 'object' || value === null) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10
|
+
return prototype === Object.prototype || prototype === null;
|
|
11
|
+
}
|
|
12
|
+
function failure(path, reason) {
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
path,
|
|
16
|
+
reason
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function parseArray(value, context) {
|
|
20
|
+
if (context.ancestors.has(value)) {
|
|
21
|
+
return failure(context.path, 'Circular arrays are not serializable.');
|
|
22
|
+
}
|
|
23
|
+
context.ancestors.add(value);
|
|
24
|
+
const parsed = [];
|
|
25
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
26
|
+
if (!Object.hasOwn(value, index)) {
|
|
27
|
+
context.ancestors.delete(value);
|
|
28
|
+
return failure(`${context.path}[${String(index)}]`, 'Sparse arrays are not serializable.');
|
|
29
|
+
}
|
|
30
|
+
const item = value[index];
|
|
31
|
+
const result = parseValue(item, {
|
|
32
|
+
ancestors: context.ancestors,
|
|
33
|
+
depth: context.depth + 1,
|
|
34
|
+
maxDepth: context.maxDepth,
|
|
35
|
+
path: `${context.path}[${String(index)}]`
|
|
36
|
+
});
|
|
37
|
+
if (!result.ok) {
|
|
38
|
+
context.ancestors.delete(value);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
parsed.push(result.value);
|
|
42
|
+
}
|
|
43
|
+
context.ancestors.delete(value);
|
|
44
|
+
return {
|
|
45
|
+
ok: true,
|
|
46
|
+
value: Object.freeze(parsed)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function parseRecord(value, context) {
|
|
50
|
+
if (context.ancestors.has(value)) {
|
|
51
|
+
return failure(context.path, 'Circular objects are not serializable.');
|
|
52
|
+
}
|
|
53
|
+
if (Reflect.ownKeys(value).length !== Object.keys(value).length) {
|
|
54
|
+
return failure(context.path, 'Symbol and non-enumerable properties are not serializable.');
|
|
55
|
+
}
|
|
56
|
+
context.ancestors.add(value);
|
|
57
|
+
const parsed = {};
|
|
58
|
+
Object.setPrototypeOf(parsed, null);
|
|
59
|
+
for (const [key, item] of Object.entries(value)) {
|
|
60
|
+
if (blockedObjectKeys.has(key)) {
|
|
61
|
+
context.ancestors.delete(value);
|
|
62
|
+
return failure(`${context.path}.${key}`, 'Prototype-sensitive object keys are not allowed.');
|
|
63
|
+
}
|
|
64
|
+
const result = parseValue(item, {
|
|
65
|
+
ancestors: context.ancestors,
|
|
66
|
+
depth: context.depth + 1,
|
|
67
|
+
maxDepth: context.maxDepth,
|
|
68
|
+
path: `${context.path}.${key}`
|
|
69
|
+
});
|
|
70
|
+
if (!result.ok) {
|
|
71
|
+
context.ancestors.delete(value);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
parsed[key] = result.value;
|
|
75
|
+
}
|
|
76
|
+
context.ancestors.delete(value);
|
|
77
|
+
return {
|
|
78
|
+
ok: true,
|
|
79
|
+
value: Object.freeze(parsed)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function parseValue(value, context) {
|
|
83
|
+
if (context.depth > context.maxDepth) {
|
|
84
|
+
return failure(context.path, `Serialization depth exceeds ${String(context.maxDepth)}.`);
|
|
85
|
+
}
|
|
86
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean') {
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
value
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (typeof value === 'number') {
|
|
93
|
+
return Number.isFinite(value) ? {
|
|
94
|
+
ok: true,
|
|
95
|
+
value
|
|
96
|
+
} : failure(context.path, 'Only finite numbers are serializable.');
|
|
97
|
+
}
|
|
98
|
+
if (Array.isArray(value)) {
|
|
99
|
+
return parseArray(value, context);
|
|
100
|
+
}
|
|
101
|
+
if (isPlainRecord(value)) {
|
|
102
|
+
return parseRecord(value, context);
|
|
103
|
+
}
|
|
104
|
+
return failure(context.path, 'Only JSON-compatible primitives, arrays, and plain objects are serializable.');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Parses an untrusted argument list into an immutable JSON-compatible snapshot.
|
|
109
|
+
*
|
|
110
|
+
* @param value Unknown request argument value.
|
|
111
|
+
* @param maxDepth Maximum supported nesting depth.
|
|
112
|
+
* @returns A parsed argument list or a deterministic path and reason.
|
|
113
|
+
*/
|
|
114
|
+
export function parseReactServerFunctionArguments(value, maxDepth) {
|
|
115
|
+
if (!Array.isArray(value)) {
|
|
116
|
+
return failure('args', 'Server Function arguments must be an array.');
|
|
117
|
+
}
|
|
118
|
+
const parsed = parseArray(value, {
|
|
119
|
+
ancestors: new Set(),
|
|
120
|
+
depth: 0,
|
|
121
|
+
maxDepth,
|
|
122
|
+
path: 'args'
|
|
123
|
+
});
|
|
124
|
+
if (!parsed.ok) {
|
|
125
|
+
return parsed;
|
|
126
|
+
}
|
|
127
|
+
return Array.isArray(parsed.value) ? {
|
|
128
|
+
ok: true,
|
|
129
|
+
value: parsed.value
|
|
130
|
+
} : failure('args', 'Server Function arguments must be an array.');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Parses one untrusted action result into an immutable JSON-compatible snapshot.
|
|
135
|
+
*
|
|
136
|
+
* @param value Unknown action result.
|
|
137
|
+
* @param maxDepth Maximum supported nesting depth.
|
|
138
|
+
* @returns A parsed result or a deterministic path and reason.
|
|
139
|
+
*/
|
|
140
|
+
export function parseReactServerFunctionValue(value, maxDepth) {
|
|
141
|
+
return parseValue(value, {
|
|
142
|
+
ancestors: new Set(),
|
|
143
|
+
depth: 0,
|
|
144
|
+
maxDepth,
|
|
145
|
+
path: 'result'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Measures the UTF-8 JSON representation of an already parsed Server Function value.
|
|
151
|
+
*
|
|
152
|
+
* @param value JSON-compatible value produced by this module.
|
|
153
|
+
* @returns Encoded byte length.
|
|
154
|
+
*/
|
|
155
|
+
export function measureReactServerFunctionValue(value) {
|
|
156
|
+
const serialized = JSON.stringify(value);
|
|
157
|
+
return serialized === undefined ? 0 : new TextEncoder().encode(serialized).byteLength;
|
|
158
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReactServerFunctionRegistry, type ReactServerFunctionRegistryOptions } from './server-functions-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an experimental signed Server Function registry for an application-owned fluo POST route.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* The returned registry does not register a router. Mount `invoke(context)` in an ordinary
|
|
7
|
+
* `@Controller(...)` and `@Post(...)` method so fluo middleware, guards, interceptors, request
|
|
8
|
+
* scopes, observers, and error serialization remain authoritative.
|
|
9
|
+
*
|
|
10
|
+
* @param options Explicit actions, allowed origins, Web Crypto provider, HMAC secret, and limits.
|
|
11
|
+
* @returns A registry that issues signed references and invokes validated action calls.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createReactServerFunctionRegistry(options: ReactServerFunctionRegistryOptions): ReactServerFunctionRegistry;
|
|
14
|
+
//# sourceMappingURL=server-functions-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-functions-server.d.ts","sourceRoot":"","sources":["../../src/experimental/server-functions-server.ts"],"names":[],"mappings":"AAaA,OAAO,EAGL,KAAK,2BAA2B,EAChC,KAAK,kCAAkC,EACxC,MAAM,6BAA6B,CAAC;AAwGrC;;;;;;;;;;GAUG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,kCAAkC,GAC1C,2BAA2B,CA4D7B"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { HttpException } from '@fluojs/http';
|
|
2
|
+
import { createReactServerFunctionRegistryConfiguration } from './server-functions-configuration.js';
|
|
3
|
+
import { ReactServerFunctionConfigurationError } from './server-functions-errors.js';
|
|
4
|
+
import { createReactServerFunctionReferenceSigner } from './server-functions-reference.js';
|
|
5
|
+
import { measureReactServerFunctionValue, parseReactServerFunctionArguments, parseReactServerFunctionValue } from './server-functions-serialization.js';
|
|
6
|
+
import { REACT_SERVER_FUNCTION_ERROR_CODES, REACT_SERVER_FUNCTION_REQUEST_HEADER } from './server-functions-types.js';
|
|
7
|
+
function getHeader(context, name) {
|
|
8
|
+
const target = name.toLowerCase();
|
|
9
|
+
for (const [headerName, value] of Object.entries(context.request.headers)) {
|
|
10
|
+
if (headerName.toLowerCase() === target && typeof value === 'string') {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
function transportError(options) {
|
|
17
|
+
return new HttpException(options.status, options.message, {
|
|
18
|
+
code: options.code,
|
|
19
|
+
...(options.meta === undefined ? {} : {
|
|
20
|
+
meta: options.meta
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function measureRequestBody(context) {
|
|
25
|
+
if (context.request.rawBody !== undefined) {
|
|
26
|
+
return context.request.rawBody.byteLength;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const serialized = JSON.stringify(context.request.body);
|
|
30
|
+
return serialized === undefined ? undefined : new TextEncoder().encode(serialized).byteLength;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (error instanceof Error) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function validateTransport(context, configuration) {
|
|
39
|
+
const bodySize = measureRequestBody(context);
|
|
40
|
+
if (bodySize !== undefined && bodySize > configuration.maxBodyBytes) {
|
|
41
|
+
throw transportError({
|
|
42
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.payloadTooLarge,
|
|
43
|
+
message: 'Server Function request body exceeds the configured byte limit.',
|
|
44
|
+
meta: {
|
|
45
|
+
maxBodyBytes: configuration.maxBodyBytes
|
|
46
|
+
},
|
|
47
|
+
status: 413
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const contentType = getHeader(context, 'content-type')?.split(';', 1)[0]?.trim().toLowerCase();
|
|
51
|
+
if (contentType !== 'application/json') {
|
|
52
|
+
throw transportError({
|
|
53
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.unsupportedMediaType,
|
|
54
|
+
message: 'Server Function requests require Content-Type application/json.',
|
|
55
|
+
status: 415
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (getHeader(context, REACT_SERVER_FUNCTION_REQUEST_HEADER) !== '1') {
|
|
59
|
+
throw transportError({
|
|
60
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.csrfRejected,
|
|
61
|
+
message: 'Server Function request marker is missing or invalid.',
|
|
62
|
+
status: 403
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const origin = getHeader(context, 'origin');
|
|
66
|
+
if (origin === undefined || !configuration.allowedOrigins.has(origin)) {
|
|
67
|
+
throw transportError({
|
|
68
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.originRejected,
|
|
69
|
+
message: 'Server Function request origin is not allowed.',
|
|
70
|
+
status: 403
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function isRequestRecord(value) {
|
|
75
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const prototype = Object.getPrototypeOf(value);
|
|
79
|
+
return prototype === Object.prototype || prototype === null;
|
|
80
|
+
}
|
|
81
|
+
function parseRequestBody(body) {
|
|
82
|
+
if (!isRequestRecord(body)) {
|
|
83
|
+
throw transportError({
|
|
84
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.invalidRequest,
|
|
85
|
+
message: 'Server Function request body must be a JSON object.',
|
|
86
|
+
status: 400
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const keys = Object.keys(body).sort();
|
|
90
|
+
if (keys.length !== 2 || keys[0] !== 'action' || keys[1] !== 'args' || typeof body.action !== 'string') {
|
|
91
|
+
throw transportError({
|
|
92
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.invalidRequest,
|
|
93
|
+
message: 'Server Function request body must contain only string action and array args fields.',
|
|
94
|
+
status: 400
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
action: body.action,
|
|
99
|
+
args: body.args
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates an experimental signed Server Function registry for an application-owned fluo POST route.
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* The returned registry does not register a router. Mount `invoke(context)` in an ordinary
|
|
108
|
+
* `@Controller(...)` and `@Post(...)` method so fluo middleware, guards, interceptors, request
|
|
109
|
+
* scopes, observers, and error serialization remain authoritative.
|
|
110
|
+
*
|
|
111
|
+
* @param options Explicit actions, allowed origins, Web Crypto provider, HMAC secret, and limits.
|
|
112
|
+
* @returns A registry that issues signed references and invokes validated action calls.
|
|
113
|
+
*/
|
|
114
|
+
export function createReactServerFunctionRegistry(options) {
|
|
115
|
+
const configuration = createReactServerFunctionRegistryConfiguration(options);
|
|
116
|
+
const signer = createReactServerFunctionReferenceSigner(options.crypto, options.secret);
|
|
117
|
+
return Object.freeze({
|
|
118
|
+
async createReference(actionId) {
|
|
119
|
+
if (!Object.hasOwn(configuration.actions, actionId)) {
|
|
120
|
+
throw new ReactServerFunctionConfigurationError(`Cannot create a Server Function reference for unknown action "${actionId}".`);
|
|
121
|
+
}
|
|
122
|
+
return signer.createReference(actionId);
|
|
123
|
+
},
|
|
124
|
+
async invoke(context) {
|
|
125
|
+
validateTransport(context, configuration);
|
|
126
|
+
const request = parseRequestBody(context.request.body);
|
|
127
|
+
const actionId = await signer.verifyReference(request.action);
|
|
128
|
+
const handler = actionId === undefined ? undefined : configuration.actions[actionId];
|
|
129
|
+
if (handler === undefined) {
|
|
130
|
+
throw transportError({
|
|
131
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.actionNotFound,
|
|
132
|
+
message: 'Server Function action was not found.',
|
|
133
|
+
status: 404
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const args = parseReactServerFunctionArguments(request.args, configuration.maxSerializationDepth);
|
|
137
|
+
if (!args.ok) {
|
|
138
|
+
throw transportError({
|
|
139
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.argumentSerializationFailed,
|
|
140
|
+
message: 'Server Function arguments are not safely serializable.',
|
|
141
|
+
meta: {
|
|
142
|
+
path: args.path,
|
|
143
|
+
reason: args.reason
|
|
144
|
+
},
|
|
145
|
+
status: 400
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const result = parseReactServerFunctionValue(await handler(args.value, context), configuration.maxSerializationDepth);
|
|
149
|
+
if (!result.ok) {
|
|
150
|
+
throw transportError({
|
|
151
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.resultSerializationFailed,
|
|
152
|
+
message: 'Server Function result is not safely serializable.',
|
|
153
|
+
meta: {
|
|
154
|
+
path: result.path,
|
|
155
|
+
reason: result.reason
|
|
156
|
+
},
|
|
157
|
+
status: 500
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const resultBytes = measureReactServerFunctionValue(result.value);
|
|
161
|
+
if (resultBytes > configuration.maxResultBytes) {
|
|
162
|
+
throw transportError({
|
|
163
|
+
code: REACT_SERVER_FUNCTION_ERROR_CODES.resultTooLarge,
|
|
164
|
+
message: 'Server Function result exceeds the configured byte limit.',
|
|
165
|
+
meta: {
|
|
166
|
+
maxResultBytes: configuration.maxResultBytes
|
|
167
|
+
},
|
|
168
|
+
status: 500
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
result: result.value
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { MaybePromise } from '@fluojs/core';
|
|
2
|
+
import type { RequestContext } from '@fluojs/http';
|
|
3
|
+
/** Header required on experimental Server Function POST requests to force a non-simple request. */
|
|
4
|
+
export declare const REACT_SERVER_FUNCTION_REQUEST_HEADER = "x-fluo-react-action";
|
|
5
|
+
/** Stable error codes emitted by the experimental Server Function transport boundary. */
|
|
6
|
+
export declare const REACT_SERVER_FUNCTION_ERROR_CODES: {
|
|
7
|
+
readonly actionNotFound: "REACT_SERVER_FUNCTION_ACTION_NOT_FOUND";
|
|
8
|
+
readonly argumentSerializationFailed: "REACT_SERVER_FUNCTION_ARGUMENT_SERIALIZATION_FAILED";
|
|
9
|
+
readonly csrfRejected: "REACT_SERVER_FUNCTION_CSRF_REJECTED";
|
|
10
|
+
readonly invalidRequest: "REACT_SERVER_FUNCTION_INVALID_REQUEST";
|
|
11
|
+
readonly originRejected: "REACT_SERVER_FUNCTION_ORIGIN_REJECTED";
|
|
12
|
+
readonly payloadTooLarge: "REACT_SERVER_FUNCTION_PAYLOAD_TOO_LARGE";
|
|
13
|
+
readonly resultSerializationFailed: "REACT_SERVER_FUNCTION_RESULT_SERIALIZATION_FAILED";
|
|
14
|
+
readonly resultTooLarge: "REACT_SERVER_FUNCTION_RESULT_TOO_LARGE";
|
|
15
|
+
readonly unsupportedMediaType: "REACT_SERVER_FUNCTION_UNSUPPORTED_MEDIA_TYPE";
|
|
16
|
+
};
|
|
17
|
+
/** Machine-readable code emitted by the experimental Server Function transport. */
|
|
18
|
+
export type ReactServerFunctionErrorCode = (typeof REACT_SERVER_FUNCTION_ERROR_CODES)[keyof typeof REACT_SERVER_FUNCTION_ERROR_CODES];
|
|
19
|
+
/** JSON-compatible value accepted as a Server Function argument or result. */
|
|
20
|
+
export type ReactServerFunctionValue = null | boolean | number | string | readonly ReactServerFunctionValue[] | {
|
|
21
|
+
readonly [key: string]: ReactServerFunctionValue;
|
|
22
|
+
};
|
|
23
|
+
/** Opaque, integrity-protected reference sent to a Server Function client. */
|
|
24
|
+
export type ReactServerFunctionReference = {
|
|
25
|
+
/** Versioned signed reference value included in the action request body. */
|
|
26
|
+
readonly value: string;
|
|
27
|
+
};
|
|
28
|
+
/** Server-side action executed after transport and identity validation. */
|
|
29
|
+
export type ReactServerFunctionHandler = (args: readonly ReactServerFunctionValue[], context: RequestContext) => MaybePromise<ReactServerFunctionValue>;
|
|
30
|
+
/** Options for creating an integrity-protected Server Function registry. */
|
|
31
|
+
export type ReactServerFunctionRegistryOptions = {
|
|
32
|
+
/** Stable action ids mapped to server-only handlers. */
|
|
33
|
+
readonly actions: Readonly<Record<string, ReactServerFunctionHandler>>;
|
|
34
|
+
/** Exact HTTP(S) origins allowed to invoke the action endpoint. */
|
|
35
|
+
readonly allowedOrigins: readonly string[];
|
|
36
|
+
/** Runtime Web Crypto provider used for HMAC-SHA-256 reference integrity. */
|
|
37
|
+
readonly crypto: Pick<Crypto, 'subtle'>;
|
|
38
|
+
/** Maximum accepted request body size in bytes. Defaults to 64 KiB. */
|
|
39
|
+
readonly maxBodyBytes?: number;
|
|
40
|
+
/** Maximum serialized action result size in bytes. Defaults to 1 MiB. */
|
|
41
|
+
readonly maxResultBytes?: number;
|
|
42
|
+
/** Maximum nested argument or result depth. Defaults to 32. */
|
|
43
|
+
readonly maxSerializationDepth?: number;
|
|
44
|
+
/** Application-owned HMAC secret containing at least 32 bytes. */
|
|
45
|
+
readonly secret: Uint8Array;
|
|
46
|
+
};
|
|
47
|
+
/** Successful value returned from a Server Function endpoint handler. */
|
|
48
|
+
export type ReactServerFunctionResponse = {
|
|
49
|
+
/** Validated JSON-compatible action result. */
|
|
50
|
+
readonly result: ReactServerFunctionValue;
|
|
51
|
+
};
|
|
52
|
+
/** Registry mounted by an application-owned ordinary fluo HTTP POST controller. */
|
|
53
|
+
export type ReactServerFunctionRegistry = {
|
|
54
|
+
/**
|
|
55
|
+
* Creates an integrity-protected client reference for one registered action.
|
|
56
|
+
*
|
|
57
|
+
* @param actionId Stable registered action id.
|
|
58
|
+
* @returns An opaque reference suitable for client transport.
|
|
59
|
+
*/
|
|
60
|
+
readonly createReference: (actionId: string) => Promise<ReactServerFunctionReference>;
|
|
61
|
+
/**
|
|
62
|
+
* Validates and invokes one action from the active fluo request context.
|
|
63
|
+
*
|
|
64
|
+
* @param context Existing request context supplied to an ordinary HTTP controller method.
|
|
65
|
+
* @returns A JSON-compatible action response for normal dispatcher serialization.
|
|
66
|
+
*/
|
|
67
|
+
readonly invoke: (context: RequestContext) => Promise<ReactServerFunctionResponse>;
|
|
68
|
+
};
|
|
69
|
+
/** Minimal application-owned fetch seam used by the experimental client callable. */
|
|
70
|
+
export type ReactServerFunctionFetch = (input: string, init: RequestInit) => Promise<Response>;
|
|
71
|
+
/** Options for creating one client-side callable Server Function reference. */
|
|
72
|
+
export type ReactServerFunctionClientOptions = {
|
|
73
|
+
/** Explicit fluo HTTP endpoint that owns Server Function POST dispatch. */
|
|
74
|
+
readonly endpoint: string;
|
|
75
|
+
/** Application-owned fetch implementation used to perform the HTTP request. */
|
|
76
|
+
readonly fetch: ReactServerFunctionFetch;
|
|
77
|
+
/** Maximum accepted response body size in bytes. Defaults to 1 MiB. */
|
|
78
|
+
readonly maxResponseBytes?: number;
|
|
79
|
+
/** Maximum nested argument or result depth. Defaults to 32. */
|
|
80
|
+
readonly maxSerializationDepth?: number;
|
|
81
|
+
/** Signed reference issued by the matching server registry. */
|
|
82
|
+
readonly reference: ReactServerFunctionReference;
|
|
83
|
+
};
|
|
84
|
+
/** Callable client proxy that transports serializable arguments to one explicit action endpoint. */
|
|
85
|
+
export type ReactServerFunctionClient = (...args: readonly ReactServerFunctionValue[]) => Promise<ReactServerFunctionValue>;
|
|
86
|
+
//# sourceMappingURL=server-functions-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-functions-types.d.ts","sourceRoot":"","sources":["../../src/experimental/server-functions-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Header required on experimental Server Function POST requests to force a non-simple request. */
|
|
2
|
+
export const REACT_SERVER_FUNCTION_REQUEST_HEADER = 'x-fluo-react-action';
|
|
3
|
+
|
|
4
|
+
/** Stable error codes emitted by the experimental Server Function transport boundary. */
|
|
5
|
+
export const REACT_SERVER_FUNCTION_ERROR_CODES = {
|
|
6
|
+
actionNotFound: 'REACT_SERVER_FUNCTION_ACTION_NOT_FOUND',
|
|
7
|
+
argumentSerializationFailed: 'REACT_SERVER_FUNCTION_ARGUMENT_SERIALIZATION_FAILED',
|
|
8
|
+
csrfRejected: 'REACT_SERVER_FUNCTION_CSRF_REJECTED',
|
|
9
|
+
invalidRequest: 'REACT_SERVER_FUNCTION_INVALID_REQUEST',
|
|
10
|
+
originRejected: 'REACT_SERVER_FUNCTION_ORIGIN_REJECTED',
|
|
11
|
+
payloadTooLarge: 'REACT_SERVER_FUNCTION_PAYLOAD_TOO_LARGE',
|
|
12
|
+
resultSerializationFailed: 'REACT_SERVER_FUNCTION_RESULT_SERIALIZATION_FAILED',
|
|
13
|
+
resultTooLarge: 'REACT_SERVER_FUNCTION_RESULT_TOO_LARGE',
|
|
14
|
+
unsupportedMediaType: 'REACT_SERVER_FUNCTION_UNSUPPORTED_MEDIA_TYPE'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Machine-readable code emitted by the experimental Server Function transport. */
|
|
18
|
+
|
|
19
|
+
/** JSON-compatible value accepted as a Server Function argument or result. */
|
|
20
|
+
|
|
21
|
+
/** Opaque, integrity-protected reference sent to a Server Function client. */
|
|
22
|
+
|
|
23
|
+
/** Server-side action executed after transport and identity validation. */
|
|
24
|
+
|
|
25
|
+
/** Options for creating an integrity-protected Server Function registry. */
|
|
26
|
+
|
|
27
|
+
/** Successful value returned from a Server Function endpoint handler. */
|
|
28
|
+
|
|
29
|
+
/** Registry mounted by an application-owned ordinary fluo HTTP POST controller. */
|
|
30
|
+
|
|
31
|
+
/** Minimal application-owned fetch seam used by the experimental client callable. */
|
|
32
|
+
|
|
33
|
+
/** Options for creating one client-side callable Server Function reference. */
|
|
34
|
+
|
|
35
|
+
/** Callable client proxy that transports serializable arguments to one explicit action endpoint. */
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Path, Router, getReactPathMetadata, getReactRouterMetadata, } from './decorators.js';
|
|
2
|
+
export type { ReactPathMetadata, ReactPathOptions, ReactRouterMetadata } from './decorators.js';
|
|
3
|
+
export { ReactModule } from './module.js';
|
|
4
|
+
export type { ReactModuleOptions } from './module.js';
|
|
5
|
+
export { renderReactResponse } from './render.js';
|
|
6
|
+
export type { ReactReadableStream, ReactReadableStreamRenderOptions, ReactReadableStreamRenderer, ReactRenderContext, RenderReactResponseOptions, } from './render.js';
|
|
7
|
+
export { createReactServerEntry } from './server-entry.js';
|
|
8
|
+
export type { ReactAssetMap, ReactBootstrapAsset, ReactBootstrapScriptDescriptor, ReactRecoverableErrorContext, ReactRecoverableErrorHandler, ReactServerEntry, ReactServerEntryHeaders, ReactServerEntryOptions, } from './server-entry.js';
|
|
9
|
+
export type { ReactScaffoldPhase } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EACV,mBAAmB,EACnB,gCAAgC,EAChC,2BAA2B,EAC3B,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Constructor, type Token } from '@fluojs/core';
|
|
2
|
+
import type { Provider } from '@fluojs/di';
|
|
3
|
+
import type { MiddlewareLike } from '@fluojs/http';
|
|
4
|
+
import { type ModuleType } from '@fluojs/runtime';
|
|
5
|
+
/**
|
|
6
|
+
* Options for registering React routers through the fluo module graph.
|
|
7
|
+
*/
|
|
8
|
+
export type ReactModuleOptions = {
|
|
9
|
+
/** React router or HTTP controller classes added to the existing HTTP handler source path. */
|
|
10
|
+
readonly controllers: readonly Constructor[];
|
|
11
|
+
/** Provider tokens exported from this dynamic React module. */
|
|
12
|
+
readonly exports?: readonly Token[];
|
|
13
|
+
/** Modules whose exported providers are visible to the registered React routers. */
|
|
14
|
+
readonly imports?: readonly ModuleType[];
|
|
15
|
+
/** Module-level middleware applied by the existing HTTP dispatcher to this module's routes. */
|
|
16
|
+
readonly middleware?: readonly MiddlewareLike[];
|
|
17
|
+
/** Providers local to this dynamic React module and visible to registered routers. */
|
|
18
|
+
readonly providers?: readonly Provider[];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Runtime-neutral module facade for registering React routers in fluo applications.
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* `ReactModule.forRoot(...)` registers React routers through the same module/controller
|
|
25
|
+
* metadata consumed by `@fluojs/runtime` and `@fluojs/http`. It does not install a
|
|
26
|
+
* React-owned matcher, renderer, Vite integration, React Server Components hooks, or
|
|
27
|
+
* server functions. The stable root package owns runtime-neutral SSR contracts; future
|
|
28
|
+
* `@fluojs/react/vite`, `@fluojs/react/client`, and `@fluojs/react/experimental/rsc`
|
|
29
|
+
* subpaths own build assets, browser navigation, and RSC/server-function experiments.
|
|
30
|
+
*/
|
|
31
|
+
export declare class ReactModule {
|
|
32
|
+
/**
|
|
33
|
+
* Registers React routers and companion module metadata through the existing HTTP path.
|
|
34
|
+
*
|
|
35
|
+
* @param options React router controllers plus ordinary module imports, providers, exports, and middleware.
|
|
36
|
+
* @returns A runtime module type suitable for `@Module({ imports: [...] })`.
|
|
37
|
+
*/
|
|
38
|
+
static forRoot(options: ReactModuleOptions): ModuleType;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEvF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,8FAA8F;IAC9F,QAAQ,CAAC,WAAW,EAAE,SAAS,WAAW,EAAE,CAAC;IAC7C,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,KAAK,EAAE,CAAC;IACpC,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAChD,sFAAsF;IACtF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC1C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBACa,WAAW;IACtB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU;CAaxD"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
let _initClass;
|
|
2
|
+
function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
|
|
3
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
|
+
function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
|
|
6
|
+
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
7
|
+
import { Module } from '@fluojs/core';
|
|
8
|
+
import { defineModule } from '@fluojs/runtime';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Options for registering React routers through the fluo module graph.
|
|
12
|
+
*/
|
|
13
|
+
let _ReactModule;
|
|
14
|
+
/**
|
|
15
|
+
* Runtime-neutral module facade for registering React routers in fluo applications.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* `ReactModule.forRoot(...)` registers React routers through the same module/controller
|
|
19
|
+
* metadata consumed by `@fluojs/runtime` and `@fluojs/http`. It does not install a
|
|
20
|
+
* React-owned matcher, renderer, Vite integration, React Server Components hooks, or
|
|
21
|
+
* server functions. The stable root package owns runtime-neutral SSR contracts; future
|
|
22
|
+
* `@fluojs/react/vite`, `@fluojs/react/client`, and `@fluojs/react/experimental/rsc`
|
|
23
|
+
* subpaths own build assets, browser navigation, and RSC/server-function experiments.
|
|
24
|
+
*/
|
|
25
|
+
class ReactModule {
|
|
26
|
+
static {
|
|
27
|
+
[_ReactModule, _initClass] = _applyDecs(this, [Module({})], []).c;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Registers React routers and companion module metadata through the existing HTTP path.
|
|
31
|
+
*
|
|
32
|
+
* @param options React router controllers plus ordinary module imports, providers, exports, and middleware.
|
|
33
|
+
* @returns A runtime module type suitable for `@Module({ imports: [...] })`.
|
|
34
|
+
*/
|
|
35
|
+
static forRoot(options) {
|
|
36
|
+
class ReactRootModule extends _ReactModule {}
|
|
37
|
+
const definition = {
|
|
38
|
+
controllers: [...options.controllers],
|
|
39
|
+
...(options.exports ? {
|
|
40
|
+
exports: [...options.exports]
|
|
41
|
+
} : {}),
|
|
42
|
+
...(options.imports ? {
|
|
43
|
+
imports: [...options.imports]
|
|
44
|
+
} : {}),
|
|
45
|
+
...(options.middleware ? {
|
|
46
|
+
middleware: [...options.middleware]
|
|
47
|
+
} : {}),
|
|
48
|
+
...(options.providers ? {
|
|
49
|
+
providers: [...options.providers]
|
|
50
|
+
} : {})
|
|
51
|
+
};
|
|
52
|
+
return defineModule(ReactRootModule, definition);
|
|
53
|
+
}
|
|
54
|
+
static {
|
|
55
|
+
_initClass();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export { _ReactModule as ReactModule };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type FrameworkRequest, type FrameworkResponseStream } from '@fluojs/http';
|
|
2
|
+
/** Minimal request abort surface used while React Web Streams are read. */
|
|
3
|
+
export type ReactAbortSource = Pick<FrameworkRequest, 'isAborted' | 'signal'>;
|
|
4
|
+
/**
|
|
5
|
+
* Throws when a request has been aborted through either supported HTTP abort surface.
|
|
6
|
+
*
|
|
7
|
+
* @param source Request abort source exposed by the active fluo request.
|
|
8
|
+
*/
|
|
9
|
+
export declare function throwIfReactRequestAborted(source: ReactAbortSource): void;
|
|
10
|
+
/**
|
|
11
|
+
* Collects a React HTML stream for buffered hosts without committing partial bodies after abort.
|
|
12
|
+
*
|
|
13
|
+
* @param stream React Web Stream to collect.
|
|
14
|
+
* @param abortSource Request abort source checked before buffered response metadata is applied.
|
|
15
|
+
* @returns Fully collected HTML bytes.
|
|
16
|
+
*/
|
|
17
|
+
export declare function collectReadableStream(stream: ReadableStream<Uint8Array>, abortSource: ReactAbortSource): Promise<Uint8Array>;
|
|
18
|
+
/**
|
|
19
|
+
* Pipes a React HTML stream into an already committed streaming response until close or abort.
|
|
20
|
+
*
|
|
21
|
+
* @param stream React Web Stream to pipe.
|
|
22
|
+
* @param target Response stream that receives HTML chunks.
|
|
23
|
+
* @param abortSource Request abort source checked between chunks.
|
|
24
|
+
* @returns A promise that resolves when piping stops and the target is closed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function pipeReadableStream(stream: ReadableStream<Uint8Array>, target: FrameworkResponseStream, abortSource: ReactAbortSource): Promise<void>;
|
|
27
|
+
//# sourceMappingURL=render-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-stream.d.ts","sourceRoot":"","sources":["../src/render-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAOxG,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;AA+B9E;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAIzE;AAyBD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,WAAW,EAAE,gBAAgB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAuCrB;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,EAAE,uBAAuB,EAC/B,WAAW,EAAE,gBAAgB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAgCf"}
|