@rikalabs/effect-react 0.0.1

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 (167) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +179 -0
  3. package/dist/actions/http.d.ts +18 -0
  4. package/dist/actions/index.d.ts +4 -0
  5. package/dist/actions/react.d.ts +7 -0
  6. package/dist/actions/service.d.ts +18 -0
  7. package/dist/actions/types.d.ts +33 -0
  8. package/dist/boundary/codecs.d.ts +40 -0
  9. package/dist/boundary/errors.d.ts +22 -0
  10. package/dist/boundary/index.d.ts +2 -0
  11. package/dist/chunk-2GIUCKL2.js +16 -0
  12. package/dist/chunk-2GIUCKL2.js.map +1 -0
  13. package/dist/chunk-2TG7YEVD.js +11 -0
  14. package/dist/chunk-2TG7YEVD.js.map +1 -0
  15. package/dist/chunk-6FI4ROTW.js +152 -0
  16. package/dist/chunk-6FI4ROTW.js.map +1 -0
  17. package/dist/chunk-C5JI7D7W.js +213 -0
  18. package/dist/chunk-C5JI7D7W.js.map +1 -0
  19. package/dist/chunk-EEYASTXR.js +99 -0
  20. package/dist/chunk-EEYASTXR.js.map +1 -0
  21. package/dist/chunk-H7MOLKTU.js +301 -0
  22. package/dist/chunk-H7MOLKTU.js.map +1 -0
  23. package/dist/chunk-IVIYY6S5.js +77 -0
  24. package/dist/chunk-IVIYY6S5.js.map +1 -0
  25. package/dist/chunk-JKN75OYC.js +87 -0
  26. package/dist/chunk-JKN75OYC.js.map +1 -0
  27. package/dist/chunk-M2CJG6T7.js +24 -0
  28. package/dist/chunk-M2CJG6T7.js.map +1 -0
  29. package/dist/chunk-MDGEGQZB.js +206 -0
  30. package/dist/chunk-MDGEGQZB.js.map +1 -0
  31. package/dist/chunk-NI2GNZ7S.js +78 -0
  32. package/dist/chunk-NI2GNZ7S.js.map +1 -0
  33. package/dist/chunk-O7XTA7H3.js +423 -0
  34. package/dist/chunk-O7XTA7H3.js.map +1 -0
  35. package/dist/chunk-S67FHWAR.js +88 -0
  36. package/dist/chunk-S67FHWAR.js.map +1 -0
  37. package/dist/chunk-SKC3HMF3.js +17 -0
  38. package/dist/chunk-SKC3HMF3.js.map +1 -0
  39. package/dist/chunk-TUJZ6XJY.js +127 -0
  40. package/dist/chunk-TUJZ6XJY.js.map +1 -0
  41. package/dist/chunk-WPV3WFMS.js +38 -0
  42. package/dist/chunk-WPV3WFMS.js.map +1 -0
  43. package/dist/chunk-XIBEKS5A.js +301 -0
  44. package/dist/chunk-XIBEKS5A.js.map +1 -0
  45. package/dist/chunk-YG22YP5K.js +68 -0
  46. package/dist/chunk-YG22YP5K.js.map +1 -0
  47. package/dist/chunk-ZMZQBREU.js +262 -0
  48. package/dist/chunk-ZMZQBREU.js.map +1 -0
  49. package/dist/client/index.cjs +191 -0
  50. package/dist/client/index.cjs.map +1 -0
  51. package/dist/client/index.d.ts +8 -0
  52. package/dist/client/index.js +14 -0
  53. package/dist/client/index.js.map +1 -0
  54. package/dist/config/index.cjs +63 -0
  55. package/dist/config/index.cjs.map +1 -0
  56. package/dist/config/index.d.ts +32 -0
  57. package/dist/config/index.js +9 -0
  58. package/dist/config/index.js.map +1 -0
  59. package/dist/data/index.d.ts +3 -0
  60. package/dist/data/react.d.ts +10 -0
  61. package/dist/data/service.d.ts +20 -0
  62. package/dist/data/types.d.ts +31 -0
  63. package/dist/devtools/events.d.ts +37 -0
  64. package/dist/devtools/index.cjs +149 -0
  65. package/dist/devtools/index.cjs.map +1 -0
  66. package/dist/devtools/index.d.ts +2 -0
  67. package/dist/devtools/index.js +18 -0
  68. package/dist/devtools/index.js.map +1 -0
  69. package/dist/devtools/react.d.ts +8 -0
  70. package/dist/form/index.cjs +301 -0
  71. package/dist/form/index.cjs.map +1 -0
  72. package/dist/form/index.d.ts +3 -0
  73. package/dist/form/index.js +14 -0
  74. package/dist/form/index.js.map +1 -0
  75. package/dist/form/react.d.ts +9 -0
  76. package/dist/form/service.d.ts +3 -0
  77. package/dist/form/types.d.ts +41 -0
  78. package/dist/framework/app.d.ts +21 -0
  79. package/dist/framework/cache.d.ts +10 -0
  80. package/dist/framework/contracts.d.ts +32 -0
  81. package/dist/framework/index.cjs +1006 -0
  82. package/dist/framework/index.cjs.map +1 -0
  83. package/dist/framework/index.d.ts +4 -0
  84. package/dist/framework/index.js +35 -0
  85. package/dist/framework/index.js.map +1 -0
  86. package/dist/framework/manifest.d.ts +12 -0
  87. package/dist/framework/vite.d.ts +13 -0
  88. package/dist/framework-vite/index.cjs +163 -0
  89. package/dist/framework-vite/index.cjs.map +1 -0
  90. package/dist/framework-vite/index.d.ts +1 -0
  91. package/dist/framework-vite/index.js +125 -0
  92. package/dist/framework-vite/index.js.map +1 -0
  93. package/dist/grid/grid.d.ts +8 -0
  94. package/dist/grid/index.cjs +238 -0
  95. package/dist/grid/index.cjs.map +1 -0
  96. package/dist/grid/index.d.ts +2 -0
  97. package/dist/grid/index.js +19 -0
  98. package/dist/grid/index.js.map +1 -0
  99. package/dist/grid/types.d.ts +35 -0
  100. package/dist/index.cjs +2512 -0
  101. package/dist/index.cjs.map +1 -0
  102. package/dist/index.d.ts +13 -0
  103. package/dist/index.js +207 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/kernel/app.d.ts +26 -0
  106. package/dist/kernel/index.d.ts +3 -0
  107. package/dist/kernel/runtime.d.ts +5 -0
  108. package/dist/kernel/telemetry.d.ts +37 -0
  109. package/dist/navigation/index.d.ts +4 -0
  110. package/dist/navigation/matcher.d.ts +13 -0
  111. package/dist/navigation/react.d.ts +12 -0
  112. package/dist/navigation/service.d.ts +23 -0
  113. package/dist/navigation/types.d.ts +65 -0
  114. package/dist/query/index.cjs +361 -0
  115. package/dist/query/index.cjs.map +1 -0
  116. package/dist/query/index.d.ts +3 -0
  117. package/dist/query/index.js +30 -0
  118. package/dist/query/index.js.map +1 -0
  119. package/dist/query/react.d.ts +27 -0
  120. package/dist/query/service.d.ts +10 -0
  121. package/dist/query/types.d.ts +5 -0
  122. package/dist/react/index.d.ts +1 -0
  123. package/dist/react/provider.d.ts +10 -0
  124. package/dist/realtime/channel.d.ts +15 -0
  125. package/dist/realtime/index.cjs +117 -0
  126. package/dist/realtime/index.cjs.map +1 -0
  127. package/dist/realtime/index.d.ts +2 -0
  128. package/dist/realtime/index.js +15 -0
  129. package/dist/realtime/index.js.map +1 -0
  130. package/dist/realtime/presence.d.ts +22 -0
  131. package/dist/render/hydration.d.ts +24 -0
  132. package/dist/render/index.d.ts +2 -0
  133. package/dist/render/ssr.d.ts +13 -0
  134. package/dist/router/helpers.d.ts +26 -0
  135. package/dist/router/index.cjs +236 -0
  136. package/dist/router/index.cjs.map +1 -0
  137. package/dist/router/index.d.ts +4 -0
  138. package/dist/router/index.js +40 -0
  139. package/dist/router/index.js.map +1 -0
  140. package/dist/router/react.d.ts +5 -0
  141. package/dist/router/service.d.ts +5 -0
  142. package/dist/router/types.d.ts +1 -0
  143. package/dist/server/index.cjs +174 -0
  144. package/dist/server/index.cjs.map +1 -0
  145. package/dist/server/index.d.ts +16 -0
  146. package/dist/server/index.js +12 -0
  147. package/dist/server/index.js.map +1 -0
  148. package/dist/state/index.cjs +128 -0
  149. package/dist/state/index.cjs.map +1 -0
  150. package/dist/state/index.d.ts +2 -0
  151. package/dist/state/index.js +36 -0
  152. package/dist/state/index.js.map +1 -0
  153. package/dist/state/react.d.ts +3 -0
  154. package/dist/state/service.d.ts +28 -0
  155. package/dist/testing/index.cjs +970 -0
  156. package/dist/testing/index.cjs.map +1 -0
  157. package/dist/testing/index.d.ts +2 -0
  158. package/dist/testing/index.js +13 -0
  159. package/dist/testing/index.js.map +1 -0
  160. package/dist/virtual/index.cjs +160 -0
  161. package/dist/virtual/index.cjs.map +1 -0
  162. package/dist/virtual/index.d.ts +2 -0
  163. package/dist/virtual/index.js +21 -0
  164. package/dist/virtual/index.js.map +1 -0
  165. package/dist/virtual/types.d.ts +25 -0
  166. package/dist/virtual/virtual.d.ts +9 -0
  167. package/package.json +156 -0
