effective-rsc 0.1.0 → 0.1.2

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 (59) hide show
  1. package/LLMS.md +54 -10
  2. package/README.md +3 -3
  3. package/dist/application/page.d.ts +14 -7
  4. package/dist/application/page.js +5 -3
  5. package/dist/application/page.js.map +1 -1
  6. package/dist/application/route-graph.d.ts +1 -1
  7. package/dist/application/route-graph.js.map +1 -1
  8. package/dist/application/server-fn.d.ts +10 -6
  9. package/dist/application/server-fn.js +9 -4
  10. package/dist/application/server-fn.js.map +1 -1
  11. package/dist/build/dev.d.ts +11 -11
  12. package/dist/build/dev.js +21 -5
  13. package/dist/build/dev.js.map +1 -1
  14. package/dist/cli.js +2 -0
  15. package/dist/cli.js.map +1 -1
  16. package/dist/client/application.js +12 -9
  17. package/dist/client/application.js.map +1 -1
  18. package/dist/client/browser-capabilities.d.ts +2 -9
  19. package/dist/client/browser-capabilities.js +3 -14
  20. package/dist/client/browser-capabilities.js.map +1 -1
  21. package/dist/client/browser-render-status.d.ts +25 -0
  22. package/dist/client/browser-render-status.js +20 -0
  23. package/dist/client/browser-render-status.js.map +1 -0
  24. package/dist/client/call-server.js +7 -2
  25. package/dist/client/call-server.js.map +1 -1
  26. package/dist/client/navigation-api.js +5 -4
  27. package/dist/client/navigation-api.js.map +1 -1
  28. package/dist/client/react-dom-renderer.d.ts +3 -2
  29. package/dist/client/react-dom-renderer.js +43 -2
  30. package/dist/client/react-dom-renderer.js.map +1 -1
  31. package/dist/client/route-refresh.d.ts +1 -2
  32. package/dist/client/route-refresh.js +5 -18
  33. package/dist/client/route-refresh.js.map +1 -1
  34. package/dist/dev/client.d.ts +2 -1
  35. package/dist/dev/client.js +46 -6
  36. package/dist/dev/client.js.map +1 -1
  37. package/dist/dev/panel.d.ts +12 -1
  38. package/dist/dev/panel.js +73 -5
  39. package/dist/dev/panel.js.map +1 -1
  40. package/dist/dev/runtime-failure.d.ts +1 -0
  41. package/dist/dev/runtime-failure.js +7 -1
  42. package/dist/dev/runtime-failure.js.map +1 -1
  43. package/dist/rsc/render-route-tree.d.ts +3 -3
  44. package/dist/rsc/render-route-tree.js +2 -2
  45. package/dist/rsc/render-route-tree.js.map +1 -1
  46. package/dist/server/application.js +54 -35
  47. package/dist/server/application.js.map +1 -1
  48. package/dist/server/server-fn-request.js +3 -1
  49. package/dist/server/server-fn-request.js.map +1 -1
  50. package/docs/02-guides/01-server-functions/50_greet.ts +18 -0
  51. package/docs/02-guides/01-server-functions/60_greeting-form.tsx +23 -0
  52. package/docs/02-guides/01-server-functions/index.md +7 -0
  53. package/docs/02-guides/03-routing/index.md +5 -1
  54. package/docs/03-advanced/02-client-navigation/index.md +6 -3
  55. package/docs/03-advanced/03-server-function-execution-and-refresh/index.md +3 -1
  56. package/docs/04-api-reference/02-page/index.md +8 -3
  57. package/docs/04-api-reference/06-middleware/index.md +2 -2
  58. package/docs/04-api-reference/08-server-fn/index.md +23 -0
  59. package/package.json +1 -1
package/LLMS.md CHANGED
@@ -75,12 +75,19 @@ Callers pass the Schema's encoded type and the handler receives its decoded type
75
75
  input; a function returning `void` can then be passed directly to `<form action>`. Let the Schema
76
76
  infer the handler parameter.
77
77
 
78
+ For form feedback with `useActionState`, use `input: [StateSchema, FormSchema]` and
79
+ `handler: (previousState, form) => ...`. React supplies both arguments; ERSC validates and decodes
80
+ each one. Keep the native Server Function reference intact when passing it to `useActionState`
81
+ to retain progressive enhancement. A single Array or Tuple Schema still describes one argument.
82
+
78
83
  A successful invocation refreshes the current route.
79
84
 
80
85
  - **[Creating the Server Function authoring module](./docs/02-guides/01-server-functions/10_ersc.ts)**
81
86
  - **[Defining a Server Function](./docs/02-guides/01-server-functions/20_follow-author.ts)**: ERSC decodes FormData before running the Effect handler.
82
87
  - **[Rendering a direct form action](./docs/02-guides/01-server-functions/30_follow-author-button.tsx)**: A FormData Server Function can be passed directly to form action.
83
88
  - **[Closing the Server Function application](./docs/02-guides/01-server-functions/40_application.tsx)**
89
+ - **[Defining a stateful form action](./docs/02-guides/01-server-functions/50_greet.ts)**: A schema list decodes React's previous state and submitted FormData separately.
90
+ - **[Rendering a stateful form](./docs/02-guides/01-server-functions/60_greeting-form.tsx)**: Pass the native reference to useActionState so React also owns progressive form submission.
84
91
 
85
92
  ## Services
86
93
 
@@ -101,7 +108,11 @@ renderer's inferred service requirements.
101
108
  - Routes are immutable and belong to one ERSC identity.
102
109
  - `page(path, page)` attaches a Page; `mount(prefix, routes)` nests a route scope.
103
110
  - Mounted scopes retain their Layout and Loading ancestry.
104
- - Page parameter Schemas decode Effect HTTP path captures before rendering.
111
+ - On GET/HEAD, the request handler decodes Page parameters once before rendering, with services
112
+ from existing route middleware available. Rejected parameters return an empty `404`, including
113
+ navigation Flight.
114
+ - Server Function POST refreshes keep parameter rejection in React's render-error path, preserving
115
+ the completed action result.
105
116
  - Effect HTTP owns route matching; ERSC rejects duplicate shapes and invalid composition while
106
117
  building the graph.
107
118
 
@@ -172,9 +183,12 @@ Give work that must outlive a request an explicit application-owned scope.
172
183
 
173
184
  ERSC handles eligible document navigations through the browser Navigation API and
174
185
  `NavigationPrecommitController`. There is no History API fallback. A browser missing either one
175
- never hydrates: the streamed document stays as served and the application behaves as a plain
176
- multi-page application, with document navigations and natively submitted forms but no interactive
177
- Client Components.
186
+ still hydrates Client Components and supports Server Functions and streamed current-page refreshes,
187
+ including HMR. Links use full-page navigation instead of the client router. Without JavaScript,
188
+ the server-rendered document retains working links and natively submitted forms.
189
+
190
+ Development reports a missing navigation API in the console and a dismissible development-panel
191
+ warning. The warning does not block interaction and is absent in production.
178
192
 
179
193
  An intercepted Page navigation has two milestones:
180
194
 
@@ -243,7 +257,9 @@ Flight EOF. Disconnecting interrupts unfinished request work and the response st
243
257
  Hydrated invocations may execute concurrently. Only the latest invocation may apply its response's
244
258
  route tree while its original history entry remains current and no navigation is active. Other
245
259
  responses trigger a fresh current-route refresh. A response tree interrupts any older current-route
246
- refresh before rendering.
260
+ refresh before rendering, then rechecks applicability after cleanup completes. Effect owns refresh
261
+ loading and cancellation; the React Transition publishes the tree without waiting for its own
262
+ commit inside an async Action.
247
263
 
248
264
  After a successful mutation, ERSC clears the Back/Forward traversal cache because any route may have
249
265
  changed.
@@ -273,9 +289,14 @@ services and register native Effect HTTP on the framework router.
273
289
  the Schema's encoded keys must exactly match the path parameters and accept strings. Compose the
274
290
  Page with `Routes.page`.
275
291
 
