@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.
- package/LICENSE +21 -0
- package/README.md +179 -0
- package/dist/actions/http.d.ts +18 -0
- package/dist/actions/index.d.ts +4 -0
- package/dist/actions/react.d.ts +7 -0
- package/dist/actions/service.d.ts +18 -0
- package/dist/actions/types.d.ts +33 -0
- package/dist/boundary/codecs.d.ts +40 -0
- package/dist/boundary/errors.d.ts +22 -0
- package/dist/boundary/index.d.ts +2 -0
- package/dist/chunk-2GIUCKL2.js +16 -0
- package/dist/chunk-2GIUCKL2.js.map +1 -0
- package/dist/chunk-2TG7YEVD.js +11 -0
- package/dist/chunk-2TG7YEVD.js.map +1 -0
- package/dist/chunk-6FI4ROTW.js +152 -0
- package/dist/chunk-6FI4ROTW.js.map +1 -0
- package/dist/chunk-C5JI7D7W.js +213 -0
- package/dist/chunk-C5JI7D7W.js.map +1 -0
- package/dist/chunk-EEYASTXR.js +99 -0
- package/dist/chunk-EEYASTXR.js.map +1 -0
- package/dist/chunk-H7MOLKTU.js +301 -0
- package/dist/chunk-H7MOLKTU.js.map +1 -0
- package/dist/chunk-IVIYY6S5.js +77 -0
- package/dist/chunk-IVIYY6S5.js.map +1 -0
- package/dist/chunk-JKN75OYC.js +87 -0
- package/dist/chunk-JKN75OYC.js.map +1 -0
- package/dist/chunk-M2CJG6T7.js +24 -0
- package/dist/chunk-M2CJG6T7.js.map +1 -0
- package/dist/chunk-MDGEGQZB.js +206 -0
- package/dist/chunk-MDGEGQZB.js.map +1 -0
- package/dist/chunk-NI2GNZ7S.js +78 -0
- package/dist/chunk-NI2GNZ7S.js.map +1 -0
- package/dist/chunk-O7XTA7H3.js +423 -0
- package/dist/chunk-O7XTA7H3.js.map +1 -0
- package/dist/chunk-S67FHWAR.js +88 -0
- package/dist/chunk-S67FHWAR.js.map +1 -0
- package/dist/chunk-SKC3HMF3.js +17 -0
- package/dist/chunk-SKC3HMF3.js.map +1 -0
- package/dist/chunk-TUJZ6XJY.js +127 -0
- package/dist/chunk-TUJZ6XJY.js.map +1 -0
- package/dist/chunk-WPV3WFMS.js +38 -0
- package/dist/chunk-WPV3WFMS.js.map +1 -0
- package/dist/chunk-XIBEKS5A.js +301 -0
- package/dist/chunk-XIBEKS5A.js.map +1 -0
- package/dist/chunk-YG22YP5K.js +68 -0
- package/dist/chunk-YG22YP5K.js.map +1 -0
- package/dist/chunk-ZMZQBREU.js +262 -0
- package/dist/chunk-ZMZQBREU.js.map +1 -0
- package/dist/client/index.cjs +191 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.js +14 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config/index.cjs +63 -0
- package/dist/config/index.cjs.map +1 -0
- package/dist/config/index.d.ts +32 -0
- package/dist/config/index.js +9 -0
- package/dist/config/index.js.map +1 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/react.d.ts +10 -0
- package/dist/data/service.d.ts +20 -0
- package/dist/data/types.d.ts +31 -0
- package/dist/devtools/events.d.ts +37 -0
- package/dist/devtools/index.cjs +149 -0
- package/dist/devtools/index.cjs.map +1 -0
- package/dist/devtools/index.d.ts +2 -0
- package/dist/devtools/index.js +18 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/devtools/react.d.ts +8 -0
- package/dist/form/index.cjs +301 -0
- package/dist/form/index.cjs.map +1 -0
- package/dist/form/index.d.ts +3 -0
- package/dist/form/index.js +14 -0
- package/dist/form/index.js.map +1 -0
- package/dist/form/react.d.ts +9 -0
- package/dist/form/service.d.ts +3 -0
- package/dist/form/types.d.ts +41 -0
- package/dist/framework/app.d.ts +21 -0
- package/dist/framework/cache.d.ts +10 -0
- package/dist/framework/contracts.d.ts +32 -0
- package/dist/framework/index.cjs +1006 -0
- package/dist/framework/index.cjs.map +1 -0
- package/dist/framework/index.d.ts +4 -0
- package/dist/framework/index.js +35 -0
- package/dist/framework/index.js.map +1 -0
- package/dist/framework/manifest.d.ts +12 -0
- package/dist/framework/vite.d.ts +13 -0
- package/dist/framework-vite/index.cjs +163 -0
- package/dist/framework-vite/index.cjs.map +1 -0
- package/dist/framework-vite/index.d.ts +1 -0
- package/dist/framework-vite/index.js +125 -0
- package/dist/framework-vite/index.js.map +1 -0
- package/dist/grid/grid.d.ts +8 -0
- package/dist/grid/index.cjs +238 -0
- package/dist/grid/index.cjs.map +1 -0
- package/dist/grid/index.d.ts +2 -0
- package/dist/grid/index.js +19 -0
- package/dist/grid/index.js.map +1 -0
- package/dist/grid/types.d.ts +35 -0
- package/dist/index.cjs +2512 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +207 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/app.d.ts +26 -0
- package/dist/kernel/index.d.ts +3 -0
- package/dist/kernel/runtime.d.ts +5 -0
- package/dist/kernel/telemetry.d.ts +37 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/matcher.d.ts +13 -0
- package/dist/navigation/react.d.ts +12 -0
- package/dist/navigation/service.d.ts +23 -0
- package/dist/navigation/types.d.ts +65 -0
- package/dist/query/index.cjs +361 -0
- package/dist/query/index.cjs.map +1 -0
- package/dist/query/index.d.ts +3 -0
- package/dist/query/index.js +30 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/react.d.ts +27 -0
- package/dist/query/service.d.ts +10 -0
- package/dist/query/types.d.ts +5 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/provider.d.ts +10 -0
- package/dist/realtime/channel.d.ts +15 -0
- package/dist/realtime/index.cjs +117 -0
- package/dist/realtime/index.cjs.map +1 -0
- package/dist/realtime/index.d.ts +2 -0
- package/dist/realtime/index.js +15 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/presence.d.ts +22 -0
- package/dist/render/hydration.d.ts +24 -0
- package/dist/render/index.d.ts +2 -0
- package/dist/render/ssr.d.ts +13 -0
- package/dist/router/helpers.d.ts +26 -0
- package/dist/router/index.cjs +236 -0
- package/dist/router/index.cjs.map +1 -0
- package/dist/router/index.d.ts +4 -0
- package/dist/router/index.js +40 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/react.d.ts +5 -0
- package/dist/router/service.d.ts +5 -0
- package/dist/router/types.d.ts +1 -0
- package/dist/server/index.cjs +174 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.js +12 -0
- package/dist/server/index.js.map +1 -0
- package/dist/state/index.cjs +128 -0
- package/dist/state/index.cjs.map +1 -0
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.js +36 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/react.d.ts +3 -0
- package/dist/state/service.d.ts +28 -0
- package/dist/testing/index.cjs +970 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/virtual/index.cjs +160 -0
- package/dist/virtual/index.cjs.map +1 -0
- package/dist/virtual/index.d.ts +2 -0
- package/dist/virtual/index.js +21 -0
- package/dist/virtual/index.js.map +1 -0
- package/dist/virtual/types.d.ts +25 -0
- package/dist/virtual/virtual.d.ts +9 -0
- package/package.json +156 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useEffectRuntime
|
|
3
|
+
} from "./chunk-2GIUCKL2.js";
|
|
4
|
+
|
|
5
|
+
// src/form/types.ts
|
|
6
|
+
var defineForm = (contract) => contract;
|
|
7
|
+
var FormValidationError = class extends Error {
|
|
8
|
+
constructor(errors) {
|
|
9
|
+
super("Form validation failed");
|
|
10
|
+
this.errors = errors;
|
|
11
|
+
this.name = "FormValidationError";
|
|
12
|
+
}
|
|
13
|
+
_tag = "FormValidationError";
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/form/service.ts
|
|
17
|
+
import { Effect, ParseResult, Schema, SubscriptionRef } from "effect";
|
|
18
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
var cloneUnknown = (value) => {
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return value.map((entry) => cloneUnknown(entry));
|
|
22
|
+
}
|
|
23
|
+
if (isRecord(value)) {
|
|
24
|
+
const clone = {};
|
|
25
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
26
|
+
clone[key] = cloneUnknown(entry);
|
|
27
|
+
}
|
|
28
|
+
return clone;
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
var cloneValue = (value) => {
|
|
33
|
+
return cloneUnknown(value);
|
|
34
|
+
};
|
|
35
|
+
var deepEqual = (left, right) => {
|
|
36
|
+
if (Object.is(left, right)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
40
|
+
if (left.length !== right.length) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
44
|
+
if (!deepEqual(left[index], right[index])) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (isRecord(left) && isRecord(right)) {
|
|
51
|
+
const leftKeys = Object.keys(left);
|
|
52
|
+
const rightKeys = Object.keys(right);
|
|
53
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
for (const key of leftKeys) {
|
|
57
|
+
if (!(key in right)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (!deepEqual(left[key], right[key])) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
};
|
|
68
|
+
var toFormErrors = (error, fieldNames) => {
|
|
69
|
+
const formatted = ParseResult.ArrayFormatter.formatErrorSync(error);
|
|
70
|
+
const errors = {};
|
|
71
|
+
for (const entry of formatted) {
|
|
72
|
+
const root = entry.path[0];
|
|
73
|
+
if (typeof root === "string" && fieldNames.has(root)) {
|
|
74
|
+
const key = root;
|
|
75
|
+
errors[key] ??= entry.message;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
errors._form ??= entry.message;
|
|
79
|
+
}
|
|
80
|
+
if (formatted.length === 0 && errors._form === void 0) {
|
|
81
|
+
errors._form = "Invalid form values.";
|
|
82
|
+
}
|
|
83
|
+
return errors;
|
|
84
|
+
};
|
|
85
|
+
var createInitialState = (defaults) => ({
|
|
86
|
+
values: cloneValue(defaults),
|
|
87
|
+
errors: {},
|
|
88
|
+
touched: {},
|
|
89
|
+
dirty: false,
|
|
90
|
+
submitting: false,
|
|
91
|
+
submitted: false
|
|
92
|
+
});
|
|
93
|
+
var makeForm = (contract) => Effect.gen(function* () {
|
|
94
|
+
const decode = Schema.decodeUnknown(contract.schema, { errors: "all" });
|
|
95
|
+
const defaults = cloneValue(contract.defaults);
|
|
96
|
+
const fieldNames = new Set(Object.keys(defaults));
|
|
97
|
+
const snapshots = yield* SubscriptionRef.make(createInitialState(defaults));
|
|
98
|
+
const validateCurrent = (current) => decode(current.values).pipe(
|
|
99
|
+
Effect.match({
|
|
100
|
+
onFailure: (issue) => ({
|
|
101
|
+
_tag: "invalid",
|
|
102
|
+
errors: toFormErrors(issue, fieldNames),
|
|
103
|
+
issue
|
|
104
|
+
}),
|
|
105
|
+
onSuccess: (values) => ({
|
|
106
|
+
_tag: "valid",
|
|
107
|
+
values: cloneValue(values)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
const setField = (field, value) => SubscriptionRef.update(snapshots, (current) => {
|
|
112
|
+
const nextValues = {
|
|
113
|
+
...current.values,
|
|
114
|
+
[field]: value
|
|
115
|
+
};
|
|
116
|
+
const nextErrors = {
|
|
117
|
+
...current.errors
|
|
118
|
+
};
|
|
119
|
+
delete nextErrors[field];
|
|
120
|
+
return {
|
|
121
|
+
...current,
|
|
122
|
+
values: nextValues,
|
|
123
|
+
errors: nextErrors,
|
|
124
|
+
touched: {
|
|
125
|
+
...current.touched,
|
|
126
|
+
[field]: true
|
|
127
|
+
},
|
|
128
|
+
dirty: !deepEqual(nextValues, defaults),
|
|
129
|
+
submitted: false
|
|
130
|
+
};
|
|
131
|
+
}).pipe(Effect.asVoid);
|
|
132
|
+
const reset = SubscriptionRef.set(
|
|
133
|
+
snapshots,
|
|
134
|
+
createInitialState(defaults)
|
|
135
|
+
).pipe(Effect.asVoid);
|
|
136
|
+
const validate = Effect.gen(function* () {
|
|
137
|
+
const current = yield* SubscriptionRef.get(snapshots);
|
|
138
|
+
const result = yield* validateCurrent(current);
|
|
139
|
+
if (result._tag === "valid") {
|
|
140
|
+
yield* SubscriptionRef.update(snapshots, (snapshot) => ({
|
|
141
|
+
...snapshot,
|
|
142
|
+
values: result.values,
|
|
143
|
+
errors: {},
|
|
144
|
+
dirty: !deepEqual(result.values, defaults)
|
|
145
|
+
}));
|
|
146
|
+
} else {
|
|
147
|
+
yield* SubscriptionRef.update(snapshots, (snapshot) => ({
|
|
148
|
+
...snapshot,
|
|
149
|
+
errors: result.errors
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
});
|
|
154
|
+
const submit = (handler) => Effect.gen(function* () {
|
|
155
|
+
yield* SubscriptionRef.update(snapshots, (current2) => ({
|
|
156
|
+
...current2,
|
|
157
|
+
submitting: true,
|
|
158
|
+
submitted: false
|
|
159
|
+
}));
|
|
160
|
+
const current = yield* SubscriptionRef.get(snapshots);
|
|
161
|
+
const validation = yield* validateCurrent(current);
|
|
162
|
+
if (validation._tag === "invalid") {
|
|
163
|
+
yield* SubscriptionRef.update(snapshots, (snapshot) => ({
|
|
164
|
+
...snapshot,
|
|
165
|
+
submitting: false,
|
|
166
|
+
submitted: false,
|
|
167
|
+
errors: validation.errors
|
|
168
|
+
}));
|
|
169
|
+
return yield* Effect.fail(new FormValidationError(validation.errors));
|
|
170
|
+
}
|
|
171
|
+
yield* SubscriptionRef.update(snapshots, (snapshot) => ({
|
|
172
|
+
...snapshot,
|
|
173
|
+
values: validation.values,
|
|
174
|
+
errors: {},
|
|
175
|
+
dirty: !deepEqual(validation.values, defaults)
|
|
176
|
+
}));
|
|
177
|
+
return yield* handler(validation.values).pipe(
|
|
178
|
+
Effect.tap(
|
|
179
|
+
() => SubscriptionRef.update(snapshots, (snapshot) => ({
|
|
180
|
+
...snapshot,
|
|
181
|
+
submitting: false,
|
|
182
|
+
submitted: true
|
|
183
|
+
})).pipe(Effect.asVoid)
|
|
184
|
+
),
|
|
185
|
+
Effect.tapError(
|
|
186
|
+
() => SubscriptionRef.update(snapshots, (snapshot) => ({
|
|
187
|
+
...snapshot,
|
|
188
|
+
submitting: false,
|
|
189
|
+
submitted: false
|
|
190
|
+
})).pipe(Effect.asVoid)
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
getSnapshot: SubscriptionRef.get(snapshots),
|
|
196
|
+
snapshots: snapshots.changes,
|
|
197
|
+
setField,
|
|
198
|
+
reset,
|
|
199
|
+
validate,
|
|
200
|
+
submit
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// src/form/react.tsx
|
|
205
|
+
import { Effect as Effect2, Fiber, Stream } from "effect";
|
|
206
|
+
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
|
207
|
+
var useFormStore = (contract) => {
|
|
208
|
+
const runtime = useEffectRuntime();
|
|
209
|
+
return useMemo(() => runtime.runSync(makeForm(contract)), [contract, runtime]);
|
|
210
|
+
};
|
|
211
|
+
var useForm = (contract) => {
|
|
212
|
+
const runtime = useEffectRuntime();
|
|
213
|
+
const form = useFormStore(contract);
|
|
214
|
+
const subscribe = useCallback(
|
|
215
|
+
(listener) => {
|
|
216
|
+
const fiber = runtime.runFork(Stream.runForEach(form.snapshots, () => Effect2.sync(listener)));
|
|
217
|
+
return () => {
|
|
218
|
+
runtime.runFork(Fiber.interrupt(fiber));
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
[form, runtime]
|
|
222
|
+
);
|
|
223
|
+
const getSnapshot = useCallback(() => runtime.runSync(form.getSnapshot), [form, runtime]);
|
|
224
|
+
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
225
|
+
const setField = useCallback(
|
|
226
|
+
(field, value) => runtime.runPromise(form.setField(field, value)),
|
|
227
|
+
[form, runtime]
|
|
228
|
+
);
|
|
229
|
+
const reset = useCallback(
|
|
230
|
+
() => runtime.runPromise(form.reset),
|
|
231
|
+
[form, runtime]
|
|
232
|
+
);
|
|
233
|
+
const validate = useCallback(
|
|
234
|
+
() => runtime.runPromise(form.validate),
|
|
235
|
+
[form, runtime]
|
|
236
|
+
);
|
|
237
|
+
const submit = useCallback(
|
|
238
|
+
(handler) => runtime.runPromise(form.submit(handler)),
|
|
239
|
+
[form, runtime]
|
|
240
|
+
);
|
|
241
|
+
return {
|
|
242
|
+
...snapshot,
|
|
243
|
+
commands: {
|
|
244
|
+
setField: form.setField,
|
|
245
|
+
reset: form.reset,
|
|
246
|
+
validate: form.validate,
|
|
247
|
+
submit: form.submit
|
|
248
|
+
},
|
|
249
|
+
setField,
|
|
250
|
+
reset,
|
|
251
|
+
validate,
|
|
252
|
+
submit
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
export {
|
|
257
|
+
defineForm,
|
|
258
|
+
FormValidationError,
|
|
259
|
+
makeForm,
|
|
260
|
+
useForm
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=chunk-ZMZQBREU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/form/types.ts","../src/form/service.ts","../src/form/react.tsx"],"sourcesContent":["import type { Effect, ParseResult, Schema, Stream } from \"effect\";\n\nexport type FormValues = Readonly<Record<string, unknown>>;\n\nexport type FormFieldName<Values extends FormValues> = Extract<keyof Values, string>;\n\nexport type FormErrorKey<Values extends FormValues> = FormFieldName<Values> | \"_form\";\n\nexport type FormErrors<Values extends FormValues> = Readonly<\n Partial<Record<FormErrorKey<Values>, string>>\n>;\n\nexport type FormTouched<Values extends FormValues> = Readonly<\n Partial<Record<FormFieldName<Values>, boolean>>\n>;\n\nexport interface FormContract<Values extends FormValues, Encoded = Values> {\n readonly schema: Schema.Schema<Values, Encoded, never>;\n readonly defaults: Values;\n}\n\nexport const defineForm = <Values extends FormValues, Encoded = Values>(\n contract: FormContract<Values, Encoded>,\n): FormContract<Values, Encoded> => contract;\n\nexport interface FormState<Values extends FormValues> {\n readonly values: Values;\n readonly errors: FormErrors<Values>;\n readonly touched: FormTouched<Values>;\n readonly dirty: boolean;\n readonly submitting: boolean;\n readonly submitted: boolean;\n}\n\nexport type FormValidationResult<Values extends FormValues> =\n | {\n readonly _tag: \"valid\";\n readonly values: Values;\n }\n | {\n readonly _tag: \"invalid\";\n readonly errors: FormErrors<Values>;\n readonly issue: ParseResult.ParseError;\n };\n\nexport class FormValidationError<Values extends FormValues> extends Error {\n readonly _tag = \"FormValidationError\" as const;\n\n constructor(readonly errors: FormErrors<Values>) {\n super(\"Form validation failed\");\n this.name = \"FormValidationError\";\n }\n}\n\nexport type FormSubmitHandler<Values extends FormValues, A, E, R = never> = (\n values: Values,\n) => Effect.Effect<A, E, R>;\n\nexport interface FormStore<Values extends FormValues> {\n readonly getSnapshot: Effect.Effect<FormState<Values>, never, never>;\n readonly snapshots: Stream.Stream<FormState<Values>>;\n readonly setField: <Field extends FormFieldName<Values>>(\n field: Field,\n value: Values[Field],\n ) => Effect.Effect<void, never, never>;\n readonly reset: Effect.Effect<void, never, never>;\n readonly validate: Effect.Effect<FormValidationResult<Values>, never, never>;\n readonly submit: <A, E, R = never>(\n handler: FormSubmitHandler<Values, A, E, R>,\n ) => Effect.Effect<A, E | FormValidationError<Values>, R>;\n}\n","import { Effect, ParseResult, Schema, SubscriptionRef } from \"effect\";\nimport {\n type FormContract,\n type FormErrorKey,\n type FormErrors,\n type FormFieldName,\n type FormState,\n type FormStore,\n FormValidationError,\n type FormValidationResult,\n type FormValues,\n} from \"./types\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst cloneUnknown = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneUnknown(entry));\n }\n\n if (isRecord(value)) {\n const clone: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n clone[key] = cloneUnknown(entry);\n }\n return clone;\n }\n\n return value;\n};\n\nconst cloneValue = <A>(value: A): A => {\n return cloneUnknown(value) as A;\n};\n\nconst deepEqual = (left: unknown, right: unknown): boolean => {\n if (Object.is(left, right)) {\n return true;\n }\n\n if (Array.isArray(left) && Array.isArray(right)) {\n if (left.length !== right.length) {\n return false;\n }\n for (let index = 0; index < left.length; index += 1) {\n if (!deepEqual(left[index], right[index])) {\n return false;\n }\n }\n return true;\n }\n\n if (isRecord(left) && isRecord(right)) {\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n for (const key of leftKeys) {\n if (!(key in right)) {\n return false;\n }\n if (!deepEqual(left[key], right[key])) {\n return false;\n }\n }\n\n return true;\n }\n\n return false;\n};\n\nconst toFormErrors = <Values extends FormValues>(\n error: ParseResult.ParseError,\n fieldNames: ReadonlySet<string>,\n): FormErrors<Values> => {\n const formatted = ParseResult.ArrayFormatter.formatErrorSync(error);\n const errors: Partial<Record<FormErrorKey<Values>, string>> = {};\n\n for (const entry of formatted) {\n const root = entry.path[0];\n if (typeof root === \"string\" && fieldNames.has(root)) {\n const key = root as FormFieldName<Values>;\n errors[key] ??= entry.message;\n continue;\n }\n\n errors._form ??= entry.message;\n }\n\n if (formatted.length === 0 && errors._form === undefined) {\n errors._form = \"Invalid form values.\";\n }\n\n return errors;\n};\n\nconst createInitialState = <Values extends FormValues>(defaults: Values): FormState<Values> => ({\n values: cloneValue(defaults),\n errors: {} as FormErrors<Values>,\n touched: {} as FormState<Values>[\"touched\"],\n dirty: false,\n submitting: false,\n submitted: false,\n});\n\nexport const makeForm = <Values extends FormValues, Encoded = Values>(\n contract: FormContract<Values, Encoded>,\n): Effect.Effect<FormStore<Values>, never, never> =>\n Effect.gen(function* () {\n const decode = Schema.decodeUnknown(contract.schema, { errors: \"all\" });\n const defaults = cloneValue(contract.defaults);\n const fieldNames = new Set(Object.keys(defaults));\n const snapshots = yield* SubscriptionRef.make<FormState<Values>>(createInitialState(defaults));\n\n const validateCurrent = (\n current: FormState<Values>,\n ): Effect.Effect<FormValidationResult<Values>, never, never> =>\n decode(current.values).pipe(\n Effect.match({\n onFailure: (issue) => ({\n _tag: \"invalid\",\n errors: toFormErrors<Values>(issue, fieldNames),\n issue,\n }),\n onSuccess: (values) => ({\n _tag: \"valid\",\n values: cloneValue(values),\n }),\n }),\n );\n\n const setField: FormStore<Values>[\"setField\"] = (field, value) =>\n SubscriptionRef.update(snapshots, (current) => {\n const nextValues = {\n ...current.values,\n [field]: value,\n } as Values;\n\n const nextErrors: Partial<Record<FormErrorKey<Values>, string>> = {\n ...current.errors,\n };\n delete nextErrors[field];\n\n return {\n ...current,\n values: nextValues,\n errors: nextErrors,\n touched: {\n ...current.touched,\n [field]: true,\n },\n dirty: !deepEqual(nextValues, defaults),\n submitted: false,\n };\n }).pipe(Effect.asVoid);\n\n const reset: FormStore<Values>[\"reset\"] = SubscriptionRef.set(\n snapshots,\n createInitialState(defaults),\n ).pipe(Effect.asVoid);\n\n const validate: FormStore<Values>[\"validate\"] = Effect.gen(function* () {\n const current = yield* SubscriptionRef.get(snapshots);\n const result = yield* validateCurrent(current);\n\n if (result._tag === \"valid\") {\n yield* SubscriptionRef.update(snapshots, (snapshot) => ({\n ...snapshot,\n values: result.values,\n errors: {} as FormErrors<Values>,\n dirty: !deepEqual(result.values, defaults),\n }));\n } else {\n yield* SubscriptionRef.update(snapshots, (snapshot) => ({\n ...snapshot,\n errors: result.errors,\n }));\n }\n\n return result;\n });\n\n const submit: FormStore<Values>[\"submit\"] = (handler) =>\n Effect.gen(function* () {\n yield* SubscriptionRef.update(snapshots, (current) => ({\n ...current,\n submitting: true,\n submitted: false,\n }));\n\n const current = yield* SubscriptionRef.get(snapshots);\n const validation = yield* validateCurrent(current);\n\n if (validation._tag === \"invalid\") {\n yield* SubscriptionRef.update(snapshots, (snapshot) => ({\n ...snapshot,\n submitting: false,\n submitted: false,\n errors: validation.errors,\n }));\n\n return yield* Effect.fail(new FormValidationError(validation.errors));\n }\n\n yield* SubscriptionRef.update(snapshots, (snapshot) => ({\n ...snapshot,\n values: validation.values,\n errors: {} as FormErrors<Values>,\n dirty: !deepEqual(validation.values, defaults),\n }));\n\n return yield* handler(validation.values).pipe(\n Effect.tap(() =>\n SubscriptionRef.update(snapshots, (snapshot) => ({\n ...snapshot,\n submitting: false,\n submitted: true,\n })).pipe(Effect.asVoid),\n ),\n Effect.tapError(() =>\n SubscriptionRef.update(snapshots, (snapshot) => ({\n ...snapshot,\n submitting: false,\n submitted: false,\n })).pipe(Effect.asVoid),\n ),\n );\n });\n\n return {\n getSnapshot: SubscriptionRef.get(snapshots),\n snapshots: snapshots.changes,\n setField,\n reset,\n validate,\n submit,\n } satisfies FormStore<Values>;\n });\n","import { Effect, Fiber, Stream } from \"effect\";\nimport { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport { useEffectRuntime } from \"../react/provider\";\nimport { makeForm } from \"./service\";\nimport type {\n FormContract,\n FormFieldName,\n FormState,\n FormStore,\n FormSubmitHandler,\n FormValidationResult,\n FormValues,\n} from \"./types\";\n\nconst useFormStore = <Values extends FormValues, Encoded = Values>(\n contract: FormContract<Values, Encoded>,\n): FormStore<Values> => {\n const runtime = useEffectRuntime();\n return useMemo(() => runtime.runSync(makeForm(contract)), [contract, runtime]);\n};\n\nexport interface UseFormResult<Values extends FormValues> extends FormState<Values> {\n readonly commands: Pick<FormStore<Values>, \"setField\" | \"reset\" | \"validate\" | \"submit\">;\n readonly setField: <Field extends FormFieldName<Values>>(\n field: Field,\n value: Values[Field],\n ) => Promise<void>;\n readonly reset: () => Promise<void>;\n readonly validate: () => Promise<FormValidationResult<Values>>;\n readonly submit: <A, E>(handler: FormSubmitHandler<Values, A, E, never>) => Promise<A>;\n}\n\nexport const useForm = <Values extends FormValues, Encoded = Values>(\n contract: FormContract<Values, Encoded>,\n): UseFormResult<Values> => {\n const runtime = useEffectRuntime();\n const form = useFormStore(contract);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n const fiber = runtime.runFork(Stream.runForEach(form.snapshots, () => Effect.sync(listener)));\n\n return () => {\n runtime.runFork(Fiber.interrupt(fiber));\n };\n },\n [form, runtime],\n );\n\n const getSnapshot = useCallback(() => runtime.runSync(form.getSnapshot), [form, runtime]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const setField = useCallback<UseFormResult<Values>[\"setField\"]>(\n (field, value) => runtime.runPromise(form.setField(field, value)),\n [form, runtime],\n );\n\n const reset = useCallback<UseFormResult<Values>[\"reset\"]>(\n () => runtime.runPromise(form.reset),\n [form, runtime],\n );\n\n const validate = useCallback<UseFormResult<Values>[\"validate\"]>(\n () => runtime.runPromise(form.validate),\n [form, runtime],\n );\n\n const submit = useCallback<UseFormResult<Values>[\"submit\"]>(\n (handler) => runtime.runPromise(form.submit(handler)),\n [form, runtime],\n );\n\n return {\n ...snapshot,\n commands: {\n setField: form.setField,\n reset: form.reset,\n validate: form.validate,\n submit: form.submit,\n },\n setField,\n reset,\n validate,\n submit,\n };\n};\n"],"mappings":";;;;;AAqBO,IAAM,aAAa,CACxB,aACkC;AAsB7B,IAAM,sBAAN,cAA6D,MAAM;AAAA,EAGxE,YAAqB,QAA4B;AAC/C,UAAM,wBAAwB;AADX;AAEnB,SAAK,OAAO;AAAA,EACd;AAAA,EALS,OAAO;AAMlB;;;ACpDA,SAAS,QAAQ,aAAa,QAAQ,uBAAuB;AAa7D,IAAM,WAAW,CAAC,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,IAAM,eAAe,CAAC,UAA4B;AAChD,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,UAAU,aAAa,KAAK,CAAC;AAAA,EACjD;AAEA,MAAI,SAAS,KAAK,GAAG;AACnB,UAAM,QAAiC,CAAC;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAM,GAAG,IAAI,aAAa,KAAK;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,IAAM,aAAa,CAAI,UAAgB;AACrC,SAAO,aAAa,KAAK;AAC3B;AAEA,IAAM,YAAY,CAAC,MAAe,UAA4B;AAC5D,MAAI,OAAO,GAAG,MAAM,KAAK,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,KAAK,GAAG;AAC/C,QAAI,KAAK,WAAW,MAAM,QAAQ;AAChC,aAAO;AAAA,IACT;AACA,aAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAI,CAAC,UAAU,KAAK,KAAK,GAAG,MAAM,KAAK,CAAC,GAAG;AACzC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,IAAI,KAAK,SAAS,KAAK,GAAG;AACrC,UAAM,WAAW,OAAO,KAAK,IAAI;AACjC,UAAM,YAAY,OAAO,KAAK,KAAK;AAEnC,QAAI,SAAS,WAAW,UAAU,QAAQ;AACxC,aAAO;AAAA,IACT;AAEA,eAAW,OAAO,UAAU;AAC1B,UAAI,EAAE,OAAO,QAAQ;AACnB,eAAO;AAAA,MACT;AACA,UAAI,CAAC,UAAU,KAAK,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG;AACrC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,IAAM,eAAe,CACnB,OACA,eACuB;AACvB,QAAM,YAAY,YAAY,eAAe,gBAAgB,KAAK;AAClE,QAAM,SAAwD,CAAC;AAE/D,aAAW,SAAS,WAAW;AAC7B,UAAM,OAAO,MAAM,KAAK,CAAC;AACzB,QAAI,OAAO,SAAS,YAAY,WAAW,IAAI,IAAI,GAAG;AACpD,YAAM,MAAM;AACZ,aAAO,GAAG,MAAM,MAAM;AACtB;AAAA,IACF;AAEA,WAAO,UAAU,MAAM;AAAA,EACzB;AAEA,MAAI,UAAU,WAAW,KAAK,OAAO,UAAU,QAAW;AACxD,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAA4B,cAAyC;AAAA,EAC9F,QAAQ,WAAW,QAAQ;AAAA,EAC3B,QAAQ,CAAC;AAAA,EACT,SAAS,CAAC;AAAA,EACV,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,WAAW;AACb;AAEO,IAAM,WAAW,CACtB,aAEA,OAAO,IAAI,aAAa;AACtB,QAAM,SAAS,OAAO,cAAc,SAAS,QAAQ,EAAE,QAAQ,MAAM,CAAC;AACtE,QAAM,WAAW,WAAW,SAAS,QAAQ;AAC7C,QAAM,aAAa,IAAI,IAAI,OAAO,KAAK,QAAQ,CAAC;AAChD,QAAM,YAAY,OAAO,gBAAgB,KAAwB,mBAAmB,QAAQ,CAAC;AAE7F,QAAM,kBAAkB,CACtB,YAEA,OAAO,QAAQ,MAAM,EAAE;AAAA,IACrB,OAAO,MAAM;AAAA,MACX,WAAW,CAAC,WAAW;AAAA,QACrB,MAAM;AAAA,QACN,QAAQ,aAAqB,OAAO,UAAU;AAAA,QAC9C;AAAA,MACF;AAAA,MACA,WAAW,CAAC,YAAY;AAAA,QACtB,MAAM;AAAA,QACN,QAAQ,WAAW,MAAM;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACH;AAEF,QAAM,WAA0C,CAAC,OAAO,UACtD,gBAAgB,OAAO,WAAW,CAAC,YAAY;AAC7C,UAAM,aAAa;AAAA,MACjB,GAAG,QAAQ;AAAA,MACX,CAAC,KAAK,GAAG;AAAA,IACX;AAEA,UAAM,aAA4D;AAAA,MAChE,GAAG,QAAQ;AAAA,IACb;AACA,WAAO,WAAW,KAAK;AAEvB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,GAAG,QAAQ;AAAA,QACX,CAAC,KAAK,GAAG;AAAA,MACX;AAAA,MACA,OAAO,CAAC,UAAU,YAAY,QAAQ;AAAA,MACtC,WAAW;AAAA,IACb;AAAA,EACF,CAAC,EAAE,KAAK,OAAO,MAAM;AAEvB,QAAM,QAAoC,gBAAgB;AAAA,IACxD;AAAA,IACA,mBAAmB,QAAQ;AAAA,EAC7B,EAAE,KAAK,OAAO,MAAM;AAEpB,QAAM,WAA0C,OAAO,IAAI,aAAa;AACtE,UAAM,UAAU,OAAO,gBAAgB,IAAI,SAAS;AACpD,UAAM,SAAS,OAAO,gBAAgB,OAAO;AAE7C,QAAI,OAAO,SAAS,SAAS;AAC3B,aAAO,gBAAgB,OAAO,WAAW,CAAC,cAAc;AAAA,QACtD,GAAG;AAAA,QACH,QAAQ,OAAO;AAAA,QACf,QAAQ,CAAC;AAAA,QACT,OAAO,CAAC,UAAU,OAAO,QAAQ,QAAQ;AAAA,MAC3C,EAAE;AAAA,IACJ,OAAO;AACL,aAAO,gBAAgB,OAAO,WAAW,CAAC,cAAc;AAAA,QACtD,GAAG;AAAA,QACH,QAAQ,OAAO;AAAA,MACjB,EAAE;AAAA,IACJ;AAEA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,SAAsC,CAAC,YAC3C,OAAO,IAAI,aAAa;AACtB,WAAO,gBAAgB,OAAO,WAAW,CAACA,cAAa;AAAA,MACrD,GAAGA;AAAA,MACH,YAAY;AAAA,MACZ,WAAW;AAAA,IACb,EAAE;AAEF,UAAM,UAAU,OAAO,gBAAgB,IAAI,SAAS;AACpD,UAAM,aAAa,OAAO,gBAAgB,OAAO;AAEjD,QAAI,WAAW,SAAS,WAAW;AACjC,aAAO,gBAAgB,OAAO,WAAW,CAAC,cAAc;AAAA,QACtD,GAAG;AAAA,QACH,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,QAAQ,WAAW;AAAA,MACrB,EAAE;AAEF,aAAO,OAAO,OAAO,KAAK,IAAI,oBAAoB,WAAW,MAAM,CAAC;AAAA,IACtE;AAEA,WAAO,gBAAgB,OAAO,WAAW,CAAC,cAAc;AAAA,MACtD,GAAG;AAAA,MACH,QAAQ,WAAW;AAAA,MACnB,QAAQ,CAAC;AAAA,MACT,OAAO,CAAC,UAAU,WAAW,QAAQ,QAAQ;AAAA,IAC/C,EAAE;AAEF,WAAO,OAAO,QAAQ,WAAW,MAAM,EAAE;AAAA,MACvC,OAAO;AAAA,QAAI,MACT,gBAAgB,OAAO,WAAW,CAAC,cAAc;AAAA,UAC/C,GAAG;AAAA,UACH,YAAY;AAAA,UACZ,WAAW;AAAA,QACb,EAAE,EAAE,KAAK,OAAO,MAAM;AAAA,MACxB;AAAA,MACA,OAAO;AAAA,QAAS,MACd,gBAAgB,OAAO,WAAW,CAAC,cAAc;AAAA,UAC/C,GAAG;AAAA,UACH,YAAY;AAAA,UACZ,WAAW;AAAA,QACb,EAAE,EAAE,KAAK,OAAO,MAAM;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AAEH,SAAO;AAAA,IACL,aAAa,gBAAgB,IAAI,SAAS;AAAA,IAC1C,WAAW,UAAU;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF,CAAC;;;AClPH,SAAS,UAAAC,SAAQ,OAAO,cAAc;AACtC,SAAS,aAAa,SAAS,4BAA4B;AAa3D,IAAM,eAAe,CACnB,aACsB;AACtB,QAAM,UAAU,iBAAiB;AACjC,SAAO,QAAQ,MAAM,QAAQ,QAAQ,SAAS,QAAQ,CAAC,GAAG,CAAC,UAAU,OAAO,CAAC;AAC/E;AAaO,IAAM,UAAU,CACrB,aAC0B;AAC1B,QAAM,UAAU,iBAAiB;AACjC,QAAM,OAAO,aAAa,QAAQ;AAElC,QAAM,YAAY;AAAA,IAChB,CAAC,aAAyB;AACxB,YAAM,QAAQ,QAAQ,QAAQ,OAAO,WAAW,KAAK,WAAW,MAAMC,QAAO,KAAK,QAAQ,CAAC,CAAC;AAE5F,aAAO,MAAM;AACX,gBAAQ,QAAQ,MAAM,UAAU,KAAK,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,IACA,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,QAAM,cAAc,YAAY,MAAM,QAAQ,QAAQ,KAAK,WAAW,GAAG,CAAC,MAAM,OAAO,CAAC;AAExF,QAAM,WAAW,qBAAqB,WAAW,aAAa,WAAW;AAEzE,QAAM,WAAW;AAAA,IACf,CAAC,OAAO,UAAU,QAAQ,WAAW,KAAK,SAAS,OAAO,KAAK,CAAC;AAAA,IAChE,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,QAAM,QAAQ;AAAA,IACZ,MAAM,QAAQ,WAAW,KAAK,KAAK;AAAA,IACnC,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,QAAM,WAAW;AAAA,IACf,MAAM,QAAQ,WAAW,KAAK,QAAQ;AAAA,IACtC,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,QAAM,SAAS;AAAA,IACb,CAAC,YAAY,QAAQ,WAAW,KAAK,OAAO,OAAO,CAAC;AAAA,IACpD,CAAC,MAAM,OAAO;AAAA,EAChB;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU;AAAA,MACR,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["current","Effect","Effect"]}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/client/index.ts
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
defaultHydrationGlobalName: () => defaultHydrationGlobalName,
|
|
24
|
+
hydrateApp: () => hydrateApp
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(client_exports);
|
|
27
|
+
var import_effect5 = require("effect");
|
|
28
|
+
|
|
29
|
+
// src/render/hydration.ts
|
|
30
|
+
var import_effect4 = require("effect");
|
|
31
|
+
|
|
32
|
+
// src/boundary/codecs.ts
|
|
33
|
+
var import_effect = require("effect");
|
|
34
|
+
|
|
35
|
+
// src/boundary/errors.ts
|
|
36
|
+
var BoundaryDecodeError = class extends Error {
|
|
37
|
+
constructor(source, messageText, causeValue) {
|
|
38
|
+
super(`Boundary decode failed at ${source}: ${messageText}`);
|
|
39
|
+
this.source = source;
|
|
40
|
+
this.messageText = messageText;
|
|
41
|
+
this.causeValue = causeValue;
|
|
42
|
+
this.name = "BoundaryDecodeError";
|
|
43
|
+
}
|
|
44
|
+
_tag = "BoundaryDecodeError";
|
|
45
|
+
};
|
|
46
|
+
var BoundaryTransportError = class extends Error {
|
|
47
|
+
constructor(source, messageText, causeValue) {
|
|
48
|
+
super(`Boundary transport failed at ${source}: ${messageText}`);
|
|
49
|
+
this.source = source;
|
|
50
|
+
this.messageText = messageText;
|
|
51
|
+
this.causeValue = causeValue;
|
|
52
|
+
this.name = "BoundaryTransportError";
|
|
53
|
+
}
|
|
54
|
+
_tag = "BoundaryTransportError";
|
|
55
|
+
};
|
|
56
|
+
var BoundaryProtocolError = class extends Error {
|
|
57
|
+
constructor(source, messageText) {
|
|
58
|
+
super(`Boundary protocol violation at ${source}: ${messageText}`);
|
|
59
|
+
this.source = source;
|
|
60
|
+
this.messageText = messageText;
|
|
61
|
+
this.name = "BoundaryProtocolError";
|
|
62
|
+
}
|
|
63
|
+
_tag = "BoundaryProtocolError";
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// src/boundary/codecs.ts
|
|
67
|
+
var Boundary = class extends import_effect.Context.Tag("EffectReact/Boundary")() {
|
|
68
|
+
};
|
|
69
|
+
var parseErrorMessage = (error) => import_effect.Cause.pretty(import_effect.Cause.fail(error)).trim();
|
|
70
|
+
var makeBoundaryService = () => ({
|
|
71
|
+
decodeUnknown: ({ source, schema, value }) => import_effect.Schema.decodeUnknown(schema)(value).pipe(
|
|
72
|
+
import_effect.Effect.mapError(
|
|
73
|
+
(error) => new BoundaryDecodeError(source, parseErrorMessage(error), error)
|
|
74
|
+
)
|
|
75
|
+
),
|
|
76
|
+
decodeTextJson: ({ source, schema, text }) => import_effect.Effect.gen(function* () {
|
|
77
|
+
const payload = yield* import_effect.Effect.try({
|
|
78
|
+
try: () => JSON.parse(text),
|
|
79
|
+
catch: (cause) => new BoundaryTransportError(source, "failed to parse JSON payload", cause)
|
|
80
|
+
});
|
|
81
|
+
return yield* import_effect.Schema.decodeUnknown(schema)(payload).pipe(
|
|
82
|
+
import_effect.Effect.mapError(
|
|
83
|
+
(error) => new BoundaryDecodeError(source, parseErrorMessage(error), error)
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
}),
|
|
87
|
+
encode: ({ source, schema, value }) => import_effect.Schema.encode(schema)(value).pipe(
|
|
88
|
+
import_effect.Effect.mapError((error) => new BoundaryProtocolError(source, parseErrorMessage(error)))
|
|
89
|
+
)
|
|
90
|
+
});
|
|
91
|
+
var BoundaryLive = import_effect.Layer.succeed(Boundary, makeBoundaryService());
|
|
92
|
+
|
|
93
|
+
// src/data/service.ts
|
|
94
|
+
var import_effect2 = require("effect");
|
|
95
|
+
var Data = class extends import_effect2.Context.Tag("EffectReact/Data")() {
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/navigation/service.ts
|
|
99
|
+
var import_effect3 = require("effect");
|
|
100
|
+
|
|
101
|
+
// src/navigation/matcher.ts
|
|
102
|
+
var normalizePathname = (pathname) => {
|
|
103
|
+
if (pathname.length === 0) {
|
|
104
|
+
return "/";
|
|
105
|
+
}
|
|
106
|
+
const withSlash = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
107
|
+
if (withSlash.length > 1 && withSlash.endsWith("/")) {
|
|
108
|
+
return withSlash.slice(0, -1);
|
|
109
|
+
}
|
|
110
|
+
return withSlash;
|
|
111
|
+
};
|
|
112
|
+
var normalizeSearchText = (searchText) => {
|
|
113
|
+
if (searchText.length === 0 || searchText === "?") {
|
|
114
|
+
return "";
|
|
115
|
+
}
|
|
116
|
+
return searchText.startsWith("?") ? searchText : `?${searchText}`;
|
|
117
|
+
};
|
|
118
|
+
var parseHref = (href) => {
|
|
119
|
+
const [pathPart, ...searchParts] = href.split("?");
|
|
120
|
+
return {
|
|
121
|
+
pathname: normalizePathname(pathPart ?? "/"),
|
|
122
|
+
searchText: normalizeSearchText(searchParts.length === 0 ? "" : searchParts.join("?"))
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// src/navigation/service.ts
|
|
127
|
+
var Navigation = class extends import_effect3.Context.Tag("EffectReact/Navigation")() {
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// src/render/hydration.ts
|
|
131
|
+
var QuerySnapshotSchema = import_effect4.Schema.Struct({
|
|
132
|
+
key: import_effect4.Schema.String,
|
|
133
|
+
phase: import_effect4.Schema.Union(
|
|
134
|
+
import_effect4.Schema.Literal("initial"),
|
|
135
|
+
import_effect4.Schema.Literal("loading"),
|
|
136
|
+
import_effect4.Schema.Literal("success"),
|
|
137
|
+
import_effect4.Schema.Literal("failure")
|
|
138
|
+
),
|
|
139
|
+
data: import_effect4.Schema.NullishOr(import_effect4.Schema.Unknown),
|
|
140
|
+
error: import_effect4.Schema.NullishOr(import_effect4.Schema.Unknown),
|
|
141
|
+
updatedAt: import_effect4.Schema.NullishOr(import_effect4.Schema.Number)
|
|
142
|
+
});
|
|
143
|
+
var HydrationStateSchema = import_effect4.Schema.Struct({
|
|
144
|
+
version: import_effect4.Schema.Literal(1),
|
|
145
|
+
data: import_effect4.Schema.Array(import_effect4.Schema.Tuple(import_effect4.Schema.String, QuerySnapshotSchema)),
|
|
146
|
+
navigationHref: import_effect4.Schema.String
|
|
147
|
+
});
|
|
148
|
+
var hydrateAppState = (payload) => import_effect4.Effect.gen(function* () {
|
|
149
|
+
const boundary = yield* Boundary;
|
|
150
|
+
const data = yield* Data;
|
|
151
|
+
const navigation = yield* Navigation;
|
|
152
|
+
const decoded = yield* boundary.decodeUnknown({
|
|
153
|
+
source: "hydration:payload",
|
|
154
|
+
schema: HydrationStateSchema,
|
|
155
|
+
value: payload
|
|
156
|
+
});
|
|
157
|
+
const mapped = new Map(decoded.data);
|
|
158
|
+
yield* data.hydrateSnapshots(mapped);
|
|
159
|
+
const current = yield* navigation.getSnapshot;
|
|
160
|
+
const parsed = parseHref(decoded.navigationHref);
|
|
161
|
+
yield* navigation.hydrateSnapshot({
|
|
162
|
+
...current,
|
|
163
|
+
pathname: parsed.pathname,
|
|
164
|
+
searchText: parsed.searchText,
|
|
165
|
+
href: decoded.navigationHref,
|
|
166
|
+
status: "success",
|
|
167
|
+
match: null,
|
|
168
|
+
loaders: {},
|
|
169
|
+
error: void 0
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// src/client/index.ts
|
|
174
|
+
var defaultHydrationGlobalName = "__effectReactHydration";
|
|
175
|
+
var readGlobalHydrationPayload = (globalName) => {
|
|
176
|
+
const globalScope = globalThis;
|
|
177
|
+
return globalScope[globalName];
|
|
178
|
+
};
|
|
179
|
+
var hydrateApp = (options) => {
|
|
180
|
+
const payload = options.payload ?? readGlobalHydrationPayload(options.globalName ?? defaultHydrationGlobalName);
|
|
181
|
+
if (payload === void 0) {
|
|
182
|
+
return options.app.runtime.runPromise(import_effect5.Effect.void);
|
|
183
|
+
}
|
|
184
|
+
return options.app.runtime.runPromise(hydrateAppState(payload));
|
|
185
|
+
};
|
|
186
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
187
|
+
0 && (module.exports = {
|
|
188
|
+
defaultHydrationGlobalName,
|
|
189
|
+
hydrateApp
|
|
190
|
+
});
|
|
191
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts","../../src/render/hydration.ts","../../src/boundary/codecs.ts","../../src/boundary/errors.ts","../../src/data/service.ts","../../src/navigation/service.ts","../../src/navigation/matcher.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport type { EffectReactApp } from \"../framework\";\nimport { hydrateAppState } from \"../render\";\n\nexport interface HydrateAppOptions {\n readonly app: EffectReactApp;\n readonly payload?: unknown;\n readonly globalName?: string;\n}\n\nexport const defaultHydrationGlobalName = \"__effectReactHydration\";\n\nconst readGlobalHydrationPayload = (globalName: string): unknown => {\n const globalScope = globalThis as Record<string, unknown>;\n return globalScope[globalName];\n};\n\nexport const hydrateApp = (options: HydrateAppOptions): Promise<void> => {\n const payload =\n options.payload ??\n readGlobalHydrationPayload(options.globalName ?? defaultHydrationGlobalName);\n\n if (payload === undefined) {\n return options.app.runtime.runPromise(Effect.void);\n }\n\n return options.app.runtime.runPromise(hydrateAppState(payload));\n};\n","import { Effect, Schema } from \"effect\";\nimport { Boundary } from \"../boundary\";\nimport { Data } from \"../data/service\";\nimport type { QuerySnapshot } from \"../data/types\";\nimport { Navigation } from \"../navigation/service\";\nimport { parseHref } from \"../navigation/matcher\";\n\nexport interface HydrationState {\n readonly version: 1;\n readonly data: readonly (readonly [string, QuerySnapshot<unknown, unknown>])[];\n readonly navigationHref: string;\n}\n\nconst QuerySnapshotSchema = Schema.Struct({\n key: Schema.String,\n phase: Schema.Union(\n Schema.Literal(\"initial\"),\n Schema.Literal(\"loading\"),\n Schema.Literal(\"success\"),\n Schema.Literal(\"failure\"),\n ),\n data: Schema.NullishOr(Schema.Unknown),\n error: Schema.NullishOr(Schema.Unknown),\n updatedAt: Schema.NullishOr(Schema.Number),\n});\n\nexport const HydrationStateSchema = Schema.Struct({\n version: Schema.Literal(1),\n data: Schema.Array(Schema.Tuple(Schema.String, QuerySnapshotSchema)),\n navigationHref: Schema.String,\n});\n\nconst escapeForScript = (value: string): string =>\n value\n .replace(/</g, \"\\\\u003c\")\n .replace(/>/g, \"\\\\u003e\")\n .replace(/\\u2028/g, \"\\\\u2028\")\n .replace(/\\u2029/g, \"\\\\u2029\");\n\nexport const dehydrateAppState = (): Effect.Effect<HydrationState, never, Data | Navigation> =>\n Effect.gen(function* () {\n const data = yield* Data;\n const navigation = yield* Navigation;\n\n const snapshots = yield* data.getAllSnapshots;\n const navigationSnapshot = yield* navigation.getSnapshot;\n\n return {\n version: 1,\n data: Array.from(snapshots.entries()),\n navigationHref: navigationSnapshot.href,\n } satisfies HydrationState;\n });\n\nexport const createHydrationScript = (\n state: HydrationState,\n globalName = \"__effectReactHydration\",\n): string => {\n const serialized = JSON.stringify(state);\n return `window[${JSON.stringify(globalName)}]=JSON.parse(${JSON.stringify(escapeForScript(serialized))});`;\n};\n\nexport const hydrateAppState = (\n payload: unknown,\n): Effect.Effect<void, unknown, Boundary | Data | Navigation> =>\n Effect.gen(function* () {\n const boundary = yield* Boundary;\n const data = yield* Data;\n const navigation = yield* Navigation;\n\n const decoded = yield* boundary.decodeUnknown({\n source: \"hydration:payload\",\n schema: HydrationStateSchema,\n value: payload,\n });\n\n const mapped = new Map<string, QuerySnapshot<unknown, unknown>>(decoded.data);\n yield* data.hydrateSnapshots(mapped);\n\n const current = yield* navigation.getSnapshot;\n const parsed = parseHref(decoded.navigationHref);\n\n yield* navigation.hydrateSnapshot({\n ...current,\n pathname: parsed.pathname,\n searchText: parsed.searchText,\n href: decoded.navigationHref,\n status: \"success\",\n match: null,\n loaders: {},\n error: undefined,\n });\n });\n","import { Cause, Context, Effect, Layer, Schema } from \"effect\";\nimport type { ParseResult } from \"effect\";\nimport {\n BoundaryDecodeError,\n BoundaryProtocolError,\n BoundaryTransportError,\n type BoundaryError,\n} from \"./errors\";\n\nexport interface BoundaryService {\n readonly decodeUnknown: <A, I>(options: {\n readonly source: string;\n readonly schema: Schema.Schema<A, I, never>;\n readonly value: unknown;\n }) => Effect.Effect<A, BoundaryDecodeError, never>;\n readonly decodeTextJson: <A, I>(options: {\n readonly source: string;\n readonly schema: Schema.Schema<A, I, never>;\n readonly text: string;\n }) => Effect.Effect<A, BoundaryError, never>;\n readonly encode: <A, I>(options: {\n readonly source: string;\n readonly schema: Schema.Schema<A, I, never>;\n readonly value: A;\n }) => Effect.Effect<I, BoundaryError, never>;\n}\n\nexport class Boundary extends Context.Tag(\"EffectReact/Boundary\")<Boundary, BoundaryService>() {}\n\nconst parseErrorMessage = (error: ParseResult.ParseError): string =>\n Cause.pretty(Cause.fail(error)).trim();\n\nexport const makeBoundaryService = (): BoundaryService => ({\n decodeUnknown: ({ source, schema, value }) =>\n Schema.decodeUnknown(schema)(value).pipe(\n Effect.mapError(\n (error) => new BoundaryDecodeError(source, parseErrorMessage(error), error),\n ),\n ),\n decodeTextJson: ({ source, schema, text }) =>\n Effect.gen(function* () {\n const payload = yield* Effect.try({\n try: () => JSON.parse(text) as unknown,\n catch: (cause) =>\n new BoundaryTransportError(source, \"failed to parse JSON payload\", cause),\n });\n\n return yield* Schema.decodeUnknown(schema)(payload).pipe(\n Effect.mapError(\n (error) => new BoundaryDecodeError(source, parseErrorMessage(error), error),\n ),\n );\n }),\n encode: ({ source, schema, value }) =>\n Schema.encode(schema)(value).pipe(\n Effect.mapError((error) => new BoundaryProtocolError(source, parseErrorMessage(error))),\n ),\n});\n\nexport const BoundaryLive = Layer.succeed(Boundary, makeBoundaryService());\n\nexport const decodeUnknown = <A, I>(options: {\n readonly source: string;\n readonly schema: Schema.Schema<A, I, never>;\n readonly value: unknown;\n}): Effect.Effect<A, BoundaryDecodeError, Boundary> =>\n Effect.flatMap(Boundary, (service) => service.decodeUnknown(options));\n\nexport const decodeTextJson = <A, I>(options: {\n readonly source: string;\n readonly schema: Schema.Schema<A, I, never>;\n readonly text: string;\n}): Effect.Effect<A, BoundaryError, Boundary> =>\n Effect.flatMap(Boundary, (service) => service.decodeTextJson(options));\n\nexport const encode = <A, I>(options: {\n readonly source: string;\n readonly schema: Schema.Schema<A, I, never>;\n readonly value: A;\n}): Effect.Effect<I, BoundaryError, Boundary> =>\n Effect.flatMap(Boundary, (service) => service.encode(options));\n","import type { ParseResult } from \"effect\";\n\nexport class BoundaryDecodeError extends Error {\n readonly _tag = \"BoundaryDecodeError\" as const;\n\n constructor(\n readonly source: string,\n readonly messageText: string,\n readonly causeValue?: ParseResult.ParseError,\n ) {\n super(`Boundary decode failed at ${source}: ${messageText}`);\n this.name = \"BoundaryDecodeError\";\n }\n}\n\nexport class BoundaryTransportError extends Error {\n readonly _tag = \"BoundaryTransportError\" as const;\n\n constructor(\n readonly source: string,\n readonly messageText: string,\n readonly causeValue?: unknown,\n ) {\n super(`Boundary transport failed at ${source}: ${messageText}`);\n this.name = \"BoundaryTransportError\";\n }\n}\n\nexport class BoundaryProtocolError extends Error {\n readonly _tag = \"BoundaryProtocolError\" as const;\n\n constructor(\n readonly source: string,\n readonly messageText: string,\n ) {\n super(`Boundary protocol violation at ${source}: ${messageText}`);\n this.name = \"BoundaryProtocolError\";\n }\n}\n\nexport type BoundaryError = BoundaryDecodeError | BoundaryTransportError | BoundaryProtocolError;\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","import {\n Cause,\n Context,\n Effect,\n Fiber,\n Layer,\n Option,\n Ref,\n type Schema,\n type Stream,\n SubscriptionRef,\n} from \"effect\";\nimport { Boundary } from \"../boundary\";\nimport { Telemetry } from \"../kernel/telemetry\";\nimport { buildHref, matchRoute, normalizeSearchText, parseHref } from \"./matcher\";\nimport {\n type AnyLoaderDefinition,\n type AnyRouteDefinition,\n type LoaderSnapshotEntry,\n NavigationCancelledError,\n type NavigationSnapshot,\n NavigationRuntimeError,\n} from \"./types\";\nimport type { NavigationError } from \"./types\";\n\nconst describeUnknown = (value: unknown): string => {\n if (value instanceof Error) {\n return `${value.name}: ${value.message}`;\n }\n if (typeof value === \"string\") {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n};\n\nconst initialSnapshot: NavigationSnapshot = {\n pathname: \"/\",\n searchText: \"\",\n href: \"/\",\n status: \"idle\",\n match: null,\n loaders: {},\n error: undefined,\n};\n\nconst toLoadersByName = (loaders: readonly AnyLoaderDefinition[]): ReadonlyMap<string, AnyLoaderDefinition> =>\n new Map(loaders.map((loader) => [loader.name, loader] as const));\n\nconst planLoaderBatches = (\n loaders: readonly AnyLoaderDefinition[],\n): Effect.Effect<readonly (readonly AnyLoaderDefinition[])[], NavigationRuntimeError, never> => {\n const byName = toLoadersByName(loaders);\n const depthByName = new Map<string, number>();\n const visiting = new Set<string>();\n\n const resolveDepth = (name: string): Effect.Effect<number, NavigationRuntimeError, never> => {\n const cached = depthByName.get(name);\n if (cached !== undefined) {\n return Effect.succeed(cached);\n }\n\n if (visiting.has(name)) {\n return Effect.fail(new NavigationRuntimeError(`Cyclic loader dependency detected at ${name}`));\n }\n\n const loader = byName.get(name);\n if (loader === undefined) {\n return Effect.fail(new NavigationRuntimeError(`Loader dependency '${name}' is not registered`));\n }\n\n visiting.add(name);\n\n const dependencies = loader.dependsOn ?? [];\n return Effect.forEach(dependencies, resolveDepth).pipe(\n Effect.map((depths) => {\n const depth = depths.length === 0 ? 0 : Math.max(...depths) + 1;\n depthByName.set(name, depth);\n visiting.delete(name);\n return depth;\n }),\n Effect.catchAll((error) => {\n visiting.delete(name);\n return Effect.fail(error);\n }),\n );\n };\n\n return Effect.gen(function* () {\n const entries = yield* Effect.forEach(loaders, (loader) =>\n Effect.map(resolveDepth(loader.name), (depth) => [depth, loader] as const),\n );\n\n const grouped = new Map<number, AnyLoaderDefinition[]>();\n for (const [depth, loader] of entries) {\n const existing = grouped.get(depth);\n if (existing === undefined) {\n grouped.set(depth, [loader]);\n } else {\n existing.push(loader);\n }\n }\n\n const depths = Array.from(grouped.keys()).sort((a, b) => a - b);\n return depths.map((depth) => grouped.get(depth) ?? []);\n });\n};\n\nexport interface NavigationService {\n readonly navigate: (href: string) => Effect.Effect<NavigationSnapshot, NavigationError, never>;\n readonly revalidate: () => Effect.Effect<NavigationSnapshot, NavigationError, never>;\n readonly getSnapshot: Effect.Effect<NavigationSnapshot, never, never>;\n readonly hydrateSnapshot: (snapshot: NavigationSnapshot) => Effect.Effect<void, never, never>;\n readonly snapshots: Stream.Stream<NavigationSnapshot>;\n}\n\nexport class Navigation extends Context.Tag(\"EffectReact/Navigation\")<\n Navigation,\n NavigationService\n>() {}\n\nexport interface MakeNavigationLayerOptions {\n readonly routes: readonly AnyRouteDefinition[];\n readonly loaders?: readonly AnyLoaderDefinition[];\n readonly initialHref?: string;\n}\n\nexport const makeNavigationLayer = (\n options: MakeNavigationLayerOptions,\n): Layer.Layer<Navigation, never, Boundary | Telemetry> => {\n const loaders = options.loaders ?? [];\n const initial = parseHref(options.initialHref ?? \"/\");\n\n return Layer.effect(\n Navigation,\n Effect.gen(function* () {\n const boundary = yield* Boundary;\n const telemetry = yield* Telemetry;\n const snapshotsRef = yield* SubscriptionRef.make<NavigationSnapshot>({\n ...initialSnapshot,\n pathname: initial.pathname,\n searchText: initial.searchText,\n href: buildHref(initial.pathname, initial.searchText),\n });\n const activeFiberRef = yield* Ref.make<Option.Option<Fiber.RuntimeFiber<NavigationSnapshot, NavigationError>>>(Option.none());\n\n const runLoaders = (\n snapshot: NavigationSnapshot,\n ): Effect.Effect<Readonly<Record<string, LoaderSnapshotEntry>>, NavigationRuntimeError, never> =>\n Effect.gen(function* () {\n if (snapshot.match === null) {\n return {};\n }\n\n const routeLoaders = loaders.filter((loader) => loader.routeId === snapshot.match!.route.id);\n if (routeLoaders.length === 0) {\n return {};\n }\n\n const batches = yield* planLoaderBatches(routeLoaders);\n const results: Record<string, unknown> = {};\n const states: Record<string, LoaderSnapshotEntry> = {};\n\n for (const loader of routeLoaders) {\n states[loader.name] = { _tag: \"pending\" };\n }\n\n yield* SubscriptionRef.update(snapshotsRef, (current) => ({\n ...current,\n loaders: {\n ...current.loaders,\n ...states,\n },\n }));\n\n for (const batch of batches) {\n const exits = yield* Effect.all(\n batch.map((loader) => {\n const base = loader.run({\n route: snapshot.match!.route,\n pathname: snapshot.pathname,\n searchText: snapshot.searchText,\n params: snapshot.match!.params,\n search: snapshot.match!.search,\n dependencyResults: results,\n });\n\n const withRetry = loader.retry ? Effect.retry(base, loader.retry) : base;\n return Effect.exit(withRetry).pipe(Effect.map((exit) => [loader, exit] as const));\n }),\n {\n concurrency: \"unbounded\",\n },\n );\n\n for (const [loader, exit] of exits) {\n if (exit._tag === \"Success\") {\n results[loader.name] = exit.value;\n states[loader.name] = {\n _tag: \"success\",\n value: exit.value,\n };\n continue;\n }\n\n const failure = Cause.failureOption(exit.cause);\n states[loader.name] = {\n _tag: \"failure\",\n error: failure._tag === \"Some\" ? failure.value : Cause.pretty(exit.cause),\n };\n\n yield* SubscriptionRef.update(snapshotsRef, (current) => ({\n ...current,\n status: \"failure\",\n loaders: {\n ...current.loaders,\n ...states,\n },\n error: states[loader.name],\n }) satisfies NavigationSnapshot);\n\n return yield* Effect.fail(\n new NavigationRuntimeError(`Loader '${loader.name}' failed for route '${snapshot.match!.route.id}'`),\n );\n }\n\n yield* SubscriptionRef.update(snapshotsRef, (current) => ({\n ...current,\n loaders: {\n ...current.loaders,\n ...states,\n },\n }) satisfies NavigationSnapshot);\n }\n\n return states;\n });\n\n const performNavigation = (\n href: string,\n ): Effect.Effect<NavigationSnapshot, NavigationError, never> =>\n Effect.gen(function* () {\n const { pathname, searchText } = parseHref(href);\n const searchParams = new URLSearchParams(searchText);\n\n const candidate = options.routes.find((route) => matchRoute({\n routes: [route],\n pathname,\n search: {},\n }) !== null);\n\n const decodedSearch =\n candidate?.search === undefined\n ? Effect.succeed({} as unknown)\n : boundary.decodeUnknown({\n source: `route:${candidate.id}:search`,\n schema: candidate.search as Schema.Schema<unknown, unknown, never>,\n value: Object.fromEntries(searchParams.entries()),\n });\n\n const search = yield* decodedSearch;\n const matched = matchRoute({\n routes: options.routes,\n pathname,\n search,\n });\n\n if (matched === null) {\n return yield* Effect.fail(\n new NavigationRuntimeError(`No route matched pathname '${pathname}'`),\n );\n }\n\n yield* telemetry.emit({\n _tag: \"navigation\",\n phase: \"start\",\n pathname,\n routeId: matched.route.id,\n timestamp: Date.now(),\n });\n\n const loadingSnapshot: NavigationSnapshot = {\n pathname,\n searchText: normalizeSearchText(searchText),\n href: buildHref(pathname, normalizeSearchText(searchText)),\n status: \"loading\",\n match: matched,\n loaders: {},\n error: undefined,\n };\n\n yield* SubscriptionRef.set(snapshotsRef, loadingSnapshot);\n\n const loaderStates = yield* runLoaders(loadingSnapshot);\n\n const completed: NavigationSnapshot = {\n ...loadingSnapshot,\n status: \"success\",\n loaders: loaderStates,\n error: undefined,\n };\n\n yield* SubscriptionRef.set(snapshotsRef, completed);\n yield* telemetry.emit({\n _tag: \"navigation\",\n phase: \"success\",\n pathname,\n routeId: matched.route.id,\n timestamp: Date.now(),\n });\n\n return completed;\n });\n\n const navigate: NavigationService[\"navigate\"] = (href) =>\n Effect.gen(function* () {\n const previous = yield* Ref.getAndSet(activeFiberRef, Option.none());\n if (Option.isSome(previous)) {\n yield* Fiber.interrupt(previous.value);\n yield* telemetry.emit({\n _tag: \"navigation\",\n phase: \"cancel\",\n pathname: href,\n timestamp: Date.now(),\n });\n }\n\n const fiber = yield* Effect.fork(performNavigation(href));\n yield* Ref.set(activeFiberRef, Option.some(fiber));\n\n const exit = yield* Effect.exit(Fiber.join(fiber));\n\n const current = yield* Ref.get(activeFiberRef);\n if (Option.isSome(current) && current.value === fiber) {\n yield* Ref.set(activeFiberRef, Option.none());\n }\n\n if (exit._tag === \"Success\") {\n return exit.value;\n }\n\n if (Cause.isInterruptedOnly(exit.cause)) {\n return yield* Effect.fail(new NavigationCancelledError(href));\n }\n\n const failure = Cause.failureOption(exit.cause);\n if (failure._tag === \"Some\") {\n return yield* Effect.fail(\n failure.value instanceof NavigationRuntimeError\n ? failure.value\n : new NavigationRuntimeError(describeUnknown(failure.value)),\n );\n }\n\n return yield* Effect.fail(new NavigationRuntimeError(Cause.pretty(exit.cause)));\n }).pipe(\n Effect.tapError((error) =>\n telemetry.emit({\n _tag: \"navigation\",\n phase: \"failure\",\n pathname: href,\n timestamp: Date.now(),\n detail: error,\n }),\n ),\n );\n\n const revalidate: NavigationService[\"revalidate\"] =\n () =>\n Effect.gen(function* () {\n const snapshot = yield* SubscriptionRef.get(snapshotsRef);\n return yield* navigate(snapshot.href);\n });\n\n return {\n navigate,\n revalidate,\n getSnapshot: SubscriptionRef.get(snapshotsRef),\n hydrateSnapshot: (snapshot) => SubscriptionRef.set(snapshotsRef, snapshot),\n snapshots: snapshotsRef.changes,\n } satisfies NavigationService;\n }),\n );\n};\n\nexport const navigateTo = (\n href: string,\n): Effect.Effect<NavigationSnapshot, NavigationError, Navigation> =>\n Effect.flatMap(Navigation, (service) => service.navigate(href));\n","import type { AnyRouteDefinition, RouteMatch } from \"./types\";\n\nconst normalizePathname = (pathname: string): string => {\n if (pathname.length === 0) {\n return \"/\";\n }\n const withSlash = pathname.startsWith(\"/\") ? pathname : `/${pathname}`;\n if (withSlash.length > 1 && withSlash.endsWith(\"/\")) {\n return withSlash.slice(0, -1);\n }\n return withSlash;\n};\n\nconst scoreRoute = (path: string): number => {\n if (path === \"/\") {\n return 10;\n }\n return path\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .reduce((score, segment) => {\n if (segment === \"*\") {\n return score;\n }\n if (segment.startsWith(\":\")) {\n return score + 2;\n }\n return score + 5;\n }, 0);\n};\n\nconst splitSegments = (path: string): readonly string[] =>\n normalizePathname(path)\n .split(\"/\")\n .filter((segment) => segment.length > 0);\n\nconst matchRoutePath = (\n routePath: string,\n pathname: string,\n): Readonly<Record<string, string>> | null => {\n const routeSegments = splitSegments(routePath);\n const pathSegments = splitSegments(pathname);\n\n const params: Record<string, string> = {};\n let i = 0;\n let j = 0;\n\n while (i < routeSegments.length && j < pathSegments.length) {\n const routeSegment = routeSegments[i]!;\n const pathSegment = pathSegments[j]!;\n\n if (routeSegment === \"*\") {\n return params;\n }\n\n if (routeSegment.startsWith(\":\")) {\n params[routeSegment.slice(1)] = decodeURIComponent(pathSegment);\n i += 1;\n j += 1;\n continue;\n }\n\n if (routeSegment !== pathSegment) {\n return null;\n }\n\n i += 1;\n j += 1;\n }\n\n if (i < routeSegments.length && routeSegments[i] === \"*\") {\n return params;\n }\n\n if (i !== routeSegments.length || j !== pathSegments.length) {\n return null;\n }\n\n return params;\n};\n\nexport interface MatchInput {\n readonly routes: readonly AnyRouteDefinition[];\n readonly pathname: string;\n readonly search: unknown;\n}\n\nexport const matchRoute = ({ routes, pathname, search }: MatchInput): RouteMatch<AnyRouteDefinition> | null => {\n const normalized = normalizePathname(pathname);\n const sorted = [...routes].sort((a, b) => scoreRoute(b.path) - scoreRoute(a.path));\n\n for (const route of sorted) {\n const params = matchRoutePath(route.path, normalized);\n if (params !== null) {\n return {\n route,\n pathname: normalized,\n params,\n search,\n };\n }\n }\n\n return null;\n};\n\nexport const buildHref = (pathname: string, searchText: string): string =>\n searchText.length > 0 ? `${normalizePathname(pathname)}${searchText}` : normalizePathname(pathname);\n\nexport const normalizeSearchText = (searchText: string): string => {\n if (searchText.length === 0 || searchText === \"?\") {\n return \"\";\n }\n return searchText.startsWith(\"?\") ? searchText : `?${searchText}`;\n};\n\nexport const parseHref = (href: string): { readonly pathname: string; readonly searchText: string } => {\n const [pathPart, ...searchParts] = href.split(\"?\");\n return {\n pathname: normalizePathname(pathPart ?? \"/\"),\n searchText: normalizeSearchText(searchParts.length === 0 ? \"\" : searchParts.join(\"?\")),\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,iBAAuB;;;ACAvB,IAAAC,iBAA+B;;;ACA/B,oBAAsD;;;ACE/C,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAG7C,YACW,QACA,aACA,YACT;AACA,UAAM,6BAA6B,MAAM,KAAK,WAAW,EAAE;AAJlD;AACA;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EATS,OAAO;AAUlB;AAEO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAGhD,YACW,QACA,aACA,YACT;AACA,UAAM,gCAAgC,MAAM,KAAK,WAAW,EAAE;AAJrD;AACA;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EATS,OAAO;AAUlB;AAEO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAG/C,YACW,QACA,aACT;AACA,UAAM,kCAAkC,MAAM,KAAK,WAAW,EAAE;AAHvD;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EARS,OAAO;AASlB;;;ADXO,IAAM,WAAN,cAAuB,sBAAQ,IAAI,sBAAsB,EAA6B,EAAE;AAAC;AAEhG,IAAM,oBAAoB,CAAC,UACzB,oBAAM,OAAO,oBAAM,KAAK,KAAK,CAAC,EAAE,KAAK;AAEhC,IAAM,sBAAsB,OAAwB;AAAA,EACzD,eAAe,CAAC,EAAE,QAAQ,QAAQ,MAAM,MACtC,qBAAO,cAAc,MAAM,EAAE,KAAK,EAAE;AAAA,IAClC,qBAAO;AAAA,MACL,CAAC,UAAU,IAAI,oBAAoB,QAAQ,kBAAkB,KAAK,GAAG,KAAK;AAAA,IAC5E;AAAA,EACF;AAAA,EACF,gBAAgB,CAAC,EAAE,QAAQ,QAAQ,KAAK,MACtC,qBAAO,IAAI,aAAa;AACtB,UAAM,UAAU,OAAO,qBAAO,IAAI;AAAA,MAChC,KAAK,MAAM,KAAK,MAAM,IAAI;AAAA,MAC1B,OAAO,CAAC,UACN,IAAI,uBAAuB,QAAQ,gCAAgC,KAAK;AAAA,IAC5E,CAAC;AAED,WAAO,OAAO,qBAAO,cAAc,MAAM,EAAE,OAAO,EAAE;AAAA,MAClD,qBAAO;AAAA,QACL,CAAC,UAAU,IAAI,oBAAoB,QAAQ,kBAAkB,KAAK,GAAG,KAAK;AAAA,MAC5E;AAAA,IACF;AAAA,EACF,CAAC;AAAA,EACH,QAAQ,CAAC,EAAE,QAAQ,QAAQ,MAAM,MAC/B,qBAAO,OAAO,MAAM,EAAE,KAAK,EAAE;AAAA,IAC3B,qBAAO,SAAS,CAAC,UAAU,IAAI,sBAAsB,QAAQ,kBAAkB,KAAK,CAAC,CAAC;AAAA,EACxF;AACJ;AAEO,IAAM,eAAe,oBAAM,QAAQ,UAAU,oBAAoB,CAAC;;;AE3DzE,IAAAC,iBAOO;AAqEA,IAAM,OAAN,cAAmB,uBAAQ,IAAI,kBAAkB,EAAqB,EAAE;AAAC;;;AC5EhF,IAAAC,iBAWO;;;ACTP,IAAM,oBAAoB,CAAC,aAA6B;AACtD,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,EACT;AACA,QAAM,YAAY,SAAS,WAAW,GAAG,IAAI,WAAW,IAAI,QAAQ;AACpE,MAAI,UAAU,SAAS,KAAK,UAAU,SAAS,GAAG,GAAG;AACnD,WAAO,UAAU,MAAM,GAAG,EAAE;AAAA,EAC9B;AACA,SAAO;AACT;AAkGO,IAAM,sBAAsB,CAAC,eAA+B;AACjE,MAAI,WAAW,WAAW,KAAK,eAAe,KAAK;AACjD,WAAO;AAAA,EACT;AACA,SAAO,WAAW,WAAW,GAAG,IAAI,aAAa,IAAI,UAAU;AACjE;AAEO,IAAM,YAAY,CAAC,SAA6E;AACrG,QAAM,CAAC,UAAU,GAAG,WAAW,IAAI,KAAK,MAAM,GAAG;AACjD,SAAO;AAAA,IACL,UAAU,kBAAkB,YAAY,GAAG;AAAA,IAC3C,YAAY,oBAAoB,YAAY,WAAW,IAAI,KAAK,YAAY,KAAK,GAAG,CAAC;AAAA,EACvF;AACF;;;ADHO,IAAM,aAAN,cAAyB,uBAAQ,IAAI,wBAAwB,EAGlE,EAAE;AAAC;;;AJ7GL,IAAM,sBAAsB,sBAAO,OAAO;AAAA,EACxC,KAAK,sBAAO;AAAA,EACZ,OAAO,sBAAO;AAAA,IACZ,sBAAO,QAAQ,SAAS;AAAA,IACxB,sBAAO,QAAQ,SAAS;AAAA,IACxB,sBAAO,QAAQ,SAAS;AAAA,IACxB,sBAAO,QAAQ,SAAS;AAAA,EAC1B;AAAA,EACA,MAAM,sBAAO,UAAU,sBAAO,OAAO;AAAA,EACrC,OAAO,sBAAO,UAAU,sBAAO,OAAO;AAAA,EACtC,WAAW,sBAAO,UAAU,sBAAO,MAAM;AAC3C,CAAC;AAEM,IAAM,uBAAuB,sBAAO,OAAO;AAAA,EAChD,SAAS,sBAAO,QAAQ,CAAC;AAAA,EACzB,MAAM,sBAAO,MAAM,sBAAO,MAAM,sBAAO,QAAQ,mBAAmB,CAAC;AAAA,EACnE,gBAAgB,sBAAO;AACzB,CAAC;AAgCM,IAAM,kBAAkB,CAC7B,YAEA,sBAAO,IAAI,aAAa;AACtB,QAAM,WAAW,OAAO;AACxB,QAAM,OAAO,OAAO;AACpB,QAAM,aAAa,OAAO;AAE1B,QAAM,UAAU,OAAO,SAAS,cAAc;AAAA,IAC5C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,EACT,CAAC;AAED,QAAM,SAAS,IAAI,IAA6C,QAAQ,IAAI;AAC5E,SAAO,KAAK,iBAAiB,MAAM;AAEnC,QAAM,UAAU,OAAO,WAAW;AAClC,QAAM,SAAS,UAAU,QAAQ,cAAc;AAE/C,SAAO,WAAW,gBAAgB;AAAA,IAChC,GAAG;AAAA,IACH,UAAU,OAAO;AAAA,IACjB,YAAY,OAAO;AAAA,IACnB,MAAM,QAAQ;AAAA,IACd,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,SAAS,CAAC;AAAA,IACV,OAAO;AAAA,EACT,CAAC;AACH,CAAC;;;ADlFI,IAAM,6BAA6B;AAE1C,IAAM,6BAA6B,CAAC,eAAgC;AAClE,QAAM,cAAc;AACpB,SAAO,YAAY,UAAU;AAC/B;AAEO,IAAM,aAAa,CAAC,YAA8C;AACvE,QAAM,UACJ,QAAQ,WACR,2BAA2B,QAAQ,cAAc,0BAA0B;AAE7E,MAAI,YAAY,QAAW;AACzB,WAAO,QAAQ,IAAI,QAAQ,WAAW,sBAAO,IAAI;AAAA,EACnD;AAEA,SAAO,QAAQ,IAAI,QAAQ,WAAW,gBAAgB,OAAO,CAAC;AAChE;","names":["import_effect","import_effect","import_effect","import_effect"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { EffectReactApp } from "../framework";
|
|
2
|
+
export interface HydrateAppOptions {
|
|
3
|
+
readonly app: EffectReactApp;
|
|
4
|
+
readonly payload?: unknown;
|
|
5
|
+
readonly globalName?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const defaultHydrationGlobalName = "__effectReactHydration";
|
|
8
|
+
export declare const hydrateApp: (options: HydrateAppOptions) => Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultHydrationGlobalName,
|
|
3
|
+
hydrateApp
|
|
4
|
+
} from "../chunk-M2CJG6T7.js";
|
|
5
|
+
import "../chunk-IVIYY6S5.js";
|
|
6
|
+
import "../chunk-C5JI7D7W.js";
|
|
7
|
+
import "../chunk-O7XTA7H3.js";
|
|
8
|
+
import "../chunk-YG22YP5K.js";
|
|
9
|
+
import "../chunk-SKC3HMF3.js";
|
|
10
|
+
export {
|
|
11
|
+
defaultHydrationGlobalName,
|
|
12
|
+
hydrateApp
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|