@wcstack/state 2.6.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.ja.md +91 -46
  2. package/README.md +93 -46
  3. package/dist/auto.min.js +1 -1
  4. package/dist/auto.min.js.map +1 -1
  5. package/dist/define.d.ts +295 -0
  6. package/dist/define.js +1 -0
  7. package/dist/index.d.ts +252 -94
  8. package/dist/index.esm.js +1 -23477
  9. package/dist/index.esm.js.map +1 -1
  10. package/dist/manifest.esm.js +21 -37
  11. package/dist/parser.d.ts +37 -39
  12. package/dist/parser.esm.js +147 -1153
  13. package/dist/split/chunks/binder.js +2 -0
  14. package/dist/split/chunks/binder.js.map +1 -0
  15. package/dist/split/chunks/checkDependency.js +2 -0
  16. package/dist/split/chunks/checkDependency.js.map +1 -0
  17. package/dist/split/chunks/diagnosticsHooks.js +2 -0
  18. package/dist/split/chunks/diagnosticsHooks.js.map +1 -0
  19. package/dist/split/chunks/errorGuidance.js +2 -0
  20. package/dist/split/chunks/errorGuidance.js.map +1 -0
  21. package/dist/split/chunks/features.d.ts +29 -0
  22. package/dist/split/chunks/filterRegistry.js +2 -0
  23. package/dist/split/chunks/filterRegistry.js.map +1 -0
  24. package/dist/split/chunks/getAllPropertyDescriptors.js +2 -0
  25. package/dist/split/chunks/getAllPropertyDescriptors.js.map +1 -0
  26. package/dist/split/chunks/lifecycleHooks.js +2 -0
  27. package/dist/split/chunks/lifecycleHooks.js.map +1 -0
  28. package/dist/split/chunks/mount.js +2 -0
  29. package/dist/split/chunks/mount.js.map +1 -0
  30. package/dist/split/chunks/pathDiagnostics.js +2 -0
  31. package/dist/split/chunks/pathDiagnostics.js.map +1 -0
  32. package/dist/split/chunks/registerComponents.js +2 -0
  33. package/dist/split/chunks/registerComponents.js.map +1 -0
  34. package/dist/split/chunks/setAll.js +2 -0
  35. package/dist/split/chunks/setAll.js.map +1 -0
  36. package/dist/split/chunks/version.js +2 -0
  37. package/dist/split/chunks/version.js.map +1 -0
  38. package/dist/split/chunks/watchRuntime.js +2 -0
  39. package/dist/split/chunks/watchRuntime.js.map +1 -0
  40. package/dist/split/core.d.ts +1417 -0
  41. package/dist/split/core.js +2 -0
  42. package/dist/split/core.js.map +1 -0
  43. package/dist/split/features/devtools.d.ts +9 -0
  44. package/dist/split/features/devtools.js +2 -0
  45. package/dist/split/features/devtools.js.map +1 -0
  46. package/dist/split/features/diagnostics.d.ts +11 -0
  47. package/dist/split/features/diagnostics.js +2 -0
  48. package/dist/split/features/diagnostics.js.map +1 -0
  49. package/dist/split/features/formats.d.ts +10 -0
  50. package/dist/split/features/formats.js +2 -0
  51. package/dist/split/features/formats.js.map +1 -0
  52. package/dist/split/features/recursion.d.ts +9 -0
  53. package/dist/split/features/recursion.js +2 -0
  54. package/dist/split/features/recursion.js.map +1 -0
  55. package/dist/split/features/scopes.d.ts +10 -0
  56. package/dist/split/features/scopes.js +2 -0
  57. package/dist/split/features/scopes.js.map +1 -0
  58. package/dist/split/features/ssr.d.ts +9 -0
  59. package/dist/split/features/ssr.js +2 -0
  60. package/dist/split/features/ssr.js.map +1 -0
  61. package/dist/split/features/temporal.d.ts +9 -0
  62. package/dist/split/features/temporal.js +2 -0
  63. package/dist/split/features/temporal.js.map +1 -0
  64. package/package.json +13 -1