276
- Pages produce React output. Only an unmatched route receives a native `404`. The mapping from a
277
- matched Page's parameter rejection to an expected HTTP outcome remains a
278
- [known limitation](https://github.com/nikhilsnayak/effective-rsc/blob/main/docs/ARCHITECTURE.md#known-limitations).
292
+ Pages produce React output. On GET/HEAD, the request handler decodes parameters once before
293
+ rendering, with services from existing route middleware available. Rejected parameters receive
294
+ an empty `404`, including navigation Flight requests; unmatched routes also receive native `404`
295
+ responses. Other failures keep their existing
296
+ error behavior.
297
+
298
+ Server Function POST refreshes decode parameters inside Page rendering. A rejection follows React's
299
+ render-error path without replacing the completed Server Function result with a `404`.
279
300
 
280
301
  ## Layout
281
302
 
@@ -318,10 +339,10 @@ middleware across mounted scopes runs once.
318
339
  | -------------------------------- | ------------------------------------ | --------------------- | ------------------------ |
319
340
  | Page GET/HEAD | Matched chain | No | Yes |
320
341
  | Hydrated Server Function POST | Remaining route chain around refresh | Server Function chain | Yes |
321
- | Progressive Server Function POST | No route refresh in the POST | Server Function chain | Yes |
342
+ | Progressive Server Function POST | Remaining route chain around refresh | Server Function chain | Yes |
322
343
  | Userland HTTP, assets, unmatched | No | No | Yes |
323
344
 
324
- During a hydrated Server Function request, middleware already active for the Server Function is not
345
+ During a Server Function request, middleware already active for the Server Function is not
325
346
  executed again for the refreshed route, even if it appears at another position in that route chain.
326
347
  Remaining route middleware wraps refreshed rendering.
327
348
 
@@ -350,6 +371,12 @@ decodes the invocation payload and infers the handler parameter; do not annotate
350
371
  returns an Effect whose requirements fit the ERSC service universe. The client reference accepts the
351
372
  Schema's encoded type and resolves `Promise<Output>`; the handler receives its decoded type.
352
373
 
374
+ For multiple positional arguments, supply a readonly schema list as `input`. Each caller argument
375
+ uses its Schema's encoded type; each handler argument uses its decoded type, in the same order.
376
+ Inline lists infer their tuple shape without `as const`. Use `input: []` for no arguments.
377
+ `input: Schema.Array(...)` and `input: Schema.Tuple(...)` still describe one argument, not a
378
+ positional argument list.
379
+
353
380
  ```ts
354
381
  const followAuthor = ERSC.ServerFn.make({
355
382
  input: Schema.Struct({ authorId: Schema.NonEmptyString }),
@@ -375,6 +402,23 @@ const followAuthorForm = ERSC.ServerFn.make({
375
402
  A ServerFn created from a derived view activates its middleware for the POST. The Middleware
376
403
  reference defines refresh reach and ordering.
377
404
 
405
+ For a `useActionState` form, declare both the previous state and submitted FormData:
406
+
407
+ ```ts
408
+ const StateSchema = Schema.Struct({ message: Schema.String });
409
+ const FormSchema = Schema.fromFormData(Schema.Struct({ name: Schema.NonEmptyString }));
410
+
411
+ const greet = ERSC.ServerFn.make({
412
+ input: [StateSchema, FormSchema],
413
+ handler: (_previousState, { name }) => Effect.succeed({ message: `Hello, ${name}` }),
414
+ });
415
+ ```
416
+
417
+ Pass the native reference directly to `useActionState(greet, { message: '' })` and its returned
418
+ action to `<form action>`. React supplies previous state and FormData for hydrated and progressive
419
+ submissions. Previous state is client input: validate it, but never trust it for authorization or
420
+ authoritative application state. Native `.bind` can prefill leading arguments.
421
+
378
422
  Direct server invocation throws. Encode expected failure in a discriminated output union; unexpected
379
423
  failures reject the Promise. Browser requests require an Origin matching the application host and
380
424
  may contain at most 10 MiB. See the
package/README.md CHANGED
@@ -24,9 +24,9 @@ native RSC support.
24
24
  ## Requirements
25
25
 
26
26
  - Bun 1.4 or newer is the only supported server runtime.
27
- - Client navigation and hydration require the Navigation API and `NavigationPrecommitController`;
28
- there is no History API fallback. Browsers without them receive the server-rendered document as a
29
- plain multi-page application, with working links and natively submitted forms.
27
+ - Client navigation requires the Navigation API and `NavigationPrecommitController`; there is no
28
+ History API fallback. Browsers without them still hydrate Client Components and support Server
29
+ Functions, but links use full-page navigation. Without JavaScript, links and native forms still work.
30
30
  - React, React DOM, Effect, Effect's browser and Bun platforms, and
31
31
  `react-server-dom-rspack` must use the exact compatible versions shown below.
32
32
 
@@ -25,19 +25,26 @@ export type PageConcern<out ParamNames extends string, out Mode extends 'Paramet
25
25
  readonly paramNames: Types.Covariant<ParamNames>;
26
26
  };
27
27
  };
28
- export type PagePathParams = Readonly<Record<string, string | undefined>>;
29
- export type PageRuntimeProps<ParamNames extends string = string> = {
30
- readonly params: Readonly<Record<ParamNames, string | undefined>>;
28
+ export type EncodedPageParams = Readonly<Record<string, string | undefined>>;
29
+ export type PageParams = {
30
+ readonly _tag: 'Encoded';
31
+ readonly value: EncodedPageParams;
32
+ } | {
33
+ readonly _tag: 'Decoded';
34
+ readonly value: Readonly<Record<string, unknown>>;
31
35
  };
32
- export type PageComponent<ParamNames extends string = string> = (props: PageRuntimeProps<ParamNames>) => Promise<Awaited<ReactNode>>;
36
+ export type PageRuntimeProps = {
37
+ readonly params: PageParams;
38
+ };
39
+ export type PageComponent = (props: PageRuntimeProps) => Promise<Awaited<ReactNode>>;
33
40
  export type StaticPageDefinition<Services> = ERSCStatefulMember<Services, 'Page', PageImplementationState> & PageConcern<never, 'Static'>;
34
41
  export type ParameterizedPageDefinition<Services, ParamNames extends string = string> = ERSCStatefulMember<Services, 'Page', PageImplementationState> & PageConcern<ParamNames, 'Parameterized'>;
35
42
  export type AnyPageDefinition<Services> = StaticPageDefinition<Services> | ParameterizedPageDefinition<Services>;
36
- export type PageImplementationState = {
43
+ export type PageImplementationState<Services = unknown> = {
37
44
  readonly component: PageComponent;
38
- readonly paramsSchema: Schema.Constraint | null;
45
+ readonly paramsSchema: PageParamsSchema<Services> | null;
39
46
  };
40
- export declare const getPageState: <Services>(page: AnyPageDefinition<Services>) => PageImplementationState;
47
+ export declare function getPageState<Services>(page: AnyPageDefinition<Services>): PageImplementationState<Services>;
41
48
  type StaticPageOptions<Error, Services> = {
42
49
  readonly params?: never;
43
50
  readonly render: () => Effect.Effect<Awaited<ReactNode>, Error, Services>;
@@ -20,18 +20,20 @@ class PageDefinitionImpl {
20
20
  Object.freeze(this);
21
21
  }
22
22
  }
23
- const getPageState = (page)=>{
23
+ // The compiled destination installs the Page's complete middleware chain before decoding.
24
+ // As with scoped middleware, its provided services are erased from the application contract.
25
+ function getPageState(page) {
24
26
  if (!isERSCMember(page, 'Page')) {
25
27
  throw new TypeError('Page must be created with ERSC.Page.make.');
26
28
  }
27
29
  return page[ERSCStateTypeId];
28
- };
30
+ }
29
31
  const makePageFactory = (identity, middleware)=>{
30
32
  function make(options) {
31
33
  if ('params' in options) {
32
34
  const { params: paramsSchema, render } = options;
33
35
  const decodeParams = Schema.decodeUnknownEffect(paramsSchema);
34
- const component = ({ params })=>identity.renderRuntime.run('Page', decodeParams(params).pipe(Effect.flatMap((decodedParams)=>Effect.suspend(()=>render({
36
+ const component = ({ params })=>identity.renderRuntime.run('Page', (params._tag === 'Decoded' ? Effect.succeed(params.value) : decodeParams(params.value)).pipe(Effect.flatMap((decodedParams)=>Effect.suspend(()=>render({
35
37
  params: decodedParams
36
38
  })))), middleware);
37
39
  return new PageDefinitionImpl(identity, component, paramsSchema);
@@ -1 +1 @@
1
- {"version":3,"file":"application/page.js","sources":["../../src/application/page.ts"],"sourcesContent":["import { Effect, Schema, type Types } from 'effect';\nimport type { ReactNode } from 'react';\n\nimport {\n type ERSCIdentity,\n ERSCIdentityTypeId,\n isERSCMember,\n ERSCMemberKindTypeId,\n type ERSCStatefulMember,\n ERSCStateTypeId,\n} from './ersc-identity';\nimport type { AnyMiddleware } from './middleware';\nimport type { ValidRouteParamName } from './route-path';\n\ndeclare const PageContractTypeId: unique symbol;\n\nexport type PageParamsSchema<Services> = Schema.ConstraintCodec<\n Readonly<Record<string, unknown>>,\n Readonly<Record<string, unknown>>,\n Services,\n unknown\n>;\n\ntype PageParamKeys<ParamsSchema> = ParamsSchema extends { readonly Encoded: infer Encoded }\n ? Extract<keyof Encoded, string>\n : never;\ntype NonStringPageParamKeys<ParamsSchema> = ParamsSchema extends {\n readonly Encoded: infer Encoded;\n}\n ? Exclude<keyof Encoded, string>\n : never;\ntype InvalidPageParamName<Name extends string> =\n Name extends ValidRouteParamName<Name> ? never : Name;\ntype InvalidPageParamValueKeys<ParamsSchema> = ParamsSchema extends {\n readonly Encoded: infer Encoded;\n}\n ? {\n [Key in Extract<keyof Encoded, string>]-?: unknown extends Encoded[Key]\n ? never\n : [Extract<Encoded[Key], string>] extends [never]\n ? Key\n : never;\n }[Extract<keyof Encoded, string>]\n : never;\ntype InvalidPageParamsSchema<ParamsSchema> =\n | NonStringPageParamKeys<ParamsSchema>\n | InvalidPageParamName<PageParamKeys<ParamsSchema>>\n | InvalidPageParamValueKeys<ParamsSchema>;\ntype ValidPageParamsSchema<ParamsSchema> = [PageParamKeys<ParamsSchema>] extends [never]\n ? never\n : string extends PageParamKeys<ParamsSchema>\n ? never\n : [InvalidPageParamsSchema<ParamsSchema>] extends [never]\n ? unknown\n : never;\n\nexport type PageConcern<\n out ParamNames extends string,\n out Mode extends 'Parameterized' | 'Static',\n> = {\n readonly [PageContractTypeId]: {\n readonly mode: Types.Covariant<Mode>;\n readonly paramNames: Types.Covariant<ParamNames>;\n };\n};\n\nexport type PagePathParams = Readonly<Record<string, string | undefined>>;\nexport type PageRuntimeProps<ParamNames extends string = string> = {\n readonly params: Readonly<Record<ParamNames, string | undefined>>;\n};\nexport type PageComponent<ParamNames extends string = string> = (\n props: PageRuntimeProps<ParamNames>,\n) => Promise<Awaited<ReactNode>>;\n\nexport type StaticPageDefinition<Services> = ERSCStatefulMember<\n Services,\n 'Page',\n PageImplementationState\n> &\n PageConcern<never, 'Static'>;\nexport type ParameterizedPageDefinition<\n Services,\n ParamNames extends string = string,\n> = ERSCStatefulMember<Services, 'Page', PageImplementationState> &\n PageConcern<ParamNames, 'Parameterized'>;\nexport type AnyPageDefinition<Services> =\n | StaticPageDefinition<Services>\n | ParameterizedPageDefinition<Services>;\n\nexport type PageImplementationState = {\n readonly component: PageComponent;\n readonly paramsSchema: Schema.Constraint | null;\n};\n\nclass PageDefinitionImpl<\n Services,\n ParamNames extends string,\n Mode extends 'Parameterized' | 'Static',\n ParamsSchema extends Schema.Constraint | null,\n>\n implements\n ERSCStatefulMember<Services, 'Page', PageImplementationState>,\n PageConcern<ParamNames, Mode>\n{\n declare readonly [PageContractTypeId]: {\n readonly mode: Types.Covariant<Mode>;\n readonly paramNames: Types.Covariant<ParamNames>;\n };\n readonly [ERSCIdentityTypeId]: ERSCIdentity<Services>;\n readonly [ERSCMemberKindTypeId] = 'Page' as const;\n get [ERSCStateTypeId](): PageImplementationState {\n return this;\n }\n readonly component: PageComponent;\n readonly paramsSchema: ParamsSchema;\n\n constructor(\n identity: ERSCIdentity<Services>,\n component: PageComponent,\n paramsSchema: ParamsSchema,\n ) {\n this[ERSCIdentityTypeId] = identity;\n this.component = component;\n this.paramsSchema = paramsSchema;\n Object.freeze(this);\n }\n}\n\nexport const getPageState = <Services>(\n page: AnyPageDefinition<Services>,\n): PageImplementationState => {\n if (!isERSCMember(page, 'Page')) {\n throw new TypeError('Page must be created with ERSC.Page.make.');\n }\n return page[ERSCStateTypeId];\n};\n\ntype StaticPageOptions<Error, Services> = {\n readonly params?: never;\n readonly render: () => Effect.Effect<Awaited<ReactNode>, Error, Services>;\n};\ntype ParameterizedPageOptions<ParamsSchema extends PageParamsSchema<Services>, Error, Services> = {\n readonly params: ParamsSchema;\n readonly render: (props: {\n readonly params: ParamsSchema['Type'];\n }) => Effect.Effect<Awaited<ReactNode>, Error, Services>;\n};\n\nexport type PageFactory<ApplicationServices, AvailableServices> = {\n readonly make: {\n <ParamsSchema extends PageParamsSchema<AvailableServices>, Error>(\n options: ParameterizedPageOptions<ParamsSchema, Error, AvailableServices> &\n ValidPageParamsSchema<ParamsSchema>,\n ): ParameterizedPageDefinition<ApplicationServices, PageParamKeys<ParamsSchema>>;\n <Error>(\n options: StaticPageOptions<Error, AvailableServices>,\n ): StaticPageDefinition<ApplicationServices>;\n };\n};\n\nexport const makePageFactory = <ApplicationServices, AvailableServices>(\n identity: ERSCIdentity<ApplicationServices>,\n middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>,\n): PageFactory<ApplicationServices, AvailableServices> => {\n function make<ParamsSchema extends PageParamsSchema<AvailableServices>, Error>(\n options: ParameterizedPageOptions<ParamsSchema, Error, AvailableServices> &\n ValidPageParamsSchema<ParamsSchema>,\n ): ParameterizedPageDefinition<ApplicationServices, PageParamKeys<ParamsSchema>>;\n function make<Error>(\n options: StaticPageOptions<Error, AvailableServices>,\n ): StaticPageDefinition<ApplicationServices>;\n function make<Error>(\n options:\n | Omit<StaticPageOptions<Error, AvailableServices>, 'params'>\n | ParameterizedPageOptions<PageParamsSchema<AvailableServices>, Error, AvailableServices>,\n ): AnyPageDefinition<ApplicationServices> {\n if ('params' in options) {\n const { params: paramsSchema, render } = options;\n const decodeParams = Schema.decodeUnknownEffect(paramsSchema);\n const component: PageComponent = ({ params }) =>\n identity.renderRuntime.run(\n 'Page',\n decodeParams(params).pipe(\n Effect.flatMap((decodedParams) =>\n Effect.suspend(() => render({ params: decodedParams })),\n ),\n ),\n middleware,\n );\n return new PageDefinitionImpl<\n ApplicationServices,\n PageParamKeys<typeof paramsSchema>,\n 'Parameterized',\n typeof paramsSchema\n >(identity, component, paramsSchema);\n }\n\n const { render } = options;\n const component: PageComponent = () =>\n identity.renderRuntime.run('Page', Effect.suspend(render), middleware);\n return new PageDefinitionImpl<ApplicationServices, never, 'Static', null>(\n identity,\n component,\n null,\n );\n }\n\n return { make };\n};\n"],"names":["Effect","Schema","ERSCIdentityTypeId","isERSCMember","ERSCMemberKindTypeId","ERSCStateTypeId","PageDefinitionImpl","identity","component","paramsSchema","Object","getPageState","page","TypeError","makePageFactory","middleware","make","options","render","decodeParams","params","decodedParams"],"mappings":";;;;;AAAoD;AAU3B;AAoFzB,MAAMM,kBAAkBA;IAcb,CAACJ,kBAAkBA,CAAC,CAAyB;IAC7C,CAACE,oBAAoBA,CAAC,GAAG,OAAgB;IAClD,IAAI,CAACC,eAAeA,CAAC,GAA4B;QAC/C,OAAO,IAAI;IACb;IACS,UAAyB;IACzB,aAA2B;IAEpC,YACEE,QAAgC,EAChCC,SAAwB,EACxBC,YAA0B,CAC1B;QACA,IAAI,CAACP,kBAAkBA,CAAC,GAAGK;QAC3B,IAAI,CAAC,SAAS,GAAGC;QACjB,IAAI,CAAC,YAAY,GAAGC;QACpBC,OAAO,MAAM,CAAC,IAAI;IACpB;AACF;AAEO,MAAMC,YAAYA,GAAG,CAC1BC;IAEA,IAAI,CAACT,YAAYA,CAACS,MAAM,SAAS;QAC/B,MAAM,IAAIC,UAAU;IACtB;IACA,OAAOD,IAAI,CAACP,eAAeA,CAAC;AAC9B,EAAE;AAyBK,MAAMS,eAAeA,GAAG,CAC7BP,UACAQ;IASA,SAASC,KACPC,OAE2F;QAE3F,IAAI,YAAYA,SAAS;YACvB,MAAM,EAAE,QAAQR,YAAY,EAAES,MAAM,EAAE,GAAGD;YACzC,MAAME,eAAelB,0BAA0B,CAACQ;YAChD,MAAMD,YAA2B,CAAC,EAAEY,MAAM,EAAE,GAC1Cb,SAAS,aAAa,CAAC,GAAG,CACxB,QACAY,aAAaC,QAAQ,IAAI,CACvBpB,cAAc,CAAC,CAACqB,gBACdrB,cAAc,CAAC,IAAMkB,OAAO;4BAAE,QAAQG;wBAAc,OAGxDN;YAEJ,OAAO,IAAIT,kBAAkBA,CAK3BC,UAAUC,WAAWC;QACzB;QAEA,MAAM,EAAES,MAAM,EAAE,GAAGD;QACnB,MAAMT,YAA2B,IAC/BD,SAAS,aAAa,CAAC,GAAG,CAAC,QAAQP,cAAc,CAACkB,SAASH;QAC7D,OAAO,IAAIT,kBAAkBA,CAC3BC,UACAC,WACA;IAEJ;IAEA,OAAO;QAAEQ;IAAK;AAChB,EAAE"}
1
+ {"version":3,"file":"application/page.js","sources":["../../src/application/page.ts"],"sourcesContent":["import { Effect, Schema, type Types } from 'effect';\nimport type { ReactNode } from 'react';\n\nimport {\n type ERSCIdentity,\n ERSCIdentityTypeId,\n isERSCMember,\n ERSCMemberKindTypeId,\n type ERSCStatefulMember,\n ERSCStateTypeId,\n} from './ersc-identity';\nimport type { AnyMiddleware } from './middleware';\nimport type { ValidRouteParamName } from './route-path';\n\ndeclare const PageContractTypeId: unique symbol;\n\nexport type PageParamsSchema<Services> = Schema.ConstraintCodec<\n Readonly<Record<string, unknown>>,\n Readonly<Record<string, unknown>>,\n Services,\n unknown\n>;\n\ntype PageParamKeys<ParamsSchema> = ParamsSchema extends { readonly Encoded: infer Encoded }\n ? Extract<keyof Encoded, string>\n : never;\ntype NonStringPageParamKeys<ParamsSchema> = ParamsSchema extends {\n readonly Encoded: infer Encoded;\n}\n ? Exclude<keyof Encoded, string>\n : never;\ntype InvalidPageParamName<Name extends string> =\n Name extends ValidRouteParamName<Name> ? never : Name;\ntype InvalidPageParamValueKeys<ParamsSchema> = ParamsSchema extends {\n readonly Encoded: infer Encoded;\n}\n ? {\n [Key in Extract<keyof Encoded, string>]-?: unknown extends Encoded[Key]\n ? never\n : [Extract<Encoded[Key], string>] extends [never]\n ? Key\n : never;\n }[Extract<keyof Encoded, string>]\n : never;\ntype InvalidPageParamsSchema<ParamsSchema> =\n | NonStringPageParamKeys<ParamsSchema>\n | InvalidPageParamName<PageParamKeys<ParamsSchema>>\n | InvalidPageParamValueKeys<ParamsSchema>;\ntype ValidPageParamsSchema<ParamsSchema> = [PageParamKeys<ParamsSchema>] extends [never]\n ? never\n : string extends PageParamKeys<ParamsSchema>\n ? never\n : [InvalidPageParamsSchema<ParamsSchema>] extends [never]\n ? unknown\n : never;\n\nexport type PageConcern<\n out ParamNames extends string,\n out Mode extends 'Parameterized' | 'Static',\n> = {\n readonly [PageContractTypeId]: {\n readonly mode: Types.Covariant<Mode>;\n readonly paramNames: Types.Covariant<ParamNames>;\n };\n};\n\nexport type EncodedPageParams = Readonly<Record<string, string | undefined>>;\nexport type PageParams =\n | { readonly _tag: 'Encoded'; readonly value: EncodedPageParams }\n | { readonly _tag: 'Decoded'; readonly value: Readonly<Record<string, unknown>> };\nexport type PageRuntimeProps = {\n readonly params: PageParams;\n};\nexport type PageComponent = (props: PageRuntimeProps) => Promise<Awaited<ReactNode>>;\n\nexport type StaticPageDefinition<Services> = ERSCStatefulMember<\n Services,\n 'Page',\n PageImplementationState\n> &\n PageConcern<never, 'Static'>;\nexport type ParameterizedPageDefinition<\n Services,\n ParamNames extends string = string,\n> = ERSCStatefulMember<Services, 'Page', PageImplementationState> &\n PageConcern<ParamNames, 'Parameterized'>;\nexport type AnyPageDefinition<Services> =\n | StaticPageDefinition<Services>\n | ParameterizedPageDefinition<Services>;\n\nexport type PageImplementationState<Services = unknown> = {\n readonly component: PageComponent;\n readonly paramsSchema: PageParamsSchema<Services> | null;\n};\n\nclass PageDefinitionImpl<\n Services,\n ParamNames extends string,\n Mode extends 'Parameterized' | 'Static',\n ParamsSchema extends PageParamsSchema<unknown> | null,\n>\n implements\n ERSCStatefulMember<Services, 'Page', PageImplementationState>,\n PageConcern<ParamNames, Mode>\n{\n declare readonly [PageContractTypeId]: {\n readonly mode: Types.Covariant<Mode>;\n readonly paramNames: Types.Covariant<ParamNames>;\n };\n readonly [ERSCIdentityTypeId]: ERSCIdentity<Services>;\n readonly [ERSCMemberKindTypeId] = 'Page' as const;\n get [ERSCStateTypeId](): PageImplementationState {\n return this;\n }\n readonly component: PageComponent;\n readonly paramsSchema: ParamsSchema;\n\n constructor(\n identity: ERSCIdentity<Services>,\n component: PageComponent,\n paramsSchema: ParamsSchema,\n ) {\n this[ERSCIdentityTypeId] = identity;\n this.component = component;\n this.paramsSchema = paramsSchema;\n Object.freeze(this);\n }\n}\n\nexport function getPageState<Services>(\n page: AnyPageDefinition<Services>,\n): PageImplementationState<Services>;\n// The compiled destination installs the Page's complete middleware chain before decoding.\n// As with scoped middleware, its provided services are erased from the application contract.\nexport function getPageState(page: AnyPageDefinition<unknown>): PageImplementationState {\n if (!isERSCMember(page, 'Page')) {\n throw new TypeError('Page must be created with ERSC.Page.make.');\n }\n return page[ERSCStateTypeId];\n}\n\ntype StaticPageOptions<Error, Services> = {\n readonly params?: never;\n readonly render: () => Effect.Effect<Awaited<ReactNode>, Error, Services>;\n};\ntype ParameterizedPageOptions<ParamsSchema extends PageParamsSchema<Services>, Error, Services> = {\n readonly params: ParamsSchema;\n readonly render: (props: {\n readonly params: ParamsSchema['Type'];\n }) => Effect.Effect<Awaited<ReactNode>, Error, Services>;\n};\n\nexport type PageFactory<ApplicationServices, AvailableServices> = {\n readonly make: {\n <ParamsSchema extends PageParamsSchema<AvailableServices>, Error>(\n options: ParameterizedPageOptions<ParamsSchema, Error, AvailableServices> &\n ValidPageParamsSchema<ParamsSchema>,\n ): ParameterizedPageDefinition<ApplicationServices, PageParamKeys<ParamsSchema>>;\n <Error>(\n options: StaticPageOptions<Error, AvailableServices>,\n ): StaticPageDefinition<ApplicationServices>;\n };\n};\n\nexport const makePageFactory = <ApplicationServices, AvailableServices>(\n identity: ERSCIdentity<ApplicationServices>,\n middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>,\n): PageFactory<ApplicationServices, AvailableServices> => {\n function make<ParamsSchema extends PageParamsSchema<AvailableServices>, Error>(\n options: ParameterizedPageOptions<ParamsSchema, Error, AvailableServices> &\n ValidPageParamsSchema<ParamsSchema>,\n ): ParameterizedPageDefinition<ApplicationServices, PageParamKeys<ParamsSchema>>;\n function make<Error>(\n options: StaticPageOptions<Error, AvailableServices>,\n ): StaticPageDefinition<ApplicationServices>;\n function make<Error>(\n options:\n | Omit<StaticPageOptions<Error, AvailableServices>, 'params'>\n | ParameterizedPageOptions<PageParamsSchema<AvailableServices>, Error, AvailableServices>,\n ): AnyPageDefinition<ApplicationServices> {\n if ('params' in options) {\n const { params: paramsSchema, render } = options;\n const decodeParams = Schema.decodeUnknownEffect(paramsSchema);\n const component: PageComponent = ({ params }) =>\n identity.renderRuntime.run(\n 'Page',\n (params._tag === 'Decoded'\n ? Effect.succeed(params.value)\n : decodeParams(params.value)\n ).pipe(\n Effect.flatMap((decodedParams) =>\n Effect.suspend(() => render({ params: decodedParams })),\n ),\n ),\n middleware,\n );\n return new PageDefinitionImpl<\n ApplicationServices,\n PageParamKeys<typeof paramsSchema>,\n 'Parameterized',\n typeof paramsSchema\n >(identity, component, paramsSchema);\n }\n\n const { render } = options;\n const component: PageComponent = () =>\n identity.renderRuntime.run('Page', Effect.suspend(render), middleware);\n return new PageDefinitionImpl<ApplicationServices, never, 'Static', null>(\n identity,\n component,\n null,\n );\n }\n\n return { make };\n};\n"],"names":["Effect","Schema","ERSCIdentityTypeId","isERSCMember","ERSCMemberKindTypeId","ERSCStateTypeId","PageDefinitionImpl","identity","component","paramsSchema","Object","getPageState","page","TypeError","makePageFactory","middleware","make","options","render","decodeParams","params","decodedParams"],"mappings":";;;;;AAAoD;AAU3B;AAqFzB,MAAMM,kBAAkBA;IAcb,CAACJ,kBAAkBA,CAAC,CAAyB;IAC7C,CAACE,oBAAoBA,CAAC,GAAG,OAAgB;IAClD,IAAI,CAACC,eAAeA,CAAC,GAA4B;QAC/C,OAAO,IAAI;IACb;IACS,UAAyB;IACzB,aAA2B;IAEpC,YACEE,QAAgC,EAChCC,SAAwB,EACxBC,YAA0B,CAC1B;QACA,IAAI,CAACP,kBAAkBA,CAAC,GAAGK;QAC3B,IAAI,CAAC,SAAS,GAAGC;QACjB,IAAI,CAAC,YAAY,GAAGC;QACpBC,OAAO,MAAM,CAAC,IAAI;IACpB;AACF;AAKA,0FAA0F;AAC1F,6FAA6F;AACtF,SAASC,YAAYA,CAACC,IAAgC;IAC3D,IAAI,CAACT,YAAYA,CAACS,MAAM,SAAS;QAC/B,MAAM,IAAIC,UAAU;IACtB;IACA,OAAOD,IAAI,CAACP,eAAeA,CAAC;AAC9B;AAyBO,MAAMS,eAAeA,GAAG,CAC7BP,UACAQ;IASA,SAASC,KACPC,OAE2F;QAE3F,IAAI,YAAYA,SAAS;YACvB,MAAM,EAAE,QAAQR,YAAY,EAAES,MAAM,EAAE,GAAGD;YACzC,MAAME,eAAelB,0BAA0B,CAACQ;YAChD,MAAMD,YAA2B,CAAC,EAAEY,MAAM,EAAE,GAC1Cb,SAAS,aAAa,CAAC,GAAG,CACxB,QACCa,CAAAA,OAAO,IAAI,KAAK,YACbpB,cAAc,CAACoB,OAAO,KAAK,IAC3BD,aAAaC,OAAO,KAAK,GAC3B,IAAI,CACJpB,cAAc,CAAC,CAACqB,gBACdrB,cAAc,CAAC,IAAMkB,OAAO;4BAAE,QAAQG;wBAAc,OAGxDN;YAEJ,OAAO,IAAIT,kBAAkBA,CAK3BC,UAAUC,WAAWC;QACzB;QAEA,MAAM,EAAES,MAAM,EAAE,GAAGD;QACnB,MAAMT,YAA2B,IAC/BD,SAAS,aAAa,CAAC,GAAG,CAAC,QAAQP,cAAc,CAACkB,SAASH;QAC7D,OAAO,IAAIT,kBAAkBA,CAC3BC,UACAC,WACA;IAEJ;IAEA,OAAO;QAAEQ;IAAK;AAChB,EAAE"}
@@ -11,7 +11,7 @@ export type RouteScope<Services> = {
11
11
  };
12
12
  export type CompiledDestination<Services> = {
13
13
  readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;
14
- readonly page: PageImplementationState;
14
+ readonly page: PageImplementationState<Services>;
15
15
  readonly pattern: AbsolutePath;
16
16
  readonly scopes: ReadonlyArray<RouteScope<Services>>;
17
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"application/route-graph.js","sources":["../../src/application/route-graph.ts"],"sourcesContent":["import type { LayoutComponent } from './layout';\nimport type { LoadingComponent } from './loading';\nimport type { AnyMiddleware } from './middleware';\nimport { getPageState, type PageImplementationState } from './page';\nimport { type AbsolutePath, joinRoutePaths, validateUnreservedPath } from './route-path';\nimport { type AnyRoutes, getRoutesState } from './routes';\n\nexport type RouteScope<Services> = {\n readonly id: string;\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n};\n\nexport type CompiledDestination<Services> = {\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly page: PageImplementationState;\n readonly pattern: AbsolutePath;\n readonly scopes: ReadonlyArray<RouteScope<Services>>;\n};\n\nexport type CompiledRouteGraph<Services> = readonly [\n CompiledDestination<Services>,\n ...Array<CompiledDestination<Services>>,\n];\n\nconst resolveRouteMiddleware = <Services>(\n inherited: ReadonlyArray<AnyMiddleware<Services>>,\n declared: ReadonlyArray<AnyMiddleware<Services>>,\n) => {\n let sharedCount = 0;\n while (sharedCount < inherited.length && inherited[sharedCount] === declared[sharedCount]) {\n sharedCount += 1;\n }\n\n return sharedCount === inherited.length\n ? declared\n : Object.freeze([...inherited, ...declared.slice(sharedCount)]);\n};\n\nexport const compileRouteGraph = <Services>(\n routes: AnyRoutes<Services>,\n): CompiledRouteGraph<Services> => {\n const rootState = getRoutesState(routes);\n if (rootState.layout === null) {\n throw new TypeError('The root Routes passed to ERSC.make must define a Layout.');\n }\n\n const destinations: Array<CompiledDestination<Services>> = [];\n const visit = (\n current: AnyRoutes<Services>,\n prefix: AbsolutePath,\n inheritedScopes: ReadonlyArray<RouteScope<Services>>,\n inheritedMiddleware: ReadonlyArray<AnyMiddleware<Services>>,\n ): void => {\n const currentState = getRoutesState(current);\n const middleware = resolveRouteMiddleware(inheritedMiddleware, currentState.middleware);\n if (new Set(middleware).size !== middleware.length) {\n throw new TypeError(\n `Middleware beneath route prefix \"${prefix}\" appears more than once in its resolved chain.`,\n );\n }\n const scopes =\n currentState.layout === null && currentState.loading === null\n ? inheritedScopes\n : Object.freeze([\n ...inheritedScopes,\n Object.freeze({\n id: `${currentState.scopeId}:${prefix}`,\n layout: currentState.layout,\n loading: currentState.loading,\n }),\n ]);\n\n for (const route of currentState.pages) {\n const pattern = joinRoutePaths(prefix, route.path);\n validateUnreservedPath(pattern);\n destinations.push(\n Object.freeze({ middleware, page: getPageState(route.page), pattern, scopes }),\n );\n }\n\n for (const mount of currentState.mounts) {\n visit(mount.routes, joinRoutePaths(prefix, mount.path), scopes, middleware);\n }\n };\n\n visit(routes, '/', [], []);\n const [firstDestination, ...remainingDestinations] = destinations;\n if (firstDestination === undefined) {\n throw new TypeError('The root Routes passed to ERSC.make must contain a Page.');\n }\n\n return Object.freeze([firstDestination, ...remainingDestinations]);\n};\n"],"names":["getPageState","joinRoutePaths","validateUnreservedPath","getRoutesState","resolveRouteMiddleware","inherited","declared","sharedCount","Object","compileRouteGraph","routes","rootState","TypeError","destinations","visit","current","prefix","inheritedScopes","inheritedMiddleware","currentState","middleware","Set","scopes","route","pattern","mount","firstDestination","remainingDestinations","undefined"],"mappings":";;;;;;;AAGoE;AACqB;AAC/B;AAoB1D,MAAMI,sBAAsBA,GAAG,CAC7BC,WACAC;IAEA,IAAIC,cAAc;IAClB,MAAOA,cAAcF,UAAU,MAAM,IAAIA,SAAS,CAACE,YAAY,KAAKD,QAAQ,CAACC,YAAY,CAAE;QACzFA,eAAe;IACjB;IAEA,OAAOA,gBAAgBF,UAAU,MAAM,GACnCC,WACAE,OAAO,MAAM,CAAC;WAAIH;WAAcC,SAAS,KAAK,CAACC;KAAa;AAClE;AAEO,MAAME,iBAAiBA,GAAG,CAC/BC;IAEA,MAAMC,YAAYR,cAAcA,CAACO;IACjC,IAAIC,UAAU,MAAM,KAAK,MAAM;QAC7B,MAAM,IAAIC,UAAU;IACtB;IAEA,MAAMC,eAAqD,EAAE;IAC7D,MAAMC,QAAQ,CACZC,SACAC,QACAC,iBACAC;QAEA,MAAMC,eAAehB,cAAcA,CAACY;QACpC,MAAMK,aAAahB,sBAAsBA,CAACc,qBAAqBC,aAAa,UAAU;QACtF,IAAI,IAAIE,IAAID,YAAY,IAAI,KAAKA,WAAW,MAAM,EAAE;YAClD,MAAM,IAAIR,UACR,CAAC,iCAAiC,EAAEI,OAAO,+CAA+C,CAAC;QAE/F;QACA,MAAMM,SACJH,aAAa,MAAM,KAAK,QAAQA,aAAa,OAAO,KAAK,OACrDF,kBACAT,OAAO,MAAM,CAAC;eACTS;YACHT,OAAO,MAAM,CAAC;gBACZ,IAAI,GAAGW,aAAa,OAAO,CAAC,CAAC,EAAEH,QAAQ;gBACvC,QAAQG,aAAa,MAAM;gBAC3B,SAASA,aAAa,OAAO;YAC/B;SACD;QAEP,KAAK,MAAMI,SAASJ,aAAa,KAAK,CAAE;YACtC,MAAMK,UAAUvB,cAAcA,CAACe,QAAQO,MAAM,IAAI;YACjDrB,sBAAsBA,CAACsB;YACvBX,aAAa,IAAI,CACfL,OAAO,MAAM,CAAC;gBAAEY;gBAAY,MAAMpB,YAAYA,CAACuB,MAAM,IAAI;gBAAGC;gBAASF;YAAO;QAEhF;QAEA,KAAK,MAAMG,SAASN,aAAa,MAAM,CAAE;YACvCL,MAAMW,MAAM,MAAM,EAAExB,cAAcA,CAACe,QAAQS,MAAM,IAAI,GAAGH,QAAQF;QAClE;IACF;IAEAN,MAAMJ,QAAQ,KAAK,EAAE,EAAE,EAAE;IACzB,MAAM,CAACgB,kBAAkB,GAAGC,sBAAsB,GAAGd;IACrD,IAAIa,qBAAqBE,WAAW;QAClC,MAAM,IAAIhB,UAAU;IACtB;IAEA,OAAOJ,OAAO,MAAM,CAAC;QAACkB;WAAqBC;KAAsB;AACnE,EAAE"}
1
+ {"version":3,"file":"application/route-graph.js","sources":["../../src/application/route-graph.ts"],"sourcesContent":["import type { LayoutComponent } from './layout';\nimport type { LoadingComponent } from './loading';\nimport type { AnyMiddleware } from './middleware';\nimport { getPageState, type PageImplementationState } from './page';\nimport { type AbsolutePath, joinRoutePaths, validateUnreservedPath } from './route-path';\nimport { type AnyRoutes, getRoutesState } from './routes';\n\nexport type RouteScope<Services> = {\n readonly id: string;\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n};\n\nexport type CompiledDestination<Services> = {\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly page: PageImplementationState<Services>;\n readonly pattern: AbsolutePath;\n readonly scopes: ReadonlyArray<RouteScope<Services>>;\n};\n\nexport type CompiledRouteGraph<Services> = readonly [\n CompiledDestination<Services>,\n ...Array<CompiledDestination<Services>>,\n];\n\nconst resolveRouteMiddleware = <Services>(\n inherited: ReadonlyArray<AnyMiddleware<Services>>,\n declared: ReadonlyArray<AnyMiddleware<Services>>,\n) => {\n let sharedCount = 0;\n while (sharedCount < inherited.length && inherited[sharedCount] === declared[sharedCount]) {\n sharedCount += 1;\n }\n\n return sharedCount === inherited.length\n ? declared\n : Object.freeze([...inherited, ...declared.slice(sharedCount)]);\n};\n\nexport const compileRouteGraph = <Services>(\n routes: AnyRoutes<Services>,\n): CompiledRouteGraph<Services> => {\n const rootState = getRoutesState(routes);\n if (rootState.layout === null) {\n throw new TypeError('The root Routes passed to ERSC.make must define a Layout.');\n }\n\n const destinations: Array<CompiledDestination<Services>> = [];\n const visit = (\n current: AnyRoutes<Services>,\n prefix: AbsolutePath,\n inheritedScopes: ReadonlyArray<RouteScope<Services>>,\n inheritedMiddleware: ReadonlyArray<AnyMiddleware<Services>>,\n ): void => {\n const currentState = getRoutesState(current);\n const middleware = resolveRouteMiddleware(inheritedMiddleware, currentState.middleware);\n if (new Set(middleware).size !== middleware.length) {\n throw new TypeError(\n `Middleware beneath route prefix \"${prefix}\" appears more than once in its resolved chain.`,\n );\n }\n const scopes =\n currentState.layout === null && currentState.loading === null\n ? inheritedScopes\n : Object.freeze([\n ...inheritedScopes,\n Object.freeze({\n id: `${currentState.scopeId}:${prefix}`,\n layout: currentState.layout,\n loading: currentState.loading,\n }),\n ]);\n\n for (const route of currentState.pages) {\n const pattern = joinRoutePaths(prefix, route.path);\n validateUnreservedPath(pattern);\n destinations.push(\n Object.freeze({ middleware, page: getPageState(route.page), pattern, scopes }),\n );\n }\n\n for (const mount of currentState.mounts) {\n visit(mount.routes, joinRoutePaths(prefix, mount.path), scopes, middleware);\n }\n };\n\n visit(routes, '/', [], []);\n const [firstDestination, ...remainingDestinations] = destinations;\n if (firstDestination === undefined) {\n throw new TypeError('The root Routes passed to ERSC.make must contain a Page.');\n }\n\n return Object.freeze([firstDestination, ...remainingDestinations]);\n};\n"],"names":["getPageState","joinRoutePaths","validateUnreservedPath","getRoutesState","resolveRouteMiddleware","inherited","declared","sharedCount","Object","compileRouteGraph","routes","rootState","TypeError","destinations","visit","current","prefix","inheritedScopes","inheritedMiddleware","currentState","middleware","Set","scopes","route","pattern","mount","firstDestination","remainingDestinations","undefined"],"mappings":";;;;;;;AAGoE;AACqB;AAC/B;AAoB1D,MAAMI,sBAAsBA,GAAG,CAC7BC,WACAC;IAEA,IAAIC,cAAc;IAClB,MAAOA,cAAcF,UAAU,MAAM,IAAIA,SAAS,CAACE,YAAY,KAAKD,QAAQ,CAACC,YAAY,CAAE;QACzFA,eAAe;IACjB;IAEA,OAAOA,gBAAgBF,UAAU,MAAM,GACnCC,WACAE,OAAO,MAAM,CAAC;WAAIH;WAAcC,SAAS,KAAK,CAACC;KAAa;AAClE;AAEO,MAAME,iBAAiBA,GAAG,CAC/BC;IAEA,MAAMC,YAAYR,cAAcA,CAACO;IACjC,IAAIC,UAAU,MAAM,KAAK,MAAM;QAC7B,MAAM,IAAIC,UAAU;IACtB;IAEA,MAAMC,eAAqD,EAAE;IAC7D,MAAMC,QAAQ,CACZC,SACAC,QACAC,iBACAC;QAEA,MAAMC,eAAehB,cAAcA,CAACY;QACpC,MAAMK,aAAahB,sBAAsBA,CAACc,qBAAqBC,aAAa,UAAU;QACtF,IAAI,IAAIE,IAAID,YAAY,IAAI,KAAKA,WAAW,MAAM,EAAE;YAClD,MAAM,IAAIR,UACR,CAAC,iCAAiC,EAAEI,OAAO,+CAA+C,CAAC;QAE/F;QACA,MAAMM,SACJH,aAAa,MAAM,KAAK,QAAQA,aAAa,OAAO,KAAK,OACrDF,kBACAT,OAAO,MAAM,CAAC;eACTS;YACHT,OAAO,MAAM,CAAC;gBACZ,IAAI,GAAGW,aAAa,OAAO,CAAC,CAAC,EAAEH,QAAQ;gBACvC,QAAQG,aAAa,MAAM;gBAC3B,SAASA,aAAa,OAAO;YAC/B;SACD;QAEP,KAAK,MAAMI,SAASJ,aAAa,KAAK,CAAE;YACtC,MAAMK,UAAUvB,cAAcA,CAACe,QAAQO,MAAM,IAAI;YACjDrB,sBAAsBA,CAACsB;YACvBX,aAAa,IAAI,CACfL,OAAO,MAAM,CAAC;gBAAEY;gBAAY,MAAMpB,YAAYA,CAACuB,MAAM,IAAI;gBAAGC;gBAASF;YAAO;QAEhF;QAEA,KAAK,MAAMG,SAASN,aAAa,MAAM,CAAE;YACvCL,MAAMW,MAAM,MAAM,EAAExB,cAAcA,CAACe,QAAQS,MAAM,IAAI,GAAGH,QAAQF;QAClE;IACF;IAEAN,MAAMJ,QAAQ,KAAK,EAAE,EAAE,EAAE;IACzB,MAAM,CAACgB,kBAAkB,GAAGC,sBAAsB,GAAGd;IACrD,IAAIa,qBAAqBE,WAAW;QAClC,MAAM,IAAIhB,UAAU;IACtB;IAEA,OAAOJ,OAAO,MAAM,CAAC;QAACkB;WAAqBC;KAAsB;AACnE,EAAE"}
@@ -15,15 +15,19 @@ type ServerFnInvocationMatch<ApplicationServices> = {
15
15
  readonly effect: Effect.Effect<unknown, ServerFnOperationError, ApplicationServices>;
16
16
  readonly middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>;
17
17
  };
