effective-rsc 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LLMS.md +85 -0
- package/README.md +14 -8
- package/dist/application/routes.d.ts +10 -10
- package/dist/application/routes.js.map +1 -1
- package/dist/build/build.d.ts +4 -2
- package/dist/build/build.js +19 -2
- package/dist/build/build.js.map +1 -1
- package/dist/build/deployment.d.ts +10 -0
- package/dist/build/deployment.js +59 -0
- package/dist/build/deployment.js.map +1 -0
- package/dist/build/dev.d.ts +4 -4
- package/dist/build/dev.js +22 -7
- package/dist/build/dev.js.map +1 -1
- package/dist/build/hook.d.ts +8 -0
- package/dist/build/hook.js +5 -0
- package/dist/build/hook.js.map +1 -0
- package/dist/build/rspack.js +1 -1
- package/dist/build/rspack.js.map +1 -1
- package/dist/cli.js +13 -24
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-renderer.d.ts +25 -25
- package/dist/client/browser-renderer.js +80 -94
- package/dist/client/browser-renderer.js.map +1 -1
- package/dist/client/call-server.js +7 -5
- package/dist/client/call-server.js.map +1 -1
- package/dist/client/client-router.js +23 -7
- package/dist/client/client-router.js.map +1 -1
- package/dist/client/flight-client.js +3 -4
- package/dist/client/flight-client.js.map +1 -1
- package/dist/client/react-dom-renderer.js +2 -1
- package/dist/client/react-dom-renderer.js.map +1 -1
- package/dist/client/route-refresh.d.ts +2 -2
- package/dist/client/route-refresh.js +54 -39
- package/dist/client/route-refresh.js.map +1 -1
- package/dist/dev/panel.js +14 -14
- package/dist/dev/panel.js.map +1 -1
- package/dist/server/application.d.ts +2 -1
- package/dist/server/application.js +8 -6
- package/dist/server/application.js.map +1 -1
- package/dist/server/html-renderer.js +12 -11
- package/dist/server/html-renderer.js.map +1 -1
- package/dist/server/serve.d.ts +7 -0
- package/dist/server/serve.js +31 -0
- package/dist/server/serve.js.map +1 -0
- package/dist/server/start.d.ts +3 -0
- package/dist/server/start.js +24 -0
- package/dist/server/start.js.map +1 -0
- package/docs/02-guides/06-deploying-to-vercel/index.md +34 -0
- package/docs/02-guides/index.md +1 -0
- package/docs/03-advanced/02-client-navigation/index.md +17 -0
- package/docs/03-advanced/04-production-startup/01_server.ts +11 -0
- package/docs/03-advanced/04-production-startup/index.md +22 -0
- package/docs/03-advanced/index.md +1 -0
- package/package.json +27 -20
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.
|
|
69
|
-
@effect/platform-browser@4.0.0-rc.
|
|
70
|
-
@effect/platform-bun@4.0.0-rc.
|
|
71
|
-
react@19.3.0-canary-
|
|
72
|
-
react-dom@19.3.0-canary-
|
|
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
|
-
##
|
|
206
|
+
## Examples and documentation
|
|
203
207
|
|
|
204
|
-
|
|
205
|
-
|
|
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
|
|
15
|
-
|
|
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
|
|
27
|
-
readonly [RoutesContractTypeId]: RoutesState<HasLayout, Paths>;
|
|
28
|
-
page<const Path extends AbsolutePath, const Page extends AnyPageDefinition<Services>>(path: Path & ValidRoutePath<Path> & NoPathCollision<
|
|
29
|
-
mount<const Prefix extends AbsolutePath, const Child extends AnyRoutes<Services>>(path: Prefix & ValidRoutePath<Prefix> & StaticMountPath<Prefix>, routes: Child & KnownNonEmptyRoutes<Child> & NoPathCollision<
|
|
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":"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"}
|
|
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":";;;;;;;AAUyB;AAIuD;AAS1D;AAgItB,MAAMQ,oBAAoBA;IAOf,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,IAAiE,EACjEC,IAA2C,EACyC;QACpF,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,MAEsD,EAMtD;QACA,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"}
|
package/dist/build/build.d.ts
CHANGED
|
@@ -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
|
|
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 {};
|
package/dist/build/build.js
CHANGED
|
@@ -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 };
|
package/dist/build/build.js.map
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/build/dev.d.ts
CHANGED
|
@@ -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,
|
|
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,
|
|
39
|
-
}) => Effect.Effect<void,
|
|
40
|
-
export declare const devApplication: (options: DevGenerationOptions) => Effect.Effect<void, import("./build.js").BuildEntryError | import("
|
|
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 =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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)
|
package/dist/build/dev.js.map
CHANGED
|
@@ -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 @@
|
|
|
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"}
|