@tanstack/router-core 1.132.21 → 1.132.26
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/cjs/router.cjs +5 -1
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.cjs +3 -1
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/transformer.cjs +7 -3
- package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/transformer.d.cts +15 -14
- package/dist/cjs/ssr/server.cjs +1 -0
- package/dist/cjs/ssr/server.cjs.map +1 -1
- package/dist/cjs/ssr/server.d.cts +1 -1
- package/dist/cjs/ssr/ssr-server.cjs +16 -0
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.d.cts +1 -0
- package/dist/esm/router.js +5 -1
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/ssr/createRequestHandler.js +4 -2
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/serializer/transformer.d.ts +15 -14
- package/dist/esm/ssr/serializer/transformer.js +7 -3
- package/dist/esm/ssr/serializer/transformer.js.map +1 -1
- package/dist/esm/ssr/server.d.ts +1 -1
- package/dist/esm/ssr/server.js +2 -1
- package/dist/esm/ssr/ssr-server.d.ts +1 -0
- package/dist/esm/ssr/ssr-server.js +17 -1
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/package.json +1 -1
- package/src/router.ts +5 -1
- package/src/ssr/createRequestHandler.ts +3 -2
- package/src/ssr/serializer/transformer.ts +61 -23
- package/src/ssr/server.ts +1 -1
- package/src/ssr/ssr-server.ts +14 -0
|
@@ -14,11 +14,13 @@ export interface DefaultSerializable {
|
|
|
14
14
|
export interface SerializableExtensions extends DefaultSerializable {
|
|
15
15
|
}
|
|
16
16
|
export type Serializable = SerializableExtensions[keyof SerializableExtensions];
|
|
17
|
-
export
|
|
18
|
-
export
|
|
17
|
+
export type UnionizeSerializationAdaptersInput<TAdapters extends ReadonlyArray<AnySerializationAdapter>> = TAdapters[number]['~types']['input'];
|
|
18
|
+
export declare function createSerializationAdapter<TInput = unknown, TOutput = unknown, const TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never = never>(opts: CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters>): SerializationAdapter<TInput, TOutput, TExtendsAdapters>;
|
|
19
|
+
export interface CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never> {
|
|
19
20
|
key: string;
|
|
21
|
+
extends?: TExtendsAdapters;
|
|
20
22
|
test: (value: unknown) => value is TInput;
|
|
21
|
-
toSerializable: (value: TInput) => ValidateSerializable<TOutput, Serializable
|
|
23
|
+
toSerializable: (value: TInput) => ValidateSerializable<TOutput, Serializable | UnionizeSerializationAdaptersInput<TExtendsAdapters>>;
|
|
22
24
|
fromSerializable: (value: TOutput) => TInput;
|
|
23
25
|
}
|
|
24
26
|
export type ValidateSerializable<T, TSerializable> = T extends ReadonlyArray<unknown> ? ResolveArrayShape<T, TSerializable, 'input'> : T extends TSerializable ? T : T extends (...args: Array<any>) => any ? 'Function is not serializable' : T extends Promise<any> ? ValidateSerializablePromise<T, TSerializable> : T extends ReadableStream<any> ? ValidateReadableStream<T, TSerializable> : T extends Set<any> ? ValidateSerializableSet<T, TSerializable> : T extends Map<any, any> ? ValidateSerializableMap<T, TSerializable> : {
|
|
@@ -34,25 +36,24 @@ export interface DefaultSerializerExtensions {
|
|
|
34
36
|
}
|
|
35
37
|
export interface SerializerExtensions extends DefaultSerializerExtensions {
|
|
36
38
|
}
|
|
37
|
-
export interface SerializationAdapter<TInput, TOutput
|
|
38
|
-
'~types': SerializationAdapterTypes<TInput, TOutput>;
|
|
39
|
+
export interface SerializationAdapter<TInput, TOutput, TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>> {
|
|
40
|
+
'~types': SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters>;
|
|
39
41
|
key: string;
|
|
42
|
+
extends?: TExtendsAdapters;
|
|
40
43
|
test: (value: unknown) => value is TInput;
|
|
41
44
|
toSerializable: (value: TInput) => TOutput;
|
|
42
45
|
fromSerializable: (value: TOutput) => TInput;
|
|
43
|
-
makePlugin: (options: {
|
|
44
|
-
didRun: boolean;
|
|
45
|
-
}) => Plugin<TInput, SerovalNode>;
|
|
46
46
|
}
|
|
47
|
-
export interface SerializationAdapterTypes<TInput, TOutput
|
|
48
|
-
input: TInput
|
|
47
|
+
export interface SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>> {
|
|
48
|
+
input: TInput | UnionizeSerializationAdaptersInput<TExtendsAdapters>;
|
|
49
49
|
output: TOutput;
|
|
50
|
+
extends: TExtendsAdapters;
|
|
50
51
|
}
|
|
51
|
-
export type AnySerializationAdapter = SerializationAdapter<any, any>;
|
|
52
|
-
export declare function makeSsrSerovalPlugin
|
|
52
|
+
export type AnySerializationAdapter = SerializationAdapter<any, any, any>;
|
|
53
|
+
export declare function makeSsrSerovalPlugin(serializationAdapter: AnySerializationAdapter, options: {
|
|
53
54
|
didRun: boolean;
|
|
54
|
-
}): Plugin<
|
|
55
|
-
export declare function makeSerovalPlugin
|
|
55
|
+
}): Plugin<any, SerovalNode>;
|
|
56
|
+
export declare function makeSerovalPlugin(serializationAdapter: AnySerializationAdapter): Plugin<any, SerovalNode>;
|
|
56
57
|
export type ValidateSerializableInput<TRegister, T> = ValidateSerializable<T, RegisteredSerializableInput<TRegister>>;
|
|
57
58
|
export type RegisteredSerializableInput<TRegister> = (unknown extends RegisteredSerializationAdapters<TRegister> ? never : RegisteredSerializationAdapters<TRegister> extends ReadonlyArray<AnySerializationAdapter> ? RegisteredSerializationAdapters<TRegister>[number]['~types']['input'] : never) | Serializable;
|
|
58
59
|
export type RegisteredSerializationAdapters<TRegister> = RegisteredConfigType<TRegister, 'serializationAdapters'>;
|
|
@@ -6,6 +6,9 @@ function createSerializationAdapter(opts) {
|
|
|
6
6
|
function makeSsrSerovalPlugin(serializationAdapter, options) {
|
|
7
7
|
return createPlugin({
|
|
8
8
|
tag: "$TSR/t/" + serializationAdapter.key,
|
|
9
|
+
extends: serializationAdapter.extends ? serializationAdapter.extends.map(
|
|
10
|
+
(ext) => makeSsrSerovalPlugin(ext, options)
|
|
11
|
+
) : void 0,
|
|
9
12
|
test: serializationAdapter.test,
|
|
10
13
|
parse: {
|
|
11
14
|
stream(value, ctx) {
|
|
@@ -23,6 +26,9 @@ function makeSsrSerovalPlugin(serializationAdapter, options) {
|
|
|
23
26
|
function makeSerovalPlugin(serializationAdapter) {
|
|
24
27
|
return createPlugin({
|
|
25
28
|
tag: "$TSR/t/" + serializationAdapter.key,
|
|
29
|
+
extends: serializationAdapter.extends ? serializationAdapter.extends.map(
|
|
30
|
+
makeSerovalPlugin
|
|
31
|
+
) : void 0,
|
|
26
32
|
test: serializationAdapter.test,
|
|
27
33
|
parse: {
|
|
28
34
|
sync(value, ctx) {
|
|
@@ -38,9 +44,7 @@ function makeSerovalPlugin(serializationAdapter) {
|
|
|
38
44
|
// we don't generate JS code outside of SSR (for now)
|
|
39
45
|
serialize: void 0,
|
|
40
46
|
deserialize(node, ctx) {
|
|
41
|
-
return serializationAdapter.fromSerializable(
|
|
42
|
-
ctx.deserialize(node)
|
|
43
|
-
);
|
|
47
|
+
return serializationAdapter.fromSerializable(ctx.deserialize(node));
|
|
44
48
|
}
|
|
45
49
|
});
|
|
46
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.js","sources":["../../../../src/ssr/serializer/transformer.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport { GLOBAL_TSR } from '../constants'\nimport type { Plugin, SerovalNode } from 'seroval'\nimport type {\n RegisteredConfigType,\n RegisteredSsr,\n SSROption,\n} from '../../router'\nimport type { LooseReturnType } from '../../utils'\nimport type { AnyRoute, ResolveAllSSR } from '../../route'\n\nexport interface DefaultSerializable {\n number: number\n string: string\n boolean: boolean\n null: null\n undefined: undefined\n bigint: bigint\n Date: Date\n}\n\nexport interface SerializableExtensions extends DefaultSerializable {}\n\nexport type Serializable = SerializableExtensions[keyof SerializableExtensions]\n\nexport function createSerializationAdapter<\n TInput = unknown,\n TOutput = unknown /* we need to check that this type is actually serializable taking into account all seroval native types and any custom plugin WE=router/start add!!! */,\n>(\n opts: CreateSerializationAdapterOptions<TInput, TOutput>,\n): SerializationAdapter<TInput, TOutput> {\n return opts as unknown as SerializationAdapter<TInput, TOutput>\n}\n\nexport interface CreateSerializationAdapterOptions<TInput, TOutput> {\n key: string\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => ValidateSerializable<TOutput, Serializable>\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport type ValidateSerializable<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'input'>\n : T extends TSerializable\n ? T\n : T extends (...args: Array<any>) => any\n ? 'Function is not serializable'\n : T extends Promise<any>\n ? ValidateSerializablePromise<T, TSerializable>\n : T extends ReadableStream<any>\n ? ValidateReadableStream<T, TSerializable>\n : T extends Set<any>\n ? ValidateSerializableSet<T, TSerializable>\n : T extends Map<any, any>\n ? ValidateSerializableMap<T, TSerializable>\n : { [K in keyof T]: ValidateSerializable<T[K], TSerializable> }\n\nexport type ValidateSerializablePromise<T, TSerializable> =\n T extends Promise<infer TAwaited>\n ? Promise<ValidateSerializable<TAwaited, TSerializable>>\n : never\n\nexport type ValidateReadableStream<T, TSerializable> =\n T extends ReadableStream<infer TStreamed>\n ? ReadableStream<ValidateSerializable<TStreamed, TSerializable>>\n : never\n\nexport type ValidateSerializableSet<T, TSerializable> =\n T extends Set<infer TItem>\n ? Set<ValidateSerializable<TItem, TSerializable>>\n : never\n\nexport type ValidateSerializableMap<T, TSerializable> =\n T extends Map<infer TKey, infer TValue>\n ? Map<\n ValidateSerializable<TKey, TSerializable>,\n ValidateSerializable<TValue, TSerializable>\n >\n : never\n\nexport type RegisteredReadableStream =\n unknown extends SerializerExtensions['ReadableStream']\n ? never\n : SerializerExtensions['ReadableStream']\n\nexport interface DefaultSerializerExtensions {\n ReadableStream: unknown\n}\n\nexport interface SerializerExtensions extends DefaultSerializerExtensions {}\n\nexport interface SerializationAdapter<TInput, TOutput> {\n '~types': SerializationAdapterTypes<TInput, TOutput>\n key: string\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => TOutput\n fromSerializable: (value: TOutput) => TInput\n makePlugin: (options: { didRun: boolean }) => Plugin<TInput, SerovalNode>\n}\n\nexport interface SerializationAdapterTypes<TInput, TOutput> {\n input: TInput\n output: TOutput\n}\n\nexport type AnySerializationAdapter = SerializationAdapter<any, any>\n\nexport function makeSsrSerovalPlugin<TInput, TOutput>(\n serializationAdapter: SerializationAdapter<TInput, TOutput>,\n options: { didRun: boolean },\n) {\n return createPlugin<TInput, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n test: serializationAdapter.test,\n parse: {\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n serialize(node, ctx) {\n options.didRun = true\n return (\n GLOBAL_TSR +\n '.t.get(\"' +\n serializationAdapter.key +\n '\")(' +\n ctx.serialize(node) +\n ')'\n )\n },\n // we never deserialize on the server during SSR\n deserialize: undefined as never,\n })\n}\n\nexport function makeSerovalPlugin<TInput, TOutput>(\n serializationAdapter: SerializationAdapter<TInput, TOutput>,\n) {\n return createPlugin<TInput, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n test: serializationAdapter.test,\n parse: {\n sync(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n async async(value, ctx) {\n return await ctx.parse(serializationAdapter.toSerializable(value))\n },\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n // we don't generate JS code outside of SSR (for now)\n serialize: undefined as never,\n deserialize(node, ctx) {\n return serializationAdapter.fromSerializable(\n ctx.deserialize(node) as TOutput,\n )\n },\n })\n}\n\nexport type ValidateSerializableInput<TRegister, T> = ValidateSerializable<\n T,\n RegisteredSerializableInput<TRegister>\n>\n\nexport type RegisteredSerializableInput<TRegister> =\n | (unknown extends RegisteredSerializationAdapters<TRegister>\n ? never\n : RegisteredSerializationAdapters<TRegister> extends ReadonlyArray<AnySerializationAdapter>\n ? RegisteredSerializationAdapters<TRegister>[number]['~types']['input']\n : never)\n | Serializable\n\nexport type RegisteredSerializationAdapters<TRegister> = RegisteredConfigType<\n TRegister,\n 'serializationAdapters'\n>\n\nexport type ValidateSerializableInputResult<TRegister, T> =\n ValidateSerializableResult<T, RegisteredSerializableInput<TRegister>>\n\nexport type ValidateSerializableResult<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'result'>\n : T extends TSerializable\n ? T\n : unknown extends SerializerExtensions['ReadableStream']\n ? { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n : T extends SerializerExtensions['ReadableStream']\n ? ReadableStream\n : { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n\nexport type RegisteredSSROption<TRegister> =\n unknown extends RegisteredConfigType<TRegister, 'defaultSsr'>\n ? SSROption\n : RegisteredConfigType<TRegister, 'defaultSsr'>\n\nexport type ValidateSerializableLifecycleResult<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n false extends RegisteredSsr<TRegister>\n ? any\n : ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute,\n TSSR,\n TFn\n > extends infer TInput\n ? TInput\n : never\n\nexport type ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n ResolveAllSSR<TParentRoute, TSSR> extends false\n ? any\n : RegisteredSSROption<TRegister> extends false\n ? any\n : ValidateSerializableInput<TRegister, LooseReturnType<TFn>>\n\ntype ResolveArrayShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = number extends T['length']\n ? T extends Array<infer U>\n ? Array<ArrayModeResult<TMode, U, TSerializable>>\n : ReadonlyArray<ArrayModeResult<TMode, T[number], TSerializable>>\n : ResolveTupleShape<T, TSerializable, TMode>\n\ntype ResolveTupleShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = T extends readonly [infer THead, ...infer TTail]\n ? readonly [\n ArrayModeResult<TMode, THead, TSerializable>,\n ...ResolveTupleShape<Readonly<TTail>, TSerializable, TMode>,\n ]\n : T\n\ntype ArrayModeResult<\n TMode extends 'input' | 'result',\n TValue,\n TSerializable,\n> = TMode extends 'input'\n ? ValidateSerializable<TValue, TSerializable>\n : ValidateSerializableResult<TValue, TSerializable>\n"],"names":[],"mappings":";;AAyBO,SAAS,2BAId,MACuC;AACvC,SAAO;AACT;AA4EO,SAAS,qBACd,sBACA,SACA;AACA,SAAO,aAAkC;AAAA,IACvC,KAAK,YAAY,qBAAqB;AAAA,IACtC,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA,IAEF,UAAU,MAAM,KAAK;AACnB,cAAQ,SAAS;AACjB,aACE,aACA,aACA,qBAAqB,MACrB,QACA,IAAI,UAAU,IAAI,IAClB;AAAA,IAEJ;AAAA;AAAA,IAEA,aAAa;AAAA,EAAA,CACd;AACH;AAEO,SAAS,kBACd,sBACA;AACA,SAAO,aAAkC;AAAA,IACvC,KAAK,YAAY,qBAAqB;AAAA,IACtC,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,KAAK,OAAO,KAAK;AACf,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,MACA,MAAM,MAAM,OAAO,KAAK;AACtB,eAAO,MAAM,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MACnE;AAAA,MACA,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA;AAAA,IAGF,WAAW;AAAA,IACX,YAAY,MAAM,KAAK;AACrB,aAAO,qBAAqB;AAAA,QAC1B,IAAI,YAAY,IAAI;AAAA,MAAA;AAAA,IAExB;AAAA,EAAA,CACD;AACH;"}
|
|
1
|
+
{"version":3,"file":"transformer.js","sources":["../../../../src/ssr/serializer/transformer.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport { GLOBAL_TSR } from '../constants'\nimport type { Plugin, SerovalNode } from 'seroval'\nimport type {\n RegisteredConfigType,\n RegisteredSsr,\n SSROption,\n} from '../../router'\nimport type { LooseReturnType } from '../../utils'\nimport type { AnyRoute, ResolveAllSSR } from '../../route'\n\nexport interface DefaultSerializable {\n number: number\n string: string\n boolean: boolean\n null: null\n undefined: undefined\n bigint: bigint\n Date: Date\n}\n\nexport interface SerializableExtensions extends DefaultSerializable {}\n\nexport type Serializable = SerializableExtensions[keyof SerializableExtensions]\n\nexport type UnionizeSerializationAdaptersInput<\n TAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> = TAdapters[number]['~types']['input']\n\nexport function createSerializationAdapter<\n TInput = unknown,\n TOutput = unknown,\n const TExtendsAdapters extends\n | ReadonlyArray<AnySerializationAdapter>\n | never = never,\n>(\n opts: CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters>,\n): SerializationAdapter<TInput, TOutput, TExtendsAdapters> {\n return opts as unknown as SerializationAdapter<\n TInput,\n TOutput,\n TExtendsAdapters\n >\n}\n\nexport interface CreateSerializationAdapterOptions<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never,\n> {\n key: string\n extends?: TExtendsAdapters\n test: (value: unknown) => value is TInput\n toSerializable: (\n value: TInput,\n ) => ValidateSerializable<\n TOutput,\n Serializable | UnionizeSerializationAdaptersInput<TExtendsAdapters>\n >\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport type ValidateSerializable<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'input'>\n : T extends TSerializable\n ? T\n : T extends (...args: Array<any>) => any\n ? 'Function is not serializable'\n : T extends Promise<any>\n ? ValidateSerializablePromise<T, TSerializable>\n : T extends ReadableStream<any>\n ? ValidateReadableStream<T, TSerializable>\n : T extends Set<any>\n ? ValidateSerializableSet<T, TSerializable>\n : T extends Map<any, any>\n ? ValidateSerializableMap<T, TSerializable>\n : { [K in keyof T]: ValidateSerializable<T[K], TSerializable> }\n\nexport type ValidateSerializablePromise<T, TSerializable> =\n T extends Promise<infer TAwaited>\n ? Promise<ValidateSerializable<TAwaited, TSerializable>>\n : never\n\nexport type ValidateReadableStream<T, TSerializable> =\n T extends ReadableStream<infer TStreamed>\n ? ReadableStream<ValidateSerializable<TStreamed, TSerializable>>\n : never\n\nexport type ValidateSerializableSet<T, TSerializable> =\n T extends Set<infer TItem>\n ? Set<ValidateSerializable<TItem, TSerializable>>\n : never\n\nexport type ValidateSerializableMap<T, TSerializable> =\n T extends Map<infer TKey, infer TValue>\n ? Map<\n ValidateSerializable<TKey, TSerializable>,\n ValidateSerializable<TValue, TSerializable>\n >\n : never\n\nexport type RegisteredReadableStream =\n unknown extends SerializerExtensions['ReadableStream']\n ? never\n : SerializerExtensions['ReadableStream']\n\nexport interface DefaultSerializerExtensions {\n ReadableStream: unknown\n}\n\nexport interface SerializerExtensions extends DefaultSerializerExtensions {}\n\nexport interface SerializationAdapter<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> {\n '~types': SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters>\n key: string\n extends?: TExtendsAdapters\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => TOutput\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport interface SerializationAdapterTypes<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> {\n input: TInput | UnionizeSerializationAdaptersInput<TExtendsAdapters>\n output: TOutput\n extends: TExtendsAdapters\n}\n\nexport type AnySerializationAdapter = SerializationAdapter<any, any, any>\n\nexport function makeSsrSerovalPlugin(\n serializationAdapter: AnySerializationAdapter,\n options: { didRun: boolean },\n): Plugin<any, SerovalNode> {\n return createPlugin<any, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n extends: serializationAdapter.extends\n ? (serializationAdapter.extends as Array<AnySerializationAdapter>).map(\n (ext) => makeSsrSerovalPlugin(ext, options),\n )\n : undefined,\n test: serializationAdapter.test,\n parse: {\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n serialize(node, ctx) {\n options.didRun = true\n return (\n GLOBAL_TSR +\n '.t.get(\"' +\n serializationAdapter.key +\n '\")(' +\n ctx.serialize(node) +\n ')'\n )\n },\n // we never deserialize on the server during SSR\n deserialize: undefined as never,\n })\n}\n\nexport function makeSerovalPlugin(\n serializationAdapter: AnySerializationAdapter,\n): Plugin<any, SerovalNode> {\n return createPlugin<any, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n extends: serializationAdapter.extends\n ? (serializationAdapter.extends as Array<AnySerializationAdapter>).map(\n makeSerovalPlugin,\n )\n : undefined,\n test: serializationAdapter.test,\n parse: {\n sync(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n async async(value, ctx) {\n return await ctx.parse(serializationAdapter.toSerializable(value))\n },\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n // we don't generate JS code outside of SSR (for now)\n serialize: undefined as never,\n deserialize(node, ctx) {\n return serializationAdapter.fromSerializable(ctx.deserialize(node))\n },\n })\n}\n\nexport type ValidateSerializableInput<TRegister, T> = ValidateSerializable<\n T,\n RegisteredSerializableInput<TRegister>\n>\n\nexport type RegisteredSerializableInput<TRegister> =\n | (unknown extends RegisteredSerializationAdapters<TRegister>\n ? never\n : RegisteredSerializationAdapters<TRegister> extends ReadonlyArray<AnySerializationAdapter>\n ? RegisteredSerializationAdapters<TRegister>[number]['~types']['input']\n : never)\n | Serializable\n\nexport type RegisteredSerializationAdapters<TRegister> = RegisteredConfigType<\n TRegister,\n 'serializationAdapters'\n>\n\nexport type ValidateSerializableInputResult<TRegister, T> =\n ValidateSerializableResult<T, RegisteredSerializableInput<TRegister>>\n\nexport type ValidateSerializableResult<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'result'>\n : T extends TSerializable\n ? T\n : unknown extends SerializerExtensions['ReadableStream']\n ? { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n : T extends SerializerExtensions['ReadableStream']\n ? ReadableStream\n : { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n\nexport type RegisteredSSROption<TRegister> =\n unknown extends RegisteredConfigType<TRegister, 'defaultSsr'>\n ? SSROption\n : RegisteredConfigType<TRegister, 'defaultSsr'>\n\nexport type ValidateSerializableLifecycleResult<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n false extends RegisteredSsr<TRegister>\n ? any\n : ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute,\n TSSR,\n TFn\n > extends infer TInput\n ? TInput\n : never\n\nexport type ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n ResolveAllSSR<TParentRoute, TSSR> extends false\n ? any\n : RegisteredSSROption<TRegister> extends false\n ? any\n : ValidateSerializableInput<TRegister, LooseReturnType<TFn>>\n\ntype ResolveArrayShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = number extends T['length']\n ? T extends Array<infer U>\n ? Array<ArrayModeResult<TMode, U, TSerializable>>\n : ReadonlyArray<ArrayModeResult<TMode, T[number], TSerializable>>\n : ResolveTupleShape<T, TSerializable, TMode>\n\ntype ResolveTupleShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = T extends readonly [infer THead, ...infer TTail]\n ? readonly [\n ArrayModeResult<TMode, THead, TSerializable>,\n ...ResolveTupleShape<Readonly<TTail>, TSerializable, TMode>,\n ]\n : T\n\ntype ArrayModeResult<\n TMode extends 'input' | 'result',\n TValue,\n TSerializable,\n> = TMode extends 'input'\n ? ValidateSerializable<TValue, TSerializable>\n : ValidateSerializableResult<TValue, TSerializable>\n"],"names":[],"mappings":";;AA6BO,SAAS,2BAOd,MACyD;AACzD,SAAO;AAKT;AA+FO,SAAS,qBACd,sBACA,SAC0B;AAC1B,SAAO,aAA+B;AAAA,IACpC,KAAK,YAAY,qBAAqB;AAAA,IACtC,SAAS,qBAAqB,UACzB,qBAAqB,QAA2C;AAAA,MAC/D,CAAC,QAAQ,qBAAqB,KAAK,OAAO;AAAA,IAAA,IAE5C;AAAA,IACJ,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA,IAEF,UAAU,MAAM,KAAK;AACnB,cAAQ,SAAS;AACjB,aACE,aACA,aACA,qBAAqB,MACrB,QACA,IAAI,UAAU,IAAI,IAClB;AAAA,IAEJ;AAAA;AAAA,IAEA,aAAa;AAAA,EAAA,CACd;AACH;AAEO,SAAS,kBACd,sBAC0B;AAC1B,SAAO,aAA+B;AAAA,IACpC,KAAK,YAAY,qBAAqB;AAAA,IACtC,SAAS,qBAAqB,UACzB,qBAAqB,QAA2C;AAAA,MAC/D;AAAA,IAAA,IAEF;AAAA,IACJ,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,KAAK,OAAO,KAAK;AACf,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,MACA,MAAM,MAAM,OAAO,KAAK;AACtB,eAAO,MAAM,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MACnE;AAAA,MACA,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA;AAAA,IAGF,WAAW;AAAA,IACX,YAAY,MAAM,KAAK;AACrB,aAAO,qBAAqB,iBAAiB,IAAI,YAAY,IAAI,CAAC;AAAA,IACpE;AAAA,EAAA,CACD;AACH;"}
|
package/dist/esm/ssr/server.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export type { RequestHandler } from './createRequestHandler.js';
|
|
|
3
3
|
export { defineHandlerCallback } from './handlerCallback.js';
|
|
4
4
|
export type { HandlerCallback } from './handlerCallback.js';
|
|
5
5
|
export { transformPipeableStreamWithRouter, transformStreamWithRouter, transformReadableStreamWithRouter, } from './transformStreamWithRouter.js';
|
|
6
|
-
export { attachRouterServerSsrUtils } from './ssr-server.js';
|
|
6
|
+
export { attachRouterServerSsrUtils, getOrigin } from './ssr-server.js';
|
package/dist/esm/ssr/server.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createRequestHandler } from "./createRequestHandler.js";
|
|
2
2
|
import { defineHandlerCallback } from "./handlerCallback.js";
|
|
3
3
|
import { transformPipeableStreamWithRouter, transformReadableStreamWithRouter, transformStreamWithRouter } from "./transformStreamWithRouter.js";
|
|
4
|
-
import { attachRouterServerSsrUtils } from "./ssr-server.js";
|
|
4
|
+
import { attachRouterServerSsrUtils, getOrigin } from "./ssr-server.js";
|
|
5
5
|
export {
|
|
6
6
|
attachRouterServerSsrUtils,
|
|
7
7
|
createRequestHandler,
|
|
8
8
|
defineHandlerCallback,
|
|
9
|
+
getOrigin,
|
|
9
10
|
transformPipeableStreamWithRouter,
|
|
10
11
|
transformReadableStreamWithRouter,
|
|
11
12
|
transformStreamWithRouter
|
|
@@ -105,8 +105,24 @@ function attachRouterServerSsrUtils({
|
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
+
function getOrigin(request) {
|
|
109
|
+
const originHeader = request.headers.get("Origin");
|
|
110
|
+
if (originHeader) {
|
|
111
|
+
try {
|
|
112
|
+
new URL(originHeader);
|
|
113
|
+
return originHeader;
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
return new URL(request.url).origin;
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
return "http://localhost";
|
|
122
|
+
}
|
|
108
123
|
export {
|
|
109
124
|
attachRouterServerSsrUtils,
|
|
110
|
-
dehydrateMatch
|
|
125
|
+
dehydrateMatch,
|
|
126
|
+
getOrigin
|
|
111
127
|
};
|
|
112
128
|
//# sourceMappingURL=ssr-server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-server.js","sources":["../../../src/ssr/ssr-server.ts"],"sourcesContent":["import { crossSerializeStream, getCrossReferenceHeader } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { createControlledPromise } from '../utils'\nimport minifiedTsrBootStrapScript from './tsrScript?script-string'\nimport { GLOBAL_TSR } from './constants'\nimport { defaultSerovalPlugins } from './serializer/seroval-plugins'\nimport { makeSsrSerovalPlugin } from './serializer/transformer'\nimport type { AnyRouter } from '../router'\nimport type { DehydratedMatch } from './ssr-client'\nimport type { DehydratedRouter } from './client'\nimport type { AnyRouteMatch } from '../Matches'\nimport type { Manifest } from '../manifest'\nimport type { AnySerializationAdapter } from './serializer/transformer'\n\ndeclare module '../router' {\n interface ServerSsr {\n setRenderFinished: () => void\n }\n interface RouterEvents {\n onInjectedHtml: {\n type: 'onInjectedHtml'\n promise: Promise<string>\n }\n }\n}\n\nconst SCOPE_ID = 'tsr'\n\nexport function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {\n const dehydratedMatch: DehydratedMatch = {\n i: match.id,\n u: match.updatedAt,\n s: match.status,\n }\n\n const properties = [\n ['__beforeLoadContext', 'b'],\n ['loaderData', 'l'],\n ['error', 'e'],\n ['ssr', 'ssr'],\n ] as const\n\n for (const [key, shorthand] of properties) {\n if (match[key] !== undefined) {\n dehydratedMatch[shorthand] = match[key]\n }\n }\n return dehydratedMatch\n}\n\nexport function attachRouterServerSsrUtils({\n router,\n manifest,\n}: {\n router: AnyRouter\n manifest: Manifest | undefined\n}) {\n router.ssr = {\n manifest,\n }\n let initialScriptSent = false\n const getInitialScript = () => {\n if (initialScriptSent) {\n return ''\n }\n initialScriptSent = true\n return `${getCrossReferenceHeader(SCOPE_ID)};${minifiedTsrBootStrapScript};`\n }\n let _dehydrated = false\n const listeners: Array<() => void> = []\n\n router.serverSsr = {\n injectedHtml: [],\n injectHtml: (getHtml) => {\n const promise = Promise.resolve().then(getHtml)\n router.serverSsr!.injectedHtml.push(promise)\n router.emit({\n type: 'onInjectedHtml',\n promise,\n })\n\n return promise.then(() => {})\n },\n injectScript: (getScript) => {\n return router.serverSsr!.injectHtml(async () => {\n const script = await getScript()\n return `<script ${router.options.ssr?.nonce ? `nonce='${router.options.ssr.nonce}'` : ''} class='$tsr'>${getInitialScript()}${script};$_TSR.c()</script>`\n })\n },\n dehydrate: async () => {\n invariant(!_dehydrated, 'router is already dehydrated!')\n let matchesToDehydrate = router.state.matches\n if (router.isShell()) {\n // In SPA mode we only want to dehydrate the root match\n matchesToDehydrate = matchesToDehydrate.slice(0, 1)\n }\n const matches = matchesToDehydrate.map(dehydrateMatch)\n\n const dehydratedRouter: DehydratedRouter = {\n manifest: router.ssr!.manifest,\n matches,\n }\n const lastMatchId = matchesToDehydrate[matchesToDehydrate.length - 1]?.id\n if (lastMatchId) {\n dehydratedRouter.lastMatchId = lastMatchId\n }\n dehydratedRouter.dehydratedData = await router.options.dehydrate?.()\n _dehydrated = true\n\n const p = createControlledPromise<string>()\n const trackPlugins = { didRun: false }\n const plugins =\n (\n router.options.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n )?.map((t) => makeSsrSerovalPlugin(t, trackPlugins)) ?? []\n crossSerializeStream(dehydratedRouter, {\n refs: new Map(),\n plugins: [...plugins, ...defaultSerovalPlugins],\n onSerialize: (data, initial) => {\n let serialized = initial ? GLOBAL_TSR + '.router=' + data : data\n if (trackPlugins.didRun) {\n serialized = GLOBAL_TSR + '.p(()=>' + serialized + ')'\n }\n router.serverSsr!.injectScript(() => serialized)\n },\n scopeId: SCOPE_ID,\n onDone: () => p.resolve(''),\n onError: (err) => p.reject(err),\n })\n // make sure the stream is kept open until the promise is resolved\n router.serverSsr!.injectHtml(() => p)\n },\n isDehydrated() {\n return _dehydrated\n },\n onRenderFinished: (listener) => listeners.push(listener),\n setRenderFinished: () => {\n listeners.forEach((l) => l())\n },\n }\n}\n"],"names":[],"mappings":";;;;;;;AA0BA,MAAM,WAAW;AAEV,SAAS,eAAe,OAAuC;AACpE,QAAM,kBAAmC;AAAA,IACvC,GAAG,MAAM;AAAA,IACT,GAAG,MAAM;AAAA,IACT,GAAG,MAAM;AAAA,EAAA;AAGX,QAAM,aAAa;AAAA,IACjB,CAAC,uBAAuB,GAAG;AAAA,IAC3B,CAAC,cAAc,GAAG;AAAA,IAClB,CAAC,SAAS,GAAG;AAAA,IACb,CAAC,OAAO,KAAK;AAAA,EAAA;AAGf,aAAW,CAAC,KAAK,SAAS,KAAK,YAAY;AACzC,QAAI,MAAM,GAAG,MAAM,QAAW;AAC5B,sBAAgB,SAAS,IAAI,MAAM,GAAG;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AACF,GAGG;AACD,SAAO,MAAM;AAAA,IACX;AAAA,EAAA;AAEF,MAAI,oBAAoB;AACxB,QAAM,mBAAmB,MAAM;AAC7B,QAAI,mBAAmB;AACrB,aAAO;AAAA,IACT;AACA,wBAAoB;AACpB,WAAO,GAAG,wBAAwB,QAAQ,CAAC,IAAI,0BAA0B;AAAA,EAC3E;AACA,MAAI,cAAc;AAClB,QAAM,YAA+B,CAAA;AAErC,SAAO,YAAY;AAAA,IACjB,cAAc,CAAA;AAAA,IACd,YAAY,CAAC,YAAY;AACvB,YAAM,UAAU,QAAQ,QAAA,EAAU,KAAK,OAAO;AAC9C,aAAO,UAAW,aAAa,KAAK,OAAO;AAC3C,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN;AAAA,MAAA,CACD;AAED,aAAO,QAAQ,KAAK,MAAM;AAAA,MAAC,CAAC;AAAA,IAC9B;AAAA,IACA,cAAc,CAAC,cAAc;AAC3B,aAAO,OAAO,UAAW,WAAW,YAAY;AAC9C,cAAM,SAAS,MAAM,UAAA;AACrB,eAAO,WAAW,OAAO,QAAQ,KAAK,QAAQ,UAAU,OAAO,QAAQ,IAAI,KAAK,MAAM,EAAE,iBAAiB,iBAAA,CAAkB,GAAG,MAAM;AAAA,MACtI,CAAC;AAAA,IACH;AAAA,IACA,WAAW,YAAY;AACrB,gBAAU,CAAC,aAAa,+BAA+B;AACvD,UAAI,qBAAqB,OAAO,MAAM;AACtC,UAAI,OAAO,WAAW;AAEpB,6BAAqB,mBAAmB,MAAM,GAAG,CAAC;AAAA,MACpD;AACA,YAAM,UAAU,mBAAmB,IAAI,cAAc;AAErD,YAAM,mBAAqC;AAAA,QACzC,UAAU,OAAO,IAAK;AAAA,QACtB;AAAA,MAAA;AAEF,YAAM,cAAc,mBAAmB,mBAAmB,SAAS,CAAC,GAAG;AACvE,UAAI,aAAa;AACf,yBAAiB,cAAc;AAAA,MACjC;AACA,uBAAiB,iBAAiB,MAAM,OAAO,QAAQ,YAAA;AACvD,oBAAc;AAEd,YAAM,IAAI,wBAAA;AACV,YAAM,eAAe,EAAE,QAAQ,MAAA;AAC/B,YAAM,UAEF,OAAO,QAAQ,uBAGd,IAAI,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC,KAAK,CAAA;AAC1D,2BAAqB,kBAAkB;AAAA,QACrC,0BAAU,IAAA;AAAA,QACV,SAAS,CAAC,GAAG,SAAS,GAAG,qBAAqB;AAAA,QAC9C,aAAa,CAAC,MAAM,YAAY;AAC9B,cAAI,aAAa,UAAU,aAAa,aAAa,OAAO;AAC5D,cAAI,aAAa,QAAQ;AACvB,yBAAa,aAAa,YAAY,aAAa;AAAA,UACrD;AACA,iBAAO,UAAW,aAAa,MAAM,UAAU;AAAA,QACjD;AAAA,QACA,SAAS;AAAA,QACT,QAAQ,MAAM,EAAE,QAAQ,EAAE;AAAA,QAC1B,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG;AAAA,MAAA,CAC/B;AAED,aAAO,UAAW,WAAW,MAAM,CAAC;AAAA,IACtC;AAAA,IACA,eAAe;AACb,aAAO;AAAA,IACT;AAAA,IACA,kBAAkB,CAAC,aAAa,UAAU,KAAK,QAAQ;AAAA,IACvD,mBAAmB,MAAM;AACvB,gBAAU,QAAQ,CAAC,MAAM,EAAA,CAAG;AAAA,IAC9B;AAAA,EAAA;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"ssr-server.js","sources":["../../../src/ssr/ssr-server.ts"],"sourcesContent":["import { crossSerializeStream, getCrossReferenceHeader } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { createControlledPromise } from '../utils'\nimport minifiedTsrBootStrapScript from './tsrScript?script-string'\nimport { GLOBAL_TSR } from './constants'\nimport { defaultSerovalPlugins } from './serializer/seroval-plugins'\nimport { makeSsrSerovalPlugin } from './serializer/transformer'\nimport type { AnyRouter } from '../router'\nimport type { DehydratedMatch } from './ssr-client'\nimport type { DehydratedRouter } from './client'\nimport type { AnyRouteMatch } from '../Matches'\nimport type { Manifest } from '../manifest'\nimport type { AnySerializationAdapter } from './serializer/transformer'\n\ndeclare module '../router' {\n interface ServerSsr {\n setRenderFinished: () => void\n }\n interface RouterEvents {\n onInjectedHtml: {\n type: 'onInjectedHtml'\n promise: Promise<string>\n }\n }\n}\n\nconst SCOPE_ID = 'tsr'\n\nexport function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {\n const dehydratedMatch: DehydratedMatch = {\n i: match.id,\n u: match.updatedAt,\n s: match.status,\n }\n\n const properties = [\n ['__beforeLoadContext', 'b'],\n ['loaderData', 'l'],\n ['error', 'e'],\n ['ssr', 'ssr'],\n ] as const\n\n for (const [key, shorthand] of properties) {\n if (match[key] !== undefined) {\n dehydratedMatch[shorthand] = match[key]\n }\n }\n return dehydratedMatch\n}\n\nexport function attachRouterServerSsrUtils({\n router,\n manifest,\n}: {\n router: AnyRouter\n manifest: Manifest | undefined\n}) {\n router.ssr = {\n manifest,\n }\n let initialScriptSent = false\n const getInitialScript = () => {\n if (initialScriptSent) {\n return ''\n }\n initialScriptSent = true\n return `${getCrossReferenceHeader(SCOPE_ID)};${minifiedTsrBootStrapScript};`\n }\n let _dehydrated = false\n const listeners: Array<() => void> = []\n\n router.serverSsr = {\n injectedHtml: [],\n injectHtml: (getHtml) => {\n const promise = Promise.resolve().then(getHtml)\n router.serverSsr!.injectedHtml.push(promise)\n router.emit({\n type: 'onInjectedHtml',\n promise,\n })\n\n return promise.then(() => {})\n },\n injectScript: (getScript) => {\n return router.serverSsr!.injectHtml(async () => {\n const script = await getScript()\n return `<script ${router.options.ssr?.nonce ? `nonce='${router.options.ssr.nonce}'` : ''} class='$tsr'>${getInitialScript()}${script};$_TSR.c()</script>`\n })\n },\n dehydrate: async () => {\n invariant(!_dehydrated, 'router is already dehydrated!')\n let matchesToDehydrate = router.state.matches\n if (router.isShell()) {\n // In SPA mode we only want to dehydrate the root match\n matchesToDehydrate = matchesToDehydrate.slice(0, 1)\n }\n const matches = matchesToDehydrate.map(dehydrateMatch)\n\n const dehydratedRouter: DehydratedRouter = {\n manifest: router.ssr!.manifest,\n matches,\n }\n const lastMatchId = matchesToDehydrate[matchesToDehydrate.length - 1]?.id\n if (lastMatchId) {\n dehydratedRouter.lastMatchId = lastMatchId\n }\n dehydratedRouter.dehydratedData = await router.options.dehydrate?.()\n _dehydrated = true\n\n const p = createControlledPromise<string>()\n const trackPlugins = { didRun: false }\n const plugins =\n (\n router.options.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n )?.map((t) => makeSsrSerovalPlugin(t, trackPlugins)) ?? []\n crossSerializeStream(dehydratedRouter, {\n refs: new Map(),\n plugins: [...plugins, ...defaultSerovalPlugins],\n onSerialize: (data, initial) => {\n let serialized = initial ? GLOBAL_TSR + '.router=' + data : data\n if (trackPlugins.didRun) {\n serialized = GLOBAL_TSR + '.p(()=>' + serialized + ')'\n }\n router.serverSsr!.injectScript(() => serialized)\n },\n scopeId: SCOPE_ID,\n onDone: () => p.resolve(''),\n onError: (err) => p.reject(err),\n })\n // make sure the stream is kept open until the promise is resolved\n router.serverSsr!.injectHtml(() => p)\n },\n isDehydrated() {\n return _dehydrated\n },\n onRenderFinished: (listener) => listeners.push(listener),\n setRenderFinished: () => {\n listeners.forEach((l) => l())\n },\n }\n}\n\nexport function getOrigin(request: Request) {\n const originHeader = request.headers.get('Origin')\n if (originHeader) {\n try {\n new URL(originHeader)\n return originHeader\n } catch {}\n }\n try {\n return new URL(request.url).origin\n } catch {}\n return 'http://localhost'\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/router.ts
CHANGED
|
@@ -2230,7 +2230,11 @@ export class RouterCore<
|
|
|
2230
2230
|
|
|
2231
2231
|
resolveRedirect = (redirect: AnyRedirect): AnyRedirect => {
|
|
2232
2232
|
if (!redirect.options.href) {
|
|
2233
|
-
|
|
2233
|
+
let href = this.buildLocation(redirect.options).url
|
|
2234
|
+
if (this.origin && href.startsWith(this.origin)) {
|
|
2235
|
+
href = href.replace(this.origin, '') || '/'
|
|
2236
|
+
}
|
|
2237
|
+
redirect.options.href = href
|
|
2234
2238
|
redirect.headers.set('Location', redirect.options.href)
|
|
2235
2239
|
}
|
|
2236
2240
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createMemoryHistory } from '@tanstack/history'
|
|
2
2
|
import { mergeHeaders } from './headers'
|
|
3
|
-
import { attachRouterServerSsrUtils } from './ssr-server'
|
|
3
|
+
import { attachRouterServerSsrUtils, getOrigin } from './ssr-server'
|
|
4
4
|
import type { HandlerCallback } from './handlerCallback'
|
|
5
5
|
import type { AnyRouter } from '../router'
|
|
6
6
|
import type { Manifest } from '../manifest'
|
|
@@ -27,7 +27,7 @@ export function createRequestHandler<TRouter extends AnyRouter>({
|
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
const url = new URL(request.url, 'http://localhost')
|
|
30
|
-
|
|
30
|
+
const origin = getOrigin(request)
|
|
31
31
|
const href = url.href.replace(url.origin, '')
|
|
32
32
|
|
|
33
33
|
// Create a history for the router
|
|
@@ -38,6 +38,7 @@ export function createRequestHandler<TRouter extends AnyRouter>({
|
|
|
38
38
|
// Update the router with the history and context
|
|
39
39
|
router.update({
|
|
40
40
|
history,
|
|
41
|
+
origin: router.options.origin ?? origin,
|
|
41
42
|
})
|
|
42
43
|
|
|
43
44
|
await router.load()
|
|
@@ -23,19 +23,40 @@ export interface SerializableExtensions extends DefaultSerializable {}
|
|
|
23
23
|
|
|
24
24
|
export type Serializable = SerializableExtensions[keyof SerializableExtensions]
|
|
25
25
|
|
|
26
|
+
export type UnionizeSerializationAdaptersInput<
|
|
27
|
+
TAdapters extends ReadonlyArray<AnySerializationAdapter>,
|
|
28
|
+
> = TAdapters[number]['~types']['input']
|
|
29
|
+
|
|
26
30
|
export function createSerializationAdapter<
|
|
27
31
|
TInput = unknown,
|
|
28
|
-
TOutput = unknown
|
|
32
|
+
TOutput = unknown,
|
|
33
|
+
const TExtendsAdapters extends
|
|
34
|
+
| ReadonlyArray<AnySerializationAdapter>
|
|
35
|
+
| never = never,
|
|
29
36
|
>(
|
|
30
|
-
opts: CreateSerializationAdapterOptions<TInput, TOutput>,
|
|
31
|
-
): SerializationAdapter<TInput, TOutput> {
|
|
32
|
-
return opts as unknown as SerializationAdapter<
|
|
37
|
+
opts: CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters>,
|
|
38
|
+
): SerializationAdapter<TInput, TOutput, TExtendsAdapters> {
|
|
39
|
+
return opts as unknown as SerializationAdapter<
|
|
40
|
+
TInput,
|
|
41
|
+
TOutput,
|
|
42
|
+
TExtendsAdapters
|
|
43
|
+
>
|
|
33
44
|
}
|
|
34
45
|
|
|
35
|
-
export interface CreateSerializationAdapterOptions<
|
|
46
|
+
export interface CreateSerializationAdapterOptions<
|
|
47
|
+
TInput,
|
|
48
|
+
TOutput,
|
|
49
|
+
TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never,
|
|
50
|
+
> {
|
|
36
51
|
key: string
|
|
52
|
+
extends?: TExtendsAdapters
|
|
37
53
|
test: (value: unknown) => value is TInput
|
|
38
|
-
toSerializable: (
|
|
54
|
+
toSerializable: (
|
|
55
|
+
value: TInput,
|
|
56
|
+
) => ValidateSerializable<
|
|
57
|
+
TOutput,
|
|
58
|
+
Serializable | UnionizeSerializationAdaptersInput<TExtendsAdapters>
|
|
59
|
+
>
|
|
39
60
|
fromSerializable: (value: TOutput) => TInput
|
|
40
61
|
}
|
|
41
62
|
|
|
@@ -90,28 +111,42 @@ export interface DefaultSerializerExtensions {
|
|
|
90
111
|
|
|
91
112
|
export interface SerializerExtensions extends DefaultSerializerExtensions {}
|
|
92
113
|
|
|
93
|
-
export interface SerializationAdapter<
|
|
94
|
-
|
|
114
|
+
export interface SerializationAdapter<
|
|
115
|
+
TInput,
|
|
116
|
+
TOutput,
|
|
117
|
+
TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,
|
|
118
|
+
> {
|
|
119
|
+
'~types': SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters>
|
|
95
120
|
key: string
|
|
121
|
+
extends?: TExtendsAdapters
|
|
96
122
|
test: (value: unknown) => value is TInput
|
|
97
123
|
toSerializable: (value: TInput) => TOutput
|
|
98
124
|
fromSerializable: (value: TOutput) => TInput
|
|
99
|
-
makePlugin: (options: { didRun: boolean }) => Plugin<TInput, SerovalNode>
|
|
100
125
|
}
|
|
101
126
|
|
|
102
|
-
export interface SerializationAdapterTypes<
|
|
103
|
-
|
|
127
|
+
export interface SerializationAdapterTypes<
|
|
128
|
+
TInput,
|
|
129
|
+
TOutput,
|
|
130
|
+
TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,
|
|
131
|
+
> {
|
|
132
|
+
input: TInput | UnionizeSerializationAdaptersInput<TExtendsAdapters>
|
|
104
133
|
output: TOutput
|
|
134
|
+
extends: TExtendsAdapters
|
|
105
135
|
}
|
|
106
136
|
|
|
107
|
-
export type AnySerializationAdapter = SerializationAdapter<any, any>
|
|
137
|
+
export type AnySerializationAdapter = SerializationAdapter<any, any, any>
|
|
108
138
|
|
|
109
|
-
export function makeSsrSerovalPlugin
|
|
110
|
-
serializationAdapter:
|
|
139
|
+
export function makeSsrSerovalPlugin(
|
|
140
|
+
serializationAdapter: AnySerializationAdapter,
|
|
111
141
|
options: { didRun: boolean },
|
|
112
|
-
) {
|
|
113
|
-
return createPlugin<
|
|
142
|
+
): Plugin<any, SerovalNode> {
|
|
143
|
+
return createPlugin<any, SerovalNode>({
|
|
114
144
|
tag: '$TSR/t/' + serializationAdapter.key,
|
|
145
|
+
extends: serializationAdapter.extends
|
|
146
|
+
? (serializationAdapter.extends as Array<AnySerializationAdapter>).map(
|
|
147
|
+
(ext) => makeSsrSerovalPlugin(ext, options),
|
|
148
|
+
)
|
|
149
|
+
: undefined,
|
|
115
150
|
test: serializationAdapter.test,
|
|
116
151
|
parse: {
|
|
117
152
|
stream(value, ctx) {
|
|
@@ -134,11 +169,16 @@ export function makeSsrSerovalPlugin<TInput, TOutput>(
|
|
|
134
169
|
})
|
|
135
170
|
}
|
|
136
171
|
|
|
137
|
-
export function makeSerovalPlugin
|
|
138
|
-
serializationAdapter:
|
|
139
|
-
) {
|
|
140
|
-
return createPlugin<
|
|
172
|
+
export function makeSerovalPlugin(
|
|
173
|
+
serializationAdapter: AnySerializationAdapter,
|
|
174
|
+
): Plugin<any, SerovalNode> {
|
|
175
|
+
return createPlugin<any, SerovalNode>({
|
|
141
176
|
tag: '$TSR/t/' + serializationAdapter.key,
|
|
177
|
+
extends: serializationAdapter.extends
|
|
178
|
+
? (serializationAdapter.extends as Array<AnySerializationAdapter>).map(
|
|
179
|
+
makeSerovalPlugin,
|
|
180
|
+
)
|
|
181
|
+
: undefined,
|
|
142
182
|
test: serializationAdapter.test,
|
|
143
183
|
parse: {
|
|
144
184
|
sync(value, ctx) {
|
|
@@ -154,9 +194,7 @@ export function makeSerovalPlugin<TInput, TOutput>(
|
|
|
154
194
|
// we don't generate JS code outside of SSR (for now)
|
|
155
195
|
serialize: undefined as never,
|
|
156
196
|
deserialize(node, ctx) {
|
|
157
|
-
return serializationAdapter.fromSerializable(
|
|
158
|
-
ctx.deserialize(node) as TOutput,
|
|
159
|
-
)
|
|
197
|
+
return serializationAdapter.fromSerializable(ctx.deserialize(node))
|
|
160
198
|
},
|
|
161
199
|
})
|
|
162
200
|
}
|
package/src/ssr/server.ts
CHANGED
|
@@ -7,7 +7,7 @@ export {
|
|
|
7
7
|
transformStreamWithRouter,
|
|
8
8
|
transformReadableStreamWithRouter,
|
|
9
9
|
} from './transformStreamWithRouter'
|
|
10
|
-
export { attachRouterServerSsrUtils } from './ssr-server'
|
|
10
|
+
export { attachRouterServerSsrUtils, getOrigin } from './ssr-server'
|
|
11
11
|
|
|
12
12
|
// declare module '../router' {
|
|
13
13
|
// export interface RegisterSsr {
|
package/src/ssr/ssr-server.ts
CHANGED
|
@@ -141,3 +141,17 @@ export function attachRouterServerSsrUtils({
|
|
|
141
141
|
},
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
+
|
|
145
|
+
export function getOrigin(request: Request) {
|
|
146
|
+
const originHeader = request.headers.get('Origin')
|
|
147
|
+
if (originHeader) {
|
|
148
|
+
try {
|
|
149
|
+
new URL(originHeader)
|
|
150
|
+
return originHeader
|
|
151
|
+
} catch {}
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
return new URL(request.url).origin
|
|
155
|
+
} catch {}
|
|
156
|
+
return 'http://localhost'
|
|
157
|
+
}
|