effective-rsc 0.1.0

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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/LLMS.md +382 -0
  3. package/README.md +235 -0
  4. package/bin/ersc.js +3 -0
  5. package/dist/application/component.d.ts +15 -0
  6. package/dist/application/component.js +20 -0
  7. package/dist/application/component.js.map +1 -0
  8. package/dist/application/definition.d.ts +31 -0
  9. package/dist/application/definition.js +57 -0
  10. package/dist/application/definition.js.map +1 -0
  11. package/dist/application/ersc-identity.d.ts +25 -0
  12. package/dist/application/ersc-identity.js +23 -0
  13. package/dist/application/ersc-identity.js.map +1 -0
  14. package/dist/application/ersc.d.ts +28 -0
  15. package/dist/application/ersc.js +72 -0
  16. package/dist/application/ersc.js.map +1 -0
  17. package/dist/application/layout.d.ts +18 -0
  18. package/dist/application/layout.js +17 -0
  19. package/dist/application/layout.js.map +1 -0
  20. package/dist/application/loading.d.ts +17 -0
  21. package/dist/application/loading.js +14 -0
  22. package/dist/application/loading.js.map +1 -0
  23. package/dist/application/middleware.d.ts +36 -0
  24. package/dist/application/middleware.js +46 -0
  25. package/dist/application/middleware.js.map +1 -0
  26. package/dist/application/page.d.ts +58 -0
  27. package/dist/application/page.js +50 -0
  28. package/dist/application/page.js.map +1 -0
  29. package/dist/application/render-runtime.d.ts +9 -0
  30. package/dist/application/render-runtime.js +28 -0
  31. package/dist/application/render-runtime.js.map +1 -0
  32. package/dist/application/route-graph.d.ts +22 -0
  33. package/dist/application/route-graph.js +68 -0
  34. package/dist/application/route-graph.js.map +1 -0
  35. package/dist/application/route-path.d.ts +31 -0
  36. package/dist/application/route-path.js +67 -0
  37. package/dist/application/route-path.js.map +1 -0
  38. package/dist/application/routes.d.ts +66 -0
  39. package/dist/application/routes.js +159 -0
  40. package/dist/application/routes.js.map +1 -0
  41. package/dist/application/server-fn.d.ts +30 -0
  42. package/dist/application/server-fn.js +58 -0
  43. package/dist/application/server-fn.js.map +1 -0
  44. package/dist/build/build.d.ts +26 -0
  45. package/dist/build/build.js +59 -0
  46. package/dist/build/build.js.map +1 -0
  47. package/dist/build/compiled-server.d.ts +53 -0
  48. package/dist/build/compiled-server.js +77 -0
  49. package/dist/build/compiled-server.js.map +1 -0
  50. package/dist/build/contract.d.ts +23 -0
  51. package/dist/build/contract.js +41 -0
  52. package/dist/build/contract.js.map +1 -0
  53. package/dist/build/dev-channel.d.ts +20 -0
  54. package/dist/build/dev-channel.js +71 -0
  55. package/dist/build/dev-channel.js.map +1 -0
  56. package/dist/build/dev.d.ts +41 -0
  57. package/dist/build/dev.js +186 -0
  58. package/dist/build/dev.js.map +1 -0
  59. package/dist/build/rsc-entry.d.ts +4 -0
  60. package/dist/build/rsc-entry.js +17 -0
  61. package/dist/build/rsc-entry.js.map +1 -0
  62. package/dist/build/rspack-config.d.ts +17 -0
  63. package/dist/build/rspack-config.js +259 -0
  64. package/dist/build/rspack-config.js.map +1 -0
  65. package/dist/build/rspack.d.ts +45 -0
  66. package/dist/build/rspack.js +231 -0
  67. package/dist/build/rspack.js.map +1 -0
  68. package/dist/build/terminal.d.ts +9 -0
  69. package/dist/build/terminal.js +17 -0
  70. package/dist/build/terminal.js.map +1 -0
  71. package/dist/cli.d.ts +14 -0
  72. package/dist/cli.js +116 -0
  73. package/dist/cli.js.map +1 -0
  74. package/dist/client/application.d.ts +2 -0
  75. package/dist/client/application.js +73 -0
  76. package/dist/client/application.js.map +1 -0
  77. package/dist/client/browser-capabilities.d.ts +9 -0
  78. package/dist/client/browser-capabilities.js +20 -0
  79. package/dist/client/browser-capabilities.js.map +1 -0
  80. package/dist/client/browser-effect-runner.d.ts +13 -0
  81. package/dist/client/browser-effect-runner.js +13 -0
  82. package/dist/client/browser-effect-runner.js.map +1 -0
  83. package/dist/client/browser-renderer.d.ts +70 -0
  84. package/dist/client/browser-renderer.js +159 -0
  85. package/dist/client/browser-renderer.js.map +1 -0
  86. package/dist/client/browser-screen.d.ts +2 -0
  87. package/dist/client/browser-screen.js +215 -0
  88. package/dist/client/browser-screen.js.map +1 -0
  89. package/dist/client/call-server.d.ts +8 -0
  90. package/dist/client/call-server.js +151 -0
  91. package/dist/client/call-server.js.map +1 -0
  92. package/dist/client/client-router.d.ts +6 -0
  93. package/dist/client/client-router.js +588 -0
  94. package/dist/client/client-router.js.map +1 -0
  95. package/dist/client/entry.d.ts +1 -0
  96. package/dist/client/entry.js +12 -0
  97. package/dist/client/entry.js.map +1 -0
  98. package/dist/client/flight-client.d.ts +83 -0
  99. package/dist/client/flight-client.js +146 -0
  100. package/dist/client/flight-client.js.map +1 -0
  101. package/dist/client/initial-flight-stream.d.ts +18 -0
  102. package/dist/client/initial-flight-stream.js +60 -0
  103. package/dist/client/initial-flight-stream.js.map +1 -0
  104. package/dist/client/navigation-api.d.ts +34 -0
  105. package/dist/client/navigation-api.js +25 -0
  106. package/dist/client/navigation-api.js.map +1 -0
  107. package/dist/client/navigation-routing.d.ts +3 -0
  108. package/dist/client/navigation-routing.js +8 -0
  109. package/dist/client/navigation-routing.js.map +1 -0
  110. package/dist/client/react-dom-renderer.d.ts +20 -0
  111. package/dist/client/react-dom-renderer.js +101 -0
  112. package/dist/client/react-dom-renderer.js.map +1 -0
  113. package/dist/client/route-loader.d.ts +81 -0
  114. package/dist/client/route-loader.js +128 -0
  115. package/dist/client/route-loader.js.map +1 -0
  116. package/dist/client/route-refresh.d.ts +31 -0
  117. package/dist/client/route-refresh.js +132 -0
  118. package/dist/client/route-refresh.js.map +1 -0
  119. package/dist/client/route-tree.d.ts +7 -0
  120. package/dist/client/route-tree.js +34 -0
  121. package/dist/client/route-tree.js.map +1 -0
  122. package/dist/dev/channel.d.ts +18 -0
  123. package/dist/dev/channel.js +30 -0
  124. package/dist/dev/channel.js.map +1 -0
  125. package/dist/dev/client.d.ts +3 -0
  126. package/dist/dev/client.js +132 -0
  127. package/dist/dev/client.js.map +1 -0
  128. package/dist/dev/hmr-update.d.ts +20 -0
  129. package/dist/dev/hmr-update.js +28 -0
  130. package/dist/dev/hmr-update.js.map +1 -0
  131. package/dist/dev/panel.d.ts +41 -0
  132. package/dist/dev/panel.js +9946 -0
  133. package/dist/dev/panel.js.map +1 -0
  134. package/dist/dev/runtime-failure.d.ts +11 -0
  135. package/dist/dev/runtime-failure.js +32 -0
  136. package/dist/dev/runtime-failure.js.map +1 -0
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.js +6 -0
  139. package/dist/index.js.map +1 -0
  140. package/dist/rsc/flight.d.ts +16 -0
  141. package/dist/rsc/flight.js +6 -0
  142. package/dist/rsc/flight.js.map +1 -0
  143. package/dist/rsc/render-route-tree.d.ts +11 -0
  144. package/dist/rsc/render-route-tree.js +52 -0
  145. package/dist/rsc/render-route-tree.js.map +1 -0
  146. package/dist/rsc/route-tree.d.ts +6 -0
  147. package/dist/rsc/route-tree.js +5 -0
  148. package/dist/rsc/route-tree.js.map +1 -0
  149. package/dist/server/application.d.ts +17 -0
  150. package/dist/server/application.js +178 -0
  151. package/dist/server/application.js.map +1 -0
  152. package/dist/server/flight-html-stream.d.ts +19 -0
  153. package/dist/server/flight-html-stream.js +193 -0
  154. package/dist/server/flight-html-stream.js.map +1 -0
  155. package/dist/server/flight-renderer.d.ts +31 -0
  156. package/dist/server/flight-renderer.js +47 -0
  157. package/dist/server/flight-renderer.js.map +1 -0
  158. package/dist/server/html-renderer.d.ts +28 -0
  159. package/dist/server/html-renderer.js +82 -0
  160. package/dist/server/html-renderer.js.map +1 -0
  161. package/dist/server/request-outcome.d.ts +8 -0
  162. package/dist/server/request-outcome.js +5 -0
  163. package/dist/server/request-outcome.js.map +1 -0
  164. package/dist/server/server-config.d.ts +17 -0
  165. package/dist/server/server-config.js +18 -0
  166. package/dist/server/server-config.js.map +1 -0
  167. package/dist/server/server-fn-outcome.d.ts +13 -0
  168. package/dist/server/server-fn-outcome.js +24 -0
  169. package/dist/server/server-fn-outcome.js.map +1 -0
  170. package/dist/server/server-fn-request.d.ts +24 -0
  171. package/dist/server/server-fn-request.js +160 -0
  172. package/dist/server/server-fn-request.js.map +1 -0
  173. package/dist/unsupported.d.ts +0 -0
  174. package/dist/unsupported.js +5 -0
  175. package/dist/unsupported.js.map +1 -0
  176. package/docs/01-getting-started/01_first-application.tsx +26 -0
  177. package/docs/01-getting-started/20_styling.tsx +6 -0
  178. package/docs/01-getting-started/index.md +27 -0
  179. package/docs/01-getting-started/styles.css +1 -0
  180. package/docs/02-guides/01-server-functions/10_ersc.ts +6 -0
  181. package/docs/02-guides/01-server-functions/20_follow-author.ts +15 -0
  182. package/docs/02-guides/01-server-functions/30_follow-author-button.tsx +19 -0
  183. package/docs/02-guides/01-server-functions/40_application.tsx +30 -0
  184. package/docs/02-guides/01-server-functions/index.md +19 -0
  185. package/docs/02-guides/02-services/10_catalog.ts +22 -0
  186. package/docs/02-guides/02-services/20_application.tsx +44 -0
  187. package/docs/02-guides/02-services/index.md +17 -0
  188. package/docs/02-guides/03-routing/10_ersc.ts +6 -0
  189. package/docs/02-guides/03-routing/10_layouts.tsx +36 -0
  190. package/docs/02-guides/03-routing/20_pages.tsx +23 -0
  191. package/docs/02-guides/03-routing/30_routes.tsx +17 -0
  192. package/docs/02-guides/03-routing/40_application.ts +7 -0
  193. package/docs/02-guides/03-routing/index.md +22 -0
  194. package/docs/02-guides/04-middleware/10_auth.ts +27 -0
  195. package/docs/02-guides/04-middleware/20_account-page.tsx +13 -0
  196. package/docs/02-guides/04-middleware/30_update-profile.ts +16 -0
  197. package/docs/02-guides/04-middleware/40_application.tsx +20 -0
  198. package/docs/02-guides/04-middleware/index.md +25 -0
  199. package/docs/02-guides/05-http/10_application-layer.tsx +60 -0
  200. package/docs/02-guides/05-http/index.md +23 -0
  201. package/docs/02-guides/index.md +11 -0
  202. package/docs/03-advanced/01-request-runtime-and-lifetimes/index.md +13 -0
  203. package/docs/03-advanced/02-client-navigation/index.md +61 -0
  204. package/docs/03-advanced/03-server-function-execution-and-refresh/index.md +17 -0
  205. package/docs/03-advanced/index.md +11 -0
  206. package/docs/04-api-reference/01-application/index.md +8 -0
  207. package/docs/04-api-reference/02-page/index.md +12 -0
  208. package/docs/04-api-reference/03-layout/index.md +4 -0
  209. package/docs/04-api-reference/04-loading/index.md +4 -0
  210. package/docs/04-api-reference/05-component/10_component.tsx +18 -0
  211. package/docs/04-api-reference/05-component/index.md +10 -0
  212. package/docs/04-api-reference/06-middleware/index.md +33 -0
  213. package/docs/04-api-reference/07-routes/index.md +20 -0
  214. package/docs/04-api-reference/08-server-fn/index.md +43 -0
  215. package/docs/04-api-reference/index.md +17 -0
  216. package/docs/environment.d.ts +1 -0
  217. package/docs/index.md +15 -0
  218. package/logo-dark.svg +6 -0
  219. package/logo.svg +6 -0
  220. package/package.json +87 -0
