@weftui/core 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,630 @@
1
+ import { E as Source, T as NoPropValue, a as SVGElements, r as Renderable, s as HTMLElements, t as ElementDescriptor } from "./index-B8idtfB3.js";
2
+ import { Cause, Context, Effect, Option, Stream, Subscribable } from "effect";
3
+ import { Rpc } from "@effect/rpc";
4
+ import { YieldWrap } from "effect/Utils";
5
+
6
+ //#region src/combinator/types.d.ts
7
+ /**
8
+ * Widens a single prop value type so that Stream/Effect/Subscribable variants
9
+ * accept any E and R — not just `never`. Static values (string, number, etc.)
10
+ * are left unchanged. TypeScript distributes this over union types.
11
+ */
12
+ type OpenPropSource<T> = T extends Stream.Stream<infer A, any, any> ? Stream.Stream<A, any, any> : T extends Effect.Effect<infer A, any, any> ? Effect.Effect<A, any, any> : T extends Subscribable.Subscribable<infer A, any, any> ? Subscribable.Subscribable<A, any, any> : T;
13
+ /**
14
+ * A node in the combinator tree.
15
+ * IS an Effect — `yield*`, `Effect.gen`, and `pipe` all work natively. Resolves
16
+ * to an {@link ElementDescriptor}.
17
+ *
18
+ * Declared as an interface (rather than a bare alias) so it can merge with the
19
+ * {@link Node} namespace below, exposing Effect-style channel accessors
20
+ * (`Node.Error` / `Node.Context`). An empty interface extending
21
+ * `Effect.Effect<ElementDescriptor, E, R>` is structurally identical to the alias
22
+ * it replaces, so `yield*`, `pipe`, and `Effect.gen` interop are unaffected.
23
+ */
24
+ interface Node<E = never, R = never> extends Effect.Effect<ElementDescriptor, E, R> {}
25
+ /**
26
+ * Channel accessors for {@link Node}, mirroring Effect's
27
+ * `Effect.Effect.Success`/`Error`/`Context`. A `Node`'s success channel is fixed
28
+ * to {@link ElementDescriptor}, so only the error and requirement channels carry
29
+ * information worth extracting.
30
+ */
31
+ declare namespace Node {
32
+ /** Extract the error channel `E` from a {@link Node} (a static node ⇒ `never`). */
33
+ type Error<N> = [N] extends [Effect.Effect<any, infer E, any>] ? E : never;
34
+ /** Extract the requirement channel `R` from a {@link Node} (a static node ⇒ `never`). */
35
+ type Context<N> = [N] extends [Effect.Effect<any, any, infer R>] ? R : never;
36
+ }
37
+ /** Extract E from a props object — Stream/Effect/Subscribable prop values contribute their E channel. */
38
+ type PropsE<P> = { [K in keyof P]: P[K] extends Stream.Stream<any, infer E, any> ? E : P[K] extends Effect.Effect<any, infer E, any> ? E : P[K] extends Subscribable.Subscribable<any, infer E, any> ? E : never }[keyof P];
39
+ /** Extract R from a props object — Stream/Effect/Subscribable prop values contribute their R channel. */
40
+ type PropsR<P> = { [K in keyof P]: P[K] extends Stream.Stream<any, any, infer R> ? R : P[K] extends Effect.Effect<any, any, infer R> ? R : P[K] extends Subscribable.Subscribable<any, any, infer R> ? R : never }[keyof P];
41
+ /** Extract E from a children array — Node (Effect) and Stream children contribute their E. */
42
+ type ChildrenE<T extends readonly Renderable[]> = [T[number]] extends [never] ? never : { [K in keyof T]: T[K] extends Effect.Effect<any, infer E, any> ? E : T[K] extends Stream.Stream<any, infer E, any> ? E : never }[number];
43
+ /** Extract R from a children array — Node (Effect) and Stream children contribute their R. */
44
+ type ChildrenR<T extends readonly Renderable[]> = [T[number]] extends [never] ? never : { [K in keyof T]: T[K] extends Effect.Effect<any, any, infer R> ? R : T[K] extends Stream.Stream<any, any, infer R> ? R : never }[number];
45
+ /**
46
+ * Strip `children` from HTML prop types and widen all Source prop types to
47
+ * allow any E/R — so callers can pass `Stream<T, E, R>` with real requirements.
48
+ */
49
+ type CombinatorialProps<P> = { [K in keyof Omit<P, "children">]: OpenPropSource<Omit<P, "children">[K]> };
50
+ //#endregion
51
+ //#region src/boundary/rpc-client.d.ts
52
+ /**
53
+ * Ambient, package-neutral seam for resolving a {@link Boundary.rpc} boundary's
54
+ * data through the application's merged `RpcGroup`. The DOM renderer
55
+ * (`@weftui/dom`) must resolve a boundary — on the server (SSR), during a
56
+ * client refetch, and on a client-first SPA mount — **without** importing
57
+ * `@effect/rpc` or `@weftui/router`. So the rpc caller is injected as a
58
+ * service: `@weftui/router` provides it (a network `RpcClient` on the browser,
59
+ * an in-process client over the handler layer on the server), and the renderer
60
+ * reads it from ambient context, treating `Option.none` (no router/rpc present)
61
+ * as a typed, descriptive error.
62
+ *
63
+ * The seam is **flat and untyped at the boundary**: a single `call(tag, payload)`
64
+ * that mirrors `RpcClient`'s flat-client shape (`(tag, payload) => Effect<success>`).
65
+ * The renderer carries the rpc's `successSchema`/`errorSchema` on the descriptor
66
+ * and owns decoding, so this seam stays free of `@effect/rpc` types.
67
+ */
68
+ interface AppRpcClient {
69
+ /**
70
+ * Invoke the rpc identified by `tag` with `payload`, resolving to its decoded
71
+ * `success` value. The error channel is opaque (`unknown`): the renderer maps a
72
+ * resolved rpc **error** onto the boundary's typed-failure replay (SSR) or its
73
+ * resource's stale-on-error channel (refetch), while transport defects surface
74
+ * the same way. `payload` is the rpc's decoded payload value (already the shape
75
+ * the rpc's `payloadSchema` describes), not a serialized envelope.
76
+ */
77
+ readonly call: (tag: string, payload: unknown) => Effect.Effect<unknown, unknown>;
78
+ }
79
+ declare const AppRpcClientTag_base: Context.TagClass<AppRpcClientTag, "@weftui/core/AppRpcClient", AppRpcClient>;
80
+ /**
81
+ * Context tag for the {@link AppRpcClient} seam. Provided by `@weftui/router`
82
+ * — a network client (`RouterLive`, POST `/_eui/rpc`) on the client, an
83
+ * in-process client over the handler layer (`RouterServer`) on the server. Absent
84
+ * in a router-less mount, where a {@link Boundary.rpc} resolves to a descriptive
85
+ * "needs router/rpc" error.
86
+ */
87
+ declare class AppRpcClientTag extends AppRpcClientTag_base {}
88
+ //#endregion
89
+ //#region src/boundary/index.d.ts
90
+ /**
91
+ * Unique type tag used by renderers to identify a failure `Boundary` descriptor.
92
+ * All variants embed this symbol as `type` in the returned descriptor.
93
+ */
94
+ declare const FAILURE_BOUNDARY: unique symbol;
95
+ /**
96
+ * Unique type tag used by renderers to identify a suspense `Boundary` descriptor.
97
+ * All `Boundary.suspend` embeds this symbol as `type` in the returned descriptor.
98
+ */
99
+ declare const SUSPENSE_BOUNDARY: unique symbol;
100
+ /**
101
+ * Unique type tag used by renderers to identify a server `Boundary` descriptor.
102
+ * Every `Boundary.rpc` embeds this symbol as `type` in the returned descriptor.
103
+ */
104
+ declare const SERVER_BOUNDARY: unique symbol;
105
+ /** Remove a single tagged error from the children's error union. */
106
+ type CatchTagE<C extends readonly Renderable[], Tag extends string> = Exclude<ChildrenE<C>, {
107
+ _tag: Tag;
108
+ }>;
109
+ /** Remove multiple tagged errors from the children's error union. */
110
+ type CatchTagsE<C extends readonly Renderable[], Tags extends string> = Exclude<ChildrenE<C>, {
111
+ _tag: Tags;
112
+ }>;
113
+ /**
114
+ * Boundary namespace encapsulating failure and suspense boundaries. Each
115
+ * variant wraps a subtree and shows a fallback in response to an event.
116
+ *
117
+ * - **Failure boundaries** (`catchAll`, `catchAllCause`, `catchTag`,
118
+ * `catchTags`, `catchSome`, `catchIf`) intercept rendering-path errors —
119
+ * construction-time errors and post-mount stream failures — mirroring
120
+ * Effect's `catch*` combinators.
121
+ * - **Suspense boundary** (`suspend`) shows a fallback while async children are
122
+ * pending, then swaps to the resolved children once all have settled.
123
+ *
124
+ * Each variant returns a plain `{ type, props }` descriptor tagged with
125
+ * {@link FAILURE_BOUNDARY} or {@link SUSPENSE_BOUNDARY}; the renderer detects it
126
+ * synchronously via the `{ type, props }` branch.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * import { Boundary, h } from "@weftui/core";
131
+ *
132
+ * // Failure boundary wrapping a suspense boundary — the common pairing:
133
+ * Boundary.catchAll({ fallback: (e) => h.div({}, e.message) }, [
134
+ * Boundary.suspend({ fallback: h.div({}, "Loading…") }, [AsyncCard()]),
135
+ * ])
136
+ * ```
137
+ */
138
+ declare namespace Boundary {
139
+ /**
140
+ * Internal descriptor props shared by the failure `Boundary.*` variants
141
+ * (everything except {@link suspend}). The renderer reads `match` to decide
142
+ * how to handle a caught error.
143
+ */
144
+ interface FailureProps {
145
+ /**
146
+ * Called with the caught `Cause`. Returns a fallback `Node` if this boundary
147
+ * handles the error, or `null` to re-raise to a parent boundary.
148
+ */
149
+ readonly match: (cause: Cause.Cause<unknown>) => Node<unknown, unknown> | null;
150
+ }
151
+ /**
152
+ * Props for the {@link suspend} boundary — used by renderers to access
153
+ * `fallback` and `children` from the node descriptor.
154
+ */
155
+ interface SuspenseProps {
156
+ /**
157
+ * Shown in the DOM while async children are pending. Pass `null` or omit to
158
+ * render nothing (only the comment markers) while pending.
159
+ */
160
+ readonly fallback?: Renderable;
161
+ }
162
+ /**
163
+ * Catch all typed failures (not defects). The children's `E` is fully
164
+ * consumed; the output `E` is only the fallback's error channel.
165
+ */
166
+ function catchAll<C extends readonly Renderable[], FE = never, FR = never>(props: {
167
+ readonly fallback: (e: ChildrenE<C>) => Node<FE, FR>;
168
+ }, children: C): Node<FE, ChildrenR<C> | FR>;
169
+ /**
170
+ * Catch all causes including defects and interruptions. The children's `E`
171
+ * is fully consumed; the output `E` is only the fallback's error channel.
172
+ */
173
+ function catchAllCause<C extends readonly Renderable[], FE = never, FR = never>(props: {
174
+ readonly fallback: (cause: Cause.Cause<ChildrenE<C>>) => Node<FE, FR>;
175
+ }, children: C): Node<FE, ChildrenR<C> | FR>;
176
+ /**
177
+ * Catch errors whose `_tag` matches `props.tag`. The matched tag is removed
178
+ * from the output `E`; unmatched errors are re-raised.
179
+ */
180
+ function catchTag<C extends readonly Renderable[], Tag extends (ChildrenE<C> extends {
181
+ _tag: string;
182
+ } ? ChildrenE<C>["_tag"] : string), FE = never, FR = never>(props: {
183
+ readonly tag: Tag;
184
+ readonly fallback: (e: Extract<ChildrenE<C>, {
185
+ _tag: Tag;
186
+ }>) => Node<FE, FR>;
187
+ }, children: C): Node<CatchTagE<C, Tag> | FE, ChildrenR<C> | FR>;
188
+ /**
189
+ * Catch errors whose `_tag` matches a key in the handlers record. Each
190
+ * matched tag is removed from the output `E`; unmatched errors are re-raised.
191
+ * The handlers record IS the first argument (no wrapping object).
192
+ */
193
+ function catchTags<C extends readonly Renderable[], Handlers extends { readonly [Tag in ChildrenE<C> extends {
194
+ _tag: string;
195
+ } ? ChildrenE<C>["_tag"] : never]?: (e: Extract<ChildrenE<C>, {
196
+ _tag: Tag;
197
+ }>) => Node<any, any> }>(handlers: Handlers, children: C): Node<CatchTagsE<C, keyof Handlers & string> | { [K in keyof Handlers]: Handlers[K] extends ((e: any) => Node<infer E, any>) ? E : never }[keyof Handlers], ChildrenR<C> | { [K in keyof Handlers]: Handlers[K] extends ((e: any) => Node<any, infer R>) ? R : never }[keyof Handlers]>;
198
+ /**
199
+ * Conditionally catch — the fallback returns `Option`. If it returns
200
+ * `Option.none()`, the error is re-raised. The children's `E` is preserved
201
+ * in the output since the boundary may not handle any given error.
202
+ */
203
+ function catchSome<C extends readonly Renderable[], FE = never, FR = never>(props: {
204
+ readonly fallback: (e: ChildrenE<C>) => Option.Option<Node<FE, FR>>;
205
+ }, children: C): Node<ChildrenE<C> | FE, ChildrenR<C> | FR>;
206
+ /**
207
+ * Conditionally catch — a predicate gates the fallback. If the predicate
208
+ * returns `false`, the error is re-raised. The children's `E` is preserved
209
+ * in the output since the boundary may not handle any given error.
210
+ */
211
+ function catchIf<C extends readonly Renderable[], FE = never, FR = never>(props: {
212
+ readonly predicate: (e: ChildrenE<C>) => boolean;
213
+ readonly fallback: (e: ChildrenE<C>) => Node<FE, FR>;
214
+ }, children: C): Node<ChildrenE<C> | FE, ChildrenR<C> | FR>;
215
+ /**
216
+ * Creates a suspense boundary node.
217
+ *
218
+ * Shows `fallback` while async children are pending (have not yet emitted
219
+ * their first value), then atomically swaps to the resolved children once
220
+ * **all** pending children have settled.
221
+ *
222
+ * The renderer (`@weftui/dom`) identifies the boundary via its
223
+ * {@link SUSPENSE_BOUNDARY} type tag.
224
+ *
225
+ * @example
226
+ * ```ts
227
+ * import { Boundary, h } from "@weftui/core";
228
+ *
229
+ * Boundary.suspend({ fallback: h.div({}, "Loading…") }, [AsyncCard(), AsyncSidebar()])
230
+ * ```
231
+ */
232
+ function suspend<C extends readonly Renderable[]>(props: SuspenseProps, children: C): Node<ChildrenE<C>, ChildrenR<C>>;
233
+ /**
234
+ * Reactive handle handed to a {@link rpc} boundary's `render`. After
235
+ * hydrate the region is no longer inert: `value` is seeded with the SSR
236
+ * payload and the client can {@link Resource.refetch} the same data on demand,
237
+ * patching the rendered subtree in place via the renderer's existing
238
+ * reactive-child machinery.
239
+ *
240
+ * On the **server** and on the **first client paint after hydrate** `value`
241
+ * emits the SSR `data` first (await-first), so SSR HTML and the adopted DOM are
242
+ * byte-identical — no fallback flash.
243
+ *
244
+ * @typeParam A - The loaded data shape.
245
+ */
246
+ interface Resource<A> {
247
+ /**
248
+ * The current data. Seeded with the SSR `data`; a successful refetch pushes
249
+ * the new value here so the subtree patches in place.
250
+ */
251
+ readonly value: Subscribable.Subscribable<A>;
252
+ /**
253
+ * Triggers an rpc-backed reload (client only; a no-op on the server). Calls
254
+ * {@link AppRpcClient.call} with the boundary's rpc `tag` and a fresh
255
+ * `payload()`, then sets {@link Resource.value} with the decoded success.
256
+ */
257
+ readonly refetch: Effect.Effect<void>;
258
+ /** `true` while a refetch is in flight (`false` on the server / before any refetch). */
259
+ readonly pending: Subscribable.Subscribable<boolean>;
260
+ /**
261
+ * `Some` with the last refetch error, else `None`. A failed refetch leaves
262
+ * the previous `value` intact (stale-on-error) — it does **not** unmount the
263
+ * subtree or raise into an enclosing failure `Boundary`.
264
+ */
265
+ readonly error: Subscribable.Subscribable<Option.Option<unknown>>;
266
+ }
267
+ /**
268
+ * Options for the {@link rpc} boundary.
269
+ */
270
+ interface RpcOptions {
271
+ /**
272
+ * Shown between the boundary's comment markers while a **client-first** mount
273
+ * (no SSR payload present) resolves the rpc. Unused on the SSR/hydrate path,
274
+ * where the seeded payload renders directly with no fallback flash. Pass
275
+ * `null` or omit to render nothing while pending.
276
+ */
277
+ readonly fallback?: Renderable;
278
+ }
279
+ /**
280
+ * Creates an rpc-backed server render boundary.
281
+ *
282
+ * The boundary is a thin consumer of one `Rpc` from the application's merged
283
+ * `RpcGroup`. Its data source is the ambient {@link AppRpcClient}: there is no
284
+ * co-located `load`, no `provide`, no per-boundary `id`/registry — the rpc
285
+ * **tag** is the stable identity and the rpc **payload schema** is the typed
286
+ * input. The handler lives in the server-only rpc Layer, so nothing here needs a
287
+ * bundler prune.
288
+ *
289
+ * - **SSR**: the server renderer calls `AppRpcClient.call(tag, payload())`
290
+ * (an in-process client over the handler Layer), encodes the success through
291
+ * the rpc's `successSchema` inline as a `<script type="application/json">`
292
+ * payload, and renders `render(seededResource)` to HTML in place.
293
+ * - **Hydrate**: reads the inline payload at the cursor, decodes via
294
+ * `successSchema`, seeds the {@link Resource}, and adopts the DOM — replaying
295
+ * the server result, never re-calling the rpc.
296
+ * - **Refetch**: `Resource.refetch` calls `AppRpcClient.call(tag, payload())`
297
+ * over the network and patches the subtree in place (stale-on-error).
298
+ * - **Client-first mount** (SPA navigation, no SSR payload): renders `fallback`,
299
+ * forks an `AppRpcClient.call(tag, payload())`, then swaps in
300
+ * `render(resource)` once it resolves.
301
+ *
302
+ * `payload` is a thunk so a fresh payload is produced per call (SSR, refetch,
303
+ * mount) — its return type is the rpc's decoded payload. The renderer identifies
304
+ * the boundary via its {@link SERVER_BOUNDARY} type tag.
305
+ *
306
+ * @example
307
+ * ```ts
308
+ * import { Boundary, h } from "@weftui/core";
309
+ * import { Rpc, RpcGroup } from "@effect/rpc";
310
+ * import { Schema } from "effect";
311
+ *
312
+ * const StockRpcs = RpcGroup.make(
313
+ * Rpc.make("GetStock", { payload: { id: Schema.String }, success: Stock }),
314
+ * );
315
+ *
316
+ * Boundary.rpc(
317
+ * StockRpcs.requests.GetStock,
318
+ * () => ({ id: product.id }),
319
+ * (resource) => h.div({}, resource.value),
320
+ * { fallback: h.div({}, "Loading stock…") },
321
+ * )
322
+ * ```
323
+ */
324
+ function rpc<R extends Rpc.Any, C extends Node<any, any>>(rpc: R, payload: () => Rpc.Payload<R>, render: (resource: Resource<Rpc.Success<R>>) => C, options?: RpcOptions): Node<Node.Error<C> | Rpc.Error<R>, Node.Context<C>>;
325
+ }
326
+ //#endregion
327
+ //#region src/server/brand.d.ts
328
+ /**
329
+ * Type-level marker stamped onto the identifier of a {@link ServerTag}. It never
330
+ * exists at runtime — only its `typeof` is referenced by {@link ServerOnly} — so
331
+ * the brand is purely a compile-time discriminator for {@link AssertNoServerOnly}.
332
+ */
333
+ declare const ServerOnlyTypeId: unique symbol;
334
+ /**
335
+ * Brand intersected into a {@link ServerTag}'s identifier. Any requirement `R`
336
+ * that contains a value of this type carries a server-only dependency, which
337
+ * {@link AssertNoServerOnly} rejects when `R` reaches client code (`hydrate`).
338
+ */
339
+ interface ServerOnly {
340
+ readonly [ServerOnlyTypeId]: typeof ServerOnlyTypeId;
341
+ }
342
+ /**
343
+ * Compile-error sentinel returned by {@link AssertNoServerOnly} when a
344
+ * server-only dependency leaks into a client requirement channel. It is a string
345
+ * literal type (not a tag the user can satisfy) so that constraining `R` against
346
+ * it surfaces a readable error at the call site.
347
+ */
348
+ type ServerOnlyLeak = "A server-only Tag (ServerTag) leaked into the client requirement channel R. Discharge it on the server via Boundary.server's `provide`.";
349
+ /**
350
+ * A `Context.Tag` whose identifier carries the {@link ServerOnly} brand.
351
+ *
352
+ * Use it exactly like `Context.Tag` for services that must only ever be provided
353
+ * on the server (e.g. a database handle behind a `Boundary.server` `load`):
354
+ *
355
+ * ```ts
356
+ * class Database extends ServerTag("Database")<Database, DatabaseShape>() {}
357
+ * ```
358
+ *
359
+ * The brand rides along in the requirement channel `R` of any effect that uses
360
+ * the tag. {@link Boundary.server}'s required `provide` discharges it on the
361
+ * server, and {@link AssertNoServerOnly} rejects it should it ever reach
362
+ * `hydrate` on the client.
363
+ */
364
+ declare const ServerTag: <const Id extends string>(id: Id) => <Self, Shape>() => Context.TagClass<Self & ServerOnly, Id, Shape>;
365
+ /**
366
+ * Passes `R` through unchanged when it contains no {@link ServerOnly} dependency,
367
+ * or resolves to the {@link ServerOnlyLeak} compile-error sentinel when it does.
368
+ *
369
+ * Applied to the requirement channel of `hydrate`'s app node so that a
370
+ * server-only `ServerTag` accidentally referenced in client (`render`) code is a
371
+ * compile error rather than a silent runtime failure.
372
+ */
373
+ type AssertNoServerOnly<R> = [Extract<R, ServerOnly>] extends [never] ? R : ServerOnlyLeak;
374
+ //#endregion
375
+ //#region src/stream/stream.d.ts
376
+ /**
377
+ * Type guard for Effect `Stream` values. Uses `any` for the error and
378
+ * requirements channels so it matches streams regardless of `E`/`R`.
379
+ */
380
+ declare function isStream(value: unknown): value is Stream.Stream<unknown, any, any>;
381
+ /**
382
+ * Normalizes a static value, `Effect`, or `Stream` into a `Stream` — the
383
+ * weft equivalent of Vue's `unref`. Static values become a single-element
384
+ * stream, Effects become a one-shot stream, and existing Streams pass through
385
+ * unchanged.
386
+ */
387
+ declare function toStream<A>(value: A | Effect.Effect<A> | Stream.Stream<A>): Stream.Stream<A>;
388
+ //#endregion
389
+ //#region src/combinator/element.d.ts
390
+ /** Augmentable interface for user-defined custom element tags and props. */
391
+ interface CustomElements {}
392
+ /**
393
+ * Callable type for an element builder (one per tag — `h.div`, `h.span`, …).
394
+ *
395
+ * Four call shapes are supported; each preserves the caller's prop and child
396
+ * `E`/`R` channels on the returned {@link Node}:
397
+ *
398
+ * - `el(props, children)` — props plus an array of children.
399
+ * - `el(props, child)` — props plus a single `string | number` child.
400
+ * - `el(props)` — props only, no children.
401
+ * - `el(children)` — children only, no props.
402
+ * - `el()` — no arguments; yields a `Node<never, never>`.
403
+ */
404
+ interface ElementFn<Props> {
405
+ <P extends Props, C extends readonly Renderable[]>(props: P, children: C): Node<PropsE<P> | ChildrenE<C>, PropsR<P> | ChildrenR<C>>;
406
+ <P extends Props>(props: P, child: string | number): Node<PropsE<P>, PropsR<P>>;
407
+ <P extends Props>(props: P): Node<PropsE<P>, PropsR<P>>;
408
+ <C extends readonly Renderable[]>(children: C): Node<ChildrenE<C>, ChildrenR<C>>;
409
+ (child: string | number): Node<never, never>;
410
+ (): Node<never, never>;
411
+ }
412
+ type DataAttributes = {
413
+ [attr: `data-${string}`]: Source.Source<string | number | undefined>;
414
+ };
415
+ type H = {
416
+ /**
417
+ * Builds a fragment node containing the given children — children are rendered
418
+ * inline, with no wrapping element. Equivalent to `<>…</>` in JSX. `E`/`R`
419
+ * from the children accumulate on the returned {@link Node}.
420
+ *
421
+ * @example
422
+ * ```ts
423
+ * h.fragment([h.span({}, "left"), h.span({}, "right")]);
424
+ * ```
425
+ */
426
+ fragment<C extends readonly Renderable[]>(children: C): Node<ChildrenE<C>, ChildrenR<C>>;
427
+ } & { [K in keyof HTMLElements]: ElementFn<CombinatorialProps<HTMLElements[K] & DataAttributes>> } & { [K in keyof SVGElements]: ElementFn<CombinatorialProps<SVGElements[K] & DataAttributes>> } & { [K in keyof CustomElements]: ElementFn<CustomElements[K] & DataAttributes> };
428
+ /**
429
+ * Builds an `h` proxy backed by the given cache. Each tag access lazily creates
430
+ * an `ElementFn` and memoizes it in the cache, so repeat accesses return the
431
+ * same function reference. Exposed primarily to allow tests to observe an
432
+ * isolated cache; production code should use the module-level `h`.
433
+ */
434
+ declare const h: H;
435
+ //#endregion
436
+ //#region src/combinator/descriptor.d.ts
437
+ /**
438
+ * Builds a static-markup {@link Node} for a known {@link ElementDescriptor}.
439
+ *
440
+ * The result is a normal `Effect.succeed(descriptor)` — fully `yield*`-able
441
+ * inside `Component.gen` and indistinguishable to Effect — but additionally
442
+ * carries the descriptor on a non-enumerable property. Renderers detect this via
443
+ * {@link getElementDescriptor} and render the descriptor directly, with no
444
+ * `runSync` probe (the reason `h.*`, `h.fragment`, and `Boundary.*` never need to
445
+ * be executed to be identified).
446
+ */
447
+ declare function elementNode<E = never, R = never>(descriptor: ElementDescriptor): Node<E, R>;
448
+ /**
449
+ * Reads the {@link ElementDescriptor} carried by a static-markup {@link Node}
450
+ * built with {@link elementNode}, or `undefined` if `node` is anything else
451
+ * (a primitive, an iterable, a `Stream`, or a reactive `Effect`).
452
+ *
453
+ * Renderers call this to take the static fast path — rendering the descriptor
454
+ * directly — before falling back to running genuinely reactive Effects.
455
+ */
456
+ declare function getElementDescriptor(node: unknown): ElementDescriptor | undefined;
457
+ //#endregion
458
+ //#region src/combinator/fragment.d.ts
459
+ /** Unique symbol identifying fragment nodes. */
460
+ declare const FRAGMENT: unique symbol;
461
+ //#endregion
462
+ //#region src/combinator/list.d.ts
463
+ /**
464
+ * Unique symbol identifying keyed-list nodes built by {@link List.each}. The
465
+ * renderer special-cases descriptors carrying this `type`, mirroring how
466
+ * `FRAGMENT` and the `Boundary` symbols are detected.
467
+ */
468
+ declare const LIST: unique symbol;
469
+ /** Element type carried by a list source — the element type of the emitted `Iterable`. */
470
+ type ItemOf<S> = Source.Success<S> extends Iterable<infer T> ? T : never;
471
+ /**
472
+ * Keyed-list combinator namespace. The opt-in alternative to wholesale child
473
+ * rebuilds: items are rendered once per key and reconciled across emissions.
474
+ */
475
+ declare namespace List {
476
+ /**
477
+ * Options for {@link each}.
478
+ *
479
+ * @typeParam S - The `of` source type (drives item/`E`/`R` inference).
480
+ * @typeParam K - The key type produced by `by` (defaults to the item type).
481
+ */
482
+ interface Options<S, K> {
483
+ /**
484
+ * The list source: a static `Iterable<T>`, or an `Effect`/`Stream`/
485
+ * `Subscribable` of one. Each emission is materialized to an array to fix
486
+ * order, then reconciled by key.
487
+ */
488
+ readonly of: S;
489
+ /**
490
+ * Projects an item to its reconciliation key, compared via Effect `Equal`
491
+ * and hashed via `Hash`. Omitted ⇒ identity is the item itself. Use a
492
+ * stable `t => t.id`; `(_, i) => i` is the index-key footgun (see specs).
493
+ */
494
+ readonly by?: (item: ItemOf<S>, index: number) => K;
495
+ }
496
+ /**
497
+ * Declares a keyed reactive list region.
498
+ *
499
+ * `render` runs **once per key**; a persisted key keeps its DOM nodes and its
500
+ * running subscription fibers across re-emits (it is never re-invoked). The
501
+ * returned node's `E`/`R` are the union of the source channels and the
502
+ * channels of the node `render` returns.
503
+ *
504
+ * @example
505
+ * ```ts
506
+ * List.each(
507
+ * { of: peopleStream, by: (p) => p.id },
508
+ * (person) => h.li({}, person.name),
509
+ * );
510
+ * ```
511
+ */
512
+ function each<S extends Source.Source<Iterable<any>, any, any>, CE = never, CR = never, K = ItemOf<S>>(options: Options<S, K>, render: (item: ItemOf<S>, index: number) => Node<CE, CR>): Node<Source.Error<S> | CE, Source.Context<S> | CR>;
513
+ /**
514
+ * Extract the error channel `E` from a list {@link Node} — re-exported from
515
+ * {@link Node.Error}, the canonical accessor (a `Node`'s success channel is
516
+ * fixed to `ElementDescriptor`, so only `Error`/`Context` are exposed here).
517
+ */
518
+ type Error<N> = Node.Error<N>;
519
+ /**
520
+ * Extract the requirement channel `R` from a list {@link Node} — re-exported
521
+ * from {@link Node.Context}, the canonical accessor.
522
+ */
523
+ type Context<N> = Node.Context<N>;
524
+ }
525
+ //#endregion
526
+ //#region src/combinator/component.d.ts
527
+ /**
528
+ * Factories for building custom components whose returned `Node`s carry the
529
+ * caller's prop `E`/`R` channels and the component's own internal `E`/`R`.
530
+ *
531
+ * Two flavours are provided:
532
+ *
533
+ * - `Component.gen` — body is a generator (use `yield*` like `Effect.gen`).
534
+ * - `Component.make` — body is a plain function returning any `Effect`.
535
+ *
536
+ * Both accept an optional second `children` argument which may be either an
537
+ * array of {@link Renderable} or a function `(input) => readonly Renderable[]` (the
538
+ * render-prop / function-children pattern).
539
+ */
540
+ declare namespace Component {
541
+ /**
542
+ * Shape of the optional `children` argument to a {@link Component}.
543
+ *
544
+ * - `readonly Renderable[]` — a flat list of children, the common case.
545
+ * - `(input: Input) => readonly Renderable[]` — function-children: the component
546
+ * supplies `input` (some scoped value) and the caller returns the children
547
+ * array. Useful for render-prop / slot patterns.
548
+ */
549
+ type Children<Input = never> = readonly Renderable[] | ((input: Input) => readonly Renderable[]);
550
+ /**
551
+ * Extract the error channel `E` from the {@link Node} a component produces —
552
+ * re-exported from {@link Node.Error}, the canonical accessor. Apply to a
553
+ * component's return type, e.g. `Component.Error<ReturnType<typeof MyComponent>>`.
554
+ */
555
+ type Error<N> = Node.Error<N>;
556
+ /**
557
+ * Extract the requirement channel `R` from the {@link Node} a component
558
+ * produces — re-exported from {@link Node.Context}, the canonical accessor.
559
+ */
560
+ type Context<N> = Node.Context<N>;
561
+ /**
562
+ * The callable shape returned by {@link gen} and {@link make}. Generic over
563
+ * the caller's specific `GenP`/`GenC` so reactive prop values and reactive
564
+ * children contribute their `E`/`R` to the resulting `Node` at the call site.
565
+ *
566
+ * For function-children, `ChildrenE`/`ChildrenR` are extracted from the
567
+ * function's `ReturnType` — the array the caller would produce — not from
568
+ * the function itself.
569
+ */
570
+ type Component<P, C extends Children, E, R> = <GenP extends P, GenC extends C>(props: GenP, children?: GenC) => Node<PropsE<GenP> | ChildrenE<GenC extends ((...args: any[]) => any) ? ReturnType<GenC> : GenC> | E, PropsR<GenP> | ChildrenR<GenC extends ((...args: any[]) => any) ? ReturnType<GenC> : GenC> | R>;
571
+ /**
572
+ * Defines a component whose body is an `Effect.gen`-style generator.
573
+ *
574
+ * The internal `E`/`R` are inferred from any `yield*`ed effects. Caller prop
575
+ * `E`/`R` and children `E`/`R` are unioned in at the call site.
576
+ *
577
+ * @example
578
+ * ```ts
579
+ * const TextField = Component.gen(function* (props: { name: string; value?: Stream.Stream<string, any, any> }) {
580
+ * return yield* h.input({ name: props.name, value: props.value });
581
+ * });
582
+ *
583
+ * TextField({ name: "email", value: userStream });
584
+ * // ^? Node<never, UserService>
585
+ * ```
586
+ *
587
+ * @example Function-children (render-prop pattern)
588
+ * ```ts
589
+ * const Tooltip = Component.gen(function* (
590
+ * _props: { label: string },
591
+ * children: (anchorId: string) => readonly Renderable[],
592
+ * ) {
593
+ * return yield* h.div({ class: "tooltip" }, children("anchor-42"));
594
+ * });
595
+ *
596
+ * Tooltip({ label: "Help" }, (id) => [h.span({ id }, "?")]);
597
+ * ```
598
+ */
599
+ function gen<Eff extends YieldWrap<Effect.Effect<any, any, any>>, BaseProps = Record<string, never>, C extends Children = readonly Renderable[]>(f: (props: BaseProps, children: C) => Generator<Eff, ElementDescriptor, never>): Component.Component<BaseProps, C, Eff extends YieldWrap<Effect.Effect<any, infer E, any>> ? E : never, Eff extends YieldWrap<Effect.Effect<any, any, infer R>> ? R : never>;
600
+ /**
601
+ * Defines a component whose body is a plain function returning any `Effect`
602
+ * (typically a {@link Node}). Use when the implementation is a one-liner or
603
+ * a pipe composition — no generator overhead.
604
+ *
605
+ * Same `E`/`R` propagation semantics as {@link gen}: internal `E`/`R` come
606
+ * from the returned effect, caller props and children contribute at the
607
+ * call site, and function-children are supported via the optional second
608
+ * argument.
609
+ *
610
+ * @example
611
+ * ```ts
612
+ * const Avatar = Component.make((props: { src: string }) =>
613
+ * h.img({ src: props.src, alt: "" }),
614
+ * );
615
+ * ```
616
+ *
617
+ * @example With function-children
618
+ * ```ts
619
+ * const List = Component.make(
620
+ * (
621
+ * props: { items: readonly string[] },
622
+ * children: (item: string) => readonly Renderable[],
623
+ * ) => h.ul({}, props.items.flatMap(children)),
624
+ * );
625
+ * ```
626
+ */
627
+ function make<Eff extends Effect.Effect<any, any, any>, BaseProps = Record<string, never>, C extends Children = readonly Renderable[]>(f: (props: BaseProps, children: C) => Eff): Component<BaseProps, C, Eff extends Effect.Effect<any, infer E, any> ? E : never, Eff extends Effect.Effect<any, any, infer R> ? R : never>;
628
+ }
629
+ //#endregion
630
+ export { type AppRpcClient, AppRpcClientTag, type AssertNoServerOnly, Boundary, CatchTagE, CatchTagsE, type ChildrenE, type ChildrenR, Component, type CustomElements, type ElementDescriptor, type ElementFn, FAILURE_BOUNDARY, FRAGMENT, LIST, List, NoPropValue, type Node, type PropsE, type PropsR, type Renderable, SERVER_BOUNDARY, SUSPENSE_BOUNDARY, type ServerOnly, type ServerOnlyLeak, ServerTag, Source, elementNode, getElementDescriptor, h, isStream, toStream };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{Cause as e,Context as t,Data as n,Deferred as r,Effect as i,Option as a,Stream as o,Subscribable as s,SubscriptionRef as c,identity as l,pipe as u}from"effect";const d=Symbol.for(`@weftui/core/ElementDescriptor`);function f(e){let t=i.succeed(e);return Object.defineProperty(t,d,{value:e,enumerable:!1}),t}function p(e){return i.isEffect(e)&&d in e?e[d]:void 0}var m=class extends t.Tag(`@weftui/core/AppRpcClient`)(){};const h=Symbol.for(`weft/FAILURE_BOUNDARY`),g=Symbol.for(`weft/SUSPENSE_BOUNDARY`),_=Symbol.for(`weft/SERVER_BOUNDARY`);function v(e,t){return f({type:h,props:{match:e,children:t}})}let y;(function(t){function n(t,n){return v(n=>{let r=e.failureOption(n);return a.isSome(r)?t.fallback(r.value):null},n)}t.catchAll=n;function r(e,t){return v(t=>e.fallback(t),t)}t.catchAllCause=r;function i(t,n){return v(n=>{let r=e.failureOption(n);if(a.isNone(r))return null;let i=r.value;return i._tag===t.tag?t.fallback(i):null},n)}t.catchTag=i;function o(t,n){return v(n=>{let r=e.failureOption(n);if(a.isNone(r))return null;let i=r.value,o=i._tag;if(o===void 0)return null;let s=t[o];return s?s(i):null},n)}t.catchTags=o;function s(t,n){return v(n=>{let r=e.failureOption(n);if(a.isNone(r))return null;let i=t.fallback(r.value);return a.isSome(i)?i.value:null},n)}t.catchSome=s;function c(t,n){return v(n=>{let r=e.failureOption(n);if(a.isNone(r))return null;let i=r.value;return t.predicate(i)?t.fallback(i):null},n)}t.catchIf=c;function l(e,t){return f({type:g,props:{...e,children:t}})}t.suspend=l;function u(e,t,n,r){let i=e;return f({type:_,props:{tag:i._tag,payloadSchema:i.payloadSchema,successSchema:i.successSchema,errorSchema:i.errorSchema,payload:t,render:n,fallback:r?.fallback}})}t.rpc=u})(y||={});const b=e=>()=>t.Tag(e)();function x(e){return typeof e==`object`&&!!e&&o.StreamTypeId in e}function S(e){return x(e)?e:i.isEffect(e)?o.fromEffect(e):o.make(e)}var C=class extends n.TaggedError(`NoPropValue`){};let w;(function(t){function n(t,n){return s.isSubscribable(t)?i.succeed(t):x(t)?i.gen(function*(){let d=yield*c.make(a.none()),f=yield*r.make(),p=yield*r.make(),m=u(o.runForEach(t,e=>u(c.set(d,a.some(e)),i.zipRight(r.succeed(f,e)),i.asVoid)),i.ensuring(u(c.get(d),i.flatMap(e=>a.isNone(e)?i.asVoid(r.fail(f,new C({key:n}))):i.void))),i.onError(t=>e.isInterruptedOnly(t)?i.void:i.asVoid(r.failCause(p,t))));yield*i.forkScoped(m);let h=u(c.get(d),i.flatMap(e=>a.isSome(e)?i.succeed(e.value):r.await(f))),g=u(d.changes,o.filterMap(l),o.interruptWhen(r.await(p)));return s.make({get:h,changes:g})}):i.isEffect(t)?i.gen(function*(){let e=yield*i.cached(t),n=o.fromEffect(e);return s.make({get:e,changes:n})}):i.succeed(s.make({get:i.succeed(t),changes:o.make(t)}))}t.toSubscribable=n})(w||={});const T=Symbol(`@weftui/core/fragment`);function E(e){return((t,n)=>{let r={},i;return Array.isArray(t)||typeof t==`string`||typeof t==`number`?i=t:t!==void 0&&(r=t,n!==void 0&&(i=n)),f({type:e,props:i===void 0?r:{...r,children:i}})})}function D(e=new Map){return new Proxy({fragment(e){return f({type:T,props:{children:e}})}},{get(t,n){return n in t?t[n]:e.get(n)??e.set(n,E(n)).get(n)}})}const O=D(new Map),k=Symbol(`@weftui/core/list`);let A;(function(e){function t(e,t){return f({type:k,props:{of:e.of,by:e.by,render:t}})}e.each=t})(A||={});let j;(function(e){function t(e){return(t,n=[])=>i.gen(function*(){return yield*e(t,n)})}e.gen=t;function n(e){return e}e.make=n})(j||={});export{m as AppRpcClientTag,y as Boundary,j as Component,h as FAILURE_BOUNDARY,T as FRAGMENT,k as LIST,A as List,C as NoPropValue,_ as SERVER_BOUNDARY,g as SUSPENSE_BOUNDARY,b as ServerTag,w as Source,f as elementNode,p as getElementDescriptor,O as h,x as isStream,S as toStream};
@@ -0,0 +1,2 @@
1
+ import { C as StyleAttributeValue, S as HTMLAttributeSource, _ as HTMLFormMethod, a as SVGElements, b as HTMLReferrerPolicy, c as HTMLRole, d as EventHandlerFn, f as HTMLAutocapitalize, g as HTMLFormEncType, h as HTMLDir, i as SVGAttributes, l as DOMAttributes, m as HTMLCrossorigin, n as ElementType, o as HTMLAttributes, p as HTMLAutocomplete, r as Renderable, s as HTMLElements, t as ElementDescriptor, u as EventHandler, v as HTMLIframeSandbox, w as StyleProperties, x as AriaAttributes, y as HTMLLinkAs } from "../index-B8idtfB3.js";
2
+ export { AriaAttributes, DOMAttributes, ElementDescriptor, ElementType, EventHandler, EventHandlerFn, HTMLAttributeSource, HTMLAttributes, HTMLAutocapitalize, HTMLAutocomplete, HTMLCrossorigin, HTMLDir, HTMLElements, HTMLFormEncType, HTMLFormMethod, HTMLIframeSandbox, HTMLLinkAs, HTMLReferrerPolicy, HTMLRole, Renderable, SVGAttributes, SVGElements, StyleAttributeValue, StyleProperties };
@@ -0,0 +1 @@
1
+ import"effect";