@@ -0,0 +1,213 @@
1
+ import {
2
+ Boundary
3
+ } from "./chunk-YG22YP5K.js";
4
+ import {
5
+ Telemetry
6
+ } from "./chunk-SKC3HMF3.js";
7
+
8
+ // src/data/types.ts
9
+ var defineQuery = (definition) => definition;
10
+ var QueryRuntimeError = class extends Error {
11
+ constructor(messageText) {
12
+ super(messageText);
13
+ this.messageText = messageText;
14
+ this.name = "QueryRuntimeError";
15
+ }
16
+ _tag = "QueryRuntimeError";
17
+ };
18
+
19
+ // src/data/service.ts
20
+ import {
21
+ Cache,
22
+ Context,
23
+ Effect,
24
+ Layer,
25
+ SubscriptionRef
26
+ } from "effect";
27
+ var defaultRuntimeOptions = {
28
+ capacity: 2048,
29
+ timeToLive: "5 minutes"
30
+ };
31
+ var stableStringify = (value) => {
32
+ if (value === null || value === void 0) {
33
+ return String(value);
34
+ }
35
+ if (typeof value !== "object") {
36
+ return JSON.stringify(value);
37
+ }
38
+ if (Array.isArray(value)) {
39
+ return `[${value.map(stableStringify).join(",")}]`;
40
+ }
41
+ const entries = Object.entries(value).sort(
42
+ ([a], [b]) => a.localeCompare(b)
43
+ );
44
+ return `{${entries.map(([key, nested]) => `${JSON.stringify(key)}:${stableStringify(nested)}`).join(",")}}`;
45
+ };
46
+ var initialSnapshot = (key) => ({
47
+ key,
48
+ phase: "initial",
49
+ data: void 0,
50
+ error: void 0,
51
+ updatedAt: null
52
+ });
53
+ var Data = class extends Context.Tag("EffectReact/Data")() {
54
+ };
55
+ var makeDataLayer = (options = {}) => {
56
+ const merged = {
57
+ ...defaultRuntimeOptions,
58
+ ...options
59
+ };
60
+ return Layer.effect(
61
+ Data,
62
+ Effect.gen(function* () {
63
+ const boundary = yield* Boundary;
64
+ const telemetry = yield* Telemetry;
65
+ const lookups = /* @__PURE__ */ new Map();
66
+ const snapshots = yield* SubscriptionRef.make(
67
+ /* @__PURE__ */ new Map()
68
+ );
69
+ const cache = yield* Cache.make({
70
+ capacity: merged.capacity,
71
+ timeToLive: merged.timeToLive,
72
+ lookup: (key) => Effect.suspend(() => {
73
+ const lookup = lookups.get(key);
74
+ if (lookup === void 0) {
75
+ return Effect.fail(new QueryRuntimeError(`No query executor registered for ${key}`));
76
+ }
77
+ return lookup;
78
+ })
79
+ });
80
+ const setSnapshot = (key, update) => SubscriptionRef.update(snapshots, (current) => {
81
+ const next = new Map(current);
82
+ const previous = next.get(key) ?? initialSnapshot(key);
83
+ next.set(key, update(previous));
84
+ return next;
85
+ }).pipe(Effect.asVoid);
86
+ const buildKey = (definition, input) => {
87
+ const base = definition.key ? definition.key(input) : input;
88
+ return `${definition.name}:${stableStringify(base)}`;
89
+ };
90
+ const fetch = (definition, input, runOptions) => Effect.gen(function* () {
91
+ const decodedInput = yield* boundary.decodeUnknown({
92
+ source: `query:${definition.name}:input`,
93
+ schema: definition.input,
94
+ value: input
95
+ });
96
+ const key = buildKey(definition, decodedInput);
97
+ yield* telemetry.emit({
98
+ _tag: "query",
99
+ phase: "start",
100
+ key,
101
+ timestamp: Date.now()
102
+ });
103
+ yield* setSnapshot(key, (previous) => ({
104
+ ...previous,
105
+ phase: "loading",
106
+ error: void 0
107
+ }));
108
+ lookups.set(
109
+ key,
110
+ definition.run(decodedInput).pipe(
111
+ Effect.flatMap(
112
+ (output) => boundary.decodeUnknown({
113
+ source: `query:${definition.name}:output`,
114
+ schema: definition.output,
115
+ value: output
116
+ })
117
+ )
118
+ )
119
+ );
120
+ if (runOptions?.forceRefresh === true) {
121
+ yield* cache.refresh(key).pipe(Effect.ignore);
122
+ }
123
+ const value = yield* cache.get(key).pipe(
124
+ Effect.mapError(
125
+ (error) => error
126
+ )
127
+ );
128
+ yield* setSnapshot(key, () => ({
129
+ key,
130
+ phase: "success",
131
+ data: value,
132
+ error: void 0,
133
+ updatedAt: Date.now()
134
+ }));
135
+ yield* telemetry.emit({
136
+ _tag: "query",
137
+ phase: "success",
138
+ key,
139
+ timestamp: Date.now()
140
+ });
141
+ return value;
142
+ }).pipe(
143
+ Effect.tapError(
144
+ (error) => Effect.gen(function* () {
145
+ const decodedInput = yield* boundary.decodeUnknown({
146
+ source: `query:${definition.name}:input`,
147
+ schema: definition.input,
148
+ value: input
149
+ });
150
+ const key = buildKey(definition, decodedInput);
151
+ yield* setSnapshot(key, (previous) => ({
152
+ ...previous,
153
+ phase: "failure",
154
+ error,
155
+ updatedAt: previous.updatedAt
156
+ }));
157
+ yield* telemetry.emit({
158
+ _tag: "query",
159
+ phase: "failure",
160
+ key,
161
+ timestamp: Date.now(),
162
+ detail: error
163
+ });
164
+ })
165
+ )
166
+ );
167
+ const prefetch = (definition, input) => fetch(definition, input).pipe(Effect.asVoid);
168
+ const invalidate = (definition, input) => Effect.gen(function* () {
169
+ const key = `${definition.name}:${stableStringify(input)}`;
170
+ yield* cache.invalidate(key);
171
+ yield* SubscriptionRef.update(snapshots, (current) => {
172
+ const next = new Map(current);
173
+ next.delete(key);
174
+ return next;
175
+ }).pipe(Effect.asVoid);
176
+ yield* telemetry.emit({
177
+ _tag: "query",
178
+ phase: "invalidate",
179
+ key,
180
+ timestamp: Date.now()
181
+ });
182
+ });
183
+ const getSnapshot = (definition, input) => Effect.gen(function* () {
184
+ const key = `${definition.name}:${stableStringify(input)}`;
185
+ const current = yield* SubscriptionRef.get(snapshots);
186
+ const snapshot = current.get(key);
187
+ if (snapshot === void 0) {
188
+ return initialSnapshot(key);
189
+ }
190
+ return snapshot;
191
+ });
192
+ return {
193
+ fetch,
194
+ prefetch,
195
+ invalidate,
196
+ getSnapshot,
197
+ getAllSnapshots: SubscriptionRef.get(snapshots),
198
+ hydrateSnapshots: (nextSnapshots) => SubscriptionRef.set(snapshots, new Map(nextSnapshots)),
199
+ snapshots: snapshots.changes
200
+ };
201
+ })
202
+ );
203
+ };
204
+ var fetchQuery = (definition, input, options) => Effect.flatMap(Data, (service) => service.fetch(definition, input, options));
205
+
206
+ export {
207
+ defineQuery,
208
+ QueryRuntimeError,
209
+ Data,
210
+ makeDataLayer,
211
+ fetchQuery
212
+ };
213
+ //# sourceMappingURL=chunk-C5JI7D7W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/types.ts","../src/data/service.ts"],"sourcesContent":["import type { Duration, Effect, Schema } from \"effect\";\nimport type { BoundaryDecodeError } from \"../boundary\";\nimport type { BoundaryProtocolError } from \"../boundary/errors\";\n\nexport interface QueryDefinition<\n Name extends string,\n Input,\n Output,\n E,\n InputEncoded = Input,\n OutputEncoded = Output,\n> {\n readonly name: Name;\n readonly input: Schema.Schema<Input, InputEncoded, never>;\n readonly output: Schema.Schema<Output, OutputEncoded, never>;\n readonly run: (input: Input) => Effect.Effect<Output, E, never>;\n readonly key?: (input: Input) => unknown;\n}\n\nexport const defineQuery = <\n Name extends string,\n Input,\n Output,\n E,\n InputEncoded = Input,\n OutputEncoded = Output,\n>(\n definition: QueryDefinition<Name, Input, Output, E, InputEncoded, OutputEncoded>,\n): QueryDefinition<Name, Input, Output, E, InputEncoded, OutputEncoded> => definition;\n\nexport type QueryPhase = \"initial\" | \"loading\" | \"success\" | \"failure\";\n\nexport interface QuerySnapshot<Output, E> {\n readonly key: string;\n readonly phase: QueryPhase;\n readonly data: Output | undefined;\n readonly error: E | BoundaryDecodeError | BoundaryProtocolError | QueryRuntimeError | undefined;\n readonly updatedAt: number | null | undefined;\n}\n\nexport interface QueryRunOptions {\n readonly forceRefresh?: boolean;\n}\n\nexport interface QueryRuntimeOptions {\n readonly capacity?: number;\n readonly timeToLive?: Duration.DurationInput;\n}\n\nexport class QueryRuntimeError extends Error {\n readonly _tag = \"QueryRuntimeError\" as const;\n\n constructor(readonly messageText: string) {\n super(messageText);\n this.name = \"QueryRuntimeError\";\n }\n}\n","import {\n Cache,\n Context,\n Effect,\n Layer,\n SubscriptionRef,\n type Stream,\n} from \"effect\";\nimport { Boundary, type BoundaryDecodeError } from \"../boundary\";\nimport type { BoundaryProtocolError } from \"../boundary/errors\";\nimport { Telemetry } from \"../kernel/telemetry\";\nimport {\n type QueryDefinition,\n type QueryRunOptions,\n type QueryRuntimeOptions,\n type QuerySnapshot,\n QueryRuntimeError,\n} from \"./types\";\n\nconst defaultRuntimeOptions: Required<QueryRuntimeOptions> = {\n capacity: 2048,\n timeToLive: \"5 minutes\",\n};\n\nconst stableStringify = (value: unknown): string => {\n if (value === null || value === undefined) {\n return String(value);\n }\n\n if (typeof value !== \"object\") {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n\n const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>\n a.localeCompare(b),\n );\n return `{${entries.map(([key, nested]) => `${JSON.stringify(key)}:${stableStringify(nested)}`).join(\",\")}}`;\n};\n\nconst initialSnapshot = <Output, E>(key: string): QuerySnapshot<Output, E> => ({\n key,\n phase: \"initial\",\n data: undefined,\n error: undefined,\n updatedAt: null,\n});\n\nexport interface DataService {\n readonly fetch: <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n options?: QueryRunOptions,\n ) => Effect.Effect<Output, E | BoundaryDecodeError | BoundaryProtocolError | QueryRuntimeError, never>;\n readonly prefetch: <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n ) => Effect.Effect<void, E | BoundaryDecodeError | BoundaryProtocolError | QueryRuntimeError, never>;\n readonly invalidate: <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n ) => Effect.Effect<void, QueryRuntimeError, never>;\n readonly getSnapshot: <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n ) => Effect.Effect<QuerySnapshot<Output, E>, never, never>;\n readonly getAllSnapshots: Effect.Effect<ReadonlyMap<string, QuerySnapshot<unknown, unknown>>, never, never>;\n readonly hydrateSnapshots: (\n snapshots: ReadonlyMap<string, QuerySnapshot<unknown, unknown>>,\n ) => Effect.Effect<void, never, never>;\n readonly snapshots: Stream.Stream<ReadonlyMap<string, QuerySnapshot<unknown, unknown>>>;\n}\n\nexport class Data extends Context.Tag(\"EffectReact/Data\")<Data, DataService>() {}\n\nexport const makeDataLayer = (\n options: QueryRuntimeOptions = {},\n): Layer.Layer<Data, never, Boundary | Telemetry> => {\n const merged = {\n ...defaultRuntimeOptions,\n ...options,\n };\n\n return Layer.effect(\n Data,\n Effect.gen(function* () {\n const boundary = yield* Boundary;\n const telemetry = yield* Telemetry;\n const lookups = new Map<string, Effect.Effect<unknown, unknown, never>>();\n const snapshots = yield* SubscriptionRef.make(\n new Map<string, QuerySnapshot<unknown, unknown>>() as ReadonlyMap<\n string,\n QuerySnapshot<unknown, unknown>\n >,\n );\n\n const cache = yield* Cache.make<string, unknown, unknown>({\n capacity: merged.capacity,\n timeToLive: merged.timeToLive,\n lookup: (key) =>\n Effect.suspend(() => {\n const lookup = lookups.get(key);\n if (lookup === undefined) {\n return Effect.fail(new QueryRuntimeError(`No query executor registered for ${key}`));\n }\n return lookup;\n }),\n });\n\n const setSnapshot = <Output, E>(\n key: string,\n update: (previous: QuerySnapshot<Output, E>) => QuerySnapshot<Output, E>,\n ): Effect.Effect<void> =>\n SubscriptionRef.update(snapshots, (current) => {\n const next = new Map(current);\n const previous =\n (next.get(key) as QuerySnapshot<Output, E> | undefined) ?? initialSnapshot<Output, E>(key);\n next.set(key, update(previous));\n return next;\n }).pipe(Effect.asVoid);\n\n const buildKey = <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: Input,\n ): string => {\n const base = definition.key ? definition.key(input) : input;\n return `${definition.name}:${stableStringify(base)}`;\n };\n\n const fetch = <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n runOptions?: QueryRunOptions,\n ): Effect.Effect<\n Output,\n E | BoundaryDecodeError | BoundaryProtocolError | QueryRuntimeError,\n never\n > =>\n Effect.gen(function* () {\n const decodedInput = yield* boundary.decodeUnknown({\n source: `query:${definition.name}:input`,\n schema: definition.input,\n value: input,\n });\n\n const key = buildKey(definition, decodedInput);\n yield* telemetry.emit({\n _tag: \"query\",\n phase: \"start\",\n key,\n timestamp: Date.now(),\n });\n\n yield* setSnapshot(key, (previous) => ({\n ...previous,\n phase: \"loading\",\n error: undefined,\n }));\n\n lookups.set(\n key,\n definition\n .run(decodedInput)\n .pipe(\n Effect.flatMap((output) =>\n boundary.decodeUnknown({\n source: `query:${definition.name}:output`,\n schema: definition.output,\n value: output,\n }),\n ),\n ) as Effect.Effect<unknown, unknown, never>,\n );\n\n if (runOptions?.forceRefresh === true) {\n yield* cache.refresh(key).pipe(Effect.ignore);\n }\n\n const value = yield* cache.get(key).pipe(\n Effect.mapError(\n (error) =>\n error as E | BoundaryDecodeError | BoundaryProtocolError | QueryRuntimeError,\n ),\n );\n\n yield* setSnapshot(key, () => ({\n key,\n phase: \"success\",\n data: value,\n error: undefined,\n updatedAt: Date.now(),\n }));\n\n yield* telemetry.emit({\n _tag: \"query\",\n phase: \"success\",\n key,\n timestamp: Date.now(),\n });\n\n return value as Output;\n }).pipe(\n Effect.tapError((error) =>\n Effect.gen(function* () {\n const decodedInput = yield* boundary.decodeUnknown({\n source: `query:${definition.name}:input`,\n schema: definition.input,\n value: input,\n });\n const key = buildKey(definition, decodedInput);\n yield* setSnapshot(key, (previous) => ({\n ...previous,\n phase: \"failure\",\n error,\n updatedAt: previous.updatedAt,\n }));\n yield* telemetry.emit({\n _tag: \"query\",\n phase: \"failure\",\n key,\n timestamp: Date.now(),\n detail: error,\n });\n }),\n ),\n );\n\n const prefetch: DataService[\"prefetch\"] = (definition, input) =>\n fetch(definition, input).pipe(Effect.asVoid);\n\n const invalidate: DataService[\"invalidate\"] = (definition, input) =>\n Effect.gen(function* () {\n const key = `${definition.name}:${stableStringify(input)}`;\n yield* cache.invalidate(key);\n yield* SubscriptionRef.update(snapshots, (current) => {\n const next = new Map(current);\n next.delete(key);\n return next;\n }).pipe(Effect.asVoid);\n yield* telemetry.emit({\n _tag: \"query\",\n phase: \"invalidate\",\n key,\n timestamp: Date.now(),\n });\n });\n\n const getSnapshot = <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n ): Effect.Effect<QuerySnapshot<Output, E>, never, never> =>\n Effect.gen(function* () {\n const key = `${definition.name}:${stableStringify(input)}`;\n const current = yield* SubscriptionRef.get(snapshots);\n const snapshot = current.get(key);\n if (snapshot === undefined) {\n return initialSnapshot<Output, E>(key);\n }\n return snapshot as QuerySnapshot<Output, E>;\n });\n\n return {\n fetch,\n prefetch,\n invalidate,\n getSnapshot,\n getAllSnapshots: SubscriptionRef.get(snapshots),\n hydrateSnapshots: (nextSnapshots) => SubscriptionRef.set(snapshots, new Map(nextSnapshots)),\n snapshots: snapshots.changes,\n } satisfies DataService;\n }),\n );\n};\n\nexport const fetchQuery = <Name extends string, Input, Output, E>(\n definition: QueryDefinition<Name, Input, Output, E>,\n input: unknown,\n options?: QueryRunOptions,\n): Effect.Effect<Output, E | BoundaryDecodeError | BoundaryProtocolError | QueryRuntimeError, Data> =>\n Effect.flatMap(Data, (service) => service.fetch(definition, input, options));\n"],"mappings":"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","names":[]}
@@ -0,0 +1,99 @@
1
+ import {
2
+ createHydrationScript,
3
+ dehydrateAppState
4
+ } from "./chunk-IVIYY6S5.js";
5
+ import {
6
+ navigateTo
7
+ } from "./chunk-O7XTA7H3.js";
8
+
9
+ // src/server/index.ts
10
+ import { Effect as Effect2 } from "effect";
11
+ import { createElement } from "react";
12
+
13
+ // src/render/ssr.ts
14
+ import { Effect } from "effect";
15
+ import * as ReactDOMServer from "react-dom/server";
16
+ var htmlResponse = (options) => {
17
+ const headers = new Headers(options.headers);
18
+ if (!headers.has("content-type")) {
19
+ headers.set("content-type", "text/html; charset=utf-8");
20
+ }
21
+ return new Response(options.html, {
22
+ status: options.status,
23
+ headers
24
+ });
25
+ };
26
+ var injectScript = (html, script) => {
27
+ const tag = `<script>${script}</script>`;
28
+ const bodyClose = html.lastIndexOf("</body>");
29
+ if (bodyClose === -1) {
30
+ return `${html}${tag}`;
31
+ }
32
+ return `${html.slice(0, bodyClose)}${tag}${html.slice(bodyClose)}`;
33
+ };
34
+ var toError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
35
+ var createSsrHandler = (options) => (request) => {
36
+ const program = Effect.gen(function* () {
37
+ const element = yield* options.render(request);
38
+ const html = ReactDOMServer.renderToString(element);
39
+ const state = yield* dehydrateAppState();
40
+ const script = createHydrationScript(state, options.hydrationGlobalName);
41
+ return htmlResponse({
42
+ html: injectScript(html, script),
43
+ status: options.status ?? 200,
44
+ ...options.headers !== void 0 ? { headers: options.headers } : {}
45
+ });
46
+ });
47
+ return options.runtime.runPromise(program).catch((cause) => {
48
+ const squashed = toError(cause);
49
+ if (options.onError !== void 0) {
50
+ return options.onError(squashed);
51
+ }
52
+ return new Response(`SSR render failed: ${squashed.message}`, {
53
+ status: 500,
54
+ headers: {
55
+ "content-type": "text/plain; charset=utf-8"
56
+ }
57
+ });
58
+ });
59
+ };
60
+
61
+ // src/server/index.ts
62
+ var defaultNotFoundElement = () => createElement("main", void 0, "Not Found");
63
+ var createRequestHandler = (options) => {
64
+ const actionPath = options.actionPath ?? "/_actions";
65
+ const ssrHandler = createSsrHandler({
66
+ runtime: options.app.runtime,
67
+ ...options.hydrationGlobalName !== void 0 ? { hydrationGlobalName: options.hydrationGlobalName } : {},
68
+ ...options.onError !== void 0 ? { onError: options.onError } : {},
69
+ render: (request) => Effect2.gen(function* () {
70
+ const url = new URL(request.url);
71
+ const href = `${url.pathname}${url.search}`;
72
+ const page = options.app.matchPage(href);
73
+ if (page === void 0) {
74
+ return defaultNotFoundElement();
75
+ }
76
+ yield* navigateTo(href);
77
+ if (options.render !== void 0) {
78
+ return yield* options.render({ request, page });
79
+ }
80
+ return createElement(page.component);
81
+ }).pipe(
82
+ Effect2.mapError(
83
+ (error) => error instanceof Error ? error : new Error(String(error))
84
+ )
85
+ )
86
+ });
87
+ return (request) => {
88
+ const url = new URL(request.url);
89
+ if (request.method.toUpperCase() === "POST" && url.pathname === actionPath) {
90
+ return options.app.handleActionRequest(request);
91
+ }
92
+ return ssrHandler(request);
93
+ };
94
+ };
95
+
96
+ export {
97
+ createRequestHandler
98
+ };
99
+ //# sourceMappingURL=chunk-EEYASTXR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/index.ts","../src/render/ssr.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { createElement, type ReactElement } from \"react\";\nimport type { AppServices } from \"../kernel/app\";\nimport { navigateTo } from \"../navigation\";\nimport { createSsrHandler } from \"../render\";\nimport type { AnyPageDefinition } from \"../framework/contracts\";\nimport type { EffectReactApp } from \"../framework/app\";\n\nexport interface CreateRequestHandlerOptions {\n readonly app: EffectReactApp;\n readonly render?: (options: {\n readonly request: Request;\n readonly page: AnyPageDefinition;\n }) => Effect.Effect<ReactElement, unknown, AppServices>;\n readonly actionPath?: string;\n readonly hydrationGlobalName?: string;\n readonly onError?: (error: Error) => Response;\n}\n\nconst defaultNotFoundElement = (): ReactElement =>\n createElement(\"main\", undefined, \"Not Found\");\n\nexport const createRequestHandler = (\n options: CreateRequestHandlerOptions,\n): ((request: Request) => Promise<Response>) => {\n const actionPath = options.actionPath ?? \"/_actions\";\n\n const ssrHandler = createSsrHandler({\n runtime: options.app.runtime,\n ...(options.hydrationGlobalName !== undefined\n ? { hydrationGlobalName: options.hydrationGlobalName }\n : {}),\n ...(options.onError !== undefined ? { onError: options.onError } : {}),\n render: (request) =>\n Effect.gen(function* () {\n const url = new URL(request.url);\n const href = `${url.pathname}${url.search}`;\n const page = options.app.matchPage(href);\n\n if (page === undefined) {\n return defaultNotFoundElement();\n }\n\n yield* navigateTo(href);\n\n if (options.render !== undefined) {\n return yield* options.render({ request, page });\n }\n\n return createElement(page.component);\n }).pipe(\n Effect.mapError((error) =>\n error instanceof Error ? error : new Error(String(error)),\n ),\n ),\n });\n\n return (request) => {\n const url = new URL(request.url);\n if (request.method.toUpperCase() === \"POST\" && url.pathname === actionPath) {\n return options.app.handleActionRequest(request);\n }\n\n return ssrHandler(request);\n };\n};\n","import { Effect } from \"effect\";\nimport type { ReactElement } from \"react\";\nimport * as ReactDOMServer from \"react-dom/server\";\nimport type { AppServices } from \"../kernel/app\";\nimport type { AppManagedRuntime } from \"../kernel/runtime\";\nimport { createHydrationScript, dehydrateAppState, type HydrationState } from \"./hydration\";\n\nexport interface CreateSsrHandlerOptions<E> {\n readonly runtime: AppManagedRuntime<AppServices>;\n readonly render: (request: Request) => Effect.Effect<ReactElement, E, AppServices>;\n readonly status?: number;\n readonly headers?: HeadersInit;\n readonly hydrationGlobalName?: string;\n readonly onError?: (error: E | Error) => Response;\n}\n\nconst htmlResponse = (options: {\n readonly html: string;\n readonly status: number;\n readonly headers?: HeadersInit;\n}): Response => {\n const headers = new Headers(options.headers);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n return new Response(options.html, {\n status: options.status,\n headers,\n });\n};\n\nconst injectScript = (html: string, script: string): string => {\n const tag = `<script>${script}</script>`;\n const bodyClose = html.lastIndexOf(\"</body>\");\n if (bodyClose === -1) {\n return `${html}${tag}`;\n }\n return `${html.slice(0, bodyClose)}${tag}${html.slice(bodyClose)}`;\n};\n\nconst toError = (cause: unknown): Error =>\n cause instanceof Error ? cause : new Error(String(cause));\n\nexport const createSsrHandler = <E>(options: CreateSsrHandlerOptions<E>) =>\n (request: Request): Promise<Response> => {\n const program = Effect.gen(function* () {\n const element = yield* options.render(request);\n const html = ReactDOMServer.renderToString(element);\n\n const state: HydrationState = yield* dehydrateAppState();\n const script = createHydrationScript(state, options.hydrationGlobalName);\n\n return htmlResponse({\n html: injectScript(html, script),\n status: options.status ?? 200,\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n });\n });\n\n return options.runtime\n .runPromise(program)\n .catch((cause: unknown) => {\n const squashed = toError(cause);\n if (options.onError !== undefined) {\n return options.onError(squashed as E | Error);\n }\n return new Response(`SSR render failed: ${squashed.message}`, {\n status: 500,\n headers: {\n \"content-type\": \"text/plain; charset=utf-8\",\n },\n });\n });\n };\n"],"mappings":"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","names":["Effect","Effect"]}
@@ -0,0 +1,301 @@
1
+ import {
2
+ useEffectRuntime
3
+ } from "./chunk-2GIUCKL2.js";
4
+ import {
5
+ Data,
6
+ fetchQuery
7
+ } from "./chunk-C5JI7D7W.js";
8
+
9
+ // src/query/service.ts
10
+ import { Effect as Effect2 } from "effect";
11
+
12
+ // src/data/react.tsx
13
+ import { Effect, Fiber, Stream } from "effect";
14
+ import { useCallback, useEffect, useMemo, useSyncExternalStore } from "react";
15
+ var useDataService = () => {
16
+ const runtime = useEffectRuntime();
17
+ return useMemo(() => runtime.runSync(Data), [runtime]);
18
+ };
19
+ var useQuery = (definition, input, options = {}) => {
20
+ const runtime = useEffectRuntime();
21
+ const data = useDataService();
22
+ const subscribe = useCallback(
23
+ (listener) => {
24
+ const fiber = runtime.runFork(
25
+ Stream.runForEach(data.snapshots, () => Effect.sync(listener))
26
+ );
27
+ return () => {
28
+ runtime.runFork(Fiber.interrupt(fiber));
29
+ };
30
+ },
31
+ [data, runtime]
32
+ );
33
+ const getSnapshot = useCallback(
34
+ () => runtime.runSync(data.getSnapshot(definition, input)),
35
+ [data, definition, input, runtime]
36
+ );
37
+ const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
38
+ useEffect(() => {
39
+ if (options.enabled === false) {
40
+ return;
41
+ }
42
+ runtime.runFork(data.prefetch(definition, input));
43
+ }, [data, definition, input, options.enabled, runtime]);
44
+ const refetch = useCallback(
45
+ () => runtime.runPromise(data.fetch(definition, input, { ...options.run, forceRefresh: true })),
46
+ [data, definition, input, options.run, runtime]
47
+ );
48
+ const invalidate2 = useCallback(
49
+ () => runtime.runPromise(data.invalidate(definition, input)),
50
+ [data, definition, input, runtime]
51
+ );
52
+ return {
53
+ ...snapshot,
54
+ refetch,
55
+ invalidate: invalidate2
56
+ };
57
+ };
58
+ var useSuspenseQuery = (definition, input) => {
59
+ const result = useQuery(definition, input);
60
+ if (result.phase === "failure") {
61
+ throw result.error;
62
+ }
63
+ if (result.phase === "success") {
64
+ return result.data;
65
+ }
66
+ throw result.refetch();
67
+ };
68
+
69
+ // src/query/service.ts
70
+ var fetchQuery2 = fetchQuery;
71
+ var prefetchQuery = (definition, input) => Effect2.flatMap(Data, (service) => service.prefetch(definition, input));
72
+ var invalidateQuery = (definition, input) => Effect2.flatMap(Data, (service) => service.invalidate(definition, input));
73
+ var prefetch = prefetchQuery;
74
+ var invalidate = invalidateQuery;
75
+
76
+ // src/query/react.tsx
77
+ import { Effect as Effect3 } from "effect";
78
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef, useState } from "react";
79
+ var upsertInfiniteEntry = (entries, nextEntry) => {
80
+ const index = entries.findIndex((entry) => entry.key === nextEntry.key);
81
+ if (index < 0) {
82
+ return [...entries, nextEntry];
83
+ }
84
+ const next = [...entries];
85
+ next[index] = nextEntry;
86
+ return next;
87
+ };
88
+ var useDataService2 = () => {
89
+ const runtime = useEffectRuntime();
90
+ return useMemo2(() => runtime.runSync(Data), [runtime]);
91
+ };
92
+ var useQuery2 = (definition, input, options = {}) => useQuery(definition, input, options);
93
+ var useSuspenseQuery2 = (definition, input) => useSuspenseQuery(definition, input);
94
+ var useInfiniteQuery = (definition, options) => {
95
+ const optionsRef = useRef(options);
96
+ optionsRef.current = options;
97
+ const initialPageParam = options.initialPageParam;
98
+ const enabled = options.enabled;
99
+ const run = options.run;
100
+ const getInput = useCallback2(
101
+ (pageParam) => optionsRef.current.getInput(pageParam),
102
+ []
103
+ );
104
+ const getNextPageParam = useCallback2(
105
+ (lastPage, allPages, lastPageParam, allPageParams) => optionsRef.current.getNextPageParam(lastPage, allPages, lastPageParam, allPageParams),
106
+ []
107
+ );
108
+ const runtime = useEffectRuntime();
109
+ const data = useDataService2();
110
+ const [initialInput, setInitialInput] = useState(
111
+ () => getInput(initialPageParam)
112
+ );
113
+ const [entries, setEntries] = useState([]);
114
+ const [error, setError] = useState(void 0);
115
+ const [isFetchingNextPage, setIsFetchingNextPage] = useState(false);
116
+ const initialQuery = useQuery2(
117
+ definition,
118
+ initialInput,
119
+ {
120
+ ...enabled !== void 0 ? { enabled } : {},
121
+ ...run !== void 0 ? { run } : {}
122
+ }
123
+ );
124
+ useEffect2(() => {
125
+ setInitialInput(getInput(initialPageParam));
126
+ setEntries([]);
127
+ setError(void 0);
128
+ setIsFetchingNextPage(false);
129
+ }, [definition, getInput, initialPageParam]);
130
+ useEffect2(() => {
131
+ if (initialQuery.phase === "success") {
132
+ setEntries(
133
+ (current) => upsertInfiniteEntry(current, {
134
+ key: initialQuery.key,
135
+ pageParam: initialPageParam,
136
+ data: initialQuery.data
137
+ })
138
+ );
139
+ setError(void 0);
140
+ return;
141
+ }
142
+ if (initialQuery.phase === "failure") {
143
+ setError(initialQuery.error);
144
+ }
145
+ }, [
146
+ initialQuery.data,
147
+ initialQuery.error,
148
+ initialQuery.key,
149
+ initialQuery.phase,
150
+ initialPageParam
151
+ ]);
152
+ const pages = useMemo2(() => entries.map((entry) => entry.data), [entries]);
153
+ const pageParams = useMemo2(() => entries.map((entry) => entry.pageParam), [entries]);
154
+ const resolveNextPageParam = useCallback2(() => {
155
+ const lastEntry = entries[entries.length - 1];
156
+ if (lastEntry !== void 0) {
157
+ return getNextPageParam(lastEntry.data, pages, lastEntry.pageParam, pageParams);
158
+ }
159
+ if (initialQuery.phase !== "success") {
160
+ return void 0;
161
+ }
162
+ const initialPage = initialQuery.data;
163
+ return getNextPageParam(
164
+ initialPage,
165
+ [initialPage],
166
+ initialPageParam,
167
+ [initialPageParam]
168
+ );
169
+ }, [
170
+ entries,
171
+ getNextPageParam,
172
+ initialPageParam,
173
+ initialQuery.data,
174
+ initialQuery.phase,
175
+ pageParams,
176
+ pages
177
+ ]);
178
+ const fetchNextPage = useCallback2(() => {
179
+ const nextPageParam = resolveNextPageParam();
180
+ if (nextPageParam === void 0) {
181
+ return runtime.runPromise(Effect3.succeed(void 0));
182
+ }
183
+ setIsFetchingNextPage(true);
184
+ setError(void 0);
185
+ const input = getInput(nextPageParam);
186
+ const program = Effect3.gen(function* () {
187
+ const value = yield* data.fetch(definition, input, run);
188
+ const snapshot = yield* data.getSnapshot(definition, input);
189
+ return {
190
+ key: snapshot.key,
191
+ pageParam: nextPageParam,
192
+ value
193
+ };
194
+ });
195
+ return runtime.runPromise(program).then(
196
+ ({ key, pageParam, value }) => {
197
+ setEntries(
198
+ (current) => upsertInfiniteEntry(current, {
199
+ key,
200
+ pageParam,
201
+ data: value
202
+ })
203
+ );
204
+ setIsFetchingNextPage(false);
205
+ return value;
206
+ },
207
+ (cause) => {
208
+ setIsFetchingNextPage(false);
209
+ const resolved = cause;
210
+ setError(resolved);
211
+ return runtime.runPromise(Effect3.fail(resolved));
212
+ }
213
+ );
214
+ }, [data, definition, getInput, resolveNextPageParam, run, runtime]);
215
+ const refetch = useCallback2(() => {
216
+ const targets = pageParams.length === 0 ? [initialPageParam] : pageParams;
217
+ setError(void 0);
218
+ const program = Effect3.forEach(
219
+ targets,
220
+ (pageParam) => {
221
+ const input = getInput(pageParam);
222
+ return Effect3.gen(function* () {
223
+ const value = yield* data.fetch(definition, input, {
224
+ ...run,
225
+ forceRefresh: true
226
+ });
227
+ const snapshot = yield* data.getSnapshot(definition, input);
228
+ return {
229
+ key: snapshot.key,
230
+ pageParam,
231
+ data: value
232
+ };
233
+ });
234
+ },
235
+ {
236
+ concurrency: 1,
237
+ discard: false
238
+ }
239
+ );
240
+ return runtime.runPromise(program).then(
241
+ (fetchedEntries) => {
242
+ setEntries(fetchedEntries);
243
+ return fetchedEntries.map((entry) => entry.data);
244
+ },
245
+ (cause) => {
246
+ const resolved = cause;
247
+ setError(resolved);
248
+ return runtime.runPromise(Effect3.fail(resolved));
249
+ }
250
+ );
251
+ }, [data, definition, getInput, initialPageParam, pageParams, run, runtime]);
252
+ const invalidate2 = useCallback2(() => {
253
+ const targets = pageParams.length === 0 ? [initialPageParam] : pageParams;
254
+ const program = Effect3.forEach(
255
+ targets,
256
+ (pageParam) => data.invalidate(definition, getInput(pageParam)),
257
+ {
258
+ concurrency: 1,
259
+ discard: true
260
+ }
261
+ );
262
+ return runtime.runPromise(program).then(
263
+ () => {
264
+ setEntries([]);
265
+ setError(void 0);
266
+ setIsFetchingNextPage(false);
267
+ return void 0;
268
+ },
269
+ (cause) => {
270
+ const resolved = cause;
271
+ setError(resolved);
272
+ return runtime.runPromise(Effect3.fail(resolved));
273
+ }
274
+ );
275
+ }, [data, definition, getInput, initialPageParam, pageParams, runtime]);
276
+ const resolvedError = error ?? (initialQuery.phase === "failure" ? initialQuery.error : void 0);
277
+ const phase = resolvedError !== void 0 ? "failure" : entries.length > 0 ? "success" : initialQuery.phase;
278
+ return {
279
+ phase,
280
+ pages,
281
+ pageParams,
282
+ error: resolvedError,
283
+ hasNextPage: resolveNextPageParam() !== void 0,
284
+ isFetchingNextPage,
285
+ fetchNextPage,
286
+ refetch,
287
+ invalidate: invalidate2
288
+ };
289
+ };
290
+
291
+ export {
292
+ fetchQuery2 as fetchQuery,
293
+ prefetchQuery,
294
+ invalidateQuery,
295
+ prefetch,
296
+ invalidate,
297
+ useQuery2 as useQuery,
298
+ useSuspenseQuery2 as useSuspenseQuery,
299
+ useInfiniteQuery
300
+ };
301
+ //# sourceMappingURL=chunk-H7MOLKTU.js.map