@weftui/dom 0.26.3 → 0.27.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.
package/README.md CHANGED
@@ -47,7 +47,7 @@ const Counter = () =>
47
47
  Effect.gen(function* () {
48
48
  const count = yield* SubscriptionRef.make(0);
49
49
  return yield* h.button({ onclick: () => SubscriptionRef.update(count, (n) => n + 1) }, [
50
- count.changes,
50
+ SubscriptionRef.changes(count),
51
51
  ]);
52
52
  });
53
53
 
@@ -1 +1 @@
1
- import{i as e,n as t,o as n,r,s as i,t as a}from"../data-Bk62ePeP.js";import{a as o,c as s,d as c,f as l,i as u,l as d,m as f,n as p,o as m,p as h,s as g,u as _}from"../boundary-replay-BR26_puM.js";import{Cause as v,Context as y,Deferred as b,Effect as x,ExecutionStrategy as S,Exit as C,Fiber as ee,FiberRef as te,HashMap as w,HashSet as T,Layer as ne,LogLevel as re,ManagedRuntime as ie,Option as E,Ref as D,Schema as ae,Scope as O,Stream as k,SubscriptionRef as A,pipe as j}from"effect";import{AppRpcClientTag as oe,FAILURE_BOUNDARY as se,FRAGMENT as ce,LIST as le,SERVER_BOUNDARY as ue,SUSPENSE_BOUNDARY as de,Source as fe,getElementDescriptor as pe,isStream as M,toStream as N}from"@weftui/core";function P(){return x.gen(function*(){let e=yield*r;return++e.streamIdCounter.current})}const me=P;let he=0;const F=()=>++he;function ge(e){if(e.length<=2||!e.startsWith(`on`))return!1;let t=e[2];return t!==void 0&&t>=`a`&&t<=`z`}function I(e,t){return x.gen(function*(){for(let[n,r]of Object.entries(t))if(n!==`children`){if(ge(n)){yield*Ce(e,n,r);continue}if(n===`ref`&&typeof r==`object`&&D.RefTypeId in r){yield*D.set(r,E.some(e));continue}if(n===`style`){yield*xe(e,r);continue}_e(e,n)?yield*ve(e,n,r):yield*ye(e,n,r)}})}function _e(e,t){if(t.startsWith(`data-`)||t.startsWith(`aria-`))return!1;let n=Object.getPrototypeOf(e);for(;n!==null;){if(Object.hasOwn(n,t))return!0;n=Object.getPrototypeOf(n)}return t in e}function ve(e,t,n){return x.gen(function*(){M(n)||x.isEffect(n)?yield*z(N(n),n=>{n==null?delete e[t]:e[t]=n},`property:${t}`):n!=null&&(e[t]=n)})}function ye(e,t,n){return x.gen(function*(){if(M(n)||x.isEffect(n))yield*z(N(n),n=>{if(n==null)e.removeAttribute(t);else{let r=be(n);r!==void 0&&(typeof n==`boolean`?n?e.setAttribute(t,``):e.removeAttribute(t):e.setAttribute(t,r))}},`attribute:${t}`);else{let r=be(n);r!==void 0&&(typeof n==`boolean`?n?e.setAttribute(t,``):e.removeAttribute(t):e.setAttribute(t,r))}})}function be(e){if(e!=null)return String(e)}function xe(e,t){return x.gen(function*(){if(M(t)||x.isEffect(t)){yield*z(N(t),t=>{if(typeof t==`string`)e.setAttribute(`style`,t);else if(typeof t==`object`&&t){e.style.cssText=``;for(let[n,r]of Object.entries(t))r!=null&&e.style.setProperty(L(n),String(r))}},`style`);return}if(typeof t==`string`){e.setAttribute(`style`,t);return}typeof t==`object`&&t&&(yield*Se(e,t))})}function Se(e,t){return x.gen(function*(){for(let[n,r]of Object.entries(t))M(r)||x.isEffect(r)?yield*z(N(r),t=>{t!=null&&e.style.setProperty(L(n),String(t))},`style.${n}`):r!=null&&e.style.setProperty(L(n),String(r))})}function L(e){return e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function R(e,t,n){return x.gen(function*(){let r=yield*x.serviceOption(a);if(E.isNone(r)){let r=yield*te.get(te.unhandledErrorLogLevel);return yield*j(x.forkIn(x.withUnhandledErrorLogLevel(e,r),t),x.withUnhandledErrorLogLevel(E.some(re.Error)),x.annotateLogs(`weft.region`,n))}let i=yield*x.forkIn(e,t);return yield*j(ee.await(i),x.flatMap(e=>C.isFailure(e)?r.value.reportError(e.cause):x.void),x.forkIn(t)),i})}function z(e,t,n){return x.gen(function*(){let i=yield*r;yield*R(k.runForEach(e,e=>x.sync(()=>void t(e))),i.scope,n)})}function Ce(e,t,n){return x.gen(function*(){let i=yield*r,a=t.slice(2).toLowerCase(),o=null,s=()=>{o&&=(e.removeEventListener(a,o),null)},c=n=>{s(),!(n==null||n===!1)&&typeof n==`function`&&(o=e=>{let r=n(e);x.isEffect(r)&&i.runtime.runFork(j(r,x.catchAll(e=>process.env.NODE_ENV===`development`?x.logError(`Event handler error: ${t}`,{error:e}):x.void)))},e.addEventListener(a,o))};yield*O.addFinalizer(i.scope,x.sync(s)),M(n)||x.isEffect(n)?yield*z(N(n),e=>c(e),`event:${t}`):c(n)})}function we(e,t,n,r,i,a){return x.gen(function*(){let o=yield*b.await(t).pipe(x.flip,x.catchAll(()=>x.interrupt)),s=e.match(o);if(yield*O.close(n,C.void),s===null)return E.isSome(r)?yield*r.value.reportError(o):yield*x.logError(`Unhandled error escaped the outermost Boundary`,o);K(i,a);let c=yield*B(s),l=a.parentNode;if(l!==null&&c!==null)if(Array.isArray(c))for(let e of c)l.insertBefore(e,a);else l.insertBefore(c,a)})}function Te(e){return x.gen(function*(){let t=yield*r,n=yield*x.serviceOption(a),i=F(),s=document.createComment(o(i)),c=document.createComment(u(i)),l=yield*O.fork(t.scope,S.sequential),d={...t,scope:l},f=yield*b.make(),p=yield*j(V(e.children),x.provideService(a,{reportError:e=>b.fail(f,e).pipe(x.asVoid)}),x.provideService(r,d),x.provideService(O.Scope,l),x.catchAllCause(t=>{let n=e.match(t);return n===null?x.failCause(t):j(O.close(l,C.void),x.flatMap(()=>B(n)),x.map(e=>e===null?[]:Array.isArray(e)?e:[e]))}));return yield*x.forkIn(we(e,f,l,n,s,c),t.scope),[s,...p,c]})}function Ee(e){return x.gen(function*(){let t=yield*r,i=yield*D.make(1),a=yield*b.make(),o=j(D.updateAndGet(i,e=>e-1),x.flatMap(e=>e<=0?x.asVoid(b.succeed(a,void 0)):x.void)),s={register:D.update(i,e=>e+1),settle:o},c=e.children,l=yield*B((c===void 0?[]:Array.isArray(c)?c:[c]).map(e=>x.isEffect(e)||M(e)?{type:()=>e,props:{}}:e)).pipe(x.provideService(n,s)),u=l===null?[]:Array.isArray(l)?l:[l];yield*o;let d=yield*b.poll(a);if(E.isSome(d))return u;let p=yield*me(),m=document.createComment(f(p)),g=document.createComment(h(p)),_=yield*B(e.fallback??null),v=[];_!==null&&(Array.isArray(_)?v.push(..._):v.push(_));let y=document.createDocumentFragment();for(let e of u)y.appendChild(e);let S=x.gen(function*(){yield*b.await(a),K(m,g);let e=g.parentNode;e!==null&&(e.insertBefore(y,g),m.remove(),g.remove())});return yield*x.forkIn(S,t.scope),[m,...v,g]})}function De(t){return x.gen(function*(){let n=yield*r,i=yield*x.serviceOption(oe);if(E.isNone(i))return yield*x.fail(new e({cause:void 0,message:`Boundary.rpc "${t.tag}" was mounted client-first without an AppRpcClient in context. Mount the app under @weftui/router (RouterLive), which provides the rpc client, so the boundary can resolve its data.`}));let a=i.value,s=F(),c=document.createComment(o(s)),l=document.createComment(u(s)),d=yield*B(t.fallback??null),f=[];d!==null&&(Array.isArray(d)?f.push(...d):f.push(d));let p=x.gen(function*(){let e=yield*a.call(t.tag,t.payload()),n=yield*$e(t.tag,t.payload,e,i),r=yield*B(t.render(n));K(c,l);let o=l.parentNode;if(o!==null&&r!==null)if(Array.isArray(r))for(let e of r)o.insertBefore(e,l);else o.insertBefore(r,l)}).pipe(x.catchAllCause(e=>x.logError(`[weft] Boundary.rpc "${t.tag}" mount failed to resolve; fallback left in place.`,e)));return yield*x.forkIn(p,n.scope),[c,...f,l]})}function B(e){return x.gen(function*(){if(typeof e==`string`||typeof e==`number`||typeof e==`bigint`)return document.createTextNode(String(e));if(typeof e==`boolean`||e==null)return null;if(M(e)||x.isEffect(e)){let t=pe(e);if(t!==void 0)return yield*B(t);if(x.isEffect(e)){let t=x.runSyncExit(e);if(C.isSuccess(t))return yield*B(t.value)}return yield*H(N(e))}if(typeof e==`object`&&Symbol.iterator in e&&!(`type`in e))return yield*V(Oe(e));if(typeof e==`object`&&`type`in e&&!(Symbol.iterator in e)){let{type:t,props:n}=e;return t===ce?yield*ke(n):t===de?yield*Ee(n):t===ue?yield*De(n):t===se?yield*Te(n):t===le?yield*Ie(n):typeof t==`string`?yield*Ae(t,n):typeof t==`function`?yield*je(t,n):yield*x.fail(new i({type:t,message:`Invalid Renderable type: expected string, FRAGMENT, or function, got ${typeof t}`}))}return null})}function Oe(e){let t=[];function n(e){if(M(e)||x.isEffect(e)){t.push(e);return}if(typeof e==`object`&&e&&Symbol.iterator in e&&!(`type`in e))for(let t of e)n(t);else t.push(e)}return n(e),t}function V(e){return x.gen(function*(){let t=[];for(let n of e)if(M(n)||x.isEffect(n)){let e=yield*H(N(n));t.push(...e)}else{let e=yield*B(n);e!==null&&(Array.isArray(e)?t.push(...e):t.push(e))}return t})}function ke(e){return x.gen(function*(){let t=`children`in e?e.children:void 0;return t===void 0?[]:yield*V(Array.isArray(t)?t:[t])})}function Ae(e,t){return x.gen(function*(){let n=document.createElement(e);yield*I(n,t);let r=`children`in t?t.children:void 0;if(r!==void 0){let e=Array.isArray(r)?r:[r];for(let t of e)if(M(t)||x.isEffect(t)){let e=yield*H(N(t));for(let t of e)n.appendChild(t)}else{let e=yield*B(t);if(e!==null)if(Array.isArray(e))for(let t of e)n.appendChild(t);else n.appendChild(e)}}return n})}function je(e,t){return x.gen(function*(){let i=e(t);if(M(i)||x.isEffect(i)){let e=yield*r,t=yield*O.fork(e.scope,S.sequential),a={...e,scope:t},o=yield*x.serviceOption(n),s=N(i);return E.isSome(o)&&(yield*o.value.register,s=j(s,k.zipWithIndex,k.flatMap(([e,t])=>t===0?k.fromEffect(x.as(o.value.settle,e)):k.make(e)))),yield*H(s).pipe(x.provideService(r,a),x.provideService(O.Scope,t))}return yield*B(i)})}function H(e){return x.gen(function*(){let t=yield*r,n=yield*P(),[i,a]=Me(n),o=null;return yield*R(k.runForEach(e,e=>x.gen(function*(){o!==null&&(yield*O.close(o,C.void)),o=yield*O.fork(t.scope,S.sequential);let n={...t,scope:o};yield*U(i,a,e).pipe(x.provideService(r,n),x.provideService(O.Scope,o))})),t.scope,`child:stream-${n}`),[i,a]})}function Me(e){return[document.createComment(l(e)),document.createComment(c(e))]}function U(e,t,n){return x.gen(function*(){let r=e.nextSibling,i=r!==null&&r!==t&&r.nextSibling===t;if(i&&r.nodeType===ot&&W(n)){let e=String(n);r.data!==e&&(r.data=e);return}if(i&&r.nodeType===X){let e=G(n);if(e!==void 0&&typeof e.type==`string`&&r.tagName.toLowerCase()===e.type.toLowerCase()){yield*Ne(r,e);return}}K(e,t);let a=yield*B(n),o=e.parentNode;if(o!==null&&a!==null)if(Array.isArray(a))for(let e of a)o.insertBefore(e,t);else o.insertBefore(a,t)})}function W(e){return typeof e==`string`||typeof e==`number`||typeof e==`bigint`}function G(e){let t=pe(e);if(t!==void 0)return t;if(typeof e==`object`&&e&&`type`in e&&!(Symbol.iterator in e)&&!M(e)&&!x.isEffect(e))return e}function Ne(e,t){return x.gen(function*(){yield*I(e,t.props);let n=t.props.children,r=n===void 0?[]:Array.isArray(n)?n:[n];if(!(yield*Pe(e,r))){for(;e.firstChild!==null;)e.firstChild.remove();yield*Fe(e,r)}})}function Pe(e,t){return x.gen(function*(){let n=Array.from(e.childNodes);if(n.length!==t.length)return!1;for(let e=0;e<t.length;e++){let r=t[e],i=n[e];if(W(r)){if(i.nodeType!==ot)return!1}else{let e=G(r);if(e===void 0||typeof e.type!=`string`||i.nodeType!==X||i.tagName.toLowerCase()!==e.type.toLowerCase())return!1}}for(let e=0;e<t.length;e++){let r=t[e],i=n[e];if(W(r)){let e=String(r);i.data!==e&&(i.data=e)}else yield*Ne(i,G(r))}return!0})}function Fe(e,t){return x.gen(function*(){for(let n of t)if(M(n)||x.isEffect(n)){let t=yield*H(N(n));for(let n of t)e.appendChild(n)}else{let t=yield*B(n);if(t!==null)if(Array.isArray(t))for(let n of t)e.appendChild(n);else e.appendChild(t)}})}function K(e,t){let n=e.nextSibling;for(;n!==null&&n!==t;){let e=n.nextSibling;n.remove(),n=e}}function Ie(e){return x.gen(function*(){let t=yield*r,{of:n,by:i,render:a}=e,o=yield*P(),[s,c]=Me(o),l=yield*O.fork(t.scope,S.sequential),u=(yield*fe.toSubscribable(n).pipe(x.provideService(O.Scope,l))).changes,d={records:w.empty(),order:[]};return yield*R(k.runForEach(u,e=>x.gen(function*(){d=yield*q(Array.from(e),i,a,d,l,c,t)})),l,`list:stream-${o}`),[s,c]})}function Le(t,n){return x.gen(function*(){let r=[],i=T.empty();for(let a=0;a<t.length;a++){let o=n===void 0?t[a]:n(t[a],a);if(T.has(i,o))return yield*x.fail(new e({cause:o,message:`List.each: duplicate key ${Ve(o)} in a single emission; keys must be unique (set a stable \`by\`).`}));i=T.add(i,o),r.push(o)}return r})}function q(e,t,n,r,i,a,o){return x.gen(function*(){let s=yield*Le(e,t),c=w.empty();r.order.forEach((e,t)=>{c=w.set(c,e,t)});let l=[],u=[];for(let t=0;t<e.length;t++){let a=s[t],d=w.get(r.records,a);if(E.isSome(d))l.push(d.value),u.push(E.getOrElse(w.get(c,a),()=>-1));else{let r=yield*Re(a,e[t],t,n,i,o);l.push(r),u.push(-1)}}let d=T.empty();for(let e of s)d=T.add(d,e);for(let e of r.order)if(!T.has(d,e)){let t=w.get(r.records,e);E.isSome(t)&&(yield*O.close(t.value.scope,C.void),Be(t.value.startMarker,t.value.endMarker))}let f=He(u),p=a.parentNode;if(p!==null)for(let e=l.length-1;e>=0;e--){let t=l[e];if(u[e]!==-1&&f.has(e))continue;let n=e+1<l.length?l[e+1].startMarker:a,r=u[e]===-1?[t.startMarker,...t.nodes,t.endMarker]:ze(t.startMarker,t.endMarker);for(let e of r)p.insertBefore(e,n)}let m=w.empty();for(let e of l)m=w.set(m,e.key,e);return{records:m,order:s}})}function Re(e,t,n,i,a,o){return x.gen(function*(){let s=yield*O.fork(a,S.sequential),c={...o,scope:s},l=yield*P(),u=document.createComment(g(l)),d=document.createComment(m(l)),f=yield*B(i(t,n)).pipe(x.provideService(r,c),x.provideService(O.Scope,s));return{key:e,scope:s,startMarker:u,endMarker:d,nodes:f===null?[]:Array.isArray(f)?f:[f]}})}function ze(e,t){let n=[],r=e;for(;r!==null&&(n.push(r),r!==t);)r=r.nextSibling;return n}function Be(e,t){let n=e;for(;n!==null;){let e=n.nextSibling;if(n.remove(),n===t)break;n=e}}function Ve(e){if(typeof e==`string`)return JSON.stringify(e);if(typeof e==`object`&&e)try{return JSON.stringify(e)}catch{return Object.prototype.toString.call(e)}return String(e)}function He(e){let t=e.length,n=[],r=Array.from({length:t},()=>-1);for(let i=0;i<t;i++){let t=e[i];if(t===-1)continue;let a=0,o=n.length;for(;a<o;){let r=a+o>>1;e[n[r]]<t?a=r+1:o=r}a>0&&(r[i]=n[a-1]),n[a]=i}let i=new Set,a=n.length>0?n[n.length-1]:-1;for(;a!==-1;)i.add(a),a=r[a];return i}function Ue(e,t){return x.gen(function*(){let n=yield*x.context(),i=yield*x.serviceOption(O.Scope),a=yield*O.make(),o=ie.make(ne.succeedContext(y.add(n,O.Scope,a))),s={runtime:o,scope:a,streamIdCounter:{current:0}},c=x.zipRight(O.close(a,C.void),x.promise(()=>o.dispose()));t.innerHTML=``;let l=yield*B(e).pipe(x.provideService(r,s),x.provideService(O.Scope,a),x.tapError(()=>c));if(l!==null)if(Array.isArray(l))for(let e of l)t.appendChild(e);else t.appendChild(l);let u=!1,d={unmount:()=>x.gen(function*(){u||(u=!0,yield*O.close(a,C.void),yield*x.promise(()=>o.dispose()))})};return E.isSome(i)&&(yield*O.addFinalizer(i.value,d.unmount())),d})}function We(e,t){return x.gen(function*(){let n=yield*x.context(),i=yield*x.serviceOption(O.Scope),a=yield*O.make(),o=ie.make(ne.succeedContext(y.add(n,O.Scope,a))),s=yield*Ke(),c={runtime:o,scope:a,streamIdCounter:{current:0},hydrationReady:s};st(t,c.streamIdCounter);let l=x.zipRight(O.close(a,C.void),x.promise(()=>o.dispose()));yield*J(e,t.firstChild,`root`).pipe(x.provideService(r,c),x.provideService(O.Scope,a),x.tapError(()=>l)),yield*s.settle,yield*s.awaitReady;let u=!1,d={unmount:()=>x.gen(function*(){u||(u=!0,yield*O.close(a,C.void),yield*x.promise(()=>o.dispose()))})};return E.isSome(i)&&(yield*O.addFinalizer(i.value,d.unmount())),d})}function J(e,t,n){return x.gen(function*(){if(typeof e==`string`||typeof e==`number`||typeof e==`bigint`)return yield*Ge(String(e),t,n);if(typeof e==`boolean`||e==null)return t;if(M(e)||x.isEffect(e)){let r=pe(e);if(r!==void 0)return yield*J(r,t,n);if(x.isEffect(e)){let r=x.runSyncExit(e);if(C.isSuccess(r))return yield*J(r.value,t,n)}return yield*Je(N(e),t,n)}if(typeof e==`object`&&Symbol.iterator in e&&!(`type`in e)){let r=t,i=0;for(let t of e)r=yield*J(t,r,`${n}[${i}]`),i++;return r}if(typeof e==`object`&&`type`in e&&!(Symbol.iterator in e)){let{type:r,props:a}=e;if(r===ce)return yield*Y(a,t,n);if(r===de){if(t!==null&&t.nodeType===Z){let e=_(t);if(e!==null&&e.kind===`start`)return yield*Xe(t,n)}return yield*Y(a,t,n)}return r===se?yield*Qe(a,t,n):r===ue?yield*et(a,t,n):r===le?yield*nt(a,t,n):typeof r==`string`?yield*tt(r,a,t,n):typeof r==`function`?yield*J(r(a),t,n):yield*x.fail(new i({type:r,message:`Invalid Renderable type during hydration at ${n}: expected string, FRAGMENT, or function, got ${typeof r}`}))}return t})}function Ge(e,t,n){return x.gen(function*(){if(e.length===0)return t;if(t===null||t.nodeType!==ot)return yield*$(`text ${JSON.stringify(e)}`,Q(t),n);let r=t;return r.data.startsWith(e)?r.data.length>e.length?r.splitText(e.length):r.nextSibling:yield*$(`text ${JSON.stringify(e)}`,Q(t),n)})}function Ke(){return x.gen(function*(){let e=yield*D.make(1),t=yield*b.make(),n=j(D.updateAndGet(e,e=>e-1),x.flatMap(e=>e<=0?x.asVoid(b.succeed(t,void 0)):x.void));return{register:D.update(e,e=>e+1),settle:n,awaitReady:b.await(t)}})}function qe(e){let t=!1;return x.suspend(()=>t||e===void 0?x.void:(t=!0,e.settle))}function Je(e,t,n){return x.gen(function*(){let i=yield*r;if(t===null||t.nodeType!==Z)return yield*$(`reactive region start marker`,Q(t),n);let a=t,o=d(a);if(o===null||o.kind!==`start`)return yield*$(`reactive region start marker`,Q(t),n);let s=ct(a);if(s===null)return yield*$(`reactive region end marker`,`unterminated region starting at ${JSON.stringify(a.data)}`,n);let c=qe(i.hydrationReady),l=!0,u=null,f=k.runForEach(e,e=>x.gen(function*(){u!==null&&(yield*O.close(u,C.void)),u=yield*O.fork(i.scope,S.sequential);let t={...i,scope:u};yield*x.gen(function*(){l?(l=!1,yield*Ye(e,a,s,n),yield*c):yield*U(a,s,e)}).pipe(x.provideService(r,t),x.provideService(O.Scope,u))})).pipe(x.ensuring(c));return i.hydrationReady!==void 0&&(yield*i.hydrationReady.register),yield*R(f,i.scope,`hydrate:stream-${o.id} (${n})`),s.nextSibling})}function Ye(e,t,n,r){return x.gen(function*(){let i=yield*J(e,t.nextSibling,`${r}<resume>`).pipe(x.map(e=>e===n?null:`adopted content did not align with the end marker`),x.catchTag(`HydrationMismatchError`,e=>x.succeed(`expected ${e.expected}, found ${e.actual} at ${e.path}`)));i!==null&&(console.error(`[weft] hydrate: reactive region at ${r} diverged from server output (${i}); patching.`),yield*U(t,n,e))})}function Xe(e,t){return x.gen(function*(){let n=Ze(e);if(n===null)return yield*$(`substituted suspense end marker`,`unterminated region starting at ${JSON.stringify(e.data)}`,t);let r=null;for(let t=e.nextSibling;t!==null&&t!==n;t=t.nextSibling)if(t.nodeType===X&&t.tagName===`SCRIPT`&&t.getAttribute(`type`)===`application/json`&&t.hasAttribute(`data-weft-suspense-failure`)){r=t;break}let i=null;if(r!==null){let e=r.textContent??``;i=yield*x.try({try:()=>JSON.parse(e),catch:e=>e}).pipe(x.catchAll(()=>x.succeed(null)))}if(typeof i!=`object`||!i||!(`error`in i))return console.error(`[weft] hydrate: substituted suspense region at ${t} has no decodable failure sentinel; leaving its static content.`),n.nextSibling;let o=yield*x.serviceOption(a);return E.isNone(o)?(console.error(`[weft] hydrate: substituted suspense region at ${t} has no enclosing Boundary to replay its failure to; leaving its static content.`,i.error),n.nextSibling):(yield*o.value.reportError(v.fail(i.error)),n.nextSibling)})}function Ze(e){let t=0,n=e.nextSibling;for(;n!==null;){if(n.nodeType===Z){let e=_(n);if(e!==null)if(e.kind===`start`)t++;else if(t===0)return n;else t--}n=n.nextSibling}return null}function Qe(e,t,n){return x.gen(function*(){if(t===null||t.nodeType!==X||t.tagName!==`SCRIPT`||t.getAttribute(`type`)!==`application/json`||!t.hasAttribute(`data-weft-boundary-failure`)){let i=yield*r,s=yield*x.serviceOption(a),c=yield*O.fork(i.scope,S.sequential),l={...i,scope:c},d=yield*b.make(),f=yield*Y(e,t,n).pipe(x.provideService(a,{reportError:e=>b.fail(d,e).pipe(x.asVoid)}),x.provideService(r,l),x.provideService(O.Scope,c)),p=t?.parentNode??null;if(t===null||t===f||p===null)return console.error(`[weft] hydrate: boundary at ${n} adopted an empty extent; live failure recovery is not installed for it.`),f;let m=F(),h=document.createComment(o(m)),g=document.createComment(u(m));return p.insertBefore(h,t),f===null?p.appendChild(g):p.insertBefore(g,f),yield*x.forkIn(we(e,d,c,s,h,g),i.scope),f}let i=t,s=i.textContent??``,c=yield*x.gen(function*(){let t=yield*x.try({try:()=>JSON.parse(s),catch:e=>e}),n=p(e.children)[t.index];if(n===void 0)return null;let r=yield*ae.decodeUnknown(n.errorSchema)(t.error);return e.match(v.fail(r))}).pipe(x.catchAll(e=>(console.error(`[weft] hydrate: boundary failure payload at ${n} failed to decode; cannot replay.`,e),x.succeed(null))));if(c===null)return yield*$(`replayable boundary failure`,`undecodable failure payload`,n);let l=yield*J(c,i.nextSibling,n);return i.remove(),l})}function $e(e,t,n,r){return x.gen(function*(){let i=yield*A.make(n),a=yield*A.make(!1),o=yield*A.make(E.none());return{value:i,refetch:E.match(r,{onNone:()=>x.void,onSome:n=>x.gen(function*(){(yield*A.get(a))||(yield*A.set(a,!0),yield*x.gen(function*(){let r=yield*x.exit(n.call(e,t()));C.isSuccess(r)?(yield*A.set(i,r.value),yield*A.set(o,E.none())):yield*A.set(o,E.some(v.squash(r.cause)))}).pipe(x.ensuring(A.set(a,!1))))})}),pending:a,error:o}})}function et(e,t,n){return x.gen(function*(){if(t===null||t.nodeType!==X||t.tagName!==`SCRIPT`||t.getAttribute(`type`)!==`application/json`)return yield*$(`server boundary payload <script type="application/json">`,Q(t),n);if(t.hasAttribute(`data-weft-boundary-failure`))return yield*$(`server boundary success payload <script type="application/json">`,`boundary failure payload`,n);let r=t,i=r.textContent??``,a=yield*x.try({try:()=>JSON.parse(i),catch:e=>e}).pipe(x.flatMap(t=>ae.decodeUnknown(e.successSchema)(t)),x.catchAll(e=>(console.error(`[weft] hydrate: server boundary payload at ${n} failed to decode; cannot replay.`,e),$(`decodable server boundary payload`,`undecodable payload`,n)))),o=yield*x.serviceOption(oe),s=yield*$e(e.tag,e.payload,a,o),c=yield*J(e.render(s),r.nextSibling,n);return r.remove(),c})}function tt(e,t,n,r){return x.gen(function*(){if(n===null||n.nodeType!==X)return yield*$(`<${e}>`,Q(n),r);let i=n;return i.tagName.toLowerCase()===e.toLowerCase()?(yield*I(i,t),yield*Y(t,i.firstChild,`${r} > ${e}`),i.nextSibling):yield*$(`<${e}>`,Q(n),r)})}function Y(e,t,n){return x.gen(function*(){let r=`children`in e?e.children:void 0;if(r===void 0)return t;let i=Array.isArray(r)?r:[r],a=t,o=0;for(let e of i)a=yield*J(e,a,`${n}[${o}]`),o++;return a})}function nt(e,t,n){return x.gen(function*(){let i=yield*r,{of:a,by:o,render:s}=e;if(t===null||t.nodeType!==Z)return yield*$(`list region start marker`,Q(t),n);let c=t,l=d(c);if(l===null||l.kind!==`start`)return yield*$(`list region start marker`,Q(t),n);let u=ct(c);if(u===null)return yield*$(`list region end marker`,`unterminated region starting at ${JSON.stringify(c.data)}`,n);let f=rt(c,u),p=yield*O.fork(i.scope,S.sequential),m=(yield*fe.toSubscribable(a).pipe(x.provideService(O.Scope,p))).changes,h={records:w.empty(),order:[]},g=!0,_=qe(i.hydrationReady),v=k.runForEach(m,e=>x.gen(function*(){let t=Array.from(e);g?(g=!1,h=yield*it(t,o,s,f,p,c,u,i,n),yield*_):h=yield*q(t,o,s,h,p,u,i)})).pipe(x.ensuring(_));return i.hydrationReady!==void 0&&(yield*i.hydrationReady.register),yield*R(v,p,`hydrate:list-${l.id} (${n})`),u.nextSibling})}function rt(e,t){let n=[],r=e.nextSibling;for(;r!==null&&r!==t;){let e=r.nodeType===Z?s(r):null;if(e===null||e.kind!==`start`){r=r.nextSibling;continue}let i=r,a=[],o=0,c=null,l=i.nextSibling;for(;l!==null&&l!==t;){if(l.nodeType===Z){let e=s(l);if(e!==null)if(e.kind===`start`)o++;else if(o===0){c=l;break}else o--}a.push(l),l=l.nextSibling}if(c===null)break;n.push({startMarker:i,endMarker:c,nodes:a}),r=c.nextSibling}return n}function it(e,t,n,r,i,a,o,s,c){return x.gen(function*(){let l=yield*Le(e,t);if(l.length!==r.length)return console.error(`[weft] hydrate: list region at ${c} had ${r.length} server item(s) but the first emission has ${l.length}; rebuilding.`),K(a,o),yield*q(e,t,n,{records:w.empty(),order:[]},i,o,s);let u=[];for(let t=0;t<e.length;t++){let a=yield*at(l[t],e[t],t,n,r[t],i,s,c);u.push(a)}let d=w.empty();for(let e of u)d=w.set(d,e.key,e);return{records:d,order:l}})}function at(e,t,n,i,a,o,s,c){return x.gen(function*(){let l=yield*O.fork(o,S.sequential),u={...s,scope:l},d=i(t,n),f=yield*J(d,a.startMarker.nextSibling,`${c}<item>`).pipe(x.provideService(r,u),x.provideService(O.Scope,l),x.map(e=>e===a.endMarker?null:`adopted item content did not align with its end marker`),x.catchTag(`HydrationMismatchError`,e=>x.succeed(`expected ${e.expected}, found ${e.actual} at ${e.path}`)));if(f===null)return{key:e,scope:l,startMarker:a.startMarker,endMarker:a.endMarker,nodes:a.nodes};console.error(`[weft] hydrate: list item at ${c} diverged from server output (${f}); patching.`),yield*O.close(l,C.void);let p=yield*O.fork(o,S.sequential),m={...s,scope:p};K(a.startMarker,a.endMarker);let h=yield*B(d).pipe(x.provideService(r,m),x.provideService(O.Scope,p)),g=h===null?[]:Array.isArray(h)?h:[h],_=a.endMarker.parentNode;if(_!==null)for(let e of g)_.insertBefore(e,a.endMarker);return{key:e,scope:p,startMarker:a.startMarker,endMarker:a.endMarker,nodes:g}})}const X=1,ot=3,Z=8;function st(e,t){let n=document.createTreeWalker(e,128),r=t.current;for(let e=n.nextNode();e!==null;e=n.nextNode()){let t=e,n=d(t)??_(t)??s(t);n!==null&&n.id>r&&(r=n.id)}t.current=r}function ct(e){let t=0,n=e.nextSibling;for(;n!==null;){if(n.nodeType===8){let e=d(n);if(e!==null)if(e.kind===`start`)t++;else if(t===0)return n;else t--}n=n.nextSibling}return null}function Q(e){if(e===null)return`end of children`;switch(e.nodeType){case 1:return`<${e.tagName.toLowerCase()}>`;case 3:return`text ${JSON.stringify(e.data)}`;case 8:return`comment ${JSON.stringify(e.data)}`;default:return`node(type ${e.nodeType})`}}function $(e,n,r){return x.fail(new t({expected:e,actual:n,path:r}))}function lt(e,t){return j(Ue(e,t),x.tap(e=>x.addFinalizer(()=>e.unmount())))}function ut(e,t){return j(We(e,t),x.tap(e=>x.addFinalizer(()=>e.unmount())))}export{We as hydrate,ut as hydrateScoped,Ue as mount,lt as mountScoped};
1
+ import{i as e,n as t,o as n,r,s as i,t as a}from"../data-uLmMpQMV.js";import{a as o,c as s,d as c,f as l,i as u,l as d,m as f,n as p,o as m,p as h,s as g,u as _}from"../boundary-replay-BR26_puM.js";import{Cause as v,Context as y,Deferred as b,Effect as x,Exit as S,Fiber as ee,HashMap as C,HashSet as w,Layer as te,ManagedRuntime as ne,Option as T,Ref as E,Schema as re,Scope as D,Stream as O,SubscriptionRef as k,pipe as A}from"effect";import{AppRpcClientTag as ie,FAILURE_BOUNDARY as ae,FRAGMENT as oe,LIST as se,SERVER_BOUNDARY as ce,SUSPENSE_BOUNDARY as le,Source as ue,Subscribable as j,getElementDescriptor as M,isStream as N,toStream as P}from"@weftui/core";function F(){return x.gen(function*(){let e=yield*r;return++e.streamIdCounter.current})}const de=F;let fe=0;const pe=()=>++fe;function me(e){if(e.length<=2||!e.startsWith(`on`))return!1;let t=e[2];return t!==void 0&&t>=`a`&&t<=`z`}function I(e,t){return x.gen(function*(){for(let[n,r]of Object.entries(t))if(n!==`children`){if(me(n)){yield*xe(e,n,r);continue}if(n===`ref`&&typeof r==`object`&&k.isSubscriptionRef(r)){yield*k.set(r,T.some(e));continue}if(n===`style`){yield*ye(e,r);continue}he(e,n)?yield*ge(e,n,r):yield*_e(e,n,r)}})}function he(e,t){if(t.startsWith(`data-`)||t.startsWith(`aria-`))return!1;let n=Object.getPrototypeOf(e);for(;n!==null;){if(Object.hasOwn(n,t))return!0;n=Object.getPrototypeOf(n)}return t in e}function ge(e,t,n){return x.gen(function*(){N(n)||x.isEffect(n)?yield*z(P(n),n=>{n==null?delete e[t]:e[t]=n},`property:${t}`):n!=null&&(e[t]=n)})}function _e(e,t,n){return x.gen(function*(){if(N(n)||x.isEffect(n))yield*z(P(n),n=>{if(n==null)e.removeAttribute(t);else{let r=ve(n);r!==void 0&&(typeof n==`boolean`?n?e.setAttribute(t,``):e.removeAttribute(t):e.setAttribute(t,r))}},`attribute:${t}`);else{let r=ve(n);r!==void 0&&(typeof n==`boolean`?n?e.setAttribute(t,``):e.removeAttribute(t):e.setAttribute(t,r))}})}function ve(e){if(e!=null)return String(e)}function ye(e,t){return x.gen(function*(){if(N(t)||x.isEffect(t)){yield*z(P(t),t=>{if(typeof t==`string`)e.setAttribute(`style`,t);else if(typeof t==`object`&&t){e.style.cssText=``;for(let[n,r]of Object.entries(t))r!=null&&e.style.setProperty(L(n),String(r))}},`style`);return}if(typeof t==`string`){e.setAttribute(`style`,t);return}typeof t==`object`&&t&&(yield*be(e,t))})}function be(e,t){return x.gen(function*(){for(let[n,r]of Object.entries(t))N(r)||x.isEffect(r)?yield*z(P(r),t=>{t!=null&&e.style.setProperty(L(n),String(t))},`style.${n}`):r!=null&&e.style.setProperty(L(n),String(r))})}function L(e){return e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function R(e,t,n){return x.gen(function*(){let r=yield*x.serviceOption(a);if(T.isNone(r)){let r=yield*x.forkIn(e,t);return yield*A(ee.await(r),x.flatMap(e=>S.isFailure(e)&&!v.hasInterruptsOnly(e.cause)?A(x.logError(e.cause),x.annotateLogs(`weft.region`,n)):x.void),x.forkIn(t)),r}let i=yield*x.forkIn(e,t);return yield*A(ee.await(i),x.flatMap(e=>S.isFailure(e)?r.value.reportError(e.cause):x.void),x.forkIn(t)),i})}function z(e,t,n){return x.gen(function*(){let i=yield*r;yield*R(O.runForEach(e,e=>x.sync(()=>void t(e))),i.scope,n)})}function xe(e,t,n){return x.gen(function*(){let i=yield*r,a=t.slice(2).toLowerCase(),o=null,s=()=>{o&&=(e.removeEventListener(a,o),null)},c=n=>{s(),!(n==null||n===!1)&&typeof n==`function`&&(o=e=>{let r=n(e);x.isEffect(r)&&i.runtime.runFork(A(r,x.catch(e=>process.env.NODE_ENV===`development`?x.logError(`Event handler error: ${t}`,{error:e}):x.void)))},e.addEventListener(a,o))};yield*D.addFinalizer(i.scope,x.sync(s)),N(n)||x.isEffect(n)?yield*z(P(n),e=>c(e),`event:${t}`):c(n)})}function Se(e,t,n,r,i,a){return x.gen(function*(){let o=yield*b.await(t).pipe(x.flip,x.catch(()=>x.interrupt)),s=e.match(o);if(yield*D.close(n,S.void),s===null)return T.isSome(r)?yield*r.value.reportError(o):yield*x.logError(`Unhandled error escaped the outermost Boundary`,o);K(i,a);let c=yield*B(s),l=a.parentNode;if(l!==null&&c!==null)if(Array.isArray(c))for(let e of c)l.insertBefore(e,a);else l.insertBefore(c,a)})}function Ce(e){return x.gen(function*(){let t=yield*r,n=yield*x.serviceOption(a),i=pe(),s=document.createComment(o(i)),c=document.createComment(u(i)),l=yield*D.fork(t.scope,`sequential`),d={...t,scope:l},f=yield*b.make(),p=yield*A(V(e.children),x.provideService(a,{reportError:e=>b.fail(f,e).pipe(x.asVoid)}),x.provideService(r,d),x.provideService(D.Scope,l),x.catchCause(t=>{let n=e.match(t);return n===null?x.failCause(t):A(D.close(l,S.void),x.flatMap(()=>B(n)),x.map(e=>e===null?[]:Array.isArray(e)?e:[e]))}));return yield*x.forkIn(Se(e,f,l,n,s,c),t.scope),[s,...p,c]})}function we(e){return x.gen(function*(){let t=yield*r,i=yield*E.make(1),a=yield*b.make(),o=A(E.updateAndGet(i,e=>e-1),x.flatMap(e=>e<=0?x.asVoid(b.succeed(a,void 0)):x.void)),s={register:E.update(i,e=>e+1),settle:o},c=e.children,l=yield*B((c===void 0?[]:Array.isArray(c)?c:[c]).map(e=>M(e)===void 0&&(x.isEffect(e)||N(e))?{type:()=>e,props:{}}:e)).pipe(x.provideService(n,s)),u=l===null?[]:Array.isArray(l)?l:[l];yield*o;let d=yield*b.poll(a);if(T.isSome(d))return u;let p=yield*de(),m=document.createComment(f(p)),g=document.createComment(h(p)),_=yield*B(e.fallback??null),v=[];_!==null&&(Array.isArray(_)?v.push(..._):v.push(_));let y=document.createDocumentFragment();for(let e of u)y.appendChild(e);let S=x.gen(function*(){yield*b.await(a),K(m,g);let e=g.parentNode;e!==null&&(e.insertBefore(y,g),m.remove(),g.remove())});return yield*x.forkIn(S,t.scope),[m,...v,g]})}function Te(t){return x.gen(function*(){let n=yield*r,i=yield*x.serviceOption(ie);if(T.isNone(i))return yield*x.fail(new e({cause:void 0,message:`Boundary.rpc "${t.tag}" was mounted client-first without an AppRpcClient in context. Mount the app under @weftui/router (RouterLive), which provides the rpc client, so the boundary can resolve its data.`}));let a=i.value,s=pe(),c=document.createComment(o(s)),l=document.createComment(u(s)),d=yield*B(t.fallback??null),f=[];d!==null&&(Array.isArray(d)?f.push(...d):f.push(d));let p=x.gen(function*(){let e=yield*a.call(t.tag,t.payload()),n=yield*Ze(t.tag,t.payload,e,i),r=yield*B(t.render(n));K(c,l);let o=l.parentNode;if(o!==null&&r!==null)if(Array.isArray(r))for(let e of r)o.insertBefore(e,l);else o.insertBefore(r,l)}).pipe(x.catchCause(e=>x.logError(`[weft] Boundary.rpc "${t.tag}" mount failed to resolve; fallback left in place.`,e)));return yield*x.forkIn(p,n.scope),[c,...f,l]})}function B(e){return x.gen(function*(){if(typeof e==`string`||typeof e==`number`||typeof e==`bigint`)return document.createTextNode(String(e));if(typeof e==`boolean`||e==null)return null;if(N(e)||x.isEffect(e)){let t=M(e);if(t!==void 0)return yield*B(t);if(x.isEffect(e)){let t=yield*x.context(),n=x.runSyncExitWith(t)(e);if(S.isSuccess(n))return yield*B(n.value)}return yield*H(P(e))}if(typeof e==`object`&&Symbol.iterator in e&&!(`type`in e))return yield*V(Ee(e));if(typeof e==`object`&&`type`in e&&!(Symbol.iterator in e)){let{type:t,props:n}=e;return t===oe?yield*De(n):t===le?yield*we(n):t===ce?yield*Te(n):t===ae?yield*Ce(n):t===se?yield*Pe(n):typeof t==`string`?yield*Oe(t,n):typeof t==`function`?yield*ke(t,n):yield*x.fail(new i({type:t,message:`Invalid Renderable type: expected string, FRAGMENT, or function, got ${typeof t}`}))}return null})}function Ee(e){let t=[];function n(e){if(N(e)||x.isEffect(e)){t.push(e);return}if(typeof e==`object`&&e&&Symbol.iterator in e&&!(`type`in e))for(let t of e)n(t);else t.push(e)}return n(e),t}function V(e){return x.gen(function*(){let t=[];for(let n of e)if(M(n)===void 0&&(N(n)||x.isEffect(n))){let e=yield*H(P(n));t.push(...e)}else{let e=yield*B(n);e!==null&&(Array.isArray(e)?t.push(...e):t.push(e))}return t})}function De(e){return x.gen(function*(){let t=`children`in e?e.children:void 0;return t===void 0?[]:yield*V(Array.isArray(t)?t:[t])})}function Oe(e,t){return x.gen(function*(){let n=document.createElement(e);yield*I(n,t);let r=`children`in t?t.children:void 0;if(r!==void 0){let e=Array.isArray(r)?r:[r];for(let t of e)if(M(t)===void 0&&(N(t)||x.isEffect(t))){let e=yield*H(P(t));for(let t of e)n.appendChild(t)}else{let e=yield*B(t);if(e!==null)if(Array.isArray(e))for(let t of e)n.appendChild(t);else n.appendChild(e)}}return n})}function ke(e,t){return x.gen(function*(){let i=e(t);if(N(i)||x.isEffect(i)){let e=yield*r,t=yield*D.fork(e.scope,`sequential`),a={...e,scope:t},o=yield*x.serviceOption(n),s=P(i);return T.isSome(o)&&(yield*o.value.register,s=A(s,O.zipWithIndex,O.flatMap(([e,t])=>t===0?O.fromEffect(x.as(o.value.settle,e)):O.make(e)))),yield*H(s).pipe(x.provideService(r,a),x.provideService(D.Scope,t))}return yield*B(i)})}function H(e){return x.gen(function*(){let t=yield*r,n=yield*F(),[i,a]=Ae(n),o=null;return yield*R(O.runForEach(e,e=>x.gen(function*(){o!==null&&(yield*D.close(o,S.void)),o=yield*D.fork(t.scope,`sequential`);let n={...t,scope:o};yield*U(i,a,e).pipe(x.provideService(r,n),x.provideService(D.Scope,o))})),t.scope,`child:stream-${n}`),[i,a]})}function Ae(e){return[document.createComment(l(e)),document.createComment(c(e))]}function U(e,t,n){return x.gen(function*(){let r=e.nextSibling,i=r!==null&&r!==t&&r.nextSibling===t;if(i&&r.nodeType===it&&W(n)){let e=String(n);r.data!==e&&(r.data=e);return}if(i&&r.nodeType===X){let e=G(n);if(e!==void 0&&typeof e.type==`string`&&r.tagName.toLowerCase()===e.type.toLowerCase()){yield*je(r,e);return}}K(e,t);let a=yield*B(n),o=e.parentNode;if(o!==null&&a!==null)if(Array.isArray(a))for(let e of a)o.insertBefore(e,t);else o.insertBefore(a,t)})}function W(e){return typeof e==`string`||typeof e==`number`||typeof e==`bigint`}function G(e){let t=M(e);if(t!==void 0)return t;if(typeof e==`object`&&e&&`type`in e&&!(Symbol.iterator in e)&&!N(e)&&!x.isEffect(e))return e}function je(e,t){return x.gen(function*(){yield*I(e,t.props);let n=t.props.children,r=n===void 0?[]:Array.isArray(n)?n:[n];if(!(yield*Me(e,r))){for(;e.firstChild!==null;)e.firstChild.remove();yield*Ne(e,r)}})}function Me(e,t){return x.gen(function*(){let n=Array.from(e.childNodes);if(n.length!==t.length)return!1;for(let e=0;e<t.length;e++){let r=t[e],i=n[e];if(W(r)){if(i.nodeType!==it)return!1}else{let e=G(r);if(e===void 0||typeof e.type!=`string`||i.nodeType!==X||i.tagName.toLowerCase()!==e.type.toLowerCase())return!1}}for(let e=0;e<t.length;e++){let r=t[e],i=n[e];if(W(r)){let e=String(r);i.data!==e&&(i.data=e)}else yield*je(i,G(r))}return!0})}function Ne(e,t){return x.gen(function*(){for(let n of t)if(N(n)||x.isEffect(n)){let t=yield*H(P(n));for(let n of t)e.appendChild(n)}else{let t=yield*B(n);if(t!==null)if(Array.isArray(t))for(let n of t)e.appendChild(n);else e.appendChild(t)}})}function K(e,t){let n=e.nextSibling;for(;n!==null&&n!==t;){let e=n.nextSibling;n.remove(),n=e}}function Pe(e){return x.gen(function*(){let t=yield*r,{of:n,by:i,render:a}=e,o=yield*F(),[s,c]=Ae(o),l=yield*D.fork(t.scope,`sequential`),u=(yield*ue.toSubscribable(n).pipe(x.provideService(D.Scope,l))).changes,d={records:C.empty(),order:[]};return yield*R(O.runForEach(u,e=>x.gen(function*(){d=yield*q(Array.from(e),i,a,d,l,c,t)})),l,`list:stream-${o}`),[s,c]})}function Fe(t,n){return x.gen(function*(){let r=[],i=w.empty();for(let a=0;a<t.length;a++){let o=n===void 0?t[a]:n(t[a],a);if(w.has(i,o))return yield*x.fail(new e({cause:o,message:`List.each: duplicate key ${ze(o)} in a single emission; keys must be unique (set a stable \`by\`).`}));i=w.add(i,o),r.push(o)}return r})}function q(e,t,n,r,i,a,o){return x.gen(function*(){let s=yield*Fe(e,t),c=C.empty();r.order.forEach((e,t)=>{c=C.set(c,e,t)});let l=[],u=[];for(let t=0;t<e.length;t++){let a=s[t],d=C.get(r.records,a);if(T.isSome(d))l.push(d.value),u.push(T.getOrElse(C.get(c,a),()=>-1));else{let r=yield*Ie(a,e[t],t,n,i,o);l.push(r),u.push(-1)}}let d=w.empty();for(let e of s)d=w.add(d,e);for(let e of r.order)if(!w.has(d,e)){let t=C.get(r.records,e);T.isSome(t)&&(yield*D.close(t.value.scope,S.void),Re(t.value.startMarker,t.value.endMarker))}let f=Be(u),p=a.parentNode;if(p!==null)for(let e=l.length-1;e>=0;e--){let t=l[e];if(u[e]!==-1&&f.has(e))continue;let n=e+1<l.length?l[e+1].startMarker:a,r=u[e]===-1?[t.startMarker,...t.nodes,t.endMarker]:Le(t.startMarker,t.endMarker);for(let e of r)p.insertBefore(e,n)}let m=C.empty();for(let e of l)m=C.set(m,e.key,e);return{records:m,order:s}})}function Ie(e,t,n,i,a,o){return x.gen(function*(){let s=yield*D.fork(a,`sequential`),c={...o,scope:s},l=yield*F(),u=document.createComment(g(l)),d=document.createComment(m(l)),f=yield*B(i(t,n)).pipe(x.provideService(r,c),x.provideService(D.Scope,s));return{key:e,scope:s,startMarker:u,endMarker:d,nodes:f===null?[]:Array.isArray(f)?f:[f]}})}function Le(e,t){let n=[],r=e;for(;r!==null&&(n.push(r),r!==t);)r=r.nextSibling;return n}function Re(e,t){let n=e;for(;n!==null;){let e=n.nextSibling;if(n.remove(),n===t)break;n=e}}function ze(e){if(typeof e==`string`)return JSON.stringify(e);if(typeof e==`object`&&e)try{return JSON.stringify(e)}catch{return Object.prototype.toString.call(e)}return String(e)}function Be(e){let t=e.length,n=[],r=Array.from({length:t},()=>-1);for(let i=0;i<t;i++){let t=e[i];if(t===-1)continue;let a=0,o=n.length;for(;a<o;){let r=a+o>>1;e[n[r]]<t?a=r+1:o=r}a>0&&(r[i]=n[a-1]),n[a]=i}let i=new Set,a=n.length>0?n[n.length-1]:-1;for(;a!==-1;)i.add(a),a=r[a];return i}function Ve(e,t){return x.gen(function*(){let n=yield*x.context(),i=yield*x.serviceOption(D.Scope),a=yield*D.make(),o=ne.make(te.succeedContext(y.add(n,D.Scope,a))),s={runtime:o,scope:a,streamIdCounter:{current:0}},c=x.andThen(D.close(a,S.void),x.promise(()=>o.dispose()));t.innerHTML=``;let l=yield*B(e).pipe(x.provideService(r,s),x.provideService(D.Scope,a),x.tapError(()=>c));if(l!==null)if(Array.isArray(l))for(let e of l)t.appendChild(e);else t.appendChild(l);let u=!1,d={unmount:()=>x.gen(function*(){u||(u=!0,yield*D.close(a,S.void),yield*x.promise(()=>o.dispose()))})};return T.isSome(i)&&(yield*D.addFinalizer(i.value,d.unmount())),d})}function He(e,t){return x.gen(function*(){let n=yield*x.context(),i=yield*x.serviceOption(D.Scope),a=yield*D.make(),o=ne.make(te.succeedContext(y.add(n,D.Scope,a))),s=yield*We(),c={runtime:o,scope:a,streamIdCounter:{current:0},hydrationReady:s};at(t,c.streamIdCounter);let l=x.andThen(D.close(a,S.void),x.promise(()=>o.dispose()));yield*J(e,t.firstChild,`root`).pipe(x.provideService(r,c),x.provideService(D.Scope,a),x.tapError(()=>l)),yield*s.settle,yield*s.awaitReady;let u=!1,d={unmount:()=>x.gen(function*(){u||(u=!0,yield*D.close(a,S.void),yield*x.promise(()=>o.dispose()))})};return T.isSome(i)&&(yield*D.addFinalizer(i.value,d.unmount())),d})}function J(e,t,n){return x.gen(function*(){if(typeof e==`string`||typeof e==`number`||typeof e==`bigint`)return yield*Ue(String(e),t,n);if(typeof e==`boolean`||e==null)return t;if(N(e)||x.isEffect(e)){let r=M(e);if(r!==void 0)return yield*J(r,t,n);if(x.isEffect(e)){let r=x.runSyncExit(e);if(S.isSuccess(r))return yield*J(r.value,t,n)}return yield*Ke(P(e),t,n)}if(typeof e==`object`&&Symbol.iterator in e&&!(`type`in e)){let r=t,i=0;for(let t of e)r=yield*J(t,r,`${n}[${i}]`),i++;return r}if(typeof e==`object`&&`type`in e&&!(Symbol.iterator in e)){let{type:r,props:a}=e;if(r===oe)return yield*Y(a,t,n);if(r===le){if(t!==null&&t.nodeType===Z){let e=_(t);if(e!==null&&e.kind===`start`)return yield*Je(t,n)}return yield*Y(a,t,n)}return r===ae?yield*Xe(a,t,n):r===ce?yield*Qe(a,t,n):r===se?yield*et(a,t,n):typeof r==`string`?yield*$e(r,a,t,n):typeof r==`function`?yield*J(r(a),t,n):yield*x.fail(new i({type:r,message:`Invalid Renderable type during hydration at ${n}: expected string, FRAGMENT, or function, got ${typeof r}`}))}return t})}function Ue(e,t,n){return x.gen(function*(){if(e.length===0)return t;if(t===null||t.nodeType!==it)return yield*$(`text ${JSON.stringify(e)}`,Q(t),n);let r=t;return r.data.startsWith(e)?r.data.length>e.length?r.splitText(e.length):r.nextSibling:yield*$(`text ${JSON.stringify(e)}`,Q(t),n)})}function We(){return x.gen(function*(){let e=yield*E.make(1),t=yield*b.make(),n=A(E.updateAndGet(e,e=>e-1),x.flatMap(e=>e<=0?x.asVoid(b.succeed(t,void 0)):x.void));return{register:E.update(e,e=>e+1),settle:n,awaitReady:b.await(t)}})}function Ge(e){let t=!1;return x.suspend(()=>t||e===void 0?x.void:(t=!0,e.settle))}function Ke(e,t,n){return x.gen(function*(){let i=yield*r;if(t===null||t.nodeType!==Z)return yield*$(`reactive region start marker`,Q(t),n);let a=t,o=d(a);if(o===null||o.kind!==`start`)return yield*$(`reactive region start marker`,Q(t),n);let s=ot(a);if(s===null)return yield*$(`reactive region end marker`,`unterminated region starting at ${JSON.stringify(a.data)}`,n);let c=Ge(i.hydrationReady),l=!0,u=null,f=O.runForEach(e,e=>x.gen(function*(){u!==null&&(yield*D.close(u,S.void)),u=yield*D.fork(i.scope,`sequential`);let t={...i,scope:u};yield*x.gen(function*(){l?(l=!1,yield*qe(e,a,s,n),yield*c):yield*U(a,s,e)}).pipe(x.provideService(r,t),x.provideService(D.Scope,u))})).pipe(x.ensuring(c));return i.hydrationReady!==void 0&&(yield*i.hydrationReady.register),yield*R(f,i.scope,`hydrate:stream-${o.id} (${n})`),s.nextSibling})}function qe(e,t,n,r){return x.gen(function*(){let i=yield*J(e,t.nextSibling,`${r}<resume>`).pipe(x.map(e=>e===n?null:`adopted content did not align with the end marker`),x.catchTag(`HydrationMismatchError`,e=>x.succeed(`expected ${e.expected}, found ${e.actual} at ${e.path}`)));i!==null&&(console.error(`[weft] hydrate: reactive region at ${r} diverged from server output (${i}); patching.`),yield*U(t,n,e))})}function Je(e,t){return x.gen(function*(){let n=Ye(e);if(n===null)return yield*$(`substituted suspense end marker`,`unterminated region starting at ${JSON.stringify(e.data)}`,t);let r=null;for(let t=e.nextSibling;t!==null&&t!==n;t=t.nextSibling)if(t.nodeType===X&&t.tagName===`SCRIPT`&&t.getAttribute(`type`)===`application/json`&&t.hasAttribute(`data-weft-suspense-failure`)){r=t;break}let i=null;if(r!==null){let e=r.textContent??``;i=yield*x.try({try:()=>JSON.parse(e),catch:e=>e}).pipe(x.catch(()=>x.succeed(null)))}if(typeof i!=`object`||!i||!(`error`in i))return console.error(`[weft] hydrate: substituted suspense region at ${t} has no decodable failure sentinel; leaving its static content.`),n.nextSibling;let o=yield*x.serviceOption(a);return T.isNone(o)?(console.error(`[weft] hydrate: substituted suspense region at ${t} has no enclosing Boundary to replay its failure to; leaving its static content.`,i.error),n.nextSibling):(yield*o.value.reportError(v.fail(i.error)),n.nextSibling)})}function Ye(e){let t=0,n=e.nextSibling;for(;n!==null;){if(n.nodeType===Z){let e=_(n);if(e!==null)if(e.kind===`start`)t++;else if(t===0)return n;else t--}n=n.nextSibling}return null}function Xe(e,t,n){return x.gen(function*(){if(t===null||t.nodeType!==X||t.tagName!==`SCRIPT`||t.getAttribute(`type`)!==`application/json`||!t.hasAttribute(`data-weft-boundary-failure`)){let i=yield*r,s=yield*x.serviceOption(a),c=yield*D.fork(i.scope,`sequential`),l={...i,scope:c},d=yield*b.make(),f=yield*Y(e,t,n).pipe(x.provideService(a,{reportError:e=>b.fail(d,e).pipe(x.asVoid)}),x.provideService(r,l),x.provideService(D.Scope,c)),p=t?.parentNode??null;if(t===null||t===f||p===null)return console.error(`[weft] hydrate: boundary at ${n} adopted an empty extent; live failure recovery is not installed for it.`),f;let m=pe(),h=document.createComment(o(m)),g=document.createComment(u(m));return p.insertBefore(h,t),f===null?p.appendChild(g):p.insertBefore(g,f),yield*x.forkIn(Se(e,d,c,s,h,g),i.scope),f}let i=t,s=i.textContent??``,c=yield*x.gen(function*(){let t=yield*x.try({try:()=>JSON.parse(s),catch:e=>e}),n=p(e.children)[t.index];if(n===void 0)return null;let r=yield*re.decodeUnknownEffect(n.errorSchema)(t.error);return e.match(v.fail(r))}).pipe(x.catch(e=>(console.error(`[weft] hydrate: boundary failure payload at ${n} failed to decode; cannot replay.`,e),x.succeed(null))));if(c===null)return yield*$(`replayable boundary failure`,`undecodable failure payload`,n);let l=yield*J(c,i.nextSibling,n);return i.remove(),l})}function Ze(e,t,n,r){return x.gen(function*(){let i=yield*k.make(n),a=yield*k.make(!1),o=yield*k.make(T.none()),s=T.match(r,{onNone:()=>x.void,onSome:n=>x.gen(function*(){(yield*k.get(a))||(yield*k.set(a,!0),yield*x.gen(function*(){let r=yield*x.exit(n.call(e,t()));S.isSuccess(r)?(yield*k.set(i,r.value),yield*k.set(o,T.none())):yield*k.set(o,T.some(v.squash(r.cause)))}).pipe(x.ensuring(k.set(a,!1))))})});return{value:j.make({get:k.get(i),changes:k.changes(i)}),refetch:s,pending:j.make({get:k.get(a),changes:k.changes(a)}),error:j.make({get:k.get(o),changes:k.changes(o)})}})}function Qe(e,t,n){return x.gen(function*(){if(t===null||t.nodeType!==X||t.tagName!==`SCRIPT`||t.getAttribute(`type`)!==`application/json`)return yield*$(`server boundary payload <script type="application/json">`,Q(t),n);if(t.hasAttribute(`data-weft-boundary-failure`))return yield*$(`server boundary success payload <script type="application/json">`,`boundary failure payload`,n);let r=t,i=r.textContent??``,a=yield*x.try({try:()=>JSON.parse(i),catch:e=>e}).pipe(x.flatMap(t=>re.decodeUnknownEffect(e.successSchema)(t)),x.catch(e=>(console.error(`[weft] hydrate: server boundary payload at ${n} failed to decode; cannot replay.`,e),$(`decodable server boundary payload`,`undecodable payload`,n)))),o=yield*x.serviceOption(ie),s=yield*Ze(e.tag,e.payload,a,o),c=yield*J(e.render(s),r.nextSibling,n);return r.remove(),c})}function $e(e,t,n,r){return x.gen(function*(){if(n===null||n.nodeType!==X)return yield*$(`<${e}>`,Q(n),r);let i=n;return i.tagName.toLowerCase()===e.toLowerCase()?(yield*I(i,t),yield*Y(t,i.firstChild,`${r} > ${e}`),i.nextSibling):yield*$(`<${e}>`,Q(n),r)})}function Y(e,t,n){return x.gen(function*(){let r=`children`in e?e.children:void 0;if(r===void 0)return t;let i=Array.isArray(r)?r:[r],a=t,o=0;for(let e of i)a=yield*J(e,a,`${n}[${o}]`),o++;return a})}function et(e,t,n){return x.gen(function*(){let i=yield*r,{of:a,by:o,render:s}=e;if(t===null||t.nodeType!==Z)return yield*$(`list region start marker`,Q(t),n);let c=t,l=d(c);if(l===null||l.kind!==`start`)return yield*$(`list region start marker`,Q(t),n);let u=ot(c);if(u===null)return yield*$(`list region end marker`,`unterminated region starting at ${JSON.stringify(c.data)}`,n);let f=tt(c,u),p=yield*D.fork(i.scope,`sequential`),m=(yield*ue.toSubscribable(a).pipe(x.provideService(D.Scope,p))).changes,h={records:C.empty(),order:[]},g=!0,_=Ge(i.hydrationReady),v=O.runForEach(m,e=>x.gen(function*(){let t=Array.from(e);g?(g=!1,h=yield*nt(t,o,s,f,p,c,u,i,n),yield*_):h=yield*q(t,o,s,h,p,u,i)})).pipe(x.ensuring(_));return i.hydrationReady!==void 0&&(yield*i.hydrationReady.register),yield*R(v,p,`hydrate:list-${l.id} (${n})`),u.nextSibling})}function tt(e,t){let n=[],r=e.nextSibling;for(;r!==null&&r!==t;){let e=r.nodeType===Z?s(r):null;if(e===null||e.kind!==`start`){r=r.nextSibling;continue}let i=r,a=[],o=0,c=null,l=i.nextSibling;for(;l!==null&&l!==t;){if(l.nodeType===Z){let e=s(l);if(e!==null)if(e.kind===`start`)o++;else if(o===0){c=l;break}else o--}a.push(l),l=l.nextSibling}if(c===null)break;n.push({startMarker:i,endMarker:c,nodes:a}),r=c.nextSibling}return n}function nt(e,t,n,r,i,a,o,s,c){return x.gen(function*(){let l=yield*Fe(e,t);if(l.length!==r.length)return console.error(`[weft] hydrate: list region at ${c} had ${r.length} server item(s) but the first emission has ${l.length}; rebuilding.`),K(a,o),yield*q(e,t,n,{records:C.empty(),order:[]},i,o,s);let u=[];for(let t=0;t<e.length;t++){let a=yield*rt(l[t],e[t],t,n,r[t],i,s,c);u.push(a)}let d=C.empty();for(let e of u)d=C.set(d,e.key,e);return{records:d,order:l}})}function rt(e,t,n,i,a,o,s,c){return x.gen(function*(){let l=yield*D.fork(o,`sequential`),u={...s,scope:l},d=i(t,n),f=yield*J(d,a.startMarker.nextSibling,`${c}<item>`).pipe(x.provideService(r,u),x.provideService(D.Scope,l),x.map(e=>e===a.endMarker?null:`adopted item content did not align with its end marker`),x.catchTag(`HydrationMismatchError`,e=>x.succeed(`expected ${e.expected}, found ${e.actual} at ${e.path}`)));if(f===null)return{key:e,scope:l,startMarker:a.startMarker,endMarker:a.endMarker,nodes:a.nodes};console.error(`[weft] hydrate: list item at ${c} diverged from server output (${f}); patching.`),yield*D.close(l,S.void);let p=yield*D.fork(o,`sequential`),m={...s,scope:p};K(a.startMarker,a.endMarker);let h=yield*B(d).pipe(x.provideService(r,m),x.provideService(D.Scope,p)),g=h===null?[]:Array.isArray(h)?h:[h],_=a.endMarker.parentNode;if(_!==null)for(let e of g)_.insertBefore(e,a.endMarker);return{key:e,scope:p,startMarker:a.startMarker,endMarker:a.endMarker,nodes:g}})}const X=1,it=3,Z=8;function at(e,t){let n=document.createTreeWalker(e,128),r=t.current;for(let e=n.nextNode();e!==null;e=n.nextNode()){let t=e,n=d(t)??_(t)??s(t);n!==null&&n.id>r&&(r=n.id)}t.current=r}function ot(e){let t=0,n=e.nextSibling;for(;n!==null;){if(n.nodeType===8){let e=d(n);if(e!==null)if(e.kind===`start`)t++;else if(t===0)return n;else t--}n=n.nextSibling}return null}function Q(e){if(e===null)return`end of children`;switch(e.nodeType){case 1:return`<${e.tagName.toLowerCase()}>`;case 3:return`text ${JSON.stringify(e.data)}`;case 8:return`comment ${JSON.stringify(e.data)}`;default:return`node(type ${e.nodeType})`}}function $(e,n,r){return x.fail(new t({expected:e,actual:n,path:r}))}function st(e,t){return A(Ve(e,t),x.tap(e=>x.addFinalizer(()=>e.unmount())))}function ct(e,t){return A(He(e,t),x.tap(e=>x.addFinalizer(()=>e.unmount())))}export{He as hydrate,ct as hydrateScoped,Ve as mount,st as mountScoped};
@@ -1 +1 @@
1
- import{Context as e,Data as t}from"effect";var n=class extends t.TaggedError(`UnsupportedNodeTypeError`){},r=class extends t.TaggedError(`StreamSubscriptionError`){},i=class extends t.TaggedError(`RenderError`){},a=class extends t.TaggedError(`HydrationMismatchError`){},o=class extends e.Tag(`BoundaryContext`)(){},s=class extends e.Tag(`SuspenseContext`)(){},c=class extends e.Tag(`RenderContext`)(){};export{r as a,i,a as n,s as o,c as r,n as s,o as t};
1
+ import{Context as e,Data as t}from"effect";var n=class extends t.TaggedError(`UnsupportedNodeTypeError`){},r=class extends t.TaggedError(`StreamSubscriptionError`){},i=class extends t.TaggedError(`RenderError`){},a=class extends t.TaggedError(`HydrationMismatchError`){},o=class extends e.Service()(`BoundaryContext`){},s=class extends e.Service()(`SuspenseContext`){},c=class extends e.Service()(`RenderContext`){};export{r as a,i,a as n,s as o,c as r,n as s,o as t};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{a as e,i as t,n,s as r}from"./data-Bk62ePeP.js";export{n as HydrationMismatchError,t as RenderError,e as StreamSubscriptionError,r as UnsupportedNodeTypeError};
1
+ import{a as e,i as t,n,s as r}from"./data-uLmMpQMV.js";export{n as HydrationMismatchError,t as RenderError,e as StreamSubscriptionError,r as UnsupportedNodeTypeError};
@@ -123,9 +123,9 @@ interface SuspenseFailureHandler {
123
123
  /** Decide a substitute for an unhandled Suspense resolution failure. */
124
124
  readonly handle: (cause: Cause.Cause<unknown>) => Option.Option<SuspenseFailureSubstitute>;
125
125
  }
126
- declare const SuspenseFailureHandlerTag_base: Context.TagClass<SuspenseFailureHandlerTag, "@weftui/dom/SuspenseFailureHandler", SuspenseFailureHandler>;
126
+ declare const SuspenseFailureHandlerTag_base: Context.ServiceClass<SuspenseFailureHandlerTag, "@weftui/dom/SuspenseFailureHandler", SuspenseFailureHandler>;
127
127
  /**
128
- * `Context.Tag` for the {@link SuspenseFailureHandler} seam. Read via
128
+ * `Context.Service` key for the {@link SuspenseFailureHandler} seam. Read via
129
129
  * `Effect.serviceOption` inside the Suspense resolution fiber, so providing it
130
130
  * is always optional. Lives in `@weftui/dom` (like `AppRpcClientTag`) so dom
131
131
  * never imports its consumers.
@@ -1 +1 @@
1
- import{s as e}from"../data-Bk62ePeP.js";import{d as t,f as n,m as r,n as i,o as a,p as o,r as s,s as c,t as l}from"../boundary-replay-BR26_puM.js";import{Cause as u,Context as d,Effect as f,ExecutionStrategy as p,Exit as m,Option as h,Queue as g,Ref as _,Schema as v,Scope as y,Stream as b,Subscribable as x}from"effect";import{AppRpcClientTag as ee,FAILURE_BOUNDARY as S,FRAGMENT as C,LIST as w,SERVER_BOUNDARY as T,SUSPENSE_BOUNDARY as E,Source as D,getElementDescriptor as O,isStream as k,toStream as A}from"@weftui/core";function te(e){if(e.length<=2||!e.startsWith(`on`))return!1;let t=e[2];return t!==void 0&&t>=`a`&&t<=`z`}const j=new Set([`area`,`base`,`br`,`col`,`embed`,`hr`,`img`,`input`,`link`,`meta`,`param`,`source`,`track`,`wbr`]),M={'"':`&quot;`,"&":`&amp;`,"'":`&#x27;`,"<":`&lt;`,">":`&gt;`};function N(e){return e.replace(/["'&<>]/g,e=>M[e]??e)}const ne=new Set([38,60,62,8232,8233]);function P(e){let t=JSON.stringify(e),n=``;for(let e=0;e<t.length;e++){let r=t.charCodeAt(e);ne.has(r)?n+=`\\u${r.toString(16).padStart(4,`0`)}`:n+=t[e]}return n}function re(e){return e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function F(e){return f.gen(function*(){let t=``;for(let[n,r]of Object.entries(e))if(!(n===`children`||n===`ref`||te(n))){if(n===`style`){t+=yield*R(r);continue}t+=yield*L(n,r)}return t})}function I(e){return k(e)||f.isEffect(e)?A(e).pipe(b.runHead,f.map(h.getOrElse(()=>void 0))):f.succeed(e)}function L(e,t){return f.gen(function*(){let n=yield*I(t);return n==null?``:typeof n==`boolean`?n?` ${e}=""`:``:` ${e}="${N(String(n))}"`})}function R(e){return f.gen(function*(){let t=yield*I(e);if(t==null)return``;if(typeof t==`string`)return t===``?``:` style="${N(t)}"`;if(typeof t==`object`){let e=[];for(let[n,r]of Object.entries(t)){let t=yield*I(r);t!=null&&e.push(`${re(n)}: ${String(t)}`)}return e.length===0?``:` style="${N(e.join(`; `))}"`}return``})}var z=class extends d.Tag(`@weftui/dom/SuspenseFailureHandler`)(){};function B(e,t,n=!1,i){let a=r(e),c=o(e),l=n?`var m=document.createElement("meta");m.setAttribute("name","robots");m.setAttribute("content","noindex");document.head.appendChild(m);`:``,u=i!==void 0,d=u?`<script type="application/json" ${s}>`+P({error:i})+`<\/script>`+t:t,f=u?``:`p.removeChild(s);p.removeChild(e);`;return`<template id="ef-s-${e}">${d}</template><script>(function(){`+l+`var w=document.createTreeWalker(document,128),s,e;while(w.nextNode()){var d=w.currentNode.data;if(d==="${a}")s=w.currentNode;if(d==="${c}"){e=w.currentNode;break;}}if(!s||!e)return;var p=s.parentNode,c=s.nextSibling,n;while(c&&c!==e){n=c.nextSibling;p.removeChild(c);c=n;}var t=document.getElementById("ef-s-${e}");p.insertBefore(t.content,e);`+f+`t.remove();document.currentScript.remove();})();<\/script>`}function V(e,t,n){return b.unwrap(f.gen(function*(){let i=++t.idCounter.current;yield*_.update(t.pendingCount,e=>e+1);let a=e.children===void 0?null:(Array.isArray(e.children),e.children),s=f.gen(function*(){let e=yield*b.mkString(n(a));yield*g.offer(t.patchQueue,h.some(B(i,e)))}).pipe(f.catchAllCause(e=>u.isInterruptedOnly(e)?f.failCause(e):f.gen(function*(){let r=yield*f.serviceOption(z);if(h.isNone(r))return;let a=r.value.handle(e);if(h.isNone(a))return;let o=yield*b.mkString(n(a.value.content));yield*g.offer(t.patchQueue,h.some(B(i,o,a.value.markNoindex,a.value.failureReplay)))})),f.ensuring(_.updateAndGet(t.pendingCount,e=>e-1).pipe(f.flatMap(e=>e<=0?g.offer(t.patchQueue,h.none()).pipe(f.asVoid):f.void))),f.ignore);yield*f.forkIn(s,t.scope);let c=`<!--${r(i)}-->`,l=`<!--${o(i)}-->`,d=e.fallback??null;return b.make(c).pipe(b.concat(n(d)),b.concat(b.make(l)))}))}function H(e,t,n){let r=e.children.length===0?null:e.children.length===1?e.children[0]:e.children;return b.unwrapScoped(f.gen(function*(){let a=yield*b.mkString(n(r)).pipe(f.catchAllCause(r=>f.gen(function*(){let a=e.match(r);if(a===null)return yield*f.failCause(r);let o=yield*b.mkString(n(a));if(t===null)return o;let s=yield*_.getAndSet(t,h.none());return h.isNone(s)?o:`<script type="application/json" ${l}>${P({index:i(e.children).indexOf(s.value.owner),error:s.value.encoded})}<\/script>`+o})));return b.make(a)}))}function ie(e,t,n){if(t===null)return f.failCause(n);let r=u.failureOption(n);return h.isNone(r)?f.failCause(n):v.encode(e.errorSchema)(r.value).pipe(f.flatMap(n=>_.set(t,h.some({owner:e,encoded:n}))),f.matchCauseEffect({onFailure:()=>f.failCause(n),onSuccess:()=>f.failCause(n)}))}function U(e){return{value:x.make({get:f.succeed(e),changes:b.make(e)}),refetch:f.void,pending:x.make({get:f.succeed(!1),changes:b.make(!1)}),error:x.make({get:f.succeed(h.none()),changes:b.make(h.none())})}}function W(e,t,n,r){return b.unwrap(f.gen(function*(){let i=yield*(yield*ee).call(e.tag,e.payload()).pipe(f.catchAllCause(t=>ie(e,n,t))),a=r(e.render(U(i)));if(!t)return a;let o=`<script type="application/json">${P(yield*v.encode(e.successSchema)(i))}<\/script>`;return b.make(o).pipe(b.concat(a))}))}function G(e){return f.scoped(D.toSubscribable(e).pipe(f.flatMap(e=>e.get),f.map(e=>Array.from(e)),f.catchTag(`NoPropValue`,()=>f.succeed([]))))}function K(t,n){if(t==null||typeof t==`boolean`)return b.empty;if(typeof t==`string`||typeof t==`number`||typeof t==`bigint`)return b.make(N(String(t)));if(k(t)||f.isEffect(t)){let e=O(t);if(e!==void 0)return K(e,n);if(f.isEffect(t)){let e=f.runSyncExit(t);if(m.isSuccess(e))return K(e.value,n)}return A(t).pipe(b.runHead,f.map(h.match({onNone:()=>b.empty,onSome:e=>K(e,n)})),b.unwrap)}if(typeof t==`object`&&Symbol.iterator in t&&!(`type`in t))return b.flatMap(b.fromIterable(t),e=>K(e,n));if(typeof t==`object`&&`type`in t&&!(Symbol.iterator in t)){let{type:e,props:r}=t;if(e===C)return J(r,n);if(e===E){let e=r;return n===null?K(e.fallback??null,null):V(e,n,e=>K(e,n))}if(e===S)return H(r,null,e=>K(e,n));if(e===T)return W(r,!1,null,e=>K(e,n));if(e===w)return q(r,n);if(typeof e==`string`){let t=b.fromEffect(F(r).pipe(f.map(t=>`<${e}${t}>`)));return j.has(e)?t:t.pipe(b.concat(J(r,n)),b.concat(b.make(`</${e}>`)))}if(typeof e==`function`)return K(e(r),n)}return b.fail(new e({type:t.type,message:`Invalid Renderable type: expected string, FRAGMENT, or function, got ${typeof t.type}`}))}function q(e,t){return b.unwrap(f.gen(function*(){let n=yield*G(e.of),r=b.empty;return n.forEach((n,i)=>{r=r.pipe(b.concat(K(e.render(n,i),t)))}),r}))}function J(e,t){let n=`children`in e?e.children:void 0;if(n==null)return b.empty;let r=Array.isArray(n)?n:[n];return b.flatMap(b.fromIterable(r),e=>K(e,t))}function Y(r,i,a){if(r==null||typeof r==`boolean`)return b.empty;if(typeof r==`string`||typeof r==`number`||typeof r==`bigint`)return b.make(N(String(r)));if(k(r)||f.isEffect(r)){let e=O(r);if(e!==void 0)return Y(e,i,a);if(f.isEffect(r)){let e=f.runSyncExit(r);if(m.isSuccess(e))return Y(e.value,i,a)}return A(r).pipe(b.runHead,f.map(e=>{let r=++i.current,o=h.match(e,{onNone:()=>b.empty,onSome:e=>Y(e,i,a)});return b.make(`<!--${n(r)}-->`).pipe(b.concat(o),b.concat(b.make(`<!--${t(r)}-->`)))}),b.unwrap)}if(typeof r==`object`&&Symbol.iterator in r&&!(`type`in r))return b.flatMap(b.fromIterable(r),e=>Y(e,i,a));if(typeof r==`object`&&`type`in r&&!(Symbol.iterator in r)){let{type:e,props:t}=r;if(e===C)return X(t,i,a);if(e===E){let e=t;return a===null?Y(e.fallback??null,i,null):V(e,a,e=>Y(e,i,a))}if(e===S)return H(t,a?.failureCollector??null,e=>Y(e,i,a));if(e===T)return W(t,!0,a?.failureCollector??null,e=>Y(e,i,a));if(e===w)return ae(t,i,a);if(typeof e==`string`){let n=b.fromEffect(F(t).pipe(f.map(t=>`<${e}${t}>`)));return j.has(e)?n:n.pipe(b.concat(X(t,i,a)),b.concat(b.make(`</${e}>`)))}if(typeof e==`function`)return Y(e(t),i,a)}return b.fail(new e({type:r.type,message:`Invalid Renderable type: expected string, FRAGMENT, or function, got ${typeof r.type}`}))}function ae(e,r,i){return b.unwrap(f.gen(function*(){let o=++r.current,s=yield*G(e.of),l=b.empty;return s.forEach((t,n)=>{let o=++r.current;l=l.pipe(b.concat(b.make(`<!--${c(o)}-->`)),b.concat(Y(e.render(t,n),r,i)),b.concat(b.make(`<!--${a(o)}-->`)))}),b.make(`<!--${n(o)}-->`).pipe(b.concat(l),b.concat(b.make(`<!--${t(o)}-->`)))}))}function X(e,t,n){let r=`children`in e?e.children:void 0;if(r==null)return b.empty;let i=Array.isArray(r)?r:[r];return b.flatMap(b.fromIterable(i),e=>Y(e,t,n))}const oe=e=>K(e,null),se=e=>b.unwrapScoped(f.gen(function*(){let t=yield*g.unbounded(),n=yield*_.make(0),r=K(e,{patchQueue:t,pendingCount:n,idCounter:{current:0},scope:yield*f.scope,failureCollector:null}).pipe(b.ensuring(_.get(n).pipe(f.flatMap(e=>e===0?g.offer(t,h.none()).pipe(f.asVoid):f.void))));return b.concat(r,Z(t))})),Z=e=>b.fromQueue(e).pipe(b.takeWhile(h.isSome),b.map(e=>e.value)),Q=(e,t)=>f.gen(function*(){let n=yield*g.unbounded(),r=yield*_.make(0);return{mainStream:Y(e,{current:0},{patchQueue:n,pendingCount:r,idCounter:{current:0},scope:t,failureCollector:yield*_.make(h.none())}).pipe(b.ensuring(_.get(r).pipe(f.flatMap(e=>e===0?g.offer(n,h.none()).pipe(f.asVoid):f.void)))),patches:Z(n)}}),$=e=>b.unwrapScoped(f.gen(function*(){let t=yield*f.scope,{mainStream:n,patches:r}=yield*Q(e,t);return b.concat(n,r)})),ce=e=>oe(e).pipe(b.mkString),le=e=>$(e).pipe(b.mkString),ue=e=>f.gen(function*(){let t=yield*f.scope,n=yield*y.fork(t,p.sequential),{mainStream:r,patches:i}=yield*Q(e,n);return{shell:yield*b.mkString(r).pipe(f.onError(e=>y.close(n,m.failCause(e)))),patches:i}});export{z as SuspenseFailureHandlerTag,ue as renderToHydratableShell,se as renderToStream,$ as renderToStreamHydratable,ce as renderToString,le as renderToStringHydratable};
1
+ import{s as e}from"../data-uLmMpQMV.js";import{d as t,f as n,m as r,n as i,o as a,p as o,r as s,s as c,t as l}from"../boundary-replay-BR26_puM.js";import{Cause as u,Context as d,Effect as f,Exit as p,Option as m,Queue as h,Ref as g,Schema as _,Scope as v,Stream as y}from"effect";import{AppRpcClientTag as ee,FAILURE_BOUNDARY as b,FRAGMENT as x,LIST as S,SERVER_BOUNDARY as C,SUSPENSE_BOUNDARY as w,Source as T,Subscribable as E,getElementDescriptor as D,isStream as O,toStream as k}from"@weftui/core";function A(e){if(e.length<=2||!e.startsWith(`on`))return!1;let t=e[2];return t!==void 0&&t>=`a`&&t<=`z`}const j=new Set([`area`,`base`,`br`,`col`,`embed`,`hr`,`img`,`input`,`link`,`meta`,`param`,`source`,`track`,`wbr`]),te={'"':`&quot;`,"&":`&amp;`,"'":`&#x27;`,"<":`&lt;`,">":`&gt;`};function M(e){return e.replace(/["'&<>]/g,e=>te[e]??e)}const N=new Set([38,60,62,8232,8233]);function P(e){let t=JSON.stringify(e),n=``;for(let e=0;e<t.length;e++){let r=t.charCodeAt(e);N.has(r)?n+=`\\u${r.toString(16).padStart(4,`0`)}`:n+=t[e]}return n}function ne(e){return e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function F(e){return f.gen(function*(){let t=``;for(let[n,r]of Object.entries(e))if(!(n===`children`||n===`ref`||A(n))){if(n===`style`){t+=yield*R(r);continue}t+=yield*L(n,r)}return t})}function I(e){return O(e)||f.isEffect(e)?k(e).pipe(y.runHead,f.map(m.getOrElse(()=>void 0))):f.succeed(e)}function L(e,t){return f.gen(function*(){let n=yield*I(t);return n==null?``:typeof n==`boolean`?n?` ${e}=""`:``:` ${e}="${M(String(n))}"`})}function R(e){return f.gen(function*(){let t=yield*I(e);if(t==null)return``;if(typeof t==`string`)return t===``?``:` style="${M(t)}"`;if(typeof t==`object`){let e=[];for(let[n,r]of Object.entries(t)){let t=yield*I(r);t!=null&&e.push(`${ne(n)}: ${String(t)}`)}return e.length===0?``:` style="${M(e.join(`; `))}"`}return``})}var z=class extends d.Service()(`@weftui/dom/SuspenseFailureHandler`){};function B(e,t,n=!1,i){let a=r(e),c=o(e),l=n?`var m=document.createElement("meta");m.setAttribute("name","robots");m.setAttribute("content","noindex");document.head.appendChild(m);`:``,u=i!==void 0,d=u?`<script type="application/json" ${s}>`+P({error:i})+`<\/script>`+t:t,f=u?``:`p.removeChild(s);p.removeChild(e);`;return`<template id="ef-s-${e}">${d}</template><script>(function(){`+l+`var w=document.createTreeWalker(document,128),s,e;while(w.nextNode()){var d=w.currentNode.data;if(d==="${a}")s=w.currentNode;if(d==="${c}"){e=w.currentNode;break;}}if(!s||!e)return;var p=s.parentNode,c=s.nextSibling,n;while(c&&c!==e){n=c.nextSibling;p.removeChild(c);c=n;}var t=document.getElementById("ef-s-${e}");p.insertBefore(t.content,e);`+f+`t.remove();document.currentScript.remove();})();<\/script>`}function V(e,t,n){return y.unwrap(f.gen(function*(){let i=++t.idCounter.current;yield*g.update(t.pendingCount,e=>e+1);let a=e.children===void 0?null:(Array.isArray(e.children),e.children),s=f.gen(function*(){let e=yield*y.mkString(n(a));yield*h.offer(t.patchQueue,m.some(B(i,e)))}).pipe(f.catchCause(e=>u.hasInterruptsOnly(e)?f.failCause(e):f.gen(function*(){let r=yield*f.serviceOption(z);if(m.isNone(r))return;let a=r.value.handle(e);if(m.isNone(a))return;let o=yield*y.mkString(n(a.value.content));yield*h.offer(t.patchQueue,m.some(B(i,o,a.value.markNoindex,a.value.failureReplay)))})),f.ensuring(g.updateAndGet(t.pendingCount,e=>e-1).pipe(f.flatMap(e=>e<=0?h.offer(t.patchQueue,m.none()).pipe(f.asVoid):f.void))),f.ignore);yield*f.forkIn(s,t.scope);let c=`<!--${r(i)}-->`,l=`<!--${o(i)}-->`,d=e.fallback??null;return y.make(c).pipe(y.concat(n(d)),y.concat(y.make(l)))}))}function H(e,t,n){let r=e.children.length===0?null:e.children.length===1?e.children[0]:e.children;return y.unwrap(f.gen(function*(){let a=yield*y.mkString(n(r)).pipe(f.catchCause(r=>f.gen(function*(){let a=e.match(r);if(a===null)return yield*f.failCause(r);let o=yield*y.mkString(n(a));if(t===null)return o;let s=yield*g.getAndSet(t,m.none());return m.isNone(s)?o:`<script type="application/json" ${l}>${P({index:i(e.children).indexOf(s.value.owner),error:s.value.encoded})}<\/script>`+o})));return y.make(a)}))}function re(e,t,n){if(t===null)return f.failCause(n);let r=u.findErrorOption(n);return m.isNone(r)?f.failCause(n):_.encodeEffect(e.errorSchema)(r.value).pipe(f.flatMap(n=>g.set(t,m.some({owner:e,encoded:n}))),f.matchCauseEffect({onFailure:()=>f.failCause(n),onSuccess:()=>f.failCause(n)}))}function U(e){return{value:E.make({get:f.succeed(e),changes:y.make(e)}),refetch:f.void,pending:E.make({get:f.succeed(!1),changes:y.make(!1)}),error:E.make({get:f.succeed(m.none()),changes:y.make(m.none())})}}function W(e,t,n,r){return y.unwrap(f.gen(function*(){let i=yield*(yield*ee).call(e.tag,e.payload()).pipe(f.catchCause(t=>re(e,n,t))),a=r(e.render(U(i)));if(!t)return a;let o=`<script type="application/json">${P(yield*_.encodeEffect(e.successSchema)(i))}<\/script>`;return y.make(o).pipe(y.concat(a))}))}function G(e){return f.scoped(T.toSubscribable(e).pipe(f.flatMap(e=>e.get),f.map(e=>Array.from(e)),f.catchTag(`NoPropValue`,()=>f.succeed([]))))}function K(t,n){if(t==null||typeof t==`boolean`)return y.empty;if(typeof t==`string`||typeof t==`number`||typeof t==`bigint`)return y.make(M(String(t)));if(O(t)||f.isEffect(t)){let e=D(t);if(e!==void 0)return K(e,n);if(f.isEffect(t)){let e=f.runSyncExit(t);if(p.isSuccess(e))return K(e.value,n)}return k(t).pipe(y.runHead,f.map(m.match({onNone:()=>y.empty,onSome:e=>K(e,n)})),y.unwrap)}if(typeof t==`object`&&Symbol.iterator in t&&!(`type`in t))return y.flatMap(y.fromIterable(t),e=>K(e,n));if(typeof t==`object`&&`type`in t&&!(Symbol.iterator in t)){let{type:e,props:r}=t;if(e===x)return J(r,n);if(e===w){let e=r;return n===null?K(e.fallback??null,null):V(e,n,e=>K(e,n))}if(e===b)return H(r,null,e=>K(e,n));if(e===C)return W(r,!1,null,e=>K(e,n));if(e===S)return q(r,n);if(typeof e==`string`){let t=y.fromEffect(F(r).pipe(f.map(t=>`<${e}${t}>`)));return j.has(e)?t:t.pipe(y.concat(J(r,n)),y.concat(y.make(`</${e}>`)))}if(typeof e==`function`)return K(e(r),n)}return y.fail(new e({type:t.type,message:`Invalid Renderable type: expected string, FRAGMENT, or function, got ${typeof t.type}`}))}function q(e,t){return y.unwrap(f.gen(function*(){let n=yield*G(e.of),r=y.empty;return n.forEach((n,i)=>{r=r.pipe(y.concat(K(e.render(n,i),t)))}),r}))}function J(e,t){let n=`children`in e?e.children:void 0;if(n==null)return y.empty;let r=Array.isArray(n)?n:[n];return y.flatMap(y.fromIterable(r),e=>K(e,t))}function Y(r,i,a){if(r==null||typeof r==`boolean`)return y.empty;if(typeof r==`string`||typeof r==`number`||typeof r==`bigint`)return y.make(M(String(r)));if(O(r)||f.isEffect(r)){let e=D(r);if(e!==void 0)return Y(e,i,a);if(f.isEffect(r)){let e=f.runSyncExit(r);if(p.isSuccess(e))return Y(e.value,i,a)}return k(r).pipe(y.runHead,f.map(e=>{let r=++i.current,o=m.match(e,{onNone:()=>y.empty,onSome:e=>Y(e,i,a)});return y.make(`<!--${n(r)}-->`).pipe(y.concat(o),y.concat(y.make(`<!--${t(r)}-->`)))}),y.unwrap)}if(typeof r==`object`&&Symbol.iterator in r&&!(`type`in r))return y.flatMap(y.fromIterable(r),e=>Y(e,i,a));if(typeof r==`object`&&`type`in r&&!(Symbol.iterator in r)){let{type:e,props:t}=r;if(e===x)return X(t,i,a);if(e===w){let e=t;return a===null?Y(e.fallback??null,i,null):V(e,a,e=>Y(e,i,a))}if(e===b)return H(t,a?.failureCollector??null,e=>Y(e,i,a));if(e===C)return W(t,!0,a?.failureCollector??null,e=>Y(e,i,a));if(e===S)return ie(t,i,a);if(typeof e==`string`){let n=y.fromEffect(F(t).pipe(f.map(t=>`<${e}${t}>`)));return j.has(e)?n:n.pipe(y.concat(X(t,i,a)),y.concat(y.make(`</${e}>`)))}if(typeof e==`function`)return Y(e(t),i,a)}return y.fail(new e({type:r.type,message:`Invalid Renderable type: expected string, FRAGMENT, or function, got ${typeof r.type}`}))}function ie(e,r,i){return y.unwrap(f.gen(function*(){let o=++r.current,s=yield*G(e.of),l=y.empty;return s.forEach((t,n)=>{let o=++r.current;l=l.pipe(y.concat(y.make(`<!--${c(o)}-->`)),y.concat(Y(e.render(t,n),r,i)),y.concat(y.make(`<!--${a(o)}-->`)))}),y.make(`<!--${n(o)}-->`).pipe(y.concat(l),y.concat(y.make(`<!--${t(o)}-->`)))}))}function X(e,t,n){let r=`children`in e?e.children:void 0;if(r==null)return y.empty;let i=Array.isArray(r)?r:[r];return y.flatMap(y.fromIterable(i),e=>Y(e,t,n))}const ae=e=>K(e,null),oe=e=>y.unwrap(f.gen(function*(){let t=yield*h.unbounded(),n=yield*g.make(0),r=K(e,{patchQueue:t,pendingCount:n,idCounter:{current:0},scope:yield*f.scope,failureCollector:null}).pipe(y.ensuring(g.get(n).pipe(f.flatMap(e=>e===0?h.offer(t,m.none()).pipe(f.asVoid):f.void))));return y.concat(r,Z(t))})),Z=e=>y.fromQueue(e).pipe(y.takeWhile(m.isSome),y.map(e=>e.value)),Q=(e,t)=>f.gen(function*(){let n=yield*h.unbounded();yield*v.addFinalizer(t,f.asVoid(h.offer(n,m.none())));let r=yield*g.make(0);return{mainStream:Y(e,{current:0},{patchQueue:n,pendingCount:r,idCounter:{current:0},scope:t,failureCollector:yield*g.make(m.none())}).pipe(y.ensuring(g.get(r).pipe(f.flatMap(e=>e===0?h.offer(n,m.none()).pipe(f.asVoid):f.void)))),patches:Z(n)}}),$=e=>y.unwrap(f.gen(function*(){let t=yield*f.scope,{mainStream:n,patches:r}=yield*Q(e,t);return y.concat(n,r)})),se=e=>ae(e).pipe(y.mkString),ce=e=>$(e).pipe(y.mkString),le=e=>f.gen(function*(){let t=yield*f.scope,n=yield*v.fork(t,`sequential`),{mainStream:r,patches:i}=yield*Q(e,n);return{shell:yield*y.mkString(r).pipe(f.onError(e=>v.close(n,p.failCause(e)))),patches:i}});export{z as SuspenseFailureHandlerTag,le as renderToHydratableShell,oe as renderToStream,$ as renderToStreamHydratable,se as renderToString,ce as renderToStringHydratable};
@@ -18,21 +18,21 @@ A component's `E` channel accumulates up the tree. A **failure boundary** is whe
18
18
  ```typescript
19
19
  import { Boundary, h } from "@weftui/core";
20
20
 
21
- Boundary.catchAll({ fallback: (e) => h.div({ class: "error" }, `Failed: ${e.message}`) }, [
21
+ Boundary.catch({ fallback: (e) => h.div({ class: "error" }, `Failed: ${e.message}`) }, [
22
22
  RiskyWidget(),
23
23
  ]);
24
24
  ```
25
25
 
26
26
  There are six failure-catch variants, mirroring Effect's own error operators so the mental model transfers directly:
27
27
 
28
- | Variant | Catches |
29
- | ------------------------ | ------------------------------------------ |
30
- | `catchAll` | every failure in `E` |
31
- | `catchAllCause` | the full `Cause` (defects included) |
32
- | `catchTag` / `catchTags` | one / several tagged errors by `_tag` |
33
- | `catchSome` / `catchIf` | a selected subset, by `Option` / predicate |
28
+ | Variant | Catches |
29
+ | ------------------------- | ------------------------------------------ |
30
+ | `catch` | every failure in `E` |
31
+ | `catchCause` | the full `Cause` (defects included) |
32
+ | `catchTag` / `catchTags` | one / several tagged errors by `_tag` |
33
+ | `catchFilter` / `catchIf` | a selected subset, by `Filter` / predicate |
34
34
 
35
- The channel algebra is the whole reason they exist: `catchTag("Foo", …)` removes `Foo` from the children's `E` and adds whatever the fallback needs — so the type of the boundary node reflects exactly which failures are still live and which were handled. An unhandled failure re-raises to the **nearest enclosing** boundary; if none catches it at **mount time**, mounting fails. Boundaries nest, so an inner `catchTag` can handle a specific case while an outer `catchAll` sweeps the rest.
35
+ The channel algebra is the whole reason they exist: `catchTag("Foo", …)` removes `Foo` from the children's `E` and adds whatever the fallback needs — so the type of the boundary node reflects exactly which failures are still live and which were handled. An unhandled failure re-raises to the **nearest enclosing** boundary; if none catches it at **mount time**, mounting fails. Boundaries nest, so an inner `catchTag` can handle a specific case while an outer `catch` sweeps the rest.
36
36
 
37
37
  ### Post-mount failures with no enclosing boundary
38
38
 
@@ -52,11 +52,11 @@ import { SubscriptionRef, Stream } from "effect";
52
52
 
53
53
  const count = yield * SubscriptionRef.make(0);
54
54
 
55
- // count.changes is a Stream<number> — each new value updates the text node
56
- h.span([count.changes]);
55
+ // SubscriptionRef.changes(count) is a Stream<number> — each new value updates the text node
56
+ h.span([SubscriptionRef.changes(count)]);
57
57
 
58
58
  // Stream as a prop — each emission sets the attribute
59
- const isDisabled = Stream.map(count.changes, (n) => n >= 10);
59
+ const isDisabled = Stream.map(SubscriptionRef.changes(count), (n) => n >= 10);
60
60
  h.button({ disabled: isDisabled }, "Submit");
61
61
  ```
62
62
 
@@ -65,22 +65,22 @@ Streams can also supply entire child arrays. Each emission replaces the previous
65
65
  ```typescript
66
66
  const todos = yield * SubscriptionRef.make<string[]>([]);
67
67
 
68
- h.ul([Stream.map(todos.changes, (list) => list.map((item) => h.li(item)))]);
68
+ h.ul([Stream.map(SubscriptionRef.changes(todos), (list) => list.map((item) => h.li(item)))]);
69
69
  ```
70
70
 
71
71
  ## Derived streams
72
72
 
73
- Because `.changes` is a plain `Stream`, the full Stream API applies:
73
+ Because `SubscriptionRef.changes(ref)` returns a plain `Stream`, the full Stream API applies:
74
74
 
75
75
  ```typescript
76
76
  const count = yield * SubscriptionRef.make(0);
77
77
 
78
- const doubled = Stream.map(count.changes, (n) => n * 2);
79
- const formatted = Stream.map(count.changes, (n) => `Count: ${n}`);
80
- const isHigh = Stream.map(count.changes, (n) => n > 10);
78
+ const doubled = Stream.map(SubscriptionRef.changes(count), (n) => n * 2);
79
+ const formatted = Stream.map(SubscriptionRef.changes(count), (n) => `Count: ${n}`);
80
+ const isHigh = Stream.map(SubscriptionRef.changes(count), (n) => n > 10);
81
81
 
82
82
  h.div([
83
- h.p([count.changes]),
83
+ h.p([SubscriptionRef.changes(count)]),
84
84
  h.p([doubled]),
85
85
  h.p([formatted]),
86
86
  h.p({ style: { color: Stream.map(isHigh, (b) => (b ? "red" : "black")) } }, "Status"),
@@ -93,8 +93,10 @@ Multiple refs can be combined with `Stream.zipLatestWith`, `Stream.merge`, or ot
93
93
  const firstName = yield * SubscriptionRef.make("");
94
94
  const lastName = yield * SubscriptionRef.make("");
95
95
 
96
- const fullName = Stream.zipLatestWith(firstName.changes, lastName.changes, (first, last) =>
97
- `${first} ${last}`.trim(),
96
+ const fullName = Stream.zipLatestWith(
97
+ SubscriptionRef.changes(firstName),
98
+ SubscriptionRef.changes(lastName),
99
+ (first, last) => `${first} ${last}`.trim(),
98
100
  );
99
101
  ```
100
102
 
@@ -20,7 +20,7 @@ type Node<E = never, R = never> = Effect.Effect<ElementDescriptor, E, R>;
20
20
  Every element in a Weft tree **is an Effect**. `h.div(...)`, a component's return value, a boundary — each is an `Effect` that, when run, produces an element descriptor. Two consequences follow immediately, and they shape everything else:
21
21
 
22
22
  1. **The error (`E`) and requirement (`R`) channels accumulate through the tree.** A child that reads a service, or a prop backed by a failible stream, contributes its `R` and `E` to its parent, which contributes to _its_ parent, up to the mount boundary. The type of your app node is the exact union of everything it needs and everything it can fail with — visible to the type checker, satisfiable exactly once, at `mount`/`hydrate`. See [The Combinator API](https://weftui.dev/docs/explanation/combinator-api) for how the accumulation works mechanically.
23
- 2. **Every Effect combinator applies to a node directly.** `Effect.provide`, `Effect.flatMap`, `Effect.gen`, `Effect.catchAll` — none of them are special-cased for UI. A node is an ordinary Effect, so the entire Effect ecosystem composes with your view for free.
23
+ 2. **Every Effect combinator applies to a node directly.** `Effect.provide`, `Effect.flatMap`, `Effect.gen`, `Effect.catch` — none of them are special-cased for UI. A node is an ordinary Effect, so the entire Effect ecosystem composes with your view for free.
24
24
 
25
25
  JSX collapses every component to an opaque `JSX.Element`, erasing both channels. Weft keeps them, and that is the point of the whole design. (There is [no JSX](https://weftui.dev/docs/explanation/combinator-api) here — components are plain functions you _call_.)
26
26
 
@@ -39,7 +39,7 @@ The `ThemeServiceLive` example above works because `mount`'s effect and the serv
39
39
  Effect.runPromise(mount(App(), root).pipe(Effect.provide(SomeScopedLayer)));
40
40
  ```
41
41
 
42
- This is exactly what happened with effect-atom's `Registry.layer` in the [`effect-atom` example](https://github.com/stefvw93/weft/tree/main/examples/effect-atom) (issue #122): every atom-driven region rendered empty, with no error, because the registry the streams read from had already been disposed.
42
+ This is exactly what happened with the atom registry layer (`AtomRegistry.layer`, from `effect/unstable/reactivity`) in the [`effect-atom` example](https://github.com/stefvw93/weft/tree/main/examples/effect-atom) (issue #122): every atom-driven region rendered empty, with no error, because the registry the streams read from had already been disposed.
43
43
 
44
44
  The fix is to give the scoped layer a lifetime that matches the app, not the initial render: provide it **outside** a scoped region that stays open for as long as the app should run, and mount inside that region with `mountScoped` (which ties `unmount` to the region's scope instead of to the resolution of the mount effect). An `Effect.never` (or `Deferred.await` on a shutdown signal) keeps the region — and therefore the layer — alive until something explicitly closes it. See [Provide Services](https://weftui.dev/docs/how-to/provide-services) for the recipe, including the `ManagedRuntime` alternative when a scoped region isn't a good fit.
45
45
 
@@ -50,7 +50,7 @@ A plain `mount`/`hydrate` discharges `R` at the call site. But under `@weftui/ro
50
50
  So the router exposes an explicit **`context` seam** — a `Layer` threaded to the document shell and every route, layout, and leaf:
51
51
 
52
52
  ```typescript
53
- class Greeting extends Context.Tag("Greeting")<Greeting, { text: string }>() {}
53
+ class Greeting extends Context.Service<Greeting, { text: string }>()("Greeting") {}
54
54
 
55
55
  // server entry
56
56
  RouterServer.render(App, { document, url, context: Layer.succeed(Greeting, { text: "hi" }) });
@@ -63,7 +63,7 @@ The seam is **symmetric** (same shape on both sides) and **type-tracked**: the d
63
63
 
64
64
  ## Server-only services: `ServerTag`
65
65
 
66
- Some services must _never_ run in the browser — a database handle, a private credential, an rpc handler's backing store. Declare those with [`ServerTag`](https://weftui.dev/docs/reference/core#servertag) instead of `Context.Tag`. It behaves exactly like `Context.Tag`, but its identifier carries a **server-only brand**.
66
+ Some services must _never_ run in the browser — a database handle, a private credential, an rpc handler's backing store. Declare those with [`ServerTag`](https://weftui.dev/docs/reference/core#servertag) instead of `Context.Service`. It behaves exactly like `Context.Service`, but its identifier carries a **server-only brand**.
67
67
 
68
68
  The brand's job is to turn a leak into a **compile error at the `hydrate` call site**. A `Boundary.rpc` handler legitimately reads server-only services on the server, but they must not survive into client code: since `render` only ever touches the _decoded result_ (never the service), a correctly-written boundary keeps its output `R` free of the brand. If a branded tag ever leaks into `render` and reaches the client requirement channel, `hydrate`'s `AssertNoServerOnly` resolves `R` to a compile-error sentinel — you learn at build time, not from a runtime defect.
69
69
 
@@ -165,7 +165,7 @@ Router.route("users/:id", {
165
165
  path: idParam,
166
166
  component: Component.gen(function* () {
167
167
  const { id } = yield* Router.params(idParam);
168
- if (id < 0) return yield* notFound();
168
+ if (!Number.isFinite(id) || id < 0) return yield* notFound();
169
169
  return yield* h.div(`User ${id}`);
170
170
  }),
171
171
  });
@@ -173,6 +173,8 @@ Router.route("users/:id", {
173
173
 
174
174
  `RouterNotFound` is exported, so a `Boundary.catchTag("RouterNotFound", …)` placed inside a subtree overrides the app-level fallback for that subtree (the router's internal boundary is outermost, so a nearer user boundary wins).
175
175
 
176
+ > **`Schema.NumberFromString` gotcha.** Decoding no longer fails on a non-numeric segment — `/users/abc` decodes `id` to `NaN` instead of missing the route. A leaf that guards a numeric param must check `Number.isFinite(id)` itself (as above); relying on the schema alone to 404 non-numeric input no longer works.
177
+
176
178
  ## Client setup
177
179
 
178
180
  On the client, provide the `Router` via `RouterLive(def)` and render `RouterApp(def)`. `RouterLive` is a **scoped layer** — it owns the `popstate` listener and the same-origin link-click interceptor — so it must outlive the mount. Provide it through a long-lived `ManagedRuntime` rather than `Effect.provide` at the node level:
@@ -276,9 +278,9 @@ export const handler = RouterServer.toWebHandler(App, { document: documentShell
276
278
 
277
279
  `render` provides both `Router.Outlet` (the app, per request) and `Router` (so the shell may read params), and renders through `renderToStringHydratable` so the client can `hydrate` in place.
278
280
 
279
- ### `@effect/platform` is the spine
281
+ ### `effect/unstable/httpapi` is the spine
280
282
 
281
- The tree is the authoring surface, but `@effect/platform`'s `HttpApi` is the **single source of truth** for paths and schemas. Sealing the tree with `Router.router(...)` builds it once (`buildHttpApi`) and stamps it onto `def.httpApi`: a single `"pages"` group with one GET endpoint per leaf at its full path pattern, carrying `setPath(pathSchema)`, `setUrlParams(querySchema)`, and a `RouterNotFound → 404` error. Both sides read that one definition, so they always agree:
283
+ The tree is the authoring surface, but `effect/unstable/httpapi`'s `HttpApi` is the **single source of truth** for paths and schemas. Sealing the tree with `Router.router(...)` builds it once (`buildHttpApi`) and stamps it onto `def.httpApi`: a single `"pages"` group with one GET endpoint per leaf at its full path pattern, carrying `setPath(pathSchema)`, `setUrlParams(querySchema)`, and a `RouterNotFound → 404` error. Both sides read that one definition, so they always agree:
282
284
 
283
285
  - **Server** — `RouterServer` dispatches through `HttpApiBuilder` (platform owns request→leaf matching, path/query decode, and the 404 status).
284
286
  - **Client** — `RouterLive` derives a real `HttpApiClient` from the same `def.httpApi` (exposed as `Router.httpApiClient`) for network work. SPA URL→leaf resolution stays **local** (there is no public client-side "match this URL against my `HttpApi`" utility in platform), fed from the same endpoint definitions so it never drifts from the server.
@@ -290,7 +292,7 @@ The tree is the authoring surface, but `@effect/platform`'s `HttpApi` is the **s
290
292
  | `RouterNotFound` | `notFound()`, or no route matched | `Boundary.catchTag("RouterNotFound", …)` (or the app-level `notFound` page) |
291
293
  | `RouterParamsError` | `Router.params` / `Router.query` on a missing/invalid key or no match | `Boundary.catchTag("RouterParamsError", …)` |
292
294
 
293
- Both are modeled as `Schema.TaggedError`, so they encode/decode across the wire the same way `Boundary.rpc` replays typed failures.
295
+ Both are modeled as `Schema.TaggedErrorClass`, so they encode/decode across the wire the same way `Boundary.rpc` replays typed failures.
294
296
 
295
297
  ## `Boundary.rpc` interplay
296
298
 
@@ -299,7 +301,7 @@ Initial SSR navigation works end to end: the server resolves the rpc and inlines
299
301
  ## See also
300
302
 
301
303
  - [`@weftui/router` API reference](https://weftui.dev/docs/reference/router)
302
- - [examples/router-ssr](https://github.com/stefvw93/weft/tree/main/examples/router-ssr) — a runnable SSR + hydration app with nested layouts, persistent layout state, type-safe `href`s, handler-arg props, and programmatic navigation over the `@effect/platform` spine
304
+ - [examples/router-ssr](https://github.com/stefvw93/weft/tree/main/examples/router-ssr) — a runnable SSR + hydration app with nested layouts, persistent layout state, type-safe `href`s, handler-arg props, and programmatic navigation over the `effect/unstable/httpapi` spine
303
305
  - [Component Authoring](https://weftui.dev/docs/how-to/author-components) — `Component.make` / `Component.gen`, the idiomatic way to write route components
304
306
  - [Server-Side Rendering](https://weftui.dev/docs/how-to/render-on-the-server) — `renderToStringHydratable`, `hydrate`, and `Boundary.rpc`
305
307
  - [RPC Data Boundaries](https://weftui.dev/docs/how-to/load-data-with-rpc) — `Boundary.rpc`, the `Resource` handle, and the four lifecycles
@@ -43,7 +43,7 @@ const Counter = () =>
43
43
  const count = yield* SubscriptionRef.make(0);
44
44
 
45
45
  return yield* h.div([
46
- h.span([count.changes]),
46
+ h.span([SubscriptionRef.changes(count)]),
47
47
  h.button({ onclick: () => SubscriptionRef.update(count, (n) => n + 1) }, "+"),
48
48
  ]);
49
49
  });
@@ -63,10 +63,10 @@ so it is already in context when you need it.
63
63
  This matters the moment a component starts **background work** — a subscription, an
64
64
  observer of a `ref`, a polling timer, anything you `fork`. The rule:
65
65
 
66
- > Fork background work with **`Effect.forkScoped`**, never a bare `Effect.fork`.
66
+ > Fork background work with **`Effect.forkScoped`**, never a bare `Effect.forkChild`.
67
67
 
68
68
  `Effect.forkScoped` attaches the fiber to the instance scope, so it keeps running for
69
- the component's lifetime and is interrupted on unmount. A bare `Effect.fork` instead
69
+ the component's lifetime and is interrupted on unmount. A bare `Effect.forkChild` instead
70
70
  attaches the fiber to the component-body fiber — the one that runs your `Effect.gen` to
71
71
  produce the tree. That fiber completes the instant the gen returns its node, so the
72
72
  forked work is cancelled almost immediately.
@@ -82,12 +82,12 @@ const AutoFocusInput = () =>
82
82
  const inputRef = yield* SubscriptionRef.make<Option.Option<HTMLInputElement>>(Option.none());
83
83
 
84
84
  yield* pipe(
85
- inputRef.changes,
85
+ SubscriptionRef.changes(inputRef),
86
86
  Stream.filter(Option.isSome),
87
87
  Stream.take(1),
88
88
  Stream.runForEach((el) => Effect.sync(() => el.value.focus())),
89
89
  Effect.forkScoped, // ✅ tied to the instance scope — survives until unmount
90
- // Effect.fork, // ❌ tied to the body fiber — interrupted when the gen returns
90
+ // Effect.forkChild, // ❌ tied to the body fiber — interrupted when the gen returns
91
91
  );
92
92
 
93
93
  return yield* h.input({ ref: inputRef, type: "text" });
@@ -9,15 +9,15 @@ description: Build a controlled form with SubscriptionRef field state, reactive
9
9
 
10
10
  **Goal:** a controlled form whose inputs drive `SubscriptionRef` state, whose errors update reactively as the user types, and whose submit runs an Effect.
11
11
 
12
- Each field is a `SubscriptionRef`. Bind it with `oninput`, derive validation from its `.changes` stream, and return an `Effect` from `onsubmit` (after `preventDefault`).
12
+ Each field is a `SubscriptionRef`. Bind it with `oninput`, derive validation from its `SubscriptionRef.changes(ref)` stream, and return an `Effect` from `onsubmit` (after `preventDefault`).
13
13
 
14
14
  ```typescript
15
15
  import { h } from "@weftui/core";
16
- import { Effect, Either, Schema, Stream, SubscriptionRef } from "effect";
16
+ import { Effect, Result, Schema, Stream, SubscriptionRef } from "effect";
17
17
 
18
18
  const Email = Schema.String.pipe(
19
- Schema.filter((s) => s.includes("@"), { message: () => "Must contain @" }),
20
- Schema.filter((s) => s.includes("."), { message: () => "Must contain a domain" }),
19
+ Schema.check(Schema.makeFilter((s) => (s.includes("@") ? undefined : "Must contain @"))),
20
+ Schema.check(Schema.makeFilter((s) => (s.includes(".") ? undefined : "Must contain a domain"))),
21
21
  );
22
22
 
23
23
  const LoginForm = () =>
@@ -26,11 +26,11 @@ const LoginForm = () =>
26
26
  const status = yield* SubscriptionRef.make<string | null>(null);
27
27
 
28
28
  // Validation is a stream derived from the field — it re-runs as the user types.
29
- const error = Stream.map(email.changes, (value) => {
29
+ const error = Stream.map(SubscriptionRef.changes(email), (value) => {
30
30
  if (value.length === 0) return null; // don't nag an empty field
31
- return Either.match(Schema.decodeUnknownEither(Email)(value), {
32
- onLeft: (e) => e.message.split(":").pop()?.trim() ?? "Invalid",
33
- onRight: () => null,
31
+ return Result.match(Schema.decodeUnknownResult(Email)(value), {
32
+ onFailure: (e) => e.message.split(":").pop()?.trim() ?? "Invalid",
33
+ onSuccess: () => null,
34
34
  });
35
35
  });
36
36
 
@@ -52,7 +52,7 @@ const LoginForm = () =>
52
52
  }),
53
53
  Stream.map(error, (err) => (err ? h.span({ class: "error-text" }, err) : null)),
54
54
  h.button({ type: "submit" }, "Login"),
55
- h.div([Stream.map(status.changes, (s) => (s ? h.span(s) : null))]),
55
+ h.div([Stream.map(SubscriptionRef.changes(status), (s) => (s ? h.span(s) : null))]),
56
56
  ],
57
57
  );
58
58
  });
@@ -61,7 +61,7 @@ const LoginForm = () =>
61
61
  ## How it works
62
62
 
63
63
  - **Field state** is a `SubscriptionRef.make("")`; `oninput` writes the current value with `SubscriptionRef.set`. Because the input is driven by the ref, it is a controlled input.
64
- - **Validation is reactive**, not on-blur or on-submit only: `Stream.map(email.changes, …)` produces an error string (or `null`) on every keystroke. Use [`Schema`](https://effect.website/docs/schema/introduction) to decode — `Schema.decodeUnknownEither(schema)(value)` returns an `Either`, and `Either.match` turns it into UI. A node or `null` in a child slot renders the error or nothing.
64
+ - **Validation is reactive**, not on-blur or on-submit only: `Stream.map(SubscriptionRef.changes(email), …)` produces an error string (or `null`) on every keystroke. Use [`Schema`](https://effect.website/docs/schema/introduction) to decode — `Schema.decodeUnknownResult(schema)(value)` returns a `Result`, and `Result.match` turns it into UI. A node or `null` in a child slot renders the error or nothing.
65
65
  - **Submit returns an Effect.** `onsubmit` calls `e.preventDefault()` and then **returns** an `Effect` (it is not `yield*`-ed inline) — the renderer runs it in a detached fiber, so it can `SubscriptionRef.set`, `Effect.sleep`, read fields with `SubscriptionRef.get`, or call a service.
66
66
 
67
67
  ## Variations
@@ -2,14 +2,14 @@
2
2
  title: Load Async Data
3
3
  order: 9
4
4
  section: how-to
5
- description: Show a loading state then resolved content with Stream.concat, and turn a failed fetch into a fallback node with Effect.catchAll — all client-side.
5
+ description: Show a loading state then resolved content with Stream.concat, and turn a failed fetch into a fallback node with Effect.catch — all client-side.
6
6
  ---
7
7
 
8
8
  # Load Async Data
9
9
 
10
10
  **Goal:** render a loading placeholder, then the fetched content, and a fallback if the fetch fails — for data that loads **on the client**.
11
11
 
12
- Return a `Stream<Node>` that emits the loading node first and the resolved node second, sequenced with `Stream.concat`. Handle failure inside the effect with `Effect.catchAll`, which maps the error to a fallback node.
12
+ Return a `Stream<Node>` that emits the loading node first and the resolved node second, sequenced with `Stream.concat`. Handle failure inside the effect with `Effect.catch`, which maps the error to a fallback node.
13
13
 
14
14
  ```typescript
15
15
  import { h } from "@weftui/core";
@@ -34,7 +34,7 @@ const UserCard = ({ id }: { id: number }) =>
34
34
  Stream.fromEffect(
35
35
  fetchUser(id).pipe(
36
36
  Effect.flatMap((user) => h.div({ class: "user-card" }, [h.h3(user.name), h.p(user.email)])),
37
- Effect.catchAll((error) => h.div({ class: "error" }, `Error: ${error.message}`)),
37
+ Effect.catch((error) => h.div({ class: "error" }, `Error: ${error.message}`)),
38
38
  ),
39
39
  ),
40
40
  );
@@ -44,7 +44,7 @@ const UserCard = ({ id }: { id: number }) =>
44
44
 
45
45
  - **`Stream.concat`** sequences two streams: `Stream.make(loadingNode)` emits once immediately, then `Stream.fromEffect(effect)` emits the resolved node when the effect completes. The renderer swaps the DOM in place on the second emission.
46
46
  - **`Effect.flatMap((data) => h.div(...))`** builds the content node from the data — `h.*` returns a `Node`, which is an `Effect`, so it composes directly in the pipeline.
47
- - **`Effect.catchAll((error) => node)`** converts the error channel into a fallback node, so the stream always yields something renderable. The failure never escapes to the mount.
47
+ - **`Effect.catch((error) => node)`** converts the error channel into a fallback node, so the stream always yields something renderable. The failure never escapes to the mount.
48
48
  - **Parallel loading is automatic:** place several async components as siblings and their fetches run concurrently — no orchestration needed.
49
49
 
50
50
  ## When to reach for a boundary instead
@@ -39,7 +39,7 @@ The rpc **contract** (pure Schema) is shared with the client. The rpc **handler*
39
39
 
40
40
  ```typescript
41
41
  // data/inventory.ts
42
- import { Rpc, RpcGroup } from "@effect/rpc";
42
+ import { Rpc, RpcGroup } from "effect/unstable/rpc";
43
43
  import { Context, Effect, Layer, Schema } from "effect";
44
44
 
45
45
  // --- Contract (shareable with the client) ---
@@ -53,10 +53,10 @@ export const GetStock = Rpc.make("GetStock", { payload: StockKey, success: Stock
53
53
  export const StockRpcs = RpcGroup.make(GetStock);
54
54
 
55
55
  // --- Handler (server-only; the client never imports this) ---
56
- class Inventory extends Context.Tag("Inventory")<
56
+ class Inventory extends Context.Service<
57
57
  Inventory,
58
58
  { readonly stockFor: (id: number) => Effect.Effect<typeof Stock.Type> }
59
- >() {}
59
+ >()("Inventory") {}
60
60
 
61
61
  const InventoryLive = Layer.succeed(Inventory, {
62
62
  stockFor: (id) => Effect.succeed({ units: 7 + (id % 5) }),
@@ -68,7 +68,7 @@ export const StockLive = StockRpcs.toLayer({
68
68
  }).pipe(Layer.provide(InventoryLive));
69
69
  ```
70
70
 
71
- Declare server-only services with [`ServerTag`](https://weftui.dev/docs/reference/core#servertag) (not `Context.Tag`) when they might be referenced from universal code: the brand makes a leak into `render` a compile error at the `hydrate` call site rather than a runtime surprise.
71
+ Declare server-only services with [`ServerTag`](https://weftui.dev/docs/reference/core#servertag) (not `Context.Service`) when they might be referenced from universal code: the brand makes a leak into `render` a compile error at the `hydrate` call site rather than a runtime surprise.
72
72
 
73
73
  ## Wiring the router
74
74
 
@@ -157,7 +157,7 @@ Boundary.catchTag({ tag: "OutOfStock", fallback: (e) => h.p({ class: "error" },
157
157
  ]);
158
158
  ```
159
159
 
160
- A transport **defect** (no `Cause.failureOption`), or an rpc with no `error` schema, is **not** replayed; it propagates — a server-side fallback and a client mismatch.
160
+ A transport **defect** (no `Cause.findErrorOption`), or an rpc with no `error` schema, is **not** replayed; it propagates — a server-side fallback and a client mismatch.
161
161
 
162
162
  ## When to use
163
163
 
@@ -121,4 +121,4 @@ In both cases the tell is the same: nothing in the composition keeps a scope ope
121
121
  - [Layer lifetime at the mount](https://weftui.dev/docs/explanation/services-and-context#layer-lifetime-at-the-mount) — why the mount effect resolving early matters for scoped layers
122
122
  - [Services and Context](https://weftui.dev/docs/explanation/services-and-context) — how `R` accumulates and discharges at the mount
123
123
  - [`mountScoped` / `hydrateScoped` reference](https://weftui.dev/docs/reference/dom#mountscoped) — signatures and error unions
124
- - [examples/effect-atom](https://github.com/stefvw93/weft/tree/main/examples/effect-atom) — a real scoped layer (`Registry.layer`) mounted with this composition
124
+ - [examples/effect-atom](https://github.com/stefvw93/weft/tree/main/examples/effect-atom) — a real scoped layer (`AtomRegistry.layer` from `effect/unstable/reactivity`) mounted with this composition
@@ -9,7 +9,7 @@ description: Capture a DOM element with the ref prop into a SubscriptionRef<Opti
9
9
 
10
10
  **Goal:** get a handle to a real DOM element — to focus it, measure it, or call an imperative browser API on it.
11
11
 
12
- Declare a `SubscriptionRef<Option<HTMLElement>>`, attach it with the `ref` prop, and either **react** to the element appearing (a scoped observer on `.changes`) or **read** it later inside a handler.
12
+ Declare a `SubscriptionRef<Option<HTMLElement>>`, attach it with the `ref` prop, and either **react** to the element appearing (a scoped observer on `SubscriptionRef.changes(ref)`) or **read** it later inside a handler.
13
13
 
14
14
  ```typescript
15
15
  import { h } from "@weftui/core";
@@ -21,7 +21,7 @@ const AutoFocusInput = () =>
21
21
 
22
22
  // Observe the element becoming available, once, and focus it.
23
23
  yield* pipe(
24
- inputRef.changes,
24
+ SubscriptionRef.changes(inputRef),
25
25
  Stream.filter(Option.isSome),
26
26
  Stream.take(1),
27
27
  Stream.runForEach((el) => Effect.sync(() => el.value.focus())),
@@ -35,8 +35,8 @@ const AutoFocusInput = () =>
35
35
  ## How it works
36
36
 
37
37
  - **The `ref` prop** takes a `SubscriptionRef<Option<T>>`. The renderer sets it to `Option.some(element)` **once**, when the element is created — so the ref is an `Option`: `None` until mount, `Some(el)` after.
38
- - **React to mount** by observing `ref.changes`: `Stream.filter(Option.isSome)` waits for the element, `Stream.take(1)` takes just the first appearance, and `Stream.runForEach` does the imperative work. This is the equivalent of a mount effect.
39
- - **Use `Effect.forkScoped`, not `Effect.fork`.** `forkScoped` ties the observer fiber to the component's **instance scope** (the ambient `Scope` the renderer provides), so it lives as long as the component is mounted. A bare `Effect.fork` binds to the transient component-body fiber and is interrupted the instant the generator returns — the observer would never fire.
38
+ - **React to mount** by observing `SubscriptionRef.changes(ref)`: `Stream.filter(Option.isSome)` waits for the element, `Stream.take(1)` takes just the first appearance, and `Stream.runForEach` does the imperative work. This is the equivalent of a mount effect.
39
+ - **Use `Effect.forkScoped`, not `Effect.forkChild`.** `forkScoped` ties the observer fiber to the component's **instance scope** (the ambient `Scope` the renderer provides), so it lives as long as the component is mounted. A bare `Effect.forkChild` binds to the transient component-body fiber and is interrupted the instant the generator returns — the observer would never fire.
40
40
 
41
41
  ## Read a ref imperatively
42
42
 
@@ -58,6 +58,6 @@ const scroll = () =>
58
58
 
59
59
  ## See also
60
60
 
61
- - [Reactive Primitives](https://weftui.dev/docs/explanation/reactive-primitives) — `SubscriptionRef` and `.changes`
61
+ - [Reactive Primitives](https://weftui.dev/docs/explanation/reactive-primitives) — `SubscriptionRef` and `SubscriptionRef.changes`
62
62
  - [Author Components](https://weftui.dev/docs/how-to/author-components) — instance scope and `Effect.forkScoped`
63
63
  - [examples/element-ref](https://github.com/stefvw93/weft/tree/main/examples/element-ref) — auto-focus, element measurement, and imperative scroll via refs
@@ -144,7 +144,7 @@ Boundary.suspend(
144
144
 
145
145
  #### `Boundary.rpc`
146
146
 
147
- A universal server/client render boundary backed by one `Rpc` from the app's merged `RpcGroup` ([`@effect/rpc`](https://github.com/Effect-TS/effect/tree/main/packages/rpc)). The rpc **`_tag`** is the boundary's stable identity and its **payload schema** the typed input; the handler lives in the server-only rpc Layer (`group.toLayer(...)`), which the client never imports — tree-shaking does the client/server split structurally. Unlike the catch variants it takes a `render` function — not a children array — and that `render` receives a reactive [`Resource`](#resourcea), not a bare value.
147
+ A universal server/client render boundary backed by one `Rpc` from the app's merged `RpcGroup` ([`effect/unstable/rpc`](https://github.com/Effect-TS/effect)). The rpc **`_tag`** is the boundary's stable identity and its **payload schema** the typed input; the handler lives in the server-only rpc Layer (`group.toLayer(...)`), which the client never imports — tree-shaking does the client/server split structurally. Unlike the catch variants it takes a `render` function — not a children array — and that `render` receives a reactive [`Resource`](#resourcea), not a bare value.
148
148
 
149
149
  ```typescript
150
150
  Boundary.rpc<R extends Rpc.Any, C extends Node<any, any>>(
@@ -201,22 +201,21 @@ The descriptor `type` every `Boundary.rpc` carries (`{ type: SERVER_BOUNDARY, pr
201
201
  interface AppRpcClient {
202
202
  readonly call: (tag: string, payload: unknown) => Effect.Effect<unknown, unknown>;
203
203
  }
204
- class AppRpcClientTag extends Context.Tag("@weftui/core/AppRpcClient")<
205
- AppRpcClientTag,
206
- AppRpcClient
207
- >() {}
204
+ class AppRpcClientTag extends Context.Service<AppRpcClientTag, AppRpcClient>()(
205
+ "@weftui/core/AppRpcClient",
206
+ ) {}
208
207
  ```
209
208
 
210
- The ambient, package-neutral seam the renderer resolves a `Boundary.rpc` through — a **flat, untyped** caller `(tag, payload) => Effect<success>`. It lets `@weftui/dom` resolve a boundary without importing `@effect/rpc` or `@weftui/router`. `@weftui/router` provides it: a **network** `RpcClient` (POST `/_eui/rpc`) in the browser, an **in-process** client over the handler Layer on the server. `call` returns the already-decoded success; the renderer owns `successSchema`/`errorSchema` decoding of the inline SSR payload only. Both `AppRpcClientTag` and the `AppRpcClient` type are re-exported from `@weftui/core`. Absent in a router-less mount, where a `Boundary.rpc` resolves to a descriptive "needs router/rpc" error (not a defect).
209
+ The ambient, package-neutral seam the renderer resolves a `Boundary.rpc` through — a **flat, untyped** caller `(tag, payload) => Effect<success>`. It lets `@weftui/dom` resolve a boundary without importing `effect/unstable/rpc` or `@weftui/router`. `@weftui/router` provides it: a **network** `RpcClient` (POST `/_eui/rpc`) in the browser, an **in-process** client over the handler Layer on the server. `call` returns the already-decoded success; the renderer owns `successSchema`/`errorSchema` decoding of the inline SSR payload only. Both `AppRpcClientTag` and the `AppRpcClient` type are re-exported from `@weftui/core`. Absent in a router-less mount, where a `Boundary.rpc` resolves to a descriptive "needs router/rpc" error (not a defect).
211
210
 
212
211
  See the [rpc data boundaries guide](https://weftui.dev/docs/how-to/load-data-with-rpc) and [examples/router-ssr](https://github.com/stefvw93/weft/tree/main/examples/router-ssr).
213
212
 
214
- #### `Boundary.catchAll`
213
+ #### `Boundary.catch`
215
214
 
216
- Catches all typed failures (`Cause.fail`). Defects (`Cause.die`) are not caught and re-raise.
215
+ Catches all typed failures (`Cause.fail`). Defects (`Cause.die`) are not caught and re-raise. Mirrors Effect 4's `Effect.catch` (renamed from `catchAll` in v3).
217
216
 
218
217
  ```typescript
219
- Boundary.catchAll<C, FE, FR>(
218
+ Boundary.catch<C, FE, FR>(
220
219
  props: { fallback: (e: ChildrenE<C>) => Node<FE, FR> },
221
220
  children: C,
222
221
  ): Node<FE, ChildrenR<C> | FR>
@@ -224,12 +223,12 @@ Boundary.catchAll<C, FE, FR>(
224
223
 
225
224
  The children's `E` is fully consumed. The output `E` is only the fallback's own error channel.
226
225
 
227
- #### `Boundary.catchAllCause`
226
+ #### `Boundary.catchCause`
228
227
 
229
- Catches every `Cause` including defects and interruptions.
228
+ Catches every `Cause` including defects and interruptions. Mirrors Effect 4's `Effect.catchCause` (renamed from `catchAllCause` in v3).
230
229
 
231
230
  ```typescript
232
- Boundary.catchAllCause<C, FE, FR>(
231
+ Boundary.catchCause<C, FE, FR>(
233
232
  props: { fallback: (cause: Cause.Cause<ChildrenE<C>>) => Node<FE, FR> },
234
233
  children: C,
235
234
  ): Node<FE, ChildrenR<C> | FR>
@@ -266,18 +265,30 @@ Boundary.catchTags<C, Handlers>(
266
265
  ): Node<UnhandledE | HandlersE, ChildrenR<C> | HandlersR>
267
266
  ```
268
267
 
269
- #### `Boundary.catchSome`
268
+ #### `Boundary.catchFilter`
270
269
 
271
- The fallback returns `Option<Node>`. `Option.none()` re-raises the error; `Option.some(node)` catches it.
270
+ Conditionally catches using a `Filter`, run on each typed failure: a `Result.succeed` (pass) recovers via `fallback`, receiving the possibly-narrowed pass value; a `Result.fail` re-raises the error (its `Fail` channel `X` is preserved in the output `E`, since the boundary may not handle any given error). Takes the `Filter` and `fallback` as **positional** arguments — no wrapping props object. Mirrors Effect 4's `Effect.catchFilter` (renamed from `catchSome`, which took an `Option`-returning function in v3).
272
271
 
273
272
  ```typescript
274
- Boundary.catchSome<C, FE, FR>(
275
- props: { fallback: (e: ChildrenE<C>) => Option.Option<Node<FE, FR>> },
273
+ Boundary.catchFilter<C, EB, X, FE, FR>(
274
+ filter: Filter.Filter<ChildrenE<C>, EB, X>,
275
+ fallback: (matched: EB) => Node<FE, FR>,
276
276
  children: C,
277
- ): Node<ChildrenE<C> | FE, ChildrenR<C> | FR>
277
+ ): Node<X | FE, ChildrenR<C> | FR>
278
+ ```
279
+
280
+ ```typescript
281
+ import { Boundary } from "@weftui/core";
282
+ import { Filter, Result } from "effect";
283
+
284
+ Boundary.catchFilter(
285
+ Filter.make((e: AppError) => (e._tag === "Net" ? Result.succeed(e) : Result.fail(e))),
286
+ (matched) => h.div({}, matched.message),
287
+ [Widget()],
288
+ );
278
289
  ```
279
290
 
280
- The children's `E` is preserved in the output because the boundary may or may not handle any given error.
291
+ The children's `E` is narrowed to the filter's `Fail` channel `X` in the output, because the boundary may or may not handle any given error.
281
292
 
282
293
  #### `Boundary.catchIf`
283
294
 
@@ -301,7 +312,7 @@ Inner boundaries shadow outer ones for their subtree — the innermost boundary
301
312
 
302
313
  ```typescript
303
314
  // Inner catches FooError; BarError propagates to outer
304
- Boundary.catchAll({ fallback: (e) => h.div(`Outer: ${e.message}`) }, [
315
+ Boundary.catch({ fallback: (e) => h.div(`Outer: ${e.message}`) }, [
305
316
  Boundary.catchTag({ tag: "Foo", fallback: (e) => h.span(`Foo: ${e.msg}`) }, [
306
317
  ChildWithFooOrBarError(),
307
318
  ]),
@@ -312,7 +323,7 @@ Boundary.catchAll({ fallback: (e) => h.div(`Outer: ${e.message}`) }, [
312
323
 
313
324
  ## ServerTag
314
325
 
315
- A `Context.Tag` whose identifier is branded server-only. Use it exactly like `Context.Tag` for services that must only ever be provided on the server — e.g. a database handle read inside an rpc handler Layer. The brand also guards [`Boundary.rpc`](#boundaryrpc): a server-only tag accidentally referenced in `render` stays in the requirement channel, where `hydrate`'s `AssertNoServerOnly` rejects it at compile time.
326
+ A `Context.Service` key whose identifier is branded server-only. Use it exactly like `Context.Service` for services that must only ever be provided on the server — e.g. a database handle read inside an rpc handler Layer. The brand also guards [`Boundary.rpc`](#boundaryrpc): a server-only tag accidentally referenced in `render` stays in the requirement channel, where `hydrate`'s `AssertNoServerOnly` rejects it at compile time.
316
327
 
317
328
  ```typescript
318
329
  import { ServerTag } from "@weftui/core";
@@ -19,7 +19,7 @@ Three entry points mirror `@weftui/dom`:
19
19
 
20
20
  ## `Router`
21
21
 
22
- `Router` is both an Effect `Context.Tag` and the authoring namespace; the two roles merge by declaration. `yield* Router` reads the per-render service; `Router.route(…)` authors a tree.
22
+ `Router` is both an Effect `Context.Service` key and the authoring namespace; the two roles merge by declaration. `yield* Router` reads the per-render service; `Router.route(…)` authors a tree.
23
23
 
24
24
  The service value carries:
25
25
 
@@ -96,7 +96,7 @@ See the [Split Routes Lazily](https://weftui.dev/docs/how-to/split-routes-lazily
96
96
 
97
97
  ### `Router.Outlet`
98
98
 
99
- A `Context.Tag` whose value is the node to splice for the next level down. A layout (or the server document shell) reads it with `const outlet = yield* Router.Outlet`. Typed **opaque** as `Node<never, never>`, and discharged by the router at render time, so it never appears in a reader's aggregate requirement channel.
99
+ A `Context.Service` key whose value is the node to splice for the next level down. A layout (or the server document shell) reads it with `const outlet = yield* Router.Outlet`. Typed **opaque** as `Node<never, never>`, and discharged by the router at render time, so it never appears in a reader's aggregate requirement channel.
100
100
 
101
101
  ### `Router.params` / `Router.query`
102
102
 
@@ -224,7 +224,7 @@ RouterLive(
224
224
  ): Layer.Layer<Router | AppRpcClientTag>;
225
225
  ```
226
226
 
227
- The client `Router` layer, backed by the History API. Seeds a `SubscriptionRef` from `window.location`, listens for `popstate`, installs the same-origin link-click interceptor, and derives the `HttpApiClient` exposed as `Router.httpApiClient` (over `FetchHttpClient`; `baseUrl` defaults to same-origin). Alongside `Router` it also provides the core [`AppRpcClientTag`](https://weftui.dev/docs/reference/core#apprpcclienttag) seam — a **network** flat rpc client over the app's merged `RpcGroup` (`RpcClient.make` → `POST /_eui/rpc`) — so `@weftui/dom` can resolve a [`Boundary.rpc`](https://weftui.dev/docs/reference/core#boundaryrpc) (hydrated refetch and client-first SPA mount) without depending on this package or `@effect/rpc`. Pass the same merged `group` the server wires into [`RouterServer`](#routerserver). **Scoped** — it must outlive the mount, so provide it through a `ManagedRuntime`:
227
+ The client `Router` layer, backed by the History API. Seeds a `SubscriptionRef` from `window.location`, listens for `popstate`, installs the same-origin link-click interceptor, and derives the `HttpApiClient` exposed as `Router.httpApiClient` (over `FetchHttpClient`; `baseUrl` defaults to same-origin). Alongside `Router` it also provides the core [`AppRpcClientTag`](https://weftui.dev/docs/reference/core#apprpcclienttag) seam — a **network** flat rpc client over the app's merged `RpcGroup` (`RpcClient.make` → `POST /_eui/rpc`) — so `@weftui/dom` can resolve a [`Boundary.rpc`](https://weftui.dev/docs/reference/core#boundaryrpc) (hydrated refetch and client-first SPA mount) without depending on this package or `effect/unstable/rpc`. Pass the same merged `group` the server wires into [`RouterServer`](#routerserver). **Scoped** — it must outlive the mount, so provide it through a `ManagedRuntime`:
228
228
 
229
229
  ```typescript
230
230
  const runtime = ManagedRuntime.make(RouterLive(App, { rpc: { group: StockRpcs } }));
@@ -294,11 +294,11 @@ Dispatch runs through the `def.httpApi` spine via `HttpApiBuilder`: platform own
294
294
 
295
295
  ### `RouterNotFound`
296
296
 
297
- `Schema.TaggedError` with an optional `path: string`. Raised by [`notFound`](#notfound) or when no route matches. Caught by the router's internal not-found boundary; export it to place your own `Boundary.catchTag("RouterNotFound", …)` (a nearer user boundary wins).
297
+ `Schema.TaggedErrorClass` with an optional `path: string`. Raised by [`notFound`](#notfound) or when no route matches. Caught by the router's internal not-found boundary; export it to place your own `Boundary.catchTag("RouterNotFound", …)` (a nearer user boundary wins).
298
298
 
299
299
  ### `RouterParamsError`
300
300
 
301
- `Schema.TaggedError` with `source: "path" | "query"` and `keys: readonly string[]`. Raised by `Router.params` / `Router.query` when the live match doesn't satisfy the requested fields. Bubbles into the tree's aggregate error channel.
301
+ `Schema.TaggedErrorClass` with `source: "path" | "query"` and `keys: readonly string[]`. Raised by `Router.params` / `Router.query` when the live match doesn't satisfy the requested fields. Bubbles into the tree's aggregate error channel.
302
302
 
303
303
  ### `notFound`
304
304
 
@@ -11,7 +11,7 @@ description: Add component-local state with SubscriptionRef and weave its stream
11
11
 
12
12
  ## Local state with `SubscriptionRef`
13
13
 
14
- Use Effect's `SubscriptionRef` for component-local state. Its `.changes` property is a `Stream` that emits the current value and then every update. Pass that stream as a child or prop and the DOM at that spot becomes live:
14
+ Use Effect's `SubscriptionRef` for component-local state. `SubscriptionRef.changes(ref)` returns a `Stream` that emits the current value and then every update. Pass that stream as a child or prop and the DOM at that spot becomes live:
15
15
 
16
16
  ```typescript
17
17
  import { h } from "@weftui/core";
@@ -23,7 +23,7 @@ const Counter = () =>
23
23
  const count = yield* SubscriptionRef.make(0);
24
24
 
25
25
  return yield* h.div([
26
- h.span([count.changes]),
26
+ h.span([SubscriptionRef.changes(count)]),
27
27
  h.button({ onclick: () => SubscriptionRef.update(count, (n) => n + 1) }, "+"),
28
28
  h.button({ onclick: () => SubscriptionRef.update(count, (n) => n - 1) }, "-"),
29
29
  ]);
@@ -36,18 +36,18 @@ void Effect.runPromise(mount(Counter(), document.getElementById("root")!));
36
36
 
37
37
  ## The key idea: the body runs once
38
38
 
39
- The `Counter` function runs **exactly once**. It creates the ref, builds the tree, and returns. After that, nothing re-invokes it — the only thing that changes the DOM is the `count.changes` stream woven into the `h.span`. When you click `+`, `SubscriptionRef.update` pushes a new value, the stream emits, and the renderer patches _just that span's text_ in place. No diff, no re-render, no sibling touched.
39
+ The `Counter` function runs **exactly once**. It creates the ref, builds the tree, and returns. After that, nothing re-invokes it — the only thing that changes the DOM is the `SubscriptionRef.changes(count)` stream woven into the `h.span`. When you click `+`, `SubscriptionRef.update` pushes a new value, the stream emits, and the renderer patches _just that span's text_ in place. No diff, no re-render, no sibling touched.
40
40
 
41
41
  This is what "streams are the weft" means in practice: reactivity is local to exactly where you thread a stream. Everything else is static. The full model is [The Rendering Model](https://weftui.dev/docs/explanation/rendering-model); the vocabulary of stream-shaped values is [Reactive Primitives](https://weftui.dev/docs/explanation/reactive-primitives).
42
42
 
43
- > **Note.** `[count.changes]` — the stream is passed as a child array. Static values (`"Hello"`, `5`) work in the same position and simply never change. The rule is uniform: a plain value is static, a stream-shaped value is reactive.
43
+ > **Note.** `[SubscriptionRef.changes(count)]` — the stream is passed as a child array. Static values (`"Hello"`, `5`) work in the same position and simply never change. The rule is uniform: a plain value is static, a stream-shaped value is reactive.
44
44
 
45
45
  ## Deriving values
46
46
 
47
- Because `.changes` is a `Stream`, you shape reactive text with ordinary stream operators:
47
+ Because `SubscriptionRef.changes(count)` returns a `Stream`, you shape reactive text with ordinary stream operators:
48
48
 
49
49
  ```typescript
50
- h.span([Stream.map(count.changes, (n) => `Count: ${n}`)]);
50
+ h.span([Stream.map(SubscriptionRef.changes(count), (n) => `Count: ${n}`)]);
51
51
  ```
52
52
 
53
53
  Anywhere you would compute a derived value, map the stream instead — the derivation stays reactive.
@@ -18,10 +18,9 @@ import { h } from "@weftui/core";
18
18
  import { mount } from "@weftui/dom/client";
19
19
  import { Context, Effect, Layer, pipe } from "effect";
20
20
 
21
- class Logger extends Context.Tag("Logger")<
22
- Logger,
23
- { log: (message: string) => Effect.Effect<void> }
24
- >() {}
21
+ class Logger extends Context.Service<Logger, { log: (message: string) => Effect.Effect<void> }>()(
22
+ "Logger",
23
+ ) {}
25
24
 
26
25
  const LoggerLive = Layer.succeed(Logger, {
27
26
  log: (message) => Effect.sync(() => console.log(message)),
@@ -20,12 +20,12 @@ import { Data, Effect } from "effect";
20
20
  class ApiError extends Data.TaggedError("ApiError")<{ status: number }> {}
21
21
 
22
22
  const SafeWidget = () =>
23
- Boundary.catchAll({ fallback: (e) => h.div({ class: "error" }, `Request failed: ${e.status}`) }, [
23
+ Boundary.catch({ fallback: (e) => h.div({ class: "error" }, `Request failed: ${e.status}`) }, [
24
24
  Effect.fail(new ApiError({ status: 503 })),
25
25
  ]);
26
26
  ```
27
27
 
28
- There are six failure-catch variants — `catchAll`, `catchAllCause`, `catchTag`, `catchTags`, `catchSome`, `catchIf` — mirroring Effect's own error operators. A failure that a boundary does not match re-raises to the **nearest enclosing** boundary; if none catches it, the mount fails. The conceptual model (and why the boundary's type reflects exactly which failures are handled) is [Boundaries and Suspense](https://weftui.dev/docs/explanation/boundaries-and-suspense).
28
+ There are six failure-catch variants — `catch`, `catchCause`, `catchTag`, `catchTags`, `catchFilter`, `catchIf` — mirroring Effect's own error operators. A failure that a boundary does not match re-raises to the **nearest enclosing** boundary; if none catches it, the mount fails. The conceptual model (and why the boundary's type reflects exactly which failures are handled) is [Boundaries and Suspense](https://weftui.dev/docs/explanation/boundaries-and-suspense).
29
29
 
30
30
  ## Render on the server
31
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weftui/dom",
3
- "version": "0.26.3",
3
+ "version": "0.27.0",
4
4
  "description": "DOM renderer for Weft — mount and hydrate in the browser, render to string or stream on the server",
5
5
  "keywords": [
6
6
  "dom",
@@ -44,13 +44,12 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "@weftui/core": "0.26.3"
47
+ "@weftui/core": "0.27.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@effect/rpc": "^0.75.1",
51
50
  "@types/jsdom": "^28.0.3",
52
51
  "@types/node": "^25.9.2",
53
- "effect": "^3.21.4",
52
+ "effect": "4.0.0-beta.93",
54
53
  "jsdom": "^29.1.1",
55
54
  "tsx": "^4.22.4",
56
55
  "typescript": "^6.0.3",
@@ -58,6 +57,6 @@
58
57
  "vite-plus": "0.2.2"
59
58
  },
60
59
  "peerDependencies": {
61
- "effect": "^3.21"
60
+ "effect": "4.0.0-beta.93"
62
61
  }
63
62
  }