fibrae 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 (70) hide show
  1. package/dist/components.d.ts +40 -0
  2. package/dist/components.js +63 -0
  3. package/dist/components.js.map +1 -0
  4. package/dist/core.d.ts +25 -0
  5. package/dist/core.js +46 -0
  6. package/dist/core.js.map +1 -0
  7. package/dist/dom.d.ts +16 -0
  8. package/dist/dom.js +67 -0
  9. package/dist/dom.js.map +1 -0
  10. package/dist/fiber-render.d.ts +33 -0
  11. package/dist/fiber-render.js +1069 -0
  12. package/dist/fiber-render.js.map +1 -0
  13. package/dist/h.d.ts +19 -0
  14. package/dist/h.js +26 -0
  15. package/dist/h.js.map +1 -0
  16. package/dist/hydration.d.ts +30 -0
  17. package/dist/hydration.js +375 -0
  18. package/dist/hydration.js.map +1 -0
  19. package/dist/index.d.ts +26 -0
  20. package/dist/index.js +28 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/jsx-runtime/index.d.ts +29 -0
  23. package/dist/jsx-runtime/index.js +61 -0
  24. package/dist/jsx-runtime/index.js.map +1 -0
  25. package/dist/render.d.ts +19 -0
  26. package/dist/render.js +325 -0
  27. package/dist/render.js.map +1 -0
  28. package/dist/router/History.d.ts +129 -0
  29. package/dist/router/History.js +241 -0
  30. package/dist/router/History.js.map +1 -0
  31. package/dist/router/Link.d.ts +52 -0
  32. package/dist/router/Link.js +131 -0
  33. package/dist/router/Link.js.map +1 -0
  34. package/dist/router/Navigator.d.ts +108 -0
  35. package/dist/router/Navigator.js +225 -0
  36. package/dist/router/Navigator.js.map +1 -0
  37. package/dist/router/Route.d.ts +65 -0
  38. package/dist/router/Route.js +143 -0
  39. package/dist/router/Route.js.map +1 -0
  40. package/dist/router/Router.d.ts +167 -0
  41. package/dist/router/Router.js +328 -0
  42. package/dist/router/Router.js.map +1 -0
  43. package/dist/router/RouterBuilder.d.ts +128 -0
  44. package/dist/router/RouterBuilder.js +112 -0
  45. package/dist/router/RouterBuilder.js.map +1 -0
  46. package/dist/router/RouterOutlet.d.ts +57 -0
  47. package/dist/router/RouterOutlet.js +132 -0
  48. package/dist/router/RouterOutlet.js.map +1 -0
  49. package/dist/router/RouterState.d.ts +102 -0
  50. package/dist/router/RouterState.js +94 -0
  51. package/dist/router/RouterState.js.map +1 -0
  52. package/dist/router/index.d.ts +28 -0
  53. package/dist/router/index.js +31 -0
  54. package/dist/router/index.js.map +1 -0
  55. package/dist/runtime.d.ts +55 -0
  56. package/dist/runtime.js +68 -0
  57. package/dist/runtime.js.map +1 -0
  58. package/dist/scope-utils.d.ts +14 -0
  59. package/dist/scope-utils.js +29 -0
  60. package/dist/scope-utils.js.map +1 -0
  61. package/dist/server.d.ts +112 -0
  62. package/dist/server.js +313 -0
  63. package/dist/server.js.map +1 -0
  64. package/dist/shared.d.ts +136 -0
  65. package/dist/shared.js +53 -0
  66. package/dist/shared.js.map +1 -0
  67. package/dist/tracking.d.ts +23 -0
  68. package/dist/tracking.js +53 -0
  69. package/dist/tracking.js.map +1 -0
  70. package/package.json +62 -0
