@wcstack/state 3.1.0 → 3.2.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 (36) hide show
  1. package/README.ja.md +25 -17
  2. package/README.md +25 -17
  3. package/dist/auto.min.js +1 -1
  4. package/dist/auto.min.js.map +1 -1
  5. package/dist/define.d.ts +11 -7
  6. package/dist/index.d.ts +13 -7
  7. package/dist/index.esm.js +1 -1
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/manifest.d.ts +12 -1
  10. package/dist/manifest.esm.js +90 -35
  11. package/dist/split/chunks/declarationAliases.js +2 -0
  12. package/dist/split/chunks/declarationAliases.js.map +1 -0
  13. package/dist/split/chunks/filterRegistry.js +1 -1
  14. package/dist/split/chunks/filterRegistry.js.map +1 -1
  15. package/dist/split/chunks/mount.js +1 -1
  16. package/dist/split/chunks/mount.js.map +1 -1
  17. package/dist/split/chunks/pathDiagnostics.js +1 -1
  18. package/dist/split/chunks/pathDiagnostics.js.map +1 -1
  19. package/dist/split/chunks/registerComponents.js +1 -1
  20. package/dist/split/chunks/registerComponents.js.map +1 -1
  21. package/dist/split/chunks/version.js +1 -1
  22. package/dist/split/core.d.ts +11 -7
  23. package/dist/split/core.js +1 -1
  24. package/dist/split/core.js.map +1 -1
  25. package/dist/split/features/devtools.js +1 -1
  26. package/dist/split/features/devtools.js.map +1 -1
  27. package/dist/split/features/formats.js +1 -1
  28. package/dist/split/features/formats.js.map +1 -1
  29. package/dist/split/features/scopes.js +1 -1
  30. package/dist/split/features/scopes.js.map +1 -1
  31. package/dist/split/features/ssr.js +1 -1
  32. package/dist/split/features/ssr.js.map +1 -1
  33. package/dist/split/features/temporal.js +1 -1
  34. package/dist/split/features/temporal.js.map +1 -1
  35. package/dist/wcs-manifest.json +64 -25
  36. package/package.json +1 -1