18
- interface ServerFunction<Input, Output, ApplicationServices> extends ERSCMember<ApplicationServices, 'ServerFn'> {
19
- (input: Input): Promise<Output>;
18
+ type ServerFnInput<Services> = Schema.ConstraintDecoder<unknown, Services> | ReadonlyArray<Schema.ConstraintDecoder<unknown, Services>>;
19
+ type ServerFnArguments<Input, Side extends 'Type' | 'Encoded'> = Input extends ReadonlyArray<Schema.Constraint> ? {
20
+ -readonly [Key in keyof Input]: Input[Key] extends Schema.Constraint ? Input[Key][Side] : never;
21
+ } : Input extends Schema.Constraint ? [Input[Side]] : never;
22
+ interface ServerFunction<Args extends ReadonlyArray<unknown>, Output, ApplicationServices> extends ERSCMember<ApplicationServices, 'ServerFn'> {
23
+ (...args: Args): Promise<Output>;
20
24
  }
21
- type ServerFnOptions<InputSchema extends Schema.Constraint, Output, Error, Services> = {
22
- readonly input: InputSchema;
23
- readonly handler: (input: InputSchema['Type']) => Effect.Effect<Output, Error, Services>;
25
+ type ServerFnOptions<Input, Output, Error, Services> = {
26
+ readonly input: Input;
27
+ readonly handler: (...args: ServerFnArguments<Input, 'Type'>) => Effect.Effect<Output, Error, Services>;
24
28
  };
25
29
  export type ServerFnFactory<ApplicationServices, AvailableServices> = {
26
- readonly make: <InputSchema extends Schema.ConstraintDecoder<unknown, AvailableServices>, Output, Error>(options: ServerFnOptions<InputSchema, Output, Error, AvailableServices>) => ServerFunction<InputSchema['Encoded'], Output, ApplicationServices>;
30
+ readonly make: <const Input extends ServerFnInput<AvailableServices>, Output, Error>(options: ServerFnOptions<Input, Output, Error, AvailableServices>) => ServerFunction<ServerFnArguments<Input, 'Encoded'>, Output, ApplicationServices>;
27
31
  };
28
32
  export declare const matchServerFnInvocation: <ApplicationServices>(value: unknown, identity: ERSCIdentity<ApplicationServices>) => ServerFnInvocationMatch<ApplicationServices>;
29
33
  export declare const makeServerFnFactory: <ApplicationServices, AvailableServices>(identity: ERSCIdentity<ApplicationServices>, middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>) => ServerFnFactory<ApplicationServices, AvailableServices>;
@@ -1,4 +1,4 @@
1
- import { Effect, Predicate, Schema } from "effect";
1
+ import { Array as external_effect_Array, Effect, Predicate, Schema } from "effect";
2
2
  import { attachERSCMember } from "./ersc-identity.js";
3
3
 
4
4
 
@@ -34,9 +34,14 @@ const matchServerFnInvocation = (value, identity)=>{
34
34
  };
35
35
  const makeServerFnFactory = (identity, middleware)=>({
36
36
  make: ({ input, handler })=>{
37
- const decode = Schema.decodeUnknownEffect(input);
38
- const serverFunction = (untrustedInput)=>{
39
- const effect = decode(untrustedInput).pipe(Effect.flatMap(handler), Effect.mapError((cause)=>new ServerFnOperationError({
37
+ const schemas = external_effect_Array.ensure(input);
38
+ const decode = Schema.decodeUnknownEffect(Schema.Tuple(schemas));
39
+ const serverFunction = (...untrustedArgs)=>{
40
+ // Unary functions still ignore extra native arguments and decode undefined when omitted.
41
+ const effect = decode(external_effect_Array.isArray(input) ? untrustedArgs : [
42
+ untrustedArgs[0]
43
+ ]).pipe(// Normalization preserves the positional Type mapping, which the generic branch erases.
44
+ Effect.flatMap((args)=>handler(...args)), Effect.mapError((cause)=>new ServerFnOperationError({
40
45
  cause
41
46
  })));
42
47
  const unavailable = Promise.reject(directInvocationError());
@@ -1 +1 @@
1
- {"version":3,"file":"application/server-fn.js","sources":["../../src/application/server-fn.ts"],"sourcesContent":["import { Effect, Predicate, Schema } from 'effect';\n\nimport { attachERSCMember, type ERSCIdentity, type ERSCMember } from './ersc-identity';\nimport type { AnyMiddleware } from './middleware';\n\nconst ServerFnInvocationTypeId: unique symbol = Symbol.for('ersc/ServerFnInvocation');\n\nclass ServerFnOperationError extends Schema.TaggedError<ServerFnOperationError>()(\n 'ServerFnOperationError',\n { cause: Schema.Defect() },\n) {}\n\ntype ServerFnInvocation<ApplicationServices> = {\n readonly [ServerFnInvocationTypeId]: {\n readonly effect: Effect.Effect<unknown, ServerFnOperationError, ApplicationServices>;\n readonly identity: ERSCIdentity<ApplicationServices>;\n readonly middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>;\n };\n};\n\ntype ServerFnInvocationMatch<ApplicationServices> =\n | { readonly _tag: 'Native' }\n | { readonly _tag: 'IdentityMismatch' }\n | {\n readonly _tag: 'Match';\n readonly effect: Effect.Effect<unknown, ServerFnOperationError, ApplicationServices>;\n readonly middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>;\n };\n\ninterface ServerFunction<Input, Output, ApplicationServices> extends ERSCMember<\n ApplicationServices,\n 'ServerFn'\n> {\n (input: Input): Promise<Output>;\n}\n\ntype ServerFnOptions<InputSchema extends Schema.Constraint, Output, Error, Services> = {\n readonly input: InputSchema;\n readonly handler: (input: InputSchema['Type']) => Effect.Effect<Output, Error, Services>;\n};\n\nexport type ServerFnFactory<ApplicationServices, AvailableServices> = {\n readonly make: <\n InputSchema extends Schema.ConstraintDecoder<unknown, AvailableServices>,\n Output,\n Error,\n >(\n options: ServerFnOptions<InputSchema, Output, Error, AvailableServices>,\n ) => ServerFunction<InputSchema['Encoded'], Output, ApplicationServices>;\n};\n\nconst directInvocationError = () =>\n new TypeError(\n 'An ERSC ServerFn is a framework intrinsic and cannot be invoked directly in the server graph.',\n );\n\nconst isServerFnInvocation = <ApplicationServices>(\n value: unknown,\n): value is ServerFnInvocation<ApplicationServices> =>\n Predicate.hasProperty(value, ServerFnInvocationTypeId);\n\nexport const matchServerFnInvocation = <ApplicationServices>(\n value: unknown,\n identity: ERSCIdentity<ApplicationServices>,\n): ServerFnInvocationMatch<ApplicationServices> => {\n if (!isServerFnInvocation<ApplicationServices>(value)) {\n return { _tag: 'Native' };\n }\n\n // The framework-owned brand proves the state shape; matching the opaque identity proves the\n // application service universe erased by the native React invocation.\n const metadata = value[ServerFnInvocationTypeId];\n if (metadata.identity !== identity) {\n return { _tag: 'IdentityMismatch' };\n }\n\n return { _tag: 'Match', effect: metadata.effect, middleware: metadata.middleware };\n};\n\nexport const makeServerFnFactory = <ApplicationServices, AvailableServices>(\n identity: ERSCIdentity<ApplicationServices>,\n middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>,\n): ServerFnFactory<ApplicationServices, AvailableServices> => ({\n make: ({ input, handler }) => {\n const decode = Schema.decodeUnknownEffect(input);\n const serverFunction = (untrustedInput: typeof input.Encoded) => {\n const effect = decode(untrustedInput).pipe(\n Effect.flatMap(handler),\n Effect.mapError((cause) => new ServerFnOperationError({ cause })),\n );\n const unavailable = Promise.reject<Effect.Success<typeof effect>>(directInvocationError());\n void unavailable.catch(() => undefined);\n\n return Object.assign(unavailable, {\n [ServerFnInvocationTypeId]: Object.freeze({ effect, identity, middleware }),\n });\n };\n\n return attachERSCMember(serverFunction, identity, 'ServerFn');\n },\n});\n"],"names":["Effect","Predicate","Schema","attachERSCMember","ServerFnInvocationTypeId","Symbol","ServerFnOperationError","directInvocationError","TypeError","isServerFnInvocation","value","matchServerFnInvocation","identity","metadata","makeServerFnFactory","middleware","input","handler","decode","serverFunction","untrustedInput","effect","cause","unavailable","Promise","undefined","Object"],"mappings":";;;;;AAAmD;AAEoC;AAGvF,MAAMI,wBAAwBA,GAAkBC,OAAO,GAAG,CAAC;AAE3D,MAAMC,sBAAsBA,SAASJ,kBAAkB,GACrD,0BACA;IAAE,OAAOA,aAAa;AAAG;AACxB;AAyCH,MAAMK,qBAAqBA,GAAG,IAC5B,IAAIC,UACF;AAGJ,MAAMC,oBAAoBA,GAAG,CAC3BC,QAEAT,qBAAqB,CAACS,OAAON,wBAAwBA;AAEhD,MAAMO,uBAAuBA,GAAG,CACrCD,OACAE;IAEA,IAAI,CAACH,oBAAoBA,CAAsBC,QAAQ;QACrD,OAAO;YAAE,MAAM;QAAS;IAC1B;IAEA,4FAA4F;IAC5F,sEAAsE;IACtE,MAAMG,WAAWH,KAAK,CAACN,wBAAwBA,CAAC;IAChD,IAAIS,SAAS,QAAQ,KAAKD,UAAU;QAClC,OAAO;YAAE,MAAM;QAAmB;IACpC;IAEA,OAAO;QAAE,MAAM;QAAS,QAAQC,SAAS,MAAM;QAAE,YAAYA,SAAS,UAAU;IAAC;AACnF,EAAE;AAEK,MAAMC,mBAAmBA,GAAG,CACjCF,UACAG,aAC6D;QAC7D,MAAM,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAAE;YACvB,MAAMC,SAAShB,0BAA0B,CAACc;YAC1C,MAAMG,iBAAiB,CAACC;gBACtB,MAAMC,SAASH,OAAOE,gBAAgB,IAAI,CACxCpB,cAAc,CAACiB,UACfjB,eAAe,CAAC,CAACsB,QAAU,IAAIhB,sBAAsBA,CAAC;wBAAEgB;oBAAM;gBAEhE,MAAMC,cAAcC,QAAQ,MAAM,CAAgCjB,qBAAqBA;gBACvF,KAAKgB,YAAY,KAAK,CAAC,IAAME;gBAE7B,OAAOC,OAAO,MAAM,CAACH,aAAa;oBAChC,CAACnB,wBAAwBA,CAAC,EAAEsB,OAAO,MAAM,CAAC;wBAAEL;wBAAQT;wBAAUG;oBAAW;gBAC3E;YACF;YAEA,OAAOZ,gBAAgBA,CAACgB,gBAAgBP,UAAU;QACpD;IACF,GAAG"}
1
+ {"version":3,"file":"application/server-fn.js","sources":["../../src/application/server-fn.ts"],"sourcesContent":["import { Array, Effect, Predicate, Schema } from 'effect';\n\nimport { attachERSCMember, type ERSCIdentity, type ERSCMember } from './ersc-identity';\nimport type { AnyMiddleware } from './middleware';\n\nconst ServerFnInvocationTypeId: unique symbol = Symbol.for('ersc/ServerFnInvocation');\n\nclass ServerFnOperationError extends Schema.TaggedError<ServerFnOperationError>()(\n 'ServerFnOperationError',\n { cause: Schema.Defect() },\n) {}\n\ntype ServerFnInvocation<ApplicationServices> = {\n readonly [ServerFnInvocationTypeId]: {\n readonly effect: Effect.Effect<unknown, ServerFnOperationError, ApplicationServices>;\n readonly identity: ERSCIdentity<ApplicationServices>;\n readonly middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>;\n };\n};\n\ntype ServerFnInvocationMatch<ApplicationServices> =\n | { readonly _tag: 'Native' }\n | { readonly _tag: 'IdentityMismatch' }\n | {\n readonly _tag: 'Match';\n readonly effect: Effect.Effect<unknown, ServerFnOperationError, ApplicationServices>;\n readonly middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>;\n };\n\ntype ServerFnInput<Services> =\n | Schema.ConstraintDecoder<unknown, Services>\n | ReadonlyArray<Schema.ConstraintDecoder<unknown, Services>>;\n\ntype ServerFnArguments<Input, Side extends 'Type' | 'Encoded'> =\n Input extends ReadonlyArray<Schema.Constraint>\n ? {\n -readonly [Key in keyof Input]: Input[Key] extends Schema.Constraint\n ? Input[Key][Side]\n : never;\n }\n : Input extends Schema.Constraint\n ? [Input[Side]]\n : never;\n\ninterface ServerFunction<\n Args extends ReadonlyArray<unknown>,\n Output,\n ApplicationServices,\n> extends ERSCMember<ApplicationServices, 'ServerFn'> {\n (...args: Args): Promise<Output>;\n}\n\ntype ServerFnOptions<Input, Output, Error, Services> = {\n readonly input: Input;\n readonly handler: (\n ...args: ServerFnArguments<Input, 'Type'>\n ) => Effect.Effect<Output, Error, Services>;\n};\n\nexport type ServerFnFactory<ApplicationServices, AvailableServices> = {\n readonly make: <const Input extends ServerFnInput<AvailableServices>, Output, Error>(\n options: ServerFnOptions<Input, Output, Error, AvailableServices>,\n ) => ServerFunction<ServerFnArguments<Input, 'Encoded'>, Output, ApplicationServices>;\n};\n\nconst directInvocationError = () =>\n new TypeError(\n 'An ERSC ServerFn is a framework intrinsic and cannot be invoked directly in the server graph.',\n );\n\nconst isServerFnInvocation = <ApplicationServices>(\n value: unknown,\n): value is ServerFnInvocation<ApplicationServices> =>\n Predicate.hasProperty(value, ServerFnInvocationTypeId);\n\nexport const matchServerFnInvocation = <ApplicationServices>(\n value: unknown,\n identity: ERSCIdentity<ApplicationServices>,\n): ServerFnInvocationMatch<ApplicationServices> => {\n if (!isServerFnInvocation<ApplicationServices>(value)) {\n return { _tag: 'Native' };\n }\n\n // The framework-owned brand proves the state shape; matching the opaque identity proves the\n // application service universe erased by the native React invocation.\n const metadata = value[ServerFnInvocationTypeId];\n if (metadata.identity !== identity) {\n return { _tag: 'IdentityMismatch' };\n }\n\n return { _tag: 'Match', effect: metadata.effect, middleware: metadata.middleware };\n};\n\nexport const makeServerFnFactory = <ApplicationServices, AvailableServices>(\n identity: ERSCIdentity<ApplicationServices>,\n middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>,\n): ServerFnFactory<ApplicationServices, AvailableServices> => ({\n make: ({ input, handler }) => {\n const schemas = Array.ensure<Schema.ConstraintDecoder<unknown, AvailableServices>>(input);\n const decode = Schema.decodeUnknownEffect(Schema.Tuple(schemas));\n const serverFunction = (...untrustedArgs: ServerFnArguments<typeof input, 'Encoded'>) => {\n // Unary functions still ignore extra native arguments and decode undefined when omitted.\n const effect = decode(Array.isArray(input) ? untrustedArgs : [untrustedArgs[0]]).pipe(\n // Normalization preserves the positional Type mapping, which the generic branch erases.\n Effect.flatMap((args: ReadonlyArray<unknown>) =>\n handler(...(args as ServerFnArguments<typeof input, 'Type'>)),\n ),\n Effect.mapError((cause) => new ServerFnOperationError({ cause })),\n );\n const unavailable = Promise.reject<Effect.Success<typeof effect>>(directInvocationError());\n void unavailable.catch(() => undefined);\n\n return Object.assign(unavailable, {\n [ServerFnInvocationTypeId]: Object.freeze({ effect, identity, middleware }),\n });\n };\n\n return attachERSCMember(serverFunction, identity, 'ServerFn');\n },\n});\n"],"names":["Array","Effect","Predicate","Schema","attachERSCMember","ServerFnInvocationTypeId","Symbol","ServerFnOperationError","directInvocationError","TypeError","isServerFnInvocation","value","matchServerFnInvocation","identity","metadata","makeServerFnFactory","middleware","input","handler","schemas","decode","serverFunction","untrustedArgs","effect","args","cause","unavailable","Promise","undefined","Object"],"mappings":";;;;;AAA0D;AAE6B;AAGvF,MAAMK,wBAAwBA,GAAkBC,OAAO,GAAG,CAAC;AAE3D,MAAMC,sBAAsBA,SAASJ,kBAAkB,GACrD,0BACA;IAAE,OAAOA,aAAa;AAAG;AACxB;AAuDH,MAAMK,qBAAqBA,GAAG,IAC5B,IAAIC,UACF;AAGJ,MAAMC,oBAAoBA,GAAG,CAC3BC,QAEAT,qBAAqB,CAACS,OAAON,wBAAwBA;AAEhD,MAAMO,uBAAuBA,GAAG,CACrCD,OACAE;IAEA,IAAI,CAACH,oBAAoBA,CAAsBC,QAAQ;QACrD,OAAO;YAAE,MAAM;QAAS;IAC1B;IAEA,4FAA4F;IAC5F,sEAAsE;IACtE,MAAMG,WAAWH,KAAK,CAACN,wBAAwBA,CAAC;IAChD,IAAIS,SAAS,QAAQ,KAAKD,UAAU;QAClC,OAAO;YAAE,MAAM;QAAmB;IACpC;IAEA,OAAO;QAAE,MAAM;QAAS,QAAQC,SAAS,MAAM;QAAE,YAAYA,SAAS,UAAU;IAAC;AACnF,EAAE;AAEK,MAAMC,mBAAmBA,GAAG,CACjCF,UACAG,aAC6D;QAC7D,MAAM,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAAE;YACvB,MAAMC,UAAUnB,4BAAY,CAAuDiB;YACnF,MAAMG,SAASjB,0BAA0B,CAACA,YAAY,CAACgB;YACvD,MAAME,iBAAiB,CAAC,GAAGC;gBACzB,yFAAyF;gBACzF,MAAMC,SAASH,OAAOpB,6BAAa,CAACiB,SAASK,gBAAgB;oBAACA,aAAa,CAAC,EAAE;iBAAC,EAAE,IAAI,CACnF,wFAAwF;gBACxFrB,cAAc,CAAC,CAACuB,OACdN,WAAYM,QAEdvB,eAAe,CAAC,CAACwB,QAAU,IAAIlB,sBAAsBA,CAAC;wBAAEkB;oBAAM;gBAEhE,MAAMC,cAAcC,QAAQ,MAAM,CAAgCnB,qBAAqBA;gBACvF,KAAKkB,YAAY,KAAK,CAAC,IAAME;gBAE7B,OAAOC,OAAO,MAAM,CAACH,aAAa;oBAChC,CAACrB,wBAAwBA,CAAC,EAAEwB,OAAO,MAAM,CAAC;wBAAEN;wBAAQV;wBAAUG;oBAAW;gBAC3E;YACF;YAEA,OAAOZ,gBAAgBA,CAACiB,gBAAgBR,UAAU;QACpD;IACF,GAAG"}
@@ -1,5 +1,5 @@
1
- import { Effect, FileSystem, Path, Schema } from 'effect';
2
- import { HttpServer } from 'effect/unstable/http';
1
+ import { Cause, Effect, FileSystem, Path, Schema, Scope } from 'effect';
2
+ import { HttpServer, HttpServerResponse } from 'effect/unstable/http';
3
3
  import { Rspack, type RspackError, type RspackWatchEvent } from './rspack.js';
4
4
  type RspackCompilation = Extract<RspackWatchEvent, {
5
5
  readonly _tag: 'Compiled';
@@ -7,7 +7,7 @@ type RspackCompilation = Extract<RspackWatchEvent, {
7
7
  declare const DevGenerationError_base: Schema.Class<DevGenerationError, Schema.TaggedStruct<"DevGenerationError", {
8
8
  readonly message: Schema.String;
9
9
  readonly cause: Schema.Defect;
10
- }>, import("effect/Cause").YieldableError>;
10
+ }>, Cause.YieldableError>;
11
11
  export declare class DevGenerationError extends DevGenerationError_base {
12
12
  }
13
13
  type AcquireDevGenerationOptions = {
@@ -20,22 +20,22 @@ type DevGenerationOptions = Omit<AcquireDevGenerationOptions, 'compilation'>;
20
20
  export type DevApplicationOptions = DevGenerationOptions;
21
21
  export declare const acquireDevGeneration: (args_0: AcquireDevGenerationOptions) => Effect.Effect<{
22
22
  hash: string;
23
- httpEffect: Effect.Effect<import("effect/unstable/http/HttpServerResponse").HttpServerResponse, import("effect/unstable/http/HttpServerError").HttpServerError, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | import("effect/Scope").Scope>;
24
- }, import("./compiled-server.js").CompiledServerError | DevGenerationError, FileSystem.FileSystem | Path.Path | import("effect/Scope").Scope>;
23
+ httpEffect: Effect.Effect<HttpServerResponse.HttpServerResponse, import("effect/unstable/http/HttpServerError").HttpServerError, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | Scope.Scope>;
24
+ }, import("./compiled-server.js").CompiledServerError | DevGenerationError, FileSystem.FileSystem | Path.Path | Scope.Scope>;
25
25
  type DevGenerationFailure = Effect.Error<ReturnType<typeof acquireDevGeneration>> | RspackError;
26
26
  export declare const makeDevGenerationStore: (options: DevGenerationOptions) => Effect.Effect<{
27
- httpEffect: Effect.Effect<import("effect/unstable/http/HttpServerResponse").HttpServerResponse, import("effect/unstable/http/HttpServerError").HttpServerError | DevGenerationFailure, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | import("effect/Scope").Scope>;
27
+ httpEffect: Effect.Effect<HttpServerResponse.HttpServerResponse, import("effect/unstable/http/HttpServerError").HttpServerError | DevGenerationFailure, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | Scope.Scope>;
28
28
  update: (event: RspackWatchEvent) => Effect.Effect<undefined, import("./compiled-server.js").CompiledServerError | DevGenerationError, FileSystem.FileSystem | Path.Path>;
29
- }, never, import("effect/Scope").Scope>;
29
+ }, never, Scope.Scope>;
30
30
  export declare const makeDevApplication: (args_0: DevGenerationOptions) => Effect.Effect<{
31
31
  closeDevChannel: Effect.Effect<void, never, never>;
32
- httpEffect: Effect.Effect<import("effect/unstable/http/HttpServerResponse").HttpServerResponse, import("./compiled-server.js").CompiledServerError | DevGenerationError | import("effect/unstable/http/HttpServerError").HttpServerError | RspackError, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | import("effect/Scope").Scope>;
32
+ httpEffect: Effect.Effect<HttpServerResponse.HttpServerResponse, import("./compiled-server.js").CompiledServerError | DevGenerationError | import("effect/unstable/http/HttpServerError").HttpServerError | RspackError, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | Scope.Scope>;
33
33
  watch: Effect.Effect<void, import("./compiled-server.js").CompiledServerError | DevGenerationError | RspackError, FileSystem.FileSystem | Path.Path>;
34
- }, import("./build.js").BuildEntryError | import("effect/PlatformError").PlatformError, FileSystem.FileSystem | Path.Path | Rspack | import("effect/Scope").Scope>;
34
+ }, import("./build.js").BuildEntryError | import("effect/PlatformError").PlatformError, FileSystem.FileSystem | Path.Path | Rspack | Scope.Scope>;
35
35
  export declare const launchDevApplication: (application: {
36
36
  closeDevChannel: Effect.Effect<void, never, never>;
37
- httpEffect: Effect.Effect<import("effect/unstable/http/HttpServerResponse").HttpServerResponse, import("./compiled-server.js").CompiledServerError | DevGenerationError | import("effect/unstable/http/HttpServerError").HttpServerError | RspackError, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | import("effect/Scope").Scope>;
37
+ httpEffect: Effect.Effect<HttpServerResponse.HttpServerResponse, import("./compiled-server.js").CompiledServerError | DevGenerationError | import("effect/unstable/http/HttpServerError").HttpServerError | RspackError, import("effect/unstable/http/HttpServerRequest").HttpServerRequest | Scope.Scope>;
38
38
  watch: Effect.Effect<void, import("./compiled-server.js").CompiledServerError | DevGenerationError | RspackError, FileSystem.FileSystem | Path.Path>;
39
39
  }) => Effect.Effect<void, import("./compiled-server.js").CompiledServerError | DevGenerationError | RspackError, FileSystem.FileSystem | HttpServer.HttpServer | Path.Path>;
40
- export declare const devApplication: (options: DevGenerationOptions) => Effect.Effect<void, import("./build.js").BuildEntryError | import("./compiled-server.js").CompiledServerError | DevGenerationError | import("effect/PlatformError").PlatformError | RspackError, FileSystem.FileSystem | HttpServer.HttpServer | Path.Path | import("effect/Scope").Scope>;
40
+ export declare const devApplication: (options: DevGenerationOptions) => Effect.Effect<void, import("./build.js").BuildEntryError | import("./compiled-server.js").CompiledServerError | DevGenerationError | import("effect/PlatformError").PlatformError | RspackError, FileSystem.FileSystem | HttpServer.HttpServer | Path.Path | Scope.Scope>;
41
41
  export {};
package/dist/build/dev.js CHANGED
@@ -1,5 +1,5 @@
1
- import { Deferred, Effect, Fiber, FileSystem, Layer, Path, Ref, Schema, ScopedRef, Stream } from "effect";
2
- import { HttpRouter, HttpServer } from "effect/unstable/http";
1
+ import { Cause, Deferred, Effect, Fiber, FileSystem, Layer, Path, Ref, Schema, Scope, ScopedRef, Stream } from "effect";
2
+ import { HttpBody, HttpRouter, HttpServer, HttpServerResponse } from "effect/unstable/http";
3
3
  import package_0 from "../../package.json" with {"type":"json"};
4
4
  import { DevChannelPath } from "../dev/channel.js";
5
5
  import { resolveApplicationBuild } from "./build.js";
@@ -52,9 +52,25 @@ const acquireDevGeneration = Effect.fnUntraced(function*({ compilation, hostname
52
52
  message: `Failed to start development generation ${compilation.hash}.`,
53
53
  cause
54
54
  })));
55
+ // Close request work before the generation's application services.
56
+ const generationScope = yield* Effect.scope;
57
+ const requests = yield* Scope.fork(generationScope, 'parallel');
58
+ const ownRequest = Effect.withFiber((fiber)=>{
59
+ Fiber.runIn(fiber, requests);
60
+ return Effect["void"];
61
+ });
55
62
  return {
56
63
  hash: compilation.hash,
57
- httpEffect
64
+ httpEffect: Effect.gen(function*() {
65
+ yield* ownRequest;
66
+ const response = yield* httpEffect;
67
+ const body = response.body;
68
+ if (body._tag !== 'Stream') {
69
+ return response;
70
+ }
71
+ // Bun consumes the response body on a separate fiber after the handler returns.
72
+ return HttpServerResponse.setBody(response, HttpBody.stream(Stream.onStart(body.stream, ownRequest), body.contentType, body.contentLength));
73
+ })
58
74
  };
59
75
  });
60
76
  const makeDevGenerationStore = Effect.fnUntraced(function*(options) {
@@ -85,7 +101,7 @@ const makeDevGenerationStore = Effect.fnUntraced(function*(options) {
85
101
  yield* ScopedRef.set(generation, acquireDevGeneration({
86
102
  ...options,
87
103
  compilation: event
88
- }).pipe(Effect.map((ready)=>({
104
+ }).pipe(Effect.interruptible, Effect.map((ready)=>({
89
105
  _tag: 'Ready',
90
106
  generation: ready
91
107
  })), Effect.tapError((error)=>Deferred.fail(current, error))));
@@ -148,7 +164,7 @@ const makeDevApplication = Effect.fnUntraced(function*({ hostname, port, root })
148
164
  const compilers = event.compilers.map(({ duration, name })=>duration === undefined ? name : `${name} ${formatDuration(duration)}`).join(' · ');
149
165
  const details = compilers.length === 0 ? '' : ` ${Terminal.dim(compilers)}`;
150
166
  return Effect.logInfo(`${Terminal.green('✓')} Ready${duration}${details}`);
151
- }), Effect["catch"]((error)=>Effect.logError(error)));
167
+ }), Effect["catch"]((error)=>channel.publishBuildFailure(Cause.pretty(Cause.fail(error))).pipe(Effect.andThen(Effect.logError(error)))));
152
168
  }
153
169
  }
154
170
  });
@@ -1 +1 @@
1
- {"version":3,"file":"build/dev.js","sources":["../../src/build/dev.ts"],"sourcesContent":["import {\n Deferred,\n Effect,\n Fiber,\n FileSystem,\n Layer,\n Path,\n Ref,\n Schema,\n ScopedRef,\n Stream,\n} from 'effect';\nimport { HttpRouter, HttpServer } from 'effect/unstable/http';\n\nimport PackageJson from '../../package.json' with { type: 'json' };\nimport { DevChannelPath } from '../dev/channel';\nimport { resolveApplicationBuild } from './build';\nimport { loadServerBundle, makeRunnableHttpLayer } from './compiled-server';\nimport { DevOutputDir, EnvironmentConfig } from './contract';\nimport { makeDevChannel } from './dev-channel';\nimport { Rspack, type RspackError, type RspackWatchEvent } from './rspack';\nimport { makeRspackDevConfig } from './rspack-config';\nimport { formatDuration, Terminal } from './terminal';\n\ntype RspackCompilation = Extract<RspackWatchEvent, { readonly _tag: 'Compiled' }>;\n\nexport class DevGenerationError extends Schema.TaggedError<DevGenerationError>()(\n 'DevGenerationError',\n {\n message: Schema.String,\n cause: Schema.Defect(),\n },\n) {}\n\ntype AcquireDevGenerationOptions = {\n readonly compilation: RspackCompilation;\n readonly hostname: string;\n readonly port: number;\n readonly root: string;\n};\n\ntype DevGenerationOptions = Omit<AcquireDevGenerationOptions, 'compilation'>;\n\nexport type DevApplicationOptions = DevGenerationOptions;\n\nexport const acquireDevGeneration = Effect.fnUntraced(function* ({\n compilation,\n hostname,\n port,\n root,\n}: AcquireDevGenerationOptions) {\n const path = yield* Path.Path;\n const bundle = yield* loadServerBundle(\n path.resolve(compilation.serverBundle.outputPath, compilation.serverBundle.filename),\n );\n const HttpLayer = yield* makeRunnableHttpLayer({\n bundle,\n clientAssetsCacheControl: EnvironmentConfig.development.clientAssetsCacheControl,\n clientOutputDir: EnvironmentConfig.development.clientOutputDir,\n hostname,\n port,\n root,\n });\n const httpEffect = yield* HttpRouter.toHttpEffect(HttpLayer).pipe(\n Effect.mapError(\n (cause) =>\n new DevGenerationError({\n message: `Failed to start development generation ${compilation.hash}.`,\n cause,\n }),\n ),\n );\n\n return {\n hash: compilation.hash,\n httpEffect,\n };\n});\n\ntype DevGeneration = Effect.Success<ReturnType<typeof acquireDevGeneration>>;\ntype DevGenerationFailure = Effect.Error<ReturnType<typeof acquireDevGeneration>> | RspackError;\n\ntype DevGenerationState =\n | { readonly _tag: 'Unavailable' }\n | { readonly _tag: 'Ready'; readonly generation: DevGeneration };\n\nexport const makeDevGenerationStore = Effect.fnUntraced(function* (options: DevGenerationOptions) {\n const generation = yield* ScopedRef.make<DevGenerationState>(() => ({ _tag: 'Unavailable' }));\n const initialCompilation = yield* Deferred.make<DevGeneration, DevGenerationFailure>();\n const compilation = yield* Ref.make(initialCompilation);\n const update = Effect.fnUntraced(function* (event: RspackWatchEvent) {\n const current = yield* Ref.get(compilation);\n\n switch (event._tag) {\n case 'Building': {\n const compilationCompleted = yield* Deferred.isDone(current);\n if (compilationCompleted) {\n const next = yield* Deferred.make<DevGeneration, DevGenerationFailure>();\n yield* Ref.set(compilation, next);\n }\n return;\n }\n case 'Failed': {\n yield* Deferred.fail(current, event.error);\n return;\n }\n case 'Compiled': {\n yield* ScopedRef.set(\n generation,\n acquireDevGeneration({ ...options, compilation: event }).pipe(\n Effect.map((ready): DevGenerationState => ({\n _tag: 'Ready',\n generation: ready,\n })),\n Effect.tapError((error) => Deferred.fail(current, error)),\n ),\n );\n const ready = yield* ScopedRef.get(generation);\n if (ready._tag === 'Unavailable') {\n return yield* Effect.die(\n new TypeError('Expected the completed development generation to be available.'),\n );\n }\n yield* Deferred.succeed(current, ready.generation);\n }\n }\n });\n const httpEffect = Ref.get(compilation).pipe(\n Effect.flatMap(Deferred.await),\n Effect.flatMap((ready) => ready.httpEffect),\n );\n\n return {\n httpEffect,\n update,\n };\n});\n\nexport const makeDevApplication = Effect.fnUntraced(function* ({\n hostname,\n port,\n root,\n}: DevApplicationOptions) {\n const { applicationRoot, entries } = yield* resolveApplicationBuild({ root });\n const fileSystem = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const rspack = yield* Rspack;\n const channel = yield* makeDevChannel;\n\n yield* fileSystem.remove(path.join(applicationRoot, DevOutputDir), {\n force: true,\n recursive: true,\n });\n\n const generationStore = yield* makeDevGenerationStore({\n hostname,\n port,\n root: applicationRoot,\n });\n const update = Effect.fnUntraced(function* (event: RspackWatchEvent) {\n switch (event._tag) {\n case 'Building': {\n yield* generationStore.update(event);\n const firstChangedFile =\n event.changedFiles.find((file) => path.basename(file).includes('.')) ??\n event.changedFiles[0];\n const changedPath =\n firstChangedFile === undefined\n ? undefined\n : path.relative(applicationRoot, firstChangedFile);\n const subject = changedPath ?? 'application';\n\n yield* Effect.logInfo(`${Terminal.cyan('●')} Compiling ${subject}...`);\n return;\n }\n case 'Failed': {\n yield* generationStore.update(event);\n yield* channel.publishBuildFailure(event.diagnostics);\n yield* Effect.logError(event.error);\n return;\n }\n case 'Compiled': {\n if (event.warnings !== undefined) {\n yield* Effect.logWarning(event.warnings);\n }\n yield* generationStore.update(event).pipe(\n Effect.andThen(channel.publishCompilation(event.clientHash)),\n Effect.tap(() => {\n const duration =\n event.duration === undefined ? '' : ` in ${formatDuration(event.duration)}`;\n const compilers = event.compilers\n .map(({ duration, name }) =>\n duration === undefined ? name : `${name} ${formatDuration(duration)}`,\n )\n .join(' · ');\n const details = compilers.length === 0 ? '' : ` ${Terminal.dim(compilers)}`;\n\n return Effect.logInfo(`${Terminal.green('✓')} Ready${duration}${details}`);\n }),\n Effect.catch((error) => Effect.logError(error)),\n );\n }\n }\n });\n const watch = rspack\n .watch(\n makeRspackDevConfig(applicationRoot, entries, {\n onCompilationStart: channel.onCompilationStart,\n onServerComponentChanges: channel.onServerComponentChanges,\n }),\n )\n .pipe(Stream.runForEach(update));\n const httpEffect = yield* HttpRouter.toHttpEffect(\n HttpRouter.addAll([\n HttpRouter.route('GET', DevChannelPath, channel.httpEffect),\n HttpRouter.route('*', '/*', generationStore.httpEffect),\n ]),\n );\n\n return {\n closeDevChannel: channel.close,\n httpEffect,\n watch,\n };\n});\n\ntype DevApplication = Effect.Success<ReturnType<typeof makeDevApplication>>;\n\nexport const launchDevApplication = Effect.fnUntraced(function* (application: DevApplication) {\n return yield* Effect.scoped(\n Effect.gen(function* () {\n const server = yield* Layer.launch(HttpServer.serve(application.httpEffect)).pipe(\n Effect.forkScoped({ startImmediately: true }),\n );\n yield* Effect.addFinalizer(() => application.closeDevChannel);\n const watch = HttpServer.addressFormattedWith((address) =>\n Effect.logInfo(\n `${Terminal.magenta('▌')} effective-rsc ${Terminal.dim(PackageJson.version)} ${address}`,\n ),\n ).pipe(Effect.andThen(application.watch));\n\n return yield* Effect.raceFirst(watch, Fiber.join(server));\n }),\n );\n});\n\nexport const devApplication = Effect.fn('ersc/build/devApplication')(function* (\n options: DevApplicationOptions,\n) {\n const application = yield* makeDevApplication(options).pipe(Effect.provide(Rspack.layer));\n\n return yield* launchDevApplication(application);\n});\n"],"names":["Deferred","Effect","Fiber","FileSystem","Layer","Path","Ref","Schema","ScopedRef","Stream","HttpRouter","HttpServer","PackageJson","DevChannelPath","resolveApplicationBuild","loadServerBundle","makeRunnableHttpLayer","DevOutputDir","EnvironmentConfig","makeDevChannel","Rspack","makeRspackDevConfig","formatDuration","Terminal","DevGenerationError","acquireDevGeneration","compilation","hostname","port","root","path","bundle","HttpLayer","httpEffect","cause","makeDevGenerationStore","options","generation","initialCompilation","update","event","current","compilationCompleted","next","ready","error","TypeError","makeDevApplication","applicationRoot","entries","fileSystem","rspack","channel","generationStore","firstChangedFile","file","changedPath","undefined","subject","duration","compilers","name","details","watch","launchDevApplication","application","server","address","devApplication"],"mappings":"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"}
1
+ {"version":3,"file":"build/dev.js","sources":["../../src/build/dev.ts"],"sourcesContent":["import {\n Cause,\n Deferred,\n Effect,\n Fiber,\n FileSystem,\n Layer,\n Path,\n Ref,\n Schema,\n Scope,\n ScopedRef,\n Stream,\n} from 'effect';\nimport { HttpBody, HttpRouter, HttpServer, HttpServerResponse } from 'effect/unstable/http';\n\nimport PackageJson from '../../package.json' with { type: 'json' };\nimport { DevChannelPath } from '../dev/channel';\nimport { resolveApplicationBuild } from './build';\nimport { loadServerBundle, makeRunnableHttpLayer } from './compiled-server';\nimport { DevOutputDir, EnvironmentConfig } from './contract';\nimport { makeDevChannel } from './dev-channel';\nimport { Rspack, type RspackError, type RspackWatchEvent } from './rspack';\nimport { makeRspackDevConfig } from './rspack-config';\nimport { formatDuration, Terminal } from './terminal';\n\ntype RspackCompilation = Extract<RspackWatchEvent, { readonly _tag: 'Compiled' }>;\n\nexport class DevGenerationError extends Schema.TaggedError<DevGenerationError>()(\n 'DevGenerationError',\n {\n message: Schema.String,\n cause: Schema.Defect(),\n },\n) {}\n\ntype AcquireDevGenerationOptions = {\n readonly compilation: RspackCompilation;\n readonly hostname: string;\n readonly port: number;\n readonly root: string;\n};\n\ntype DevGenerationOptions = Omit<AcquireDevGenerationOptions, 'compilation'>;\n\nexport type DevApplicationOptions = DevGenerationOptions;\n\nexport const acquireDevGeneration = Effect.fnUntraced(function* ({\n compilation,\n hostname,\n port,\n root,\n}: AcquireDevGenerationOptions) {\n const path = yield* Path.Path;\n const bundle = yield* loadServerBundle(\n path.resolve(compilation.serverBundle.outputPath, compilation.serverBundle.filename),\n );\n const HttpLayer = yield* makeRunnableHttpLayer({\n bundle,\n clientAssetsCacheControl: EnvironmentConfig.development.clientAssetsCacheControl,\n clientOutputDir: EnvironmentConfig.development.clientOutputDir,\n hostname,\n port,\n root,\n });\n const httpEffect = yield* HttpRouter.toHttpEffect(HttpLayer).pipe(\n Effect.mapError(\n (cause) =>\n new DevGenerationError({\n message: `Failed to start development generation ${compilation.hash}.`,\n cause,\n }),\n ),\n );\n\n // Close request work before the generation's application services.\n const generationScope = yield* Effect.scope;\n const requests = yield* Scope.fork(generationScope, 'parallel');\n const ownRequest = Effect.withFiber((fiber) => {\n Fiber.runIn(fiber, requests);\n return Effect.void;\n });\n\n return {\n hash: compilation.hash,\n httpEffect: Effect.gen(function* () {\n yield* ownRequest;\n const response = yield* httpEffect;\n const body = response.body;\n if (body._tag !== 'Stream') {\n return response;\n }\n\n // Bun consumes the response body on a separate fiber after the handler returns.\n return HttpServerResponse.setBody(\n response,\n HttpBody.stream(\n Stream.onStart(body.stream, ownRequest),\n body.contentType,\n body.contentLength,\n ),\n );\n }),\n };\n});\n\ntype DevGeneration = Effect.Success<ReturnType<typeof acquireDevGeneration>>;\ntype DevGenerationFailure = Effect.Error<ReturnType<typeof acquireDevGeneration>> | RspackError;\n\ntype DevGenerationState =\n | { readonly _tag: 'Unavailable' }\n | { readonly _tag: 'Ready'; readonly generation: DevGeneration };\n\nexport const makeDevGenerationStore = Effect.fnUntraced(function* (options: DevGenerationOptions) {\n const generation = yield* ScopedRef.make<DevGenerationState>(() => ({ _tag: 'Unavailable' }));\n const initialCompilation = yield* Deferred.make<DevGeneration, DevGenerationFailure>();\n const compilation = yield* Ref.make(initialCompilation);\n const update = Effect.fnUntraced(function* (event: RspackWatchEvent) {\n const current = yield* Ref.get(compilation);\n\n switch (event._tag) {\n case 'Building': {\n const compilationCompleted = yield* Deferred.isDone(current);\n if (compilationCompleted) {\n const next = yield* Deferred.make<DevGeneration, DevGenerationFailure>();\n yield* Ref.set(compilation, next);\n }\n return;\n }\n case 'Failed': {\n yield* Deferred.fail(current, event.error);\n return;\n }\n case 'Compiled': {\n yield* ScopedRef.set(\n generation,\n acquireDevGeneration({ ...options, compilation: event }).pipe(\n Effect.interruptible,\n Effect.map((ready): DevGenerationState => ({\n _tag: 'Ready',\n generation: ready,\n })),\n Effect.tapError((error) => Deferred.fail(current, error)),\n ),\n );\n const ready = yield* ScopedRef.get(generation);\n if (ready._tag === 'Unavailable') {\n return yield* Effect.die(\n new TypeError('Expected the completed development generation to be available.'),\n );\n }\n yield* Deferred.succeed(current, ready.generation);\n }\n }\n });\n const httpEffect = Ref.get(compilation).pipe(\n Effect.flatMap(Deferred.await),\n Effect.flatMap((ready) => ready.httpEffect),\n );\n\n return {\n httpEffect,\n update,\n };\n});\n\nexport const makeDevApplication = Effect.fnUntraced(function* ({\n hostname,\n port,\n root,\n}: DevApplicationOptions) {\n const { applicationRoot, entries } = yield* resolveApplicationBuild({ root });\n const fileSystem = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const rspack = yield* Rspack;\n const channel = yield* makeDevChannel;\n\n yield* fileSystem.remove(path.join(applicationRoot, DevOutputDir), {\n force: true,\n recursive: true,\n });\n\n const generationStore = yield* makeDevGenerationStore({\n hostname,\n port,\n root: applicationRoot,\n });\n const update = Effect.fnUntraced(function* (event: RspackWatchEvent) {\n switch (event._tag) {\n case 'Building': {\n yield* generationStore.update(event);\n const firstChangedFile =\n event.changedFiles.find((file) => path.basename(file).includes('.')) ??\n event.changedFiles[0];\n const changedPath =\n firstChangedFile === undefined\n ? undefined\n : path.relative(applicationRoot, firstChangedFile);\n const subject = changedPath ?? 'application';\n\n yield* Effect.logInfo(`${Terminal.cyan('●')} Compiling ${subject}...`);\n return;\n }\n case 'Failed': {\n yield* generationStore.update(event);\n yield* channel.publishBuildFailure(event.diagnostics);\n yield* Effect.logError(event.error);\n return;\n }\n case 'Compiled': {\n if (event.warnings !== undefined) {\n yield* Effect.logWarning(event.warnings);\n }\n yield* generationStore.update(event).pipe(\n Effect.andThen(channel.publishCompilation(event.clientHash)),\n Effect.tap(() => {\n const duration =\n event.duration === undefined ? '' : ` in ${formatDuration(event.duration)}`;\n const compilers = event.compilers\n .map(({ duration, name }) =>\n duration === undefined ? name : `${name} ${formatDuration(duration)}`,\n )\n .join(' · ');\n const details = compilers.length === 0 ? '' : ` ${Terminal.dim(compilers)}`;\n\n return Effect.logInfo(`${Terminal.green('✓')} Ready${duration}${details}`);\n }),\n Effect.catch((error) =>\n channel\n .publishBuildFailure(Cause.pretty(Cause.fail(error)))\n .pipe(Effect.andThen(Effect.logError(error))),\n ),\n );\n }\n }\n });\n const watch = rspack\n .watch(\n makeRspackDevConfig(applicationRoot, entries, {\n onCompilationStart: channel.onCompilationStart,\n onServerComponentChanges: channel.onServerComponentChanges,\n }),\n )\n .pipe(Stream.runForEach(update));\n const httpEffect = yield* HttpRouter.toHttpEffect(\n HttpRouter.addAll([\n HttpRouter.route('GET', DevChannelPath, channel.httpEffect),\n HttpRouter.route('*', '/*', generationStore.httpEffect),\n ]),\n );\n\n return {\n closeDevChannel: channel.close,\n httpEffect,\n watch,\n };\n});\n\ntype DevApplication = Effect.Success<ReturnType<typeof makeDevApplication>>;\n\nexport const launchDevApplication = Effect.fnUntraced(function* (application: DevApplication) {\n return yield* Effect.scoped(\n Effect.gen(function* () {\n const server = yield* Layer.launch(HttpServer.serve(application.httpEffect)).pipe(\n Effect.forkScoped({ startImmediately: true }),\n );\n yield* Effect.addFinalizer(() => application.closeDevChannel);\n const watch = HttpServer.addressFormattedWith((address) =>\n Effect.logInfo(\n `${Terminal.magenta('▌')} effective-rsc ${Terminal.dim(PackageJson.version)} ${address}`,\n ),\n ).pipe(Effect.andThen(application.watch));\n\n return yield* Effect.raceFirst(watch, Fiber.join(server));\n }),\n );\n});\n\nexport const devApplication = Effect.fn('ersc/build/devApplication')(function* (\n options: DevApplicationOptions,\n) {\n const application = yield* makeDevApplication(options).pipe(Effect.provide(Rspack.layer));\n\n return yield* launchDevApplication(application);\n});\n"],"names":["Cause","Deferred","Effect","Fiber","FileSystem","Layer","Path","Ref","Schema","Scope","ScopedRef","Stream","HttpBody","HttpRouter","HttpServer","HttpServerResponse","PackageJson","DevChannelPath","resolveApplicationBuild","loadServerBundle","makeRunnableHttpLayer","DevOutputDir","EnvironmentConfig","makeDevChannel","Rspack","makeRspackDevConfig","formatDuration","Terminal","DevGenerationError","acquireDevGeneration","compilation","hostname","port","root","path","bundle","HttpLayer","httpEffect","cause","generationScope","requests","ownRequest","fiber","response","body","makeDevGenerationStore","options","generation","initialCompilation","update","event","current","compilationCompleted","next","ready","error","TypeError","makeDevApplication","applicationRoot","entries","fileSystem","rspack","channel","generationStore","firstChangedFile","file","changedPath","undefined","subject","duration","compilers","name","details","watch","launchDevApplication","application","server","address","devApplication"],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -83,6 +83,8 @@ const runDev = Effect.fnUntraced(function*({ hostname, port }) {
83
83
  root: process.cwd()
84
84
  }).pipe(Effect.provide(__rspack_external__effect_platform_bun_BunHttpServer_0e4f7bbb.layer({
85
85
  development: true,
86
+ // Explicit dev shutdown interrupts request scopes before releasing their generations.
87
+ disablePreemptiveShutdown: true,
86
88
  hostname,
87
89
  idleTimeout: ApplicationIdleTimeoutSeconds,
88
90
  maxRequestBodySize: ApplicationMaxRequestBodySizeBytes,