@@ -0,0 +1,132 @@
1
+ /**
2
+ * RouterOutlet - Reactive route rendering component.
3
+ *
4
+ * Subscribes to Navigator.currentRoute and renders the matched route's component.
5
+ * When route changes, runs the new route's loader and renders the component.
6
+ *
7
+ * For SSR hydration, the RouterStateAtom is pre-populated and the loader is skipped
8
+ * on first render.
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * function App() {
13
+ * return (
14
+ * <div>
15
+ * <Nav />
16
+ * <RouterOutlet />
17
+ * </div>
18
+ * );
19
+ * }
20
+ * ```
21
+ */
22
+ import * as Effect from "effect/Effect";
23
+ import * as Stream from "effect/Stream";
24
+ import * as Option from "effect/Option";
25
+ import { Registry as AtomRegistry } from "@effect-atom/atom";
26
+ import { Navigator } from "./Navigator.js";
27
+ import { RouterHandlers } from "./RouterBuilder.js";
28
+ import { RouterStateAtom } from "./RouterState.js";
29
+ // =============================================================================
30
+ // RouterOutlet Component
31
+ // =============================================================================
32
+ /**
33
+ * RouterOutlet component for reactive route rendering.
34
+ *
35
+ * The RouterOutlet:
36
+ * 1. Checks if RouterStateAtom has data (SSR hydration case)
37
+ * 2. Subscribes to Navigator.currentRoute for navigation changes
38
+ * 3. When route changes, runs the matched route's loader
39
+ * 4. Updates RouterStateAtom with the full state (for DI access)
40
+ * 5. Renders the route's component with loader data
41
+ *
42
+ * For SSR hydration, the RouterStateAtom is pre-populated by the server,
43
+ * so the first render uses that data and skips the loader.
44
+ */
45
+ export function RouterOutlet(_props = {}) {
46
+ // Track if this is the first render (for SSR hydration)
47
+ let isFirstRender = true;
48
+ return Stream.unwrap(Effect.gen(function* () {
49
+ const navigator = yield* Navigator;
50
+ const routerHandlers = yield* RouterHandlers;
51
+ const registry = yield* AtomRegistry.AtomRegistry;
52
+ // Check if we have hydrated state from SSR
53
+ const hydratedState = registry.get(RouterStateAtom);
54
+ // Create a stream from the currentRoute atom (navigation trigger)
55
+ const routeStream = AtomRegistry.toStream(registry, navigator.currentRoute);
56
+ // Map route changes to rendered VElements
57
+ return Stream.mapEffect(routeStream, (currentRoute) => Effect.gen(function* () {
58
+ if (Option.isNone(currentRoute)) {
59
+ // No route matched - clear router state and render 404
60
+ registry.set(RouterStateAtom, Option.none());
61
+ return {
62
+ type: "div",
63
+ props: {
64
+ children: [
65
+ {
66
+ type: "TEXT_ELEMENT",
67
+ props: { nodeValue: "404 - Not Found", children: [] },
68
+ },
69
+ ],
70
+ },
71
+ };
72
+ }
73
+ const { routeName, params, searchParams } = currentRoute.value;
74
+ // Get handler for this route
75
+ const handler = routerHandlers.getHandler(routeName);
76
+ if (Option.isNone(handler)) {
77
+ registry.set(RouterStateAtom, Option.none());
78
+ return {
79
+ type: "div",
80
+ props: {
81
+ children: [
82
+ {
83
+ type: "TEXT_ELEMENT",
84
+ props: {
85
+ nodeValue: `No handler for route: ${routeName}`,
86
+ children: [],
87
+ },
88
+ },
89
+ ],
90
+ },
91
+ };
92
+ }
93
+ let loaderData;
94
+ let routerState;
95
+ // Check if we should use hydrated SSR state
96
+ const shouldUseHydratedState = isFirstRender &&
97
+ Option.isSome(hydratedState) &&
98
+ hydratedState.value.routeName === routeName;
99
+ if (shouldUseHydratedState) {
100
+ // Use SSR-hydrated state
101
+ routerState = hydratedState.value;
102
+ loaderData = routerState.loaderData;
103
+ }
104
+ else {
105
+ // Run the loader
106
+ const loaderCtx = { path: params, searchParams };
107
+ loaderData = yield* handler.value.loader(loaderCtx);
108
+ // Build the new router state
109
+ routerState = {
110
+ routeName,
111
+ params,
112
+ searchParams,
113
+ loaderData,
114
+ };
115
+ // Update RouterStateAtom (for DI access by other components)
116
+ registry.set(RouterStateAtom, Option.some(routerState));
117
+ }
118
+ // Mark first render complete
119
+ isFirstRender = false;
120
+ // Render the component with both props patterns:
121
+ // 1. Traditional props (loaderData, path, searchParams)
122
+ // 2. Components can also access via RouterStateAtom/RouterStateService
123
+ const element = handler.value.component({
124
+ loaderData,
125
+ path: params,
126
+ searchParams,
127
+ });
128
+ return element;
129
+ }));
130
+ }));
131
+ }
132
+ //# sourceMappingURL=RouterOutlet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterOutlet.js","sourceRoot":"","sources":["../../src/router/RouterOutlet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * RouterState - Unified serializable state for the router.
3
+ *
4
+ * Contains everything needed to render the current route:
5
+ * - routeName: The matched route's name
6
+ * - params: Decoded path parameters
7
+ * - searchParams: Query string parameters
8
+ * - loaderData: Data returned by the route's loader
9
+ *
10
+ * This atom is:
11
+ * - Serializable for SSR hydration
12
+ * - Updated on navigation
13
+ * - Accessible via Effect DI
14
+ */
15
+ import * as Schema from "effect/Schema";
16
+ import * as Option from "effect/Option";
17
+ import * as Context from "effect/Context";
18
+ import * as Effect from "effect/Effect";
19
+ import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
20
+ /**
21
+ * Complete router state including loader data.
22
+ * This is what gets serialized for SSR and hydrated on client.
23
+ */
24
+ export interface RouterState {
25
+ readonly routeName: string;
26
+ readonly params: Record<string, unknown>;
27
+ readonly searchParams: Record<string, string>;
28
+ readonly loaderData: unknown;
29
+ }
30
+ /**
31
+ * Schema for RouterState - used for serialization.
32
+ *
33
+ * Note: loaderData uses Schema.Unknown since the actual type
34
+ * is inferred from the loader Effect return type.
35
+ */
36
+ export declare const RouterStateSchema: Schema.Struct<{
37
+ routeName: typeof Schema.String;
38
+ params: Schema.Record$<typeof Schema.String, typeof Schema.Unknown>;
39
+ searchParams: Schema.Record$<typeof Schema.String, typeof Schema.String>;
40
+ loaderData: typeof Schema.Unknown;
41
+ }>;
42
+ /**
43
+ * The router state atom - a serializable atom containing the full route state.
44
+ *
45
+ * When None, no route is matched.
46
+ * When Some, contains the matched route info and loader data.
47
+ *
48
+ * This atom is automatically:
49
+ * - Dehydrated during SSR (included in __FIBRAE_STATE__)
50
+ * - Hydrated on client (restored from __FIBRAE_STATE__)
51
+ */
52
+ export declare const RouterStateAtom: Atom.Writable<Option.Option<RouterState>, Option.Option<RouterState>> & Atom.Serializable<Schema.Option<Schema.Struct<{
53
+ routeName: typeof Schema.String;
54
+ params: Schema.Record$<typeof Schema.String, typeof Schema.Unknown>;
55
+ searchParams: Schema.Record$<typeof Schema.String, typeof Schema.String>;
56
+ loaderData: typeof Schema.Unknown;
57
+ }>>>;
58
+ declare const RouterStateService_base: Context.TagClass<RouterStateService, "@fibrae/router/RouterStateService", {
59
+ /**
60
+ * Get the current router state.
61
+ */
62
+ readonly get: Effect.Effect<Option.Option<RouterState>, never, AtomRegistry.AtomRegistry>;
63
+ /**
64
+ * Set the router state (used internally by Navigator).
65
+ */
66
+ readonly set: (state: Option.Option<RouterState>) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>;
67
+ /**
68
+ * The underlying atom (for reactive subscriptions).
69
+ */
70
+ readonly atom: Atom.Writable<Option.Option<RouterState>, Option.Option<RouterState>>;
71
+ }>;
72
+ /**
73
+ * Service tag for accessing router state via Effect DI.
74
+ *
75
+ * Usage in components:
76
+ * ```typescript
77
+ * const Component = () => Effect.gen(function* () {
78
+ * const state = yield* RouterStateService;
79
+ * if (Option.isSome(state)) {
80
+ * const { loaderData, params } = state.value;
81
+ * // ...
82
+ * }
83
+ * });
84
+ * ```
85
+ */
86
+ export declare class RouterStateService extends RouterStateService_base {
87
+ }
88
+ /**
89
+ * Get the current router state.
90
+ */
91
+ export declare const getRouterState: Effect.Effect<Option.Option<RouterState>, never, RouterStateService | AtomRegistry.AtomRegistry>;
92
+ /**
93
+ * Get the current loader data (typed by the caller).
94
+ * Returns None if no route is matched.
95
+ */
96
+ export declare const getLoaderData: <T>() => Effect.Effect<Option.Option<T>, never, RouterStateService | AtomRegistry.AtomRegistry>;
97
+ /**
98
+ * Get the current route params.
99
+ * Returns None if no route is matched.
100
+ */
101
+ export declare const getRouteParams: Effect.Effect<Option.Option<Record<string, unknown>>, never, RouterStateService | AtomRegistry.AtomRegistry>;
102
+ export {};
@@ -0,0 +1,94 @@
1
+ /**
2
+ * RouterState - Unified serializable state for the router.
3
+ *
4
+ * Contains everything needed to render the current route:
5
+ * - routeName: The matched route's name
6
+ * - params: Decoded path parameters
7
+ * - searchParams: Query string parameters
8
+ * - loaderData: Data returned by the route's loader
9
+ *
10
+ * This atom is:
11
+ * - Serializable for SSR hydration
12
+ * - Updated on navigation
13
+ * - Accessible via Effect DI
14
+ */
15
+ import * as Schema from "effect/Schema";
16
+ import * as Option from "effect/Option";
17
+ import * as Context from "effect/Context";
18
+ import * as Effect from "effect/Effect";
19
+ import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
20
+ /**
21
+ * Schema for RouterState - used for serialization.
22
+ *
23
+ * Note: loaderData uses Schema.Unknown since the actual type
24
+ * is inferred from the loader Effect return type.
25
+ */
26
+ export const RouterStateSchema = Schema.Struct({
27
+ routeName: Schema.String,
28
+ params: Schema.Record({ key: Schema.String, value: Schema.Unknown }),
29
+ searchParams: Schema.Record({ key: Schema.String, value: Schema.String }),
30
+ loaderData: Schema.Unknown,
31
+ });
32
+ // =============================================================================
33
+ // Serializable Atom
34
+ // =============================================================================
35
+ /**
36
+ * The router state atom - a serializable atom containing the full route state.
37
+ *
38
+ * When None, no route is matched.
39
+ * When Some, contains the matched route info and loader data.
40
+ *
41
+ * This atom is automatically:
42
+ * - Dehydrated during SSR (included in __FIBRAE_STATE__)
43
+ * - Hydrated on client (restored from __FIBRAE_STATE__)
44
+ */
45
+ export const RouterStateAtom = Atom.make(Option.none()).pipe(Atom.serializable({
46
+ key: "@fibrae/router/state",
47
+ schema: Schema.Option(RouterStateSchema),
48
+ }));
49
+ // =============================================================================
50
+ // Service Tag
51
+ // =============================================================================
52
+ /**
53
+ * Service tag for accessing router state via Effect DI.
54
+ *
55
+ * Usage in components:
56
+ * ```typescript
57
+ * const Component = () => Effect.gen(function* () {
58
+ * const state = yield* RouterStateService;
59
+ * if (Option.isSome(state)) {
60
+ * const { loaderData, params } = state.value;
61
+ * // ...
62
+ * }
63
+ * });
64
+ * ```
65
+ */
66
+ export class RouterStateService extends Context.Tag("@fibrae/router/RouterStateService")() {
67
+ }
68
+ // =============================================================================
69
+ // Convenience Accessors
70
+ // =============================================================================
71
+ /**
72
+ * Get the current router state.
73
+ */
74
+ export const getRouterState = Effect.gen(function* () {
75
+ const service = yield* RouterStateService;
76
+ return yield* service.get;
77
+ });
78
+ /**
79
+ * Get the current loader data (typed by the caller).
80
+ * Returns None if no route is matched.
81
+ */
82
+ export const getLoaderData = () => Effect.gen(function* () {
83
+ const state = yield* getRouterState;
84
+ return Option.map(state, (s) => s.loaderData);
85
+ });
86
+ /**
87
+ * Get the current route params.
88
+ * Returns None if no route is matched.
89
+ */
90
+ export const getRouteParams = Effect.gen(function* () {
91
+ const state = yield* getRouterState;
92
+ return Option.map(state, (s) => s.params);
93
+ });
94
+ //# sourceMappingURL=RouterState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterState.js","sourceRoot":"","sources":["../../src/router/RouterState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAiBnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACpE,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACzE,UAAU,EAAE,MAAM,CAAC,OAAO;CAC3B,CAAC,CAAC;AAEH,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CACtC,MAAM,CAAC,IAAI,EAAE,CACd,CAAC,IAAI,CACJ,IAAI,CAAC,YAAY,CAAC;IAChB,GAAG,EAAE,sBAAsB;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC;CACzC,CAAC,CACH,CAAC;AAEF,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,kBAAmB,SAAQ,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,EAkBrF;CAAG;AAEN,gFAAgF;AAChF,wBAAwB;AACxB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAIvB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC;IAC1C,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAI3B,EAAE,CACF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC;IACpC,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAe,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEL;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAIvB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC;IACpC,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Router module exports.
3
+ *
4
+ * Provides Effect-first routing with the HttpApi pattern:
5
+ * - Route declarations with schema-validated params
6
+ * - RouterBuilder for handler implementation
7
+ * - History service for navigation
8
+ * - Type-safe navigation
9
+ */
10
+ export * as Route from "./Route.js";
11
+ export * as Router from "./Router.js";
12
+ export * as RouterBuilder from "./RouterBuilder.js";
13
+ export * as History from "./History.js";
14
+ export * as Navigator from "./Navigator.js";
15
+ export * as RouterState from "./RouterState.js";
16
+ export type { LoaderContext, ComponentProps, HandlerConfig, RouteHandler, GroupHandlers, } from "./RouterBuilder.js";
17
+ export { RouterHandlers } from "./RouterBuilder.js";
18
+ export type { HistoryLocation, HistoryService } from "./History.js";
19
+ export { History as HistoryTag, BrowserHistoryLive, MemoryHistoryLive } from "./History.js";
20
+ export type { CurrentRoute, NavigateOptions, NavigatorService } from "./Navigator.js";
21
+ export { Navigator as NavigatorTag, NavigatorLive } from "./Navigator.js";
22
+ export type { LinkProps } from "./Link.js";
23
+ export { createLink } from "./Link.js";
24
+ export type { RouterOutletProps } from "./RouterOutlet.js";
25
+ export { RouterOutlet } from "./RouterOutlet.js";
26
+ export type { ServerLayerOptions, BrowserLayerOptions, DehydratedRouterState, SSRRouteResult, } from "./Router.js";
27
+ export { CurrentRouteElement } from "./Router.js";
28
+ export { RouterStateAtom, RouterStateService, RouterStateSchema, getRouterState, getLoaderData, getRouteParams, } from "./RouterState.js";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Router module exports.
3
+ *
4
+ * Provides Effect-first routing with the HttpApi pattern:
5
+ * - Route declarations with schema-validated params
6
+ * - RouterBuilder for handler implementation
7
+ * - History service for navigation
8
+ * - Type-safe navigation
9
+ */
10
+ // Route declaration
11
+ export * as Route from "./Route.js";
12
+ // Router and groups
13
+ export * as Router from "./Router.js";
14
+ // Handler implementation
15
+ export * as RouterBuilder from "./RouterBuilder.js";
16
+ // History service
17
+ export * as History from "./History.js";
18
+ // Navigator service
19
+ export * as Navigator from "./Navigator.js";
20
+ // Router state (unified serializable state)
21
+ export * as RouterState from "./RouterState.js";
22
+ export { RouterHandlers } from "./RouterBuilder.js";
23
+ export { History as HistoryTag, BrowserHistoryLive, MemoryHistoryLive } from "./History.js";
24
+ export { Navigator as NavigatorTag, NavigatorLive } from "./Navigator.js";
25
+ export { createLink } from "./Link.js";
26
+ export { RouterOutlet } from "./RouterOutlet.js";
27
+ export { CurrentRouteElement } from "./Router.js";
28
+ // Re-export RouterState utilities for convenience
29
+ // (RouterState type is accessible via RouterState.RouterState namespace)
30
+ export { RouterStateAtom, RouterStateService, RouterStateSchema, getRouterState, getLoaderData, getRouteParams, } from "./RouterState.js";
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oBAAoB;AACpB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC,oBAAoB;AACpB,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,yBAAyB;AACzB,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AAEpD,kBAAkB;AAClB,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC,oBAAoB;AACpB,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C,4CAA4C;AAC5C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAWhD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAI5F,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI1E,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AASjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,kDAAkD;AAClD,yEAAyE;AACzE,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,GACf,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,55 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Scope from "effect/Scope";
3
+ import * as Layer from "effect/Layer";
4
+ import * as Ref from "effect/Ref";
5
+ import * as Option from "effect/Option";
6
+ import * as Context from "effect/Context";
7
+ import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
8
+ import type { Fiber } from "./shared.js";
9
+ export interface FiberState {
10
+ currentRoot: Option.Option<Fiber>;
11
+ wipRoot: Option.Option<Fiber>;
12
+ nextUnitOfWork: Option.Option<Fiber>;
13
+ deletions: Fiber[];
14
+ renderQueue: Set<Fiber>;
15
+ batchScheduled: boolean;
16
+ listenerStore: WeakMap<HTMLElement, Record<string, EventListener>>;
17
+ }
18
+ export declare const makeFiberState: () => FiberState;
19
+ export declare const CustomAtomRegistryLayer: Layer.Layer<AtomRegistry.AtomRegistry, never, never>;
20
+ declare const FibraeRuntime_base: Effect.Service.Class<FibraeRuntime, "FibraeRuntime", {
21
+ readonly accessors: true;
22
+ readonly dependencies: readonly [Layer.Layer<AtomRegistry.AtomRegistry, never, never>];
23
+ readonly scoped: Effect.Effect<{
24
+ registry: AtomRegistry.Registry;
25
+ rootScope: Scope.CloseableScope;
26
+ runFork: <XE extends unknown, XA extends unknown>(effect: Effect.Effect<XA, XE, AtomRegistry.AtomRegistry>, options?: import("effect/Runtime").RunForkOptions | undefined) => import("effect/Fiber").RuntimeFiber<XA, XE>;
27
+ AtomOps: {
28
+ get: <A>(atom: Atom.Atom<A>) => A;
29
+ set: <R, W>(atom: Atom.Writable<R, W>, value: W) => void;
30
+ update: <R, W>(atom: Atom.Writable<R, W>, f: (_: R) => W) => void;
31
+ modify: <R, W, A>(atom: Atom.Writable<R, W>, f: (_: R) => [returnValue: A, nextValue: W]) => A;
32
+ };
33
+ fiberState: Ref.Ref<FiberState>;
34
+ fullContextRef: Ref.Ref<Context.Context<unknown>>;
35
+ }, never, Scope.Scope | AtomRegistry.AtomRegistry>;
36
+ }>;
37
+ export declare class FibraeRuntime extends FibraeRuntime_base {
38
+ static Live: Layer.Layer<FibraeRuntime, never, never>;
39
+ /**
40
+ * Layer that provides both FibraeRuntime AND AtomRegistry.
41
+ * Use this when composing with user layers that need AtomRegistry access.
42
+ * (FibraeRuntime.Default consumes AtomRegistry internally but doesn't re-export it)
43
+ */
44
+ static LiveWithRegistry: Layer.Layer<AtomRegistry.AtomRegistry | FibraeRuntime, never, never>;
45
+ }
46
+ /**
47
+ * Fork an effect with the full application context.
48
+ *
49
+ * The fullContextRef contains ALL services (FibraeRuntime, AtomRegistry, Navigator, etc.)
50
+ * captured at render() time after all layers are built.
51
+ *
52
+ * IMPORTANT: fullContextRef must be set by render() before this is called.
53
+ */
54
+ export declare const runForkWithRuntime: (runtime: FibraeRuntime) => <A, E>(effect: Effect.Effect<A, E, unknown>) => import("effect/Fiber").RuntimeFiber<unknown, unknown>;
55
+ export {};
@@ -0,0 +1,68 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Scope from "effect/Scope";
3
+ import * as FiberSet from "effect/FiberSet";
4
+ import * as Layer from "effect/Layer";
5
+ import * as Ref from "effect/Ref";
6
+ import * as Option from "effect/Option";
7
+ import * as Context from "effect/Context";
8
+ import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
9
+ export const makeFiberState = () => ({
10
+ currentRoot: Option.none(),
11
+ wipRoot: Option.none(),
12
+ nextUnitOfWork: Option.none(),
13
+ deletions: [],
14
+ renderQueue: new Set(),
15
+ batchScheduled: false,
16
+ listenerStore: new WeakMap(),
17
+ });
18
+ // =============================================================================
19
+ // Runtime Service
20
+ // =============================================================================
21
+ export const CustomAtomRegistryLayer = AtomRegistry.layerOptions({
22
+ scheduleTask: (f) => f()
23
+ });
24
+ export class FibraeRuntime extends Effect.Service()("FibraeRuntime", {
25
+ accessors: true,
26
+ dependencies: [CustomAtomRegistryLayer],
27
+ scoped: Effect.gen(function* () {
28
+ const registry = yield* AtomRegistry.AtomRegistry;
29
+ const rootScope = yield* Scope.make();
30
+ const runFork = yield* FiberSet.makeRuntime();
31
+ // Store the full context in a Ref so it can be updated after all layers are built
32
+ // Initially empty - will be set by render() after user layers are applied
33
+ const fullContextRef = yield* Ref.make(Context.empty());
34
+ // Each render tree gets its own fiber state
35
+ const fiberState = yield* Ref.make(makeFiberState());
36
+ const AtomOps = {
37
+ get: (atom) => registry.get(atom),
38
+ set: (atom, value) => registry.set(atom, value),
39
+ update: (atom, f) => registry.update(atom, f),
40
+ modify: (atom, f) => registry.modify(atom, f),
41
+ };
42
+ return { registry, rootScope, runFork, AtomOps, fiberState, fullContextRef };
43
+ }),
44
+ }) {
45
+ static Live = FibraeRuntime.Default;
46
+ /**
47
+ * Layer that provides both FibraeRuntime AND AtomRegistry.
48
+ * Use this when composing with user layers that need AtomRegistry access.
49
+ * (FibraeRuntime.Default consumes AtomRegistry internally but doesn't re-export it)
50
+ */
51
+ static LiveWithRegistry = Layer.merge(FibraeRuntime.Default, CustomAtomRegistryLayer);
52
+ }
53
+ /**
54
+ * Fork an effect with the full application context.
55
+ *
56
+ * The fullContextRef contains ALL services (FibraeRuntime, AtomRegistry, Navigator, etc.)
57
+ * captured at render() time after all layers are built.
58
+ *
59
+ * IMPORTANT: fullContextRef must be set by render() before this is called.
60
+ */
61
+ export const runForkWithRuntime = (runtime) => (effect) => {
62
+ const withContext = Effect.gen(function* () {
63
+ const fullContext = yield* Ref.get(runtime.fullContextRef);
64
+ return yield* Effect.provide(effect, fullContext);
65
+ });
66
+ return runtime.runFork(withContext);
67
+ };
68
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Scope from "effect/Scope";
3
+ import * as Ref from "effect/Ref";
4
+ /**
5
+ * Clear content by closing the current scope in the Ref and creating a fresh one.
6
+ * This triggers finalizers that remove DOM nodes and cancel subscriptions.
7
+ * Returns the new scope for convenience.
8
+ */
9
+ export declare const clearContentScope: (contentScopeRef: Ref.Ref<Scope.Scope.Closeable>) => Effect.Effect<Scope.Scope.Closeable, never, never>;
10
+ /**
11
+ * Register a DOM node for cleanup when scope closes.
12
+ * Removes the node from its parent when the scope is closed.
13
+ */
14
+ export declare const registerNodeCleanup: (node: Node, scope: Scope.Scope.Closeable) => Effect.Effect<void, never, never>;
@@ -0,0 +1,29 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Scope from "effect/Scope";
3
+ import * as Exit from "effect/Exit";
4
+ import * as Ref from "effect/Ref";
5
+ // =============================================================================
6
+ // Scope Utilities
7
+ // =============================================================================
8
+ /**
9
+ * Clear content by closing the current scope in the Ref and creating a fresh one.
10
+ * This triggers finalizers that remove DOM nodes and cancel subscriptions.
11
+ * Returns the new scope for convenience.
12
+ */
13
+ export const clearContentScope = (contentScopeRef) => Effect.gen(function* () {
14
+ const oldScope = yield* Ref.get(contentScopeRef);
15
+ yield* Scope.close(oldScope, Exit.void);
16
+ const newScope = yield* Scope.make();
17
+ yield* Ref.set(contentScopeRef, newScope);
18
+ return newScope;
19
+ });
20
+ /**
21
+ * Register a DOM node for cleanup when scope closes.
22
+ * Removes the node from its parent when the scope is closed.
23
+ */
24
+ export const registerNodeCleanup = (node, scope) => Scope.addFinalizer(scope, Effect.sync(() => {
25
+ if (node.parentNode) {
26
+ node.parentNode.removeChild(node);
27
+ }
28
+ }));
29
+ //# sourceMappingURL=scope-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-utils.js","sourceRoot":"","sources":["../src/scope-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAElC,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,eAA+C,EACK,EAAE,CACtD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjD,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACrC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC1C,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,IAAU,EACV,KAA4B,EACO,EAAE,CACrC,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;IACzC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;AACH,CAAC,CAAC,CAAC,CAAC"}