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
package/LLMS.md CHANGED
@@ -159,6 +159,41 @@ reach.
159
159
 
160
160
  - **[Composing ERSC and userland HTTP](./docs/02-guides/05-http/10_application-layer.tsx)**: ERSC concerns and native HTTP routes share one application Layer.
161
161
 
162
+ ### Deploying to Vercel
163
+
164
+ Deploy to Vercel with Bun 1.4+. Match the adapter version to `effective-rsc`.
165
+
166
+ ```sh
167
+ bun add --dev @ersc/vercel
168
+ ```
169
+
170
+ Set the build script in `package.json`:
171
+
172
+ ```json
173
+ {
174
+ "scripts": {
175
+ "build": "ersc build --adapter @ersc/vercel"
176
+ }
177
+ }
178
+ ```
179
+
180
+ Commit `bun.lock`, connect your GitHub repository in Vercel, and set:
181
+
182
+ | Setting | Value |
183
+ | ---------------- | ------------------------------- |
184
+ | Framework Preset | Other |
185
+ | Root Directory | Application directory |
186
+ | Install Command | `bun install --frozen-lockfile` |
187
+ | Build Command | `bun run --bun build` |
188
+ | Output Directory | Leave the override disabled |
189
+
190
+ Add your environment variables and deploy. The adapter generates `.vercel/output/`; no custom
191
+ server entry or `vercel.json` is needed.
192
+
193
+ For [monorepos](https://vercel.com/docs/monorepos/monorepo-faq), enable **Include source files outside
194
+ of the Root Directory in the Build Step**. With Turborepo, use
195
+ `bun run --bun turbo run build --filter=your-app` to build the app and its workspace dependencies.
196
+
162
197
  ## Advanced
163
198
 
164
199
  These guides describe ERSC's runtime guarantees. See the
@@ -244,6 +279,23 @@ These types describe only the first publication. Suspense content that resolves
244
279
  separate, untyped React Transition. Applications should use their own Suspense-specific
245
280
  `<ViewTransition>` boundaries and styling for those reveals.
246
281
 
282
+ #### Application transition types
283
+
284
+ Add whitespace-separated application transition types to a native link with
285
+ `data-ersc-transition-types`:
286
+
287
+ ```tsx
288
+ <a href='/photos/2' data-ersc-transition-types='photo-next'>
289
+ Next photo
290
+ </a>
291
+ ```
292
+
293
+ These are added alongside ERSC's built-in types for that push or replace navigation and can be
294
+ used in your `<ViewTransition>` type maps. They are not replayed on Back/Forward.
295
+
296
+ The names `navigation`, `navigation-*`, `server-function`, and `hmr-refresh` are reserved for ERSC
297
+ and ignored in the attribute.
298
+
247
299
  ## Server Function execution and refresh
248
300
 
249
301
  Hydrated invocations and progressively enhanced forms execute the same request-scoped Effect
@@ -264,6 +316,39 @@ commit inside an async Action.
264
316
  After a successful mutation, ERSC clears the Back/Forward traversal cache because any route may have
265
317
  changed.
266
318
 
319
+ ## Production startup
320
+
321
+ Run `ersc build`, then `ersc start`. A custom Bun entry can await
322
+ `start({ root, hostname, port })` from `effective-rsc/server`. All options are required;
323
+ `root` is the application directory. Deploy its `.ersc/`, `public/`, and runtime dependencies.
324
+
325
+ The Promise resolves when ready; startup failures reject and exit. ERSC owns signal handling
326
+ and cleanup, so do not wrap it in `BunRuntime.runMain`.
327
+
328
+ ### Deployment adapters
329
+
330
+ `ersc build --adapter <package>` runs an installed adapter after compilation; it does not upload.
331
+ Without the flag, packaging is skipped and previous output remains.
332
+
333
+ Adapters export `build: BuildHook` from `./build`, with types from `effective-rsc/build`.
334
+ The hook receives absolute `root`, `serverDir`, `clientDir`, and `publicDir` paths and returns
335
+ `Effect<void, Error, Scope>`. Inputs are read-only; adapters provide dependencies and ERSC owns
336
+ cleanup/cancellation. Failures stop the build.
337
+
338
+ ### Server entry
339
+
340
+ Save this as `server.ts` in the application root and run it with `bun server.ts` after building.
341
+
342
+ ```ts
343
+ import { start } from 'effective-rsc/server';
344
+
345
+ await start({
346
+ hostname: 'localhost',
347
+ port: 18193,
348
+ root: import.meta.dir,
349
+ });
350
+ ```
351
+
267
352
  ## API reference
268
353
 
269
354
  Under the `react-server` condition, the package root exports `Application`.
package/README.md CHANGED
@@ -65,11 +65,11 @@ mkdir my-effective-rsc-app
65
65
  cd my-effective-rsc-app
66
66
  bun init -y
67
67
  bun add effective-rsc \
68
- effect@4.0.0-rc.112 \
69
- @effect/platform-browser@4.0.0-rc.112 \
70
- @effect/platform-bun@4.0.0-rc.112 \
71
- react@19.3.0-canary-8425b691-20260904 \
72
- react-dom@19.3.0-canary-8425b691-20260904 \
68
+ effect@4.0.0-rc.113 \
69
+ @effect/platform-browser@4.0.0-rc.113 \
70
+ @effect/platform-bun@4.0.0-rc.113 \
71
+ react@19.3.0-canary-1d34f91d-20260909 \
72
+ react-dom@19.3.0-canary-1d34f91d-20260909 \
73
73
  react-server-dom-rspack@0.1.0
74
74
  bun add --dev \
75
75
  typescript@7.0.2 \
@@ -154,6 +154,10 @@ Run `bun run dev`, then open `http://localhost:18193`. For a production run, use
154
154
  For deployment, `ersc start` accepts `--hostname` and `--port`. Command-line flags take precedence
155
155
  over `HOST` and `PORT`; the defaults are `localhost` and `18193`.
156
156
 
157
+ For a custom Bun entry, await `start({ root, hostname, port })` from `effective-rsc/server`.
158
+ Use `ersc build --adapter <package>` to package deployment output without uploading it.
159
+ See the [production startup guide](https://github.com/nikhilsnayak/effective-rsc/blob/main/packages/effective-rsc/docs/03-advanced/04-production-startup/index.md).
160
+
157
161
  ## Styling
158
162
 
159
163
  Import stylesheets from the modules that use them; there is no framework stylesheet entry point:
@@ -199,10 +203,12 @@ The package-root API is available only under the `react-server` condition. The f
199
203
  enables that condition for application authoring modules; importing `effective-rsc` from another
200
204
  runtime, including a Client Component, throws immediately.
201
205
 
202
- ## Example and documentation
206
+ ## Examples and documentation
203
207
 
204
- The [event platform](https://github.com/nikhilsnayak/effective-rsc/tree/main/examples/event-platform)
205
- is the complete application example.
208
+ - [Hello world](https://github.com/nikhilsnayak/effective-rsc/tree/main/examples/hello-world): a small
209
+ example with streaming, navigation, a counter, and a Server Function form.
210
+ - [Event platform](https://github.com/nikhilsnayak/effective-rsc/tree/main/examples/event-platform):
211
+ the complete application example, using local SQLite persistence.
206
212
 
207
213
  - [Getting started](https://github.com/nikhilsnayak/effective-rsc/blob/main/packages/effective-rsc/docs/01-getting-started/index.md)
208
214
  - [Guides](https://github.com/nikhilsnayak/effective-rsc/blob/main/packages/effective-rsc/docs/02-guides/index.md)
@@ -6,14 +6,14 @@ import type { AnyMiddleware } from './middleware.js';
6
6
  import { type AnyPageDefinition, type PageConcern } from './page.js';
7
7
  import { type AbsolutePath, type JoinPath, type RouteParamNames, type RouteShape, type ValidRoutePath } from './route-path.js';
8
8
  declare const RoutesContractTypeId: unique symbol;
9
- type RoutesState<HasLayout extends boolean, Paths extends AbsolutePath> = {
9
+ type RoutesState<HasLayout extends boolean, Paths extends AbsolutePath, Shapes extends AbsolutePath> = {
10
10
  readonly hasLayout: Types.Covariant<HasLayout>;
11
11
  readonly paths: Types.Covariant<Paths>;
12
+ readonly shapes: Types.Covariant<Shapes>;
12
13
  };
13
14
  type MountedPaths<Prefix extends AbsolutePath, Child> = RoutesPaths<Child> extends infer Path extends AbsolutePath ? JoinPath<Prefix, Path> : never;
14
- type RouteShapes<Paths extends AbsolutePath> = Paths extends AbsolutePath ? RouteShape<Paths> : never;
15
- type NoPathCollision<Current extends AbsolutePath, Added extends AbsolutePath> = [
16
- Extract<RouteShapes<Current>, RouteShapes<Added>>
15
+ type NoPathCollision<CurrentShapes extends AbsolutePath, Added extends AbsolutePath> = [
16
+ Extract<RouteShape<Added>, CurrentShapes>
17
17
  ] extends [never] ? unknown : never;
18
18
  type PageParamNames<Page> = Page extends PageConcern<infer ParamNames, infer _Mode> ? ParamNames : never;
19
19
  type PageMode<Page> = Page extends PageConcern<infer _ParamNames, infer Mode> ? Mode : never;
@@ -23,14 +23,14 @@ type ExactPageParamNames<Path extends AbsolutePath, Page> = [RouteParamNames<Pat
23
23
  type MatchingPageParams<Path extends AbsolutePath, Page> = PageMode<Page> extends 'Static' ? [RouteParamNames<Path>] extends [never] ? unknown : never : PageMode<Page> extends 'Parameterized' ? [RouteParamNames<Path>] extends [never] ? never : ExactPageParamNames<Path, Page> : never;
24
24
  type StaticMountPath<Path extends AbsolutePath> = [RouteParamNames<Path>] extends [never] ? unknown : never;
25
25
  type KnownNonEmptyRoutes<Definition> = AbsolutePath extends RoutesPaths<Definition> ? never : [RoutesPaths<Definition>] extends [never] ? never : unknown;
26
- export interface RoutesDefinition<Services, out HasLayout extends boolean, out Paths extends AbsolutePath> extends ERSCStatefulMember<Services, 'Routes', RoutesImplementationState<Services>> {
27
- readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths>;
28
- page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(path: Path & ValidRoutePath<Path> & NoPathCollision<Paths, Path>, page: Page & MatchingPageParams<Path, Page>): RoutesDefinition<Services, HasLayout, Paths | Path>;
29
- mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>, routes: Child & KnownNonEmptyRoutes<Child> & NoPathCollision<Paths, MountedPaths<Prefix, Child>>): RoutesDefinition<Services, HasLayout, Paths | MountedPaths<Prefix, Child>>;
26
+ export interface RoutesDefinition<Services, out HasLayout extends boolean, out Paths extends AbsolutePath, out Shapes extends AbsolutePath = RouteShape<Paths>> extends ERSCStatefulMember<Services, 'Routes', RoutesImplementationState<Services>> {
27
+ readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths, Shapes>;
28
+ page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(path: Path & ValidRoutePath<Path> & NoPathCollision<Shapes, Path>, page: Page & MatchingPageParams<Path, Page>): RoutesDefinition<Services, HasLayout, Paths | Path, Shapes | RouteShape<Path>>;
29
+ mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>, routes: Child & KnownNonEmptyRoutes<Child> & NoPathCollision<Shapes, MountedPaths<Prefix, Child>>): RoutesDefinition<Services, HasLayout, Paths | MountedPaths<Prefix, Child>, Shapes | RouteShape<MountedPaths<Prefix, Child>>>;
30
30
  }
31
31
  export type AnyRoutes<Services> = RoutesDefinition<Services, boolean, AbsolutePath>;
32
- export type RoutesHasLayout<Definition> = Definition extends RoutesDefinition<infer _Services, infer HasLayout, infer _Paths> ? HasLayout : never;
33
- export type RoutesPaths<Definition> = Definition extends RoutesDefinition<infer _Services, infer _HasLayout, infer Paths> ? Paths : never;
32
+ export type RoutesHasLayout<Definition> = Definition extends RoutesDefinition<infer _Services, infer HasLayout, infer _Paths, infer _Shapes> ? HasLayout : never;
33
+ export type RoutesPaths<Definition> = Definition extends RoutesDefinition<infer _Services, infer _HasLayout, infer Paths, infer _Shapes> ? Paths : never;
34
34
  type RoutesPage<Services> = {
35
35
  readonly page: AnyPageDefinition<Services>;
36
36
  readonly path: AbsolutePath;
@@ -1 +1 @@
1
- {"version":3,"file":"application/routes.js","sources":["../../src/application/routes.ts"],"sourcesContent":["import { type Types } from 'effect';\n\nimport {\n type ERSCIdentity,\n ERSCIdentityTypeId,\n ERSCMemberKindTypeId,\n type ERSCStatefulMember,\n ERSCStateTypeId,\n getERSCIdentity,\n isERSCMember,\n} from './ersc-identity';\nimport type { LayoutComponent } from './layout';\nimport type { LoadingComponent } from './loading';\nimport type { AnyMiddleware } from './middleware';\nimport { type AnyPageDefinition, getPageState, type PageConcern } from './page';\nimport {\n type AbsolutePath,\n analyzeRoutePath,\n joinRoutePaths,\n type JoinPath,\n type RouteParamNames,\n type RouteShape,\n type ValidRoutePath,\n} from './route-path';\n\ndeclare const RoutesContractTypeId: unique symbol;\n\ntype RoutesState<HasLayout extends boolean, Paths extends AbsolutePath> = {\n readonly hasLayout: Types.Covariant<HasLayout>;\n readonly paths: Types.Covariant<Paths>;\n};\n\ntype MountedPaths<Prefix extends AbsolutePath, Child> =\n RoutesPaths<Child> extends infer Path extends AbsolutePath ? JoinPath<Prefix, Path> : never;\n\ntype RouteShapes<Paths extends AbsolutePath> = Paths extends AbsolutePath\n ? RouteShape<Paths>\n : never;\n\ntype NoPathCollision<Current extends AbsolutePath, Added extends AbsolutePath> = [\n Extract<RouteShapes<Current>, RouteShapes<Added>>,\n] extends [never]\n ? unknown\n : never;\n\ntype PageParamNames<Page> =\n Page extends PageConcern<infer ParamNames, infer _Mode> ? ParamNames : never;\n\ntype PageMode<Page> = Page extends PageConcern<infer _ParamNames, infer Mode> ? Mode : never;\n\ntype ExactPageParamNames<Path extends AbsolutePath, Page> = [RouteParamNames<Path>] extends [\n PageParamNames<Page>,\n]\n ? [PageParamNames<Page>] extends [RouteParamNames<Path>]\n ? unknown\n : never\n : never;\n\ntype MatchingPageParams<Path extends AbsolutePath, Page> =\n PageMode<Page> extends 'Static'\n ? [RouteParamNames<Path>] extends [never]\n ? unknown\n : never\n : PageMode<Page> extends 'Parameterized'\n ? [RouteParamNames<Path>] extends [never]\n ? never\n : ExactPageParamNames<Path, Page>\n : never;\n\ntype StaticMountPath<Path extends AbsolutePath> = [RouteParamNames<Path>] extends [never]\n ? unknown\n : never;\n\ntype KnownNonEmptyRoutes<Definition> =\n AbsolutePath extends RoutesPaths<Definition>\n ? never\n : [RoutesPaths<Definition>] extends [never]\n ? never\n : unknown;\n\nexport interface RoutesDefinition<\n Services,\n out HasLayout extends boolean,\n out Paths extends AbsolutePath,\n> extends ERSCStatefulMember<Services, 'Routes', RoutesImplementationState<Services>> {\n readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths>;\n\n page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(\n path: Path & ValidRoutePath<Path> & NoPathCollision<Paths, Path>,\n page: Page & MatchingPageParams<Path, Page>,\n ): RoutesDefinition<Services, HasLayout, Paths | Path>;\n\n mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(\n path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>,\n routes: Child &\n KnownNonEmptyRoutes<Child> &\n NoPathCollision<Paths, MountedPaths<Prefix, Child>>,\n ): RoutesDefinition<Services, HasLayout, Paths | MountedPaths<Prefix, Child>>;\n}\n\nexport type AnyRoutes<Services> = RoutesDefinition<Services, boolean, AbsolutePath>;\n\nexport type RoutesHasLayout<Definition> =\n Definition extends RoutesDefinition<infer _Services, infer HasLayout, infer _Paths>\n ? HasLayout\n : never;\n\nexport type RoutesPaths<Definition> =\n Definition extends RoutesDefinition<infer _Services, infer _HasLayout, infer Paths>\n ? Paths\n : never;\n\ntype RoutesPage<Services> = {\n readonly page: AnyPageDefinition<Services>;\n readonly path: AbsolutePath;\n};\n\ntype RoutesMount<Services> = {\n readonly path: AbsolutePath;\n readonly routes: AnyRoutes<Services>;\n};\n\nexport type RoutesImplementationState<Services> = {\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly mounts: ReadonlyArray<RoutesMount<Services>>;\n readonly pages: ReadonlyArray<RoutesPage<Services>>;\n readonly paths: ReadonlyArray<AbsolutePath>;\n readonly scopeId: number;\n};\n\ntype RoutesOptions<Services> = {\n readonly layout?: LayoutComponent<Services>;\n readonly loading?: LoadingComponent<Services>;\n};\n\ntype HasLayoutFromOptions<Options> = Options extends { readonly layout: unknown } ? true : false;\n\ntype RuntimeRoutesOptions<Services> = RoutesImplementationState<Services> & {\n readonly routeShapes: ReadonlySet<string>;\n};\n\nclass RoutesDefinitionImpl<\n Services,\n HasLayout extends boolean,\n Paths extends AbsolutePath,\n> implements RoutesDefinition<Services, HasLayout, Paths> {\n declare readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths>;\n readonly [ERSCIdentityTypeId]: ERSCIdentity<Services>;\n readonly [ERSCMemberKindTypeId] = 'Routes' as const;\n get [ERSCStateTypeId](): RoutesImplementationState<Services> {\n return this;\n }\n\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly mounts: ReadonlyArray<RoutesMount<Services>>;\n readonly pages: ReadonlyArray<RoutesPage<Services>>;\n readonly paths: ReadonlyArray<AbsolutePath>;\n readonly scopeId: number;\n readonly #routeShapes: ReadonlySet<string>;\n\n constructor(\n identity: ERSCIdentity<Services>,\n {\n layout,\n loading,\n middleware,\n mounts,\n pages,\n paths,\n routeShapes,\n scopeId,\n }: RuntimeRoutesOptions<Services>,\n ) {\n this[ERSCIdentityTypeId] = identity;\n this.layout = layout;\n this.loading = loading;\n this.middleware = middleware;\n this.mounts = mounts;\n this.pages = pages;\n this.paths = paths;\n this.scopeId = scopeId;\n this.#routeShapes = routeShapes;\n Object.freeze(this);\n }\n\n page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(\n path: Path & ValidRoutePath<Path> & NoPathCollision<Paths, Path>,\n page: Page & MatchingPageParams<Path, Page>,\n ): RoutesDefinitionImpl<Services, HasLayout, Paths | Path> {\n const route = analyzeRoutePath(path);\n if (this.#routeShapes.has(route.shape)) {\n throw new TypeError(`Route \"${path}\" conflicts with an existing route pattern.`);\n }\n const pageState = getPageState(page);\n if (getERSCIdentity(page) !== this[ERSCIdentityTypeId]) {\n throw new TypeError(`Page for \"${path}\" was created by a different ERSC module.`);\n }\n\n if (route._tag === 'ParameterFree' && pageState.paramsSchema !== null) {\n throw new TypeError(`Parameterized Page for \"${path}\" requires route parameters.`);\n }\n if (route._tag === 'Parameterized' && pageState.paramsSchema === null) {\n throw new TypeError(`Page for \"${path}\" must declare a parameter Schema.`);\n }\n\n const routeShapes = new Set(this.#routeShapes);\n routeShapes.add(route.shape);\n\n return new RoutesDefinitionImpl(this[ERSCIdentityTypeId], {\n layout: this.layout,\n loading: this.loading,\n middleware: this.middleware,\n mounts: this.mounts,\n pages: Object.freeze([...this.pages, Object.freeze({ page, path })]),\n paths: Object.freeze([...this.paths, path]),\n routeShapes,\n scopeId: this.scopeId,\n });\n }\n\n mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(\n path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>,\n routes: Child &\n KnownNonEmptyRoutes<Child> &\n NoPathCollision<Paths, MountedPaths<Prefix, Child>>,\n ): RoutesDefinitionImpl<Services, HasLayout, Paths | MountedPaths<Prefix, Child>> {\n const route = analyzeRoutePath(path);\n if (route._tag === 'Parameterized') {\n throw new TypeError(`Routes cannot be mounted beneath parameterized path \"${path}\".`);\n }\n const routesState = getRoutesState(routes);\n if (routesState.paths.length === 0) {\n throw new TypeError(`Cannot mount empty Routes at \"${path}\".`);\n }\n if (getERSCIdentity(routes) !== this[ERSCIdentityTypeId]) {\n throw new TypeError(`Routes mounted at \"${path}\" were created by a different ERSC module.`);\n }\n\n const mountedPaths = routesState.paths.map((childPath) => joinRoutePaths(path, childPath));\n const routeShapes = new Set(this.#routeShapes);\n for (const mountedPath of mountedPaths) {\n const shape = analyzeRoutePath(mountedPath).shape;\n if (routeShapes.has(shape)) {\n throw new TypeError(`Route \"${mountedPath}\" conflicts with an existing route pattern.`);\n }\n routeShapes.add(shape);\n }\n\n return new RoutesDefinitionImpl(this[ERSCIdentityTypeId], {\n layout: this.layout,\n loading: this.loading,\n middleware: this.middleware,\n mounts: Object.freeze([...this.mounts, Object.freeze({ path, routes })]),\n pages: this.pages,\n paths: Object.freeze([...this.paths, ...mountedPaths]),\n routeShapes,\n scopeId: this.scopeId,\n });\n }\n}\n\nexport const getRoutesState = <Services>(\n routes: AnyRoutes<Services>,\n): RoutesImplementationState<Services> => {\n if (!isERSCMember(routes, 'Routes')) {\n throw new TypeError('Routes must be created with ERSC.Routes.make.');\n }\n return routes[ERSCStateTypeId];\n};\n\nexport type RoutesFactory<Services> = {\n readonly make: {\n (): RoutesDefinition<Services, false, never>;\n <Options extends RoutesOptions<Services>>(\n options: Options,\n ): RoutesDefinition<Services, HasLayoutFromOptions<Options>, never>;\n };\n};\n\nexport const makeRoutesFactory = <Services>(\n identity: ERSCIdentity<Services>,\n middleware: ReadonlyArray<AnyMiddleware<Services>>,\n allocateScopeId: () => number,\n): RoutesFactory<Services> => {\n function make(): RoutesDefinition<Services, false, never>;\n function make<Options extends RoutesOptions<Services>>(\n options: Options,\n ): RoutesDefinition<Services, HasLayoutFromOptions<Options>, never>;\n function make(options: RoutesOptions<Services> = {}): AnyRoutes<Services> {\n if (options.layout !== undefined) {\n if (!isERSCMember(options.layout, 'Layout')) {\n throw new TypeError('Layout must be created with ERSC.Layout.make.');\n }\n if (getERSCIdentity(options.layout) !== identity) {\n throw new TypeError('Layout was created by a different ERSC module.');\n }\n }\n if (options.loading !== undefined) {\n if (!isERSCMember(options.loading, 'Loading')) {\n throw new TypeError('Loading must be created with ERSC.Loading.make.');\n }\n if (getERSCIdentity(options.loading) !== identity) {\n throw new TypeError('Loading was created by a different ERSC module.');\n }\n }\n const scopeId = allocateScopeId();\n\n return new RoutesDefinitionImpl(identity, {\n layout: options.layout ?? null,\n loading: options.loading ?? null,\n middleware,\n mounts: Object.freeze([]),\n pages: Object.freeze([]),\n paths: Object.freeze([]),\n routeShapes: new Set(),\n scopeId,\n });\n }\n\n return { make };\n};\n"],"names":["ERSCIdentityTypeId","ERSCMemberKindTypeId","ERSCStateTypeId","getERSCIdentity","isERSCMember","getPageState","analyzeRoutePath","joinRoutePaths","RoutesDefinitionImpl","identity","layout","loading","middleware","mounts","pages","paths","routeShapes","scopeId","Object","path","page","route","TypeError","pageState","Set","routes","routesState","getRoutesState","mountedPaths","childPath","mountedPath","shape","makeRoutesFactory","allocateScopeId","make","options","undefined"],"mappings":";;;;;;;AAUyB;AAIuD;AAS1D;AAwHtB,MAAMQ,oBAAoBA;IAMf,CAACR,kBAAkBA,CAAC,CAAyB;IAC7C,CAACC,oBAAoBA,CAAC,GAAG,SAAkB;IACpD,IAAI,CAACC,eAAeA,CAAC,GAAwC;QAC3D,OAAO,IAAI;IACb;IAES,OAAyC;IACzC,QAA2C;IAC3C,WAAmD;IACnD,OAA6C;IAC7C,MAA2C;IAC3C,MAAmC;IACnC,QAAgB;IAChB,YAAY,CAAsB;IAE3C,YACEO,QAAgC,EAChC,EACEC,MAAM,EACNC,OAAO,EACPC,UAAU,EACVC,MAAM,EACNC,KAAK,EACLC,KAAK,EACLC,WAAW,EACXC,OAAO,EACwB,CACjC;QACA,IAAI,CAACjB,kBAAkBA,CAAC,GAAGS;QAC3B,IAAI,CAAC,MAAM,GAAGC;QACd,IAAI,CAAC,OAAO,GAAGC;QACf,IAAI,CAAC,UAAU,GAAGC;QAClB,IAAI,CAAC,MAAM,GAAGC;QACd,IAAI,CAAC,KAAK,GAAGC;QACb,IAAI,CAAC,KAAK,GAAGC;QACb,IAAI,CAAC,OAAO,GAAGE;QACf,IAAI,CAAC,YAAY,GAAGD;QACpBE,OAAO,MAAM,CAAC,IAAI;IACpB;IAEA,KACEC,IAAgE,EAChEC,IAA2C,EACc;QACzD,MAAMC,QAAQf,gBAAgBA,CAACa;QAC/B,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAACE,MAAM,KAAK,GAAG;YACtC,MAAM,IAAIC,UAAU,CAAC,OAAO,EAAEH,KAAK,2CAA2C,CAAC;QACjF;QACA,MAAMI,YAAYlB,YAAYA,CAACe;QAC/B,IAAIjB,eAAeA,CAACiB,UAAU,IAAI,CAACpB,kBAAkBA,CAAC,EAAE;YACtD,MAAM,IAAIsB,UAAU,CAAC,UAAU,EAAEH,KAAK,yCAAyC,CAAC;QAClF;QAEA,IAAIE,MAAM,IAAI,KAAK,mBAAmBE,UAAU,YAAY,KAAK,MAAM;YACrE,MAAM,IAAID,UAAU,CAAC,wBAAwB,EAAEH,KAAK,4BAA4B,CAAC;QACnF;QACA,IAAIE,MAAM,IAAI,KAAK,mBAAmBE,UAAU,YAAY,KAAK,MAAM;YACrE,MAAM,IAAID,UAAU,CAAC,UAAU,EAAEH,KAAK,kCAAkC,CAAC;QAC3E;QAEA,MAAMH,cAAc,IAAIQ,IAAI,IAAI,CAAC,YAAY;QAC7CR,YAAY,GAAG,CAACK,MAAM,KAAK;QAE3B,OAAO,IAAIb,oBAAoBA,CAAC,IAAI,CAACR,kBAAkBA,CAAC,EAAE;YACxD,QAAQ,IAAI,CAAC,MAAM;YACnB,SAAS,IAAI,CAAC,OAAO;YACrB,YAAY,IAAI,CAAC,UAAU;YAC3B,QAAQ,IAAI,CAAC,MAAM;YACnB,OAAOkB,OAAO,MAAM,CAAC;mBAAI,IAAI,CAAC,KAAK;gBAAEA,OAAO,MAAM,CAAC;oBAAEE;oBAAMD;gBAAK;aAAG;YACnE,OAAOD,OAAO,MAAM,CAAC;mBAAI,IAAI,CAAC,KAAK;gBAAEC;aAAK;YAC1CH;YACA,SAAS,IAAI,CAAC,OAAO;QACvB;IACF;IAEA,MACEG,IAA+D,EAC/DM,MAEqD,EAC2B;QAChF,MAAMJ,QAAQf,gBAAgBA,CAACa;QAC/B,IAAIE,MAAM,IAAI,KAAK,iBAAiB;YAClC,MAAM,IAAIC,UAAU,CAAC,qDAAqD,EAAEH,KAAK,EAAE,CAAC;QACtF;QACA,MAAMO,cAAcC,cAAcA,CAACF;QACnC,IAAIC,YAAY,KAAK,CAAC,MAAM,KAAK,GAAG;YAClC,MAAM,IAAIJ,UAAU,CAAC,8BAA8B,EAAEH,KAAK,EAAE,CAAC;QAC/D;QACA,IAAIhB,eAAeA,CAACsB,YAAY,IAAI,CAACzB,kBAAkBA,CAAC,EAAE;YACxD,MAAM,IAAIsB,UAAU,CAAC,mBAAmB,EAAEH,KAAK,0CAA0C,CAAC;QAC5F;QAEA,MAAMS,eAAeF,YAAY,KAAK,CAAC,GAAG,CAAC,CAACG,YAActB,cAAcA,CAACY,MAAMU;QAC/E,MAAMb,cAAc,IAAIQ,IAAI,IAAI,CAAC,YAAY;QAC7C,KAAK,MAAMM,eAAeF,aAAc;YACtC,MAAMG,QAAQzB,gBAAgBA,CAACwB,aAAa,KAAK;YACjD,IAAId,YAAY,GAAG,CAACe,QAAQ;gBAC1B,MAAM,IAAIT,UAAU,CAAC,OAAO,EAAEQ,YAAY,2CAA2C,CAAC;YACxF;YACAd,YAAY,GAAG,CAACe;QAClB;QAEA,OAAO,IAAIvB,oBAAoBA,CAAC,IAAI,CAACR,kBAAkBA,CAAC,EAAE;YACxD,QAAQ,IAAI,CAAC,MAAM;YACnB,SAAS,IAAI,CAAC,OAAO;YACrB,YAAY,IAAI,CAAC,UAAU;YAC3B,QAAQkB,OAAO,MAAM,CAAC;mBAAI,IAAI,CAAC,MAAM;gBAAEA,OAAO,MAAM,CAAC;oBAAEC;oBAAMM;gBAAO;aAAG;YACvE,OAAO,IAAI,CAAC,KAAK;YACjB,OAAOP,OAAO,MAAM,CAAC;mBAAI,IAAI,CAAC,KAAK;mBAAKU;aAAa;YACrDZ;YACA,SAAS,IAAI,CAAC,OAAO;QACvB;IACF;AACF;AAEO,MAAMW,cAAcA,GAAG,CAC5BF;IAEA,IAAI,CAACrB,YAAYA,CAACqB,QAAQ,WAAW;QACnC,MAAM,IAAIH,UAAU;IACtB;IACA,OAAOG,MAAM,CAACvB,eAAeA,CAAC;AAChC,EAAE;AAWK,MAAM8B,iBAAiBA,GAAG,CAC/BvB,UACAG,YACAqB;IAMA,SAASC,KAAKC,UAAmC,CAAC,CAAC;QACjD,IAAIA,QAAQ,MAAM,KAAKC,WAAW;YAChC,IAAI,CAAChC,YAAYA,CAAC+B,QAAQ,MAAM,EAAE,WAAW;gBAC3C,MAAM,IAAIb,UAAU;YACtB;YACA,IAAInB,eAAeA,CAACgC,QAAQ,MAAM,MAAM1B,UAAU;gBAChD,MAAM,IAAIa,UAAU;YACtB;QACF;QACA,IAAIa,QAAQ,OAAO,KAAKC,WAAW;YACjC,IAAI,CAAChC,YAAYA,CAAC+B,QAAQ,OAAO,EAAE,YAAY;gBAC7C,MAAM,IAAIb,UAAU;YACtB;YACA,IAAInB,eAAeA,CAACgC,QAAQ,OAAO,MAAM1B,UAAU;gBACjD,MAAM,IAAIa,UAAU;YACtB;QACF;QACA,MAAML,UAAUgB;QAEhB,OAAO,IAAIzB,oBAAoBA,CAACC,UAAU;YACxC,QAAQ0B,QAAQ,MAAM,IAAI;YAC1B,SAASA,QAAQ,OAAO,IAAI;YAC5BvB;YACA,QAAQM,OAAO,MAAM,CAAC,EAAE;YACxB,OAAOA,OAAO,MAAM,CAAC,EAAE;YACvB,OAAOA,OAAO,MAAM,CAAC,EAAE;YACvB,aAAa,IAAIM;YACjBP;QACF;IACF;IAEA,OAAO;QAAEiB;IAAK;AAChB,EAAE"}
1
+ {"version":3,"file":"application/routes.js","sources":["../../src/application/routes.ts"],"sourcesContent":["import { type Types } from 'effect';\n\nimport {\n type ERSCIdentity,\n ERSCIdentityTypeId,\n ERSCMemberKindTypeId,\n type ERSCStatefulMember,\n ERSCStateTypeId,\n getERSCIdentity,\n isERSCMember,\n} from './ersc-identity';\nimport type { LayoutComponent } from './layout';\nimport type { LoadingComponent } from './loading';\nimport type { AnyMiddleware } from './middleware';\nimport { type AnyPageDefinition, getPageState, type PageConcern } from './page';\nimport {\n type AbsolutePath,\n analyzeRoutePath,\n joinRoutePaths,\n type JoinPath,\n type RouteParamNames,\n type RouteShape,\n type ValidRoutePath,\n} from './route-path';\n\ndeclare const RoutesContractTypeId: unique symbol;\n\ntype RoutesState<\n HasLayout extends boolean,\n Paths extends AbsolutePath,\n Shapes extends AbsolutePath,\n> = {\n readonly hasLayout: Types.Covariant<HasLayout>;\n readonly paths: Types.Covariant<Paths>;\n readonly shapes: Types.Covariant<Shapes>;\n};\n\ntype MountedPaths<Prefix extends AbsolutePath, Child> =\n RoutesPaths<Child> extends infer Path extends AbsolutePath ? JoinPath<Prefix, Path> : never;\n\ntype NoPathCollision<CurrentShapes extends AbsolutePath, Added extends AbsolutePath> = [\n Extract<RouteShape<Added>, CurrentShapes>,\n] extends [never]\n ? unknown\n : never;\n\ntype PageParamNames<Page> =\n Page extends PageConcern<infer ParamNames, infer _Mode> ? ParamNames : never;\n\ntype PageMode<Page> = Page extends PageConcern<infer _ParamNames, infer Mode> ? Mode : never;\n\ntype ExactPageParamNames<Path extends AbsolutePath, Page> = [RouteParamNames<Path>] extends [\n PageParamNames<Page>,\n]\n ? [PageParamNames<Page>] extends [RouteParamNames<Path>]\n ? unknown\n : never\n : never;\n\ntype MatchingPageParams<Path extends AbsolutePath, Page> =\n PageMode<Page> extends 'Static'\n ? [RouteParamNames<Path>] extends [never]\n ? unknown\n : never\n : PageMode<Page> extends 'Parameterized'\n ? [RouteParamNames<Path>] extends [never]\n ? never\n : ExactPageParamNames<Path, Page>\n : never;\n\ntype StaticMountPath<Path extends AbsolutePath> = [RouteParamNames<Path>] extends [never]\n ? unknown\n : never;\n\ntype KnownNonEmptyRoutes<Definition> =\n AbsolutePath extends RoutesPaths<Definition>\n ? never\n : [RoutesPaths<Definition>] extends [never]\n ? never\n : unknown;\n\nexport interface RoutesDefinition<\n Services,\n out HasLayout extends boolean,\n out Paths extends AbsolutePath,\n // Retain each matcher shape so additions do not recompute every earlier path's shape.\n out Shapes extends AbsolutePath = RouteShape<Paths>,\n> extends ERSCStatefulMember<Services, 'Routes', RoutesImplementationState<Services>> {\n readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths, Shapes>;\n\n page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(\n path: Path & ValidRoutePath<Path> & NoPathCollision<Shapes, Path>,\n page: Page & MatchingPageParams<Path, Page>,\n ): RoutesDefinition<Services, HasLayout, Paths | Path, Shapes | RouteShape<Path>>;\n\n mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(\n path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>,\n routes: Child &\n KnownNonEmptyRoutes<Child> &\n NoPathCollision<Shapes, MountedPaths<Prefix, Child>>,\n ): RoutesDefinition<\n Services,\n HasLayout,\n Paths | MountedPaths<Prefix, Child>,\n Shapes | RouteShape<MountedPaths<Prefix, Child>>\n >;\n}\n\nexport type AnyRoutes<Services> = RoutesDefinition<Services, boolean, AbsolutePath>;\n\nexport type RoutesHasLayout<Definition> =\n Definition extends RoutesDefinition<infer _Services, infer HasLayout, infer _Paths, infer _Shapes>\n ? HasLayout\n : never;\n\nexport type RoutesPaths<Definition> =\n Definition extends RoutesDefinition<infer _Services, infer _HasLayout, infer Paths, infer _Shapes>\n ? Paths\n : never;\n\ntype RoutesPage<Services> = {\n readonly page: AnyPageDefinition<Services>;\n readonly path: AbsolutePath;\n};\n\ntype RoutesMount<Services> = {\n readonly path: AbsolutePath;\n readonly routes: AnyRoutes<Services>;\n};\n\nexport type RoutesImplementationState<Services> = {\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly mounts: ReadonlyArray<RoutesMount<Services>>;\n readonly pages: ReadonlyArray<RoutesPage<Services>>;\n readonly paths: ReadonlyArray<AbsolutePath>;\n readonly scopeId: number;\n};\n\ntype RoutesOptions<Services> = {\n readonly layout?: LayoutComponent<Services>;\n readonly loading?: LoadingComponent<Services>;\n};\n\ntype HasLayoutFromOptions<Options> = Options extends { readonly layout: unknown } ? true : false;\n\ntype RuntimeRoutesOptions<Services> = RoutesImplementationState<Services> & {\n readonly routeShapes: ReadonlySet<string>;\n};\n\nclass RoutesDefinitionImpl<\n Services,\n HasLayout extends boolean,\n Paths extends AbsolutePath,\n Shapes extends AbsolutePath = RouteShape<Paths>,\n> implements RoutesDefinition<Services, HasLayout, Paths, Shapes> {\n declare readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths, Shapes>;\n readonly [ERSCIdentityTypeId]: ERSCIdentity<Services>;\n readonly [ERSCMemberKindTypeId] = 'Routes' as const;\n get [ERSCStateTypeId](): RoutesImplementationState<Services> {\n return this;\n }\n\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly mounts: ReadonlyArray<RoutesMount<Services>>;\n readonly pages: ReadonlyArray<RoutesPage<Services>>;\n readonly paths: ReadonlyArray<AbsolutePath>;\n readonly scopeId: number;\n readonly #routeShapes: ReadonlySet<string>;\n\n constructor(\n identity: ERSCIdentity<Services>,\n {\n layout,\n loading,\n middleware,\n mounts,\n pages,\n paths,\n routeShapes,\n scopeId,\n }: RuntimeRoutesOptions<Services>,\n ) {\n this[ERSCIdentityTypeId] = identity;\n this.layout = layout;\n this.loading = loading;\n this.middleware = middleware;\n this.mounts = mounts;\n this.pages = pages;\n this.paths = paths;\n this.scopeId = scopeId;\n this.#routeShapes = routeShapes;\n Object.freeze(this);\n }\n\n page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(\n path: Path & ValidRoutePath<Path> & NoPathCollision<Shapes, Path>,\n page: Page & MatchingPageParams<Path, Page>,\n ): RoutesDefinitionImpl<Services, HasLayout, Paths | Path, Shapes | RouteShape<Path>> {\n const route = analyzeRoutePath(path);\n if (this.#routeShapes.has(route.shape)) {\n throw new TypeError(`Route \"${path}\" conflicts with an existing route pattern.`);\n }\n const pageState = getPageState(page);\n if (getERSCIdentity(page) !== this[ERSCIdentityTypeId]) {\n throw new TypeError(`Page for \"${path}\" was created by a different ERSC module.`);\n }\n\n if (route._tag === 'ParameterFree' && pageState.paramsSchema !== null) {\n throw new TypeError(`Parameterized Page for \"${path}\" requires route parameters.`);\n }\n if (route._tag === 'Parameterized' && pageState.paramsSchema === null) {\n throw new TypeError(`Page for \"${path}\" must declare a parameter Schema.`);\n }\n\n const routeShapes = new Set(this.#routeShapes);\n routeShapes.add(route.shape);\n\n return new RoutesDefinitionImpl(this[ERSCIdentityTypeId], {\n layout: this.layout,\n loading: this.loading,\n middleware: this.middleware,\n mounts: this.mounts,\n pages: Object.freeze([...this.pages, Object.freeze({ page, path })]),\n paths: Object.freeze([...this.paths, path]),\n routeShapes,\n scopeId: this.scopeId,\n });\n }\n\n mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(\n path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>,\n routes: Child &\n KnownNonEmptyRoutes<Child> &\n NoPathCollision<Shapes, MountedPaths<Prefix, Child>>,\n ): RoutesDefinitionImpl<\n Services,\n HasLayout,\n Paths | MountedPaths<Prefix, Child>,\n Shapes | RouteShape<MountedPaths<Prefix, Child>>\n > {\n const route = analyzeRoutePath(path);\n if (route._tag === 'Parameterized') {\n throw new TypeError(`Routes cannot be mounted beneath parameterized path \"${path}\".`);\n }\n const routesState = getRoutesState(routes);\n if (routesState.paths.length === 0) {\n throw new TypeError(`Cannot mount empty Routes at \"${path}\".`);\n }\n if (getERSCIdentity(routes) !== this[ERSCIdentityTypeId]) {\n throw new TypeError(`Routes mounted at \"${path}\" were created by a different ERSC module.`);\n }\n\n const mountedPaths = routesState.paths.map((childPath) => joinRoutePaths(path, childPath));\n const routeShapes = new Set(this.#routeShapes);\n for (const mountedPath of mountedPaths) {\n const shape = analyzeRoutePath(mountedPath).shape;\n if (routeShapes.has(shape)) {\n throw new TypeError(`Route \"${mountedPath}\" conflicts with an existing route pattern.`);\n }\n routeShapes.add(shape);\n }\n\n return new RoutesDefinitionImpl(this[ERSCIdentityTypeId], {\n layout: this.layout,\n loading: this.loading,\n middleware: this.middleware,\n mounts: Object.freeze([...this.mounts, Object.freeze({ path, routes })]),\n pages: this.pages,\n paths: Object.freeze([...this.paths, ...mountedPaths]),\n routeShapes,\n scopeId: this.scopeId,\n });\n }\n}\n\nexport const getRoutesState = <Services>(\n routes: AnyRoutes<Services>,\n): RoutesImplementationState<Services> => {\n if (!isERSCMember(routes, 'Routes')) {\n throw new TypeError('Routes must be created with ERSC.Routes.make.');\n }\n return routes[ERSCStateTypeId];\n};\n\nexport type RoutesFactory<Services> = {\n readonly make: {\n (): RoutesDefinition<Services, false, never>;\n <Options extends RoutesOptions<Services>>(\n options: Options,\n ): RoutesDefinition<Services, HasLayoutFromOptions<Options>, never>;\n };\n};\n\nexport const makeRoutesFactory = <Services>(\n identity: ERSCIdentity<Services>,\n middleware: ReadonlyArray<AnyMiddleware<Services>>,\n allocateScopeId: () => number,\n): RoutesFactory<Services> => {\n function make(): RoutesDefinition<Services, false, never>;\n function make<Options extends RoutesOptions<Services>>(\n options: Options,\n ): RoutesDefinition<Services, HasLayoutFromOptions<Options>, never>;\n function make(options: RoutesOptions<Services> = {}): AnyRoutes<Services> {\n if (options.layout !== undefined) {\n if (!isERSCMember(options.layout, 'Layout')) {\n throw new TypeError('Layout must be created with ERSC.Layout.make.');\n }\n if (getERSCIdentity(options.layout) !== identity) {\n throw new TypeError('Layout was created by a different ERSC module.');\n }\n }\n if (options.loading !== undefined) {\n if (!isERSCMember(options.loading, 'Loading')) {\n throw new TypeError('Loading must be created with ERSC.Loading.make.');\n }\n if (getERSCIdentity(options.loading) !== identity) {\n throw new TypeError('Loading was created by a different ERSC module.');\n }\n }\n const scopeId = allocateScopeId();\n\n return new RoutesDefinitionImpl(identity, {\n layout: options.layout ?? null,\n loading: options.loading ?? null,\n middleware,\n mounts: Object.freeze([]),\n pages: Object.freeze([]),\n paths: Object.freeze([]),\n routeShapes: new Set(),\n scopeId,\n });\n }\n\n return { make };\n};\n"],"names":["ERSCIdentityTypeId","ERSCMemberKindTypeId","ERSCStateTypeId","getERSCIdentity","isERSCMember","getPageState","analyzeRoutePath","joinRoutePaths","RoutesDefinitionImpl","identity","layout","loading","middleware","mounts","pages","paths","routeShapes","scopeId","Object","path","page","route","TypeError","pageState","Set","routes","routesState","getRoutesState","mountedPaths","childPath","mountedPath","shape","makeRoutesFactory","allocateScopeId","make","options","undefined"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Effect, Path, Schema } from 'effect';
1
+ import { Effect, Option, Path, Schema } from 'effect';
2
2
  import { Rspack } from './rspack.js';
3
3
  export type BuildOptions = {
4
4
  readonly root: string;
@@ -22,5 +22,7 @@ export declare const resolveApplicationBuild: (args_0: ResolveApplicationBuildOp
22
22
  };
23
23
  }, BuildEntryError, Path.Path>;
24
24
  export declare const build: (options: BuildOptions) => Effect.Effect<void, BuildEntryError | import("./rspack.js").RspackError, Path.Path | Rspack | import("effect/Scope").Scope>;
25
- export declare const buildApplication: (options: BuildOptions) => Effect.Effect<void, BuildEntryError | import("./rspack.js").RspackError, Path.Path>;
25
+ export declare const buildApplication: (options: BuildOptions & {
26
+ readonly adapter: Option.Option<string>;
27
+ }) => Effect.Effect<void, BuildEntryError | import("./deployment.js").DeploymentBuildError | import("./rspack.js").RspackError, Path.Path>;
26
28
  export {};
@@ -1,7 +1,13 @@
1
- import { Effect, Path, Schema } from "effect";
2
- import { ApplicationEntryPath } from "./contract.js";
1
+ import { Effect, Option, Path, Schema } from "effect";
2
+ import { ApplicationEntryPath, EnvironmentConfig, PublicAssetsDir } from "./contract.js";
3
+ import { runDeploymentBuild } from "./deployment.js";
3
4
  import { Rspack } from "./rspack.js";
4
5
  import { makeRspackBuildConfig } from "./rspack-config.js";
6
+ import { Terminal } from "./terminal.js";
7
+
8
+
9
+
10
+
5
11
 
6
12
 
7
13
 
@@ -52,6 +58,17 @@ const build = Effect.fn('ersc/rspack/build')(function*(options) {
52
58
  });
53
59
  const buildApplication = Effect.fn('ersc/build/buildApplication')(function*(options) {
54
60
  yield* build(options).pipe(Effect.provide(Rspack.layer), Effect.scoped);
61
+ if (Option.isSome(options.adapter)) {
62
+ const path = yield* Path.Path;
63
+ const root = path.resolve(options.root);
64
+ yield* runDeploymentBuild(options.adapter.value, {
65
+ root,
66
+ serverDir: path.join(root, EnvironmentConfig.production.serverOutputDir),
67
+ clientDir: path.join(root, EnvironmentConfig.production.clientOutputDir),
68
+ publicDir: path.join(root, PublicAssetsDir)
69
+ });
70
+ }
71
+ yield* Effect.logInfo(`${Terminal.green('✓')} Build finished successfully.`);
55
72
  });
56
73
 
57
74
  export { BuildEntryError, build, buildApplication, resolveApplicationBuild };
@@ -1 +1 @@
1
- {"version":3,"file":"build/build.js","sources":["../../src/build/build.ts"],"sourcesContent":["import { Effect, Path, Schema } from 'effect';\n\nimport { ApplicationEntryPath } from './contract';\nimport { Rspack } from './rspack';\nimport { makeRspackBuildConfig } from './rspack-config';\n\nexport type BuildOptions = {\n readonly root: string;\n};\n\nexport type ResolveApplicationBuildOptions = BuildOptions & {\n readonly buildModuleUrl?: URL;\n};\n\nexport class BuildEntryError extends Schema.TaggedError<BuildEntryError>()('BuildEntryError', {\n message: Schema.String,\n cause: Schema.Defect(),\n}) {}\n\nconst ClientEntryPath = '../client/entry.js';\nconst RscEntryPath = './rsc-entry.js';\nconst SsrEntryPath = '../server/html-renderer.js';\n\nconst resolveFrameworkEntry = Effect.fnUntraced(function* (\n buildModuleUrl: URL,\n relativePath: string,\n) {\n const path = yield* Path.Path;\n\n const buildModulePath = yield* path.fromFileUrl(buildModuleUrl).pipe(\n Effect.mapError(\n (cause) =>\n new BuildEntryError({\n message: `Failed to convert the framework build module ${buildModuleUrl.href} to a file path.`,\n cause,\n }),\n ),\n );\n\n return path.resolve(path.dirname(buildModulePath), relativePath);\n});\n\nexport const resolveApplicationBuild = Effect.fnUntraced(function* ({\n root,\n buildModuleUrl = new URL(import.meta.url),\n}: ResolveApplicationBuildOptions) {\n const path = yield* Path.Path;\n const applicationRoot = path.resolve(root);\n const applicationPath = path.resolve(applicationRoot, ApplicationEntryPath);\n const clientEntry = yield* resolveFrameworkEntry(buildModuleUrl, ClientEntryPath);\n const rscEntry = yield* resolveFrameworkEntry(buildModuleUrl, RscEntryPath);\n const ssrEntry = yield* resolveFrameworkEntry(buildModuleUrl, SsrEntryPath);\n const entries = {\n application: applicationPath,\n client: clientEntry,\n rsc: rscEntry,\n ssr: ssrEntry,\n };\n\n return { applicationRoot, entries } as const;\n});\n\nexport const build = Effect.fn('ersc/rspack/build')(function* (options: BuildOptions) {\n const { applicationRoot, entries } = yield* resolveApplicationBuild(options);\n const rspack = yield* Rspack;\n\n yield* rspack.build(makeRspackBuildConfig(applicationRoot, entries));\n});\n\nexport const buildApplication = Effect.fn('ersc/build/buildApplication')(function* (\n options: BuildOptions,\n) {\n yield* build(options).pipe(Effect.provide(Rspack.layer), Effect.scoped);\n});\n"],"names":["Effect","Path","Schema","ApplicationEntryPath","Rspack","makeRspackBuildConfig","BuildEntryError","ClientEntryPath","RscEntryPath","SsrEntryPath","resolveFrameworkEntry","buildModuleUrl","relativePath","path","buildModulePath","cause","resolveApplicationBuild","root","URL","applicationRoot","applicationPath","clientEntry","rscEntry","ssrEntry","entries","build","options","rspack","buildApplication"],"mappings":";;;;;;;;;AAA8C;AAEI;AAChB;AACsB;AAUjD,MAAMM,eAAeA,SAASJ,kBAAkB,GAAoB,mBAAmB;IAC5F,SAASA,aAAa;IACtB,OAAOA,aAAa;AACtB;AAAI;AAEJ,MAAMK,eAAeA,GAAG;AACxB,MAAMC,YAAYA,GAAG;AACrB,MAAMC,YAAYA,GAAG;AAErB,MAAMC,qBAAqBA,GAAGV,iBAAiB,CAAC,UAC9CW,cAAmB,EACnBC,YAAoB;IAEpB,MAAMC,OAAO,OAAOZ,SAAS;IAE7B,MAAMa,kBAAkB,OAAOD,KAAK,WAAW,CAACF,gBAAgB,IAAI,CAClEX,eAAe,CACb,CAACe,QACC,IAAIT,eAAeA,CAAC;YAClB,SAAS,CAAC,6CAA6C,EAAEK,eAAe,IAAI,CAAC,gBAAgB,CAAC;YAC9FI;QACF;IAIN,OAAOF,KAAK,OAAO,CAACA,KAAK,OAAO,CAACC,kBAAkBF;AACrD;AAEO,MAAMI,uBAAuBA,GAAGhB,iBAAiB,CAAC,UAAW,EAClEiB,IAAI,EACJN,iBAAiB,IAAIO,IAAI,YAAY,GAAG,CAAC,EACV;IAC/B,MAAML,OAAO,OAAOZ,SAAS;IAC7B,MAAMkB,kBAAkBN,KAAK,OAAO,CAACI;IACrC,MAAMG,kBAAkBP,KAAK,OAAO,CAACM,iBAAiBhB,oBAAoBA;IAC1E,MAAMkB,cAAc,OAAOX,qBAAqBA,CAACC,gBAAgBJ,eAAeA;IAChF,MAAMe,WAAW,OAAOZ,qBAAqBA,CAACC,gBAAgBH,YAAYA;IAC1E,MAAMe,WAAW,OAAOb,qBAAqBA,CAACC,gBAAgBF,YAAYA;IAC1E,MAAMe,UAAU;QACd,aAAaJ;QACb,QAAQC;QACR,KAAKC;QACL,KAAKC;IACP;IAEA,OAAO;QAAEJ;QAAiBK;IAAQ;AACpC,GAAG;AAEI,MAAMC,KAAKA,GAAGzB,SAAS,CAAC,qBAAqB,UAAW0B,OAAqB;IAClF,MAAM,EAAEP,eAAe,EAAEK,OAAO,EAAE,GAAG,OAAOR,uBAAuBA,CAACU;IACpE,MAAMC,SAAS,OAAOvB,MAAMA;IAE5B,OAAOuB,OAAO,KAAK,CAACtB,qBAAqBA,CAACc,iBAAiBK;AAC7D,GAAG;AAEI,MAAMI,gBAAgBA,GAAG5B,SAAS,CAAC,+BAA+B,UACvE0B,OAAqB;IAErB,OAAOD,KAAKA,CAACC,SAAS,IAAI,CAAC1B,cAAc,CAACI,YAAY,GAAGJ,aAAa;AACxE,GAAG"}
1
+ {"version":3,"file":"build/build.js","sources":["../../src/build/build.ts"],"sourcesContent":["import { Effect, Option, Path, Schema } from 'effect';\n\nimport { ApplicationEntryPath, EnvironmentConfig, PublicAssetsDir } from './contract';\nimport { runDeploymentBuild } from './deployment';\nimport { Rspack } from './rspack';\nimport { makeRspackBuildConfig } from './rspack-config';\nimport { Terminal } from './terminal';\n\nexport type BuildOptions = {\n readonly root: string;\n};\n\nexport type ResolveApplicationBuildOptions = BuildOptions & {\n readonly buildModuleUrl?: URL;\n};\n\nexport class BuildEntryError extends Schema.TaggedError<BuildEntryError>()('BuildEntryError', {\n message: Schema.String,\n cause: Schema.Defect(),\n}) {}\n\nconst ClientEntryPath = '../client/entry.js';\nconst RscEntryPath = './rsc-entry.js';\nconst SsrEntryPath = '../server/html-renderer.js';\n\nconst resolveFrameworkEntry = Effect.fnUntraced(function* (\n buildModuleUrl: URL,\n relativePath: string,\n) {\n const path = yield* Path.Path;\n\n const buildModulePath = yield* path.fromFileUrl(buildModuleUrl).pipe(\n Effect.mapError(\n (cause) =>\n new BuildEntryError({\n message: `Failed to convert the framework build module ${buildModuleUrl.href} to a file path.`,\n cause,\n }),\n ),\n );\n\n return path.resolve(path.dirname(buildModulePath), relativePath);\n});\n\nexport const resolveApplicationBuild = Effect.fnUntraced(function* ({\n root,\n buildModuleUrl = new URL(import.meta.url),\n}: ResolveApplicationBuildOptions) {\n const path = yield* Path.Path;\n const applicationRoot = path.resolve(root);\n const applicationPath = path.resolve(applicationRoot, ApplicationEntryPath);\n const clientEntry = yield* resolveFrameworkEntry(buildModuleUrl, ClientEntryPath);\n const rscEntry = yield* resolveFrameworkEntry(buildModuleUrl, RscEntryPath);\n const ssrEntry = yield* resolveFrameworkEntry(buildModuleUrl, SsrEntryPath);\n const entries = {\n application: applicationPath,\n client: clientEntry,\n rsc: rscEntry,\n ssr: ssrEntry,\n };\n\n return { applicationRoot, entries } as const;\n});\n\nexport const build = Effect.fn('ersc/rspack/build')(function* (options: BuildOptions) {\n const { applicationRoot, entries } = yield* resolveApplicationBuild(options);\n const rspack = yield* Rspack;\n\n yield* rspack.build(makeRspackBuildConfig(applicationRoot, entries));\n});\n\nexport const buildApplication = Effect.fn('ersc/build/buildApplication')(function* (\n options: BuildOptions & { readonly adapter: Option.Option<string> },\n) {\n yield* build(options).pipe(Effect.provide(Rspack.layer), Effect.scoped);\n if (Option.isSome(options.adapter)) {\n const path = yield* Path.Path;\n const root = path.resolve(options.root);\n yield* runDeploymentBuild(options.adapter.value, {\n root,\n serverDir: path.join(root, EnvironmentConfig.production.serverOutputDir),\n clientDir: path.join(root, EnvironmentConfig.production.clientOutputDir),\n publicDir: path.join(root, PublicAssetsDir),\n });\n }\n yield* Effect.logInfo(`${Terminal.green('✓')} Build finished successfully.`);\n});\n"],"names":["Effect","Option","Path","Schema","ApplicationEntryPath","EnvironmentConfig","PublicAssetsDir","runDeploymentBuild","Rspack","makeRspackBuildConfig","Terminal","BuildEntryError","ClientEntryPath","RscEntryPath","SsrEntryPath","resolveFrameworkEntry","buildModuleUrl","relativePath","path","buildModulePath","cause","resolveApplicationBuild","root","URL","applicationRoot","applicationPath","clientEntry","rscEntry","ssrEntry","entries","build","options","rspack","buildApplication"],"mappings":";;;;;;;;;;;;;AAAsD;AAEgC;AACpC;AAChB;AACsB;AAClB;AAU/B,MAAMW,eAAeA,SAASR,kBAAkB,GAAoB,mBAAmB;IAC5F,SAASA,aAAa;IACtB,OAAOA,aAAa;AACtB;AAAI;AAEJ,MAAMS,eAAeA,GAAG;AACxB,MAAMC,YAAYA,GAAG;AACrB,MAAMC,YAAYA,GAAG;AAErB,MAAMC,qBAAqBA,GAAGf,iBAAiB,CAAC,UAC9CgB,cAAmB,EACnBC,YAAoB;IAEpB,MAAMC,OAAO,OAAOhB,SAAS;IAE7B,MAAMiB,kBAAkB,OAAOD,KAAK,WAAW,CAACF,gBAAgB,IAAI,CAClEhB,eAAe,CACb,CAACoB,QACC,IAAIT,eAAeA,CAAC;YAClB,SAAS,CAAC,6CAA6C,EAAEK,eAAe,IAAI,CAAC,gBAAgB,CAAC;YAC9FI;QACF;IAIN,OAAOF,KAAK,OAAO,CAACA,KAAK,OAAO,CAACC,kBAAkBF;AACrD;AAEO,MAAMI,uBAAuBA,GAAGrB,iBAAiB,CAAC,UAAW,EAClEsB,IAAI,EACJN,iBAAiB,IAAIO,IAAI,YAAY,GAAG,CAAC,EACV;IAC/B,MAAML,OAAO,OAAOhB,SAAS;IAC7B,MAAMsB,kBAAkBN,KAAK,OAAO,CAACI;IACrC,MAAMG,kBAAkBP,KAAK,OAAO,CAACM,iBAAiBpB,oBAAoBA;IAC1E,MAAMsB,cAAc,OAAOX,qBAAqBA,CAACC,gBAAgBJ,eAAeA;IAChF,MAAMe,WAAW,OAAOZ,qBAAqBA,CAACC,gBAAgBH,YAAYA;IAC1E,MAAMe,WAAW,OAAOb,qBAAqBA,CAACC,gBAAgBF,YAAYA;IAC1E,MAAMe,UAAU;QACd,aAAaJ;QACb,QAAQC;QACR,KAAKC;QACL,KAAKC;IACP;IAEA,OAAO;QAAEJ;QAAiBK;IAAQ;AACpC,GAAG;AAEI,MAAMC,KAAKA,GAAG9B,SAAS,CAAC,qBAAqB,UAAW+B,OAAqB;IAClF,MAAM,EAAEP,eAAe,EAAEK,OAAO,EAAE,GAAG,OAAOR,uBAAuBA,CAACU;IACpE,MAAMC,SAAS,OAAOxB,MAAMA;IAE5B,OAAOwB,OAAO,KAAK,CAACvB,qBAAqBA,CAACe,iBAAiBK;AAC7D,GAAG;AAEI,MAAMI,gBAAgBA,GAAGjC,SAAS,CAAC,+BAA+B,UACvE+B,OAAmE;IAEnE,OAAOD,KAAKA,CAACC,SAAS,IAAI,CAAC/B,cAAc,CAACQ,YAAY,GAAGR,aAAa;IACtE,IAAIC,aAAa,CAAC8B,QAAQ,OAAO,GAAG;QAClC,MAAMb,OAAO,OAAOhB,SAAS;QAC7B,MAAMoB,OAAOJ,KAAK,OAAO,CAACa,QAAQ,IAAI;QACtC,OAAOxB,kBAAkBA,CAACwB,QAAQ,OAAO,CAAC,KAAK,EAAE;YAC/CT;YACA,WAAWJ,KAAK,IAAI,CAACI,MAAMjB,4CAA4C;YACvE,WAAWa,KAAK,IAAI,CAACI,MAAMjB,4CAA4C;YACvE,WAAWa,KAAK,IAAI,CAACI,MAAMhB,eAAeA;QAC5C;IACF;IACA,OAAON,cAAc,CAAC,GAAGU,cAAc,CAAC,KAAK,6BAA6B,CAAC;AAC7E,GAAG"}
@@ -0,0 +1,10 @@
1
+ import { Effect, Path, Schema } from 'effect';
2
+ import type { BuildContext } from './hook.js';
3
+ declare const DeploymentBuildError_base: Schema.Class<DeploymentBuildError, Schema.TaggedStruct<"DeploymentBuildError", {
4
+ readonly message: Schema.String;
5
+ readonly cause: Schema.Defect;
6
+ }>, import("effect/Cause").YieldableError>;
7
+ export declare class DeploymentBuildError extends DeploymentBuildError_base {
8
+ }
9
+ export declare const runDeploymentBuild: (name: string, context: BuildContext) => Effect.Effect<void, DeploymentBuildError, Path.Path>;
10
+ export {};
@@ -0,0 +1,59 @@
1
+ import { Duration, Effect, Path, Predicate, Schema } from "effect";
2
+ import { Terminal, formatDuration } from "./terminal.js";
3
+
4
+
5
+
6
+
7
+
8
+ class DeploymentBuildError extends Schema.TaggedError()('DeploymentBuildError', {
9
+ message: Schema.String,
10
+ cause: Schema.Defect()
11
+ }) {
12
+ }
13
+ const decodeHookModule = Schema.decodeUnknownEffect(Schema.Struct({
14
+ build: Schema.declare((input)=>Predicate.isFunction(input))
15
+ }));
16
+ const runDeploymentBuild = Effect.fn('ersc/build/runDeploymentBuild')(function*(name, context) {
17
+ const path = yield* Path.Path;
18
+ yield* Effect.logInfo(`${Terminal.cyan('●')} Building deployment with ${name}...`);
19
+ const [duration] = yield* Effect.gen(function*() {
20
+ const entry = yield* Effect["try"]({
21
+ try: ()=>Bun.resolveSync(`${name}/build`, context.root),
22
+ catch: (cause)=>new DeploymentBuildError({
23
+ message: `Cannot resolve ${name}'s build hook.`,
24
+ cause
25
+ })
26
+ });
27
+ const url = yield* path.toFileUrl(entry);
28
+ const loaded = yield* Effect.tryPromise({
29
+ try: ()=>import(url.href),
30
+ catch: (cause)=>new DeploymentBuildError({
31
+ message: `Cannot load ${name}'s build hook.`,
32
+ cause
33
+ })
34
+ });
35
+ const module = yield* decodeHookModule(loaded);
36
+ const buildEffect = yield* Effect["try"]({
37
+ try: ()=>module.build(context),
38
+ catch: (cause)=>new DeploymentBuildError({
39
+ message: `${name}'s build hook threw.`,
40
+ cause
41
+ })
42
+ });
43
+ if (!Effect.isEffect(buildEffect)) {
44
+ return yield* new DeploymentBuildError({
45
+ message: `${name}'s build hook must return an Effect.`,
46
+ cause: buildEffect
47
+ });
48
+ }
49
+ yield* buildEffect;
50
+ }).pipe(Effect.mapError((cause)=>new DeploymentBuildError({
51
+ message: `Deployment build ${name} failed.`,
52
+ cause
53
+ })), Effect.scoped, Effect.timed);
54
+ yield* Effect.logInfo(`${Terminal.green('✓')} Deployment built with ${name} in ${formatDuration(Math.round(Duration.toMillis(duration)))}.`);
55
+ });
56
+
57
+ export { DeploymentBuildError, runDeploymentBuild };
58
+
59
+ //# sourceMappingURL=deployment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build/deployment.js","sources":["../../src/build/deployment.ts"],"sourcesContent":["import { Duration, Effect, Path, Predicate, Schema } from 'effect';\n\nimport type { BuildContext, BuildHook } from './hook';\nimport { formatDuration, Terminal } from './terminal';\n\nexport class DeploymentBuildError extends Schema.TaggedError<DeploymentBuildError>()(\n 'DeploymentBuildError',\n {\n message: Schema.String,\n cause: Schema.Defect(),\n },\n) {}\n\nconst decodeHookModule = Schema.decodeUnknownEffect(\n Schema.Struct({\n build: Schema.declare((input): input is BuildHook => Predicate.isFunction(input)),\n }),\n);\n\nexport const runDeploymentBuild = Effect.fn('ersc/build/runDeploymentBuild')(function* (\n name: string,\n context: BuildContext,\n) {\n const path = yield* Path.Path;\n\n yield* Effect.logInfo(`${Terminal.cyan('●')} Building deployment with ${name}...`);\n const [duration] = yield* Effect.gen(function* () {\n const entry = yield* Effect.try({\n try: () => Bun.resolveSync(`${name}/build`, context.root),\n catch: (cause) =>\n new DeploymentBuildError({ message: `Cannot resolve ${name}'s build hook.`, cause }),\n });\n const url = yield* path.toFileUrl(entry);\n const loaded = yield* Effect.tryPromise({\n try: (): Promise<unknown> => import(url.href),\n catch: (cause) =>\n new DeploymentBuildError({ message: `Cannot load ${name}'s build hook.`, cause }),\n });\n const module = yield* decodeHookModule(loaded);\n const buildEffect = yield* Effect.try({\n try: () => module.build(context),\n catch: (cause) => new DeploymentBuildError({ message: `${name}'s build hook threw.`, cause }),\n });\n if (!Effect.isEffect(buildEffect)) {\n return yield* new DeploymentBuildError({\n message: `${name}'s build hook must return an Effect.`,\n cause: buildEffect,\n });\n }\n yield* buildEffect;\n }).pipe(\n Effect.mapError(\n (cause) => new DeploymentBuildError({ message: `Deployment build ${name} failed.`, cause }),\n ),\n Effect.scoped,\n Effect.timed,\n );\n yield* Effect.logInfo(\n `${Terminal.green('✓')} Deployment built with ${name} in ${formatDuration(Math.round(Duration.toMillis(duration)))}.`,\n );\n});\n"],"names":["Duration","Effect","Path","Predicate","Schema","formatDuration","Terminal","DeploymentBuildError","decodeHookModule","input","runDeploymentBuild","name","context","path","duration","entry","Bun","cause","url","loaded","module","buildEffect","Math"],"mappings":";;;;;AAAmE;AAGb;AAE/C,MAAMO,oBAAoBA,SAASH,kBAAkB,GAC1D,wBACA;IACE,SAASA,aAAa;IACtB,OAAOA,aAAa;AACtB;AACC;AAEH,MAAMI,gBAAgBA,GAAGJ,0BAA0B,CACjDA,aAAa,CAAC;IACZ,OAAOA,cAAc,CAAC,CAACK,QAA8BN,oBAAoB,CAACM;AAC5E;AAGK,MAAMC,kBAAkBA,GAAGT,SAAS,CAAC,iCAAiC,UAC3EU,IAAY,EACZC,OAAqB;IAErB,MAAMC,OAAO,OAAOX,SAAS;IAE7B,OAAOD,cAAc,CAAC,GAAGK,aAAa,CAAC,KAAK,0BAA0B,EAAEK,KAAK,GAAG,CAAC;IACjF,MAAM,CAACG,SAAS,GAAG,OAAOb,UAAU,CAAC;QACnC,MAAMc,QAAQ,OAAOd,aAAU,CAAC;YAC9B,KAAK,IAAMe,IAAI,WAAW,CAAC,GAAGL,KAAK,MAAM,CAAC,EAAEC,QAAQ,IAAI;YACxD,OAAO,CAACK,QACN,IAAIV,oBAAoBA,CAAC;oBAAE,SAAS,CAAC,eAAe,EAAEI,KAAK,cAAc,CAAC;oBAAEM;gBAAM;QACtF;QACA,MAAMC,MAAM,OAAOL,KAAK,SAAS,CAACE;QAClC,MAAMI,SAAS,OAAOlB,iBAAiB,CAAC;YACtC,KAAK,IAAwB,MAAM,CAACiB,IAAI,IAAI;YAC5C,OAAO,CAACD,QACN,IAAIV,oBAAoBA,CAAC;oBAAE,SAAS,CAAC,YAAY,EAAEI,KAAK,cAAc,CAAC;oBAAEM;gBAAM;QACnF;QACA,MAAMG,SAAS,OAAOZ,gBAAgBA,CAACW;QACvC,MAAME,cAAc,OAAOpB,aAAU,CAAC;YACpC,KAAK,IAAMmB,OAAO,KAAK,CAACR;YACxB,OAAO,CAACK,QAAU,IAAIV,oBAAoBA,CAAC;oBAAE,SAAS,GAAGI,KAAK,oBAAoB,CAAC;oBAAEM;gBAAM;QAC7F;QACA,IAAI,CAAChB,eAAe,CAACoB,cAAc;YACjC,OAAO,OAAO,IAAId,oBAAoBA,CAAC;gBACrC,SAAS,GAAGI,KAAK,oCAAoC,CAAC;gBACtD,OAAOU;YACT;QACF;QACA,OAAOA;IACT,GAAG,IAAI,CACLpB,eAAe,CACb,CAACgB,QAAU,IAAIV,oBAAoBA,CAAC;YAAE,SAAS,CAAC,iBAAiB,EAAEI,KAAK,QAAQ,CAAC;YAAEM;QAAM,KAE3FhB,aAAa,EACbA,YAAY;IAEd,OAAOA,cAAc,CACnB,GAAGK,cAAc,CAAC,KAAK,uBAAuB,EAAEK,KAAK,IAAI,EAAEN,cAAcA,CAACiB,KAAK,KAAK,CAACtB,iBAAiB,CAACc,YAAY,CAAC,CAAC;AAEzH,GAAG"}
@@ -30,12 +30,12 @@ export declare const makeDevGenerationStore: (options: DevGenerationOptions) =>
30
30
  export declare const makeDevApplication: (args_0: DevGenerationOptions) => Effect.Effect<{
31
31
  closeDevChannel: Effect.Effect<void, never, never>;
32
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
- watch: Effect.Effect<void, import("./compiled-server.js").CompiledServerError | DevGenerationError | RspackError, FileSystem.FileSystem | Path.Path>;
33
+ watch: Effect.Effect<void, DevGenerationFailure, FileSystem.FileSystem | Path.Path>;
34
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
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
- watch: Effect.Effect<void, import("./compiled-server.js").CompiledServerError | DevGenerationError | RspackError, FileSystem.FileSystem | Path.Path>;
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 | Scope.Scope>;
38
+ watch: Effect.Effect<void, DevGenerationFailure, FileSystem.FileSystem | Path.Path>;
39
+ }) => Effect.Effect<void, DevGenerationFailure, FileSystem.FileSystem | HttpServer.HttpServer | Path.Path>;
40
+ export declare const devApplication: (options: DevGenerationOptions) => Effect.Effect<void, import("./build.js").BuildEntryError | import("effect/PlatformError").PlatformError | DevGenerationFailure, FileSystem.FileSystem | HttpServer.HttpServer | Path.Path | Scope.Scope>;
41
41
  export {};
package/dist/build/dev.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Cause, Deferred, Effect, Fiber, FileSystem, Layer, Path, Ref, Schema, Scope, ScopedRef, Stream } from "effect";
1
+ import { Cause, Deferred, Effect, Fiber, FiberHandle, FileSystem, Layer, Path, Ref, Schema, Scope, ScopedRef, Stream } from "effect";
2
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";
@@ -79,6 +79,7 @@ const makeDevGenerationStore = Effect.fnUntraced(function*(options) {
79
79
  }));
80
80
  const initialCompilation = yield* Deferred.make();
81
81
  const compilation = yield* Ref.make(initialCompilation);
82
+ // Only acquisition can be cancelled; installation must also release waiting requests.
82
83
  const update = Effect.fnUntraced(function*(event) {
83
84
  const current = yield* Ref.get(compilation);
84
85
  switch(event._tag){
@@ -112,7 +113,7 @@ const makeDevGenerationStore = Effect.fnUntraced(function*(options) {
112
113
  yield* Deferred.succeed(current, ready.generation);
113
114
  }
114
115
  }
115
- });
116
+ }, Effect.uninterruptible);
116
117
  const httpEffect = Ref.get(compilation).pipe(Effect.flatMap(Deferred["await"]), Effect.flatMap((ready)=>ready.httpEffect));
117
118
  return {
118
119
  httpEffect,
@@ -167,11 +168,25 @@ const makeDevApplication = Effect.fnUntraced(function*({ hostname, port, root })
167
168
  }), Effect["catch"]((error)=>channel.publishBuildFailure(Cause.pretty(Cause.fail(error))).pipe(Effect.andThen(Effect.logError(error)))));
168
169
  }
169
170
  }
170
- });
171
- const watch = rspack.watch(makeRspackDevConfig(applicationRoot, entries, {
172
- onCompilationStart: channel.onCompilationStart,
173
- onServerComponentChanges: channel.onServerComponentChanges
174
- })).pipe(Stream.runForEach(update));
171
+ }, Effect.uninterruptible);
172
+ const watch = Effect.scoped(Effect.gen(function*() {
173
+ const startup = yield* FiberHandle.make();
174
+ const events = rspack.watch(makeRspackDevConfig(applicationRoot, entries, {
175
+ onCompilationStart: channel.onCompilationStart,
176
+ onServerComponentChanges: channel.onServerComponentChanges
177
+ })).pipe(Stream.runForEach(Effect.fnUntraced(function*(event) {
178
+ // Finish obsolete startup cleanup before handling the next build event.
179
+ yield* FiberHandle.clear(startup);
180
+ if (event._tag === 'Compiled') {
181
+ yield* FiberHandle.run(startup, update(event), {
182
+ startImmediately: true
183
+ });
184
+ } else {
185
+ yield* update(event);
186
+ }
187
+ })), Effect.andThen(FiberHandle.awaitEmpty(startup)));
188
+ yield* Effect.raceFirst(events, FiberHandle.join(startup));
189
+ }));
175
190
  const httpEffect = yield* HttpRouter.toHttpEffect(HttpRouter.addAll([
176
191
  HttpRouter.route('GET', DevChannelPath, channel.httpEffect),
177
192
  HttpRouter.route('*', '/*', generationStore.httpEffect)
@@ -1 +1 @@
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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"}
1
+ {"version":3,"file":"build/dev.js","sources":["../../src/build/dev.ts"],"sourcesContent":["import {\n Cause,\n Deferred,\n Effect,\n Fiber,\n FiberHandle,\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 // Only acquisition can be cancelled; installation must also release waiting requests.\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 }, Effect.uninterruptible);\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 }, Effect.uninterruptible);\n const watch = Effect.scoped(\n Effect.gen(function* () {\n const startup = yield* FiberHandle.make<void, DevGenerationFailure>();\n const events = rspack\n .watch(\n makeRspackDevConfig(applicationRoot, entries, {\n onCompilationStart: channel.onCompilationStart,\n onServerComponentChanges: channel.onServerComponentChanges,\n }),\n )\n .pipe(\n Stream.runForEach(\n Effect.fnUntraced(function* (event) {\n // Finish obsolete startup cleanup before handling the next build event.\n yield* FiberHandle.clear(startup);\n if (event._tag === 'Compiled') {\n yield* FiberHandle.run(startup, update(event), { startImmediately: true });\n } else {\n yield* update(event);\n }\n }),\n ),\n Effect.andThen(FiberHandle.awaitEmpty(startup)),\n );\n\n yield* Effect.raceFirst(events, FiberHandle.join(startup));\n }),\n );\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","FiberHandle","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","startup","events","launchDevApplication","application","server","address","devApplication"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Effect, Scope } from 'effect';
2
+ export type BuildContext = {
3
+ readonly root: string;
4
+ readonly serverDir: string;
5
+ readonly clientDir: string;
6
+ readonly publicDir: string;
7
+ };
8
+ export type BuildHook = (context: BuildContext) => Effect.Effect<void, Error, Scope.Scope>;
@@ -0,0 +1,5 @@
1
+
2
+
3
+ export {};
4
+
5
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build/hook.js","sources":["../../src/build/hook.ts"],"sourcesContent":["import type { Effect, Scope } from 'effect';\n\nexport type BuildContext = {\n readonly root: string;\n readonly serverDir: string;\n readonly clientDir: string;\n readonly publicDir: string;\n};\n\nexport type BuildHook = (context: BuildContext) => Effect.Effect<void, Error, Scope.Scope>;\n"],"names":[],"mappings":"AAS2F"}