@@ -0,0 +1,2 @@
1
+ import{c as t,S as e}from"../chunks/filterRegistry.js";import{O as n,P as o,Q as s,R as r,S as a,U as c,V as i,n as l,m as d,W as u,y as f,X as p,K as m,o as h,Y as N,Z as g,_ as y,v as b,$ as S,a0 as T,a1 as x,a2 as A,a3 as O,a4 as C,a5 as v,a6 as _,a7 as E,a8 as w,a9 as k,k as M,aa as P,ab as D,ac as j,ad as $,ae as W,g as B}from"../chunks/binder.js";import{H,a as q}from"../chunks/registerComponents.js";import{V as F}from"../chunks/version.js";import{W as R,I,g as z}from"../chunks/pathDiagnostics.js";import"../chunks/errorGuidance.js";import"../chunks/lifecycleHooks.js";import"../chunks/setAll.js";import"../chunks/getAllPropertyDescriptors.js";import"../chunks/checkDependency.js";import"../chunks/diagnosticsHooks.js";const J=/^@@wcs-(?:for|if|elseif|else):[^-]/,V=/^@@wcs-(for|if|elseif|else)-start:(.+)$/,L=/^@@wcs-(for|if|elseif|else)-end:(.+)$/,G=/^@@wcs-text-start:(.+)$/;function K(t){return t.replace(/</g,"\\u003c").replace(/>/g,"\\u003e").replace(/&/g,"\\u0026").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}class Q extends H{_stateData=null;_templates=null;_hydrateProps=null;get version(){return this.getAttribute("version")||""}get stateData(){return null===this._stateData&&(this._stateData=this._loadStateData()),this._stateData}get templates(){return null===this._templates&&(this._templates=this._loadTemplates()),this._templates}get hydrateProps(){return null===this._hydrateProps&&(this._hydrateProps=this._loadHydrateProps()),this._hydrateProps}getTemplate(t){return this.templates.get(t)??null}verifyVersion(){const t=this.version;if(!t)return!0;const e=t.split("."),n=F.split(".");return e[0]===n[0]&&e[1]===n[1]}setStateData(t){this._stateData=t}setHydrateProps(t){this._hydrateProps=t}_loadStateData(){const t=this.querySelector('script[type="application/json"]:not([data-wcs-ssr-props])');if(!t)return{};try{return JSON.parse(t.textContent||"{}")}catch{return{}}}_loadTemplates(){const t=new Map,e=this.querySelectorAll("template[id]");for(const n of e){const e=n.getAttribute("id");e&&t.set(e,n)}return t}_loadHydrateProps(){const t=this.querySelector("script[data-wcs-ssr-props]");if(!t)return{};try{return JSON.parse(t.textContent||"{}")}catch{return{}}}static find(e){const n=t.tagNames.ssr,o=e instanceof Element?e:e instanceof Document?e.documentElement:null;if(!o)return null;return o.querySelector(n)}static extractStateData(t){const e=t.__state;if(!e||"object"!=typeof e)return{};const n={};for(const t of Object.keys(e)){if(t.startsWith("$"))continue;const o=Object.getOwnPropertyDescriptor(e,t);if(void 0!==o&&"function"==typeof o.get)continue;const s=e[t];"function"!=typeof s&&(n[t]=s)}return n}static buildContent(e,c){const i=document.createElement("script");i.setAttribute("type","application/json"),i.textContent=K(JSON.stringify(c)),e.appendChild(i);const l=n();for(const n of l){const s=o(n);if(!s)continue;const r=document.createElement("template");r.setAttribute("id",n);const a=s.parseBindTextResult,c="else"===a.bindingType?"else:":`${a.bindingType}: ${a.statePathName}`;r.setAttribute(t.bindAttributeName,c);const i=s.fragment.cloneNode(!0);r.content.appendChild(i),e.appendChild(r)}const d=s();if(d.length>0){const t={};for(let e=0;e<d.length;e++){const n=d[e],o=r(n);if(0===o.length)continue;const s=`wcs-ssr-${e}`;n.setAttribute("data-wcs-ssr-id",s);const a={};for(const t of o)a[t.propName]=t.value;t[s]=a}if(Object.keys(t).length>0){const n=document.createElement("script");n.setAttribute("type","application/json"),n.setAttribute("data-wcs-ssr-props",""),n.textContent=K(JSON.stringify(t)),e.appendChild(n)}}a()}static removeBlockBoundaryComments(t){const e=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT),n=[];for(;e.nextNode();){const t=e.currentNode;(V.test(t.data)||L.test(t.data))&&n.push(t)}for(const t of n)t.remove()}static removeStructuralComments(t){const e=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT),n=[];for(;e.nextNode();){const t=e.currentNode;J.test(t.data)&&n.push(t)}for(const t of n)t.remove()}static restoreTextBindings(t){const e=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT),n=[];for(;e.nextNode();){const t=e.currentNode,o=G.exec(t.data);o&&n.push({comment:t,path:o[1]})}for(const{comment:t,path:e}of n){const n=document.createComment(`@@: ${e}`);t.parentNode.insertBefore(n,t);let o=t.nextSibling;t.remove();const s=`@@wcs-text-end:${e}`;for(;o;){const t=o.nextSibling;if(o.nodeType===Node.COMMENT_NODE&&o.data===s){o.parentNode.removeChild(o);break}o.parentNode.removeChild(o),o=t}}}static cleanupDom(e){const n=document.body,o=e.querySelectorAll(t.tagNames.ssr),s=new Map;for(const t of o){const e=t.querySelectorAll("template[id]");for(const t of e){const e=t.getAttribute("id");e&&s.set(e,t)}}const r=document.createTreeWalker(n,NodeFilter.SHOW_COMMENT),a=[];for(;r.nextNode();){const t=r.currentNode;V.test(t.data)&&a.push(t)}for(const t of a){const e=V.exec(t.data),n=`@@wcs-${e[1]}-end:${e[2]}`;let o=t.nextSibling;for(;o;){const t=o.nextSibling;if(o.nodeType===Node.COMMENT_NODE&&o.data===n){o.remove();break}o.remove(),o=t}t.remove()}Q.restoreTextBindings(n);const c=document.createTreeWalker(n,NodeFilter.SHOW_COMMENT),i=[];for(;c.nextNode();){const t=c.currentNode;if(J.test(t.data)){const e=t.data.split(":")[1];i.push({comment:t,uuid:e})}}for(const{comment:e,uuid:n}of i){const o=s.get(n);if(o){const n=document.createElement("template"),s=o.getAttribute(t.bindAttributeName);s&&n.setAttribute(t.bindAttributeName,s);const r=document.importNode(o.content,!0);if(r.childNodes.length>0)n.content.appendChild(r);else for(const t of Array.from(o.childNodes))n.content.appendChild(document.importNode(t,!0));e.parentNode.replaceChild(n,e)}}const l=e.querySelectorAll("[data-wcs-ssr-id]");for(const t of l)t.removeAttribute("data-wcs-ssr-id");for(const t of o)t.remove()}}const U={protocol:"wcs-ssr-snapshot",version:1,build:function(e){const n=t.tagNames.state,o=t.tagNames.ssr,s=e.querySelectorAll(`${n}[enable-ssr]:not([mount]):not([bind-component])`);for(const t of s){const e=t.previousElementSibling;if(null!==e&&e.tagName.toLowerCase()===o)continue;const n=document.createElement(o);n.setAttribute("version",F),Q.buildContent(n,Q.extractStateData(t)),t.parentNode?.insertBefore(n,t)}}};const X=new Set(["for","if","elseif","else"]);function Y(t){const e=new j;if(0===t.length)return{bindingInfos:[],subscriberNodes:[],bindingSession:e};const n=t[0].parentNode,o=t[t.length-1].nextSibling,s=document.createElement("div");for(const e of t)s.appendChild(e);const[r,a]=i(s),c=e.initialize(a,{registerAddress:!1,applyOnReconnect:!1});if(n)for(;s.firstChild;)n.insertBefore(s.firstChild,o);return{bindingInfos:c,subscriberNodes:r,bindingSession:e}}function Z(t,e,n){for(const o of e)"event"===o.bindingType||X.has(o.bindingType)||o.node.nodeType===Node.COMMENT_NODE||o.statePathName in I||z(o.statePathName).wildcardCount>n||t.push(o)}function tt(e,n,o){const s={for:t.commentForPrefix,if:t.commentIfPrefix,elseif:t.commentElseIfPrefix,else:t.commentElsePrefix}[n];if(!s)return null;const r=`@@${s}:${o}`,a=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT);for(;a.nextNode();){const t=a.currentNode;if(t.data===r)return t}return null}function et(e,n){const o=e;let s=null;for(const[e,r]of n.templates){const n=r.getAttribute(t.bindAttributeName)||"";let a=N(n)[0];const c=a.bindingType;"else"===c&&s&&(a={...s,outFilters:[...s.outFilters,$()],bindingType:"else"}),"if"===c||"elseif"===c?s=a:"else"===c&&(s=null);const i=document.importNode(r.content,!0),l="for"===c?a.statePathName:void 0;g(i),"string"==typeof l&&y(i,l),b(o,i,l);const d={fragment:i,parseBindTextResult:a,nodeInfos:S(i)};T(e,o,d)}}const nt={hydrate:async function(e){await c(e);const n=e.querySelectorAll(t.tagNames.ssr);for(const t of n){const n=t;if(!n.verifyVersion())return console.warn(`[@wcstack/state] SSR version mismatch: server="${n.version}", client="${F}". Falling back to full render.`),Q.cleanupDom(e),!1}for(const t of n)et(e,t);const s=function(t){const e=[],n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT),o=[];for(;n.nextNode();)o.push(n.currentNode);for(const t of o){const n=V.exec(t.data);if(!n)continue;const o=n[1],s=n[2],r=s.split(":");let a,c,i=null;"for"===o?(a=r[0],c=r[1],i=parseInt(r[2],10)):(a=r[0],c=r.slice(1).join(":"));const l=[];let d=t.nextSibling;const u=`@@wcs-${o}-end:${s}`;for(;d&&(d.nodeType!==Node.COMMENT_NODE||d.data!==u);)l.push(d),d=d.nextSibling;e.push({type:o,uuid:a,path:c,index:i,nodes:l})}return e}(document.body),r=function(t,e){const n=new Map,s=[];for(const o of e){if(0===o.nodes.length)continue;const e=x(o.nodes),{bindingInfos:r,subscriberNodes:a,bindingSession:c}=Y(o.nodes);A(e,c);for(const t of a)t.nodeType===Node.ELEMENT_NODE&&t.setAttribute("data-wcs-completed","");O(e,r),C(e,a);const i=[];for(const t of r)t.statePathName in I&&i.push(t);if(v(e,i),"for"===o.type&&null!==o.index){const a=tt(t,"for",o.uuid);if(a){const t=_(null,o.index);E(a,t,e);const i=o.nodes[o.nodes.length-1];w(a,i),k(a,e);const l=z(o.path+"."+R),d=M(l,t);P(e,d),c.initialize(r,{registerAddress:!0,registerPathInfo:!1,applyOnReconnect:!1}),Z(s,r,l.wildcardCount);let u=n.get(o.uuid);u||(u=[],n.set(o.uuid,u)),u.push(t)}}else{const n=tt(t,o.type,o.uuid);n&&(k(n,e),c.initialize(r,{registerAddress:!0,registerPathInfo:!1,applyOnReconnect:!1}),Z(s,r,0))}}for(const[e,s]of n){const n=tt(t,"for",e);if(!n)continue;const r=n.getRootNode(),a=o(e);if(!a)continue;const c=a.parseBindTextResult.statePathName,i=f(r);i&&i.createState("readonly",t=>{const e=t[c];Array.isArray(e)&&D(e,s)})}return s}(document.body,s);Q.removeBlockBoundaryComments(document.body);const a=[];for(const t of n)t.parentNode&&(a.push({el:t,parent:t.parentNode,next:t.nextSibling}),t.remove());Q.restoreTextBindings(document.body);const[N,g]=i(document.body);for(const t of N)if(t.nodeType===Node.ELEMENT_NODE){const e=t;e.hasAttribute("data-wcs-completed")||(l(t,null),e.setAttribute("data-wcs-completed",""))}else l(t,null);const y=[],b=[],S=d(document.body).initialize(g);for(const t of S)if("event"!==t.bindingType)if(X.has(t.bindingType))b.push(t);else{if(t.statePathName.includes(R))continue;y.push(t)}for(const t of b)if("for"===t.bindingType){const e=u(t),n=t.replaceNode.getRootNode(),o=f(n);o&&o.createState("readonly",n=>{const o=n[t.statePathName];Array.isArray(o)&&(p(e,o),m(e,o))})}h([...y,...r]);for(const{el:t,parent:e,next:n}of a)e.insertBefore(t,n);const T=e.querySelectorAll(t.tagNames.ssr);for(const t of T){const n=t.hydrateProps;for(const[t,o]of Object.entries(n)){const n=e.querySelector(`[data-wcs-ssr-id="${t}"]`);if(n)for(const[t,e]of Object.entries(o))n[t]=e}}const j=e.querySelectorAll("[data-wcs-completed]");for(const t of j)t.removeAttribute("data-wcs-completed");return!0},loadState(t){const e=t.parentNode;if(!e)return null;const n=Q.find(e);if(!n)return null;const o=n.stateData;return Object.keys(o).length>0?o:null},async emitSnapshot(e){await B(e.rootNode);const n=Q.extractStateData(e),o=document.createElement(t.tagNames.ssr);o.setAttribute("version",F),Q.buildContent(o,n),e.parentNode?.insertBefore(o,e)}};let ot=!1;function st(){ot||(ot=!0,W(nt),q(e=>{e.get(t.tagNames.ssr)||e.define(t.tagNames.ssr,Q)}),function(){const t=globalThis;void 0===t[e]&&(t[e]=U)}())}const rt={name:"ssr",install(){st()}};export{rt as default,rt as ssr};
2
+ //# sourceMappingURL=ssr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssr.js","sources":["../../../../../src/ssr/Ssr.ts","../../../../../src/ssr/buildSsrDocument.ts","../../../../../src/ssr/hydrateBindings.ts","../../../../../src/ssr/install.ts","../../../../../src/features/ssr.ts"],"sourcesContent":["import { config } from \"../config\";\nimport { IState } from \"../types\";\nimport { VERSION } from \"../version\";\nimport { getAllFragmentUUIDs, getFragmentInfoByUUID } from \"../structural/fragmentInfoByUUID\";\nimport { getAllSsrPropertyNodes, getSsrProperties, clearSsrPropertyStore } from \"../apply/ssrPropertyStore\";\nimport { HTMLElementBase } from \"../platform/HTMLElementBase\";\n\nexport interface ISsrElement {\n readonly version: string;\n readonly stateData: IState;\n readonly templates: Map<string, HTMLTemplateElement>;\n readonly hydrateProps: Record<string, Record<string, unknown>>;\n getTemplate(uuid: string): HTMLTemplateElement | null;\n verifyVersion(): boolean;\n}\n\n// SSR コメントパターン\nconst SSR_PLACEHOLDER_COMMENT = /^@@wcs-(?:for|if|elseif|else):[^-]/;\nconst SSR_BLOCK_START = /^@@wcs-(for|if|elseif|else)-start:(.+)$/;\nconst SSR_BLOCK_END = /^@@wcs-(for|if|elseif|else)-end:(.+)$/;\nconst SSR_TEXT_START = /^@@wcs-text-start:(.+)$/;\n\nexport {\n SSR_PLACEHOLDER_COMMENT,\n SSR_BLOCK_START,\n SSR_BLOCK_END,\n SSR_TEXT_START,\n};\n\n/**\n * script 要素へ埋め込む JSON を HTML パーサから保護する。\n * HTML 直列化時、script の中身は生のまま出力されるため、state 値に\n * \"</script>\" や \"<!--\" を含む文字列があると script を脱出できてしまう。\n * \"<\" \">\" \"&\" と U+2028/U+2029 を JSON の \\uXXXX エスケープへ置換する\n * (JSON.parse では元の文字列と等価に復元される)。\n */\nfunction escapeJsonForScript(json: string): string {\n return json\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/&/g, '\\\\u0026')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\nexport class Ssr extends HTMLElementBase implements ISsrElement {\n private _stateData: IState | null = null;\n private _templates: Map<string, HTMLTemplateElement> | null = null;\n private _hydrateProps: Record<string, Record<string, unknown>> | null = null;\n\n get version(): string {\n return this.getAttribute('version') || '';\n }\n\n get stateData(): IState {\n if (this._stateData === null) {\n this._stateData = this._loadStateData();\n }\n return this._stateData;\n }\n\n get templates(): Map<string, HTMLTemplateElement> {\n if (this._templates === null) {\n this._templates = this._loadTemplates();\n }\n return this._templates;\n }\n\n get hydrateProps(): Record<string, Record<string, unknown>> {\n if (this._hydrateProps === null) {\n this._hydrateProps = this._loadHydrateProps();\n }\n return this._hydrateProps;\n }\n\n getTemplate(uuid: string): HTMLTemplateElement | null {\n return this.templates.get(uuid) ?? null;\n }\n\n /**\n * サーバーの SSR バージョンとクライアントの state バージョンを検証する。\n * メジャー・マイナーバージョンが一致すればtrue。\n * version 属性がない場合は検証スキップ(true)。\n */\n verifyVersion(): boolean {\n const serverVersion = this.version;\n if (!serverVersion) return true;\n const serverParts = serverVersion.split('.');\n const clientParts = VERSION.split('.');\n // メジャー・マイナーが一致すれば互換\n return serverParts[0] === clientParts[0] && serverParts[1] === clientParts[1];\n }\n\n setStateData(data: IState): void {\n this._stateData = data;\n }\n\n setHydrateProps(props: Record<string, Record<string, unknown>>): void {\n this._hydrateProps = props;\n }\n\n private _loadStateData(): IState {\n const script = this.querySelector(\n `script[type=\"application/json\"]:not([data-wcs-ssr-props])`\n );\n if (!script) return {};\n try {\n return JSON.parse(script.textContent || '{}');\n } catch {\n return {};\n }\n }\n\n private _loadTemplates(): Map<string, HTMLTemplateElement> {\n const map = new Map<string, HTMLTemplateElement>();\n const templates = this.querySelectorAll<HTMLTemplateElement>('template[id]');\n for (const tpl of templates) {\n const id = tpl.getAttribute('id');\n if (id) {\n map.set(id, tpl);\n }\n }\n return map;\n }\n\n private _loadHydrateProps(): Record<string, Record<string, unknown>> {\n const script = this.querySelector('script[data-wcs-ssr-props]');\n if (!script) return {};\n try {\n return JSON.parse(script.textContent || '{}');\n } catch {\n return {};\n }\n }\n\n static find(root: Node): ISsrElement | null {\n const tagName = config.tagNames.ssr;\n const parentEl = root instanceof Element\n ? root\n : root instanceof Document\n ? root.documentElement\n : null;\n if (!parentEl) return null;\n const el = parentEl.querySelector(tagName);\n return el as ISsrElement | null;\n }\n\n /**\n * stateData と構造テンプレート・プロパティから <wcs-ssr> の中身を構築する。\n * server パッケージの renderToString から呼ばれる。\n */\n /**\n * wcs-state 要素から $ プレフィックスや関数を除いたデータを抽出する。\n */\n static extractStateData(stateEl: Element): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const key of Object.keys(raw)) {\n if (key.startsWith('$')) continue;\n // **アクセサは評価しない。** スナップショットが運ぶのはデータで、派生値は\n // クライアントが同じ宣言から作り直す。ここは Object.entries で舐めていたので、\n // own かつ enumerable な getter を**生の state オブジェクト**を this にして\n // 評価していた — proxy の上でしか意味を持たない本体(`this[\"items.*.n\"]` や\n // `this.$getAll(...)`)が、パス getter なら NaN → JSON の null で静かに壊れ、\n // `$getAll` を呼ぶ getter なら TypeError でページ全体の SSR を落としていた\n // (docs/state-recursive-path-impl-plan.md §7)。\n const descriptor = Object.getOwnPropertyDescriptor(raw, key);\n if (descriptor !== undefined && typeof descriptor.get === 'function') continue;\n const value = (raw as Record<string, unknown>)[key];\n if (typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n }\n\n static buildContent(ssrEl: Element, stateData: Record<string, any>): void {\n // 初期データ JSON\n const jsonScript = document.createElement('script');\n jsonScript.setAttribute('type', 'application/json');\n jsonScript.textContent = escapeJsonForScript(JSON.stringify(stateData));\n ssrEl.appendChild(jsonScript);\n\n // UUID で管理されているテンプレートを復元して格納\n const uuids = getAllFragmentUUIDs();\n for (const uuid of uuids) {\n const fragmentInfo = getFragmentInfoByUUID(uuid);\n if (!fragmentInfo) continue;\n\n const tpl = document.createElement('template');\n tpl.setAttribute('id', uuid);\n\n const bindResult = fragmentInfo.parseBindTextResult;\n const bindText = bindResult.bindingType === 'else'\n ? 'else:'\n : `${bindResult.bindingType}: ${bindResult.statePathName}`;\n tpl.setAttribute(config.bindAttributeName, bindText);\n\n const content = fragmentInfo.fragment.cloneNode(true) as DocumentFragment;\n tpl.content.appendChild(content);\n\n ssrEl.appendChild(tpl);\n }\n\n // 属性で代替不可なプロパティをハイドレーション用に格納\n const ssrNodes = getAllSsrPropertyNodes();\n if (ssrNodes.length > 0) {\n const propsData: Record<string, Record<string, unknown>> = {};\n for (let i = 0; i < ssrNodes.length; i++) {\n const node = ssrNodes[i];\n const entries = getSsrProperties(node);\n if (entries.length === 0) continue;\n const id = `wcs-ssr-${i}`;\n (node as Element).setAttribute('data-wcs-ssr-id', id);\n const props: Record<string, unknown> = {};\n for (const entry of entries) {\n props[entry.propName] = entry.value;\n }\n propsData[id] = props;\n }\n if (Object.keys(propsData).length > 0) {\n const propsScript = document.createElement('script');\n propsScript.setAttribute('type', 'application/json');\n propsScript.setAttribute('data-wcs-ssr-props', '');\n propsScript.textContent = escapeJsonForScript(JSON.stringify(propsData));\n ssrEl.appendChild(propsScript);\n }\n }\n\n clearSsrPropertyStore();\n }\n\n /**\n * SSR ブロック境界コメント (@@wcs-*-start/end) を除去する\n */\n static removeBlockBoundaryComments(root: Node): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const toRemove: Comment[] = [];\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n if (SSR_BLOCK_START.test(comment.data) || SSR_BLOCK_END.test(comment.data)) {\n toRemove.push(comment);\n }\n }\n for (const comment of toRemove) {\n comment.remove();\n }\n }\n\n /**\n * SSR の構造プレースホルダーコメント (@@wcs-for:uuid 等) を除去する\n */\n static removeStructuralComments(root: Node): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const toRemove: Comment[] = [];\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n if (SSR_PLACEHOLDER_COMMENT.test(comment.data)) {\n toRemove.push(comment);\n }\n }\n for (const comment of toRemove) {\n comment.remove();\n }\n }\n\n /**\n * SSR テキストバインディングコメントを復元する。\n * <!--@@wcs-text-start:path-->text<!--@@wcs-text-end:path-->\n * → <!--@@: path--> (バインディングシステムが認識する形式)\n */\n static restoreTextBindings(root: Node): void {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const startComments: { comment: Comment, path: string }[] = [];\n\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n const match = SSR_TEXT_START.exec(comment.data);\n if (match) {\n startComments.push({ comment, path: match[1] });\n }\n }\n\n for (const { comment, path } of startComments) {\n const bindComment = document.createComment(`@@: ${path}`);\n comment.parentNode!.insertBefore(bindComment, comment);\n\n let sibling: Node | null = comment.nextSibling;\n comment.remove();\n\n const endPattern = `@@wcs-text-end:${path}`;\n while (sibling) {\n const next: Node | null = sibling.nextSibling;\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n sibling.parentNode!.removeChild(sibling);\n break;\n }\n sibling.parentNode!.removeChild(sibling);\n sibling = next;\n }\n }\n }\n\n /**\n * SSR DOM をクリーンアップし、buildBindings が動作できる状態に戻す。\n * バージョン不一致時のフォールバック用。\n *\n * 1. SSR ブロック境界コメント間のレンダリング済みノードを除去\n * 2. SSR テキストバインディングを @@: 形式に復元\n * 3. プレースホルダーコメントを <wcs-ssr> 内のテンプレートで差し替え\n * 4. data-wcs-ssr-id 属性を除去\n * 5. <wcs-ssr> を除去\n */\n static cleanupDom(root: Document): void {\n const body = document.body;\n\n // <wcs-ssr> からテンプレート UUID マップを構築(カスタム要素未定義でも動作するよう DOM 直接走査)\n const ssrElements = root.querySelectorAll(config.tagNames.ssr);\n const templateByUuid = new Map<string, HTMLTemplateElement>();\n for (const ssrNode of ssrElements) {\n const templates = ssrNode.querySelectorAll<HTMLTemplateElement>('template[id]');\n for (const tpl of templates) {\n const id = tpl.getAttribute('id');\n if (id) {\n templateByUuid.set(id, tpl);\n }\n }\n }\n\n // SSR ブロック境界コメント間のレンダリング済みノードと境界コメントを除去\n const walker1 = document.createTreeWalker(body, NodeFilter.SHOW_COMMENT);\n const startComments: Comment[] = [];\n while (walker1.nextNode()) {\n const comment = walker1.currentNode as Comment;\n if (SSR_BLOCK_START.test(comment.data)) {\n startComments.push(comment);\n }\n }\n for (const startComment of startComments) {\n const match = SSR_BLOCK_START.exec(startComment.data)!;\n const type = match[1];\n const info = match[2];\n const endPattern = `@@wcs-${type}-end:${info}`;\n let sibling = startComment.nextSibling;\n while (sibling) {\n const next = sibling.nextSibling;\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n sibling.remove();\n break;\n }\n sibling.remove();\n sibling = next;\n }\n startComment.remove();\n }\n\n // SSR テキストバインディングを @@: 形式に復元\n Ssr.restoreTextBindings(body);\n\n // プレースホルダーコメント (@@wcs-for:uuid 等) をテンプレートに差し替え\n const walker2 = document.createTreeWalker(body, NodeFilter.SHOW_COMMENT);\n const placeholders: { comment: Comment, uuid: string }[] = [];\n while (walker2.nextNode()) {\n const comment = walker2.currentNode as Comment;\n if (SSR_PLACEHOLDER_COMMENT.test(comment.data)) {\n const uuid = comment.data.split(':')[1];\n placeholders.push({ comment, uuid });\n }\n }\n for (const { comment, uuid } of placeholders) {\n const tpl = templateByUuid.get(uuid);\n if (tpl) {\n const restored = document.createElement('template') as HTMLTemplateElement;\n const bindAttr = tpl.getAttribute(config.bindAttributeName);\n if (bindAttr) restored.setAttribute(config.bindAttributeName, bindAttr);\n const imported = document.importNode(tpl.content, true);\n if (imported.childNodes.length > 0) {\n restored.content.appendChild(imported);\n } else {\n for (const child of Array.from(tpl.childNodes)) {\n restored.content.appendChild(document.importNode(child, true));\n }\n }\n comment.parentNode!.replaceChild(restored, comment);\n }\n }\n\n // data-wcs-ssr-id 属性を除去\n const ssrIdElements = root.querySelectorAll('[data-wcs-ssr-id]');\n for (const el of ssrIdElements) {\n el.removeAttribute('data-wcs-ssr-id');\n }\n\n // <wcs-ssr> を除去\n for (const el of ssrElements) {\n el.remove();\n }\n }\n}\n","import { config } from \"../config\";\nimport { Ssr } from \"./Ssr\";\nimport { VERSION } from \"../version\";\nimport { IWcsSsrSnapshotBuilder, SSR_SNAPSHOT_BUILDER_KEY } from \"../protocol/ssrSnapshot\";\n\n/**\n * ssr-snapshot プロトコルの提供側(docs/ssr-router-design.md §5)。\n *\n * `<wcs-ssr>` スナップショットを document 全体に対する最終パスとして生成する。\n * connectedCallback 内の inline 生成は「その時点の DOM」しか見えず、router が\n * 後から挿入するルート内容の構造テンプレートを取り逃がすレースがあった\n * (state のロード方式と文書順に依存)。renderToString が全要素の完了と\n * バインディング構築の後にこれを呼ぶことで、スナップショットは常に確定後の\n * DOM を見る。\n *\n * 複数 `enable-ssr` state の意味論は inline 生成と同一に保つ(文書順に生成・\n * fragment レジストリはモジュール共有・props store は生成ごとにクリア)。\n * その整理は本プロトコルの範囲外の既存挙動として引き継ぐ。\n */\nexport function buildSsrDocument(root: Document): void {\n const stateTag = config.tagNames.state;\n const ssrTag = config.tagNames.ssr;\n // スナップショットはルートツリーに 1 本(D14): ボリューム(mount=)と bind-component は\n // 独立ツリー(__state)を持たないため、含めると空の <wcs-ssr> を生成してしまう。\n // Ssr.find は文書先頭一致なので、ルートより前の空スナップショットをルートが掴み、\n // ハイドレーション全体が無言で CSR 退化する\n const stateElements = root.querySelectorAll(`${stateTag}[enable-ssr]:not([mount]):not([bind-component])`);\n for (const stateEl of stateElements) {\n // 既に直前へ生成済み(旧 server との組み合わせで inline 生成された等)なら\n // 何もしない — build() は冪等でなければならない(プロトコル契約)\n const prev = stateEl.previousElementSibling;\n if (prev !== null && prev.tagName.toLowerCase() === ssrTag) {\n continue;\n }\n const ssrEl = document.createElement(ssrTag);\n ssrEl.setAttribute(\"version\", VERSION);\n Ssr.buildContent(ssrEl, Ssr.extractStateData(stateEl));\n stateEl.parentNode?.insertBefore(ssrEl, stateEl);\n }\n}\n\nconst builder: IWcsSsrSnapshotBuilder = {\n protocol: \"wcs-ssr-snapshot\",\n version: 1,\n build: buildSsrDocument,\n};\n\n/**\n * グローバル symbol へ自分を載せる。`bootstrapState` から呼ぶ。\n * binder(registerBinder)と同じ規範 — 既に別のコピーが載っているなら譲る\n * (そのコピーのレジストリが、そのページの正本だからである)。\n */\nexport function registerSsrSnapshotBuilder(): void {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[SSR_SNAPSHOT_BUILDER_KEY] === undefined) {\n globals[SSR_SNAPSHOT_BUILDER_KEY] = builder;\n }\n}\n\n/** テスト用: 登録を外す */\nexport function _unregisterSsrSnapshotBuilder(): void {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[SSR_SNAPSHOT_BUILDER_KEY] === builder) {\n delete globals[SSR_SNAPSHOT_BUILDER_KEY];\n }\n}\n","import { getAbsoluteStateAddressByBinding } from \"../binding/getAbsoluteStateAddressByBinding\";\nimport { setLastListValueByAbsoluteStateAddress } from \"../list/lastListValueByAbsoluteStateAddress\";\nimport { setStateListBaseline } from \"../list/stateListBaseline\";\nimport { parseBindTextsForElement } from \"../bindTextParser/parseBindTextsForElement\";\nimport { ParseBindTextResult } from \"../bindTextParser/types\";\nimport { BindingSession, getOrCreateBindingSession } from \"../bindings/BindingSession\";\nimport { collectNodesAndBindingInfos } from \"../bindings/collectNodesAndBindingInfos\";\nimport { setBindingsByContent } from \"../bindings/bindingsByContent\";\nimport { setBindingSessionByContent } from \"../bindings/bindingSessionByContent\";\nimport { setIndexBindingsByContent } from \"../bindings/indexBindingsByContent\";\nimport { setNodesByContent } from \"../bindings/nodesByContent\";\nimport { bindLoopContextToContent } from \"../bindings/bindLoopContextToContent\";\nimport { config } from \"../config\";\nimport { WILDCARD, INDEX_BY_INDEX_NAME } from \"../define\";\nimport { Ssr, SSR_BLOCK_START } from \"./Ssr\";\nimport { getStateElement } from \"../stateElementByName\";\nimport { setLoopContextByNode } from \"../list/loopContextByNode\";\nimport { applyChangeFromBindings } from \"../apply/applyChangeFromBindings\";\nimport { hydrateSetContent, hydrateSetLastNode } from \"../apply/applyChangeToFor\";\nimport { waitForStateInitialize } from \"../waitForStateInitialize\";\nimport { setFragmentInfoByUUID, getFragmentInfoByUUID } from \"../structural/fragmentInfoByUUID\";\nimport { setContentByNode } from \"../structural/contentsByNode\";\nimport { createContentFromNodes } from \"../structural/createContent\";\nimport { collectStructuralFragments } from \"../structural/collectStructuralFragments\";\nimport { createNotFilter } from \"../structural/createNotFilter\";\nimport { getFragmentNodeInfos } from \"../structural/getFragmentNodeInfos\";\nimport { optimizeFragment } from \"../structural/optimizeFragment\";\nimport { expandShorthandPaths } from \"../structural/expandShorthandPaths\";\nimport { createListIndex } from \"../list/createListIndex\";\nimport { IListIndex } from \"../list/types\";\nimport { setListIndexesByList } from \"../list/listIndexesByList\";\nimport { getPathInfo } from \"../address/PathInfo\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IBindingInfo } from \"../types\";\nimport { VERSION } from \"../version\";\n\n// ハイドレーション時にスキップするバインディングタイプ\nconst STRUCTURAL_TYPES = new Set(['for', 'if', 'elseif', 'else']);\n\n\ninterface ISsrBlock {\n type: string; // for, if, elseif, else\n uuid: string;\n path: string;\n index: number | null; // for のみ\n nodes: Node[]; // start〜end 間のノード\n}\n\n/**\n * SSR ブロック境界コメントを走査して、start〜end 間のノードを収集する\n */\nfunction collectSsrBlocks(root: Node): ISsrBlock[] {\n const blocks: ISsrBlock[] = [];\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const startComments: Comment[] = [];\n\n // まず全コメントを収集\n while (walker.nextNode()) {\n startComments.push(walker.currentNode as Comment);\n }\n\n for (const comment of startComments) {\n const startMatch = SSR_BLOCK_START.exec(comment.data);\n if (!startMatch) continue;\n\n const type = startMatch[1];\n const info = startMatch[2]; // \"uuid:path:index\" or \"uuid:path\"\n const parts = info.split(':');\n\n let uuid: string;\n let path: string;\n let index: number | null = null;\n\n if (type === 'for') {\n // uuid:path:index\n uuid = parts[0];\n path = parts[1];\n index = parseInt(parts[2], 10);\n } else {\n // uuid:path\n uuid = parts[0];\n path = parts.slice(1).join(':');\n }\n\n // start と end の間のノードを収集\n const nodes: Node[] = [];\n let sibling = comment.nextSibling;\n const endPattern = `@@wcs-${type}-end:${info}`;\n while (sibling) {\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n break;\n }\n nodes.push(sibling);\n sibling = sibling.nextSibling;\n }\n\n blocks.push({ type, uuid, path, index, nodes });\n }\n\n return blocks;\n}\n\n/**\n * live DOM ノード群からバインディングを収集する。\n * ノードを一時的に DocumentFragment に移動して collectNodesAndBindingInfos を実行し、\n * 元の位置に戻す。\n */\nfunction collectBindingsFromLiveNodes(\n nodes: Node[],\n): { bindingInfos: IBindingInfo[], subscriberNodes: Node[], bindingSession: BindingSession } {\n const bindingSession = new BindingSession();\n if (nodes.length === 0) {\n return { bindingInfos: [], subscriberNodes: [], bindingSession };\n }\n\n // ノードの元の位置を記録\n const parent = nodes[0].parentNode;\n const nextSibling = nodes[nodes.length - 1].nextSibling;\n\n // 一時的に wrapper 要素に移動(collectNodesAndBindingInfos は Element を受け付ける)\n const wrapper = document.createElement('div');\n for (const node of nodes) {\n wrapper.appendChild(node);\n }\n\n // バインディング収集\n const [subscriberNodes, allBindings] = collectNodesAndBindingInfos(wrapper);\n\n const bindingInfos = bindingSession.initialize(allBindings, {\n registerAddress: false,\n applyOnReconnect: false,\n });\n\n // 元の位置に戻す\n if (parent) {\n while (wrapper.firstChild) {\n parent.insertBefore(wrapper.firstChild, nextSibling);\n }\n }\n\n return {\n bindingInfos,\n subscriberNodes,\n bindingSession,\n };\n}\n\n/**\n * ブロックの中で初回値を適用するバインディングを集める(#258 X6 — hydrateBindings の注記)。\n *\n * 除くもの:\n * - 構造バインディング(SSR が描画済み)とイベント。\n * - コメントに乗ったバインディング。ブロックを集める時点のコメントのバインディングは構造の置き場\n * (`<!--@@wcs-for:uuid-->`)だけで、テキストの `@@:` はこの後で `Ssr.restoreTextBindings` が戻す。\n * テンプレートを復帰できなかった入れ子の置き場は text として解釈される(`text: uuid`)ので、\n * 構造の種別だけでは除けない。\n * - 添字のバインディング(`$1` / `$2` …)。state に依存しないので依存辺のための適用が要らず、SSR が\n * 描いた添字のままでよい(入れ子の内側の `$2` は、外側のループ文脈しか持たないので読めもしない)。\n * - ループの深さより多いワイルドカードを持つバインディング。入れ子のブロックの行は外側のブロックの\n * Content に吸収され、外側のループ文脈しか持たない(入れ子ハイドレーションの既知の制限・\n * integration.listLedgerParentKey.test.ts)。\n * コメントと段数の足りないバインディングは、適用しても失敗の報告をハイドレーションのたびに増やすだけになる。\n */\nfunction collectBlockBindings(out: IBindingInfo[], bindings: readonly IBindingInfo[], loopDepth: number): void {\n for (const binding of bindings) {\n if (binding.bindingType === \"event\" || STRUCTURAL_TYPES.has(binding.bindingType)) {\n continue;\n }\n if (binding.node.nodeType === Node.COMMENT_NODE || binding.statePathName in INDEX_BY_INDEX_NAME) {\n continue;\n }\n if (getPathInfo(binding.statePathName).wildcardCount > loopDepth) {\n continue;\n }\n out.push(binding);\n }\n}\n\n/**\n * SSR ブロックの DOM ノードを Content 化し、バインディングを登録する。\n * 戻り値はブロックの中で初回値を適用するバインディング(`collectBlockBindings`)。\n */\nfunction hydrateBlocks(root: Node, blocks: ISsrBlock[]): IBindingInfo[] {\n // for ブロックの listIndex を UUID ごとに収集\n const listIndexesByUuid: Map<string, IListIndex[]> = new Map();\n const blockBindings: IBindingInfo[] = [];\n\n for (const block of blocks) {\n if (block.nodes.length === 0) continue;\n\n const content = createContentFromNodes(block.nodes);\n\n // Content のバインディングを収集\n const { bindingInfos, subscriberNodes, bindingSession } = collectBindingsFromLiveNodes(block.nodes);\n setBindingSessionByContent(content, bindingSession);\n\n // Content 内のノードに data-wcs-completed を付与\n // (メインの collectNodesAndBindingInfos で重複登録されないようにする)\n for (const node of subscriberNodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n (node as Element).setAttribute('data-wcs-completed', '');\n }\n }\n setBindingsByContent(content, bindingInfos);\n setNodesByContent(content, subscriberNodes);\n\n const indexBindings: IBindingInfo[] = [];\n for (const binding of bindingInfos) {\n if (binding.statePathName in INDEX_BY_INDEX_NAME) {\n indexBindings.push(binding);\n }\n }\n setIndexBindingsByContent(content, indexBindings);\n\n if (block.type === 'for' && block.index !== null) {\n const placeholderComment = findPlaceholderComment(root, 'for', block.uuid);\n if (placeholderComment) {\n const listIndex = createListIndex(null, block.index);\n hydrateSetContent(placeholderComment, listIndex, content);\n const lastNode = block.nodes[block.nodes.length - 1];\n hydrateSetLastNode(placeholderComment, lastNode);\n setContentByNode(placeholderComment, content);\n\n // ループコンテキストをバインドし、バインディングをアドレスに登録\n const pathInfo = getPathInfo(block.path + '.' + WILDCARD);\n const stateAddress = createStateAddress(pathInfo, listIndex);\n // ILoopContext は IStateAddress + listIndex なので、stateAddress をそのまま使う\n bindLoopContextToContent(content, stateAddress as any);\n\n bindingSession.initialize(bindingInfos, {\n registerAddress: true,\n registerPathInfo: false,\n applyOnReconnect: false,\n });\n collectBlockBindings(blockBindings, bindingInfos, pathInfo.wildcardCount);\n\n // listIndex を UUID ごとに収集(後で setListIndexesByList に渡す)\n let indexes = listIndexesByUuid.get(block.uuid);\n if (!indexes) {\n indexes = [];\n listIndexesByUuid.set(block.uuid, indexes);\n }\n indexes.push(listIndex);\n }\n } else {\n const placeholderComment = findPlaceholderComment(root, block.type, block.uuid);\n if (placeholderComment) {\n setContentByNode(placeholderComment, content);\n\n bindingSession.initialize(bindingInfos, {\n registerAddress: true,\n registerPathInfo: false,\n applyOnReconnect: false,\n });\n // if / elseif / else の中身はループの外(入れ子の行はここに吸収されても段数で除かれる)\n collectBlockBindings(blockBindings, bindingInfos, 0);\n }\n }\n }\n\n // for ブロックの listIndex を state のリスト値に紐づける\n for (const [uuid, indexes] of listIndexesByUuid) {\n const placeholderComment = findPlaceholderComment(root, 'for', uuid);\n if (!placeholderComment) continue;\n // state から現在のリスト値を取得して listIndexes を設定\n const rootNode = placeholderComment.getRootNode() as Node;\n // structuralBindings はまだ登録前なので、getParseBindTextResults を直接使う\n const fragmentInfo = getFragmentInfoByUUID(uuid);\n if (!fragmentInfo) continue;\n const statePathName = fragmentInfo.parseBindTextResult.statePathName;\n const stateElement = getStateElement(rootNode);\n if (!stateElement) continue;\n stateElement.createState(\"readonly\", (state) => {\n const list = state[statePathName];\n if (Array.isArray(list)) {\n setListIndexesByList(list, indexes);\n }\n });\n }\n return blockBindings;\n}\n\nfunction findPlaceholderComment(root: Node, type: string, uuid: string): Comment | null {\n const keywordMap: Record<string, string> = {\n 'for': config.commentForPrefix,\n 'if': config.commentIfPrefix,\n 'elseif': config.commentElseIfPrefix,\n 'else': config.commentElsePrefix,\n };\n const keyword = keywordMap[type];\n if (!keyword) return null;\n\n const pattern = `@@${keyword}:${uuid}`;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n if (comment.data === pattern) {\n return comment;\n }\n }\n return null;\n}\n\n/**\n * <wcs-ssr> 内のテンプレートを fragmentInfoByUUID に復帰させる。\n */\nfunction restoreFragments(root: Document, ssrEl: Ssr): void {\n const rootNode = root as Node;\n let lastIfParseResult: ParseBindTextResult | null = null;\n\n for (const [uuid, tpl] of ssrEl.templates) {\n const bindText = tpl.getAttribute(config.bindAttributeName) || '';\n const parseBindTextResults = parseBindTextsForElement(bindText);\n let parseBindTextResult = parseBindTextResults[0];\n const bindingType = parseBindTextResult.bindingType;\n\n // else: 直前の if 条件の not → 条件反転(elseif は独自条件のままでよい)\n if (bindingType === 'else' && lastIfParseResult) {\n parseBindTextResult = {\n ...lastIfParseResult,\n outFilters: [...lastIfParseResult.outFilters, createNotFilter()],\n bindingType: 'else',\n };\n }\n\n // if chain の追跡\n if (bindingType === 'if') {\n lastIfParseResult = parseBindTextResult;\n } else if (bindingType === 'elseif') {\n lastIfParseResult = parseBindTextResult;\n } else if (bindingType === 'else') {\n lastIfParseResult = null;\n }\n\n const fragment = document.importNode(tpl.content, true);\n const forPath = bindingType === \"for\" ? parseBindTextResult.statePathName : undefined;\n optimizeFragment(fragment);\n if (typeof forPath === \"string\") {\n expandShorthandPaths(fragment, forPath);\n }\n collectStructuralFragments(rootNode, fragment, forPath);\n\n const fragmentInfo = {\n fragment,\n parseBindTextResult,\n nodeInfos: getFragmentNodeInfos(fragment),\n };\n setFragmentInfoByUUID(uuid, rootNode, fragmentInfo);\n }\n}\n\n/**\n * SSR ハイドレーション用バインディング初期化。\n * バージョン不一致時は DOM をクリーンアップして false を返す\n * (呼び出し元で buildBindings にフォールバック)。\n */\nexport async function hydrateBindings(root: Document): Promise<boolean> {\n await waitForStateInitialize(root);\n\n // バージョン検証\n const ssrElements = root.querySelectorAll(config.tagNames.ssr);\n for (const ssrNode of ssrElements) {\n const ssrEl = ssrNode as Ssr;\n if (!ssrEl.verifyVersion()) {\n console.warn(\n `[@wcstack/state] SSR version mismatch: server=\"${ssrEl.version}\", client=\"${VERSION}\". Falling back to full render.`\n );\n Ssr.cleanupDom(root);\n return false;\n }\n }\n\n // <wcs-ssr> からテンプレートを fragmentInfoByUUID に復帰\n for (const ssrNode of ssrElements) {\n restoreFragments(root, ssrNode as Ssr);\n }\n\n // SSR ブロック境界コメントから既存 DOM を Content 化\n const blocks = collectSsrBlocks(document.body);\n const blockBindings = hydrateBlocks(document.body, blocks);\n\n // ブロック境界コメント (start/end) を除去\n Ssr.removeBlockBoundaryComments(document.body);\n\n // <wcs-ssr> を一時除去(バインディング走査に含めない)\n const ssrParents: { el: Element, parent: Node, next: Node | null }[] = [];\n for (const el of ssrElements) {\n if (el.parentNode) {\n ssrParents.push({ el, parent: el.parentNode, next: el.nextSibling });\n el.remove();\n }\n }\n\n // 構造プレースホルダーコメント (@@wcs-for:uuid 等) は残す\n // → バインディング走査で拾われ、状態変化時の再レンダリングに使われる\n\n // SSR テキストバインディングを @@: 形式に復元\n Ssr.restoreTextBindings(document.body);\n\n // ノードとバインディングを収集\n const [subscriberNodes, allBindings] = collectNodesAndBindingInfos(document.body);\n\n // 収集完了したノードに data-wcs-completed 属性を付与\n // for ブロック内ノード(hydrateBlocks で登録済み)にはループコンテキストをリセットしない\n for (const node of subscriberNodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n if (!el.hasAttribute('data-wcs-completed')) {\n setLoopContextByNode(node, null);\n el.setAttribute('data-wcs-completed', '');\n }\n } else {\n // コメントノード等\n setLoopContextByNode(node, null);\n }\n }\n\n // バインディングを構造系とそれ以外に分離\n const normalBindings: IBindingInfo[] = [];\n const structuralBindings: IBindingInfo[] = [];\n const bindingSession = getOrCreateBindingSession(document.body);\n const initializedBindings = bindingSession.initialize(allBindings);\n\n for (const binding of initializedBindings) {\n if (binding.bindingType === \"event\") continue;\n if (STRUCTURAL_TYPES.has(binding.bindingType)) {\n structuralBindings.push(binding);\n } else if (binding.statePathName.includes(WILDCARD)) {\n // for ブロック内のバインディング → Content のバインディングとして登録済み\n continue;\n } else {\n normalBindings.push(binding);\n }\n }\n\n // for バインディングの lastListValue を初期値として設定\n // (次回の状態変化時に差分計算の基準になる)\n for (const binding of structuralBindings) {\n if (binding.bindingType === 'for') {\n const absAddr = getAbsoluteStateAddressByBinding(binding);\n const rootNode = binding.replaceNode.getRootNode() as Node;\n const stateElement = getStateElement(rootNode);\n if (stateElement) {\n stateElement.createState(\"readonly\", (state) => {\n const value = state[binding.statePathName];\n if (Array.isArray(value)) {\n setLastListValueByAbsoluteStateAddress(absAddr, value);\n // 描画の基準と同時に state 側の基準も進める(E1。applyChangeFromBindings と対称)\n setStateListBaseline(absAddr, value);\n }\n });\n }\n }\n }\n\n // 初回値の適用(構造バインディングは SSR 描画済みなので除く)。SSR ブロック(for の行・if の中身)の\n // 中のバインディングも適用する(#258 X6): getter の依存辺は getter を評価したときにしか張られない\n // ので、適用しないと行の `items.*.double` は `items.*.n` を書いても一度も再評価されず、サーバーが\n // 書いたテキストのまま固まる。値は SSR と同じ state から読むのでテキストは変わらない\n applyChangeFromBindings([...normalBindings, ...blockBindings]);\n\n // <wcs-ssr> を元に戻す\n for (const { el, parent, next } of ssrParents) {\n parent.insertBefore(el, next);\n }\n\n // hydrateProps 復元\n const restoredSsrElements = root.querySelectorAll(config.tagNames.ssr);\n for (const ssrNode of restoredSsrElements) {\n const ssrEl = ssrNode as Ssr;\n const props = ssrEl.hydrateProps;\n for (const [id, propMap] of Object.entries(props)) {\n const target = root.querySelector(`[data-wcs-ssr-id=\"${id}\"]`);\n if (!target) continue;\n for (const [propName, value] of Object.entries(propMap)) {\n (target as any)[propName] = value;\n }\n }\n }\n\n // ハイドレーション中の重複登録防止用属性を除去\n const completedEls = root.querySelectorAll('[data-wcs-completed]');\n for (const el of completedEls) {\n el.removeAttribute('data-wcs-completed');\n }\n\n return true;\n}\n\n/** @internal テスト用 */\nexport const __test = {\n collectSsrBlocks,\n collectBindingsFromLiveNodes,\n hydrateBlocks,\n findPlaceholderComment,\n restoreFragments,\n};\n","/**\n * ssr/install.ts — SSR 機能の install(設計案 H8、S5)。core の受け口(core/ssrHooks.ts と\n * registerComponents の definer)へこの機能の実装を置き、ssr-snapshot プロトコルを提供する。\n * 従来 `State` と `stateElementByName` と `registerComponents` に直書きされていた分岐で、\n * 理由のコメントは元の位置から移してある。\n */\nimport { config } from \"../config\";\nimport type { IStateElement } from \"../components/types\";\nimport { ISsrHooks, setSsrHooks } from \"../core/ssrHooks\";\nimport { registerComponentDefiner } from \"../registerComponents\";\nimport { getBindingsReady } from \"../stateElementByName\";\nimport { VERSION } from \"../version\";\nimport { registerSsrSnapshotBuilder } from \"./buildSsrDocument\";\nimport { hydrateBindings } from \"./hydrateBindings\";\nimport { Ssr } from \"./Ssr\";\n\nexport const ssrFeatureHooks: ISsrHooks = {\n hydrate: hydrateBindings,\n loadState(element) {\n const root = element.parentNode;\n if (!root) return null;\n const ssrEl = Ssr.find(root);\n if (!ssrEl) return null;\n const data = ssrEl.stateData;\n return Object.keys(data).length > 0 ? data : null;\n },\n async emitSnapshot(element) {\n await getBindingsReady((element as unknown as IStateElement).rootNode);\n const stateData = Ssr.extractStateData(element);\n const ssrEl = document.createElement(config.tagNames.ssr);\n ssrEl.setAttribute(\"version\", VERSION);\n Ssr.buildContent(ssrEl, stateData);\n element.parentNode?.insertBefore(ssrEl, element);\n },\n};\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installSsr(): void {\n if (installed) return;\n installed = true;\n setSsrHooks(ssrFeatureHooks);\n registerComponentDefiner((registry) => {\n if (!registry.get(config.tagNames.ssr)) {\n registry.define(config.tagNames.ssr, Ssr);\n }\n });\n // ssr-snapshot プロトコルの提供(docs/ssr-router-design.md §5)。renderToString が\n // `<wcs-ssr>` 生成をサーバー主導の最終パスへ回せるようにする。登録は冪等\n registerSsrSnapshotBuilder();\n}\n","/**\n * features/ssr.ts — サーバー描画とハイドレーション(@wcstack/state/features/ssr)。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installSsr } from \"../ssr/install\";\n\nexport const ssr: IStateFeature = {\n name: \"ssr\",\n install(): void {\n installSsr();\n },\n};\nexport default ssr;\n"],"names":["SSR_PLACEHOLDER_COMMENT","SSR_BLOCK_START","SSR_BLOCK_END","SSR_TEXT_START","escapeJsonForScript","json","replace","Ssr","HTMLElementBase","_stateData","_templates","_hydrateProps","version","this","getAttribute","stateData","_loadStateData","templates","_loadTemplates","hydrateProps","_loadHydrateProps","getTemplate","uuid","get","verifyVersion","serverVersion","serverParts","split","clientParts","VERSION","setStateData","data","setHydrateProps","props","script","querySelector","JSON","parse","textContent","map","Map","querySelectorAll","tpl","id","set","find","root","tagName","config","tagNames","ssr","parentEl","Element","Document","documentElement","extractStateData","stateEl","raw","__state","key","Object","keys","startsWith","descriptor","getOwnPropertyDescriptor","undefined","value","buildContent","ssrEl","jsonScript","document","createElement","setAttribute","stringify","appendChild","uuids","getAllFragmentUUIDs","fragmentInfo","getFragmentInfoByUUID","bindResult","parseBindTextResult","bindText","bindingType","statePathName","bindAttributeName","content","fragment","cloneNode","ssrNodes","getAllSsrPropertyNodes","length","propsData","i","node","entries","getSsrProperties","entry","propName","propsScript","clearSsrPropertyStore","removeBlockBoundaryComments","walker","createTreeWalker","NodeFilter","SHOW_COMMENT","toRemove","nextNode","comment","currentNode","test","push","remove","removeStructuralComments","restoreTextBindings","startComments","match","exec","path","bindComment","createComment","parentNode","insertBefore","sibling","nextSibling","endPattern","next","nodeType","Node","COMMENT_NODE","removeChild","cleanupDom","body","ssrElements","templateByUuid","ssrNode","walker1","startComment","walker2","placeholders","restored","bindAttr","imported","importNode","childNodes","child","Array","from","replaceChild","ssrIdElements","el","removeAttribute","builder","protocol","build","stateTag","state","ssrTag","stateElements","prev","previousElementSibling","toLowerCase","STRUCTURAL_TYPES","Set","collectBindingsFromLiveNodes","nodes","bindingSession","BindingSession","bindingInfos","subscriberNodes","parent","wrapper","allBindings","collectNodesAndBindingInfos","initialize","registerAddress","applyOnReconnect","firstChild","collectBlockBindings","out","bindings","loopDepth","binding","has","INDEX_BY_INDEX_NAME","getPathInfo","wildcardCount","findPlaceholderComment","type","keyword","for","commentForPrefix","if","commentIfPrefix","elseif","commentElseIfPrefix","else","commentElsePrefix","pattern","restoreFragments","rootNode","lastIfParseResult","parseBindTextsForElement","outFilters","createNotFilter","forPath","optimizeFragment","expandShorthandPaths","collectStructuralFragments","nodeInfos","getFragmentNodeInfos","setFragmentInfoByUUID","ssrFeatureHooks","hydrate","async","waitForStateInitialize","console","warn","blocks","startMatch","info","parts","index","parseInt","slice","join","collectSsrBlocks","blockBindings","listIndexesByUuid","block","createContentFromNodes","setBindingSessionByContent","ELEMENT_NODE","setBindingsByContent","setNodesByContent","indexBindings","setIndexBindingsByContent","placeholderComment","listIndex","createListIndex","hydrateSetContent","lastNode","hydrateSetLastNode","setContentByNode","pathInfo","WILDCARD","stateAddress","createStateAddress","bindLoopContextToContent","registerPathInfo","indexes","getRootNode","stateElement","getStateElement","createState","list","isArray","setListIndexesByList","hydrateBlocks","ssrParents","hasAttribute","setLoopContextByNode","normalBindings","structuralBindings","initializedBindings","getOrCreateBindingSession","includes","absAddr","getAbsoluteStateAddressByBinding","replaceNode","setLastListValueByAbsoluteStateAddress","setStateListBaseline","applyChangeFromBindings","restoredSsrElements","propMap","target","completedEls","loadState","element","emitSnapshot","getBindingsReady","installed","installSsr","setSsrHooks","registerComponentDefiner","registry","define","globals","globalThis","SSR_SNAPSHOT_BUILDER_KEY","registerSsrSnapshotBuilder","name","install"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { I as IStateFeature } from '../chunks/features.js';
2
+
3
+ /**
4
+ * features/temporal.ts — `$watch` / `$scan` / `$streams`(@wcstack/state/features/temporal)。
5
+ */
6
+
7
+ declare const temporal: IStateFeature;
8
+
9
+ export { temporal as default, temporal };
@@ -0,0 +1,2 @@
1
+ import{g as e,r as t,N as n,a as o}from"../chunks/getAllPropertyDescriptors.js";import{S as s,a as r,D as a,W as i,b as c,g as u,M as l,c as f,d,e as $}from"../chunks/pathDiagnostics.js";import{r as m,L as p,d as h}from"../chunks/errorGuidance.js";import{c as y,d as g,e as w,l as b,f as v}from"../chunks/binder.js";import{g as k,c as O,a as j,s as S,m as A,b as P,r as I,h as E,i as _,d as R,e as x,f as z,w as W,n as M,p as D,j as L,k as N,l as C,o as F,q as G,t as T,u as q,v as U,x as H}from"../chunks/watchRuntime.js";import{i as K}from"../chunks/filterRegistry.js";const Q="[wcs/scan-declaration-invalid]",B=Object.freeze([]);function J(e){return`${s} entry "${e}"`}function V(e,t){for(const n of e.cumulativePaths)if(t.has(n))return n;return null}function X(e,t,n,o){return`[wcs/scan-source-computed] ${e} ${t} "${n}" ${o===n?"is a getter":o.includes(`${i}${i}`)?`is computed by the recursive getter "${o}"`:`is under the getter "${o}"`}. A getter re-evaluates whenever its inputs change, so folding it would count re-evaluations, not events. Fold the plain value the getter reads, or use "on" with an event token.${p}`}function Y(e,t,n){0===n.length&&m(`${Q} ${e} "${t}" must be a non-empty state path.${p}`),n.startsWith("$")&&m(`${Q} ${e} ${t} "${n}" must not start with "$" (reserved namespace).${p}`),n.includes("@")&&m(`${Q} ${e} ${t} "${n}" must not contain "@" — there is a single state tree per root.${p}`),n in Object.prototype&&m(`${Q} ${e} ${t} "${n}" must not be a property name inherited from Object.prototype (e.g. "__proto__", "constructor").${p}`);const o=u(n);for(const s of o.segments)0===s.length&&m(`${Q} ${e} ${t} "${n}" has an empty path segment.${p}`);return o.wildcardCount>l&&m(`${Q} ${e} ${t} "${n}" exceeds the maximum wildcard depth (${l}).`),o}function Z(e,t,n,o){const c=J(e);0===e.length&&m(`${Q} ${s} entry name must be a non-empty string.${p}`),(e.includes(a)||e.includes(i))&&m(`${Q} ${c} must be a flat property name ("${a}" and "${i}" are not allowed). The output is a property the runtime owns.${p}`),e.startsWith("$")&&m(`${Q} ${c} must not start with "$" (reserved namespace).${p}`),e in Object.prototype&&m(`${Q} ${c} must not be a property name inherited from Object.prototype (e.g. "__proto__", "constructor").${p}`),t.has(e)&&m(`${Q} ${c} conflicts with a getter declared on the state.${p}`),n.has(e)&&m(`${Q} ${c} conflicts with a setter declared on the state.${p}`),o.has(e)&&m(`${Q} ${c} conflicts with the ${r} entry of the same name — each output has exactly one owner.${p}`)}function ee(e,t,n){const o=t.get(e);t.has(e)&&o!==n.initial&&!W(e,o)&&m(`${Q} ${J(e)} conflicts with a method (a function-valued property) declared on the state. The output is a property the runtime owns.${p}`)}function te(e,t,n,o,s,r){const i=J(e),u=void 0!==t.from,l=void 0!==t.on;if(u===l&&m(`${Q} ${i} must declare exactly one of "from" (a state path) or "on" (an event-token name).${p}`),l){const e=t.on;return"string"==typeof e&&0!==e.length||m(`${Q} ${i} "on" must be a non-empty event-token name.${p}`),n.has(e)||m(`${Q} ${i} on "${e}" is not declared in ${c}.${h(e,n)}${p}`),{kind:"event",tokenName:e}}const f=t.from;"string"!=typeof f&&m(`${Q} ${i} "from" must be a state path string.${p}`);const d=Y(i,"from",f),$=V(d,o)??r?.recursiveGetterOwning(f)??null;null!==$&&m(X(i,"from",f,$));const y=V(d,s);return null!==y&&m(function(e,t,n){return`${Q} ${e} from "${t}" ${n===t?"is a setter without a getter":`is under the setter without a getter "${n}"`}, so it always reads undefined and every fold would receive undefined. Fold the plain value the setter writes, or use "on" with an event token.${p}`}(i,f,y)),(f===e||f.startsWith(e+a))&&m(`${Q} ${i} from "${f}" reads the entry's own output — the scan would fold its own writes forever.${p}`),{kind:"path",path:f,pathInfo:d}}function ne(e,t,n,o){if(void 0===t)return B;const s=J(e);Array.isArray(t)||m(`${Q} ${s} "resetOn" must be an array of state paths.${p}`);const r=[];for(const e of t){"string"!=typeof e&&m(`${Q} ${s} "resetOn" must contain only state path strings.${p}`);const t=Y(s,"resetOn",e);t.wildcardCount>0&&m(`${Q} ${s} resetOn "${e}" must not contain "${i}" — a reset returns the whole output to "initial".${p}`);const c=V(t,o);null!==c&&m(X(s,"resetOn",e,c)),"path"===n.kind&&e===n.path&&m(`${Q} ${s} resetOn "${e}" is the entry's own "from" — every change would reset instead of fold.${p}`),"path"===n.kind&&e.startsWith(n.path+a)&&m(`${Q} ${s} resetOn "${e}" sits under the entry's own "from" "${n.path}" — every write of "from" also lands it, so the reset would win every time and nothing would fold.${p}`),r.push(e)}return r}function oe(t,n,o=null){const a=t[s];if(void 0===a)return null;("object"!=typeof a||null===a||Array.isArray(a))&&m(`${Q} ${s} must be an object mapping output names to scan definitions ({ from | on, initial, fold, resetOn? }).${p}`);const i=new Set,c=new Set,l=new Set,f=new Map;for(const[n,o]of Object.entries(e(t)))"function"==typeof o.get?i.add(n):"function"==typeof o.set&&l.add(n),"function"==typeof o.set&&c.add(n),"function"==typeof o.value&&f.set(n,o.value);const d=function(e){const t=e[r];return"object"!=typeof t||null===t?new Set:new Set(Object.keys(t))}(t),$=[];let h=0;for(const[e,t]of Object.entries(a)){Z(e,i,c,d),("object"!=typeof t||null===t||Array.isArray(t))&&m(`${Q} ${J(e)} must be an object ({ from | on, initial, fold, resetOn? }).${p}`);const s=t;ee(e,f,s);const r=te(e,s,n,i,l,o);"initial"in s||m(`${Q} ${J(e)} requires "initial" — the seed of the accumulator and the value "resetOn" returns to.${p}`),"function"!=typeof s.fold&&m(`${Q} ${J(e)} fold must be a function.${p}`);const a=ne(e,s.resetOn,r,i);$.push({name:e,source:r,fold:s.fold,initial:s.initial,resetOn:a,order:h++})}return function(e){const t=new Set(e.map(e=>e.name)),n=new Map;for(const o of e){for(const e of o.resetOn){const n=u(e).segments[0];t.has(n)&&m(`${Q} ${J(o.name)} resetOn "${e}" reads the ${s} output "${n}" — a reset driven by an accumulator is a feedback loop. Reset on the plain inputs instead.${p}`)}if("path"===o.source.kind){const e=o.source.pathInfo.segments[0];t.has(e)&&n.set(o.name,e)}}for(const e of n.keys()){const o=[e];let r=n.get(e);for(;void 0!==r&&o.length<=t.size;)r===e&&m(`${Q} ${s} entries ${[...o,e].map(e=>`"${e}"`).join(" → ")} feed each other through "from" — each fold would re-trigger the next forever.${p}`),o.push(r),r=n.get(r)}}($),$.length>0?$:null}function se(e){const t=e.fold;return(n,o,...s)=>{const r=n;let a="read-output";try{const n=r[e.name];a="threw";const i=E(e),c=i&&!_(n,e.initial)?P(e.initial):n,u=t(c,o,...s);if(R(u))return void x(e.name,u);Object.is(u,n)||(a="write",r[e.name]=u,I(e.name,u)),i&&O(e)}catch(t){z(e.name,t,a)}}}const re="scanEntries",ae={order:8,validate(e,t,n){const o=oe(t,n.get("eventTokenNames")??new Set,n.get("recursionRegistry")??null);n.set(re,o)},applyEarly(e,t,n){const o=n.get(re)??null;null!==o&&(function(e,t){for(const n of t)if(!(n.name in e)){const t=P(n.initial);e[n.name]=t,I(n.name,t)}}(t,o),function(e,t){for(const n of t)"event"===n.source.kind&&g(e,n.source.tokenName).subscribe(se(n))}(e,o))},register(e,t,n){const o=n.get(re)??null,s=function(e){const t=new Map,n=k(e);if(void 0!==n)for(const e of n.entries)O(e)&&t.set(e.name,e.resetOn);return j(e),t}(e);e.setScanPaths?.(null===o?null:function(e,t,n){const o=S(e,t);for(const o of t){const t=n.get(o.name);"event"===o.source.kind&&void 0!==t&&o.resetOn.some(n=>t.includes(n)&&y().hasQueuedPath(e,n))&&A(o)}const s=new Set;for(const t of o.byFromPath.keys())s.add(t),e.setPathInfo(t,"prop","scan");for(const t of o.byResetPath.keys())e.setPathInfo(t,"prop","scan");return s.size>0?s:null}(e,o,s))}};let ie=!1;const ce=Object.freeze([]),ue=Object.freeze([]);function le(e,t,n){const o=new Set([n]),s=[n];for(;s.length>0;){const n=s.pop(),r=e.staticDependency.get(n)??ce,a=e.dynamicDependency.get(n)??ce,i=t.byFromPath.get(n)??ue;for(const e of[...r,...a,...i.map(e=>e.name)])o.has(e)||(o.add(e),s.push(e))}return o}const fe=(e,t)=>t,de=new Set;const $e=new WeakMap,me=new WeakMap;function pe(e,t,n){return new Proxy(Object.create(null),{get(t,o){if("string"!=typeof o)return;const s=N(e).get(o);return void 0!==s?n(s):void 0},has:(t,n)=>"string"==typeof n&&N(e).has(n),ownKeys:()=>Array.from(N(e).keys()),getOwnPropertyDescriptor(t,o){if("string"!=typeof o)return;const s=N(e).get(o);return void 0!==s?{configurable:!0,enumerable:!0,value:n(s)}:void 0},set(){m(`${t} namespace is read-only; assigning to it is not allowed.`)},deleteProperty(){m(`${t} namespace is read-only; deleting from it is not allowed.`)}})}function he(e){const t=$e.get(e);if(void 0!==t)return t;const n=pe(e,f,e=>e.status);return $e.set(e,n),n}function ye(e){const t=me.get(e);if(void 0!==t)return t;const n=pe(e,d,e=>e.error);return me.set(e,n),n}function ge(e){$e.delete(e),me.delete(e)}let we=null;function be(e,t){let n=e;for(let e=1;e<t.length;e++){if(Object(n)!==n)return;n=Reflect.get(n,t[e])}return n}const ve={read(e,t){!function(e,t){null!==we&&we.add(b(e,t))}(e,t);const o=t.pathInfo.segments[0];return o===f?be(he(e),t.pathInfo.segments):o===d?be(ye(e),t.pathInfo.segments):n},get:(e,t)=>t===f?he(e.stateElement):t===d?ye(e.stateElement):n};async function ke(e,t,n,o){let s=null,r=null;const a=()=>{if(s&&s!==r){r=s;try{s.return?.()?.then?.(void 0,()=>{})}catch{}}};n.addEventListener("abort",a,{once:!0});try{const r=await e(t,n);if(s=function(e,t){if("function"==typeof e?.getReader)return async function*(e,t){const n=e.getReader(),o=()=>{n.cancel().catch(()=>{})};t.addEventListener("abort",o,{once:!0});try{for(;;){const{done:e,value:t}=await n.read();if(e)return;yield t}}finally{t.removeEventListener("abort",o),n.releaseLock()}}(e,t);if("function"==typeof e?.[Symbol.asyncIterator])return e;throw new TypeError("[@wcstack/state] $streams: source must return an AsyncIterable or a ReadableStream (got neither).")}(r,n)[Symbol.asyncIterator](),n.aborted)return void a();for(;;){const e=await s.next();if(e.done)break;if(n.aborted)return;o.fold(e.value)}if(n.aborted)return;o.done()}catch(e){if(n.aborted)return;o.fail(e)}finally{n.removeEventListener("abort",a)}}function Oe(e){_e();const t=N(e);if(0!==t.size){G(e);for(const n of t.values())je(e,n)}}function je(e,t){t.controller?.abort();const n=new AbortController;t.controller=n;const o=function(e,t){const n=t.definition.args;if(null===n)return void t.depAddresses.clear();const o=we,s=new Set;let i;we=s;try{e.createState("readonly",e=>{i=n(e)})}finally{we=o}i instanceof Promise&&m(`${r} entry "${t.name}" args must be synchronous (it returned a Promise).`);const c=`${f}${a}${t.name}`,u=`${d}${a}${t.name}`;for(const n of s){const o=n.absolutePathInfo.pathInfo;n.absolutePathInfo.stateElement!==e||o.path!==t.name&&o.path!==c&&o.path!==u||m(`${r} entry "${t.name}" args must not read the stream itself ("${o.path}"): a self-dependency would restart the stream on its own writes (infinite loop).`),o.wildcardCount>0&&m(`${r} entry "${t.name}" args must not read wildcard paths ("${o.path}"): wildcard dependencies are out of scope.`)}return t.depAddresses=s,i}(e,t);!function(e,t){const n=k(e);if(void 0!==n&&0!==t.depAddresses.size)for(const o of n.entries){if("path"!==o.source.kind||o.source.pathInfo.segments[0]!==t.name)continue;const a=le(e,n,o.name);for(const e of t.depAddresses){const n=e.absolutePathInfo.pathInfo.path;a.has(n)&&m(`[wcs/scan-feedback-loop] ${r} entry "${t.name}" args read "${n}", which is derived from the ${s} output "${o.name}" that this stream feeds. Every landing would restart the stream on its own result. Advance the cursor from an event ($on) and keep it a plain property instead of deriving it from the accumulator.`)}}}(e,t),e.createState("writable",e=>{e[t.name]=t.definition.initial}),Se(e,t,"active",null);const i=t.definition,c={fold(n){e.createState("writable",e=>{e[t.name]=i.fold(e[t.name],n)})},done(){Se(e,t,"done",null)},fail(o){Se(e,t,"error",o),n.abort()}};ke(i.source,o,n.signal,c)}function Se(e,t,n,o){t.status=n,t.error=o;const s=q(e,t.name),r=s.status!==n,i=!Object.is(s.error,o);(r||i)&&(U(e,t.name,n,o),e.createState("writable",e=>{r&&e.$postUpdate(`${f}${a}${t.name}`),i&&e.$postUpdate(`${d}${a}${t.name}`)}))}function Ae(e){const t=T();if(0===t.size)return;const n=[];for(const o of t)for(const t of N(o).values())for(const s of t.depAddresses)if(e.has(s)){n.push({stateElement:o,entry:t});break}for(const{stateElement:e,entry:o}of n)if(t.has(e)&&N(e).get(o.name)===o)try{je(e,o)}catch(n){o.controller?.abort(),t.has(e)&&N(e).get(o.name)===o&&Se(e,o,"error",n)}}let Pe=!1;const Ie=new WeakMap,Ee={order:20,apply(e,t){ge(e),F(e),function(e,t){const n=t[r];if(void 0===n)return void D(e,de);"object"==typeof n&&null!==n||m(`${r} must be an object mapping stream names to stream definitions.`);const o=new Map;for(const[s,c]of Object.entries(n)){0===s.length&&m(`${r} entry name must be a non-empty string.`),s.includes(a)&&m(`${r} entry "${s}" must be a flat property name ("${a}" is not allowed).`),s.includes(i)&&m(`${r} entry "${s}" must be a flat property name ("${i}" is not allowed).`),s.startsWith("$")&&m(`${r} entry "${s}" must not start with "$" (reserved namespace).`),s in Object.prototype&&m(`${r} entry "${s}" must not be a property name inherited from Object.prototype (e.g. "__proto__", "constructor").`),e.getterPaths.has(s)&&m(`${r} entry "${s}" conflicts with a getter declared on the state.`),e.setterPaths.has(s)&&m(`${r} entry "${s}" conflicts with a setter declared on the state.`),"object"==typeof c&&null!==c||m(`${r} entry "${s}" must be an object ({ args?, source, fold?, initial? }).`);const n=c;"function"!=typeof n.source&&m(`${r} entry "${s}" source must be a function.`);const u=void 0!==n.fold;u&&"function"!=typeof n.fold&&m(`${r} entry "${s}" fold must be a function.`),u&&!("initial"in n)&&m(`${r} entry "${s}" requires "initial" when fold is specified (reduce needs a seed value).`),void 0!==n.args&&"function"!=typeof n.args&&m(`${r} entry "${s}" args must be a function.`);const l={name:s,definition:{args:n.args??null,source:n.source,fold:n.fold??fe,initial:n.initial},status:"idle",error:null,controller:null,depAddresses:new Set};s in t||(t[s]=l.definition.initial),o.set(s,l)}L(e,o),D(e,new Set(o.keys()))}(e,t),void 0!==t[r]&&e.attachAddressHooks?.("streams",r)},activate(e,t){if(!K()&&null!=e.connectedRootNode){if(null===t){if(!0!==e.initialized)return;return Oe(e),void Ie.set(e,e.connectGeneration??0)}t===e.connectGeneration&&Ie.get(e)!==t&&Oe(e)}},deactivate(e){C(e),ge(e)}};function _e(){Pe||(Pe=!0,o("streams",ve),t("streams",Ee),v(Ae,$))}const Re={name:"temporal",install(){H(),ie||(ie=!0,t("scan",ae),w(M)),_e()}};export{Re as default,Re as temporal};
2
+ //# sourceMappingURL=temporal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.js","sources":["../../../../../src/scan/processScanDeclaration.ts","../../../../../src/scan/declarations.ts","../../../../../src/scan/scanFeedback.ts","../../../../../src/stream/processStreamsDeclaration.ts","../../../../../src/stream/streamNamespace.ts","../../../../../src/stream/argsTrace.ts","../../../../../src/stream/addressHooks.ts","../../../../../src/stream/consumeSource.ts","../../../../../src/stream/streamRuntime.ts","../../../../../src/features/temporal.ts"],"sourcesContent":["/**\n * scan/processScanDeclaration.ts\n *\n * `$scan: { <output>: { from | on, initial, fold, resetOn? } }` の解析と配線\n * (docs/state-scan-design.md §1-2 / §2-4)。\n *\n * `_state` セッター上の位置が違う 3 段に分ける:\n * 1. `parseScanDeclaration` — `value` だけを読む検査。世代を進める**前**に走るので、\n * ここで throw した再セットは要素を丸ごと旧世代に残す。\n * 2. `materializeScanOutputs` / `subscribeScanEvents` — `clearEventTokenRegistry` の直後。\n * 実体化を `_rebuildPathInfo` より前に置くのは、前世代の `from`(別 scan の出力の子)を\n * 張り直すときに存在検査が偽の miss を出さないため。`on` の購読を `$on` より前に置くのは、\n * 同じトークンで reducer → effect の順にするため(D11)。\n * 3. `registerScans` — `processWatchDeclaration` の直前(`_pathSet` クリア後)。\n */\n\nimport { getPathInfo } from \"../address/PathInfo\";\nimport type { IPathInfo } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { DELIMITER, MAX_WILDCARD_DEPTH, STATE_EVENT_TOKENS_NAME, STATE_SCAN_NAME, STATE_STREAMS_NAME, WILDCARD } from \"../define\";\nimport { didYouMean, LINT_HINT } from \"../errorGuidance\";\nimport { getOrCreateEventToken } from \"../event/eventTokenRegistry\";\nimport { getAllPropertyDescriptors } from \"../getAllPropertyDescriptors\";\nimport type { IStateProxy } from \"../proxy/types\";\nimport { raiseError } from \"../raiseError\";\nimport type { TokenSubscriber } from \"../token/Token\";\nimport type { IState } from \"../types\";\nimport { getUpdater } from \"../updater/updater\";\nimport { consumePendingScanReset, hasPendingScanReset, markPendingScanReset } from \"./eventReset\";\nimport { cloneInitial, isSameAsInitial, recordOutputValue, wasPlacedOnOutput } from \"./initialValue\";\nimport { isThenable, reportScanError, reportScanThenable, type ScanFailure } from \"./scanReport\";\nimport { clearScanRegistry, getScanRegistry, setScanRegistry } from \"./scanRegistry\";\nimport type { IScanEntry, ScanFold, ScanSource } from \"./types\";\n\nconst INVALID = \"[wcs/scan-declaration-invalid]\";\nconst COMPUTED = \"[wcs/scan-source-computed]\";\nconst NO_RESET: readonly string[] = Object.freeze([]);\n\n/**\n * `$recursion` の `**` getter の展開形を引く口(recursion/registry.ts の RecursionRegistry)。\n * `_state` セッターは `$scan` の検査より前に新しい宣言のレジストリを作るので、それを受け取る。\n */\nexport interface IRecursiveGetterLookup {\n recursiveGetterOwning(concretePath: string): string | null;\n}\n\nfunction entryLabel(name: string): string {\n return `${STATE_SCAN_NAME} entry \"${name}\"`;\n}\n\n/** 累積パス(`a` / `a.b` / `a.b.c`)のうち最初に getter であるものを返す */\nfunction findGetterOnPath(pathInfo: IPathInfo, getterPaths: ReadonlySet<string>): string | null {\n for (const path of pathInfo.cumulativePaths) {\n if (getterPaths.has(path)) {\n return path;\n }\n }\n return null;\n}\n\nfunction computedMessage(label: string, field: string, path: string, getter: string): string {\n const where = getter === path\n ? \"is a getter\"\n : getter.includes(`${WILDCARD}${WILDCARD}`)\n ? `is computed by the recursive getter \"${getter}\"`\n : `is under the getter \"${getter}\"`;\n return `${COMPUTED} ${label} ${field} \"${path}\" ${where}. A getter re-evaluates whenever its inputs change, ` +\n `so folding it would count re-evaluations, not events. Fold the plain value the getter reads, or use \"on\" with an event token.${LINT_HINT}`;\n}\n\nfunction writeOnlyMessage(label: string, path: string, setter: string): string {\n const where = setter === path ? \"is a setter without a getter\" : `is under the setter without a getter \"${setter}\"`;\n return `${INVALID} ${label} from \"${path}\" ${where}, so it always reads undefined and every fold would receive undefined. ` +\n `Fold the plain value the setter writes, or use \"on\" with an event token.${LINT_HINT}`;\n}\n\nfunction assertValidScanPath(label: string, field: string, path: string): IPathInfo {\n if (path.length === 0) {\n raiseError(`${INVALID} ${label} \"${field}\" must be a non-empty state path.${LINT_HINT}`);\n }\n if (path.startsWith(\"$\")) {\n raiseError(`${INVALID} ${label} ${field} \"${path}\" must not start with \"$\" (reserved namespace).${LINT_HINT}`);\n }\n if (path.includes(\"@\")) {\n raiseError(`${INVALID} ${label} ${field} \"${path}\" must not contain \"@\" — there is a single state tree per root.${LINT_HINT}`);\n }\n if (path in Object.prototype) {\n raiseError(`${INVALID} ${label} ${field} \"${path}\" must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").${LINT_HINT}`);\n }\n const pathInfo = getPathInfo(path);\n for (const segment of pathInfo.segments) {\n if (segment.length === 0) {\n raiseError(`${INVALID} ${label} ${field} \"${path}\" has an empty path segment.${LINT_HINT}`);\n }\n }\n if (pathInfo.wildcardCount > MAX_WILDCARD_DEPTH) {\n raiseError(`${INVALID} ${label} ${field} \"${path}\" exceeds the maximum wildcard depth (${MAX_WILDCARD_DEPTH}).`);\n }\n return pathInfo;\n}\n\nfunction collectStreamNames(state: IState): ReadonlySet<string> {\n const streams = (state as Record<string, unknown>)[STATE_STREAMS_NAME];\n if (typeof streams !== \"object\" || streams === null) {\n return new Set<string>();\n }\n return new Set(Object.keys(streams));\n}\n\nfunction assertOutputName(\n name: string,\n getterPaths: ReadonlySet<string>,\n setterPaths: ReadonlySet<string>,\n streamNames: ReadonlySet<string>,\n): void {\n const label = entryLabel(name);\n if (name.length === 0) {\n raiseError(`${INVALID} ${STATE_SCAN_NAME} entry name must be a non-empty string.${LINT_HINT}`);\n }\n if (name.includes(DELIMITER) || name.includes(WILDCARD)) {\n raiseError(`${INVALID} ${label} must be a flat property name (\"${DELIMITER}\" and \"${WILDCARD}\" are not allowed). The output is a property the runtime owns.${LINT_HINT}`);\n }\n if (name.startsWith(\"$\")) {\n raiseError(`${INVALID} ${label} must not start with \"$\" (reserved namespace).${LINT_HINT}`);\n }\n if (name in Object.prototype) {\n raiseError(`${INVALID} ${label} must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").${LINT_HINT}`);\n }\n if (getterPaths.has(name)) {\n raiseError(`${INVALID} ${label} conflicts with a getter declared on the state.${LINT_HINT}`);\n }\n if (setterPaths.has(name)) {\n raiseError(`${INVALID} ${label} conflicts with a setter declared on the state.${LINT_HINT}`);\n }\n if (streamNames.has(name)) {\n raiseError(`${INVALID} ${label} conflicts with the ${STATE_STREAMS_NAME} entry of the same name — each output has exactly one owner.${LINT_HINT}`);\n }\n}\n\n/**\n * 出力名がメソッド(関数値のプロパティ)と衝突していないか(D7)。\n *\n * 実体化は既にある値を保持するので、衝突を通すと最初の `acc` がメソッドになり、fold の結果が\n * メソッドを上書きする。`initial` 自身が関数で、その値が置かれている形だけは通す —\n * 同じオブジェクトの再セットで、実体化済みの出力を見ているだけだから。\n */\nfunction assertNoMethodConflict(\n name: string,\n functionValues: ReadonlyMap<string, unknown>,\n definition: Record<string, unknown>,\n): void {\n const value = functionValues.get(name);\n // fold・実体化・reset がこの出力に置いたことのある関数値なら、それは累積(同じオブジェクト・値のコピーの\n // 再セット・D7)。どの世代のオブジェクトに書かれたかに依らない。名前だけで通すと、新しいオブジェクトの\n // 同名の本物のメソッドを見逃す(§5-9 の C5-8 / C5-14)\n if (functionValues.has(name) && value !== definition.initial && !wasPlacedOnOutput(name, value)) {\n raiseError(`${INVALID} ${entryLabel(name)} conflicts with a method (a function-valued property) declared on the state. The output is a property the runtime owns.${LINT_HINT}`);\n }\n}\n\nfunction parseSource(\n name: string,\n definition: Record<string, unknown>,\n eventTokenNames: ReadonlySet<string>,\n getterPaths: ReadonlySet<string>,\n writeOnlyPaths: ReadonlySet<string>,\n recursion: IRecursiveGetterLookup | null,\n): ScanSource {\n const label = entryLabel(name);\n const hasFrom = typeof definition.from !== \"undefined\";\n const hasOn = typeof definition.on !== \"undefined\";\n if (hasFrom === hasOn) {\n raiseError(`${INVALID} ${label} must declare exactly one of \"from\" (a state path) or \"on\" (an event-token name).${LINT_HINT}`);\n }\n if (hasOn) {\n const tokenName = definition.on;\n if (typeof tokenName !== \"string\" || tokenName.length === 0) {\n raiseError(`${INVALID} ${label} \"on\" must be a non-empty event-token name.${LINT_HINT}`);\n }\n if (!eventTokenNames.has(tokenName)) {\n raiseError(`${INVALID} ${label} on \"${tokenName}\" is not declared in ${STATE_EVENT_TOKENS_NAME}.${didYouMean(tokenName, eventTokenNames)}${LINT_HINT}`);\n }\n return { kind: \"event\", tokenName };\n }\n const path = definition.from;\n if (typeof path !== \"string\") {\n raiseError(`${INVALID} ${label} \"from\" must be a state path string.${LINT_HINT}`);\n }\n const pathInfo = assertValidScanPath(label, \"from\", path);\n // `**` getter の展開形(`nodes.*.total`)とその値の内側も getter。字面の getterPaths には `**` の形しか\n // 載らないので、再帰レジストリで引く(pathDiagnostics の checkDeclaredPath と同じ判定)。\n // 展開形は必ず `*` を含むので `resetOn` はワイルドカードの検査で先に落ちる\n const getter = findGetterOnPath(pathInfo, getterPaths) ?? recursion?.recursiveGetterOwning(path) ?? null;\n if (getter !== null) {\n raiseError(computedMessage(label, \"from\", path, getter));\n }\n // getter の無い setter は読むと常に undefined(`resetOn` は値を読まない引き金なので通す)\n const setter = findGetterOnPath(pathInfo, writeOnlyPaths);\n if (setter !== null) {\n raiseError(writeOnlyMessage(label, path, setter));\n }\n if (path === name || path.startsWith(name + DELIMITER)) {\n raiseError(`${INVALID} ${label} from \"${path}\" reads the entry's own output — the scan would fold its own writes forever.${LINT_HINT}`);\n }\n return { kind: \"path\", path, pathInfo };\n}\n\nfunction parseResetOn(\n name: string,\n raw: unknown,\n source: ScanSource,\n getterPaths: ReadonlySet<string>,\n): readonly string[] {\n if (typeof raw === \"undefined\") {\n return NO_RESET;\n }\n const label = entryLabel(name);\n if (!Array.isArray(raw)) {\n raiseError(`${INVALID} ${label} \"resetOn\" must be an array of state paths.${LINT_HINT}`);\n }\n const paths: string[] = [];\n for (const item of raw) {\n if (typeof item !== \"string\") {\n raiseError(`${INVALID} ${label} \"resetOn\" must contain only state path strings.${LINT_HINT}`);\n }\n const pathInfo = assertValidScanPath(label, \"resetOn\", item);\n if (pathInfo.wildcardCount > 0) {\n raiseError(`${INVALID} ${label} resetOn \"${item}\" must not contain \"${WILDCARD}\" — a reset returns the whole output to \"initial\".${LINT_HINT}`);\n }\n const getter = findGetterOnPath(pathInfo, getterPaths);\n if (getter !== null) {\n raiseError(computedMessage(label, \"resetOn\", item, getter));\n }\n if (source.kind === \"path\" && item === source.path) {\n raiseError(`${INVALID} ${label} resetOn \"${item}\" is the entry's own \"from\" — every change would reset instead of fold.${LINT_HINT}`);\n }\n // 子孫は死に設定: `from` を書くと依存展開で子孫も同じバッチに載り、reset が毎回勝つ。\n // 祖先(`from: \"items.*.qty\"` × `resetOn: [\"items\"]`)は「親の差し替えで作り直す」として通す\n if (source.kind === \"path\" && item.startsWith(source.path + DELIMITER)) {\n raiseError(`${INVALID} ${label} resetOn \"${item}\" sits under the entry's own \"from\" \"${source.path}\" — every write of \"from\" also lands it, so the reset would win every time and nothing would fold.${LINT_HINT}`);\n }\n paths.push(item);\n }\n return paths;\n}\n\n/**\n * scan 出力を介した参照の検査(エントリを跨ぐもの):\n * - `resetOn` が scan 出力(自他とも)を読む = 累積が累積を消すフィードバック。\n * - `from` の根を辿って scan 同士が循環する = 互いの書き込みで永久に畳み合う。\n * 各 scan の `from` は 1 本なので、辿る先は高々 1 つ(関数グラフ)。\n */\nfunction assertNoOutputReferences(entries: readonly IScanEntry[]): void {\n const outputs = new Set(entries.map((entry) => entry.name));\n const next = new Map<string, string>();\n for (const entry of entries) {\n for (const path of entry.resetOn) {\n const root = getPathInfo(path).segments[0];\n if (outputs.has(root)) {\n raiseError(`${INVALID} ${entryLabel(entry.name)} resetOn \"${path}\" reads the ${STATE_SCAN_NAME} output \"${root}\" — a reset driven by an accumulator is a feedback loop. Reset on the plain inputs instead.${LINT_HINT}`);\n }\n }\n if (entry.source.kind === \"path\") {\n const root = entry.source.pathInfo.segments[0];\n if (outputs.has(root)) {\n next.set(entry.name, root);\n }\n }\n }\n for (const start of next.keys()) {\n const chain = [start];\n let current = next.get(start);\n while (typeof current !== \"undefined\" && chain.length <= outputs.size) {\n if (current === start) {\n raiseError(`${INVALID} ${STATE_SCAN_NAME} entries ${[...chain, start].map((n) => `\"${n}\"`).join(\" → \")} feed each other through \"from\" — each fold would re-trigger the next forever.${LINT_HINT}`);\n }\n chain.push(current);\n current = next.get(current);\n }\n }\n}\n\n/**\n * `$scan` 宣言の検査(`value` だけを読む)。宣言が無い・空なら null。\n *\n * getter / setter の判定は `value` の property descriptor から直接取る(`_getterPaths` は\n * この時点ではまだ旧世代のもの)。`$streams` 名との衝突も `value` の宣言から見る。\n * `recursion` は `value` から作った `$recursion` のレジストリ(宣言が無ければ null)。\n */\nexport function parseScanDeclaration(\n state: IState,\n eventTokenNames: ReadonlySet<string>,\n recursion: IRecursiveGetterLookup | null = null,\n): readonly IScanEntry[] | null {\n const declared = (state as Record<string, unknown>)[STATE_SCAN_NAME];\n if (typeof declared === \"undefined\") {\n return null;\n }\n if (typeof declared !== \"object\" || declared === null || Array.isArray(declared)) {\n raiseError(`${INVALID} ${STATE_SCAN_NAME} must be an object mapping output names to scan definitions ({ from | on, initial, fold, resetOn? }).${LINT_HINT}`);\n }\n const getterPaths = new Set<string>();\n const setterPaths = new Set<string>();\n const writeOnlyPaths = new Set<string>();\n const functionValues = new Map<string, unknown>();\n for (const [key, descriptor] of Object.entries(getAllPropertyDescriptors(state))) {\n if (typeof descriptor.get === \"function\") {\n getterPaths.add(key);\n } else if (typeof descriptor.set === \"function\") {\n writeOnlyPaths.add(key);\n }\n if (typeof descriptor.set === \"function\") {\n setterPaths.add(key);\n }\n if (typeof descriptor.value === \"function\") {\n functionValues.set(key, descriptor.value);\n }\n }\n const streamNames = collectStreamNames(state);\n const entries: IScanEntry[] = [];\n let order = 0;\n for (const [name, def] of Object.entries(declared as Record<string, unknown>)) {\n assertOutputName(name, getterPaths, setterPaths, streamNames);\n // 配列もオブジェクトとして読まない(`$scan` 自体の検査と同じ。静的検証も同じ文言で拾う)\n if (typeof def !== \"object\" || def === null || Array.isArray(def)) {\n raiseError(`${INVALID} ${entryLabel(name)} must be an object ({ from | on, initial, fold, resetOn? }).${LINT_HINT}`);\n }\n const definition = def as Record<string, unknown>;\n assertNoMethodConflict(name, functionValues, definition);\n const source = parseSource(name, definition, eventTokenNames, getterPaths, writeOnlyPaths, recursion);\n if (!(\"initial\" in definition)) {\n raiseError(`${INVALID} ${entryLabel(name)} requires \"initial\" — the seed of the accumulator and the value \"resetOn\" returns to.${LINT_HINT}`);\n }\n if (typeof definition.fold !== \"function\") {\n raiseError(`${INVALID} ${entryLabel(name)} fold must be a function.${LINT_HINT}`);\n }\n const resetOn = parseResetOn(name, definition.resetOn, source, getterPaths);\n entries.push({\n name,\n source,\n fold: definition.fold as ScanFold,\n initial: definition.initial,\n resetOn,\n order: order++,\n });\n }\n assertNoOutputReferences(entries);\n return entries.length > 0 ? entries : null;\n}\n\n/**\n * 出力の実体化(設計書 D7)。未定義なら `initial` を置き、既に値があれば保持する\n * (同じオブジェクトの再セット・SSR ハイドレーションで累積を失わない)。plain な配列とオブジェクトは\n * 複製して置く — 出力が `initial` の間に子パスへ書いても宣言の `initial` を書き換えない(scan/initialValue.ts)。\n */\nexport function materializeScanOutputs(state: IState, entries: readonly IScanEntry[]): void {\n for (const entry of entries) {\n if (!(entry.name in state)) {\n const value = cloneInitial(entry.initial);\n (state as Record<string, unknown>)[entry.name] = value;\n recordOutputValue(entry.name, value);\n }\n }\n}\n\nfunction createEventFold(entry: IScanEntry): TokenSubscriber {\n const fold = entry.fold;\n return (state: unknown, event: unknown, ...indexes: unknown[]): void => {\n const proxy = state as IStateProxy;\n // 報告を「出力を読めなかった」「fold が throw した」「出力を書けなかった」で分ける\n let failure: ScanFailure = \"read-output\";\n try {\n const current = proxy[entry.name];\n failure = \"threw\";\n // `resetOn` の書き込みより後の出来事は、reset 後の出力に畳む(scan/eventReset.ts)\n const reset = hasPendingScanReset(entry);\n // reset 後の出力から畳む。出力が既に initial と同じ値ならそのまま、違えば複製から(宣言の initial は渡さない)\n const acc = reset && !isSameAsInitial(current, entry.initial) ? cloneInitial(entry.initial) : current;\n const next = fold(acc, event, ...indexes);\n if (isThenable(next)) {\n // 保留は残す — drain が出力を initial に戻す\n reportScanThenable(entry.name, next);\n return;\n }\n if (!Object.is(next, current)) {\n failure = \"write\";\n proxy[entry.name] = next;\n recordOutputValue(entry.name, next);\n }\n // 保留は書き込みが通ってから消す。書き込みが throw したら残し、drain が initial に戻す(§2-2)\n if (reset) {\n consumePendingScanReset(entry);\n }\n } catch (error) {\n // 後続の subscriber(同じトークンの `$on`)を巻き添えにしない\n reportScanError(entry.name, error, failure);\n }\n };\n}\n\n/**\n * `on` の scan を event-token の subscriber として登録する(設計書 §2-2)。\n * 購読の寿命は `$on` と同じ(`_state` の再セットで `clearEventTokenRegistry` の後に張り直す。\n * 切断では消えないので、ルート `<wcs-state>` の再接続の後も畳み続ける — Issue #273)。\n */\nexport function subscribeScanEvents(stateElement: IStateElement, entries: readonly IScanEntry[]): void {\n for (const entry of entries) {\n if (entry.source.kind === \"event\") {\n getOrCreateEventToken(stateElement, entry.source.tokenName).subscribe(createEventFold(entry));\n }\n }\n}\n\n/** 再セットで引き継ぐ `on` scan の保留 reset(出力名 → 旧宣言の `resetOn`) */\nexport type ScanResetCarry = ReadonlyMap<string, readonly string[]>;\n\n/**\n * registry を外す(`_state` 再セットで作り直す前)。旧宣言の `on` scan に立っていた保留 reset は、\n * 新しい宣言の entry(別のオブジェクト)へ引き継ぐ候補として返し、旧 entry からは消す\n * (残すと誰にも使われず、保留の数 — scan/eventReset.ts の捨てる走査のゲート — だけが戻らない)。\n */\nexport function unregisterScans(stateElement: IStateElement): ScanResetCarry {\n const carry = new Map<string, readonly string[]>();\n const registry = getScanRegistry(stateElement);\n if (typeof registry !== \"undefined\") {\n for (const entry of registry.entries) {\n if (consumePendingScanReset(entry)) {\n carry.set(entry.name, entry.resetOn);\n }\n }\n }\n clearScanRegistry(stateElement);\n return carry;\n}\n\n/**\n * registry を作り、`from` / `resetOn` を依存グラフへ登録する。`from` パスの集合\n * (旧値キャプチャのゲート)を返す。無ければ null。\n *\n * 依存グラフ登録が要る理由は `$watch` と同じ(docs/state-watch-hook-design.md §8):\n * `setPathInfo` はバインドからしか呼ばれないので、宣言しただけでは祖先への書き込みが\n * このパスへ展開されず、バッチに載らない。\n *\n * `carry`(unregisterScans の戻り値)の保留 reset は、同じ出力名の `on` scan が、まだ drain されていない\n * 書き込み(updater のキューに積まれているパス)を新旧どちらの `resetOn` にも持つときだけ引き継ぐ(D6)。\n * 旧宣言の保留は発火対象の state への書き込みでしか立たないので、「enqueue の時点で立つ」契約は保たれる。\n * 引き継がないと、書き込みより後のイベントが reset されていない出力に畳まれ、drain でも戻らない\n * (同じバッチの `from` の scan は reset される)。\n */\nexport function registerScans(\n stateElement: IStateElement,\n entries: readonly IScanEntry[],\n carry: ScanResetCarry,\n): ReadonlySet<string> | null {\n const registry = setScanRegistry(stateElement, entries);\n for (const entry of entries) {\n const carried = carry.get(entry.name);\n if (entry.source.kind !== \"event\" || typeof carried === \"undefined\") {\n continue;\n }\n if (entry.resetOn.some((path) => carried.includes(path) && getUpdater().hasQueuedPath(stateElement, path))) {\n markPendingScanReset(entry);\n }\n }\n const fromPaths = new Set<string>();\n for (const path of registry.byFromPath.keys()) {\n fromPaths.add(path);\n stateElement.setPathInfo(path, \"prop\", \"scan\");\n }\n for (const path of registry.byResetPath.keys()) {\n stateElement.setPathInfo(path, \"prop\", \"scan\");\n }\n return fromPaths.size > 0 ? fromPaths : null;\n}\n","/**\n * scan/declarations.ts — `$scan` の宣言(設計案 H4、S4)。\n *\n * `$scan` は「世代を進める**前**に検証し、他の宣言が作った値を要る」唯一の宣言で、受け口の\n * 文脈袋(`IDeclarationContext`)を要求した当の機能。core が publish した `$eventTokens` の\n * 名前と再帰レジストリを検証で読み、解析したエントリを袋に入れて次の段へ渡す。\n *\n * 段の位置は docs/state-scan-design.md の順序契約そのまま:\n * validate `value` と宣言済みトークン名しか読まない(§1-2)\n * applyEarly 出力の実体化は `_rebuildPathInfo` より前、`on` の購読は `$on` より前\n * (同じトークンでは reducer → effect の順、D11)\n * register registry と from / resetOn の依存グラフ登録(`_pathSet` クリア後であること)。\n * watch(order 10)より先に走る — scan だけを宣言した state も drain の発火対象に載せる\n */\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { IRecursiveGetterLookup, materializeScanOutputs, parseScanDeclaration, registerScans, subscribeScanEvents, unregisterScans } from \"./processScanDeclaration\";\nimport type { IScanEntry } from \"./types\";\nimport { registerEnqueueListener } from \"../updater/updater\";\nimport { noteEnqueueForScanReset } from \"./eventReset\";\n\nconst SCAN_ENTRIES = \"scanEntries\";\n\nexport const scanDeclarationHooks: IDeclarationHooks = {\n // watch(10)・streams(20)より先。register の並び(scan → watch)もこれで決まる\n order: 8,\n validate(_element, value, ctx) {\n // `**` getter の展開形を from に書いた形を落とすため、`value` から作った再帰レジストリも渡す(D5)。\n // fold が関数を返す出力は、その出力に置いた関数値をメソッド衝突と見なさない(scan/initialValue.ts の記録・D7)。\n const entries = parseScanDeclaration(\n value,\n ctx.get<ReadonlySet<string>>(\"eventTokenNames\") ?? new Set<string>(),\n ctx.get<IRecursiveGetterLookup | null>(\"recursionRegistry\") ?? null,\n );\n ctx.set(SCAN_ENTRIES, entries);\n },\n applyEarly(element, value, ctx) {\n const entries = ctx.get<readonly IScanEntry[] | null>(SCAN_ENTRIES) ?? null;\n if (entries !== null) {\n materializeScanOutputs(value, entries);\n subscribeScanEvents(element, entries);\n }\n },\n register(element, _value, ctx) {\n const entries = ctx.get<readonly IScanEntry[] | null>(SCAN_ENTRIES) ?? null;\n const carried = unregisterScans(element);\n element.setScanPaths?.(entries === null ? null : registerScans(element, entries, carried));\n },\n};\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installScanDeclarations(): void {\n if (installed) return;\n installed = true;\n registerDeclarationHooks(\"scan\", scanDeclarationHooks);\n // `on` scan の `resetOn` を書き込みの時点で保留する(eventReset.ts)。該当する宣言が無ければ整数比較 1 回\n registerEnqueueListener(noteEnqueueForScanReset);\n}\n","/**\n * scan/scanFeedback.ts\n *\n * 自己ループの柵(docs/state-scan-design.md D9 / §2-3)。\n *\n * `from` の根が `$streams` 名である scan について、その stream の `args` 依存に\n * scan 出力から到達できるパスが含まれていたら raise する。\n *\n * $scan.feed { from: \"pageResult\" }\n * get page() { return Math.floor(this.feed.items.length / this.pageSize) + 1; }\n * $streams.pageResult { args: (s) => ({ page: s.page }) }\n *\n * は、ページが着地するたびに `feed` → `page` → restart と進み、sentinel を経由せずに\n * 全ページを読み続ける(冪等キーが無ければ同じページを無限に取り直す)。\n *\n * 辿る辺は書き込みが届く先そのもの:\n * - `staticDependency`(親 → 子)と `dynamicDependency`(読まれたパス → それを読む getter)。\n * 書き込みの伝播(`walkDependency`)と同じグラフ。\n * - 到達したパスを `from` に持つ別の scan の出力。依存グラフには載らない辺だが、その scan が\n * 次のバッチで畳んで書くので、`feed` → `feed2`(`from: \"feed\"`)→ `page` の連鎖も同じループになる。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport { STATE_SCAN_NAME, STATE_STREAMS_NAME } from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport type { IStreamEntry } from \"../stream/types\";\nimport { getScanRegistry } from \"./scanRegistry\";\nimport type { IScanEntry, IScanRegistry } from \"./types\";\n\nconst NO_EDGES: readonly string[] = Object.freeze([]);\nconst NO_SCANS: readonly IScanEntry[] = Object.freeze([]);\n\nfunction collectReachablePaths(stateElement: IStateElement, registry: IScanRegistry, start: string): ReadonlySet<string> {\n const reachable = new Set<string>([start]);\n const queue = [start];\n while (queue.length > 0) {\n const path = queue.pop() as string;\n const children = stateElement.staticDependency.get(path) ?? NO_EDGES;\n const dependents = stateElement.dynamicDependency.get(path) ?? NO_EDGES;\n const downstream = registry.byFromPath.get(path) ?? NO_SCANS;\n for (const next of [...children, ...dependents, ...downstream.map((scan) => scan.name)]) {\n if (!reachable.has(next)) {\n reachable.add(next);\n queue.push(next);\n }\n }\n }\n return reachable;\n}\n\n/** stream の起動・restart(`traceArgs` の直後)で呼ぶ。 */\nexport function assertNoScanFeedback(stateElement: IStateElement, streamEntry: IStreamEntry): void {\n const registry = getScanRegistry(stateElement);\n if (typeof registry === \"undefined\" || streamEntry.depAddresses.size === 0) {\n return;\n }\n for (const scan of registry.entries) {\n if (scan.source.kind !== \"path\" || scan.source.pathInfo.segments[0] !== streamEntry.name) {\n continue;\n }\n const reachable = collectReachablePaths(stateElement, registry, scan.name);\n for (const dep of streamEntry.depAddresses) {\n const depPath = dep.absolutePathInfo.pathInfo.path;\n if (reachable.has(depPath)) {\n raiseError(\n `[wcs/scan-feedback-loop] ${STATE_STREAMS_NAME} entry \"${streamEntry.name}\" args read \"${depPath}\", ` +\n `which is derived from the ${STATE_SCAN_NAME} output \"${scan.name}\" that this stream feeds. ` +\n `Every landing would restart the stream on its own result. Advance the cursor from an event ($on) ` +\n `and keep it a plain property instead of deriving it from the accumulator.`,\n );\n }\n }\n }\n}\n","/**\n * stream/processStreamsDeclaration.ts\n *\n * `$streams: { <name>: { args?, source, fold?, initial? } }` 宣言マップを解析し、\n * IStreamEntry を構築して streamRegistry に一括登録する\n * (docs/state-streams-design.md §1-1 / §1-2 / §1-3)。\n *\n * - バリデーション(§1-2): 違反は raiseError。\n * - 名前はフラットなプロパティ名のみ(空文字 / `.`(DELIMITER)/ `*`(WILDCARD)/ 先頭 `$` を禁止)。\n * - Object.prototype の継承名(`__proto__` / `constructor` / `toString` 等)を禁止\n * (own key でなくても `in` 判定が真になり、実体化 skip + 起動時 Reflect.set の\n * 継承 setter 化 — `__proto__` は prototype 差し替え — を引き起こすため)。\n * - getter / setter として宣言済みのパスとの衝突を禁止(getterPaths / setterPaths を検査)。\n * - `source` は関数必須。`fold` は(あれば)関数。`fold` があるのに `initial` が無ければエラー\n * (reduce は initial 必須。`initial` の有無は in 演算子で判定)。`args` は(あれば)関数。\n * - fold 省略時は latest(`(_acc, chunk) => chunk`)を注入する(§0 決定レコード)。\n * - 値プロパティ実体化(§1-3): `state[name]` が未定義なら `initial`\n * (fold 無しなら undefined)でデータプロパティとして初期化する。\n * ユーザーが同名プロパティを先に宣言していた場合は上書きしない\n * (起動時の initial リセットは streamRuntime 側の責務)。\n * - 通知 dedup 台帳の prune(§4-3): 新宣言に存在しない名前の lastNotified エントリを\n * 削除する(台帳は stateElement 寿命 — 再 set 跨ぎ dedup が必要なのは同名のみ)。\n *\n * 呼び出しは stateElement.getterPaths / setterPaths の確定後であること\n * (State の `_state` セッターが getStateInfo の反映より後に呼ぶことで保証する)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport { DELIMITER, STATE_STREAMS_NAME, WILDCARD } from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport type { IState } from \"../types\";\nimport { pruneLastNotified } from \"./lastNotified\";\nimport { setStreamEntries } from \"./streamRegistry\";\nimport type { IStreamDefinition, IStreamEntry, StreamFold, StreamSource } from \"./types\";\n\n/** fold 省略時に注入される既定 fold(latest = 最新チャンクで置換) */\nconst latestFold: StreamFold = (_acc, chunk) => chunk;\n\n/** `$streams` 無し宣言の prune 用(旧宣言の全名前が残骸になる) */\nconst NO_STREAM_NAMES: ReadonlySet<string> = new Set<string>();\n\nexport function processStreamsDeclaration(stateElement: IStateElement, state: IState): void {\n const declared = (state as Record<string, unknown>)[STATE_STREAMS_NAME];\n if (typeof declared === \"undefined\") {\n // $streams 無しの再 set でも旧宣言の名前は通知 dedup 台帳の残骸になるため prune する\n pruneLastNotified(stateElement, NO_STREAM_NAMES);\n return;\n }\n if (typeof declared !== \"object\" || declared === null) {\n raiseError(`${STATE_STREAMS_NAME} must be an object mapping stream names to stream definitions.`);\n }\n const entries = new Map<string, IStreamEntry>();\n for (const [name, def] of Object.entries(declared as Record<string, unknown>)) {\n if (name.length === 0) {\n raiseError(`${STATE_STREAMS_NAME} entry name must be a non-empty string.`);\n }\n if (name.includes(DELIMITER)) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" must be a flat property name (\"${DELIMITER}\" is not allowed).`);\n }\n if (name.includes(WILDCARD)) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" must be a flat property name (\"${WILDCARD}\" is not allowed).`);\n }\n if (name.startsWith(\"$\")) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" must not start with \"$\" (reserved namespace).`);\n }\n // Object.prototype の継承名(__proto__ / constructor / toString 等)は一律拒否する。\n // own key でないのに `name in state` が真になるため実体化(§1-3)が skip され、\n // 起動時の initial リセット(Reflect.set)が継承 setter に化ける\n // (特に __proto__ は state の prototype を差し替える)ため、名前検査の防衛線で落とす(§1-2)。\n if (name in Object.prototype) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").`);\n }\n if (stateElement.getterPaths.has(name)) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" conflicts with a getter declared on the state.`);\n }\n if (stateElement.setterPaths.has(name)) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" conflicts with a setter declared on the state.`);\n }\n if (typeof def !== \"object\" || def === null) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" must be an object ({ args?, source, fold?, initial? }).`);\n }\n const definition = def as Record<string, unknown>;\n if (typeof definition.source !== \"function\") {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" source must be a function.`);\n }\n const hasFold = typeof definition.fold !== \"undefined\";\n if (hasFold && typeof definition.fold !== \"function\") {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" fold must be a function.`);\n }\n if (hasFold && !(\"initial\" in definition)) {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" requires \"initial\" when fold is specified (reduce needs a seed value).`);\n }\n const hasArgs = typeof definition.args !== \"undefined\";\n if (hasArgs && typeof definition.args !== \"function\") {\n raiseError(`${STATE_STREAMS_NAME} entry \"${name}\" args must be a function.`);\n }\n const entry: IStreamEntry = {\n name,\n definition: {\n args: (definition.args as IStreamDefinition[\"args\"] | undefined) ?? null,\n source: definition.source as StreamSource,\n fold: (definition.fold as StreamFold | undefined) ?? latestFold,\n initial: definition.initial,\n },\n status: \"idle\",\n error: null,\n controller: null,\n depAddresses: new Set(),\n };\n // 値プロパティ実体化(§1-3): ユーザーが同名プロパティを先に宣言していたら上書きしない\n if (!(name in state)) {\n state[name] = entry.definition.initial;\n }\n entries.set(name, entry);\n }\n setStreamEntries(stateElement, entries);\n // 新宣言に存在しない名前の通知 dedup 台帳エントリを prune する\n // (同名は保持 = §4-3 の再 set 跨ぎ dedup 契約を維持。stream/lastNotified.ts 参照)\n pruneLastNotified(stateElement, new Set(entries.keys()));\n}\n","/**\n * stream/streamNamespace.ts\n *\n * `$streamStatus` / `$streamError` の read-only namespace proxy\n * (docs/state-streams-design.md §4-1 / §4-2)。commandNamespace と対称。\n *\n * - state element 単位で memo 化し、同一 stateElement なら同じ proxy が返る。\n * - 宣言された stream 名(`$streams` に列挙されたもの)のみ registry entry の\n * status / error を返す。宣言外の名前・Symbol キーは undefined\n * (`then` / `constructor` 等を内部機構が触っても throw しない寛容規約、\n * $command と同じ)。\n * - 値は memo しない: proxy は getStreamEntries を毎回読む thin gateway\n * (status / error は runtime が随時書き換えるため。registry entry が正本、§2-1)。\n * - set / deleteProperty は raiseError。setByAddress の親走査が namespace proxy に\n * 到達したときの Reflect.set もここで落ちる(書き込み防御 S11 の終端)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport {\n STATE_STREAM_ERROR_NAMESPACE_NAME,\n STATE_STREAM_STATUS_NAMESPACE_NAME,\n} from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport { getStreamEntries } from \"./streamRegistry\";\nimport type { IStreamEntry } from \"./types\";\n\nconst statusNamespaceByStateElement: WeakMap<IStateElement, object> = new WeakMap();\nconst errorNamespaceByStateElement: WeakMap<IStateElement, object> = new WeakMap();\n\nfunction createStreamNamespaceProxy(\n stateElement: IStateElement,\n namespaceName: string,\n pick: (entry: IStreamEntry) => unknown,\n): object {\n return new Proxy(Object.create(null), {\n get(_target: object, prop: PropertyKey): unknown {\n if (typeof prop !== \"string\") {\n return undefined;\n }\n const entry = getStreamEntries(stateElement).get(prop);\n if (typeof entry === \"undefined\") {\n return undefined;\n }\n return pick(entry);\n },\n has(_target: object, prop: PropertyKey): boolean {\n return typeof prop === \"string\" && getStreamEntries(stateElement).has(prop);\n },\n ownKeys(): string[] {\n return Array.from(getStreamEntries(stateElement).keys());\n },\n getOwnPropertyDescriptor(_target: object, prop: PropertyKey): PropertyDescriptor | undefined {\n if (typeof prop !== \"string\") {\n return undefined;\n }\n const entry = getStreamEntries(stateElement).get(prop);\n if (typeof entry === \"undefined\") {\n return undefined;\n }\n return {\n configurable: true,\n enumerable: true,\n value: pick(entry),\n };\n },\n set(): boolean {\n raiseError(`${namespaceName} namespace is read-only; assigning to it is not allowed.`);\n },\n deleteProperty(): boolean {\n raiseError(`${namespaceName} namespace is read-only; deleting from it is not allowed.`);\n },\n });\n}\n\nexport function getStreamStatusNamespace(stateElement: IStateElement): object {\n const cached = statusNamespaceByStateElement.get(stateElement);\n if (typeof cached !== \"undefined\") {\n return cached;\n }\n const proxy = createStreamNamespaceProxy(\n stateElement,\n STATE_STREAM_STATUS_NAMESPACE_NAME,\n (entry) => entry.status,\n );\n statusNamespaceByStateElement.set(stateElement, proxy);\n return proxy;\n}\n\nexport function getStreamErrorNamespace(stateElement: IStateElement): object {\n const cached = errorNamespaceByStateElement.get(stateElement);\n if (typeof cached !== \"undefined\") {\n return cached;\n }\n const proxy = createStreamNamespaceProxy(\n stateElement,\n STATE_STREAM_ERROR_NAMESPACE_NAME,\n (entry) => entry.error,\n );\n errorNamespaceByStateElement.set(stateElement, proxy);\n return proxy;\n}\n\n/**\n * 両 namespace proxy の memo を破棄する(clearCommandNamespace と対称)。\n * disconnectedCallback と `_state` 再 set 時に呼ばれる。\n */\nexport function clearStreamNamespace(stateElement: IStateElement): void {\n statusNamespaceByStateElement.delete(stateElement);\n errorNamespaceByStateElement.delete(stateElement);\n}\n\nexport const __private__ = {\n statusNamespaceByStateElement,\n errorNamespaceByStateElement,\n};\n","/**\n * stream/argsTrace.ts\n *\n * `$streams` の args トレース(依存捕捉、docs/state-streams-design.md §3-1)。\n *\n * - モジュールスコープの collector を立てて readonly proxy 上で args を評価し、\n * getByAddress を通った読みを絶対アドレス(IAbsoluteStateAddress)として捕捉する。\n * TreePath / AbsoluteStateAddress は両方キャッシュ済みのため、捕捉した\n * アドレスは drain バッチと Set.has のインスタンス同一性で O(1) 照合できる(§2-1)。\n * - collectStreamDependency は getByAddress のホットパスから毎読み呼ばれるため、\n * collector === null なら即 return し、それ以外の計算を一切しない。\n * - 起動・restart のたびに traceArgs が呼ばれ、成功時は entry.depAddresses を\n * 丸ごと置換する(per-run の動的再捕捉)。失敗時は前回成功 run の検証済み\n * 捕捉を保持する(§2-2 の「error からも依存変化で restart」を保つ)。\n * - lastNotified.ts と同じく import 循環回避のための小モジュール\n * (getByAddress → argsTrace ← streamRuntime の一方向依存に保つ)。\n */\n\nimport { liftAddress } from \"../address/liftAddress\";\nimport type { IAbsoluteStateAddress, IStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport {\n DELIMITER,\n STATE_STREAMS_NAME,\n STATE_STREAM_ERROR_NAMESPACE_NAME,\n STATE_STREAM_STATUS_NAMESPACE_NAME,\n} from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport type { IStreamEntry } from \"./types\";\n\n/** トレース中のみ非 null。getByAddress を通った読みの絶対アドレスが溜まる。 */\nlet collector: Set<IAbsoluteStateAddress> | null = null;\n\n/**\n * getByAddress の入口(checkDependency 直後)から毎読み呼ばれるフック。\n * トレース外(collector === null)では何もしない。\n */\nexport function collectStreamDependency(stateElement: IStateElement, address: IStateAddress): void {\n if (collector === null) {\n return;\n }\n collector.add(liftAddress(stateElement, address));\n}\n\n/**\n * args を readonly proxy で同期評価し、読まれたパスを entry.depAddresses に\n * 丸ごと置換で再捕捉する(§3-1)。評価値(source の第 1 引数になる)を返す。\n *\n * - args === null(宣言で省略)なら depAddresses を clear して undefined\n * (依存なし = 起動後 restart しない)。\n * - 検査(違反は raiseError):\n * (a) 評価値が Promise(同期契約違反)\n * (b) 自己依存 — `<name>` / `$streamStatus.<name>` / `$streamError.<name>` の読み\n * (restart の自己書き込みで再発火する無限ループ、S8)\n * (c) wildcard を含むパスの読み(`$getAll` 等も同様。第 1 段スコープ外)\n * - 失敗時(args のユーザー例外・検査違反)は今回の捕捉(captured)を採用せず\n * 伝播し、entry.depAddresses には**前回成功 run の検証済み捕捉を保持する**。\n * これにより drain リスナーが throw を error 経路に正規化したあとも、依存の\n * 書き込みで再試行できる(§2-2「done / error からも依存変化で restart」——\n * 一時的な args throw で stream が恒久固着しない)。ループ安全性:\n * 保持されるのは前回**成功** run の捕捉のみ(自己依存・wildcard 検査済み)で\n * 自分の `<name>` / `$streamStatus.<name>` / `$streamError.<name>` を含み得ず、\n * traceArgs throw 時の startStream は initial リセットに到達しないため、\n * error 正規化の書き込みが保持 deps に再 hit することはない。再試行は依存\n * 書き込み 1 回につき高々 1 回で有界。未検査の captured を採用しないことが\n * ループ防止の要件であり、前回検証済み捕捉の保持はそれを侵さない。\n * - collector は finally で必ず復元する(例外・再入安全。ネスト評価は想定しないが\n * 防御的に「前の collector を復元」の形にしておく — コストは同等)。\n */\nexport function traceArgs(stateElement: IStateElement, entry: IStreamEntry): unknown {\n const argsFn = entry.definition.args;\n if (argsFn === null) {\n entry.depAddresses.clear();\n return undefined;\n }\n const previousCollector = collector;\n const captured = new Set<IAbsoluteStateAddress>();\n collector = captured;\n let argsValue: unknown = undefined;\n try {\n stateElement.createState(\"readonly\", (state) => {\n argsValue = argsFn(state);\n });\n } finally {\n // args のユーザー例外時は captured を採用せずそのまま伝播する\n // (entry.depAddresses は前回成功 run の検証済み捕捉を保持)\n collector = previousCollector;\n }\n if (argsValue instanceof Promise) {\n raiseError(\n `${STATE_STREAMS_NAME} entry \"${entry.name}\" args must be synchronous (it returned a Promise).`,\n );\n }\n const selfStatusPath = `${STATE_STREAM_STATUS_NAMESPACE_NAME}${DELIMITER}${entry.name}`;\n const selfErrorPath = `${STATE_STREAM_ERROR_NAMESPACE_NAME}${DELIMITER}${entry.name}`;\n for (const dep of captured) {\n const pathInfo = dep.absolutePathInfo.pathInfo;\n if (\n dep.absolutePathInfo.stateElement === stateElement &&\n (pathInfo.path === entry.name || pathInfo.path === selfStatusPath || pathInfo.path === selfErrorPath)\n ) {\n raiseError(\n `${STATE_STREAMS_NAME} entry \"${entry.name}\" args must not read the stream itself (\"${pathInfo.path}\"): a self-dependency would restart the stream on its own writes (infinite loop).`,\n );\n }\n if (pathInfo.wildcardCount > 0) {\n raiseError(\n `${STATE_STREAMS_NAME} entry \"${entry.name}\" args must not read wildcard paths (\"${pathInfo.path}\"): wildcard dependencies are out of scope.`,\n );\n }\n }\n entry.depAddresses = captured;\n return argsValue;\n}\n","/**\n * stream/addressHooks.ts — `$streams` を宣言した state に付く読み書き境界の hook(設計案 H1、S3)。\n * 従来 core(getByAddress / get トラップ)が直接 import していた 3 辺(argsTrace・streamNamespace)を\n * ここへ移し、`$streams` の無い state では一切走らない。\n */\nimport { STATE_STREAM_ERROR_NAMESPACE_NAME, STATE_STREAM_STATUS_NAMESPACE_NAME } from \"../define\";\nimport { NOT_HANDLED, IAddressHooks } from \"../core/addressHooks\";\nimport { collectStreamDependency } from \"./argsTrace\";\nimport { getStreamErrorNamespace, getStreamStatusNamespace } from \"./streamNamespace\";\n\n/** namespace 配下のパスは raw state を持たないため namespace オブジェクトを辿る(getByAddress の walkNamespace と同じ規約) */\nfunction walkNamespace(namespace: object, segments: string[]): any {\n let value: any = namespace;\n for (let i = 1; i < segments.length; i++) {\n if (Object(value) !== value) {\n return undefined;\n }\n value = Reflect.get(value, segments[i]);\n }\n return value;\n}\n\nexport const streamAddressHooks: IAddressHooks = {\n read(stateElement, address) {\n // $streams の args トレース中のみ絶対アドレスを捕捉(collector 非活性なら即 return)\n collectStreamDependency(stateElement, address);\n const firstSegment = address.pathInfo.segments[0];\n if (firstSegment === STATE_STREAM_STATUS_NAMESPACE_NAME) {\n return walkNamespace(getStreamStatusNamespace(stateElement), address.pathInfo.segments);\n }\n if (firstSegment === STATE_STREAM_ERROR_NAMESPACE_NAME) {\n return walkNamespace(getStreamErrorNamespace(stateElement), address.pathInfo.segments);\n }\n return NOT_HANDLED;\n },\n get(handler, prop) {\n if (prop === STATE_STREAM_STATUS_NAMESPACE_NAME) {\n return getStreamStatusNamespace(handler.stateElement);\n }\n if (prop === STATE_STREAM_ERROR_NAMESPACE_NAME) {\n return getStreamErrorNamespace(handler.stateElement);\n }\n return NOT_HANDLED;\n },\n};\n","/**\n * stream/consumeSource.ts\n *\n * `$streams` のチャンク消費ループ(docs/state-streams-design.md §3-3)。\n * packages/signals/src/streamResource.ts の consume / iterate /\n * readableToAsyncIterable の移植(パッケージ間依存は持たない自己完結原則)。\n *\n * 唯一の構造差分は状態書き込みの IConsumeSink への委譲:\n * value.set(fold(value.peek(), chunk)) → sink.fold(chunk)\n * status.set(\"done\") → sink.done()\n * error.set(e) + status.set(\"error\") → sink.fail(e)\n *\n * sink.fold() が throw した場合(fold throw)もループ内の throw として\n * 既存の catch に流れ、signal.aborted なら return、でなければ sink.fail(e)。\n * consumeSource 自体は fold throw と source throw を区別しない\n * (producer の掃除 = controller.abort() は呼び出し側 runtime が fail 内で行う)。\n * consumeSource は reject しない(全経路 catch 済み)。\n *\n * ---------------------------------------------------------------------------\n * 以下、移植元モジュールヘッダの契約(原文英語のまま維持):\n *\n * CONTRACT (cooperative cancellation — STRONG REQUIREMENT): the `source` MUST honor\n * the `AbortSignal` it is given. Honoring it is what drives switchMap restart/dispose;\n * a source that ignores it cannot be reliably cancelled.\n *\n * Rescue levels on abort:\n * - ReadableStream: FULLY rescued. A parked read() is force-unwound via\n * reader.cancel(), which both releases the underlying source and settles the\n * pending read() so the loop unwinds. Anything getReader-bearing is routed\n * through this path even when it is ALSO natively async-iterable (Node 18+ /\n * Chrome 124+ / Firefox): the spec serializes asyncIterator.return() behind\n * the pending next() ([[ongoingPromise]]), so the AsyncIterable rescue below\n * cannot force-unwind a parked read on a native ReadableStream.\n * - AsyncIterable / async generator: PARTIALLY rescued. On abort we call\n * iterator.return() to trigger the generator's finally/cleanup. But a parked\n * `await` (the producer stalling before its next yield while IGNORING `signal`)\n * cannot be force-unwound from outside — return() only takes effect when the\n * generator next resumes. So a source that parks forever and never observes\n * `signal` still leaks its consume task. Honor `signal` to bound this.\n * The `if (signal.aborted) return` check only runs after a chunk arrives, not while\n * parked — it drops stale chunks but is not, by itself, a cancellation mechanism.\n */\n\nimport type { IConsumeSink, StreamProducer, StreamSource } from \"./types\";\n\nexport async function consumeSource(\n source: StreamSource,\n args: unknown,\n signal: AbortSignal,\n sink: IConsumeSink,\n): Promise<void> {\n // Obtain the iterator EXPLICITLY (not via `for await`'s implicit one) so abort can\n // call `iterator.return()` to trigger an AsyncIterable / async generator's\n // `finally`/cleanup. A `for await` only calls `.return()` when the loop itself exits;\n // if the producer is PARKED (awaiting before the next yield while ignoring `signal`),\n // the loop never advances, so the implicit `.return()` never runs and the task leaks\n // past restart/dispose. Calling `.return()` on abort is the PARTIAL rescue: the\n // parked `await` cannot be force-unwound from outside, but once the generator resumes\n // (its next tick), `.return()` makes it run its `finally` and stop — recovering the\n // common \"generator wakes up after abort\" case. The ReadableStream path is fully\n // rescued via `reader.cancel()` (see `readableToAsyncIterable`).\n let iterator: AsyncIterator<unknown> | null = null;\n // Guard against returning the SAME iterator twice. `onAbort` is reachable two ways:\n // the abort listener, and the explicit call below when abort raced the\n // `await source(...)`. The guard keys on the iterator instance (not a plain \"ran\"\n // flag): the listener firing with iterator still null must NOT consume the single\n // real cleanup that the explicit call performs once the iterator exists. So we only\n // mark an iterator returned once we have actually called `.return()` on it.\n let returned: AsyncIterator<unknown> | null = null;\n const onAbort = (): void => {\n if (!iterator || iterator === returned) {\n return; // nothing to release yet, or already released this iterator\n }\n returned = iterator;\n // Fire the iterator's cleanup. Swallow any throw/rejection from `.return()` — we\n // are tearing down; a producer that rejects on return must not surface here.\n try {\n void iterator.return?.()?.then?.(undefined, () => {});\n } catch {\n // `.return()` threw synchronously while tearing down — ignore.\n }\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n try {\n const produced = await source(args, signal);\n iterator = iterate(produced, signal)[Symbol.asyncIterator]();\n if (signal.aborted) {\n // Aborted while awaiting the source: the abort listener already ran (iterator\n // was still null then), so explicitly release the just-produced iterator now —\n // this fires a generator's finally / a ReadableStream's cancel for the\n // resource we created but will never iterate.\n onAbort();\n return;\n }\n for (;;) {\n const result = await iterator.next();\n if (result.done) {\n break;\n }\n if (signal.aborted) {\n return; // stale chunk from a superseded/disposed run — drop it\n }\n sink.fold(result.value);\n }\n if (signal.aborted) {\n return; // stream ended but this run was aborted — don't mark done\n }\n sink.done();\n } catch (e) {\n if (signal.aborted) {\n return; // an abort that surfaced as a throw is not an error\n }\n sink.fail(e); // keep the last folded value (do not reset)\n } finally {\n signal.removeEventListener(\"abort\", onAbort);\n }\n}\n\nfunction iterate(produced: StreamProducer, signal: AbortSignal): AsyncIterable<unknown> {\n // Anything ReadableStream-shaped (has getReader) takes the reader path FIRST —\n // even when it is also async-iterable. On runtimes where ReadableStream\n // implements native async iteration (Node 18+ / Chrome 124+ / Firefox), the\n // spec serializes `iterator.return()` behind the pending `next()`\n // ([[ongoingPromise]]), so the AsyncIterable rescue cannot force-unwind a\n // parked read: abort would hang the consume task until the producer's next\n // chunk (or forever on a silent stream), leaking the underlying source.\n // `reader.cancel()` has no such ordering — routing every getReader-bearing\n // source through it keeps the FULL rescue promised for ReadableStream.\n // Optional chaining: a null/undefined source return value must fall through to\n // the explicit TypeError below, not throw an opaque property access error.\n if (typeof (produced as ReadableStream<unknown>)?.getReader === \"function\") {\n return readableToAsyncIterable(produced as ReadableStream<unknown>, signal);\n }\n if (typeof (produced as AsyncIterable<unknown>)?.[Symbol.asyncIterator] === \"function\") {\n return produced as AsyncIterable<unknown>;\n }\n throw new TypeError(\n \"[@wcstack/state] $streams: source must return an AsyncIterable or a ReadableStream (got neither).\",\n );\n}\n\nasync function* readableToAsyncIterable(\n stream: ReadableStream<unknown>,\n signal: AbortSignal,\n): AsyncGenerator<unknown> {\n const reader = stream.getReader();\n // A ReadableStream read() does NOT observe an AbortSignal on its own. Without\n // this, a switchMap restart / dispose leaves the previous reader parked in a\n // pending read() forever, leaking the underlying source. Cancelling on abort\n // both releases the source AND settles the pending read() so the for-await\n // unwinds and the finally below can release the lock. Abort is the only\n // early-exit path for this generator (the consumer never calls .return()\n // without aborting), so this is the sole place a non-drained stream is cancelled.\n const onAbort = (): void => {\n void reader.cancel().catch(() => {}); // tearing down; swallow a rejected cancel\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n return;\n }\n yield value;\n }\n } finally {\n signal.removeEventListener(\"abort\", onAbort);\n reader.releaseLock();\n }\n}\n","/**\n * stream/streamRuntime.ts\n *\n * `$streams` の起動・チャンク反映・status 遷移(docs/state-streams-design.md\n * §2-2 / §3-3 / §4-3)。\n *\n * スコープ:\n * - eager 起動(startStreams)と start = restart の共通手順(startStream)。\n * - args は traceArgs(stream/argsTrace.ts)で readonly proxy 評価と同時に依存を\n * per-run 再捕捉する(§3-1)。\n * - 依存駆動 restart(§3-2): モジュール初期化時に updater の drain 終了リスナーを\n * 1 つ登録し(restartStreamsOnUpdateBatch)、起動中 stateElement\n * (stream/activeStateElements.ts — startStreams で add・abortAllStreams /\n * clearStreamRegistry で delete)の各 entry について depAddresses と batch を\n * 交差させ、hit した entry を restart する。\n *\n * 切断後の後始末について(不変条件):\n * - disconnect(abortAllStreams)は registry entry を直接ミューテーションして\n * idle に戻す($postUpdate は呼ばない — 切断済みで binding 更新は不要かつ\n * rootNode が無い)。\n * - abort 済み run の sink コールバック(fold / done / fail)は consumeSource の\n * stale-drop(全経路の signal.aborted チェック)が createState 到達前に\n * 落とすため、runtime 側に切断後ガードは不要。\n * 「runtime が createState を呼ぶのは自分の controller が生きている間だけ」が\n * この 2 つの組み合わせで常に保たれる。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport {\n DELIMITER,\n STATE_STREAM_ERROR_NAMESPACE_NAME,\n STATE_STREAM_STATUS_NAMESPACE_NAME,\n STREAM_LISTENER_PRIORITY,\n} from \"../define\";\nimport { assertNoScanFeedback } from \"../scan/scanFeedback\";\nimport { registerUpdateBatchListener } from \"../updater/updater\";\nimport { registerFeatureHooks } from \"../core/addressHooks\";\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { STATE_STREAMS_NAME } from \"../define\";\nimport { inSsr } from \"../config\";\nimport { processStreamsDeclaration } from \"./processStreamsDeclaration\";\nimport { clearStreamNamespace } from \"./streamNamespace\";\nimport { abortAllStreams, clearStreamRegistry } from \"./streamRegistry\";\nimport { streamAddressHooks } from \"./addressHooks\";\nimport { addActiveStateElement, getActiveStateElements } from \"./activeStateElements\";\nimport { traceArgs } from \"./argsTrace\";\nimport { consumeSource } from \"./consumeSource\";\nimport { getLastNotified, setLastNotified } from \"./lastNotified\";\nimport { getStreamEntries } from \"./streamRegistry\";\nimport type { IConsumeSink, IStreamEntry, StreamStatus } from \"./types\";\n\n/**\n * 登録済みの全 stream を起動する(eager 起動、設計書 §2-3)。\n * State.connectedCallback($connectedCallback 完了後)と接続中の `_state` 再 set\n * から呼ばれる想定。\n *\n * 同時に依存駆動 restart(§3-2)の対象として activeStateElements に登録する\n * (delete 側は abortAllStreams / clearStreamRegistry —\n * stream/activeStateElements.ts のリーク防止不変条件を参照)。\n * eager 起動の throw(args のユーザー例外等)はここでは正規化せず loud fail のまま\n * (既存の $connectedCallback と同じ扱い。正規化は drain リスナー側の restart のみ)。\n */\nexport function startStreams(stateElement: IStateElement): void {\n // 初回の宣言起動で listener を確実に載せる(bootstrapState() を経ない経路の保険。冪等)\n installStreamRuntime();\n const entries = getStreamEntries(stateElement);\n if (entries.size === 0) {\n return;\n }\n addActiveStateElement(stateElement);\n for (const entry of entries.values()) {\n startStream(stateElement, entry);\n }\n}\n\n/**\n * stream を起動する。start = restart の共通手順(設計書 §2-2):\n *\n * 1. 旧 run を abort(restart 時)→ 新 AbortController\n * 2. traceArgs で args を readonly proxy 評価し依存を丸ごと再捕捉\n * (Promise / 自己依存 / wildcard 読みは raiseError、§3-1)\n * 3. 値を initial にリセット(起動 = 最初の run も restart と同一セマンティクス、§1-3)\n * 4. status=\"active\"・error=null を反映\n * 5. consumeSource で消費開始\n */\nexport function startStream(stateElement: IStateElement, entry: IStreamEntry): void {\n entry.controller?.abort();\n const controller = new AbortController();\n entry.controller = controller;\n\n // args 評価 + 依存の per-run 再捕捉(args === null なら depAddresses を clear して\n // undefined。Promise / 自己依存 / wildcard 読みは raiseError、§3-1)\n const argsValue = traceArgs(stateElement, entry);\n // scan 出力 → args の前進ループを起動前に止める(docs/state-scan-design.md D9)\n assertNoScanFeedback(stateElement, entry);\n\n // 値リセット: setByAddress を通すことで updater coalesce・sameValueGuard・\n // walkDependency(stream 値に依存する computed の dirty 化)がすべて乗る(§3-3)\n stateElement.createState(\"writable\", (state) => {\n state[entry.name] = entry.definition.initial;\n });\n\n updateStreamStatus(stateElement, entry, \"active\", null);\n\n const definition = entry.definition;\n const sink: IConsumeSink = {\n fold(chunk: unknown): void {\n // fold の throw はそのまま伝播させる(consumeSource が fail 経路に回す)\n stateElement.createState(\"writable\", (state) => {\n state[entry.name] = definition.fold(state[entry.name], chunk);\n });\n },\n done(): void {\n updateStreamStatus(stateElement, entry, \"done\", null);\n },\n fail(error: unknown): void {\n // 値は直前の fold 結果を保持(リセットしない)\n updateStreamStatus(stateElement, entry, \"error\", error);\n // fold-throw 時の producer 掃除(iterator.return() / reader.cancel() を発火)。\n // source-throw 時は producer が既に終了しているので abort は無害(§3-3)。\n controller.abort();\n },\n };\n void consumeSource(definition.source, argsValue, controller.signal, sink);\n}\n\n/**\n * status / error の反映ヘルパ(設計書 §4-3)。\n *\n * - registry entry が正本。常に最新値へ書き換える。\n * - 「最後に通知した観測値」(stream/lastNotified.ts — 再 set・再接続を跨いで\n * stateElement の寿命で生存する台帳)から変化した項目に対応する名前空間パス\n * (`$streamStatus.<name>` / `$streamError.<name>`)だけを writable proxy の\n * $postUpdate で通知する(updater enqueue + walkDependency)。\n * - 両方不変なら通知しない(名前空間パスは setByAddress を通らないため\n * sameValueGuard が効かず、同等の same-value 判定を runtime 側が持つ)。\n * abortAllStreams の無通知ミューテーションで台帳が invalidate されている場合は\n * 同値扱いにならず必ず通知される(再接続ウィンドウ内の fresh 読みが描画した\n * idle の恒久陳腐化を防ぐ、§4-3)。\n */\nexport function updateStreamStatus(\n stateElement: IStateElement,\n entry: IStreamEntry,\n status: StreamStatus,\n error: unknown,\n): void {\n entry.status = status;\n entry.error = error;\n const last = getLastNotified(stateElement, entry.name);\n const statusChanged = last.status !== status;\n const errorChanged = !Object.is(last.error, error);\n if (!statusChanged && !errorChanged) {\n return;\n }\n setLastNotified(stateElement, entry.name, status, error);\n stateElement.createState(\"writable\", (state) => {\n if (statusChanged) {\n state.$postUpdate(`${STATE_STREAM_STATUS_NAMESPACE_NAME}${DELIMITER}${entry.name}`);\n }\n if (errorChanged) {\n state.$postUpdate(`${STATE_STREAM_ERROR_NAMESPACE_NAME}${DELIMITER}${entry.name}`);\n }\n });\n}\n\n/**\n * 依存駆動 restart の drain リスナー(設計書 §3-2)。\n * モジュール初期化時に registerUpdateBatchListener で 1 つだけ登録される。\n *\n * - 起動中の各 stateElement の各 entry について、depAddresses と batch の交差を\n * Set.has のインスタンス同一性で判定する(小さい方 = depAddresses を回して\n * batch.has(dep)。AbsoluteStateAddress はキャッシュにより同一 (stateElement, path,\n * listIndex) が同一インスタンス、§2-1)。args なし(depAddresses 空)の entry は\n * 自然にスキップされる。\n * - status は問わず restart する(done / error からも依存の叩き直しで再試行、§2-2)。\n * - hit は収集してから一括で restart する(イテレーション中の registry 変更を避ける。\n * entry ごとに最初の hit で break するため「1 drain につき 1 entry 最大 1 restart」\n * もここで自然に成立する — 同一 tick 内の複数依存書き込みは 1 restart に畳まれる)。\n * - hits の実行時にも active + entry identity を再チェックする: 先行 restart の\n * source / args は consumeSource / traceArgs の同期プレフィックスで同期実行される\n * ため、そこで (a) 他の stateElement(や自分自身のホスト)の同期切断、(b) 同一要素の\n * _state 同期再 set(clearStreamRegistry → startStreams で Set に再 add される)が\n * 起こり得る。(a) は切断済み要素への startStream が rootNode 不在で throw する経路、\n * (b) は registry から置換済みの旧 entry を restart して到達不能な孤児 consume run を\n * リークする経路(§3-2「未接続の stateElement の entry は restart しない」・\n * §5-1「切断後は idle」に違反)で、いずれも「entry が現行 registry の live entry で\n * あること」の再検証で skip する。startStream **実行中**の自己切断・再 set は事前\n * チェックではガードできないため、catch 側でも同じ再検証を行ってから error に\n * 正規化する(切断済みでの正規化は createState が再 throw して drain リスナー外へ\n * 漏れ、後続 hits の restart を巻き添えにするため)。\n * - restart(startStream)は entry ごとに try/catch し、throw(args のユーザー例外・\n * Promise 同期契約違反等)は controller.abort() → status=\"error\"・$streamError 格納\n * に正規化する(§3-2 規範 3)。updater の drain を壊さず、他 entry の restart も\n * 継続する。eager 起動(connect 時の startStreams)の throw は従来どおり loud fail。\n * - restart 内の書き込み(initial リセット・status 通知)は updater への enqueue のみで\n * 新しい microtask バッチを作る(drain 再入ではない)。自己依存は traceArgs が\n * 宣言時に raiseError で検出するため、restart 書き込みが自分の依存に再 hit する\n * ループは起きない(§3-1)。\n */\nfunction restartStreamsOnUpdateBatch(batch: ReadonlySet<IAbsoluteStateAddress>): void {\n const activeStateElements = getActiveStateElements();\n if (activeStateElements.size === 0) {\n // stream 未使用アプリの drain に配列・イテレータ割り当てのコストを載せない\n return;\n }\n const hits: { stateElement: IStateElement; entry: IStreamEntry }[] = [];\n for (const stateElement of activeStateElements) {\n for (const entry of getStreamEntries(stateElement).values()) {\n for (const dep of entry.depAddresses) {\n if (batch.has(dep)) {\n hits.push({ stateElement, entry });\n break;\n }\n }\n }\n }\n for (const { stateElement, entry } of hits) {\n // 先行 restart の source / args 同期実行は他要素の切断や同一要素の _state 同期再 set を\n // 行い得るため、実行時に再チェックする(live な Set / registry ビューで即時反映):\n // - 切断済み要素は skip(§3-2「未接続の stateElement の entry は restart しない」)\n // - entry が現行 registry のものでなければ skip — 同期再 set で置換された旧 entry を\n // restart すると、registry から到達不能なため abortAllStreams でも止められない\n // 孤児 consume run がリークする\n if (\n !activeStateElements.has(stateElement) ||\n getStreamEntries(stateElement).get(entry.name) !== entry\n ) {\n continue;\n }\n try {\n startStream(stateElement, entry);\n } catch (e) {\n entry.controller?.abort();\n // startStream 実行中(args / source の同期プレフィックス)の自己切断・同期再 set は\n // 上の再チェックではガードできない。切断済みだと updateStreamStatus の createState が\n // rootNode 不在で再 throw して drain リスナー外へ漏れる(後続 hits の restart を\n // 巻き添えにする)ため、entry がまだ現行の live entry である場合のみ error に\n // 正規化する(切断済みなら abortAllStreams が idle に戻し済み。§3-2 規範 3 / §5-1)。\n if (\n activeStateElements.has(stateElement) &&\n getStreamEntries(stateElement).get(entry.name) === entry\n ) {\n updateStreamStatus(stateElement, entry, \"error\", e);\n }\n }\n }\n}\n\n// drain 終了 listener の登録。優先度で `$watch` の後に固定する(設計書 §3-2 層 1)。\n// モジュール評価時には登録しない(watch/watchRuntime.ts と同じ理由)。bootstrapState() が呼ぶ(冪等)。\nlet streamRuntimeInstalled = false;\n/**\n * `_state` セッター側の startStreams が走った connect 世代(接続末尾の startStreams との\n * 二重起動防止、設計書 §2-3。世代が進めば不一致となり自然に無効化される — サイクル単位の\n * フラグリセット相当)。従来 `State` の private フィールドだった。\n */\nconst startedGenerationByElement = new WeakMap<IStateElement, number>();\n\n/**\n * `$streams` の宣言とライフサイクル(設計案 H4)。\n */\nexport const streamDeclarationHooks: IDeclarationHooks = {\n // watch の後に起動し、先に停止する(受け口が deactivate を逆順で回す)\n order: 20,\n apply(element, value) {\n // $streams: 再 set 時の二重起動防止のため旧 stream を abort + registry 全削除してから\n // 新宣言をパースする(clearEventTokenRegistry → processOnDeclaration と同じ再配線パターン)。\n // getterPaths / setterPaths の収集後であること(宣言バリデーションが衝突検査で参照する)。\n // namespace proxy の memo も破棄して古い proxy を捨てる(clearCommandNamespace と対称)。\n clearStreamNamespace(element);\n clearStreamRegistry(element);\n processStreamsDeclaration(element, value);\n // hook は要素の寿命の間は付いたまま(再 set で $streams が消えても、残った $streamStatus /\n // $streamError の束縛は名前空間の null を読む — 従来の core 直結と同じ振る舞い)\n if (typeof (value as Record<string, unknown>)[STATE_STREAMS_NAME] !== \"undefined\") {\n element.attachAddressHooks?.(\"streams\", STATE_STREAMS_NAME);\n }\n },\n activate(element, captured) {\n // rootNode ガード: $connectedCallback の await 中に切断された場合は起動しない。ガードなしだと\n // startStream 内の createState が rootNode 解決の raiseError で throw し、\n // connectedCallbackPromise が永遠に未解決になる(「未接続の entry は restart しない」設計書 §3-2)。\n if (inSsr() || element.connectedRootNode == null) {\n return;\n }\n if (captured === null) {\n // 接続中の再 set(S13): 新宣言で即再起動する。初回(初期化中)は起動せず、接続の末尾が担う\n if (element.initialized !== true) {\n return;\n }\n startStreams(element);\n // $connectedCallback 実行中の再 set(setInitialState)では、ここで新宣言が起動済みのため\n // 接続末尾の startStreams を skip させる。skip しないと同一 connect サイクルで新宣言の\n // source が 2 回起動する(1 回目は即 abort — switchMap 意味論で状態は壊れないが、\n // 副作用を持つ source が 2 回発火してしまう)\n startedGenerationByElement.set(element, element.connectGeneration ?? 0);\n return;\n }\n // 接続の末尾: 世代ガード(陳腐な connect の再開を弾く)と、宣言側で起動済みの世代を skip する\n if (captured !== element.connectGeneration || startedGenerationByElement.get(element) === captured) {\n return;\n }\n startStreams(element);\n },\n deactivate(element) {\n // stream は abort のみで registry は保持する(再接続時に同じ宣言から initial で\n // 再起動できる、設計書 §5-1 / §5-2)。namespace proxy の memo は破棄する\n // (clearCommandNamespace と対称。registry は残るため再接続後の初回アクセスで\n // 同内容の proxy が再生成される)。\n abortAllStreams(element);\n clearStreamNamespace(element);\n },\n};\n\nexport function installStreamRuntime(): void {\n if (streamRuntimeInstalled) return;\n streamRuntimeInstalled = true;\n registerFeatureHooks(\"streams\", streamAddressHooks);\n registerDeclarationHooks(\"streams\", streamDeclarationHooks);\n registerUpdateBatchListener(restartStreamsOnUpdateBatch, STREAM_LISTENER_PRIORITY);\n}\n","/**\n * features/temporal.ts — `$watch` / `$scan` / `$streams`(@wcstack/state/features/temporal)。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installScanDeclarations } from \"../scan/declarations\";\nimport { installStreamRuntime } from \"../stream/streamRuntime\";\nimport { installWatchRuntime } from \"../watch/watchRuntime\";\n\nexport const temporal: IStateFeature = {\n name: \"temporal\",\n install(): void {\n installWatchRuntime();\n installScanDeclarations();\n installStreamRuntime();\n },\n};\nexport default temporal;\n"],"names":["INVALID","NO_RESET","Object","freeze","entryLabel","name","STATE_SCAN_NAME","findGetterOnPath","pathInfo","getterPaths","path","cumulativePaths","has","computedMessage","label","field","getter","includes","WILDCARD","LINT_HINT","assertValidScanPath","length","raiseError","startsWith","prototype","getPathInfo","segment","segments","wildcardCount","MAX_WILDCARD_DEPTH","assertOutputName","setterPaths","streamNames","DELIMITER","STATE_STREAMS_NAME","assertNoMethodConflict","functionValues","definition","value","get","initial","wasPlacedOnOutput","parseSource","eventTokenNames","writeOnlyPaths","recursion","hasFrom","from","hasOn","on","tokenName","STATE_EVENT_TOKENS_NAME","didYouMean","kind","recursiveGetterOwning","setter","writeOnlyMessage","parseResetOn","raw","source","Array","isArray","paths","item","push","parseScanDeclaration","state","declared","Set","Map","key","descriptor","entries","getAllPropertyDescriptors","add","set","streams","keys","collectStreamNames","order","def","fold","resetOn","outputs","map","entry","next","root","start","chain","current","size","n","join","assertNoOutputReferences","createEventFold","event","indexes","proxy","failure","reset","hasPendingScanReset","acc","isSameAsInitial","cloneInitial","isThenable","reportScanThenable","is","recordOutputValue","consumePendingScanReset","error","reportScanError","SCAN_ENTRIES","scanDeclarationHooks","validate","_element","ctx","applyEarly","element","materializeScanOutputs","stateElement","getOrCreateEventToken","subscribe","subscribeScanEvents","register","_value","carried","carry","registry","getScanRegistry","clearScanRegistry","unregisterScans","setScanPaths","setScanRegistry","some","getUpdater","hasQueuedPath","markPendingScanReset","fromPaths","byFromPath","setPathInfo","byResetPath","registerScans","installed","NO_EDGES","NO_SCANS","collectReachablePaths","reachable","queue","pop","children","staticDependency","dependents","dynamicDependency","downstream","scan","latestFold","_acc","chunk","NO_STREAM_NAMES","statusNamespaceByStateElement","WeakMap","errorNamespaceByStateElement","createStreamNamespaceProxy","namespaceName","pick","Proxy","create","_target","prop","getStreamEntries","ownKeys","getOwnPropertyDescriptor","configurable","enumerable","deleteProperty","getStreamStatusNamespace","cached","STATE_STREAM_STATUS_NAMESPACE_NAME","status","getStreamErrorNamespace","STATE_STREAM_ERROR_NAMESPACE_NAME","clearStreamNamespace","delete","collector","walkNamespace","namespace","i","Reflect","streamAddressHooks","read","address","liftAddress","collectStreamDependency","firstSegment","NOT_HANDLED","handler","async","consumeSource","args","signal","sink","iterator","returned","onAbort","return","then","undefined","addEventListener","once","produced","getReader","stream","reader","cancel","catch","done","removeEventListener","releaseLock","readableToAsyncIterable","Symbol","asyncIterator","TypeError","iterate","aborted","result","e","fail","startStreams","installStreamRuntime","addActiveStateElement","values","startStream","controller","abort","AbortController","argsValue","argsFn","depAddresses","clear","previousCollector","captured","createState","Promise","selfStatusPath","selfErrorPath","dep","absolutePathInfo","traceArgs","streamEntry","depPath","assertNoScanFeedback","updateStreamStatus","last","getLastNotified","statusChanged","errorChanged","setLastNotified","$postUpdate","restartStreamsOnUpdateBatch","batch","activeStateElements","getActiveStateElements","hits","streamRuntimeInstalled","startedGenerationByElement","streamDeclarationHooks","apply","clearStreamRegistry","pruneLastNotified","hasFold","setStreamEntries","processStreamsDeclaration","attachAddressHooks","activate","inSsr","connectedRootNode","initialized","connectGeneration","deactivate","abortAllStreams","registerFeatureHooks","registerDeclarationHooks","registerUpdateBatchListener","STREAM_LISTENER_PRIORITY","temporal","install","installWatchRuntime","registerEnqueueListener","noteEnqueueForScanReset"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/state",
3
- "version": "2.6.1",
3
+ "version": "3.0.0",
4
4
  "description": "Reactive state management with declarative data binding for Web Components. Zero dependencies, buildless.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",
@@ -12,6 +12,18 @@
12
12
  "import": "./dist/index.esm.js"
13
13
  },
14
14
  "./auto": "./dist/auto.min.js",
15
+ "./core": {
16
+ "types": "./dist/split/core.d.ts",
17
+ "import": "./dist/split/core.js"
18
+ },
19
+ "./features/*": {
20
+ "types": "./dist/split/features/*.d.ts",
21
+ "import": "./dist/split/features/*.js"
22
+ },
23
+ "./define": {
24
+ "types": "./dist/define.d.ts",
25
+ "import": "./dist/define.js"
26
+ },
15
27
  "./manifest": {
16
28
  "types": "./dist/manifest.d.ts",
17
29
  "import": "./dist/manifest.esm.js"