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.
Files changed (54) hide show
  1. package/LLMS.md +85 -0
  2. package/README.md +14 -8
  3. package/dist/application/routes.d.ts +10 -10
  4. package/dist/application/routes.js.map +1 -1
  5. package/dist/build/build.d.ts +4 -2
  6. package/dist/build/build.js +19 -2
  7. package/dist/build/build.js.map +1 -1
  8. package/dist/build/deployment.d.ts +10 -0
  9. package/dist/build/deployment.js +59 -0
  10. package/dist/build/deployment.js.map +1 -0
  11. package/dist/build/dev.d.ts +4 -4
  12. package/dist/build/dev.js +22 -7
  13. package/dist/build/dev.js.map +1 -1
  14. package/dist/build/hook.d.ts +8 -0
  15. package/dist/build/hook.js +5 -0
  16. package/dist/build/hook.js.map +1 -0
  17. package/dist/build/rspack.js +1 -1
  18. package/dist/build/rspack.js.map +1 -1
  19. package/dist/cli.js +13 -24
  20. package/dist/cli.js.map +1 -1
  21. package/dist/client/browser-renderer.d.ts +25 -25
  22. package/dist/client/browser-renderer.js +80 -94
  23. package/dist/client/browser-renderer.js.map +1 -1
  24. package/dist/client/call-server.js +7 -5
  25. package/dist/client/call-server.js.map +1 -1
  26. package/dist/client/client-router.js +23 -7
  27. package/dist/client/client-router.js.map +1 -1
  28. package/dist/client/flight-client.js +3 -4
  29. package/dist/client/flight-client.js.map +1 -1
  30. package/dist/client/react-dom-renderer.js +2 -1
  31. package/dist/client/react-dom-renderer.js.map +1 -1
  32. package/dist/client/route-refresh.d.ts +2 -2
  33. package/dist/client/route-refresh.js +54 -39
  34. package/dist/client/route-refresh.js.map +1 -1
  35. package/dist/dev/panel.js +14 -14
  36. package/dist/dev/panel.js.map +1 -1
  37. package/dist/server/application.d.ts +2 -1
  38. package/dist/server/application.js +8 -6
  39. package/dist/server/application.js.map +1 -1
  40. package/dist/server/html-renderer.js +12 -11
  41. package/dist/server/html-renderer.js.map +1 -1
  42. package/dist/server/serve.d.ts +7 -0
  43. package/dist/server/serve.js +31 -0
  44. package/dist/server/serve.js.map +1 -0
  45. package/dist/server/start.d.ts +3 -0
  46. package/dist/server/start.js +24 -0
  47. package/dist/server/start.js.map +1 -0
  48. package/docs/02-guides/06-deploying-to-vercel/index.md +34 -0
  49. package/docs/02-guides/index.md +1 -0
  50. package/docs/03-advanced/02-client-navigation/index.md +17 -0
  51. package/docs/03-advanced/04-production-startup/01_server.ts +11 -0
  52. package/docs/03-advanced/04-production-startup/index.md +22 -0
  53. package/docs/03-advanced/index.md +1 -0
  54. 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)=>Stream.fromReadableStream({
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(Effect.context(), (requestContext)=>{
165
- const RequestContextMiddleware = HttpRouter.middleware()((httpEffect)=>httpEffect.pipe(Effect.provideContext(requestContext)));
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
- })).pipe(Layer.provide(RequestLayer));
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":"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"}
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 { Fragment, jsx, jsxs } from "react/jsx-runtime";
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__*/ jsxs(Fragment, {
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(\n <>\n {clientStylesheets.map((href) => (\n <link key={href} rel='stylesheet' href={href} precedence='default' />\n ))}\n <SsrRoot />\n </>,\n {\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 ),\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","renderToReadableStream","createFromReadableStream","RouteTree","FlightHtmlInjector","ServerConfig","HtmlRenderError","HtmlRenderer","clientBootstrapScripts","clientStylesheets","flightHtmlInjector","flight","formState","signal","runtime","ssrFlightStream","browserFlightStream","payload","SsrRoot","routeTree","htmlStream","href","error","errorInfo","cause"],"mappings":";;;;;;;;;;;;;;;;;;AAA8E;AAClD;AACkC;AACY;AAEzB;AAES;AAEX;AAIxC,MAAMW,eAAeA,SAASP,kBAAkB,GAAoB,mBAAmB;IAC5F,OAAOA,aAAa;AACtB;AAAI;AAEG,MAAMQ,YAAYA,SAASZ,eAAe,GAC/C,0CACA;IACE,MAAMC,UAAU,CAAC;QACf,MAAM,EAAEY,sBAAsB,EAAEC,iBAAiB,EAAE,GAAG,OAAOJ,YAAYA;QACzE,MAAMK,qBAAqB,OAAON,kBAAkBA;QAEpD,OAAO;YACL,QAAQR,SAAS,CAAC,uBAAuB,UAAW,EAClDe,MAAM,EACNC,SAAS,EAIV;gBACC,MAAMC,SAAS,OAAOjB,kBAAkB;gBACxC,MAAMkB,UAAU,OAAOjB,2BAA2B;gBAClD,MAAM,CAACkB,iBAAiBC,oBAAoB,GAAGL,OAAO,MAAM,CAAC,GAAG;gBAChE,IAAIM,UAA6C;gBAEjD,SAASC;oBACP,MAAM,EAAEC,SAAS,EAAE,GAAGnB,GAAGA,CACtBiB,YAAYf,wBAAwBA,CAAgBa;oBAEvD,qBAAO,IAACZ,SAASA;wBAAC,MAAMgB;;gBAC1B;gBAEA,MAAMC,aAAa,OAAOxB,iBAAiB,CAAC;oBAC1C,KAAK,IACHK,sBAAsBA,eACpB;;gCACGQ,kBAAkB,GAAG,CAAC,CAACY,qBACtB,IAAC;wCAAgB,KAAI;wCAAa,MAAMA;wCAAM,YAAW;uCAA9CA;8CAEb,IAACH;;4BAEH;4BACE,kBAAkB;mCAAIV;6BAAuB;4BAC7CI;4BACA,SAAS,CAACU,OAAOC;gCACf,IAAI,CAACV,OAAO,OAAO,IAAI,CAACF,OAAO,MAAM,CAAC,OAAO,EAAE;oCAC7C,KAAKG,QACHlB,eAAe,CAAC,uBAAuB0B,OAAOC,UAAU,cAAc;gCAE1E;4BACF;4BACAV;wBACF;oBAEJ,OAAO,CAACW,QAAU,IAAIlB,eAAeA,CAAC;4BAAEkB;wBAAM;gBAChD;gBAEA,OAAOJ,WAAW,WAAW,CAACV,mBAAmB,MAAM,CAACM;YAC1D;QACF;IACF;AACF;IAEA,OAAgB,QAAQlB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACxD"}
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,3 @@
1
+ import { type StartOptions } from './serve.js';
2
+ export type { StartOptions } from './serve.js';
3
+ export declare const start: (options: StartOptions) => Promise<void>;
@@ -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.
@@ -9,3 +9,4 @@ Familiarity with React Server Components and Effect is assumed.
9
9
  - [Routing](./03-routing/index.md)
10
10
  - [Middleware](./04-middleware/index.md)
11
11
  - [Userland HTTP](./05-http/index.md)
12
+ - [Deploying to Vercel](./06-deploying-to-vercel/index.md)
@@ -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.2",
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://github.com/nikhilsnayak/effective-rsc#readme",
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.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.18.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.112",
62
- "@effect/platform-bun": "4.0.0-rc.112",
63
- "@effect/vitest": "4.0.0-rc.112",
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.1",
67
- "@types/react": "19.2.18",
68
- "@types/react-dom": "19.2.7",
69
- "effect": "4.0.0-rc.112",
70
- "react": "19.3.0-canary-8425b691-20260904",
71
- "react-dom": "19.3.0-canary-8425b691-20260904",
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": "^4.1.11"
81
+ "vitest": "^5.0.0"
75
82
  },
76
83
  "peerDependencies": {
77
- "@effect/platform-browser": "4.0.0-rc.112",
78
- "@effect/platform-bun": "4.0.0-rc.112",
79
- "effect": "4.0.0-rc.112",
80
- "react": "19.3.0-canary-8425b691-20260904",
81
- "react-dom": "19.3.0-canary-8425b691-20260904",
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": {