@@ -1 +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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"}
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":["/**\r\n * scan/processScanDeclaration.ts\r\n *\r\n * `$scan: { <output>: { from | on, initial, fold, resetOn? } }` の解析と配線\r\n * (docs/state-scan-design.md §1-2 / §2-4)。\r\n *\r\n * `_state` セッター上の位置が違う 3 段に分ける:\r\n * 1. `parseScanDeclaration` — `value` だけを読む検査。世代を進める**前**に走るので、\r\n * ここで throw した再セットは要素を丸ごと旧世代に残す。\r\n * 2. `materializeScanOutputs` / `subscribeScanEvents` — `clearEventTokenRegistry` の直後。\r\n * 実体化を `_rebuildPathInfo` より前に置くのは、前世代の `from`(別 scan の出力の子)を\r\n * 張り直すときに存在検査が偽の miss を出さないため。`on` の購読を `$on` より前に置くのは、\r\n * 同じトークンで reducer → effect の順にするため(D11)。\r\n * 3. `registerScans` — `processWatchDeclaration` の直前(`_pathSet` クリア後)。\r\n */\r\n\r\nimport { getPathInfo } from \"../address/PathInfo\";\r\nimport type { IPathInfo } from \"../address/types\";\r\nimport type { IStateElement } from \"../components/types\";\r\nimport { DELIMITER, MAX_WILDCARD_DEPTH, STATE_EVENT_TOKENS_NAME, STATE_SCAN_NAME, STATE_STREAMS_NAME, WILDCARD } from \"../define\";\r\r\nimport { normalizeDeclarationAliases } from \"../declarationAliases\";\nimport { didYouMean, LINT_HINT } from \"../errorGuidance\";\r\nimport { getOrCreateEventToken } from \"../event/eventTokenRegistry\";\r\nimport { getAllPropertyDescriptors } from \"../getAllPropertyDescriptors\";\r\nimport type { IStateProxy } from \"../proxy/types\";\r\nimport { raiseError } from \"../raiseError\";\r\nimport type { TokenSubscriber } from \"../token/Token\";\r\nimport type { IState } from \"../types\";\r\nimport { getUpdater } from \"../updater/updater\";\r\nimport { consumePendingScanReset, hasPendingScanReset, markPendingScanReset } from \"./eventReset\";\r\nimport { cloneInitial, isSameAsInitial, recordOutputValue, wasPlacedOnOutput } from \"./initialValue\";\r\nimport { isThenable, reportScanError, reportScanThenable, type ScanFailure } from \"./scanReport\";\r\nimport { clearScanRegistry, getScanRegistry, setScanRegistry } from \"./scanRegistry\";\r\nimport type { IScanEntry, ScanFold, ScanSource } from \"./types\";\r\n\r\nconst INVALID = \"[wcs/scan-declaration-invalid]\";\r\nconst COMPUTED = \"[wcs/scan-source-computed]\";\r\nconst NO_RESET: readonly string[] = Object.freeze([]);\r\n\r\n/**\r\n * `$recursion` の `**` getter の展開形を引く口(recursion/registry.ts の RecursionRegistry)。\r\n * `_state` セッターは `$scan` の検査より前に新しい宣言のレジストリを作るので、それを受け取る。\r\n */\r\nexport interface IRecursiveGetterLookup {\r\n recursiveGetterOwning(concretePath: string): string | null;\r\n}\r\n\r\nfunction entryLabel(name: string): string {\r\n return `${STATE_SCAN_NAME} entry \"${name}\"`;\r\n}\r\n\r\n/** 累積パス(`a` / `a.b` / `a.b.c`)のうち最初に getter であるものを返す */\r\nfunction findGetterOnPath(pathInfo: IPathInfo, getterPaths: ReadonlySet<string>): string | null {\r\n for (const path of pathInfo.cumulativePaths) {\r\n if (getterPaths.has(path)) {\r\n return path;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction computedMessage(label: string, field: string, path: string, getter: string): string {\r\n const where = getter === path\r\n ? \"is a getter\"\r\n : getter.includes(`${WILDCARD}${WILDCARD}`)\r\n ? `is computed by the recursive getter \"${getter}\"`\r\n : `is under the getter \"${getter}\"`;\r\n return `${COMPUTED} ${label} ${field} \"${path}\" ${where}. A getter re-evaluates whenever its inputs change, ` +\r\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}`;\r\n}\r\n\r\nfunction writeOnlyMessage(label: string, path: string, setter: string): string {\r\n const where = setter === path ? \"is a setter without a getter\" : `is under the setter without a getter \"${setter}\"`;\r\n return `${INVALID} ${label} from \"${path}\" ${where}, so it always reads undefined and every fold would receive undefined. ` +\r\n `Fold the plain value the setter writes, or use \"on\" with an event token.${LINT_HINT}`;\r\n}\r\n\r\nfunction assertValidScanPath(label: string, field: string, path: string): IPathInfo {\r\n if (path.length === 0) {\r\n raiseError(`${INVALID} ${label} \"${field}\" must be a non-empty state path.${LINT_HINT}`);\r\n }\r\n if (path.startsWith(\"$\")) {\r\n raiseError(`${INVALID} ${label} ${field} \"${path}\" must not start with \"$\" (reserved namespace).${LINT_HINT}`);\r\n }\r\n if (path.includes(\"@\")) {\r\n raiseError(`${INVALID} ${label} ${field} \"${path}\" must not contain \"@\" — there is a single state tree per root.${LINT_HINT}`);\r\n }\r\n if (path in Object.prototype) {\r\n raiseError(`${INVALID} ${label} ${field} \"${path}\" must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").${LINT_HINT}`);\r\n }\r\n const pathInfo = getPathInfo(path);\r\n for (const segment of pathInfo.segments) {\r\n if (segment.length === 0) {\r\n raiseError(`${INVALID} ${label} ${field} \"${path}\" has an empty path segment.${LINT_HINT}`);\r\n }\r\n }\r\n if (pathInfo.wildcardCount > MAX_WILDCARD_DEPTH) {\r\n raiseError(`${INVALID} ${label} ${field} \"${path}\" exceeds the maximum wildcard depth (${MAX_WILDCARD_DEPTH}).`);\r\n }\r\n return pathInfo;\r\n}\r\n\r\nfunction collectStreamNames(state: IState): ReadonlySet<string> {\r\n // 旧名(`$streams`)で宣言した state も読めるように(要件 B12 — 入口を経ない呼び出しでも効く。冪等)\r\n normalizeDeclarationAliases(state);\r\n const streams = (state as Record<string, unknown>)[STATE_STREAMS_NAME];\r\n if (typeof streams !== \"object\" || streams === null) {\r\n return new Set<string>();\r\n }\r\n return new Set(Object.keys(streams));\r\n}\r\n\r\nfunction assertOutputName(\r\n name: string,\r\n getterPaths: ReadonlySet<string>,\r\n setterPaths: ReadonlySet<string>,\r\n streamNames: ReadonlySet<string>,\r\n): void {\r\n const label = entryLabel(name);\r\n if (name.length === 0) {\r\n raiseError(`${INVALID} ${STATE_SCAN_NAME} entry name must be a non-empty string.${LINT_HINT}`);\r\n }\r\n if (name.includes(DELIMITER) || name.includes(WILDCARD)) {\r\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}`);\r\n }\r\n if (name.startsWith(\"$\")) {\r\n raiseError(`${INVALID} ${label} must not start with \"$\" (reserved namespace).${LINT_HINT}`);\r\n }\r\n if (name in Object.prototype) {\r\n raiseError(`${INVALID} ${label} must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").${LINT_HINT}`);\r\n }\r\n if (getterPaths.has(name)) {\r\n raiseError(`${INVALID} ${label} conflicts with a getter declared on the state.${LINT_HINT}`);\r\n }\r\n if (setterPaths.has(name)) {\r\n raiseError(`${INVALID} ${label} conflicts with a setter declared on the state.${LINT_HINT}`);\r\n }\r\n if (streamNames.has(name)) {\r\n raiseError(`${INVALID} ${label} conflicts with the ${STATE_STREAMS_NAME} entry of the same name — each output has exactly one owner.${LINT_HINT}`);\r\n }\r\n}\r\n\r\n/**\r\n * 出力名がメソッド(関数値のプロパティ)と衝突していないか(D7)。\r\n *\r\n * 実体化は既にある値を保持するので、衝突を通すと最初の `acc` がメソッドになり、fold の結果が\r\n * メソッドを上書きする。`initial` 自身が関数で、その値が置かれている形だけは通す —\r\n * 同じオブジェクトの再セットで、実体化済みの出力を見ているだけだから。\r\n */\r\nfunction assertNoMethodConflict(\r\n name: string,\r\n functionValues: ReadonlyMap<string, unknown>,\r\n definition: Record<string, unknown>,\r\n): void {\r\n const value = functionValues.get(name);\r\n // fold・実体化・reset がこの出力に置いたことのある関数値なら、それは累積(同じオブジェクト・値のコピーの\r\n // 再セット・D7)。どの世代のオブジェクトに書かれたかに依らない。名前だけで通すと、新しいオブジェクトの\r\n // 同名の本物のメソッドを見逃す(§5-9 の C5-8 / C5-14)\r\n if (functionValues.has(name) && value !== definition.initial && !wasPlacedOnOutput(name, value)) {\r\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}`);\r\n }\r\n}\r\n\r\nfunction parseSource(\r\n name: string,\r\n definition: Record<string, unknown>,\r\n eventTokenNames: ReadonlySet<string>,\r\n getterPaths: ReadonlySet<string>,\r\n writeOnlyPaths: ReadonlySet<string>,\r\n recursion: IRecursiveGetterLookup | null,\r\n): ScanSource {\r\n const label = entryLabel(name);\r\n const hasFrom = typeof definition.from !== \"undefined\";\r\n const hasOn = typeof definition.on !== \"undefined\";\r\n if (hasFrom === hasOn) {\r\n raiseError(`${INVALID} ${label} must declare exactly one of \"from\" (a state path) or \"on\" (an event-token name).${LINT_HINT}`);\r\n }\r\n if (hasOn) {\r\n const tokenName = definition.on;\r\n if (typeof tokenName !== \"string\" || tokenName.length === 0) {\r\n raiseError(`${INVALID} ${label} \"on\" must be a non-empty event-token name.${LINT_HINT}`);\r\n }\r\n if (!eventTokenNames.has(tokenName)) {\r\n raiseError(`${INVALID} ${label} on \"${tokenName}\" is not declared in ${STATE_EVENT_TOKENS_NAME}.${didYouMean(tokenName, eventTokenNames)}${LINT_HINT}`);\r\n }\r\n return { kind: \"event\", tokenName };\r\n }\r\n const path = definition.from;\r\n if (typeof path !== \"string\") {\r\n raiseError(`${INVALID} ${label} \"from\" must be a state path string.${LINT_HINT}`);\r\n }\r\n const pathInfo = assertValidScanPath(label, \"from\", path);\r\n // `**` getter の展開形(`nodes.*.total`)とその値の内側も getter。字面の getterPaths には `**` の形しか\r\n // 載らないので、再帰レジストリで引く(pathDiagnostics の checkDeclaredPath と同じ判定)。\r\n // 展開形は必ず `*` を含むので `resetOn` はワイルドカードの検査で先に落ちる\r\n const getter = findGetterOnPath(pathInfo, getterPaths) ?? recursion?.recursiveGetterOwning(path) ?? null;\r\n if (getter !== null) {\r\n raiseError(computedMessage(label, \"from\", path, getter));\r\n }\r\n // getter の無い setter は読むと常に undefined(`resetOn` は値を読まない引き金なので通す)\r\n const setter = findGetterOnPath(pathInfo, writeOnlyPaths);\r\n if (setter !== null) {\r\n raiseError(writeOnlyMessage(label, path, setter));\r\n }\r\n if (path === name || path.startsWith(name + DELIMITER)) {\r\n raiseError(`${INVALID} ${label} from \"${path}\" reads the entry's own output — the scan would fold its own writes forever.${LINT_HINT}`);\r\n }\r\n return { kind: \"path\", path, pathInfo };\r\n}\r\n\r\nfunction parseResetOn(\r\n name: string,\r\n raw: unknown,\r\n source: ScanSource,\r\n getterPaths: ReadonlySet<string>,\r\n): readonly string[] {\r\n if (typeof raw === \"undefined\") {\r\n return NO_RESET;\r\n }\r\n const label = entryLabel(name);\r\n if (!Array.isArray(raw)) {\r\n raiseError(`${INVALID} ${label} \"resetOn\" must be an array of state paths.${LINT_HINT}`);\r\n }\r\n const paths: string[] = [];\r\n for (const item of raw) {\r\n if (typeof item !== \"string\") {\r\n raiseError(`${INVALID} ${label} \"resetOn\" must contain only state path strings.${LINT_HINT}`);\r\n }\r\n const pathInfo = assertValidScanPath(label, \"resetOn\", item);\r\n if (pathInfo.wildcardCount > 0) {\r\n raiseError(`${INVALID} ${label} resetOn \"${item}\" must not contain \"${WILDCARD}\" — a reset returns the whole output to \"initial\".${LINT_HINT}`);\r\n }\r\n const getter = findGetterOnPath(pathInfo, getterPaths);\r\n if (getter !== null) {\r\n raiseError(computedMessage(label, \"resetOn\", item, getter));\r\n }\r\n if (source.kind === \"path\" && item === source.path) {\r\n raiseError(`${INVALID} ${label} resetOn \"${item}\" is the entry's own \"from\" — every change would reset instead of fold.${LINT_HINT}`);\r\n }\r\n // 子孫は死に設定: `from` を書くと依存展開で子孫も同じバッチに載り、reset が毎回勝つ。\r\n // 祖先(`from: \"items.*.qty\"` × `resetOn: [\"items\"]`)は「親の差し替えで作り直す」として通す\r\n if (source.kind === \"path\" && item.startsWith(source.path + DELIMITER)) {\r\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}`);\r\n }\r\n paths.push(item);\r\n }\r\n return paths;\r\n}\r\n\r\n/**\r\n * scan 出力を介した参照の検査(エントリを跨ぐもの):\r\n * - `resetOn` が scan 出力(自他とも)を読む = 累積が累積を消すフィードバック。\r\n * - `from` の根を辿って scan 同士が循環する = 互いの書き込みで永久に畳み合う。\r\n * 各 scan の `from` は 1 本なので、辿る先は高々 1 つ(関数グラフ)。\r\n */\r\nfunction assertNoOutputReferences(entries: readonly IScanEntry[]): void {\r\n const outputs = new Set(entries.map((entry) => entry.name));\r\n const next = new Map<string, string>();\r\n for (const entry of entries) {\r\n for (const path of entry.resetOn) {\r\n const root = getPathInfo(path).segments[0];\r\n if (outputs.has(root)) {\r\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}`);\r\n }\r\n }\r\n if (entry.source.kind === \"path\") {\r\n const root = entry.source.pathInfo.segments[0];\r\n if (outputs.has(root)) {\r\n next.set(entry.name, root);\r\n }\r\n }\r\n }\r\n for (const start of next.keys()) {\r\n const chain = [start];\r\n let current = next.get(start);\r\n while (typeof current !== \"undefined\" && chain.length <= outputs.size) {\r\n if (current === start) {\r\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}`);\r\n }\r\n chain.push(current);\r\n current = next.get(current);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * `$scan` 宣言の検査(`value` だけを読む)。宣言が無い・空なら null。\r\n *\r\n * getter / setter の判定は `value` の property descriptor から直接取る(`_getterPaths` は\r\n * この時点ではまだ旧世代のもの)。`$streams` 名との衝突も `value` の宣言から見る。\r\n * `recursion` は `value` から作った `$recursion` のレジストリ(宣言が無ければ null)。\r\n */\r\nexport function parseScanDeclaration(\r\n state: IState,\r\n eventTokenNames: ReadonlySet<string>,\r\n recursion: IRecursiveGetterLookup | null = null,\r\n): readonly IScanEntry[] | null {\r\n const declared = (state as Record<string, unknown>)[STATE_SCAN_NAME];\r\n if (typeof declared === \"undefined\") {\r\n return null;\r\n }\r\n if (typeof declared !== \"object\" || declared === null || Array.isArray(declared)) {\r\n raiseError(`${INVALID} ${STATE_SCAN_NAME} must be an object mapping output names to scan definitions ({ from | on, initial, fold, resetOn? }).${LINT_HINT}`);\r\n }\r\n const getterPaths = new Set<string>();\r\n const setterPaths = new Set<string>();\r\n const writeOnlyPaths = new Set<string>();\r\n const functionValues = new Map<string, unknown>();\r\n for (const [key, descriptor] of Object.entries(getAllPropertyDescriptors(state))) {\r\n if (typeof descriptor.get === \"function\") {\r\n getterPaths.add(key);\r\n } else if (typeof descriptor.set === \"function\") {\r\n writeOnlyPaths.add(key);\r\n }\r\n if (typeof descriptor.set === \"function\") {\r\n setterPaths.add(key);\r\n }\r\n if (typeof descriptor.value === \"function\") {\r\n functionValues.set(key, descriptor.value);\r\n }\r\n }\r\n const streamNames = collectStreamNames(state);\r\n const entries: IScanEntry[] = [];\r\n let order = 0;\r\n for (const [name, def] of Object.entries(declared as Record<string, unknown>)) {\r\n assertOutputName(name, getterPaths, setterPaths, streamNames);\r\n // 配列もオブジェクトとして読まない(`$scan` 自体の検査と同じ。静的検証も同じ文言で拾う)\r\n if (typeof def !== \"object\" || def === null || Array.isArray(def)) {\r\n raiseError(`${INVALID} ${entryLabel(name)} must be an object ({ from | on, initial, fold, resetOn? }).${LINT_HINT}`);\r\n }\r\n const definition = def as Record<string, unknown>;\r\n assertNoMethodConflict(name, functionValues, definition);\r\n const source = parseSource(name, definition, eventTokenNames, getterPaths, writeOnlyPaths, recursion);\r\n if (!(\"initial\" in definition)) {\r\n raiseError(`${INVALID} ${entryLabel(name)} requires \"initial\" — the seed of the accumulator and the value \"resetOn\" returns to.${LINT_HINT}`);\r\n }\r\n if (typeof definition.fold !== \"function\") {\r\n raiseError(`${INVALID} ${entryLabel(name)} fold must be a function.${LINT_HINT}`);\r\n }\r\n const resetOn = parseResetOn(name, definition.resetOn, source, getterPaths);\r\n entries.push({\r\n name,\r\n source,\r\n fold: definition.fold as ScanFold,\r\n initial: definition.initial,\r\n resetOn,\r\n order: order++,\r\n });\r\n }\r\n assertNoOutputReferences(entries);\r\n return entries.length > 0 ? entries : null;\r\n}\r\n\r\n/**\r\n * 出力の実体化(設計書 D7)。未定義なら `initial` を置き、既に値があれば保持する\r\n * (同じオブジェクトの再セット・SSR ハイドレーションで累積を失わない)。plain な配列とオブジェクトは\r\n * 複製して置く — 出力が `initial` の間に子パスへ書いても宣言の `initial` を書き換えない(scan/initialValue.ts)。\r\n */\r\nexport function materializeScanOutputs(state: IState, entries: readonly IScanEntry[]): void {\r\n for (const entry of entries) {\r\n if (!(entry.name in state)) {\r\n const value = cloneInitial(entry.initial);\r\n (state as Record<string, unknown>)[entry.name] = value;\r\n recordOutputValue(entry.name, value);\r\n }\r\n }\r\n}\r\n\r\nfunction createEventFold(entry: IScanEntry): TokenSubscriber {\r\n const fold = entry.fold;\r\n return (state: unknown, event: unknown, ...indexes: unknown[]): void => {\r\n const proxy = state as IStateProxy;\r\n // 報告を「出力を読めなかった」「fold が throw した」「出力を書けなかった」で分ける\r\n let failure: ScanFailure = \"read-output\";\r\n try {\r\n const current = proxy[entry.name];\r\n failure = \"threw\";\r\n // `resetOn` の書き込みより後の出来事は、reset 後の出力に畳む(scan/eventReset.ts)\r\n const reset = hasPendingScanReset(entry);\r\n // reset 後の出力から畳む。出力が既に initial と同じ値ならそのまま、違えば複製から(宣言の initial は渡さない)\r\n const acc = reset && !isSameAsInitial(current, entry.initial) ? cloneInitial(entry.initial) : current;\r\n const next = fold(acc, event, ...indexes);\r\n if (isThenable(next)) {\r\n // 保留は残す — drain が出力を initial に戻す\r\n reportScanThenable(entry.name, next);\r\n return;\r\n }\r\n if (!Object.is(next, current)) {\r\n failure = \"write\";\r\n proxy[entry.name] = next;\r\n recordOutputValue(entry.name, next);\r\n }\r\n // 保留は書き込みが通ってから消す。書き込みが throw したら残し、drain が initial に戻す(§2-2)\r\n if (reset) {\r\n consumePendingScanReset(entry);\r\n }\r\n } catch (error) {\r\n // 後続の subscriber(同じトークンの `$on`)を巻き添えにしない\r\n reportScanError(entry.name, error, failure);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * `on` の scan を event-token の subscriber として登録する(設計書 §2-2)。\r\n * 購読の寿命は `$on` と同じ(`_state` の再セットで `clearEventTokenRegistry` の後に張り直す。\r\n * 切断では消えないので、ルート `<wcs-state>` の再接続の後も畳み続ける — Issue #273)。\r\n */\r\nexport function subscribeScanEvents(stateElement: IStateElement, entries: readonly IScanEntry[]): void {\r\n for (const entry of entries) {\r\n if (entry.source.kind === \"event\") {\r\n getOrCreateEventToken(stateElement, entry.source.tokenName).subscribe(createEventFold(entry));\r\n }\r\n }\r\n}\r\n\r\n/** 再セットで引き継ぐ `on` scan の保留 reset(出力名 → 旧宣言の `resetOn`) */\r\nexport type ScanResetCarry = ReadonlyMap<string, readonly string[]>;\r\n\r\n/**\r\n * registry を外す(`_state` 再セットで作り直す前)。旧宣言の `on` scan に立っていた保留 reset は、\r\n * 新しい宣言の entry(別のオブジェクト)へ引き継ぐ候補として返し、旧 entry からは消す\r\n * (残すと誰にも使われず、保留の数 — scan/eventReset.ts の捨てる走査のゲート — だけが戻らない)。\r\n */\r\nexport function unregisterScans(stateElement: IStateElement): ScanResetCarry {\r\n const carry = new Map<string, readonly string[]>();\r\n const registry = getScanRegistry(stateElement);\r\n if (typeof registry !== \"undefined\") {\r\n for (const entry of registry.entries) {\r\n if (consumePendingScanReset(entry)) {\r\n carry.set(entry.name, entry.resetOn);\r\n }\r\n }\r\n }\r\n clearScanRegistry(stateElement);\r\n return carry;\r\n}\r\n\r\n/**\r\n * registry を作り、`from` / `resetOn` を依存グラフへ登録する。`from` パスの集合\r\n * (旧値キャプチャのゲート)を返す。無ければ null。\r\n *\r\n * 依存グラフ登録が要る理由は `$watch` と同じ(docs/state-watch-hook-design.md §8):\r\n * `setPathInfo` はバインドからしか呼ばれないので、宣言しただけでは祖先への書き込みが\r\n * このパスへ展開されず、バッチに載らない。\r\n *\r\n * `carry`(unregisterScans の戻り値)の保留 reset は、同じ出力名の `on` scan が、まだ drain されていない\r\n * 書き込み(updater のキューに積まれているパス)を新旧どちらの `resetOn` にも持つときだけ引き継ぐ(D6)。\r\n * 旧宣言の保留は発火対象の state への書き込みでしか立たないので、「enqueue の時点で立つ」契約は保たれる。\r\n * 引き継がないと、書き込みより後のイベントが reset されていない出力に畳まれ、drain でも戻らない\r\n * (同じバッチの `from` の scan は reset される)。\r\n */\r\nexport function registerScans(\r\n stateElement: IStateElement,\r\n entries: readonly IScanEntry[],\r\n carry: ScanResetCarry,\r\n): ReadonlySet<string> | null {\r\n const registry = setScanRegistry(stateElement, entries);\r\n for (const entry of entries) {\r\n const carried = carry.get(entry.name);\r\n if (entry.source.kind !== \"event\" || typeof carried === \"undefined\") {\r\n continue;\r\n }\r\n if (entry.resetOn.some((path) => carried.includes(path) && getUpdater().hasQueuedPath(stateElement, path))) {\r\n markPendingScanReset(entry);\r\n }\r\n }\r\n const fromPaths = new Set<string>();\r\n for (const path of registry.byFromPath.keys()) {\r\n fromPaths.add(path);\r\n stateElement.setPathInfo(path, \"prop\", \"scan\");\r\n }\r\n for (const path of registry.byResetPath.keys()) {\r\n stateElement.setPathInfo(path, \"prop\", \"scan\");\r\n }\r\n return fromPaths.size > 0 ? fromPaths : null;\r\n}\r\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 { normalizeDeclarationAliases } from \"../declarationAliases\";\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 // 旧名(`$streams`)で宣言した state も読めるように(要件 B12 — 入口を経ない呼び出しでも効く。冪等)\n normalizeDeclarationAliases(state);\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","normalizeDeclarationAliases","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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"}