@@ -0,0 +1,9 @@
1
+ import type { Effect } from 'effect';
2
+ export type RenderRuntime<Services> = <Output, Error>(effect: Effect.Effect<Output, Error, Services>) => Promise<Output>;
3
+ type RenderConcern = 'Component' | 'Layout' | 'Page';
4
+ export type RenderRuntimeContext = {
5
+ readonly bind: <Services, Output>(runtime: RenderRuntime<Services>, activeMiddleware: ReadonlyArray<object>, evaluate: () => Output) => Output;
6
+ readonly run: <Output, Error, Services>(concern: RenderConcern, effect: Effect.Effect<Output, Error, Services>, requiredMiddleware: ReadonlyArray<object>) => Promise<Output>;
7
+ };
8
+ export declare const makeRenderRuntimeContext: () => RenderRuntimeContext;
9
+ export {};
@@ -0,0 +1,28 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+
4
+
5
+ const makeRenderRuntimeContext = ()=>{
6
+ const storage = new AsyncLocalStorage();
7
+ return {
8
+ bind: (runtime, activeMiddleware, evaluate)=>storage.run({
9
+ activeMiddleware,
10
+ run: runtime
11
+ }, evaluate),
12
+ run: (concern, effect, requiredMiddleware)=>{
13
+ const bound = storage.getStore();
14
+ if (bound === undefined) {
15
+ throw new TypeError(`ERSC ${concern} rendered outside its application request runtime.`);
16
+ }
17
+ const middlewareAvailable = requiredMiddleware.every((required)=>bound.activeMiddleware.includes(required));
18
+ if (!middlewareAvailable) {
19
+ throw new TypeError(`ERSC ${concern} requires a middleware scope that is not active for this request.`);
20
+ }
21
+ return bound.run(effect);
22
+ }
23
+ };
24
+ };
25
+
26
+ export { makeRenderRuntimeContext };
27
+
28
+ //# sourceMappingURL=render-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"application/render-runtime.js","sources":["../../src/application/render-runtime.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\n\nimport type { Effect } from 'effect';\n\nexport type RenderRuntime<Services> = <Output, Error>(\n effect: Effect.Effect<Output, Error, Services>,\n) => Promise<Output>;\n\ntype RenderConcern = 'Component' | 'Layout' | 'Page';\n\ntype BoundRenderRuntime = {\n readonly activeMiddleware: ReadonlyArray<object>;\n readonly run: RenderRuntime<any>;\n};\n\nexport type RenderRuntimeContext = {\n readonly bind: <Services, Output>(\n runtime: RenderRuntime<Services>,\n activeMiddleware: ReadonlyArray<object>,\n evaluate: () => Output,\n ) => Output;\n readonly run: <Output, Error, Services>(\n concern: RenderConcern,\n effect: Effect.Effect<Output, Error, Services>,\n requiredMiddleware: ReadonlyArray<object>,\n ) => Promise<Output>;\n};\n\nexport const makeRenderRuntimeContext = (): RenderRuntimeContext => {\n const storage = new AsyncLocalStorage<BoundRenderRuntime>();\n\n return {\n bind: (runtime, activeMiddleware, evaluate) =>\n storage.run({ activeMiddleware, run: runtime }, evaluate),\n run: (concern, effect, requiredMiddleware) => {\n const bound = storage.getStore();\n if (bound === undefined) {\n throw new TypeError(`ERSC ${concern} rendered outside its application request runtime.`);\n }\n const middlewareAvailable = requiredMiddleware.every((required) =>\n bound.activeMiddleware.includes(required),\n );\n if (!middlewareAvailable) {\n throw new TypeError(\n `ERSC ${concern} requires a middleware scope that is not active for this request.`,\n );\n }\n\n return bound.run(effect);\n },\n };\n};\n"],"names":["AsyncLocalStorage","makeRenderRuntimeContext","storage","runtime","activeMiddleware","evaluate","concern","effect","requiredMiddleware","bound","undefined","TypeError","middlewareAvailable","required"],"mappings":";;;AAAqD;AA4B9C,MAAMC,wBAAwBA,GAAG;IACtC,MAAMC,UAAU,IAAIF,iBAAiBA;IAErC,OAAO;QACL,MAAM,CAACG,SAASC,kBAAkBC,WAChCH,QAAQ,GAAG,CAAC;gBAAEE;gBAAkB,KAAKD;YAAQ,GAAGE;QAClD,KAAK,CAACC,SAASC,QAAQC;YACrB,MAAMC,QAAQP,QAAQ,QAAQ;YAC9B,IAAIO,UAAUC,WAAW;gBACvB,MAAM,IAAIC,UAAU,CAAC,KAAK,EAAEL,QAAQ,kDAAkD,CAAC;YACzF;YACA,MAAMM,sBAAsBJ,mBAAmB,KAAK,CAAC,CAACK,WACpDJ,MAAM,gBAAgB,CAAC,QAAQ,CAACI;YAElC,IAAI,CAACD,qBAAqB;gBACxB,MAAM,IAAID,UACR,CAAC,KAAK,EAAEL,QAAQ,iEAAiE,CAAC;YAEtF;YAEA,OAAOG,MAAM,GAAG,CAACF;QACnB;IACF;AACF,EAAE"}
@@ -0,0 +1,22 @@
1
+ import type { LayoutComponent } from './layout.js';
2
+ import type { LoadingComponent } from './loading.js';
3
+ import type { AnyMiddleware } from './middleware.js';
4
+ import { type PageImplementationState } from './page.js';
5
+ import { type AbsolutePath } from './route-path.js';
6
+ import { type AnyRoutes } from './routes.js';
7
+ export type RouteScope<Services> = {
8
+ readonly id: string;
9
+ readonly layout: LayoutComponent<Services> | null;
10
+ readonly loading: LoadingComponent<Services> | null;
11
+ };
12
+ export type CompiledDestination<Services> = {
13
+ readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;
14
+ readonly page: PageImplementationState;
15
+ readonly pattern: AbsolutePath;
16
+ readonly scopes: ReadonlyArray<RouteScope<Services>>;
17
+ };
18
+ export type CompiledRouteGraph<Services> = readonly [
19
+ CompiledDestination<Services>,
20
+ ...Array<CompiledDestination<Services>>
21
+ ];
22
+ export declare const compileRouteGraph: <Services>(routes: AnyRoutes<Services>) => CompiledRouteGraph<Services>;
@@ -0,0 +1,68 @@
1
+ import { getPageState } from "./page.js";
2
+ import { joinRoutePaths, validateUnreservedPath } from "./route-path.js";
3
+ import { getRoutesState } from "./routes.js";
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ const resolveRouteMiddleware = (inherited, declared)=>{
12
+ let sharedCount = 0;
13
+ while(sharedCount < inherited.length && inherited[sharedCount] === declared[sharedCount]){
14
+ sharedCount += 1;
15
+ }
16
+ return sharedCount === inherited.length ? declared : Object.freeze([
17
+ ...inherited,
18
+ ...declared.slice(sharedCount)
19
+ ]);
20
+ };
21
+ const compileRouteGraph = (routes)=>{
22
+ const rootState = getRoutesState(routes);
23
+ if (rootState.layout === null) {
24
+ throw new TypeError('The root Routes passed to ERSC.make must define a Layout.');
25
+ }
26
+ const destinations = [];
27
+ const visit = (current, prefix, inheritedScopes, inheritedMiddleware)=>{
28
+ const currentState = getRoutesState(current);
29
+ const middleware = resolveRouteMiddleware(inheritedMiddleware, currentState.middleware);
30
+ if (new Set(middleware).size !== middleware.length) {
31
+ throw new TypeError(`Middleware beneath route prefix "${prefix}" appears more than once in its resolved chain.`);
32
+ }
33
+ const scopes = currentState.layout === null && currentState.loading === null ? inheritedScopes : Object.freeze([
34
+ ...inheritedScopes,
35
+ Object.freeze({
36
+ id: `${currentState.scopeId}:${prefix}`,
37
+ layout: currentState.layout,
38
+ loading: currentState.loading
39
+ })
40
+ ]);
41
+ for (const route of currentState.pages){
42
+ const pattern = joinRoutePaths(prefix, route.path);
43
+ validateUnreservedPath(pattern);
44
+ destinations.push(Object.freeze({
45
+ middleware,
46
+ page: getPageState(route.page),
47
+ pattern,
48
+ scopes
49
+ }));
50
+ }
51
+ for (const mount of currentState.mounts){
52
+ visit(mount.routes, joinRoutePaths(prefix, mount.path), scopes, middleware);
53
+ }
54
+ };
55
+ visit(routes, '/', [], []);
56
+ const [firstDestination, ...remainingDestinations] = destinations;
57
+ if (firstDestination === undefined) {
58
+ throw new TypeError('The root Routes passed to ERSC.make must contain a Page.');
59
+ }
60
+ return Object.freeze([
61
+ firstDestination,
62
+ ...remainingDestinations
63
+ ]);
64
+ };
65
+
66
+ export { compileRouteGraph };
67
+
68
+ //# sourceMappingURL=route-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"application/route-graph.js","sources":["../../src/application/route-graph.ts"],"sourcesContent":["import type { LayoutComponent } from './layout';\nimport type { LoadingComponent } from './loading';\nimport type { AnyMiddleware } from './middleware';\nimport { getPageState, type PageImplementationState } from './page';\nimport { type AbsolutePath, joinRoutePaths, validateUnreservedPath } from './route-path';\nimport { type AnyRoutes, getRoutesState } from './routes';\n\nexport type RouteScope<Services> = {\n readonly id: string;\n readonly layout: LayoutComponent<Services> | null;\n readonly loading: LoadingComponent<Services> | null;\n};\n\nexport type CompiledDestination<Services> = {\n readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;\n readonly page: PageImplementationState;\n readonly pattern: AbsolutePath;\n readonly scopes: ReadonlyArray<RouteScope<Services>>;\n};\n\nexport type CompiledRouteGraph<Services> = readonly [\n CompiledDestination<Services>,\n ...Array<CompiledDestination<Services>>,\n];\n\nconst resolveRouteMiddleware = <Services>(\n inherited: ReadonlyArray<AnyMiddleware<Services>>,\n declared: ReadonlyArray<AnyMiddleware<Services>>,\n) => {\n let sharedCount = 0;\n while (sharedCount < inherited.length && inherited[sharedCount] === declared[sharedCount]) {\n sharedCount += 1;\n }\n\n return sharedCount === inherited.length\n ? declared\n : Object.freeze([...inherited, ...declared.slice(sharedCount)]);\n};\n\nexport const compileRouteGraph = <Services>(\n routes: AnyRoutes<Services>,\n): CompiledRouteGraph<Services> => {\n const rootState = getRoutesState(routes);\n if (rootState.layout === null) {\n throw new TypeError('The root Routes passed to ERSC.make must define a Layout.');\n }\n\n const destinations: Array<CompiledDestination<Services>> = [];\n const visit = (\n current: AnyRoutes<Services>,\n prefix: AbsolutePath,\n inheritedScopes: ReadonlyArray<RouteScope<Services>>,\n inheritedMiddleware: ReadonlyArray<AnyMiddleware<Services>>,\n ): void => {\n const currentState = getRoutesState(current);\n const middleware = resolveRouteMiddleware(inheritedMiddleware, currentState.middleware);\n if (new Set(middleware).size !== middleware.length) {\n throw new TypeError(\n `Middleware beneath route prefix \"${prefix}\" appears more than once in its resolved chain.`,\n );\n }\n const scopes =\n currentState.layout === null && currentState.loading === null\n ? inheritedScopes\n : Object.freeze([\n ...inheritedScopes,\n Object.freeze({\n id: `${currentState.scopeId}:${prefix}`,\n layout: currentState.layout,\n loading: currentState.loading,\n }),\n ]);\n\n for (const route of currentState.pages) {\n const pattern = joinRoutePaths(prefix, route.path);\n validateUnreservedPath(pattern);\n destinations.push(\n Object.freeze({ middleware, page: getPageState(route.page), pattern, scopes }),\n );\n }\n\n for (const mount of currentState.mounts) {\n visit(mount.routes, joinRoutePaths(prefix, mount.path), scopes, middleware);\n }\n };\n\n visit(routes, '/', [], []);\n const [firstDestination, ...remainingDestinations] = destinations;\n if (firstDestination === undefined) {\n throw new TypeError('The root Routes passed to ERSC.make must contain a Page.');\n }\n\n return Object.freeze([firstDestination, ...remainingDestinations]);\n};\n"],"names":["getPageState","joinRoutePaths","validateUnreservedPath","getRoutesState","resolveRouteMiddleware","inherited","declared","sharedCount","Object","compileRouteGraph","routes","rootState","TypeError","destinations","visit","current","prefix","inheritedScopes","inheritedMiddleware","currentState","middleware","Set","scopes","route","pattern","mount","firstDestination","remainingDestinations","undefined"],"mappings":";;;;;;;AAGoE;AACqB;AAC/B;AAoB1D,MAAMI,sBAAsBA,GAAG,CAC7BC,WACAC;IAEA,IAAIC,cAAc;IAClB,MAAOA,cAAcF,UAAU,MAAM,IAAIA,SAAS,CAACE,YAAY,KAAKD,QAAQ,CAACC,YAAY,CAAE;QACzFA,eAAe;IACjB;IAEA,OAAOA,gBAAgBF,UAAU,MAAM,GACnCC,WACAE,OAAO,MAAM,CAAC;WAAIH;WAAcC,SAAS,KAAK,CAACC;KAAa;AAClE;AAEO,MAAME,iBAAiBA,GAAG,CAC/BC;IAEA,MAAMC,YAAYR,cAAcA,CAACO;IACjC,IAAIC,UAAU,MAAM,KAAK,MAAM;QAC7B,MAAM,IAAIC,UAAU;IACtB;IAEA,MAAMC,eAAqD,EAAE;IAC7D,MAAMC,QAAQ,CACZC,SACAC,QACAC,iBACAC;QAEA,MAAMC,eAAehB,cAAcA,CAACY;QACpC,MAAMK,aAAahB,sBAAsBA,CAACc,qBAAqBC,aAAa,UAAU;QACtF,IAAI,IAAIE,IAAID,YAAY,IAAI,KAAKA,WAAW,MAAM,EAAE;YAClD,MAAM,IAAIR,UACR,CAAC,iCAAiC,EAAEI,OAAO,+CAA+C,CAAC;QAE/F;QACA,MAAMM,SACJH,aAAa,MAAM,KAAK,QAAQA,aAAa,OAAO,KAAK,OACrDF,kBACAT,OAAO,MAAM,CAAC;eACTS;YACHT,OAAO,MAAM,CAAC;gBACZ,IAAI,GAAGW,aAAa,OAAO,CAAC,CAAC,EAAEH,QAAQ;gBACvC,QAAQG,aAAa,MAAM;gBAC3B,SAASA,aAAa,OAAO;YAC/B;SACD;QAEP,KAAK,MAAMI,SAASJ,aAAa,KAAK,CAAE;YACtC,MAAMK,UAAUvB,cAAcA,CAACe,QAAQO,MAAM,IAAI;YACjDrB,sBAAsBA,CAACsB;YACvBX,aAAa,IAAI,CACfL,OAAO,MAAM,CAAC;gBAAEY;gBAAY,MAAMpB,YAAYA,CAACuB,MAAM,IAAI;gBAAGC;gBAASF;YAAO;QAEhF;QAEA,KAAK,MAAMG,SAASN,aAAa,MAAM,CAAE;YACvCL,MAAMW,MAAM,MAAM,EAAExB,cAAcA,CAACe,QAAQS,MAAM,IAAI,GAAGH,QAAQF;QAClE;IACF;IAEAN,MAAMJ,QAAQ,KAAK,EAAE,EAAE,EAAE;IACzB,MAAM,CAACgB,kBAAkB,GAAGC,sBAAsB,GAAGd;IACrD,IAAIa,qBAAqBE,WAAW;QAClC,MAAM,IAAIhB,UAAU;IACtB;IAEA,OAAOJ,OAAO,MAAM,CAAC;QAACkB;WAAqBC;KAAsB;AACnE,EAAE"}
@@ -0,0 +1,31 @@
1
+ export type AbsolutePath = `/${string}`;
2
+ type InvalidRouteCharacter = '*' | '?' | '#' | '%' | ';' | '\\';
3
+ type InvalidParameterCharacter = InvalidRouteCharacter | '/' | ':' | '(' | ')' | '.' | '-';
4
+ export type ValidRouteParamName<Name extends string> = string extends Name ? never : Name extends '' ? never : Name extends `${string}${InvalidParameterCharacter}${string}` ? never : Name;
5
+ type IsUnion<Value, Whole = Value> = Value extends Whole ? [Whole] extends [Value] ? false : true : never;
6
+ type ValidRouteSegments<Segments extends string, Seen extends string = never> = string extends Segments ? false : Segments extends `${infer Segment}/${infer Rest}` ? Segment extends '' | '.' | '..' ? false : Segment extends `:${infer Parameter}` ? Parameter extends '' ? false : Parameter extends `${string}${InvalidParameterCharacter}${string}` ? false : Parameter extends Seen ? false : ValidRouteSegments<Rest, Seen | Parameter> : Segment extends `${string}:${string}` ? false : ValidRouteSegments<Rest, Seen> : Segments extends '' | '.' | '..' ? false : Segments extends `:${infer Parameter}` ? Parameter extends '' ? false : Parameter extends `${string}${InvalidParameterCharacter}${string}` ? false : Parameter extends Seen ? false : true : Segments extends `${string}:${string}` ? false : true;
7
+ export type ValidRoutePath<Path extends AbsolutePath> = true extends IsUnion<Path> ? never : Path extends '/' ? Path : Path extends `${string}${InvalidRouteCharacter}${string}` ? never : Path extends `/${infer Segments}` ? ValidRouteSegments<Segments> extends true ? Path : never : never;
8
+ type RouteParamNamesFromSegments<Segments extends string> = Segments extends `${infer Segment}/${infer Rest}` ? (Segment extends `:${infer Parameter}` ? Parameter : never) | RouteParamNamesFromSegments<Rest> : Segments extends `:${infer Parameter}` ? Parameter : never;
9
+ export type RouteParamNames<Path extends AbsolutePath> = Path extends `/${infer Segments}` ? RouteParamNamesFromSegments<Segments> : never;
10
+ type RouteShapeSegments<Segments extends string> = Segments extends `${infer Segment}/${infer Rest}` ? `${Segment extends `:${string}` ? ':' : Segment}/${RouteShapeSegments<Rest>}` : Segments extends `:${string}` ? ':' : Segments;
11
+ export type RouteShape<Path extends AbsolutePath> = Path extends `/${infer Segments}` ? Lowercase<`/${RouteShapeSegments<Segments>}`> : never;
12
+ export type JoinPath<Prefix extends AbsolutePath, Path extends AbsolutePath> = Prefix extends '/' ? Path : Path extends '/' ? Prefix : `${Prefix}${Path}`;
13
+ export declare const FrameworkNamespace = "/_ersc";
14
+ export declare const FrameworkAssetNamespace = "/_ersc/assets";
15
+ export declare const FrameworkAssetPrefix: "/_ersc/assets/";
16
+ type SegmentCanMatch<Segment extends string, Expected extends string> = Segment extends `:${string}` ? true : Lowercase<Segment> extends Expected ? true : false;
17
+ type MatchesReservedSegments<Segments extends string> = Segments extends `${infer First}/${string}` ? SegmentCanMatch<First, '_ersc'> : SegmentCanMatch<Segments, '_ersc'>;
18
+ export type ReservedRoutePath<Path extends AbsolutePath> = Path extends `/${infer Segments}` ? MatchesReservedSegments<Segments> extends true ? Path : never : never;
19
+ type RouteAnalysis = {
20
+ readonly _tag: 'ParameterFree';
21
+ readonly shape: string;
22
+ } | {
23
+ readonly _tag: 'Parameterized';
24
+ readonly parameterNames: readonly [string, ...Array<string>];
25
+ readonly shape: string;
26
+ };
27
+ export declare const analyzeRoutePath: (path: string) => RouteAnalysis;
28
+ export declare const validateUnreservedPath: (path: string) => void;
29
+ export declare const joinRoutePaths: (prefix: AbsolutePath, path: AbsolutePath) => AbsolutePath;
30
+ export declare const isAbsolutePath: (value: string) => value is AbsolutePath;
31
+ export {};
@@ -0,0 +1,67 @@
1
+ const FrameworkNamespace = '/_ersc';
2
+ const FrameworkAssetNamespace = `${FrameworkNamespace}/assets`;
3
+ const FrameworkAssetPrefix = `${FrameworkAssetNamespace}/`;
4
+ const InvalidRoutePath = /[*?#%;\\]/u;
5
+ const DynamicSegment = /^:([^:().-]+)$/u;
6
+ const analyzeRoutePath = (path)=>{
7
+ if (!path.startsWith('/') || InvalidRoutePath.test(path)) {
8
+ throw new TypeError(`Invalid route path "${path}". Route paths must start with "/" and cannot contain "*", "?", "#", "%", ";", or "\\".`);
9
+ }
10
+ const segments = path === '/' ? [] : path.slice(1).split('/');
11
+ if (segments.some((segment)=>segment === '' || segment === '.' || segment === '..')) {
12
+ throw new TypeError(`Invalid route path "${path}". Route paths cannot contain empty, ".", or ".." segments or end with "/".`);
13
+ }
14
+ const parameterNames = new Set();
15
+ const shapeSegments = [];
16
+ for (const segment of segments){
17
+ if (!segment.includes(':')) {
18
+ shapeSegments.push(segment.toLowerCase());
19
+ continue;
20
+ }
21
+ const match = DynamicSegment.exec(segment);
22
+ if (match === null) {
23
+ throw new TypeError(`Invalid route path "${path}". Dynamic segments must use the ":parameter" convention.`);
24
+ }
25
+ const parameterName = match[1];
26
+ if (parameterName === undefined || parameterNames.has(parameterName)) {
27
+ throw new TypeError(`Invalid route path "${path}". Dynamic parameter names must be unique within a route.`);
28
+ }
29
+ parameterNames.add(parameterName);
30
+ shapeSegments.push(':');
31
+ }
32
+ const shape = `/${shapeSegments.join('/')}`;
33
+ const parameters = parameterNames.values();
34
+ const firstParameter = parameters.next();
35
+ return firstParameter.done ? {
36
+ _tag: 'ParameterFree',
37
+ shape
38
+ } : {
39
+ _tag: 'Parameterized',
40
+ parameterNames: Object.freeze([
41
+ firstParameter.value,
42
+ ...parameters
43
+ ]),
44
+ shape
45
+ };
46
+ };
47
+ const validateUnreservedPath = (path)=>{
48
+ const segments = path.slice(1).split('/');
49
+ const canMatch = (segment, expected)=>segment?.startsWith(':') === true || segment?.toLowerCase() === expected;
50
+ if (canMatch(segments[0], '_ersc')) {
51
+ throw new TypeError(`Route "${path}" uses the framework-reserved "${FrameworkNamespace}" namespace.`);
52
+ }
53
+ };
54
+ const joinRoutePaths = (prefix, path)=>{
55
+ if (prefix === '/') {
56
+ return path;
57
+ }
58
+ if (path === '/') {
59
+ return prefix;
60
+ }
61
+ return `${prefix}${path}`;
62
+ };
63
+ const isAbsolutePath = (value)=>value.startsWith('/');
64
+
65
+ export { FrameworkAssetNamespace, FrameworkAssetPrefix, FrameworkNamespace, analyzeRoutePath, isAbsolutePath, joinRoutePaths, validateUnreservedPath };
66
+
67
+ //# sourceMappingURL=route-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"application/route-path.js","sources":["../../src/application/route-path.ts"],"sourcesContent":["export type AbsolutePath = `/${string}`;\n\n// Compile-time and runtime route grammars are deliberately paired. Any grammar change must update\n// both ValidRoutePath/ValidRouteParamName and analyzeRoutePath, with one paired type/runtime test.\ntype InvalidRouteCharacter = '*' | '?' | '#' | '%' | ';' | '\\\\';\ntype InvalidParameterCharacter = InvalidRouteCharacter | '/' | ':' | '(' | ')' | '.' | '-';\n\nexport type ValidRouteParamName<Name extends string> = string extends Name\n ? never\n : Name extends ''\n ? never\n : Name extends `${string}${InvalidParameterCharacter}${string}`\n ? never\n : Name;\n\ntype IsUnion<Value, Whole = Value> = Value extends Whole\n ? [Whole] extends [Value]\n ? false\n : true\n : never;\n\ntype ValidRouteSegments<\n Segments extends string,\n Seen extends string = never,\n> = string extends Segments\n ? false\n : Segments extends `${infer Segment}/${infer Rest}`\n ? Segment extends '' | '.' | '..'\n ? false\n : Segment extends `:${infer Parameter}`\n ? Parameter extends ''\n ? false\n : Parameter extends `${string}${InvalidParameterCharacter}${string}`\n ? false\n : Parameter extends Seen\n ? false\n : ValidRouteSegments<Rest, Seen | Parameter>\n : Segment extends `${string}:${string}`\n ? false\n : ValidRouteSegments<Rest, Seen>\n : Segments extends '' | '.' | '..'\n ? false\n : Segments extends `:${infer Parameter}`\n ? Parameter extends ''\n ? false\n : Parameter extends `${string}${InvalidParameterCharacter}${string}`\n ? false\n : Parameter extends Seen\n ? false\n : true\n : Segments extends `${string}:${string}`\n ? false\n : true;\n\nexport type ValidRoutePath<Path extends AbsolutePath> =\n true extends IsUnion<Path>\n ? never\n : Path extends '/'\n ? Path\n : Path extends `${string}${InvalidRouteCharacter}${string}`\n ? never\n : Path extends `/${infer Segments}`\n ? ValidRouteSegments<Segments> extends true\n ? Path\n : never\n : never;\n\ntype RouteParamNamesFromSegments<Segments extends string> =\n Segments extends `${infer Segment}/${infer Rest}`\n ?\n | (Segment extends `:${infer Parameter}` ? Parameter : never)\n | RouteParamNamesFromSegments<Rest>\n : Segments extends `:${infer Parameter}`\n ? Parameter\n : never;\n\nexport type RouteParamNames<Path extends AbsolutePath> = Path extends `/${infer Segments}`\n ? RouteParamNamesFromSegments<Segments>\n : never;\n\ntype RouteShapeSegments<Segments extends string> = Segments extends `${infer Segment}/${infer Rest}`\n ? `${Segment extends `:${string}` ? ':' : Segment}/${RouteShapeSegments<Rest>}`\n : Segments extends `:${string}`\n ? ':'\n : Segments;\n\nexport type RouteShape<Path extends AbsolutePath> = Path extends `/${infer Segments}`\n ? Lowercase<`/${RouteShapeSegments<Segments>}`>\n : never;\n\nexport type JoinPath<Prefix extends AbsolutePath, Path extends AbsolutePath> = Prefix extends '/'\n ? Path\n : Path extends '/'\n ? Prefix\n : `${Prefix}${Path}`;\n\nexport const FrameworkNamespace = '/_ersc';\n\nexport const FrameworkAssetNamespace = `${FrameworkNamespace}/assets`;\n\nexport const FrameworkAssetPrefix = `${FrameworkAssetNamespace}/` as const;\n\ntype SegmentCanMatch<Segment extends string, Expected extends string> = Segment extends `:${string}`\n ? true\n : Lowercase<Segment> extends Expected\n ? true\n : false;\n\ntype MatchesReservedSegments<Segments extends string> = Segments extends `${infer First}/${string}`\n ? SegmentCanMatch<First, '_ersc'>\n : SegmentCanMatch<Segments, '_ersc'>;\n\nexport type ReservedRoutePath<Path extends AbsolutePath> = Path extends `/${infer Segments}`\n ? MatchesReservedSegments<Segments> extends true\n ? Path\n : never\n : never;\n\nconst InvalidRoutePath = /[*?#%;\\\\]/u;\nconst DynamicSegment = /^:([^:().-]+)$/u;\n\ntype RouteAnalysis =\n | {\n readonly _tag: 'ParameterFree';\n readonly shape: string;\n }\n | {\n readonly _tag: 'Parameterized';\n readonly parameterNames: readonly [string, ...Array<string>];\n readonly shape: string;\n };\n\nexport const analyzeRoutePath = (path: string): RouteAnalysis => {\n if (!path.startsWith('/') || InvalidRoutePath.test(path)) {\n throw new TypeError(\n `Invalid route path \"${path}\". Route paths must start with \"/\" and cannot contain \"*\", \"?\", \"#\", \"%\", \";\", or \"\\\\\".`,\n );\n }\n\n const segments = path === '/' ? [] : path.slice(1).split('/');\n if (segments.some((segment) => segment === '' || segment === '.' || segment === '..')) {\n throw new TypeError(\n `Invalid route path \"${path}\". Route paths cannot contain empty, \".\", or \"..\" segments or end with \"/\".`,\n );\n }\n\n const parameterNames = new Set<string>();\n const shapeSegments: Array<string> = [];\n for (const segment of segments) {\n if (!segment.includes(':')) {\n shapeSegments.push(segment.toLowerCase());\n continue;\n }\n\n const match = DynamicSegment.exec(segment);\n if (match === null) {\n throw new TypeError(\n `Invalid route path \"${path}\". Dynamic segments must use the \":parameter\" convention.`,\n );\n }\n\n const parameterName = match[1];\n if (parameterName === undefined || parameterNames.has(parameterName)) {\n throw new TypeError(\n `Invalid route path \"${path}\". Dynamic parameter names must be unique within a route.`,\n );\n }\n\n parameterNames.add(parameterName);\n shapeSegments.push(':');\n }\n\n const shape = `/${shapeSegments.join('/')}`;\n const parameters = parameterNames.values();\n const firstParameter = parameters.next();\n return firstParameter.done\n ? { _tag: 'ParameterFree', shape }\n : {\n _tag: 'Parameterized',\n parameterNames: Object.freeze([firstParameter.value, ...parameters]),\n shape,\n };\n};\n\nexport const validateUnreservedPath = (path: string) => {\n const segments = path.slice(1).split('/');\n const canMatch = (segment: string | undefined, expected: string) =>\n segment?.startsWith(':') === true || segment?.toLowerCase() === expected;\n if (canMatch(segments[0], '_ersc')) {\n throw new TypeError(\n `Route \"${path}\" uses the framework-reserved \"${FrameworkNamespace}\" namespace.`,\n );\n }\n};\n\nexport const joinRoutePaths = (prefix: AbsolutePath, path: AbsolutePath): AbsolutePath => {\n if (prefix === '/') {\n return path;\n }\n if (path === '/') {\n return prefix;\n }\n return `${prefix}${path}`;\n};\n\nexport const isAbsolutePath = (value: string): value is AbsolutePath => value.startsWith('/');\n"],"names":["FrameworkNamespace","FrameworkAssetNamespace","FrameworkAssetPrefix","InvalidRoutePath","DynamicSegment","analyzeRoutePath","path","TypeError","segments","segment","parameterNames","Set","shapeSegments","match","parameterName","undefined","shape","parameters","firstParameter","Object","validateUnreservedPath","canMatch","expected","joinRoutePaths","prefix","isAbsolutePath","value"],"mappings":"AAgGO,MAAMA,kBAAkBA,GAAG,SAAS;AAEpC,MAAMC,uBAAuBA,GAAG,GAAGD,kBAAkBA,CAAC,OAAO,CAAC,CAAC;AAE/D,MAAME,oBAAoBA,GAAG,GAAGD,uBAAuBA,CAAC,CAAC,CAAC,CAAU;AAkB3E,MAAME,gBAAgBA,GAAG;AACzB,MAAMC,cAAcA,GAAG;AAahB,MAAMC,gBAAgBA,GAAG,CAACC;IAC/B,IAAI,CAACA,KAAK,UAAU,CAAC,QAAQH,gBAAgBA,CAAC,IAAI,CAACG,OAAO;QACxD,MAAM,IAAIC,UACR,CAAC,oBAAoB,EAAED,KAAK,uFAAuF,CAAC;IAExH;IAEA,MAAME,WAAWF,SAAS,MAAM,EAAE,GAAGA,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC;IACzD,IAAIE,SAAS,IAAI,CAAC,CAACC,UAAYA,YAAY,MAAMA,YAAY,OAAOA,YAAY,OAAO;QACrF,MAAM,IAAIF,UACR,CAAC,oBAAoB,EAAED,KAAK,2EAA2E,CAAC;IAE5G;IAEA,MAAMI,iBAAiB,IAAIC;IAC3B,MAAMC,gBAA+B,EAAE;IACvC,KAAK,MAAMH,WAAWD,SAAU;QAC9B,IAAI,CAACC,QAAQ,QAAQ,CAAC,MAAM;YAC1BG,cAAc,IAAI,CAACH,QAAQ,WAAW;YACtC;QACF;QAEA,MAAMI,QAAQT,cAAcA,CAAC,IAAI,CAACK;QAClC,IAAII,UAAU,MAAM;YAClB,MAAM,IAAIN,UACR,CAAC,oBAAoB,EAAED,KAAK,yDAAyD,CAAC;QAE1F;QAEA,MAAMQ,gBAAgBD,KAAK,CAAC,EAAE;QAC9B,IAAIC,kBAAkBC,aAAaL,eAAe,GAAG,CAACI,gBAAgB;YACpE,MAAM,IAAIP,UACR,CAAC,oBAAoB,EAAED,KAAK,yDAAyD,CAAC;QAE1F;QAEAI,eAAe,GAAG,CAACI;QACnBF,cAAc,IAAI,CAAC;IACrB;IAEA,MAAMI,QAAQ,CAAC,CAAC,EAAEJ,cAAc,IAAI,CAAC,MAAM;IAC3C,MAAMK,aAAaP,eAAe,MAAM;IACxC,MAAMQ,iBAAiBD,WAAW,IAAI;IACtC,OAAOC,eAAe,IAAI,GACtB;QAAE,MAAM;QAAiBF;IAAM,IAC/B;QACE,MAAM;QACN,gBAAgBG,OAAO,MAAM,CAAC;YAACD,eAAe,KAAK;eAAKD;SAAW;QACnED;IACF;AACN,EAAE;AAEK,MAAMI,sBAAsBA,GAAG,CAACd;IACrC,MAAME,WAAWF,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC;IACrC,MAAMe,WAAW,CAACZ,SAA6Ba,WAC7Cb,SAAS,WAAW,SAAS,QAAQA,SAAS,kBAAkBa;IAClE,IAAID,SAASb,QAAQ,CAAC,EAAE,EAAE,UAAU;QAClC,MAAM,IAAID,UACR,CAAC,OAAO,EAAED,KAAK,+BAA+B,EAAEN,kBAAkBA,CAAC,YAAY,CAAC;IAEpF;AACF,EAAE;AAEK,MAAMuB,cAAcA,GAAG,CAACC,QAAsBlB;IACnD,IAAIkB,WAAW,KAAK;QAClB,OAAOlB;IACT;IACA,IAAIA,SAAS,KAAK;QAChB,OAAOkB;IACT;IACA,OAAO,GAAGA,SAASlB,MAAM;AAC3B,EAAE;AAEK,MAAMmB,cAAcA,GAAG,CAACC,QAAyCA,MAAM,UAAU,CAAC,KAAK"}
@@ -0,0 +1,66 @@
1
+ import { type Types } from 'effect';
2
+ import { type ERSCIdentity, type ERSCStatefulMember } from './ersc-identity.js';
3
+ import type { LayoutComponent } from './layout.js';
4
+ import type { LoadingComponent } from './loading.js';
5
+ import type { AnyMiddleware } from './middleware.js';
6
+ import { type AnyPageDefinition, type PageConcern } from './page.js';
7
+ import { type AbsolutePath, type JoinPath, type RouteParamNames, type RouteShape, type ValidRoutePath } from './route-path.js';
8
+ declare const RoutesContractTypeId: unique symbol;
9
+ type RoutesState<HasLayout extends boolean, Paths extends AbsolutePath> = {
10
+ readonly hasLayout: Types.Covariant<HasLayout>;
11
+ readonly paths: Types.Covariant<Paths>;
12
+ };
13
+ 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>>
17
+ ] extends [never] ? unknown : never;
18
+ type PageParamNames<Page> = Page extends PageConcern<infer ParamNames, infer _Mode> ? ParamNames : never;
19
+ type PageMode<Page> = Page extends PageConcern<infer _ParamNames, infer Mode> ? Mode : never;
20
+ type ExactPageParamNames<Path extends AbsolutePath, Page> = [RouteParamNames<Path>] extends [
21
+ PageParamNames<Page>
22
+ ] ? [PageParamNames<Page>] extends [RouteParamNames<Path>] ? unknown : never : never;
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
+ type StaticMountPath<Path extends AbsolutePath> = [RouteParamNames<Path>] extends [never] ? unknown : never;
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>>;
30
+ }
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;
34
+ type RoutesPage<Services> = {
35
+ readonly page: AnyPageDefinition<Services>;
36
+ readonly path: AbsolutePath;
37
+ };
38
+ type RoutesMount<Services> = {
39
+ readonly path: AbsolutePath;
40
+ readonly routes: AnyRoutes<Services>;
41
+ };
42
+ export type RoutesImplementationState<Services> = {
43
+ readonly layout: LayoutComponent<Services> | null;
44
+ readonly loading: LoadingComponent<Services> | null;
45
+ readonly middleware: ReadonlyArray<AnyMiddleware<Services>>;
46
+ readonly mounts: ReadonlyArray<RoutesMount<Services>>;
47
+ readonly pages: ReadonlyArray<RoutesPage<Services>>;
48
+ readonly paths: ReadonlyArray<AbsolutePath>;
49
+ readonly scopeId: number;
50
+ };
51
+ type RoutesOptions<Services> = {
52
+ readonly layout?: LayoutComponent<Services>;
53
+ readonly loading?: LoadingComponent<Services>;
54
+ };
55
+ type HasLayoutFromOptions<Options> = Options extends {
56
+ readonly layout: unknown;
57
+ } ? true : false;
58
+ export declare const getRoutesState: <Services>(routes: AnyRoutes<Services>) => RoutesImplementationState<Services>;
59
+ export type RoutesFactory<Services> = {
60
+ readonly make: {
61
+ (): RoutesDefinition<Services, false, never>;
62
+ <Options extends RoutesOptions<Services>>(options: Options): RoutesDefinition<Services, HasLayoutFromOptions<Options>, never>;
63
+ };
64
+ };
65
+ export declare const makeRoutesFactory: <Services>(identity: ERSCIdentity<Services>, middleware: ReadonlyArray<AnyMiddleware<Services>>, allocateScopeId: () => number) => RoutesFactory<Services>;
66
+ export {};
@@ -0,0 +1,159 @@
1
+ import { ERSCIdentityTypeId, ERSCMemberKindTypeId, ERSCStateTypeId, getERSCIdentity, isERSCMember } from "./ersc-identity.js";
2
+ import { getPageState } from "./page.js";
3
+ import { analyzeRoutePath, joinRoutePaths } from "./route-path.js";
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ class RoutesDefinitionImpl {
12
+ [ERSCIdentityTypeId];
13
+ [ERSCMemberKindTypeId] = 'Routes';
14
+ get [ERSCStateTypeId]() {
15
+ return this;
16
+ }
17
+ layout;
18
+ loading;
19
+ middleware;
20
+ mounts;
21
+ pages;
22
+ paths;
23
+ scopeId;
24
+ #routeShapes;
25
+ constructor(identity, { layout, loading, middleware, mounts, pages, paths, routeShapes, scopeId }){
26
+ this[ERSCIdentityTypeId] = identity;
27
+ this.layout = layout;
28
+ this.loading = loading;
29
+ this.middleware = middleware;
30
+ this.mounts = mounts;
31
+ this.pages = pages;
32
+ this.paths = paths;
33
+ this.scopeId = scopeId;
34
+ this.#routeShapes = routeShapes;
35
+ Object.freeze(this);
36
+ }
37
+ page(path, page) {
38
+ const route = analyzeRoutePath(path);
39
+ if (this.#routeShapes.has(route.shape)) {
40
+ throw new TypeError(`Route "${path}" conflicts with an existing route pattern.`);
41
+ }
42
+ const pageState = getPageState(page);
43
+ if (getERSCIdentity(page) !== this[ERSCIdentityTypeId]) {
44
+ throw new TypeError(`Page for "${path}" was created by a different ERSC module.`);
45
+ }
46
+ if (route._tag === 'ParameterFree' && pageState.paramsSchema !== null) {
47
+ throw new TypeError(`Parameterized Page for "${path}" requires route parameters.`);
48
+ }
49
+ if (route._tag === 'Parameterized' && pageState.paramsSchema === null) {
50
+ throw new TypeError(`Page for "${path}" must declare a parameter Schema.`);
51
+ }
52
+ const routeShapes = new Set(this.#routeShapes);
53
+ routeShapes.add(route.shape);
54
+ return new RoutesDefinitionImpl(this[ERSCIdentityTypeId], {
55
+ layout: this.layout,
56
+ loading: this.loading,
57
+ middleware: this.middleware,
58
+ mounts: this.mounts,
59
+ pages: Object.freeze([
60
+ ...this.pages,
61
+ Object.freeze({
62
+ page,
63
+ path
64
+ })
65
+ ]),
66
+ paths: Object.freeze([
67
+ ...this.paths,
68
+ path
69
+ ]),
70
+ routeShapes,
71
+ scopeId: this.scopeId
72
+ });
73
+ }
74
+ mount(path, routes) {
75
+ const route = analyzeRoutePath(path);
76
+ if (route._tag === 'Parameterized') {
77
+ throw new TypeError(`Routes cannot be mounted beneath parameterized path "${path}".`);
78
+ }
79
+ const routesState = getRoutesState(routes);
80
+ if (routesState.paths.length === 0) {
81
+ throw new TypeError(`Cannot mount empty Routes at "${path}".`);
82
+ }
83
+ if (getERSCIdentity(routes) !== this[ERSCIdentityTypeId]) {
84
+ throw new TypeError(`Routes mounted at "${path}" were created by a different ERSC module.`);
85
+ }
86
+ const mountedPaths = routesState.paths.map((childPath)=>joinRoutePaths(path, childPath));
87
+ const routeShapes = new Set(this.#routeShapes);
88
+ for (const mountedPath of mountedPaths){
89
+ const shape = analyzeRoutePath(mountedPath).shape;
90
+ if (routeShapes.has(shape)) {
91
+ throw new TypeError(`Route "${mountedPath}" conflicts with an existing route pattern.`);
92
+ }
93
+ routeShapes.add(shape);
94
+ }
95
+ return new RoutesDefinitionImpl(this[ERSCIdentityTypeId], {
96
+ layout: this.layout,
97
+ loading: this.loading,
98
+ middleware: this.middleware,
99
+ mounts: Object.freeze([
100
+ ...this.mounts,
101
+ Object.freeze({
102
+ path,
103
+ routes
104
+ })
105
+ ]),
106
+ pages: this.pages,
107
+ paths: Object.freeze([
108
+ ...this.paths,
109
+ ...mountedPaths
110
+ ]),
111
+ routeShapes,
112
+ scopeId: this.scopeId
113
+ });
114
+ }
115
+ }
116
+ const getRoutesState = (routes)=>{
117
+ if (!isERSCMember(routes, 'Routes')) {
118
+ throw new TypeError('Routes must be created with ERSC.Routes.make.');
119
+ }
120
+ return routes[ERSCStateTypeId];
121
+ };
122
+ const makeRoutesFactory = (identity, middleware, allocateScopeId)=>{
123
+ function make(options = {}) {
124
+ if (options.layout !== undefined) {
125
+ if (!isERSCMember(options.layout, 'Layout')) {
126
+ throw new TypeError('Layout must be created with ERSC.Layout.make.');
127
+ }
128
+ if (getERSCIdentity(options.layout) !== identity) {
129
+ throw new TypeError('Layout was created by a different ERSC module.');
130
+ }
131
+ }
132
+ if (options.loading !== undefined) {
133
+ if (!isERSCMember(options.loading, 'Loading')) {
134
+ throw new TypeError('Loading must be created with ERSC.Loading.make.');
135
+ }
136
+ if (getERSCIdentity(options.loading) !== identity) {
137
+ throw new TypeError('Loading was created by a different ERSC module.');
138
+ }
139
+ }
140
+ const scopeId = allocateScopeId();
141
+ return new RoutesDefinitionImpl(identity, {
142
+ layout: options.layout ?? null,
143
+ loading: options.loading ?? null,
144
+ middleware,
145
+ mounts: Object.freeze([]),
146
+ pages: Object.freeze([]),
147
+ paths: Object.freeze([]),
148
+ routeShapes: new Set(),
149
+ scopeId
150
+ });
151
+ }
152
+ return {
153
+ make
154
+ };
155
+ };
156
+
157
+ export { getRoutesState, makeRoutesFactory };
158
+
159
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,30 @@
1
+ import { Effect, Schema } from 'effect';
2
+ import { type ERSCIdentity, type ERSCMember } from './ersc-identity.js';
3
+ import type { AnyMiddleware } from './middleware.js';
4
+ declare const ServerFnOperationError_base: Schema.Class<ServerFnOperationError, Schema.TaggedStruct<"ServerFnOperationError", {
5
+ readonly cause: Schema.Defect;
6
+ }>, import("effect/Cause").YieldableError>;
7
+ declare class ServerFnOperationError extends ServerFnOperationError_base {
8
+ }
9
+ type ServerFnInvocationMatch<ApplicationServices> = {
10
+ readonly _tag: 'Native';
11
+ } | {
12
+ readonly _tag: 'IdentityMismatch';
13
+ } | {
14
+ readonly _tag: 'Match';
15
+ readonly effect: Effect.Effect<unknown, ServerFnOperationError, ApplicationServices>;
16
+ readonly middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>;
17
+ };
18
+ interface ServerFunction<Input, Output, ApplicationServices> extends ERSCMember<ApplicationServices, 'ServerFn'> {
19
+ (input: Input): Promise<Output>;
20
+ }
21
+ type ServerFnOptions<InputSchema extends Schema.Constraint, Output, Error, Services> = {
22
+ readonly input: InputSchema;
23
+ readonly handler: (input: InputSchema['Type']) => Effect.Effect<Output, Error, Services>;
24
+ };
25
+ export type ServerFnFactory<ApplicationServices, AvailableServices> = {
26
+ readonly make: <InputSchema extends Schema.ConstraintDecoder<unknown, AvailableServices>, Output, Error>(options: ServerFnOptions<InputSchema, Output, Error, AvailableServices>) => ServerFunction<InputSchema['Encoded'], Output, ApplicationServices>;
27
+ };
28
+ export declare const matchServerFnInvocation: <ApplicationServices>(value: unknown, identity: ERSCIdentity<ApplicationServices>) => ServerFnInvocationMatch<ApplicationServices>;
29
+ export declare const makeServerFnFactory: <ApplicationServices, AvailableServices>(identity: ERSCIdentity<ApplicationServices>, middleware: ReadonlyArray<AnyMiddleware<ApplicationServices>>) => ServerFnFactory<ApplicationServices, AvailableServices>;
30
+ export {};
@@ -0,0 +1,58 @@
1
+ import { Effect, Predicate, Schema } from "effect";
2
+ import { attachERSCMember } from "./ersc-identity.js";
3
+
4
+
5
+
6
+
7
+
8
+ const ServerFnInvocationTypeId = Symbol.for('ersc/ServerFnInvocation');
9
+ class ServerFnOperationError extends Schema.TaggedError()('ServerFnOperationError', {
10
+ cause: Schema.Defect()
11
+ }) {
12
+ }
13
+ const directInvocationError = ()=>new TypeError('An ERSC ServerFn is a framework intrinsic and cannot be invoked directly in the server graph.');
14
+ const isServerFnInvocation = (value)=>Predicate.hasProperty(value, ServerFnInvocationTypeId);
15
+ const matchServerFnInvocation = (value, identity)=>{
16
+ if (!isServerFnInvocation(value)) {
17
+ return {
18
+ _tag: 'Native'
19
+ };
20
+ }
21
+ // The framework-owned brand proves the state shape; matching the opaque identity proves the
22
+ // application service universe erased by the native React invocation.
23
+ const metadata = value[ServerFnInvocationTypeId];
24
+ if (metadata.identity !== identity) {
25
+ return {
26
+ _tag: 'IdentityMismatch'
27
+ };
28
+ }
29
+ return {
30
+ _tag: 'Match',
31
+ effect: metadata.effect,
32
+ middleware: metadata.middleware
33
+ };
34
+ };
35
+ const makeServerFnFactory = (identity, middleware)=>({
36
+ make: ({ input, handler })=>{
37
+ const decode = Schema.decodeUnknownEffect(input);
38
+ const serverFunction = (untrustedInput)=>{
39
+ const effect = decode(untrustedInput).pipe(Effect.flatMap(handler), Effect.mapError((cause)=>new ServerFnOperationError({
40
+ cause
41
+ })));
42
+ const unavailable = Promise.reject(directInvocationError());
43
+ void unavailable.catch(()=>undefined);
44
+ return Object.assign(unavailable, {
45
+ [ServerFnInvocationTypeId]: Object.freeze({
46
+ effect,
47
+ identity,
48
+ middleware
49
+ })
50
+ });
51
+ };
52
+ return attachERSCMember(serverFunction, identity, 'ServerFn');
53
+ }
54
+ });
55
+
56
+ export { makeServerFnFactory, matchServerFnInvocation };
57
+
58
+ //# sourceMappingURL=server-fn.js.map