effective-rsc 0.1.2 → 0.1.4
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/LLMS.md +85 -0
- package/README.md +14 -8
- package/dist/application/routes.d.ts +10 -10
- package/dist/application/routes.js.map +1 -1
- package/dist/build/build.d.ts +4 -2
- package/dist/build/build.js +19 -2
- package/dist/build/build.js.map +1 -1
- package/dist/build/deployment.d.ts +10 -0
- package/dist/build/deployment.js +59 -0
- package/dist/build/deployment.js.map +1 -0
- package/dist/build/dev.d.ts +4 -4
- package/dist/build/dev.js +22 -7
- package/dist/build/dev.js.map +1 -1
- package/dist/build/hook.d.ts +8 -0
- package/dist/build/hook.js +5 -0
- package/dist/build/hook.js.map +1 -0
- package/dist/build/rspack.js +1 -1
- package/dist/build/rspack.js.map +1 -1
- package/dist/cli.js +13 -24
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-renderer.d.ts +25 -25
- package/dist/client/browser-renderer.js +80 -94
- package/dist/client/browser-renderer.js.map +1 -1
- package/dist/client/call-server.js +7 -5
- package/dist/client/call-server.js.map +1 -1
- package/dist/client/client-router.js +23 -7
- package/dist/client/client-router.js.map +1 -1
- package/dist/client/flight-client.js +3 -4
- package/dist/client/flight-client.js.map +1 -1
- package/dist/client/react-dom-renderer.js +2 -1
- package/dist/client/react-dom-renderer.js.map +1 -1
- package/dist/client/route-refresh.d.ts +2 -2
- package/dist/client/route-refresh.js +54 -39
- package/dist/client/route-refresh.js.map +1 -1
- package/dist/dev/panel.js +14 -14
- package/dist/dev/panel.js.map +1 -1
- package/dist/server/application.d.ts +2 -1
- package/dist/server/application.js +8 -6
- package/dist/server/application.js.map +1 -1
- package/dist/server/html-renderer.js +12 -11
- package/dist/server/html-renderer.js.map +1 -1
- package/dist/server/serve.d.ts +7 -0
- package/dist/server/serve.js +31 -0
- package/dist/server/serve.js.map +1 -0
- package/dist/server/start.d.ts +3 -0
- package/dist/server/start.js +24 -0
- package/dist/server/start.js.map +1 -0
- package/docs/02-guides/06-deploying-to-vercel/index.md +34 -0
- package/docs/02-guides/index.md +1 -0
- package/docs/03-advanced/02-client-navigation/index.md +17 -0
- package/docs/03-advanced/04-production-startup/01_server.ts +11 -0
- package/docs/03-advanced/04-production-startup/index.md +22 -0
- package/docs/03-advanced/index.md +1 -0
- package/package.json +27 -20
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Layer } from 'effect';
|
|
2
2
|
import type { PlatformError } from 'effect/PlatformError';
|
|
3
3
|
import { HttpRouter, HttpStaticServer } from 'effect/unstable/http';
|
|
4
|
+
import type { ServeError } from 'effect/unstable/http/HttpServerError';
|
|
4
5
|
import { type ApplicationDefinition } from '../application/definition.js';
|
|
5
6
|
import { HtmlRenderError } from './html-renderer.js';
|
|
6
7
|
import { ServerConfig } from './server-config.js';
|
|
7
8
|
import { type ServerFnRequestFailure } from './server-fn-request.js';
|
|
8
9
|
type HttpApplicationRequirements = ServerConfig | Layer.Services<ReturnType<typeof HttpStaticServer.layer>> | HttpRouter.Request.From<'Error', HtmlRenderError | ServerFnRequestFailure>;
|
|
9
10
|
export type HttpApplicationLayer<ApplicationError> = Layer.Layer<never, ApplicationError | PlatformError, HttpApplicationRequirements>;
|
|
10
|
-
export type ServerApplicationLayer<ApplicationError> = Layer.Layer<never, ApplicationError | PlatformError, ServerConfig>;
|
|
11
|
+
export type ServerApplicationLayer<ApplicationError> = Layer.Layer<never, HttpRouter.Request.Without<ApplicationError> | PlatformError | ServeError, ServerConfig>;
|
|
11
12
|
declare const httpLayer: <Services, ApplicationError>(application: ApplicationDefinition<Services, ApplicationError>) => HttpApplicationLayer<ApplicationError>;
|
|
12
13
|
declare const serverLayer: <Services, ApplicationError>(application: ApplicationDefinition<Services, ApplicationError>) => ServerApplicationLayer<ApplicationError>;
|
|
13
14
|
export declare const ServerApplication: {
|
|
@@ -13,6 +13,9 @@ import { ApplicationIdleTimeoutSeconds, ApplicationMaxRequestBodySizeBytes, Serv
|
|
|
13
13
|
import { prepareServerFnRequest } from "./server-fn-request.js";
|
|
14
14
|
|
|
15
15
|
import * as __rspack_external__effect_platform_bun_BunHttpServer_0e4f7bbb from "@effect/platform-bun/BunHttpServer";
|
|
16
|
+
import * as __rspack_external__effect_platform_bun_BunStream_c9d32906 from "@effect/platform-bun/BunStream";
|
|
17
|
+
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
|
|
@@ -72,7 +75,7 @@ const appendAcceptVary = (vary)=>{
|
|
|
72
75
|
return fields.includes('*') || fields.includes('accept') ? vary : `${vary}, Accept`;
|
|
73
76
|
};
|
|
74
77
|
const acceptVaryPreResponseHandler = (_request, response)=>Effect.succeed(HttpServerResponse.setHeader(response, 'vary', appendAcceptVary(response.headers['vary'])));
|
|
75
|
-
const fromWebStream = (stream, options)=>
|
|
78
|
+
const fromWebStream = (stream, options)=>__rspack_external__effect_platform_bun_BunStream_c9d32906.fromReadableStream({
|
|
76
79
|
evaluate: ()=>stream,
|
|
77
80
|
onError: (cause)=>cause,
|
|
78
81
|
releaseLockOnEnd: options?.releaseLockOnEnd
|
|
@@ -109,8 +112,7 @@ const httpLayer = (application)=>{
|
|
|
109
112
|
}).pipe(Stream.ensuring(flight.release)), {
|
|
110
113
|
contentType: `${FlightMediaType};charset=utf-8`,
|
|
111
114
|
headers: {
|
|
112
|
-
...DynamicResponseHeaders
|
|
113
|
-
'content-location': requestUrl.value.href
|
|
115
|
+
...DynamicResponseHeaders
|
|
114
116
|
},
|
|
115
117
|
status
|
|
116
118
|
});
|
|
@@ -161,8 +163,8 @@ const httpLayer = (application)=>{
|
|
|
161
163
|
return applyMiddleware(prepared.middleware, response);
|
|
162
164
|
};
|
|
163
165
|
const RequestLayer = Layer.mergeAll(RenderersLayer, applicationState.layer);
|
|
164
|
-
const ApplicationRoutesLayer = Layer.unwrap(Effect.map(
|
|
165
|
-
const RequestContextMiddleware = HttpRouter.middleware()((httpEffect)=>httpEffect.pipe(Effect.provideContext(
|
|
166
|
+
const ApplicationRoutesLayer = Layer.unwrap(Effect.map(Layer.build(RequestLayer), (applicationServices)=>{
|
|
167
|
+
const RequestContextMiddleware = HttpRouter.middleware()((httpEffect)=>httpEffect.pipe(Effect.provideContext(applicationServices)));
|
|
166
168
|
const makeRouteLayer = (destination)=>{
|
|
167
169
|
const GetLayer = HttpRouter.add('GET', destination.pattern, (request)=>render({
|
|
168
170
|
destination,
|
|
@@ -183,7 +185,7 @@ const httpLayer = (application)=>{
|
|
|
183
185
|
};
|
|
184
186
|
const [firstDestination, ...remainingDestinations] = applicationState.routes;
|
|
185
187
|
return Layer.mergeAll(makeRouteLayer(firstDestination), ...remainingDestinations.map(makeRouteLayer));
|
|
186
|
-
}))
|
|
188
|
+
}));
|
|
187
189
|
return Layer.mergeAll(StaticAssetsLayer, PublicAssetsLayer).pipe(Layer.provideMerge(ApplicationRoutesLayer));
|
|
188
190
|
};
|
|
189
191
|
const serverLayer = (application)=>HttpRouter.serve(httpLayer(application)).pipe(Layer.provide(BunServerLayer));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server/application.js","sources":["../../src/server/application.ts"],"sourcesContent":["import * as BunHttpServer from '@effect/platform-bun/BunHttpServer';\nimport { Effect, Layer, Option, Schema, Stream, type Types } from 'effect';\nimport type { PlatformError } from 'effect/PlatformError';\nimport {\n HttpEffect,\n HttpRouter,\n HttpServerRequest,\n HttpServerResponse,\n HttpStaticServer,\n} from 'effect/unstable/http';\n\nimport { type ApplicationDefinition, getApplicationState } from '../application/definition';\nimport { getERSCIdentity } from '../application/ersc-identity';\nimport {\n applyMiddleware,\n type AnyMiddleware,\n getScopedHttpMiddleware,\n} from '../application/middleware';\nimport type { EncodedPageParams, PageParams } from '../application/page';\nimport type { CompiledDestination } from '../application/route-graph';\nimport { FrameworkAssetNamespace, isAbsolutePath } from '../application/route-path';\nimport { FlightMediaType } from '../rsc/flight';\nimport { renderRouteTree } from '../rsc/render-route-tree';\nimport { FlightHtmlInjector } from './flight-html-stream';\nimport { FlightRenderer } from './flight-renderer';\nimport { HtmlRenderError, HtmlRenderer } from './html-renderer';\nimport type { RequestOutcome } from './request-outcome';\nimport {\n ApplicationIdleTimeoutSeconds,\n ApplicationMaxRequestBodySizeBytes,\n ServerConfig,\n} from './server-config';\nimport {\n prepareServerFnRequest,\n type PreparedServerFnRequest,\n type ServerFnRequestFailure,\n} from './server-fn-request';\n\nconst RenderersLayer = Layer.mergeAll(FlightRenderer.layer, HtmlRenderer.layer).pipe(\n Layer.provide(FlightHtmlInjector.layer),\n);\n\nconst StaticAssetsLayer = Layer.unwrap(\n Effect.map(ServerConfig, ({ clientAssetsCacheControl, clientAssetsRoot }) =>\n HttpStaticServer.layer({\n cacheControl: clientAssetsCacheControl,\n prefix: FrameworkAssetNamespace,\n root: clientAssetsRoot,\n }).pipe(Layer.provide(HttpRouter.disableLogger)),\n ),\n);\n\nconst PublicAssetsLayer = Layer.unwrap(\n Effect.map(ServerConfig, ({ publicAssetsRoot }) =>\n HttpStaticServer.layer({\n cacheControl: 'public, max-age=0',\n root: publicAssetsRoot,\n }),\n ),\n);\n\n// Bun derives `development` from NODE_ENV, which `ersc start` does not set, and its error page\n// carries the failure message and source stack.\nconst BunServerLayer = Layer.unwrap(\n Effect.map(ServerConfig, ({ hostname, port }) =>\n BunHttpServer.layer({\n development: false,\n hostname,\n idleTimeout: ApplicationIdleTimeoutSeconds,\n maxRequestBodySize: ApplicationMaxRequestBodySizeBytes,\n port,\n }),\n ),\n);\n\nconst EmptyEncodedPageParams: EncodedPageParams = Object.freeze({});\nconst DynamicResponseHeaders = {\n 'cache-control': 'private, no-store',\n} as const;\n\nconst appendAcceptVary = (vary: string | undefined) => {\n if (vary === undefined || vary.trim() === '') {\n return 'Accept';\n }\n\n const fields = vary.split(',').map((field) => field.trim().toLowerCase());\n return fields.includes('*') || fields.includes('accept') ? vary : `${vary}, Accept`;\n};\n\nconst acceptVaryPreResponseHandler: HttpEffect.PreResponseHandler = (_request, response) =>\n Effect.succeed(\n HttpServerResponse.setHeader(response, 'vary', appendAcceptVary(response.headers['vary'])),\n );\n\ntype RenderOptions<Services> = RequestOutcome & {\n readonly destination: CompiledDestination<Services>;\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly request: HttpServerRequest.HttpServerRequest;\n};\n\nconst fromWebStream = (\n stream: ReadableStream<Uint8Array>,\n options?: { readonly releaseLockOnEnd?: boolean },\n) =>\n Stream.fromReadableStream({\n evaluate: () => stream,\n onError: (cause) => cause,\n releaseLockOnEnd: options?.releaseLockOnEnd,\n });\n\nconst combinePageMiddleware = <Services>(\n middleware: ReadonlyArray<AnyMiddleware<Services>>,\n last: AnyMiddleware<Services>,\n) =>\n middleware\n .slice(0, -1)\n .reduceRight(\n (combined, current) => combined.combine(getScopedHttpMiddleware(current)),\n getScopedHttpMiddleware(last),\n );\n\ntype HttpApplicationRequirements =\n | ServerConfig\n | Layer.Services<ReturnType<typeof HttpStaticServer.layer>>\n | HttpRouter.Request.From<'Error', HtmlRenderError | ServerFnRequestFailure>;\n\nexport type HttpApplicationLayer<ApplicationError> = Layer.Layer<\n never,\n ApplicationError | PlatformError,\n HttpApplicationRequirements\n>;\n\nexport type ServerApplicationLayer<ApplicationError> = Layer.Layer<\n never,\n ApplicationError | PlatformError,\n ServerConfig\n>;\n\nconst httpLayer = <Services, ApplicationError>(\n application: ApplicationDefinition<Services, ApplicationError>,\n): HttpApplicationLayer<ApplicationError> => {\n const applicationState = getApplicationState(application);\n const identity = getERSCIdentity(application);\n const render = Effect.fnUntraced(function* ({\n destination,\n formState,\n middleware,\n request,\n serverFnResult,\n status,\n temporaryReferences,\n }: RenderOptions<Services>) {\n const requestUrl = HttpServerRequest.toURL(request);\n if (Option.isNone(requestUrl) || !isAbsolutePath(requestUrl.value.pathname)) {\n return yield* Effect.die(\n new TypeError(`Expected request URL \"${request.originalUrl}\" to contain an absolute path.`),\n );\n }\n\n const pathname = requestUrl.value.pathname;\n const encodedParams = yield* destination.page.paramsSchema === null\n ? Effect.succeed(EmptyEncodedPageParams)\n : HttpRouter.params;\n const renderResponse = Effect.fnUntraced(function* (params: PageParams) {\n const routeTree = renderRouteTree({\n destination,\n params,\n pathname,\n });\n const flightRenderer = yield* FlightRenderer;\n const flight = yield* flightRenderer.render({\n formState,\n middleware,\n renderRuntime: identity.renderRuntime,\n routeTree,\n serverFnResult,\n temporaryReferences,\n });\n\n if (request.headers['accept'] === FlightMediaType) {\n return HttpServerResponse.stream(\n fromWebStream(flight.stream, { releaseLockOnEnd: true }).pipe(\n Stream.ensuring(flight.release),\n ),\n {\n contentType: `${FlightMediaType};charset=utf-8`,\n headers: {\n ...DynamicResponseHeaders,\n 'content-location': requestUrl.value.href,\n },\n status,\n },\n );\n }\n\n const htmlRenderer = yield* HtmlRenderer;\n const htmlStream = yield* htmlRenderer\n .render({ flight, formState })\n .pipe(Effect.onError(() => flight.release));\n\n return HttpServerResponse.stream(\n fromWebStream(htmlStream).pipe(Stream.ensuring(flight.release)),\n {\n contentType: 'text/html;charset=utf-8',\n headers: DynamicResponseHeaders,\n status,\n },\n );\n });\n\n if (request.method !== 'POST' && destination.page.paramsSchema !== null) {\n return yield* Schema.decodeEffect(destination.page.paramsSchema)(encodedParams).pipe(\n Effect.matchEffect({\n onFailure: () =>\n Effect.succeed(\n HttpServerResponse.empty({ status: 404, headers: DynamicResponseHeaders }),\n ),\n onSuccess: (value) => renderResponse({ _tag: 'Decoded', value }),\n }),\n );\n }\n return yield* renderResponse({ _tag: 'Encoded', value: encodedParams });\n });\n\n const executeServerFnAndRefresh = (\n prepared: PreparedServerFnRequest<Services>,\n destination: CompiledDestination<Services>,\n request: HttpServerRequest.HttpServerRequest,\n ) => {\n const refreshMiddleware = destination.middleware.filter(\n (middleware) => !prepared.middleware.includes(middleware),\n );\n const renderMiddleware =\n refreshMiddleware.length === 0\n ? prepared.middleware\n : Object.freeze([...prepared.middleware, ...refreshMiddleware]);\n const response = prepared.execute.pipe(\n Effect.flatMap((outcome) => {\n const refresh = render({\n ...outcome,\n destination,\n middleware: renderMiddleware,\n request,\n });\n return applyMiddleware(refreshMiddleware, refresh);\n }),\n );\n\n return applyMiddleware(prepared.middleware, response);\n };\n\n const RequestLayer = Layer.mergeAll(RenderersLayer, applicationState.layer);\n const ApplicationRoutesLayer = Layer.unwrap(\n Effect.map(Effect.context<Services | FlightRenderer | HtmlRenderer>(), (requestContext) => {\n const RequestContextMiddleware = HttpRouter.middleware<{\n provides: Services | FlightRenderer | HtmlRenderer;\n }>()((httpEffect): Effect.Effect<HttpServerResponse.HttpServerResponse, Types.unhandled> =>\n httpEffect.pipe(Effect.provideContext(requestContext)),\n );\n const makeRouteLayer = (destination: CompiledDestination<Services>) => {\n const GetLayer = HttpRouter.add('GET', destination.pattern, (request) =>\n render({\n destination,\n formState: null,\n middleware: destination.middleware,\n request,\n serverFnResult: null,\n status: 200,\n }).pipe(HttpEffect.withPreResponseHandler(acceptVaryPreResponseHandler)),\n );\n const lastPageMiddleware = destination.middleware.at(-1);\n const PageMiddleware =\n lastPageMiddleware === undefined\n ? RequestContextMiddleware\n : combinePageMiddleware(destination.middleware, lastPageMiddleware).combine(\n RequestContextMiddleware,\n );\n const PageLayer = GetLayer.pipe(Layer.provide(PageMiddleware.layer));\n const ServerFnLayer = HttpRouter.add('POST', destination.pattern, (request) =>\n prepareServerFnRequest(request, identity).pipe(\n Effect.flatMap((prepared) => executeServerFnAndRefresh(prepared, destination, request)),\n Effect.catchTag('ServerFnRequestError', (error) =>\n Effect.succeed(\n HttpServerResponse.text(error.message, {\n headers: DynamicResponseHeaders,\n status: error.status,\n }),\n ),\n ),\n HttpEffect.withPreResponseHandler(acceptVaryPreResponseHandler),\n ),\n ).pipe(Layer.provide(RequestContextMiddleware.layer));\n\n return Layer.mergeAll(PageLayer, ServerFnLayer);\n };\n const [firstDestination, ...remainingDestinations] = applicationState.routes;\n return Layer.mergeAll(\n makeRouteLayer(firstDestination),\n ...remainingDestinations.map(makeRouteLayer),\n );\n }),\n ).pipe(Layer.provide(RequestLayer));\n\n return Layer.mergeAll(StaticAssetsLayer, PublicAssetsLayer).pipe(\n Layer.provideMerge(ApplicationRoutesLayer),\n );\n};\n\nconst serverLayer = <Services, ApplicationError>(\n application: ApplicationDefinition<Services, ApplicationError>,\n): ServerApplicationLayer<ApplicationError> =>\n HttpRouter.serve(httpLayer(application)).pipe(Layer.provide(BunServerLayer));\n\nexport const ServerApplication = { httpLayer, serverLayer };\n"],"names":["BunHttpServer","Effect","Layer","Option","Schema","Stream","HttpEffect","HttpRouter","HttpServerRequest","HttpServerResponse","HttpStaticServer","getApplicationState","getERSCIdentity","applyMiddleware","getScopedHttpMiddleware","FrameworkAssetNamespace","isAbsolutePath","FlightMediaType","renderRouteTree","FlightHtmlInjector","FlightRenderer","HtmlRenderer","ApplicationIdleTimeoutSeconds","ApplicationMaxRequestBodySizeBytes","ServerConfig","prepareServerFnRequest","RenderersLayer","StaticAssetsLayer","clientAssetsCacheControl","clientAssetsRoot","PublicAssetsLayer","publicAssetsRoot","BunServerLayer","hostname","port","EmptyEncodedPageParams","Object","DynamicResponseHeaders","appendAcceptVary","vary","undefined","fields","field","acceptVaryPreResponseHandler","_request","response","fromWebStream","stream","options","cause","combinePageMiddleware","middleware","last","combined","current","httpLayer","application","applicationState","identity","render","destination","formState","request","serverFnResult","status","temporaryReferences","requestUrl","TypeError","pathname","encodedParams","renderResponse","params","routeTree","flightRenderer","flight","htmlRenderer","htmlStream","value","executeServerFnAndRefresh","prepared","refreshMiddleware","renderMiddleware","outcome","refresh","RequestLayer","ApplicationRoutesLayer","requestContext","RequestContextMiddleware","httpEffect","makeRouteLayer","GetLayer","lastPageMiddleware","PageMiddleware","PageLayer","ServerFnLayer","error","firstDestination","remainingDestinations","serverLayer","ServerApplication"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAoE;AACO;AAQ7C;AAE8D;AAC7B;AAK5B;AAGiD;AACpC;AACW;AACD;AACP;AACa;AAMvC;AAKI;AAE7B,MAAM0B,cAAcA,GAAGxB,cAAc,CAACkB,oBAAoB,EAAEC,kBAAkB,EAAE,IAAI,CAClFnB,aAAa,CAACiB,wBAAwB;AAGxC,MAAMQ,iBAAiBA,GAAGzB,YAAY,CACpCD,UAAU,CAACuB,YAAYA,EAAE,CAAC,EAAEI,wBAAwB,EAAEC,gBAAgB,EAAE,GACtEnB,sBAAsB,CAAC;QACrB,cAAckB;QACd,QAAQb,uBAAuBA;QAC/B,MAAMc;IACR,GAAG,IAAI,CAAC3B,aAAa,CAACK,wBAAwB;AAIlD,MAAMuB,iBAAiBA,GAAG5B,YAAY,CACpCD,UAAU,CAACuB,YAAYA,EAAE,CAAC,EAAEO,gBAAgB,EAAE,GAC5CrB,sBAAsB,CAAC;QACrB,cAAc;QACd,MAAMqB;IACR;AAIJ,+FAA+F;AAC/F,gDAAgD;AAChD,MAAMC,cAAcA,GAAG9B,YAAY,CACjCD,UAAU,CAACuB,YAAYA,EAAE,CAAC,EAAES,QAAQ,EAAEC,IAAI,EAAE,GAC1ClC,mEAAmB,CAAC;QAClB,aAAa;QACbiC;QACA,aAAaX,6BAA6BA;QAC1C,oBAAoBC,kCAAkCA;QACtDW;IACF;AAIJ,MAAMC,sBAAsBA,GAAsBC,OAAO,MAAM,CAAC,CAAC;AACjE,MAAMC,sBAAsBA,GAAG;IAC7B,iBAAiB;AACnB;AAEA,MAAMC,gBAAgBA,GAAG,CAACC;IACxB,IAAIA,SAASC,aAAaD,KAAK,IAAI,OAAO,IAAI;QAC5C,OAAO;IACT;IAEA,MAAME,SAASF,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAACG,QAAUA,MAAM,IAAI,GAAG,WAAW;IACtE,OAAOD,OAAO,QAAQ,CAAC,QAAQA,OAAO,QAAQ,CAAC,YAAYF,OAAO,GAAGA,KAAK,QAAQ,CAAC;AACrF;AAEA,MAAMI,4BAA4BA,GAAkC,CAACC,UAAUC,WAC7E5C,cAAc,CACZQ,4BAA4B,CAACoC,UAAU,QAAQP,gBAAgBA,CAACO,SAAS,OAAO,CAAC,OAAO;AAS5F,MAAMC,aAAaA,GAAG,CACpBC,QACAC,UAEA3C,yBAAyB,CAAC;QACxB,UAAU,IAAM0C;QAChB,SAAS,CAACE,QAAUA;QACpB,kBAAkBD,SAAS;IAC7B;AAEF,MAAME,qBAAqBA,GAAG,CAC5BC,YACAC,OAEAD,WACG,KAAK,CAAC,GAAG,CAAC,GACV,WAAW,CACV,CAACE,UAAUC,UAAYD,SAAS,OAAO,CAACvC,uBAAuBA,CAACwC,WAChExC,uBAAuBA,CAACsC;AAoB9B,MAAMG,SAASA,GAAG,CAChBC;IAEA,MAAMC,mBAAmB9C,mBAAmBA,CAAC6C;IAC7C,MAAME,WAAW9C,eAAeA,CAAC4C;IACjC,MAAMG,SAAS1D,iBAAiB,CAAC,UAAW,EAC1C2D,WAAW,EACXC,SAAS,EACTV,UAAU,EACVW,OAAO,EACPC,cAAc,EACdC,MAAM,EACNC,mBAAmB,EACK;QACxB,MAAMC,aAAa1D,uBAAuB,CAACsD;QAC3C,IAAI3D,aAAa,CAAC+D,eAAe,CAAClD,cAAcA,CAACkD,WAAW,KAAK,CAAC,QAAQ,GAAG;YAC3E,OAAO,OAAOjE,UAAU,CACtB,IAAIkE,UAAU,CAAC,sBAAsB,EAAEL,QAAQ,WAAW,CAAC,8BAA8B,CAAC;QAE9F;QAEA,MAAMM,WAAWF,WAAW,KAAK,CAAC,QAAQ;QAC1C,MAAMG,gBAAgB,OAAOT,YAAY,IAAI,CAAC,YAAY,KAAK,OAC3D3D,cAAc,CAACkC,sBAAsBA,IACrC5B,iBAAiB;QACrB,MAAM+D,iBAAiBrE,iBAAiB,CAAC,UAAWsE,MAAkB;YACpE,MAAMC,YAAYtD,eAAeA,CAAC;gBAChC0C;gBACAW;gBACAH;YACF;YACA,MAAMK,iBAAiB,OAAOrD,cAAcA;YAC5C,MAAMsD,SAAS,OAAOD,eAAe,MAAM,CAAC;gBAC1CZ;gBACAV;gBACA,eAAeO,SAAS,aAAa;gBACrCc;gBACAT;gBACAE;YACF;YAEA,IAAIH,QAAQ,OAAO,CAAC,SAAS,KAAK7C,eAAeA,EAAE;gBACjD,OAAOR,yBAAyB,CAC9BqC,aAAaA,CAAC4B,OAAO,MAAM,EAAE;oBAAE,kBAAkB;gBAAK,GAAG,IAAI,CAC3DrE,eAAe,CAACqE,OAAO,OAAO,IAEhC;oBACE,aAAa,GAAGzD,eAAeA,CAAC,cAAc,CAAC;oBAC/C,SAAS;wBACP,GAAGoB,sBAAsB;wBACzB,oBAAoB6B,WAAW,KAAK,CAAC,IAAI;oBAC3C;oBACAF;gBACF;YAEJ;YAEA,MAAMW,eAAe,OAAOtD,YAAYA;YACxC,MAAMuD,aAAa,OAAOD,aACvB,MAAM,CAAC;gBAAED;gBAAQb;YAAU,GAC3B,IAAI,CAAC5D,cAAc,CAAC,IAAMyE,OAAO,OAAO;YAE3C,OAAOjE,yBAAyB,CAC9BqC,aAAaA,CAAC8B,YAAY,IAAI,CAACvE,eAAe,CAACqE,OAAO,OAAO,IAC7D;gBACE,aAAa;gBACb,SAASrC,sBAAsBA;gBAC/B2B;YACF;QAEJ;QAEA,IAAIF,QAAQ,MAAM,KAAK,UAAUF,YAAY,IAAI,CAAC,YAAY,KAAK,MAAM;YACvE,OAAO,OAAOxD,mBAAmB,CAACwD,YAAY,IAAI,CAAC,YAAY,EAAES,eAAe,IAAI,CAClFpE,kBAAkB,CAAC;gBACjB,WAAW,IACTA,cAAc,CACZQ,wBAAwB,CAAC;wBAAE,QAAQ;wBAAK,SAAS4B,sBAAsBA;oBAAC;gBAE5E,WAAW,CAACwC,QAAUP,eAAe;wBAAE,MAAM;wBAAWO;oBAAM;YAChE;QAEJ;QACA,OAAO,OAAOP,eAAe;YAAE,MAAM;YAAW,OAAOD;QAAc;IACvE;IAEA,MAAMS,4BAA4B,CAChCC,UACAnB,aACAE;QAEA,MAAMkB,oBAAoBpB,YAAY,UAAU,CAAC,MAAM,CACrD,CAACT,aAAe,CAAC4B,SAAS,UAAU,CAAC,QAAQ,CAAC5B;QAEhD,MAAM8B,mBACJD,kBAAkB,MAAM,KAAK,IACzBD,SAAS,UAAU,GACnB3C,OAAO,MAAM,CAAC;eAAI2C,SAAS,UAAU;eAAKC;SAAkB;QAClE,MAAMnC,WAAWkC,SAAS,OAAO,CAAC,IAAI,CACpC9E,cAAc,CAAC,CAACiF;YACd,MAAMC,UAAUxB,OAAO;gBACrB,GAAGuB,OAAO;gBACVtB;gBACA,YAAYqB;gBACZnB;YACF;YACA,OAAOjD,eAAeA,CAACmE,mBAAmBG;QAC5C;QAGF,OAAOtE,eAAeA,CAACkE,SAAS,UAAU,EAAElC;IAC9C;IAEA,MAAMuC,eAAelF,cAAc,CAACwB,cAAcA,EAAE+B,iBAAiB,KAAK;IAC1E,MAAM4B,yBAAyBnF,YAAY,CACzCD,UAAU,CAACA,cAAc,IAA8C,CAACqF;QACtE,MAAMC,2BAA2BhF,qBAAqB,GAEjD,CAACiF,aACJA,WAAW,IAAI,CAACvF,qBAAqB,CAACqF;QAExC,MAAMG,iBAAiB,CAAC7B;YACtB,MAAM8B,WAAWnF,cAAc,CAAC,OAAOqD,YAAY,OAAO,EAAE,CAACE,UAC3DH,OAAO;oBACLC;oBACA,WAAW;oBACX,YAAYA,YAAY,UAAU;oBAClCE;oBACA,gBAAgB;oBAChB,QAAQ;gBACV,GAAG,IAAI,CAACxD,iCAAiC,CAACqC,4BAA4BA;YAExE,MAAMgD,qBAAqB/B,YAAY,UAAU,CAAC,EAAE,CAAC,CAAC;YACtD,MAAMgC,iBACJD,uBAAuBnD,YACnB+C,2BACArC,qBAAqBA,CAACU,YAAY,UAAU,EAAE+B,oBAAoB,OAAO,CACvEJ;YAER,MAAMM,YAAYH,SAAS,IAAI,CAACxF,aAAa,CAAC0F,eAAe,KAAK;YAClE,MAAME,gBAAgBvF,cAAc,CAAC,QAAQqD,YAAY,OAAO,EAAE,CAACE,UACjErC,sBAAsBA,CAACqC,SAASJ,UAAU,IAAI,CAC5CzD,cAAc,CAAC,CAAC8E,WAAaD,0BAA0BC,UAAUnB,aAAaE,WAC9E7D,eAAe,CAAC,wBAAwB,CAAC8F,QACvC9F,cAAc,CACZQ,uBAAuB,CAACsF,MAAM,OAAO,EAAE;wBACrC,SAAS1D,sBAAsBA;wBAC/B,QAAQ0D,MAAM,MAAM;oBACtB,MAGJzF,iCAAiC,CAACqC,4BAA4BA,IAEhE,IAAI,CAACzC,aAAa,CAACqF,yBAAyB,KAAK;YAEnD,OAAOrF,cAAc,CAAC2F,WAAWC;QACnC;QACA,MAAM,CAACE,kBAAkB,GAAGC,sBAAsB,GAAGxC,iBAAiB,MAAM;QAC5E,OAAOvD,cAAc,CACnBuF,eAAeO,sBACZC,sBAAsB,GAAG,CAACR;IAEjC,IACA,IAAI,CAACvF,aAAa,CAACkF;IAErB,OAAOlF,cAAc,CAACyB,iBAAiBA,EAAEG,iBAAiBA,EAAE,IAAI,CAC9D5B,kBAAkB,CAACmF;AAEvB;AAEA,MAAMa,WAAWA,GAAG,CAClB1C,cAEAjD,gBAAgB,CAACgD,SAASA,CAACC,cAAc,IAAI,CAACtD,aAAa,CAAC8B,cAAcA;AAErE,MAAMmE,iBAAiBA,GAAG;IAAE5C,oBAASA;IAAE2C,wBAAWA;AAAC,EAAE"}
|
|
1
|
+
{"version":3,"file":"server/application.js","sources":["../../src/server/application.ts"],"sourcesContent":["import * as BunHttpServer from '@effect/platform-bun/BunHttpServer';\nimport * as BunStream from '@effect/platform-bun/BunStream';\nimport { Effect, Layer, Option, Schema, Stream, type Types } from 'effect';\nimport type { PlatformError } from 'effect/PlatformError';\nimport {\n HttpEffect,\n HttpRouter,\n HttpServerRequest,\n HttpServerResponse,\n HttpStaticServer,\n} from 'effect/unstable/http';\nimport type { ServeError } from 'effect/unstable/http/HttpServerError';\n\nimport { type ApplicationDefinition, getApplicationState } from '../application/definition';\nimport { getERSCIdentity } from '../application/ersc-identity';\nimport {\n applyMiddleware,\n type AnyMiddleware,\n getScopedHttpMiddleware,\n} from '../application/middleware';\nimport type { EncodedPageParams, PageParams } from '../application/page';\nimport type { CompiledDestination } from '../application/route-graph';\nimport { FrameworkAssetNamespace, isAbsolutePath } from '../application/route-path';\nimport { FlightMediaType } from '../rsc/flight';\nimport { renderRouteTree } from '../rsc/render-route-tree';\nimport { FlightHtmlInjector } from './flight-html-stream';\nimport { FlightRenderer } from './flight-renderer';\nimport { HtmlRenderError, HtmlRenderer } from './html-renderer';\nimport type { RequestOutcome } from './request-outcome';\nimport {\n ApplicationIdleTimeoutSeconds,\n ApplicationMaxRequestBodySizeBytes,\n ServerConfig,\n} from './server-config';\nimport {\n prepareServerFnRequest,\n type PreparedServerFnRequest,\n type ServerFnRequestFailure,\n} from './server-fn-request';\n\nconst RenderersLayer = Layer.mergeAll(FlightRenderer.layer, HtmlRenderer.layer).pipe(\n Layer.provide(FlightHtmlInjector.layer),\n);\n\nconst StaticAssetsLayer = Layer.unwrap(\n Effect.map(ServerConfig, ({ clientAssetsCacheControl, clientAssetsRoot }) =>\n HttpStaticServer.layer({\n cacheControl: clientAssetsCacheControl,\n prefix: FrameworkAssetNamespace,\n root: clientAssetsRoot,\n }).pipe(Layer.provide(HttpRouter.disableLogger)),\n ),\n);\n\nconst PublicAssetsLayer = Layer.unwrap(\n Effect.map(ServerConfig, ({ publicAssetsRoot }) =>\n HttpStaticServer.layer({\n cacheControl: 'public, max-age=0',\n root: publicAssetsRoot,\n }),\n ),\n);\n\n// Bun derives `development` from NODE_ENV, which `ersc start` does not set, and its error page\n// carries the failure message and source stack.\nconst BunServerLayer = Layer.unwrap(\n Effect.map(ServerConfig, ({ hostname, port }) =>\n BunHttpServer.layer({\n development: false,\n hostname,\n idleTimeout: ApplicationIdleTimeoutSeconds,\n maxRequestBodySize: ApplicationMaxRequestBodySizeBytes,\n port,\n }),\n ),\n);\n\nconst EmptyEncodedPageParams: EncodedPageParams = Object.freeze({});\nconst DynamicResponseHeaders = {\n 'cache-control': 'private, no-store',\n} as const;\n\nconst appendAcceptVary = (vary: string | undefined) => {\n if (vary === undefined || vary.trim() === '') {\n return 'Accept';\n }\n\n const fields = vary.split(',').map((field) => field.trim().toLowerCase());\n return fields.includes('*') || fields.includes('accept') ? vary : `${vary}, Accept`;\n};\n\nconst acceptVaryPreResponseHandler: HttpEffect.PreResponseHandler = (_request, response) =>\n Effect.succeed(\n HttpServerResponse.setHeader(response, 'vary', appendAcceptVary(response.headers['vary'])),\n );\n\ntype RenderOptions<Services> = RequestOutcome & {\n readonly destination: CompiledDestination<Services>;\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly request: HttpServerRequest.HttpServerRequest;\n};\n\nconst fromWebStream = (\n stream: ReadableStream<Uint8Array>,\n options?: { readonly releaseLockOnEnd?: boolean },\n) =>\n BunStream.fromReadableStream({\n evaluate: () => stream,\n onError: (cause) => cause,\n releaseLockOnEnd: options?.releaseLockOnEnd,\n });\n\nconst combinePageMiddleware = <Services>(\n middleware: ReadonlyArray<AnyMiddleware<Services>>,\n last: AnyMiddleware<Services>,\n) =>\n middleware\n .slice(0, -1)\n .reduceRight(\n (combined, current) => combined.combine(getScopedHttpMiddleware(current)),\n getScopedHttpMiddleware(last),\n );\n\ntype HttpApplicationRequirements =\n | ServerConfig\n | Layer.Services<ReturnType<typeof HttpStaticServer.layer>>\n | HttpRouter.Request.From<'Error', HtmlRenderError | ServerFnRequestFailure>;\n\nexport type HttpApplicationLayer<ApplicationError> = Layer.Layer<\n never,\n ApplicationError | PlatformError,\n HttpApplicationRequirements\n>;\n\nexport type ServerApplicationLayer<ApplicationError> = Layer.Layer<\n never,\n HttpRouter.Request.Without<ApplicationError> | PlatformError | ServeError,\n ServerConfig\n>;\n\nconst httpLayer = <Services, ApplicationError>(\n application: ApplicationDefinition<Services, ApplicationError>,\n): HttpApplicationLayer<ApplicationError> => {\n const applicationState = getApplicationState(application);\n const identity = getERSCIdentity(application);\n const render = Effect.fnUntraced(function* ({\n destination,\n formState,\n middleware,\n request,\n serverFnResult,\n status,\n temporaryReferences,\n }: RenderOptions<Services>) {\n const requestUrl = HttpServerRequest.toURL(request);\n if (Option.isNone(requestUrl) || !isAbsolutePath(requestUrl.value.pathname)) {\n return yield* Effect.die(\n new TypeError(`Expected request URL \"${request.originalUrl}\" to contain an absolute path.`),\n );\n }\n\n const pathname = requestUrl.value.pathname;\n const encodedParams = yield* destination.page.paramsSchema === null\n ? Effect.succeed(EmptyEncodedPageParams)\n : HttpRouter.params;\n const renderResponse = Effect.fnUntraced(function* (params: PageParams) {\n const routeTree = renderRouteTree({\n destination,\n params,\n pathname,\n });\n const flightRenderer = yield* FlightRenderer;\n const flight = yield* flightRenderer.render({\n formState,\n middleware,\n renderRuntime: identity.renderRuntime,\n routeTree,\n serverFnResult,\n temporaryReferences,\n });\n\n if (request.headers['accept'] === FlightMediaType) {\n return HttpServerResponse.stream(\n fromWebStream(flight.stream, { releaseLockOnEnd: true }).pipe(\n Stream.ensuring(flight.release),\n ),\n {\n contentType: `${FlightMediaType};charset=utf-8`,\n headers: {\n ...DynamicResponseHeaders,\n },\n status,\n },\n );\n }\n\n const htmlRenderer = yield* HtmlRenderer;\n const htmlStream = yield* htmlRenderer\n .render({ flight, formState })\n .pipe(Effect.onError(() => flight.release));\n\n return HttpServerResponse.stream(\n fromWebStream(htmlStream).pipe(Stream.ensuring(flight.release)),\n {\n contentType: 'text/html;charset=utf-8',\n headers: DynamicResponseHeaders,\n status,\n },\n );\n });\n\n if (request.method !== 'POST' && destination.page.paramsSchema !== null) {\n return yield* Schema.decodeEffect(destination.page.paramsSchema)(encodedParams).pipe(\n Effect.matchEffect({\n onFailure: () =>\n Effect.succeed(\n HttpServerResponse.empty({ status: 404, headers: DynamicResponseHeaders }),\n ),\n onSuccess: (value) => renderResponse({ _tag: 'Decoded', value }),\n }),\n );\n }\n return yield* renderResponse({ _tag: 'Encoded', value: encodedParams });\n });\n\n const executeServerFnAndRefresh = (\n prepared: PreparedServerFnRequest<Services>,\n destination: CompiledDestination<Services>,\n request: HttpServerRequest.HttpServerRequest,\n ) => {\n const refreshMiddleware = destination.middleware.filter(\n (middleware) => !prepared.middleware.includes(middleware),\n );\n const renderMiddleware =\n refreshMiddleware.length === 0\n ? prepared.middleware\n : Object.freeze([...prepared.middleware, ...refreshMiddleware]);\n const response = prepared.execute.pipe(\n Effect.flatMap((outcome) => {\n const refresh = render({\n ...outcome,\n destination,\n middleware: renderMiddleware,\n request,\n });\n return applyMiddleware(refreshMiddleware, refresh);\n }),\n );\n\n return applyMiddleware(prepared.middleware, response);\n };\n\n const RequestLayer = Layer.mergeAll(RenderersLayer, applicationState.layer);\n const ApplicationRoutesLayer = Layer.unwrap(\n Effect.map(Layer.build(RequestLayer), (applicationServices) => {\n const RequestContextMiddleware = HttpRouter.middleware<{\n provides: Services | FlightRenderer | HtmlRenderer;\n }>()((httpEffect): Effect.Effect<HttpServerResponse.HttpServerResponse, Types.unhandled> =>\n httpEffect.pipe(Effect.provideContext(applicationServices)),\n );\n const makeRouteLayer = (destination: CompiledDestination<Services>) => {\n const GetLayer = HttpRouter.add('GET', destination.pattern, (request) =>\n render({\n destination,\n formState: null,\n middleware: destination.middleware,\n request,\n serverFnResult: null,\n status: 200,\n }).pipe(HttpEffect.withPreResponseHandler(acceptVaryPreResponseHandler)),\n );\n const lastPageMiddleware = destination.middleware.at(-1);\n const PageMiddleware =\n lastPageMiddleware === undefined\n ? RequestContextMiddleware\n : combinePageMiddleware(destination.middleware, lastPageMiddleware).combine(\n RequestContextMiddleware,\n );\n const PageLayer = GetLayer.pipe(Layer.provide(PageMiddleware.layer));\n const ServerFnLayer = HttpRouter.add('POST', destination.pattern, (request) =>\n prepareServerFnRequest(request, identity).pipe(\n Effect.flatMap((prepared) => executeServerFnAndRefresh(prepared, destination, request)),\n Effect.catchTag('ServerFnRequestError', (error) =>\n Effect.succeed(\n HttpServerResponse.text(error.message, {\n headers: DynamicResponseHeaders,\n status: error.status,\n }),\n ),\n ),\n HttpEffect.withPreResponseHandler(acceptVaryPreResponseHandler),\n ),\n ).pipe(Layer.provide(RequestContextMiddleware.layer));\n\n return Layer.mergeAll(PageLayer, ServerFnLayer);\n };\n const [firstDestination, ...remainingDestinations] = applicationState.routes;\n return Layer.mergeAll(\n makeRouteLayer(firstDestination),\n ...remainingDestinations.map(makeRouteLayer),\n );\n }),\n );\n\n return Layer.mergeAll(StaticAssetsLayer, PublicAssetsLayer).pipe(\n Layer.provideMerge(ApplicationRoutesLayer),\n );\n};\n\nconst serverLayer = <Services, ApplicationError>(\n application: ApplicationDefinition<Services, ApplicationError>,\n): ServerApplicationLayer<ApplicationError> =>\n HttpRouter.serve(httpLayer(application)).pipe(Layer.provide(BunServerLayer));\n\nexport const ServerApplication = { httpLayer, serverLayer };\n"],"names":["BunHttpServer","BunStream","Effect","Layer","Option","Schema","Stream","HttpEffect","HttpRouter","HttpServerRequest","HttpServerResponse","HttpStaticServer","getApplicationState","getERSCIdentity","applyMiddleware","getScopedHttpMiddleware","FrameworkAssetNamespace","isAbsolutePath","FlightMediaType","renderRouteTree","FlightHtmlInjector","FlightRenderer","HtmlRenderer","ApplicationIdleTimeoutSeconds","ApplicationMaxRequestBodySizeBytes","ServerConfig","prepareServerFnRequest","RenderersLayer","StaticAssetsLayer","clientAssetsCacheControl","clientAssetsRoot","PublicAssetsLayer","publicAssetsRoot","BunServerLayer","hostname","port","EmptyEncodedPageParams","Object","DynamicResponseHeaders","appendAcceptVary","vary","undefined","fields","field","acceptVaryPreResponseHandler","_request","response","fromWebStream","stream","options","cause","combinePageMiddleware","middleware","last","combined","current","httpLayer","application","applicationState","identity","render","destination","formState","request","serverFnResult","status","temporaryReferences","requestUrl","TypeError","pathname","encodedParams","renderResponse","params","routeTree","flightRenderer","flight","htmlRenderer","htmlStream","value","executeServerFnAndRefresh","prepared","refreshMiddleware","renderMiddleware","outcome","refresh","RequestLayer","ApplicationRoutesLayer","applicationServices","RequestContextMiddleware","httpEffect","makeRouteLayer","GetLayer","lastPageMiddleware","PageMiddleware","PageLayer","ServerFnLayer","error","firstDestination","remainingDestinations","serverLayer","ServerApplication"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Context, Effect, FiberSet, Layer, Schema } from "effect";
|
|
3
3
|
import { use } from "react";
|
|
4
|
+
import { preinit } from "react-dom";
|
|
4
5
|
import { renderToReadableStream } from "react-dom/server.bun";
|
|
5
6
|
import { createFromReadableStream } from "react-server-dom-rspack/client";
|
|
6
7
|
import { RouteTree } from "../client/route-tree.js";
|
|
@@ -23,6 +24,8 @@ import { ServerConfig } from "./server-config.js";
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
|
|
28
|
+
|
|
26
29
|
class HtmlRenderError extends Schema.TaggedError()('HtmlRenderError', {
|
|
27
30
|
cause: Schema.Defect()
|
|
28
31
|
}) {
|
|
@@ -38,22 +41,20 @@ class HtmlRenderer extends Context.Service()('ersc/server/html-renderer/HtmlRend
|
|
|
38
41
|
const [ssrFlightStream, browserFlightStream] = flight.stream.tee();
|
|
39
42
|
let payload = null;
|
|
40
43
|
function SsrRoot() {
|
|
44
|
+
// Emit CSS without server-only siblings that shift hydration's useId paths.
|
|
45
|
+
for (const href of clientStylesheets){
|
|
46
|
+
preinit(href, {
|
|
47
|
+
as: 'style',
|
|
48
|
+
precedence: 'default'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
41
51
|
const { routeTree } = use(payload ??= createFromReadableStream(ssrFlightStream));
|
|
42
52
|
return /*#__PURE__*/ jsx(RouteTree, {
|
|
43
53
|
root: routeTree
|
|
44
54
|
});
|
|
45
55
|
}
|
|
46
56
|
const htmlStream = yield* Effect.tryPromise({
|
|
47
|
-
try: ()=>renderToReadableStream(/*#__PURE__*/
|
|
48
|
-
children: [
|
|
49
|
-
clientStylesheets.map((href)=>/*#__PURE__*/ jsx("link", {
|
|
50
|
-
rel: "stylesheet",
|
|
51
|
-
href: href,
|
|
52
|
-
precedence: "default"
|
|
53
|
-
}, href)),
|
|
54
|
-
/*#__PURE__*/ jsx(SsrRoot, {})
|
|
55
|
-
]
|
|
56
|
-
}), {
|
|
57
|
+
try: ()=>renderToReadableStream(/*#__PURE__*/ jsx(SsrRoot, {}), {
|
|
57
58
|
bootstrapScripts: [
|
|
58
59
|
...clientBootstrapScripts
|
|
59
60
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server/html-renderer.js","sources":["../../src/server/html-renderer.tsx"],"sourcesContent":["import { Context, Effect, FiberSet, Layer, Schema, type Scope } from 'effect';\nimport { use } from 'react';\nimport { renderToReadableStream } from 'react-dom/server.bun';\nimport { createFromReadableStream } from 'react-server-dom-rspack/client';\n\nimport { RouteTree } from '../client/route-tree';\nimport type { FlightPayload } from '../rsc/flight';\nimport { FlightHtmlInjector } from './flight-html-stream';\nimport type { FlightRender } from './flight-renderer';\nimport { ServerConfig } from './server-config';\n\ntype HtmlStream = ReadableStream<Uint8Array>;\n\nexport class HtmlRenderError extends Schema.TaggedError<HtmlRenderError>()('HtmlRenderError', {\n cause: Schema.Defect(),\n}) {}\n\nexport class HtmlRenderer extends Context.Service<HtmlRenderer>()(\n 'ersc/server/html-renderer/HtmlRenderer',\n {\n make: Effect.gen(function* () {\n const { clientBootstrapScripts, clientStylesheets } = yield* ServerConfig;\n const flightHtmlInjector = yield* FlightHtmlInjector;\n\n return {\n render: Effect.fn('HtmlRenderer.render')(function* ({\n flight,\n formState,\n }: {\n readonly flight: FlightRender;\n readonly formState: FlightPayload['formState'];\n }): Effect.fn.Return<HtmlStream, HtmlRenderError, Scope.Scope> {\n const signal = yield* Effect.abortSignal;\n const runtime = yield* FiberSet.makeRuntimePromise<never>();\n const [ssrFlightStream, browserFlightStream] = flight.stream.tee();\n let payload: PromiseLike<FlightPayload> | null = null;\n\n function SsrRoot() {\n const { routeTree } = use(\n (payload ??= createFromReadableStream<FlightPayload>(ssrFlightStream)),\n );\n return <RouteTree root={routeTree} />;\n }\n\n const htmlStream = yield* Effect.tryPromise({\n try: () =>\n renderToReadableStream(
|
|
1
|
+
{"version":3,"file":"server/html-renderer.js","sources":["../../src/server/html-renderer.tsx"],"sourcesContent":["import { Context, Effect, FiberSet, Layer, Schema, type Scope } from 'effect';\nimport { use } from 'react';\nimport { preinit } from 'react-dom';\nimport { renderToReadableStream } from 'react-dom/server.bun';\nimport { createFromReadableStream } from 'react-server-dom-rspack/client';\n\nimport { RouteTree } from '../client/route-tree';\nimport type { FlightPayload } from '../rsc/flight';\nimport { FlightHtmlInjector } from './flight-html-stream';\nimport type { FlightRender } from './flight-renderer';\nimport { ServerConfig } from './server-config';\n\ntype HtmlStream = ReadableStream<Uint8Array>;\n\nexport class HtmlRenderError extends Schema.TaggedError<HtmlRenderError>()('HtmlRenderError', {\n cause: Schema.Defect(),\n}) {}\n\nexport class HtmlRenderer extends Context.Service<HtmlRenderer>()(\n 'ersc/server/html-renderer/HtmlRenderer',\n {\n make: Effect.gen(function* () {\n const { clientBootstrapScripts, clientStylesheets } = yield* ServerConfig;\n const flightHtmlInjector = yield* FlightHtmlInjector;\n\n return {\n render: Effect.fn('HtmlRenderer.render')(function* ({\n flight,\n formState,\n }: {\n readonly flight: FlightRender;\n readonly formState: FlightPayload['formState'];\n }): Effect.fn.Return<HtmlStream, HtmlRenderError, Scope.Scope> {\n const signal = yield* Effect.abortSignal;\n const runtime = yield* FiberSet.makeRuntimePromise<never>();\n const [ssrFlightStream, browserFlightStream] = flight.stream.tee();\n let payload: PromiseLike<FlightPayload> | null = null;\n\n function SsrRoot() {\n // Emit CSS without server-only siblings that shift hydration's useId paths.\n for (const href of clientStylesheets) {\n preinit(href, { as: 'style', precedence: 'default' });\n }\n const { routeTree } = use(\n (payload ??= createFromReadableStream<FlightPayload>(ssrFlightStream)),\n );\n return <RouteTree root={routeTree} />;\n }\n\n const htmlStream = yield* Effect.tryPromise({\n try: () =>\n renderToReadableStream(<SsrRoot />, {\n bootstrapScripts: [...clientBootstrapScripts],\n formState,\n onError: (error, errorInfo) => {\n if (!signal.aborted && !flight.signal.aborted) {\n void runtime(\n Effect.logError('HTML render failed.', error, errorInfo.componentStack),\n );\n }\n },\n signal,\n }),\n catch: (cause) => new HtmlRenderError({ cause }),\n });\n\n return htmlStream.pipeThrough(flightHtmlInjector.inject(browserFlightStream));\n }),\n };\n }),\n },\n) {\n static readonly layer = Layer.effect(this, this.make);\n}\n"],"names":["Context","Effect","FiberSet","Layer","Schema","use","preinit","renderToReadableStream","createFromReadableStream","RouteTree","FlightHtmlInjector","ServerConfig","HtmlRenderError","HtmlRenderer","clientBootstrapScripts","clientStylesheets","flightHtmlInjector","flight","formState","signal","runtime","ssrFlightStream","browserFlightStream","payload","SsrRoot","href","routeTree","htmlStream","error","errorInfo","cause"],"mappings":";;;;;;;;;;;;;;;;;;;;AAA8E;AAClD;AACQ;AAC0B;AACY;AAEzB;AAES;AAEX;AAIxC,MAAMY,eAAeA,SAASR,kBAAkB,GAAoB,mBAAmB;IAC5F,OAAOA,aAAa;AACtB;AAAI;AAEG,MAAMS,YAAYA,SAASb,eAAe,GAC/C,0CACA;IACE,MAAMC,UAAU,CAAC;QACf,MAAM,EAAEa,sBAAsB,EAAEC,iBAAiB,EAAE,GAAG,OAAOJ,YAAYA;QACzE,MAAMK,qBAAqB,OAAON,kBAAkBA;QAEpD,OAAO;YACL,QAAQT,SAAS,CAAC,uBAAuB,UAAW,EAClDgB,MAAM,EACNC,SAAS,EAIV;gBACC,MAAMC,SAAS,OAAOlB,kBAAkB;gBACxC,MAAMmB,UAAU,OAAOlB,2BAA2B;gBAClD,MAAM,CAACmB,iBAAiBC,oBAAoB,GAAGL,OAAO,MAAM,CAAC,GAAG;gBAChE,IAAIM,UAA6C;gBAEjD,SAASC;oBACP,4EAA4E;oBAC5E,KAAK,MAAMC,QAAQV,kBAAmB;wBACpCT,OAAOA,CAACmB,MAAM;4BAAE,IAAI;4BAAS,YAAY;wBAAU;oBACrD;oBACA,MAAM,EAAEC,SAAS,EAAE,GAAGrB,GAAGA,CACtBkB,YAAYf,wBAAwBA,CAAgBa;oBAEvD,qBAAO,IAACZ,SAASA;wBAAC,MAAMiB;;gBAC1B;gBAEA,MAAMC,aAAa,OAAO1B,iBAAiB,CAAC;oBAC1C,KAAK,IACHM,sBAAsBA,eAAC,IAACiB,cAAY;4BAClC,kBAAkB;mCAAIV;6BAAuB;4BAC7CI;4BACA,SAAS,CAACU,OAAOC;gCACf,IAAI,CAACV,OAAO,OAAO,IAAI,CAACF,OAAO,MAAM,CAAC,OAAO,EAAE;oCAC7C,KAAKG,QACHnB,eAAe,CAAC,uBAAuB2B,OAAOC,UAAU,cAAc;gCAE1E;4BACF;4BACAV;wBACF;oBACF,OAAO,CAACW,QAAU,IAAIlB,eAAeA,CAAC;4BAAEkB;wBAAM;gBAChD;gBAEA,OAAOH,WAAW,WAAW,CAACX,mBAAmB,MAAM,CAACM;YAC1D;QACF;IACF;AACF;IAEA,OAAgB,QAAQnB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACxD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
export type StartOptions = {
|
|
3
|
+
readonly hostname: string;
|
|
4
|
+
readonly port: number;
|
|
5
|
+
readonly root: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const serve: (options: StartOptions) => Effect.Effect<void, import("../build/compiled-server.js").CompiledServerError | import("effect/Types").unhandled, import("effect/Scope").Scope>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Effect, Layer } from "effect";
|
|
2
|
+
import { loadCompiledServer, makeRunnableServerLayer } from "../build/compiled-server.js";
|
|
3
|
+
import { EnvironmentConfig } from "../build/contract.js";
|
|
4
|
+
|
|
5
|
+
import * as __rspack_external__effect_platform_bun_BunServices_112addf2 from "@effect/platform-bun/BunServices";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const resolveServerLayer = Effect.fnUntraced(function*({ hostname, port, root }) {
|
|
15
|
+
const bundle = yield* loadCompiledServer(root);
|
|
16
|
+
return yield* makeRunnableServerLayer({
|
|
17
|
+
bundle,
|
|
18
|
+
clientAssetsCacheControl: EnvironmentConfig.production.clientAssetsCacheControl,
|
|
19
|
+
clientOutputDir: EnvironmentConfig.production.clientOutputDir,
|
|
20
|
+
hostname,
|
|
21
|
+
port,
|
|
22
|
+
root
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
const serve = Effect.fn('ersc/server/serve')(function*(options) {
|
|
26
|
+
yield* Layer.build(Layer.unwrap(resolveServerLayer(options)).pipe(Layer.provide(__rspack_external__effect_platform_bun_BunServices_112addf2.layer)));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export { serve };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server/serve.js","sources":["../../src/server/serve.ts"],"sourcesContent":["import * as BunServices from '@effect/platform-bun/BunServices';\nimport { Effect, Layer } from 'effect';\n\nimport { loadCompiledServer, makeRunnableServerLayer } from '../build/compiled-server';\nimport { EnvironmentConfig } from '../build/contract';\n\nexport type StartOptions = {\n readonly hostname: string;\n readonly port: number;\n readonly root: string;\n};\n\nconst resolveServerLayer = Effect.fnUntraced(function* ({ hostname, port, root }: StartOptions) {\n const bundle = yield* loadCompiledServer(root);\n return yield* makeRunnableServerLayer({\n bundle,\n clientAssetsCacheControl: EnvironmentConfig.production.clientAssetsCacheControl,\n clientOutputDir: EnvironmentConfig.production.clientOutputDir,\n hostname,\n port,\n root,\n });\n});\n\nexport const serve = Effect.fn('ersc/server/serve')(function* (options: StartOptions) {\n yield* Layer.build(\n Layer.unwrap(resolveServerLayer(options)).pipe(Layer.provide(BunServices.layer)),\n );\n});\n"],"names":["BunServices","Effect","Layer","loadCompiledServer","makeRunnableServerLayer","EnvironmentConfig","resolveServerLayer","hostname","port","root","bundle","serve","options"],"mappings":";;;;;;;;;AAAgE;AACzB;AAEgD;AACjC;AAQtD,MAAMM,kBAAkBA,GAAGL,iBAAiB,CAAC,UAAW,EAAEM,QAAQ,EAAEC,IAAI,EAAEC,IAAI,EAAgB;IAC5F,MAAMC,SAAS,OAAOP,kBAAkBA,CAACM;IACzC,OAAO,OAAOL,uBAAuBA,CAAC;QACpCM;QACA,0BAA0BL,qDAAqD;QAC/E,iBAAiBA,4CAA4C;QAC7DE;QACAC;QACAC;IACF;AACF;AAEO,MAAME,KAAKA,GAAGV,SAAS,CAAC,qBAAqB,UAAWW,OAAqB;IAClF,OAAOV,WAAW,CAChBA,YAAY,CAACI,kBAAkBA,CAACM,UAAU,IAAI,CAACV,aAAa,CAACF,iEAAiB;AAElF,GAAG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Deferred, Effect, Runtime } from "effect";
|
|
2
|
+
import { serve } from "./serve.js";
|
|
3
|
+
|
|
4
|
+
import * as __rspack_external__effect_platform_bun_BunRuntime_e8fbdd23 from "@effect/platform-bun/BunRuntime";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const start = (options)=>{
|
|
12
|
+
const ready = Deferred.makeUnsafe();
|
|
13
|
+
__rspack_external__effect_platform_bun_BunRuntime_e8fbdd23.runMain(serve(options).pipe(Effect.tap(()=>Deferred.succeed(ready, undefined)), Effect.andThen(Effect.never), Effect.scoped, Effect.onExit((exit)=>Deferred.done(ready, exit))), {
|
|
14
|
+
// Let the caller observe readiness rejection before runMain exits the process.
|
|
15
|
+
teardown: (exit, onExit)=>{
|
|
16
|
+
setImmediate(()=>Runtime.defaultTeardown(exit, onExit));
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return Effect.runPromise(Deferred["await"](ready));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { start };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server/start.js","sources":["../../src/server/start.ts"],"sourcesContent":["import * as BunRuntime from '@effect/platform-bun/BunRuntime';\nimport { Deferred, Effect, Runtime } from 'effect';\n\nimport { serve, type StartOptions } from './serve';\n\nexport type { StartOptions } from './serve';\n\nexport const start = (options: StartOptions): Promise<void> => {\n const ready = Deferred.makeUnsafe<void, Effect.Error<ReturnType<typeof serve>>>();\n\n BunRuntime.runMain(\n serve(options).pipe(\n Effect.tap(() => Deferred.succeed(ready, undefined)),\n Effect.andThen(Effect.never),\n Effect.scoped,\n Effect.onExit((exit) => Deferred.done(ready, exit)),\n ),\n {\n // Let the caller observe readiness rejection before runMain exits the process.\n teardown: (exit, onExit) => {\n setImmediate(() => Runtime.defaultTeardown(exit, onExit));\n },\n },\n );\n\n return Effect.runPromise(Deferred.await(ready));\n};\n"],"names":["BunRuntime","Deferred","Effect","Runtime","serve","start","options","ready","undefined","exit","onExit","setImmediate"],"mappings":";;;;;;;AAA8D;AACX;AAEA;AAI5C,MAAMK,KAAKA,GAAG,CAACC;IACpB,MAAMC,QAAQN,mBAAmB;IAEjCD,kEAAkB,CAChBI,KAAKA,CAACE,SAAS,IAAI,CACjBJ,UAAU,CAAC,IAAMD,gBAAgB,CAACM,OAAOC,aACzCN,cAAc,CAACA,YAAY,GAC3BA,aAAa,EACbA,aAAa,CAAC,CAACO,OAASR,aAAa,CAACM,OAAOE,SAE/C;QACE,+EAA+E;QAC/E,UAAU,CAACA,MAAMC;YACfC,aAAa,IAAMR,uBAAuB,CAACM,MAAMC;QACnD;IACF;IAGF,OAAOR,iBAAiB,CAACD,iBAAc,CAACM;AAC1C,EAAE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
### Deploying to Vercel
|
|
2
|
+
|
|
3
|
+
Deploy to Vercel with Bun 1.4+. Match the adapter version to `effective-rsc`.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
bun add --dev @ersc/vercel
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Set the build script in `package.json`:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "ersc build --adapter @ersc/vercel"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Commit `bun.lock`, connect your GitHub repository in Vercel, and set:
|
|
20
|
+
|
|
21
|
+
| Setting | Value |
|
|
22
|
+
| ---------------- | ------------------------------- |
|
|
23
|
+
| Framework Preset | Other |
|
|
24
|
+
| Root Directory | Application directory |
|
|
25
|
+
| Install Command | `bun install --frozen-lockfile` |
|
|
26
|
+
| Build Command | `bun run --bun build` |
|
|
27
|
+
| Output Directory | Leave the override disabled |
|
|
28
|
+
|
|
29
|
+
Add your environment variables and deploy. The adapter generates `.vercel/output/`; no custom
|
|
30
|
+
server entry or `vercel.json` is needed.
|
|
31
|
+
|
|
32
|
+
For [monorepos](https://vercel.com/docs/monorepos/monorepo-faq), enable **Include source files outside
|
|
33
|
+
of the Root Directory in the Build Step**. With Turborepo, use
|
|
34
|
+
`bun run --bun turbo run build --filter=your-app` to build the app and its workspace dependencies.
|
package/docs/02-guides/index.md
CHANGED
|
@@ -62,3 +62,20 @@ but ERSC does not impose that policy.
|
|
|
62
62
|
These types describe only the first publication. Suspense content that resolves later renders in a
|
|
63
63
|
separate, untyped React Transition. Applications should use their own Suspense-specific
|
|
64
64
|
`<ViewTransition>` boundaries and styling for those reveals.
|
|
65
|
+
|
|
66
|
+
#### Application transition types
|
|
67
|
+
|
|
68
|
+
Add whitespace-separated application transition types to a native link with
|
|
69
|
+
`data-ersc-transition-types`:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
<a href='/photos/2' data-ersc-transition-types='photo-next'>
|
|
73
|
+
Next photo
|
|
74
|
+
</a>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
These are added alongside ERSC's built-in types for that push or replace navigation and can be
|
|
78
|
+
used in your `<ViewTransition>` type maps. They are not replayed on Back/Forward.
|
|
79
|
+
|
|
80
|
+
The names `navigation`, `navigation-*`, `server-function`, and `hmr-refresh` are reserved for ERSC
|
|
81
|
+
and ignored in the attribute.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Server entry
|
|
3
|
+
* Save this as `server.ts` in the application root and run it with `bun server.ts` after building.
|
|
4
|
+
*/
|
|
5
|
+
import { start } from 'effective-rsc/server';
|
|
6
|
+
|
|
7
|
+
await start({
|
|
8
|
+
hostname: 'localhost',
|
|
9
|
+
port: 18193,
|
|
10
|
+
root: import.meta.dir,
|
|
11
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## Production startup
|
|
2
|
+
|
|
3
|
+
Run `ersc build`, then `ersc start`. A custom Bun entry can await
|
|
4
|
+
`start({ root, hostname, port })` from `effective-rsc/server`. All options are required;
|
|
5
|
+
`root` is the application directory. Deploy its `.ersc/`, `public/`, and runtime dependencies.
|
|
6
|
+
|
|
7
|
+
The Promise resolves when ready; startup failures reject and exit. ERSC owns signal handling
|
|
8
|
+
and cleanup, so do not wrap it in `BunRuntime.runMain`.
|
|
9
|
+
|
|
10
|
+
### Deployment adapters
|
|
11
|
+
|
|
12
|
+
`ersc build --adapter <package>` runs an installed adapter after compilation; it does not upload.
|
|
13
|
+
Without the flag, packaging is skipped and previous output remains.
|
|
14
|
+
|
|
15
|
+
Adapters export `build: BuildHook` from `./build`, with types from `effective-rsc/build`.
|
|
16
|
+
The hook receives absolute `root`, `serverDir`, `clientDir`, and `publicDir` paths and returns
|
|
17
|
+
`Effect<void, Error, Scope>`. Inputs are read-only; adapters provide dependencies and ERSC owns
|
|
18
|
+
cleanup/cancellation. Failures stop the build.
|
|
19
|
+
|
|
20
|
+
<!-- source-navigation -->
|
|
21
|
+
|
|
22
|
+
- [Deploying to Vercel](../../02-guides/06-deploying-to-vercel/index.md)
|
|
@@ -9,3 +9,4 @@ before adopting them.
|
|
|
9
9
|
- [Request runtime and lifetimes](./01-request-runtime-and-lifetimes/index.md)
|
|
10
10
|
- [Client navigation](./02-client-navigation/index.md)
|
|
11
11
|
- [Server Function execution and refresh](./03-server-function-execution-and-refresh/index.md)
|
|
12
|
+
- [Production startup](./04-production-startup/index.md)
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effective-rsc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "An experimental, Effect-native React Server Components framework for Bun.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
7
7
|
"effect",
|
|
8
8
|
"react-server-components"
|
|
9
9
|
],
|
|
10
|
-
"homepage": "https://
|
|
10
|
+
"homepage": "https://effective-rsc.nikhilsnayak.dev/",
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/nikhilsnayak/effective-rsc/issues"
|
|
13
13
|
},
|
|
@@ -37,6 +37,14 @@
|
|
|
37
37
|
"types": "./dist/index.d.ts",
|
|
38
38
|
"react-server": "./dist/index.js",
|
|
39
39
|
"default": "./dist/unsupported.js"
|
|
40
|
+
},
|
|
41
|
+
"./server": {
|
|
42
|
+
"types": "./dist/server/start.d.ts",
|
|
43
|
+
"default": "./dist/server/start.js"
|
|
44
|
+
},
|
|
45
|
+
"./build": {
|
|
46
|
+
"types": "./dist/build/hook.d.ts",
|
|
47
|
+
"default": "./dist/build/hook.js"
|
|
40
48
|
}
|
|
41
49
|
},
|
|
42
50
|
"publishConfig": {
|
|
@@ -47,38 +55,37 @@
|
|
|
47
55
|
"docs:check": "bun ../../scripts/generate-docs.ts --check",
|
|
48
56
|
"prepack": "bun run build && bun run docs:check",
|
|
49
57
|
"test": "bun run --bun vitest run",
|
|
50
|
-
"test:types": "tsc --noEmit -p tests/types/tsconfig.json",
|
|
51
58
|
"test:watch": "bun run --bun vitest"
|
|
52
59
|
},
|
|
53
60
|
"dependencies": {
|
|
54
|
-
"@rspack/core": "2.2.
|
|
61
|
+
"@rspack/core": "2.2.3",
|
|
55
62
|
"@rspack/plugin-react-refresh": "2.0.2",
|
|
56
63
|
"@tailwindcss/webpack": "4.3.3",
|
|
57
|
-
"react-refresh": "0.
|
|
64
|
+
"react-refresh": "0.19.0"
|
|
58
65
|
},
|
|
59
66
|
"devDependencies": {
|
|
60
67
|
"@base-ui/react": "^1.8.0",
|
|
61
|
-
"@effect/platform-browser": "4.0.0-rc.
|
|
62
|
-
"@effect/platform-bun": "4.0.0-rc.
|
|
63
|
-
"@effect/vitest": "4.0.0-rc.
|
|
68
|
+
"@effect/platform-browser": "4.0.0-rc.113",
|
|
69
|
+
"@effect/platform-bun": "4.0.0-rc.113",
|
|
70
|
+
"@effect/vitest": "4.0.0-rc.113",
|
|
64
71
|
"@rsbuild/plugin-react": "2.1.0",
|
|
65
72
|
"@rslib/core": "1.0.0",
|
|
66
|
-
"@types/bun": "^1.4.
|
|
67
|
-
"@types/react": "19.
|
|
68
|
-
"@types/react-dom": "19.
|
|
69
|
-
"effect": "4.0.0-rc.
|
|
70
|
-
"react": "19.3.0-canary-
|
|
71
|
-
"react-dom": "19.3.0-canary-
|
|
73
|
+
"@types/bun": "^1.4.2",
|
|
74
|
+
"@types/react": "19.3.0",
|
|
75
|
+
"@types/react-dom": "19.3.0",
|
|
76
|
+
"effect": "4.0.0-rc.113",
|
|
77
|
+
"react": "19.3.0-canary-1d34f91d-20260909",
|
|
78
|
+
"react-dom": "19.3.0-canary-1d34f91d-20260909",
|
|
72
79
|
"react-server-dom-rspack": "0.1.0",
|
|
73
80
|
"typescript": "7.0.2",
|
|
74
|
-
"vitest": "^
|
|
81
|
+
"vitest": "^5.0.0"
|
|
75
82
|
},
|
|
76
83
|
"peerDependencies": {
|
|
77
|
-
"@effect/platform-browser": "4.0.0-rc.
|
|
78
|
-
"@effect/platform-bun": "4.0.0-rc.
|
|
79
|
-
"effect": "4.0.0-rc.
|
|
80
|
-
"react": "19.3.0-canary-
|
|
81
|
-
"react-dom": "19.3.0-canary-
|
|
84
|
+
"@effect/platform-browser": "4.0.0-rc.113",
|
|
85
|
+
"@effect/platform-bun": "4.0.0-rc.113",
|
|
86
|
+
"effect": "4.0.0-rc.113",
|
|
87
|
+
"react": "19.3.0-canary-1d34f91d-20260909",
|
|
88
|
+
"react-dom": "19.3.0-canary-1d34f91d-20260909",
|
|
82
89
|
"react-server-dom-rspack": "0.1.0"
|
|
83
90
|
},
|
|
84
91
|
"engines": {
|