@wcstack/state 3.1.0 → 3.3.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 (56) hide show
  1. package/README.ja.md +128 -90
  2. package/README.md +129 -91
  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 +58 -15
  7. package/dist/index.esm.js +1 -1
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/manifest.d.ts +39 -5
  10. package/dist/manifest.esm.js +315 -253
  11. package/dist/parser.d.ts +16 -2
  12. package/dist/parser.esm.js +223 -50
  13. package/dist/split/chunks/binder.js +1 -1
  14. package/dist/split/chunks/binder.js.map +1 -1
  15. package/dist/split/chunks/checkDependency.js +1 -1
  16. package/dist/split/chunks/declarationAliases.js +2 -0
  17. package/dist/split/chunks/declarationAliases.js.map +1 -0
  18. package/dist/split/chunks/declarationHooks.js +2 -0
  19. package/dist/split/chunks/declarationHooks.js.map +1 -0
  20. package/dist/split/chunks/featureBridge.js +2 -0
  21. package/dist/split/chunks/featureBridge.js.map +1 -0
  22. package/dist/split/chunks/filterRegistry.js +1 -1
  23. package/dist/split/chunks/filterRegistry.js.map +1 -1
  24. package/dist/split/chunks/getAllPropertyDescriptors.js +1 -1
  25. package/dist/split/chunks/getAllPropertyDescriptors.js.map +1 -1
  26. package/dist/split/chunks/lifecycleHooks.js +1 -1
  27. package/dist/split/chunks/pathDiagnostics.js +1 -1
  28. package/dist/split/chunks/pathDiagnostics.js.map +1 -1
  29. package/dist/split/chunks/registerComponents.js +1 -1
  30. package/dist/split/chunks/registerComponents.js.map +1 -1
  31. package/dist/split/chunks/setAll.js +1 -1
  32. package/dist/split/chunks/setAll.js.map +1 -1
  33. package/dist/split/chunks/version.js +1 -1
  34. package/dist/split/core.d.ts +21 -9
  35. package/dist/split/core.js +1 -1
  36. package/dist/split/core.js.map +1 -1
  37. package/dist/split/features/devtools.js +1 -1
  38. package/dist/split/features/devtools.js.map +1 -1
  39. package/dist/split/features/diagnostics.js +1 -1
  40. package/dist/split/features/diagnostics.js.map +1 -1
  41. package/dist/split/features/formats.js +1 -1
  42. package/dist/split/features/formats.js.map +1 -1
  43. package/dist/split/features/recursion.js +1 -1
  44. package/dist/split/features/recursion.js.map +1 -1
  45. package/dist/split/features/scopes.js +1 -1
  46. package/dist/split/features/scopes.js.map +1 -1
  47. package/dist/split/features/ssr.js +1 -1
  48. package/dist/split/features/ssr.js.map +1 -1
  49. package/dist/split/features/temporal.js +1 -1
  50. package/dist/split/features/temporal.js.map +1 -1
  51. package/dist/wcs-manifest.json +98 -44
  52. package/package.json +1 -1
  53. package/dist/split/chunks/mount.js +0 -2
  54. package/dist/split/chunks/mount.js.map +0 -1
  55. package/dist/split/chunks/watchRuntime.js +0 -2
  56. package/dist/split/chunks/watchRuntime.js.map +0 -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/scanRegistry.ts","../../../../../src/scan/eventReset.ts","../../../../../src/scan/initialValue.ts","../../../../../src/scan/scanReport.ts","../../../../../src/scan/processScanDeclaration.ts","../../../../../src/scan/declarations.ts","../../../../../src/scan/scanFeedback.ts","../../../../../src/stream/lastNotified.ts","../../../../../src/stream/activeStateElements.ts","../../../../../src/stream/streamRegistry.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/watch/chainDepth.ts","../../../../../src/watch/computedSnapshots.ts","../../../../../src/watch/prevValues.ts","../../../../../src/watch/watchRegistry.ts","../../../../../src/watch/processWatchDeclaration.ts","../../../../../src/watch/addressHooks.ts","../../../../../src/watch/rowLanding.ts","../../../../../src/scan/scanRuntime.ts","../../../../../src/watch/watchRuntime.ts","../../../../../src/features/temporal.ts"],"sourcesContent":["/**\n * scan/scanRegistry.ts\n *\n * `$scan` の registry(docs/state-scan-design.md §2)。\n *\n * `$watch` の registry とは別台帳にする。watch の registry はパスにつき entry 1 個\n * (`Map<string, IWatchEntry>`)なので、同じパスを `$watch` と `$scan` が並んで\n * 見る形・同じ `from` を 2 つの scan が畳む形を載せられない。\n *\n * 寿命は `$watch` と揃える: `_state` 再セットで作り直し、切断では消さない\n * (発火対象から外れるのは watch runtime の active 集合側)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport type { IScanEntry, IScanRegistry } from \"./types\";\n\nconst registryByStateElement: WeakMap<IStateElement, IScanRegistry> = new WeakMap();\n\n/**\n * drain 側の粗いゲート: 発火対象(watch runtime の active 集合)に居て、`from` か `resetOn` を持つ state。\n *\n * 空のあいだ watch runtime は scan の収集ループに入らない = `$scan` を使っていない画面の drain に、\n * バッチのアドレスごとの registry 引きを載せない。registry の有無ではなく active 集合への出入り\n * (watch/watchRegistry.ts の addActiveWatchStateElement / deactivateWatch / clearWatchRegistry)で\n * 数えるので、`$scan` を持つ state を DOM から外せば(SPA のページ差し替え)ゲートは閉じ、\n * 再接続(startWatch)で開き直す。strong Set でも、切断と再セットで必ず外れるので GC を妨げない\n * (active 集合と同じ不変条件)。\n */\nconst drainActive = new Set<IStateElement>();\n\n/**\n * enqueue 側のゲート: 発火対象に居て、`resetOn` を持つ `on` scan がある state(scan/eventReset.ts)。\n * 空のあいだ updater の enqueue は整数比較 1 回で抜ける。数え方は drainActive と同じ。\n */\nconst eventResetActive = new Set<IStateElement>();\n\nfunction hasDrainWork(registry: IScanRegistry): boolean {\n return registry.byFromPath.size > 0 || registry.byResetPath.size > 0;\n}\n\nfunction hasEventResetWork(registry: IScanRegistry): boolean {\n return registry.eventResetByPath.size > 0;\n}\n\nfunction pushEntry(map: Map<string, IScanEntry[]>, key: string, entry: IScanEntry): void {\n const list = map.get(key);\n if (typeof list === \"undefined\") {\n map.set(key, [entry]);\n } else {\n list.push(entry);\n }\n}\n\n/** registry を置換登録する(`_state` セッターから)。 */\nexport function setScanRegistry(stateElement: IStateElement, entries: readonly IScanEntry[]): IScanRegistry {\n clearScanRegistry(stateElement);\n const byFromPath = new Map<string, IScanEntry[]>();\n const byResetPath = new Map<string, IScanEntry[]>();\n const eventResetByPath = new Map<string, IScanEntry[]>();\n for (const entry of entries) {\n if (entry.source.kind === \"path\") {\n pushEntry(byFromPath, entry.source.path, entry);\n }\n for (const path of entry.resetOn) {\n pushEntry(byResetPath, path, entry);\n if (entry.source.kind === \"event\") {\n pushEntry(eventResetByPath, path, entry);\n }\n }\n }\n const registry: IScanRegistry = { entries: new Set(entries), byFromPath, byResetPath, eventResetByPath };\n registryByStateElement.set(stateElement, registry);\n return registry;\n}\n\nexport function getScanRegistry(stateElement: IStateElement): IScanRegistry | undefined {\n return registryByStateElement.get(stateElement);\n}\n\n/**\n * registry を削除する(`_state` 再セットで作り直す前)。ゲートからも外す — 同じ再セットの\n * startWatch が新しい registry で数え直す(`_state` セッターは registry を作った後に\n * clearWatchRegistry → startWatch を通る)。\n */\nexport function clearScanRegistry(stateElement: IStateElement): void {\n deactivateScanGates(stateElement);\n registryByStateElement.delete(stateElement);\n}\n\n/** 発火対象に載った(watch/watchRegistry.ts の addActiveWatchStateElement 専用)。冪等。 */\nexport function activateScanGates(stateElement: IStateElement): void {\n const registry = registryByStateElement.get(stateElement);\n if (typeof registry === \"undefined\") {\n return;\n }\n if (hasDrainWork(registry)) {\n drainActive.add(stateElement);\n }\n if (hasEventResetWork(registry)) {\n eventResetActive.add(stateElement);\n }\n}\n\n/** 発火対象から外れた(切断・再セット)。 */\nexport function deactivateScanGates(stateElement: IStateElement): void {\n drainActive.delete(stateElement);\n eventResetActive.delete(stateElement);\n}\n\n/**\n * drain で発火すべき scan(`from` か `resetOn`)を持つか。\n * `startWatch` が発火対象集合へ載せる判定に使う(`on` だけの scan は drain を要らない)。\n */\nexport function hasScanDrainWork(stateElement: IStateElement): boolean {\n const registry = registryByStateElement.get(stateElement);\n return typeof registry !== \"undefined\" && hasDrainWork(registry);\n}\n\n/** 発火対象に居て、`resetOn` を持つ `on` scan がある state か(enqueue の保留判定)。 */\nexport function hasActiveScanEventReset(stateElement: IStateElement): boolean {\n return eventResetActive.has(stateElement);\n}\n\nexport function getScanDrainGateCount(): number {\n return drainActive.size;\n}\n\nexport function getScanEventResetGateCount(): number {\n return eventResetActive.size;\n}\n","/**\n * scan/eventReset.ts\n *\n * `on` scan の `resetOn` を「書き込みの時点」で効かせる台帳(docs/state-scan-design.md D6)。\n *\n * `on` の fold は出来事のその場で同期に書く。一方 `resetOn` のパスはバッチに載って drain の\n * 終わりにしか見えない。drain で reset するだけだと、reset の書き込みから drain までに起きた\n * 出来事 — その書き込みの binding 適用で要素が同期に dispatch したものを含む — まで消える。\n *\n * そこで reset の要求を enqueue の時点で entry に保留する。\n * - 保留中に来た出来事の fold は `initial` から畳み、出力の書き込みが通ったら保留を消す\n * (fold の throw・thenable・書き込みの throw なら残す)。\n * - 保留が残ったまま drain に来たら、scan runtime が出力を `initial` に戻して保留を消す。\n * これで「書き込みより後の出来事は reset 後の出力に畳まれる」順序になる。\n *\n * 保留は「その書き込みが載ったバッチの drain で initial に戻す」予約なので、寿命をそのバッチに\n * 揃える。drain がそのバッチの scan を発火しない(書き込みの後・drain の前に切断された・連鎖深さの\n * 上限で打ち切った・先行 fold が同期に切断や再セットをした)なら保留を捨てる。残すと、後の無関係な\n * 出来事が突然 `initial` から畳み始める。同じ条件の `from` の scan は reset しない(発火しない)ので、\n * それに揃える。保留は entry ごとの 1 bit でどのバッチの書き込みかを持たないので、同じ `resetOn` の\n * パスが次のバッチ向けに既に積まれていれば捨てない — その保留は次のバッチの drain が使う。\n *\n * updater(enqueue 側)から呼ばれるので updater を import しない(watch/chainDepth.ts と同じ理由)。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { getScanEventResetGateCount, getScanRegistry, hasActiveScanEventReset } from \"./scanRegistry\";\nimport type { IScanEntry } from \"./types\";\n\nconst pendingResets: WeakSet<IScanEntry> = new WeakSet();\n\n/**\n * 保留中の entry の数。捨てる走査(discardPendingScanResets)のゲート。保留は enqueue の直後の drain で\n * 使うか捨てるか次のバッチへ持ち越すので、ふつうは 0。enqueue のゲート(発火対象の state)と別に持つのは、\n * 書き込みの後・drain の前に切断された state がゲートから外れても、その保留は drain で捨てるため。\n */\nlet pendingResetCount = 0;\n\n/** このアドレスを `resetOn` に持つ `on` scan(無ければ undefined) */\nfunction eventResetEntriesAt(absAddress: IAbsoluteStateAddress): readonly IScanEntry[] | undefined {\n return getScanRegistry(absAddress.absolutePathInfo.stateElement)\n ?.eventResetByPath.get(absAddress.absolutePathInfo.pathInfo.path);\n}\n\n/**\n * 書き込みの enqueue を記録する(updater 専用)。\n * `resetOn` を持つ `on` scan が発火対象の state に 1 つも無ければ(そうした state を DOM から外した後を含む)、\n * 整数比較 1 回で抜ける。\n */\nexport function noteEnqueueForScanReset(absAddress: IAbsoluteStateAddress): void {\n if (getScanEventResetGateCount() === 0) {\n return;\n }\n // 発火対象でない state(切断中・初期化中・SSR)の書き込みは reset しない — drain 側と同じ扱い\n if (!hasActiveScanEventReset(absAddress.absolutePathInfo.stateElement)) {\n return;\n }\n const entries = eventResetEntriesAt(absAddress);\n if (typeof entries === \"undefined\") {\n return;\n }\n for (const entry of entries) {\n markPendingScanReset(entry);\n }\n}\n\n/**\n * 保留を立てる。enqueue の記録(上)と、`_state` 再セットで旧宣言の保留を同じ出力の `on` scan へ\n * 引き継ぐとき(processScanDeclaration.ts の registerScans)だけが呼ぶ。\n */\nexport function markPendingScanReset(entry: IScanEntry): void {\n if (!pendingResets.has(entry)) {\n pendingResets.add(entry);\n pendingResetCount++;\n }\n}\n\nexport function hasPendingScanReset(entry: IScanEntry): boolean {\n return pendingResets.has(entry);\n}\n\n/** 保留があれば消して true を返す。 */\nexport function consumePendingScanReset(entry: IScanEntry): boolean {\n if (!pendingResets.delete(entry)) {\n return false;\n }\n pendingResetCount--;\n return true;\n}\n\n/** 保留中の entry の数(テストと診断用)。 */\nexport function getPendingScanResetCount(): number {\n return pendingResetCount;\n}\n\n/**\n * drain がバッチの scan を発火しないとき、そのバッチが載せた保留を捨てる。\n * `firing` はこの drain で scan を発火する state の集合。null はバッチ全体を発火しない\n * (連鎖深さの上限)。`isQueued` は「次のバッチ向けに、この state のこのパスが積まれているか」\n * (updater を import しないので呼び出し側から受け取る)。\n */\nexport function discardPendingScanResets(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n firing: ReadonlySet<IStateElement> | null,\n isQueued: (stateElement: IStateElement, path: string) => boolean,\n): void {\n if (pendingResetCount === 0) {\n return;\n }\n for (const absAddress of batch) {\n const stateElement = absAddress.absolutePathInfo.stateElement;\n if (firing?.has(stateElement) === true) {\n continue;\n }\n const entries = eventResetEntriesAt(absAddress);\n if (typeof entries === \"undefined\") {\n continue;\n }\n for (const entry of entries) {\n if (!entry.resetOn.some((path) => isQueued(stateElement, path))) {\n consumePendingScanReset(entry);\n }\n }\n }\n}\n","/**\n * scan/initialValue.ts\n *\n * 出力に置く `initial` の複製と、「出力がいま `initial` と同じ値か」の判定\n * (docs/state-scan-design.md D6 / D7・§5-9)。\n *\n * 実体化と reset が宣言の `initial` をそのまま置くと、出力が `initial` の間に子パスへ書いた値\n * (`$watch` ハンドラの注記など)が宣言の `initial` 自体を書き換える。以後の reset はその値に戻し、\n * 出力が同じ参照なので書き込みもしない。そこで plain なデータは複製して置く。\n *\n * plain なデータ: プロトタイプが `Array.prototype` / `Object.prototype` / null で、凍結されておらず、\n * 自前のプロパティがすべて列挙できる文字列キーのデータプロパティ(配列は添字と `length` だけ)の\n * 配列とオブジェクト。判定は property descriptor で行い、getter を実行しない。それ以外\n * (getter / setter・Symbol キー・列挙できないプロパティ・配列の追加プロパティ・Array のサブクラス・\n * 凍結された値・関数・クラスのインスタンス・Map / Set・Date・DOM ノード)は参照のまま置く。\n *\n * 「reset で出力が既に `initial` なら書かない」は、参照ではなく値で見る。plain なデータは中身を再帰で\n * 比べ、それ以外は同一性で比べる。訪れた対を覚えるので、形の違う循環でも止まる。\n */\n\ntype PlainKind = \"array\" | \"object\";\n\nconst ARRAY_INDEX = /^(?:0|[1-9]\\d*)$/;\n\nfunction isEnumerableData(target: object, key: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor;\n return descriptor.enumerable === true && \"value\" in descriptor;\n}\n\n/** plain なデータならその種類、そうでなければ null(参照のまま扱う)。 */\nfunction plainKind(value: unknown): PlainKind | null {\n if (typeof value !== \"object\" || value === null || Object.isFrozen(value)) {\n return null;\n }\n const proto: unknown = Object.getPrototypeOf(value);\n if (Array.isArray(value)) {\n const plainArray = proto === Array.prototype && Reflect.ownKeys(value).every(\n (key) => key === \"length\" || (typeof key === \"string\" && ARRAY_INDEX.test(key) && isEnumerableData(value, key)),\n );\n return plainArray ? \"array\" : null;\n }\n const plainObject = (proto === Object.prototype || proto === null) && Reflect.ownKeys(value).every(\n (key) => typeof key === \"string\" && isEnumerableData(value, key),\n );\n return plainObject ? \"object\" : null;\n}\n\nfunction cloneValue(value: unknown, copies: Map<object, unknown>): unknown {\n const kind = plainKind(value);\n if (kind === null) {\n return value;\n }\n const source = value as Record<string, unknown>;\n const known = copies.get(source);\n if (typeof known !== \"undefined\") {\n return known;\n }\n let copy: Record<string, unknown>;\n if (kind === \"array\") {\n // 穴はそのまま(添字のキーだけを写す)\n copy = new Array((value as unknown[]).length) as unknown as Record<string, unknown>;\n } else {\n copy = Object.getPrototypeOf(value) === null ? Object.create(null) : {};\n }\n copies.set(source, copy);\n for (const key of Object.keys(source)) {\n copy[key] = cloneValue(source[key], copies);\n }\n return copy;\n}\n\n/** plain なデータを再帰で複製する。それ以外の値は参照のまま返す(循環と共有参照も保つ)。 */\nexport function cloneInitial<T>(initial: T): T {\n return cloneValue(initial, new Map()) as T;\n}\n\nfunction sameValue(current: unknown, initial: unknown, compared: Map<object, Set<object>>): boolean {\n if (Object.is(current, initial)) {\n return true;\n }\n // 宣言側の種類を先に決め、配列の長さ・キーの数が違えば、出力側の descriptor を見ずに抜ける\n // (大きく積み上がった出力を空の initial と比べるたびに、出力の大きさに比例させない)\n const kind = plainKind(initial);\n if (kind === null || typeof current !== \"object\" || current === null) {\n return false;\n }\n const left = current as Record<string, unknown>;\n const right = initial as Record<string, unknown>;\n if (kind === \"array\") {\n if (!Array.isArray(current) || current.length !== (initial as unknown[]).length) {\n return false;\n }\n } else if (Array.isArray(current) || Object.keys(left).length !== Object.keys(right).length) {\n return false;\n }\n if (plainKind(current) !== kind) {\n return false;\n }\n // 訪れた対を出力側の値ごとの集合で覚える。形の違う循環(自己循環と 2 段の循環など)でも、同じ対の 2 回目で止まる\n let seen = compared.get(left);\n if (typeof seen === \"undefined\") {\n seen = new Set();\n compared.set(left, seen);\n } else if (seen.has(right)) {\n return true;\n }\n seen.add(right);\n if (kind === \"array\") {\n for (let index = 0; index < (current as unknown[]).length; index++) {\n if (!sameValue(left[index], right[index], compared)) {\n return false;\n }\n }\n return true;\n }\n return Object.keys(right).every(\n (key) => Object.prototype.hasOwnProperty.call(left, key) && sameValue(left[key], right[key], compared),\n );\n}\n\n/** 出力が `initial` と同じ値か(plain なデータは中身を、それ以外は同一性を比べる)。 */\nexport function isSameAsInitial(current: unknown, initial: unknown): boolean {\n return sameValue(current, initial, new Map());\n}\n\n/**\n * 実体化・fold・reset が出力に置いた関数値と、その出力名(docs/state-scan-design.md D7・§5-9 の C5-14)。\n *\n * fold が関数を返す出力は、再セットの宣言検査で state の関数値として見える。それがこの出力に置いた値なら\n * 累積で、メソッドとの衝突ではない。どの世代の state オブジェクトに書かれたか(世代を進めた後に throw した\n * 再セットの後は、新しい `__state` にだけ書かれる)に依らず判定できるよう、値そのものを記録する。\n * 関数は WeakMap のキーなので、出力から外れれば記録ごと回収される。\n */\nconst outputNamesByFunction: WeakMap<object, Set<string>> = new WeakMap();\n\n/** 出力に置いた値を記録する(関数のときだけ残す)。 */\nexport function recordOutputValue(name: string, value: unknown): void {\n if (typeof value !== \"function\") {\n return;\n }\n const names = outputNamesByFunction.get(value);\n if (typeof names === \"undefined\") {\n outputNamesByFunction.set(value, new Set([name]));\n } else {\n names.add(name);\n }\n}\n\n/** その関数値を、実体化・fold・reset がこの出力に置いたことがあるか。 */\nexport function wasPlacedOnOutput(name: string, value: unknown): boolean {\n return typeof value === \"function\" && outputNamesByFunction.get(value)?.has(name) === true;\n}\n","/**\n * scan/scanReport.ts\n *\n * `$scan` の失敗の報告(docs/state-scan-design.md D4 / D5)。\n *\n * 値の読み・fold・出力の書き込みの例外は scan 側で閉じる(drain リスナーと event-token の\n * emit ループを他の機構と共有しているため)。閉じた事実を console と devtools の両方に出す。\n * devtools には `$watch` と同じ `state:watch-error` を path `$scan.<出力名>` で流し、phase は\n * 直し方で分ける: 値を読めなかった(`evaluate`)・fold が契約を破った(`fold`)・出力を\n * 書けなかった(`write`)。読みの失敗は console の文言でさらに 3 つに分ける:\n * 出力(`read-output`)・`from` の行の位置(`read-rows`)・行の値(`read-source`)。\n */\n\nimport { STATE_SCAN_NAME } from \"../define\";\nimport { devtoolsSink } from \"../platform/devtoolsSink\";\n\n/** 失敗の種類。原因も直し方も違うので console の文言を分ける */\nexport type ScanFailure = \"read-source\" | \"read-rows\" | \"read-output\" | \"threw\" | \"returned-promise\" | \"write\";\n\ntype ScanPhase = \"evaluate\" | \"fold\" | \"write\";\n\nconst SCAN_FAILURE_MESSAGE: Readonly<Record<ScanFailure, (name: string) => string>> = {\n \"read-source\": (name) =>\n `${STATE_SCAN_NAME} could not read a \"from\" value for \"${name}\". That landing was not folded; the other landings of the batch still were.`,\n \"read-rows\": (name) => `${STATE_SCAN_NAME} could not read the rows of \"from\" for \"${name}\". Nothing was folded or written.`,\n \"read-output\": (name) => `${STATE_SCAN_NAME} could not read the output \"${name}\". Nothing was folded or written.`,\n threw: (name) => `${STATE_SCAN_NAME} fold for \"${name}\" threw. The output was not written.`,\n \"returned-promise\": (name) =>\n `${STATE_SCAN_NAME} fold for \"${name}\" returned a Promise. fold must be synchronous and return the next value; the output was not written.`,\n write: (name) => `${STATE_SCAN_NAME} could not write the output \"${name}\".`,\n};\n\nconst SCAN_FAILURE_PHASE: Readonly<Record<ScanFailure, ScanPhase>> = {\n \"read-source\": \"evaluate\",\n \"read-rows\": \"evaluate\",\n \"read-output\": \"evaluate\",\n threw: \"fold\",\n \"returned-promise\": \"fold\",\n write: \"write\",\n};\n\nfunction sendToDevtools(name: string, phase: ScanPhase, error: unknown): void {\n if (devtoolsSink !== null) {\n devtoolsSink({\n type: \"state:watch-error\",\n phase,\n path: `${STATE_SCAN_NAME}.${name}`,\n error,\n });\n }\n}\n\nexport function reportScanError(name: string, error: unknown, failure: ScanFailure): void {\n console.error(`[@wcstack/state] ${SCAN_FAILURE_MESSAGE[failure](name)}`, error);\n sendToDevtools(name, SCAN_FAILURE_PHASE[failure], error);\n}\n\nexport function isThenable(value: unknown): boolean {\n return value !== null\n && (typeof value === \"object\" || typeof value === \"function\")\n && typeof (value as { then?: unknown }).then === \"function\";\n}\n\n/**\n * fold が thenable を返した(同期契約違反)。書き込まずに報告し、\n * 後から reject されても unhandled rejection にしない。\n */\nexport function reportScanThenable(name: string, value: unknown): void {\n (value as PromiseLike<unknown>).then(undefined, () => undefined);\n reportScanError(\n name,\n new TypeError(`${STATE_SCAN_NAME} fold for \"${name}\" returned a Promise. fold must be synchronous and return the next value.`),\n \"returned-promise\",\n );\n}\n\nconst lateGetterReported: WeakSet<object> = new WeakSet();\n\n/**\n * 宣言時には plain だった `from` が、接ぎ木(ボリュームのアクセサ登録)で後から getter に\n * なった(設計書 D5 後段)。getter の再評価回数を畳まないよう、その scan を止める。\n * entry につき 1 回だけ報告する。fold を適用しないと決めた失敗なので devtools の phase は `fold`。\n */\nexport function reportLateGetterSource(entry: object, name: string, path: string): void {\n if (lateGetterReported.has(entry)) {\n return;\n }\n lateGetterReported.add(entry);\n const message = `[wcs/scan-source-computed] ${STATE_SCAN_NAME} entry \"${name}\" from \"${path}\" is now backed by a getter ` +\n `(registered after the declaration, e.g. by a volume). A getter re-evaluates whenever its inputs change, ` +\n `so this scan stopped folding. Fold the plain value the getter reads instead.`;\n console.error(`[@wcstack/state] ${message}`);\n sendToDevtools(name, \"fold\", new Error(message));\n}\n","/**\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_STREAM_NAME, WILDCARD } from \"../define\";\nimport { normalizeDeclarationAliases } from \"../declarationAliases\";\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 // 旧名(`$streams`)で宣言した state も読めるように(要件 B12 — 入口を経ない呼び出しでも効く。冪等)\n normalizeDeclarationAliases(state);\n const streams = (state as Record<string, unknown>)[STATE_STREAM_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_STREAM_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_STREAM_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_STREAM_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/lastNotified.ts\n *\n * 「最後に通知した観測値」台帳 — DOM binding / $updatedCallback(観測層)が\n * 最後に見た status・error(docs/state-streams-design.md §4-3)。\n *\n * 通知の same-value 判定を entry フィールドとの比較で行うと、再 set\n * (clearStreamRegistry → 新 entry 生成)を跨いだ陳腐化を検出できない\n * (error 表示中に再 set すると新 entry は error=null で生まれるため\n * null → null と誤判定して $postUpdate が落ち、DOM に旧 error が残る)。\n * そのため通知 dedup は entry の寿命ではなく stateElement の寿命で持つ\n * (ただし再 set で新宣言から消えた名前のエントリは pruneLastNotified で削除する —\n * 同名にしか dedup は要らず、放置すると台帳が単調増加するため)。\n * 未通知(初回)の基準値は宣言直後の観測初期値と同じ { idle, null }。\n *\n * さらに abortAllStreams(§5-1)は registry entry を通知なしで idle / null に\n * 直接ミューテーションするため、観測層が「台帳の値」と「idle / null」の\n * どちらを見たか確定できなくなる(binding / computed の fresh 読みは通知が\n * なくても他パスの drain で走る)。その乖離フィールドは invalidateLastNotified\n * で UNCERTAIN に無効化し、次回 updateStreamStatus の同値判定が必ず\n * 「変化あり」になるようにする(再接続ウィンドウ内の idle 描画が恒久陳腐化\n * しないための不変条件、§4-3)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport type { StreamStatus } from \"./types\";\n\n/**\n * 無通知ミューテーション後の「観測値が確定できない」印。\n * どの実値とも一致しないため、次回の通知 dedup(`!==` / `Object.is`)を強制的に解除する。\n */\nconst UNCERTAIN: unique symbol = Symbol(\"wcs-stream-last-notified-uncertain\");\n\nexport interface ILastNotified {\n status: StreamStatus | typeof UNCERTAIN;\n error: unknown;\n}\n\nconst lastNotifiedByStateElement = new WeakMap<IStateElement, Map<string, ILastNotified>>();\n\n/**\n * 最後に通知した観測値を返す。未通知なら基準値 { idle, null }。\n */\nexport function getLastNotified(stateElement: IStateElement, name: string): ILastNotified {\n return (\n lastNotifiedByStateElement.get(stateElement)?.get(name) ?? { status: \"idle\", error: null }\n );\n}\n\n/**\n * 通知した観測値を記録する(updateStreamStatus が $postUpdate 発行と同時に呼ぶ)。\n */\nexport function setLastNotified(\n stateElement: IStateElement,\n name: string,\n status: StreamStatus,\n error: unknown,\n): void {\n let lastMap = lastNotifiedByStateElement.get(stateElement);\n if (typeof lastMap === \"undefined\") {\n lastMap = new Map();\n lastNotifiedByStateElement.set(stateElement, lastMap);\n }\n lastMap.set(name, { status, error });\n}\n\n/**\n * 再 set(clearStreamRegistry → processStreamsDeclaration)後に呼び、新宣言に\n * 存在しない名前の台帳エントリを削除する。台帳は stateElement の寿命で生存するが\n * (§4-3 の再 set・再接続跨ぎ dedup)、それが必要なのは同名エントリのみで、\n * 旧宣言にしか無い名前は以後どの通知経路(updateStreamStatus)からも参照されない。\n * prune しないと、再 set のたびに異なる stream 名を使うステートで台帳が\n * stateElement の寿命の間単調増加する。\n * 既知の許容: prune 後に同名を再宣言した場合、dedup は基準値 { idle, null } から\n * やり直しになる(宣言削除時の binding 陳腐化が §4-4 の既知エッジである以上、\n * 再宣言は新規宣言と同じ扱いでよい)。\n */\nexport function pruneLastNotified(stateElement: IStateElement, liveNames: ReadonlySet<string>): void {\n const lastMap = lastNotifiedByStateElement.get(stateElement);\n if (typeof lastMap === \"undefined\") {\n return;\n }\n for (const name of lastMap.keys()) {\n if (!liveNames.has(name)) {\n lastMap.delete(name);\n }\n }\n}\n\n/**\n * 無通知ミューテーション(abortAllStreams の idle / null 直接書き換え)の直後に呼び、\n * 台帳のうちミューテーション後の値と一致しないフィールドを UNCERTAIN に無効化する。\n * 一致しているフィールド(観測層がどちらを見ても同じ値)は dedup を維持する\n * (例: error が null のままなら再接続時に $streamError.<name> の余計な通知は出ない)。\n */\nexport function invalidateLastNotified(stateElement: IStateElement, name: string): void {\n const lastMap = lastNotifiedByStateElement.get(stateElement);\n if (typeof lastMap === \"undefined\") {\n return;\n }\n const last = lastMap.get(name);\n if (typeof last === \"undefined\") {\n // 未通知: 基準値 { idle, null } はミューテーション後の値と一致するため乖離しない\n return;\n }\n lastMap.set(name, {\n status: last.status === \"idle\" ? last.status : UNCERTAIN,\n error: Object.is(last.error, null) ? null : UNCERTAIN,\n });\n}\n\nexport const __private__ = {\n lastNotifiedByStateElement,\n UNCERTAIN,\n};\n","/**\n * stream/activeStateElements.ts\n *\n * 起動中(startStreams 済み・未切断)の stateElement の列挙用 Set\n * (docs/state-streams-design.md §3-2)。\n *\n * streamRegistry の WeakMap は列挙不能のため、updater の drain リスナーが\n * 「どの stateElement の entry と batch を交差させるか」を知るには\n * 列挙可能な strong Set が別途必要になる。lastNotified.ts と同じ\n * 「import 循環回避の小モジュール」パターン\n * (streamRegistry → activeStateElements ← streamRuntime の一方向依存に保つ)。\n *\n * リーク防止の不変条件(strong Set が切断済み要素の GC を妨げないための連動):\n * - add は startStreams(streamRuntime.ts)だけが行う\n * (eager 起動=connect 時、および接続中の `_state` 再 set 時の再起動)。\n * - delete は abortAllStreams / clearStreamRegistry(streamRegistry.ts)が行う。\n * disconnect(disconnectedCallback → abortAllStreams)と `_state` 再 set\n * (clearStreamRegistry → processStreamsDeclaration → 接続中なら startStreams で\n * 再 add)の両経路が必ずここを通るため、「Set に居る = 接続中かつ起動済み」が\n * 常に保たれ、切断済み stateElement への強参照は残らない。\n * 設計書 §3-2 の「未接続(disconnect 済み)の stateElement の entry は restart\n * しない」はこの不変条件で担保される。\n */\n\nimport type { IStateElement } from \"../components/types\";\n\nconst activeStateElements = new Set<IStateElement>();\n\n/**\n * 起動中 stateElement として登録する(startStreams 専用。不変条件はモジュールヘッダ参照)。\n */\nexport function addActiveStateElement(stateElement: IStateElement): void {\n activeStateElements.add(stateElement);\n}\n\n/**\n * 起動中 stateElement から外す(abortAllStreams / clearStreamRegistry 専用)。\n */\nexport function deleteActiveStateElement(stateElement: IStateElement): void {\n activeStateElements.delete(stateElement);\n}\n\n/**\n * 起動中 stateElement を列挙する(drain リスナーの交差判定用)。\n */\nexport function getActiveStateElements(): ReadonlySet<IStateElement> {\n return activeStateElements;\n}\n\nexport const __private__ = {\n activeStateElements,\n};\n","/**\n * stream/streamRegistry.ts\n *\n * `$streams` の registry(docs/state-streams-design.md §2-1 / §5)。\n * eventTokenRegistry と対称の WeakMap registry。\n *\n * - status / error の正本は registry entry(state オブジェクト上に実プロパティは持たない)。\n * - disconnect 時は abortAllStreams(abort のみ・registry 保持)、\n * `_state` 再 set 時のみ clearStreamRegistry(abort + 全削除)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport { deleteActiveStateElement } from \"./activeStateElements\";\nimport { invalidateLastNotified } from \"./lastNotified\";\nimport type { IStreamEntry } from \"./types\";\n\nconst registryByStateElement: WeakMap<IStateElement, Map<string, IStreamEntry>> = new WeakMap();\n\n/**\n * stream entry 群を置換登録する(`_state` セッターからの再構築で丸ごと差し替える)。\n */\nexport function setStreamEntries(stateElement: IStateElement, entries: Map<string, IStreamEntry>): void {\n registryByStateElement.set(stateElement, entries);\n}\n\n/**\n * 登録済みの stream entry 群を返す。未登録なら空 Map を返す(registry への登録はしない)。\n */\nexport function getStreamEntries(stateElement: IStateElement): Map<string, IStreamEntry> {\n return registryByStateElement.get(stateElement) ?? new Map<string, IStreamEntry>();\n}\n\n/**\n * 全 stream を abort して idle に戻す(設計書 §5-1)。registry は保持する。\n *\n * disconnectedCallback(切断時)に呼ばれるため、status / error の反映は\n * proxy / $postUpdate を使わず entry への直接ミューテーションで行う\n * (切断済みで binding 更新は不要かつ rootNode が無い)。\n *\n * 無通知ミューテーションは「最後に通知した観測値」台帳(stream/lastNotified.ts)\n * と registry を乖離させるため、同時に台帳側を invalidate する。これを怠ると\n * 再接続ウィンドウ内の fresh 読み(他パスの drain での getter 再計算など)が\n * 描画した idle に対し、restart の updateStreamStatus(\"active\") が切断前の\n * 通知値と同値判定されて skip され、DOM が恒久的に陳腐化する(設計書 §4-3)。\n */\nexport function abortAllStreams(stateElement: IStateElement): void {\n // 依存駆動 restart の対象から外す(切断済み stateElement は restart しない、\n // 設計書 §3-2。add 側は startStreams — stream/activeStateElements.ts の\n // リーク防止不変条件を参照)。registry の有無に関わらず必ず外す。\n deleteActiveStateElement(stateElement);\n const entries = registryByStateElement.get(stateElement);\n if (typeof entries === \"undefined\") {\n return;\n }\n for (const entry of entries.values()) {\n entry.controller?.abort();\n entry.controller = null;\n entry.status = \"idle\";\n entry.error = null;\n invalidateLastNotified(stateElement, entry.name);\n }\n}\n\n/**\n * 全 stream を abort したうえで registry から削除する(`_state` 再 set 時の再配線用、設計書 §5-2)。\n */\nexport function clearStreamRegistry(stateElement: IStateElement): void {\n abortAllStreams(stateElement);\n // abortAllStreams が既に delete 済みだが、「clear = 全削除でも必ず restart 対象から\n // 外れる」不変条件を将来の abortAllStreams の変更から独立に保証するため明示的に呼ぶ。\n deleteActiveStateElement(stateElement);\n registryByStateElement.delete(stateElement);\n}\n\nexport const __private__ = {\n registryByStateElement,\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 * - メソッド(関数値のプロパティ)との衝突を禁止(`$scan` の D7 と同じ規則)。\n * 同名メソッドがあると `name in state` が真になって実体化(§1-3)が skip され、\n * 起動時の initial リセットがそのメソッドを無言で上書きする(宣言から遠い場所で\n * \"not a function\" として現れる)。判定はプロトタイプ鎖込みの descriptor で行い\n * getter は評価しない。`initial` 自身が関数の形と、runtime(実体化・リセット・fold)が\n * その値を置いたことがある形(fold が関数を返す stream の再セット)は通す。\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_STREAM_NAME, WILDCARD } from \"../define\";\nimport { normalizeDeclarationAliases } from \"../declarationAliases\";\nimport { getAllPropertyDescriptors } from \"../getAllPropertyDescriptors\";\nimport { raiseError } from \"../raiseError\";\nimport { recordOutputValue, wasPlacedOnOutput } from \"../scan/initialValue\";\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_STREAM_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_STREAM_NAME} must be an object mapping stream names to stream definitions.`);\n }\n const entries = new Map<string, IStreamEntry>();\n // メソッド衝突検査(§1-2)用。プロトタイプ鎖込み・getter を評価しない\n const descriptors = getAllPropertyDescriptors(state);\n for (const [name, def] of Object.entries(declared as Record<string, unknown>)) {\n if (name.length === 0) {\n raiseError(`${STATE_STREAM_NAME} entry name must be a non-empty string.`);\n }\n if (name.includes(DELIMITER)) {\n raiseError(`${STATE_STREAM_NAME} entry \"${name}\" must be a flat property name (\"${DELIMITER}\" is not allowed).`);\n }\n if (name.includes(WILDCARD)) {\n raiseError(`${STATE_STREAM_NAME} entry \"${name}\" must be a flat property name (\"${WILDCARD}\" is not allowed).`);\n }\n if (name.startsWith(\"$\")) {\n raiseError(`${STATE_STREAM_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_STREAM_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_STREAM_NAME} entry \"${name}\" conflicts with a getter declared on the state.`);\n }\n if (stateElement.setterPaths.has(name)) {\n raiseError(`${STATE_STREAM_NAME} entry \"${name}\" conflicts with a setter declared on the state.`);\n }\n if (typeof def !== \"object\" || def === null) {\n raiseError(`${STATE_STREAM_NAME} entry \"${name}\" must be an object ({ args?, source, fold?, initial? }).`);\n }\n const definition = def as Record<string, unknown>;\n // メソッド衝突(`$scan` の D7 と同じ規則)。同名メソッドは実体化を skip させ、起動時の\n // initial リセットで無言に消えるため、宣言時に落とす。`initial` 自身が関数の形と、\n // runtime がその値を出力に置いたことがある形(fold が関数を返す stream の再セット)は通す\n const current = descriptors[name]?.value;\n if (typeof current === \"function\" && current !== definition.initial && !wasPlacedOnOutput(name, current)) {\n raiseError(`${STATE_STREAM_NAME} entry \"${name}\" conflicts with a method (a function-valued property) declared on the state. The value is a property the runtime owns.`);\n }\n if (typeof definition.source !== \"function\") {\n raiseError(`${STATE_STREAM_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_STREAM_NAME} entry \"${name}\" fold must be a function.`);\n }\n if (hasFold && !(\"initial\" in definition)) {\n raiseError(`${STATE_STREAM_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_STREAM_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 // 置いた関数値を記録する(`initial` が関数の stream の再セットをメソッド衝突としない)\n recordOutputValue(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_STREAM_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_STREAM_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_STREAM_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_STREAM_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 { STATE_STREAM_NAME } from \"../define\";\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 // `onAbort` is reachable two ways: the abort listener (registered `{ once: true }` and\n // removed in the `finally`), and the explicit call below when abort raced the\n // `await source(...)`. At most ONE of them can see a non-null `iterator`, so `.return()`\n // runs at most once and no \"already returned\" flag is needed: `iterator` is assigned and\n // `signal.aborted` is read in the SAME synchronous block, so the listener either already\n // ran while `iterator` was still null (releasing nothing — hence the explicit call) or\n // runs strictly after that block, by which time the explicit call can no longer happen.\n const onAbort = (): void => {\n if (iterator === null) {\n return; // nothing to release yet — the explicit call below does it\n }\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] ${STATE_STREAM_NAME}: 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 { recordOutputValue } from \"../scan/initialValue\";\nimport { assertNoScanFeedback } from \"../scan/scanFeedback\";\nimport { registerUpdateBatchListener } from \"../updater/updater\";\nimport { registerFeatureHooks } from \"../core/addressHooks\";\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { STATE_STREAM_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 // runtime が置いた関数値を記録する(再セットの宣言検査が fold / initial の関数を\n // メソッド衝突と誤検出しないため。scan/initialValue.ts — `$scan` の D7 と共有)\n recordOutputValue(entry.name, entry.definition.initial);\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 const next = definition.fold(state[entry.name], chunk);\n state[entry.name] = next;\n recordOutputValue(entry.name, next);\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_STREAM_NAME] !== \"undefined\") {\n element.attachAddressHooks?.(\"streams\", STATE_STREAM_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 * watch/chainDepth.ts\n *\n * `$watch` ハンドラ起点の書き込み連鎖の深さを数える台帳\n * (docs/state-watch-hook-design.md §7-2)。\n *\n * watch ハンドラ内の書き込みは新しい microtask バッチを作るため、伝播 context の\n * hop 上限(MAX_PROPAGATION_HOPS)のガードが効かない。かつ書き込み先が動的なので、\n * `$streams` のような「宣言時の自己依存検出」も使えない。よって実行時に数える。\n *\n * updater(enqueue 側)と watchRuntime(発火側)の両方から参照されるため、\n * **依存ゼロの葉モジュール**にして循環 import を避ける(platform/devtoolsSink.ts と同じ方針)。\n *\n * 数え方: ハンドラ実行中に enqueue が起きたときだけ「次のバッチはこの連鎖の続き」と\n * マークする。ハンドラが何も書かなければ次のバッチは深さ 0 に戻るので、利用者操作が\n * 何度続いても深さは伸びない。\n */\n\n/** ハンドラ実行中に立つ「今の連鎖の深さ + 1」。0 なら watch 起点ではない */\nlet firingDepth = 0;\n\n/** 次に drain されるバッチの深さ */\nlet pendingDepth = 0;\n\n/** watch の発火フェーズ開始(watchRuntime 専用) */\nexport function beginWatchFiring(depth: number): void {\n firingDepth = depth + 1;\n}\n\n/** watch の発火フェーズ終了(watchRuntime 専用。必ず finally で呼ぶ) */\nexport function endWatchFiring(): void {\n firingDepth = 0;\n}\n\n/**\n * 書き込みの enqueue を記録する(updater 専用)。\n * ハンドラ実行中でなければ何もしない = 通常の書き込みに深さは付かない。\n */\nexport function noteEnqueueForWatchChain(): void {\n if (firingDepth > pendingDepth) {\n pendingDepth = firingDepth;\n }\n}\n\n/** 次バッチの深さを消費する(watchRuntime 専用。読んだらリセット) */\nexport function consumeWatchChainDepth(): number {\n const depth = pendingDepth;\n pendingDepth = 0;\n return depth;\n}\n\nexport const __private__ = {\n reset(): void {\n firingDepth = 0;\n pendingDepth = 0;\n },\n};\n","/**\n * watch/computedSnapshots.ts\n *\n * watch 対象の computed(getter)の「前回評価値」台帳\n * (docs/state-watch-hook-design.md §5)。\n *\n * getter は `setByAddress` を通らないので、スカラ書き込み用の旧値台帳\n * (watch/prevValues.ts)には載らない。`prev` を渡すには前回の評価値を\n * **バッチを跨いで**保持する必要があり、こちらは drain ごとにクリアしない。\n *\n * 寿命は stateElement 単位(WeakMap)。`_state` 再 set では宣言ごと作り直すため\n * 破棄する。切断では破棄しない —— 再接続時の初回評価が上書きするので、\n * 残っていても害がなく、registry を保持する扱いとも揃う。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\n\nconst snapshotsByStateElement: WeakMap<IStateElement, Map<IAbsoluteStateAddress, unknown>> = new WeakMap();\n\nexport function getComputedSnapshot(\n stateElement: IStateElement,\n absAddress: IAbsoluteStateAddress,\n): unknown {\n return snapshotsByStateElement.get(stateElement)?.get(absAddress);\n}\n\nexport function setComputedSnapshot(\n stateElement: IStateElement,\n absAddress: IAbsoluteStateAddress,\n value: unknown,\n): void {\n let snapshots = snapshotsByStateElement.get(stateElement);\n if (typeof snapshots === \"undefined\") {\n snapshots = new Map<IAbsoluteStateAddress, unknown>();\n snapshotsByStateElement.set(stateElement, snapshots);\n }\n snapshots.set(absAddress, value);\n}\n\n/** `_state` 再 set で宣言ごと作り直すときに破棄する */\nexport function clearComputedSnapshots(stateElement: IStateElement): void {\n snapshotsByStateElement.delete(stateElement);\n}\n\nexport const __private__ = {\n snapshotsByStateElement,\n};\n","/**\n * watch/prevValues.ts\n *\n * `$watch` ハンドラへ渡す `prev`(バッチ開始時点の値)の台帳\n * (docs/state-watch-hook-design.md §4-1)。\n *\n * 記録するのは **watch 宣言済みパスへの書き込みだけ**、かつ **バッチ内で最初の 1 回だけ**\n * (first-write-wins)。したがって `prev` は「そのバッチが始まる前の値」、`cur` は\n * drain 時点の確定値になる。同一バッチ内の中間値は観測できない(§3-4)。\n *\n * 値の出どころは same-value guard が既に読んでいる旧値であり、watch のために\n * 追加の getByAddress は行わない(§10)。その帰結として:\n * - 参照型(object / array)は guard が素通しするので `prev` は undefined\n * - `config.sameValueGuard = false` でも undefined\n * - `$postUpdate` / stream の status 通知は setByAddress を通らないので undefined\n *\n * 台帳は drain 終端(watchRuntime)でクリアされる。drain の外で書き込まれた分が\n * 次のバッチへ持ち越されることはない。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\n\nconst prevValueByAbsoluteStateAddress: Map<IAbsoluteStateAddress, unknown> = new Map();\n\n/**\n * バッチ内で最初の書き込みのときだけ旧値を記録する(first-write-wins)。\n */\nexport function recordPrevValue(absAddress: IAbsoluteStateAddress, oldValue: unknown): void {\n if (prevValueByAbsoluteStateAddress.has(absAddress)) {\n return;\n }\n prevValueByAbsoluteStateAddress.set(absAddress, oldValue);\n}\n\n/**\n * 記録済みの旧値を返す。記録が無ければ undefined(§4-1 の「prev を保証しない」経路)。\n */\nexport function getPrevValue(absAddress: IAbsoluteStateAddress): unknown {\n return prevValueByAbsoluteStateAddress.get(absAddress);\n}\n\n/**\n * 旧値が記録済みか(記録された undefined と、記録が無いことを区別する)。\n */\nexport function hasPrevValue(absAddress: IAbsoluteStateAddress): boolean {\n return prevValueByAbsoluteStateAddress.has(absAddress);\n}\n\n/**\n * 台帳をクリアする(drain 終端で必ず呼ぶ)。\n */\nexport function clearPrevValues(): void {\n prevValueByAbsoluteStateAddress.clear();\n}\n\nexport const __private__ = {\n prevValueByAbsoluteStateAddress,\n};\n","/**\n * watch/watchRegistry.ts\n *\n * `$watch` の registry と、drain リスナーの走査元になる「発火対象の stateElement 集合」\n * (docs/state-watch-hook-design.md §9)。\n *\n * `$streams` は registry(delete 側)と runtime(add 側)が相互に依存するため\n * active 集合を stream/activeStateElements.ts へ切り出しているが、`$watch` は\n * **add が State のライフサイクル側、delete が registry 側**で、runtime は読むだけの\n * 一方向依存になる。よって循環せず、1 モジュールにまとめられる。\n *\n * リーク防止の不変条件(strong Set が切断済み要素の GC を妨げないための連動):\n * - add は `startWatch`(`State.connectedCallback` の $connectedCallback 完了後、および\n * 接続中の `_state` 再 set)だけが行い、**宣言が 1 つも無い stateElement は入れない**。\n * - delete は `deactivateWatch`(disconnectedCallback)/`clearWatchRegistry`(`_state`\n * 再 set)だけが行う。\n * どちらの経路も必ずここを通るため「Set に居る = 接続中かつ宣言済み」が保たれる。\n * この「宣言済み」の側が崩れると、`$watch` 未使用アプリの drain にも収集ループが乗る\n * (ゼロコスト契約、docs/state-watch-hook-design.md §10)。\n * `$scan` の drain / enqueue のゲート(scan/scanRegistry.ts)も同じ出入りで数える。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport { activateScanGates, deactivateScanGates } from \"../scan/scanRegistry\";\nimport type { IWatchEntry } from \"./types\";\n\nconst registryByStateElement: WeakMap<IStateElement, Map<string, IWatchEntry>> = new WeakMap();\n\n/**\n * ボリュームが追記した watch entry(webComponent/volume.ts — 接頭辞翻訳済み・\n * ハンドラは chroot 包装済み)。ルート自身の宣言(上の registry・_state 再 set で\n * 丸ごと差し替わる)とはライフサイクルが違うため別台帳にする。同じ翻訳パスに\n * ルートの宣言とボリュームの宣言が並ぶことも、複数ボリュームが同名パスに並ぶことも\n * ある(配列・登録順)。\n */\nconst volumeEntriesByStateElement: WeakMap<IStateElement, Map<string, IWatchEntry[]>> = new WeakMap();\nconst activeStateElements = new Set<IStateElement>();\n\n/**\n * 未登録時に返す共有の空 Map。\n *\n * ここで毎回 `new Map()` すると、drain の収集ループが「バッチのアドレス 1 個につき\n * Map を 1 個」アロケートすることになる(発火対象だが宣言を持たない stateElement を\n * 通る経路)。読み出ししかしない返り値なので 1 個を使い回す。\n */\nconst EMPTY_ENTRIES: ReadonlyMap<string, IWatchEntry> = new Map<string, IWatchEntry>();\n\n/**\n * watch entry 群を置換登録する(`_state` セッターからの再構築で丸ごと差し替える)。\n */\nexport function setWatchEntries(stateElement: IStateElement, entries: Map<string, IWatchEntry>): void {\n registryByStateElement.set(stateElement, entries);\n}\n\n/**\n * 登録済みの watch entry 群を返す。未登録なら共有の空 Map を返す\n * (registry への登録はしない。返り値は読み出し専用)。\n */\nexport function getWatchEntries(stateElement: IStateElement): ReadonlyMap<string, IWatchEntry> {\n return registryByStateElement.get(stateElement) ?? EMPTY_ENTRIES;\n}\n\n/**\n * 発火対象として登録する(`startWatch` 専用。不変条件はモジュールヘッダ参照)。\n */\nexport function addActiveWatchStateElement(stateElement: IStateElement): void {\n activeStateElements.add(stateElement);\n activateScanGates(stateElement);\n}\n\n/**\n * 発火対象を列挙する(drain リスナーの early return 判定用)。\n */\nexport function getActiveWatchStateElements(): ReadonlySet<IStateElement> {\n return activeStateElements;\n}\n\n/**\n * 発火対象から外す(切断時)。**registry は保持する。**\n *\n * `$streams` の abortAllStreams と同じ二段構えで、切断は「発火しなくなる」だけにする。\n * registry まで捨てると、再接続(connectedCallback → startWatch)で宣言を作り直す経路が\n * 無い(`_state` セッターは初回ロード時にしか走らない)ため、watch が二度と発火しない。\n */\nexport function deactivateWatch(stateElement: IStateElement): void {\n activeStateElements.delete(stateElement);\n deactivateScanGates(stateElement);\n}\n\n/**\n * registry から削除し、発火対象からも外す(`_state` 再 set 時の再配線用)。\n */\nexport function clearWatchRegistry(stateElement: IStateElement): void {\n activeStateElements.delete(stateElement);\n deactivateScanGates(stateElement);\n registryByStateElement.delete(stateElement);\n}\n\n/** ボリュームの watch entry を追記する(置換しない)。 */\nexport function addVolumeWatchEntries(stateElement: IStateElement, entries: readonly IWatchEntry[]): void {\n let byPath = volumeEntriesByStateElement.get(stateElement);\n if (typeof byPath === \"undefined\") {\n byPath = new Map();\n volumeEntriesByStateElement.set(stateElement, byPath);\n }\n for (const entry of entries) {\n const list = byPath.get(entry.path);\n if (typeof list === \"undefined\") {\n byPath.set(entry.path, [entry]);\n } else {\n list.push(entry);\n }\n }\n}\n\nconst EMPTY_VOLUME_ENTRIES: ReadonlyMap<string, readonly IWatchEntry[]> = new Map();\n\nexport function getVolumeWatchEntries(stateElement: IStateElement): ReadonlyMap<string, readonly IWatchEntry[]> {\n return volumeEntriesByStateElement.get(stateElement) ?? EMPTY_VOLUME_ENTRIES;\n}\n\nexport const __private__ = {\n registryByStateElement,\n activeStateElements,\n};\n","/**\n * watch/processWatchDeclaration.ts\n *\n * `$watch: { \"<path>\": (cur, prev, ...indexes) => void }` 宣言マップを解析し、\n * IWatchEntry を構築して watchRegistry に一括登録する\n * (docs/state-watch-hook-design.md §2-2 / §8)。\n *\n * `$streams` の processStreamsDeclaration と対称だが、**キーが宣言名ではなくパス**である\n * ぶん検証が異なる(`.` / `*` を許可し、代わりにパスとしての妥当性を見る)。\n *\n * 依存グラフ登録(§8)がこの関数の要点:\n * `setPathInfo` は BindingSession(= DOM バインディング登録)からしか呼ばれないため、\n * 静的依存グラフに載るのは「バインドされたパス」だけである。watch を宣言しただけでは\n * walkDependency がそのパスを知らず、`items` への代入で `items.*.price` がバッチに載らない\n * = ハンドラが黙って一度も発火しない。宣言時に自分で登録することでこれを塞ぐ。\n *\n * 呼び出しは stateElement の `_pathSet` クリア後・getterPaths 確定後であること\n * (State の `_state` セッターが順序を保証する)。\n */\n\nimport { getPathInfo } from \"../address/PathInfo\";\nimport type { IStateElement } from \"../components/types\";\nimport { MAX_WILDCARD_DEPTH, STATE_WATCH_NAME } from \"../define\";\nimport { LINT_HINT } from \"../errorGuidance\";\nimport { raiseError } from \"../raiseError\";\nimport type { IState } from \"../types\";\nimport { setWatchEntries } from \"./watchRegistry\";\nimport type { IWatchEntry, WatchHandler } from \"./types\";\n\n/**\n * `$watch` 宣言を registry へ反映し、監視対象パスの集合を返す。\n *\n * 宣言が無い(または空)なら **null** を返す。呼び出し側(State)はこれを\n * `watchPaths` に保持し、setByAddress のホットパスは `!== null` の分岐 1 個で\n * 抜けられる(ゼロコスト契約、§10)。\n */\n/**\n * `$watch` パスの静的検査(宣言側とボリュームの接頭辞登録 — webComponent/volume.ts —\n * で共有)。検証に通れば pathInfo を返す。\n */\nexport function assertValidWatchPath(path: string): ReturnType<typeof getPathInfo> {\n if (path.length === 0) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry name must be a non-empty state path.`);\n }\n if (path.startsWith(\"$\")) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must not start with \"$\" (reserved namespace).${LINT_HINT}`);\n }\n // 越境 watch は不採用(設計 D8)。他 state のアドレスは発火対象にしないため、\n // \"@\" 付きのパスは受け取った時点で落とす(名前次元は v2 で撤去 — 黙って発火しないより良い)。\n if (path.includes(\"@\")) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must not contain \"@\" — the name selector was removed in v2; watch only paths of the state tree.${LINT_HINT}`);\n }\n // Object.prototype の継承名は `path in state` 系の判定を汚すため一律拒否する\n // (processStreamsDeclaration と同じ防衛線)。\n if (path in Object.prototype) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").`);\n }\n const pathInfo = getPathInfo(path);\n // 空セグメント(\"a..b\" / 先頭・末尾の \".\")は getPathInfo が黙って受理してしまうため、\n // ここで落とす。放置すると解決不能なアドレスを依存グラフへ登録することになる。\n for (const segment of pathInfo.segments) {\n if (segment.length === 0) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" has an empty path segment.${LINT_HINT}`);\n }\n }\n if (pathInfo.wildcardCount > MAX_WILDCARD_DEPTH) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" exceeds the maximum wildcard depth (${MAX_WILDCARD_DEPTH}).`);\n }\n return pathInfo;\n}\n\nexport function processWatchDeclaration(\n stateElement: IStateElement,\n state: IState,\n): ReadonlySet<string> | null {\n const declared = (state as Record<string, unknown>)[STATE_WATCH_NAME];\n if (typeof declared === \"undefined\") {\n return null;\n }\n if (typeof declared !== \"object\" || declared === null) {\n // lint 側の findNonObjectWatch が「断定できる形」を同 code で検出するため誘導を付ける。\n // (LINT_HINT を付けない残りは、lint が検出しない空キー・Object.prototype 継承名・\n // ワイルドカード深度超過の 3 shape。)\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} must be an object mapping state paths to handler functions.${LINT_HINT}`);\n }\n const entries = new Map<string, IWatchEntry>();\n const paths = new Set<string>();\n let order = 0;\n for (const [path, handler] of Object.entries(declared as Record<string, unknown>)) {\n if (typeof handler !== \"function\") {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must be a function.${LINT_HINT}`);\n }\n const pathInfo = assertValidWatchPath(path);\n entries.set(path, {\n path,\n pathInfo,\n handler: handler as WatchHandler,\n order: order++,\n });\n paths.add(path);\n // 依存グラフ登録(§8)。\"for\" 以外の bindingType は親 → 子の staticDependency\n // チェーンを生やすだけで listPaths / elementPaths を触らない(State.setPathInfo 参照)。\n // source=\"watch\" は存在検査の診断 code を `wcs/watch-path-missing` に切り替える\n // (watch キーの miss は raiseError にも掛からず、黙って発火しないだけになる)。\n stateElement.setPathInfo(path, \"prop\", \"watch\");\n }\n setWatchEntries(stateElement, entries);\n return paths.size > 0 ? paths : null;\n}\n","/**\n * watch/addressHooks.ts — `$watch` / `$scan` を宣言した state に付く hook(設計案 H1、S3)。\n * 宣言済みパスの `prev` 台帳(prevValues.ts)への記録を core(setByAddress)から移し、\n * どちらも宣言しない state では一切走らない。台帳を読むのは `$watch`\n * (docs/state-watch-hook-design.md §4-1)と `$scan` の `from`(docs/state-scan-design.md §2-1)。\n */\nimport { IAddressHooks } from \"../core/addressHooks\";\nimport { getPrevValue, hasPrevValue, recordPrevValue } from \"./prevValues\";\n\nexport const watchAddressHooks: IAddressHooks = {\n // same-value guard が既に読んだ旧値だけを使い、そのための追加読みはしない\n writeObserve(stateElement, path, absAddress, oldValue, hasOldValue) {\n if (!hasOldValue) {\n return;\n }\n const watchPaths = stateElement.watchPaths;\n const scanPaths = stateElement.scanPaths;\n if (watchPaths?.has(path) === true || scanPaths?.has(path) === true) {\n recordPrevValue(absAddress, oldValue);\n }\n },\n // 要素の入れ替えで行が動いた: 旧値の台帳を行に追従させる\n swapped(_stateElement, elementAbsAddress, displacedAbsAddress) {\n if (hasPrevValue(displacedAbsAddress)) {\n recordPrevValue(elementAbsAddress, getPrevValue(displacedAbsAddress));\n }\n },\n};\n","/**\n * watch/rowLanding.ts\n *\n * ワイルドカードのパスの行の着地を、drain の時点のリストの位置 1 つにつき 1 つに絞る(#274)。\n * `$watch` と `$scan` の `from` が共有する(docs/state-scan-design.md D3・§5-5)。\n *\n * バッチに載る行のアドレスは、書き込みの時点の行を指す。同じ job でその後にリストを短くした・\n * 置き換えた・途中から取り除いた・`list.*` へ要素を書き込んだと、drain の時点ではアドレスの行が\n * もうその位置に居ないことがある。添字で読むと、範囲外の読みで throw するか、その位置にいま居る\n * 別の行の値で発火する。\n */\n\nimport { createStateAddress } from \"../address/StateAddress\";\nimport type { IAbsoluteStateAddress, IPathInfo } from \"../address/types\";\nimport { isSameListIndexValue } from \"../list/createListIndex\";\nimport { getListIndexesByList, isRetiredListIndex } from \"../list/listIndexesByList\";\nimport type { IListIndex } from \"../list/types\";\nimport { listIndexAtWildcard } from \"../list/wildcardLevel\";\nimport { getByAddressSymbol } from \"../proxy/symbols\";\nimport type { IStateProxy } from \"../proxy/types\";\n\nexport interface ILandingRow {\n readonly absAddress: IAbsoluteStateAddress;\n readonly indexes: readonly number[];\n}\n\n/** 行のアドレスと、いまのリストの位置の関係 */\ntype RowPlacement = \"current\" | \"replaced\" | \"gone\";\n\n/**\n * 行の連鎖に、差分がリストから外した(退役した)行があるか。読むだけの前判定で、リストは読まない。\n * `$watch` はこれが真のヒット(か、同じ位置に重なるヒット)があるときだけ位置を引く。\n */\nexport function hasRetiredRow(listIndex: IListIndex): boolean {\n for (let row: IListIndex | null = listIndex; row !== null; row = row.parentListIndex) {\n if (isRetiredListIndex(row)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * 行のアドレスが、いまのリストのその位置とどう関係するか。外側の段から台帳を引く。\n * 読むだけ(`$scan` の計画の相・D18)なので、台帳は観測用の `getListIndexesByList` で引き、\n * 親ポインタを修理する `resolveListIndexesByList` は使わない。\n * - `gone`: その位置に行が無い(リストを短くした・空にした・配列でなくした)か、アドレスの行を\n * 差分がリストから外した(退役した — 行を取り除いた・リストを置き換えた)。\n * - `current`: その位置の行が、アドレスの行そのものか、同じリスト要素を表す行。\n * - `replaced`: その位置には別の要素の行が居るが、アドレスの行は差分に外されていない\n * (`list.*` への要素の書き込みは、差分を通らずに台帳のその位置へ別の行を差し込む)。\n */\nfunction placementOf(state: IStateProxy, pathInfo: IPathInfo, row: ILandingRow): RowPlacement {\n // ワイルドカードのパスの着地は、収集の段階で listIndex を持つものに限っている\n const listIndex = row.absAddress.listIndex as IListIndex;\n let placement: RowPlacement = \"current\";\n let parentListIndex: IListIndex | null = null;\n for (let level = 0; level < pathInfo.wildcardCount; level++) {\n const list = state[getByAddressSymbol](createStateAddress(pathInfo.wildcardParentPathInfos[level], parentListIndex));\n // 台帳を持たない値(配列でない・空の配列)は行が無い\n const current: IListIndex | undefined = getListIndexesByList(list as readonly unknown[])?.[row.indexes[level]];\n if (typeof current === \"undefined\") {\n return \"gone\";\n }\n // `$scan` も `$watch` もルートのツリーでだけ発火するので、行の連鎖にスコープの base 段は無い(段は必ずある)\n const own = listIndexAtWildcard(listIndex, level, pathInfo.wildcardCount) as IListIndex;\n if (current !== own && !isSameListIndexValue(current, own)) {\n if (isRetiredListIndex(own)) {\n return \"gone\";\n }\n placement = \"replaced\";\n }\n parentListIndex = current;\n }\n return placement;\n}\n\n/**\n * 行の着地を、いまのリストの位置 1 つにつき 1 つに絞る。戻り値の順は、位置ごとに最初に残した行の順。\n *\n * - 位置に行が無いアドレス(行を書いてからリストを短くした・空にした)は捨てる。\n * 添字で読むと範囲外の読みで throw する。\n * - 差分がリストから外した行のアドレス(行を書いてからその行を取り除いた・リストを置き換えた)は捨てる。\n * 添字で読むと、その位置にいま居る行の値を読む — 置き換えで入った行は自分のアドレスで着地するので二重になり、\n * 位置だけが移ってきた行は変わっていないのに着地する(#274・docs/state-scan-design.md §5-5)。\n * - 同じ位置に、いまそこに居る行のアドレスと、差分に外されていない別の行のアドレス(`list.*` への要素の\n * 書き込みの前にその行へ書いた形)が並んだら前者を残す。後者しか無い位置は残し、その位置のいまの値を読ませる。\n */\nexport function selectLandedRows<T extends ILandingRow>(state: IStateProxy, pathInfo: IPathInfo, rows: readonly T[]): T[] {\n const byPosition = new Map<string, { readonly row: T; readonly rank: number }>();\n for (const row of rows) {\n const placement = placementOf(state, pathInfo, row);\n if (placement === \"gone\") {\n continue;\n }\n const rank = placement === \"current\" ? 1 : 0;\n const key = row.indexes.join(\",\");\n const kept = byPosition.get(key);\n if (typeof kept === \"undefined\" || rank > kept.rank) {\n byPosition.set(key, { row, rank });\n }\n }\n return Array.from(byPosition.values(), (kept) => kept.row);\n}\n","/**\n * scan/scanRuntime.ts\n *\n * `$scan` の drain 側の発火 — `from` と `resetOn`(docs/state-scan-design.md §2-1)。\n *\n * watch runtime の drain リスナー(`WATCH_LISTENER_PRIORITY`)から呼ばれる(D11)。\n * 発火対象集合・連鎖深さ・`prev` 台帳は `$watch` と共有する。\n *\n * 発火単位(D3): バッチに載った `from` の絶対アドレス 1 つにつき fold 1 回。\n * 同じ出力へ複数行(wildcard)が載ったバッチでは、indexes 昇順に acc を連鎖させて\n * 最後に 1 回だけ書く。開始値と `Object.is` で同じなら書かない。\n * 行の着地は、いまのリストの位置 1 つにつき 1 回に絞る(watch/rowLanding.ts の selectLandedRows — `$watch` と共有)。\n *\n * 計画と書き込みを 2 相に分ける(D18): 全 scan の次の値を読むだけで決め(planScansOnUpdateBatch)、\n * 宣言順に書く(commitScanPlans)。どちらも同じ drain の `$watch` の発火より前(D11)。\n * - 1 相で「畳んでは書く」と、ある scan の出力を `from` に取る後続の scan が、同じ drain で\n * 先行 scan が書いたばかりの(まだバッチとして届いていない)値を畳み、次のバッチで同じ値を\n * もう一度畳む — 届いていた値は取りこぼす。宣言順しだいで exactly-once が破れる。\n * - 書き込みが `$watch` より前なので、同じ drain の `$watch` ハンドラは畳んで書いた後の出力を読み、ハンドラが\n * 出力へ書いた値はそのまま残る。その代わり、出力の source を drain のリスナーが書き進めて、出力の着地と\n * source の新しい着地が同じバッチに載る連鎖では、出力を見る `$watch` の prev が前の着地を持ち、cur が\n * 1 段先行し、同じ値で 2 回発火し得る(D12 の契約・§5-6 の差し戻し)。\n *\n * 失敗は種類ごとに閉じる(D4): 読めない行はその行だけを捨てて連鎖を続け(`$watch` が行ごとに\n * evaluate で閉じるのと同じ)、出力の読み・行の位置引き・fold の throw はその scan の書き込みを止める。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { getScopedIndexes } from \"../list/wildcardLevel\";\nimport type { IStateProxy } from \"../proxy/types\";\nimport { getStreamEntries } from \"../stream/streamRegistry\";\nimport { getUpdater } from \"../updater/updater\";\nimport { beginWatchFiring, endWatchFiring } from \"../watch/chainDepth\";\nimport { getPrevValue } from \"../watch/prevValues\";\nimport { selectLandedRows } from \"../watch/rowLanding\";\nimport { consumePendingScanReset, discardPendingScanResets } from \"./eventReset\";\nimport { cloneInitial, isSameAsInitial, recordOutputValue } from \"./initialValue\";\nimport { isThenable, reportLateGetterSource, reportScanError, reportScanThenable, type ScanFailure } from \"./scanReport\";\nimport { getScanDrainGateCount, getScanRegistry } from \"./scanRegistry\";\nimport type { IScanEntry, IScanPathSource } from \"./types\";\n\nexport interface IScanRow {\n readonly absAddress: IAbsoluteStateAddress;\n readonly indexes: number[];\n}\n\nexport interface IScanGroup {\n readonly stateElement: IStateElement;\n readonly entry: IScanEntry;\n readonly rows: IScanRow[];\n reset: boolean;\n}\n\n/** 相 1 の結果。`group.reset` なら相 2 が `initial` の複製を書く(出力が既に initial と同じ値なら書かない) */\nexport interface IScanPlan {\n readonly group: IScanGroup;\n readonly next: unknown;\n}\n\nconst NO_PLANS: readonly IScanPlan[] = Object.freeze([]);\n\nfunction groupOf(groups: Map<IScanEntry, IScanGroup>, stateElement: IStateElement, entry: IScanEntry): IScanGroup {\n let group = groups.get(entry);\n if (typeof group === \"undefined\") {\n group = { stateElement, entry, rows: [], reset: false };\n groups.set(entry, group);\n }\n return group;\n}\n\n/**\n * 同じ entry の行は wildcard の段数が同じ(indexes の長さが等しい)なので、\n * 外側の段から最初に違う段で比べる。\n */\nfunction compareRows(a: IScanRow, b: IScanRow): number {\n let level = 0;\n while (level < a.indexes.length - 1 && a.indexes[level] === b.indexes[level]) {\n level++;\n }\n return a.indexes[level] - b.indexes[level];\n}\n\n/**\n * `from` の根が `$streams` 名で、そのバッチにその stream の restart 依存が載っているか(D10)。\n * 載っていれば同じ drain の STREAM リスナーが run を abort する。到着した chunk は\n * 捨てられる run のものなので畳まない(`$streams` §3-2「restart が勝つ」)。\n */\nfunction isStreamRestartPending(\n stateElement: IStateElement,\n rootName: string,\n batch: ReadonlySet<IAbsoluteStateAddress>,\n): boolean {\n const streamEntry = getStreamEntries(stateElement).get(rootName);\n if (typeof streamEntry === \"undefined\") {\n return false;\n }\n for (const dep of streamEntry.depAddresses) {\n if (batch.has(dep)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasGetterOnPath(stateElement: IStateElement, source: IScanPathSource): boolean {\n for (const path of source.pathInfo.cumulativePaths) {\n if (stateElement.getterPaths.has(path)) {\n return true;\n }\n }\n return false;\n}\n\n/** 先行する fold や書き込みが同期に切断・再セットを起こし得る(`$watch` と同じ再確認) */\nfunction isLive(group: IScanGroup, activeStateElements: ReadonlySet<IStateElement>): boolean {\n return activeStateElements.has(group.stateElement)\n && getScanRegistry(group.stateElement)?.entries.has(group.entry) === true;\n}\n\n/**\n * 発火しないと決まった group の、`on` scan の保留 reset を捨てる(scan/eventReset.ts)。\n * `on` の group は `resetOn` のヒットからしか作られない。同じ `resetOn` のパスが次のバッチ向けに\n * 積まれていれば、その保留は次のバッチの drain が使うので残す(discardSkippedScanResets と同じ規則)。\n */\nfunction dropPendingReset(group: IScanGroup): void {\n const { entry, stateElement } = group;\n if (entry.source.kind === \"event\" && !entry.resetOn.some((path) => isQueuedForNextBatch(stateElement, path))) {\n consumePendingScanReset(entry);\n }\n}\n\n/** 次のバッチ(まだ drain されていない書き込み)に、この state のこのパスが積まれているか */\nfunction isQueuedForNextBatch(stateElement: IStateElement, path: string): boolean {\n return getUpdater().hasQueuedPath(stateElement, path);\n}\n\n/**\n * このバッチの scan を発火しない drain(発火対象でない state・連鎖深さの上限)で、`on` scan の\n * 保留 reset を捨てる。`firing` はこの drain で scan を発火する state の集合、null はバッチ全体を\n * 発火しない。同じ `resetOn` のパスが次のバッチ向けに積まれていれば、その保留は残す。\n */\nexport function discardSkippedScanResets(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n firing: ReadonlySet<IStateElement> | null,\n): void {\n discardPendingScanResets(batch, firing, isQueuedForNextBatch);\n}\n\nfunction readSource(state: IStateProxy, source: IScanPathSource, row: IScanRow): unknown {\n return source.pathInfo.wildcardCount === 0\n ? state[source.path]\n : state.$resolve(source.path, row.indexes);\n}\n\n/** 相 1: 次の値を読むだけで決める。書き込みは無いか null。 */\nfunction planGroup(\n group: IScanGroup,\n batch: ReadonlySet<IAbsoluteStateAddress>,\n activeStateElements: ReadonlySet<IStateElement>,\n): IScanPlan | null {\n if (!isLive(group, activeStateElements)) {\n dropPendingReset(group);\n return null;\n }\n const { stateElement, entry } = group;\n if (group.reset) {\n // reset が勝つ(D6)。同じバッチの行は畳まない\n return { group, next: entry.initial };\n }\n // reset でない group は `from` の行ヒットから作られている\n const source = entry.source as IScanPathSource;\n if (hasGetterOnPath(stateElement, source)) {\n reportLateGetterSource(entry, entry.name, source.path);\n return null;\n }\n if (isStreamRestartPending(stateElement, source.pathInfo.segments[0], batch)) {\n return null;\n }\n // コールバック内の代入は制御フロー解析に載らないので、結果と進み具合は入れ物で受け取る\n const result: { plan: IScanPlan | null; failure: ScanFailure } = { plan: null, failure: \"read-output\" };\n try {\n stateElement.createState(\"readonly\", (state) => {\n const start = state[entry.name];\n // 行の位置引き(selectLandedRows)はリストを読むので throw しうる。出力の読みは\n // 済んでいるので、ここから先の失敗は `from` 側(read-rows)として報告する\n result.failure = \"read-rows\";\n const rows = source.pathInfo.wildcardCount === 0\n ? group.rows\n : selectLandedRows(state, source.pathInfo, group.rows);\n result.failure = \"threw\";\n const fold = entry.fold;\n let acc = start;\n for (const row of rows.sort(compareRows)) {\n let cur: unknown;\n try {\n cur = readSource(state, source, row);\n } catch (error) {\n // 読めない行だけを捨てて、残りの行の連鎖は続ける\n reportScanError(entry.name, error, \"read-source\");\n continue;\n }\n const next = fold(acc, cur, getPrevValue(row.absAddress), ...row.indexes);\n if (isThenable(next)) {\n reportScanThenable(entry.name, next);\n return;\n }\n acc = next;\n }\n if (!Object.is(acc, start)) {\n result.plan = { group, next: acc };\n }\n });\n } catch (error) {\n // 他の scan・`$watch`・`$streams` restart を巻き添えにしない(D4)\n reportScanError(entry.name, error, result.failure);\n }\n return result.plan;\n}\n\n/** 相 2 の 1 件: 書く直前に再確認する(後続の scan の fold が同期に切断・再セットし得る)。 */\nfunction commitPlan(plan: IScanPlan, activeStateElements: ReadonlySet<IStateElement>): void {\n const { group } = plan;\n if (!isLive(group, activeStateElements)) {\n dropPendingReset(group);\n return;\n }\n const { stateElement, entry } = group;\n // `on` の reset は保留が残っているときだけ。書き込みの後に来た出来事が `initial` から\n // 畳んで保留を消していれば、その出力は reset 済み(scan/eventReset.ts)\n if (group.reset && entry.source.kind === \"event\" && !consumePendingScanReset(entry)) {\n return;\n }\n try {\n stateElement.createState(\"writable\", (state) => {\n const current = state[entry.name];\n // reset は既に initial と同じ値なら書かない(着地も `$watch` の発火も起こさない)。書くときは複製を置く(D6 / D7)\n const writes = group.reset ? !isSameAsInitial(current, entry.initial) : !Object.is(current, plan.next);\n if (writes) {\n const next = group.reset ? cloneInitial(entry.initial) : plan.next;\n state[entry.name] = next;\n recordOutputValue(entry.name, next);\n }\n });\n } catch (error) {\n reportScanError(entry.name, error, \"write\");\n }\n}\n\n/**\n * 相 1: バッチの `from` / `resetOn` ヒットを集め、宣言順に次の値を決める(書かない)。\n * `depth` は watch runtime が消費した連鎖深さ。fold の中の書き込みも連鎖に数える。\n */\nexport function planScansOnUpdateBatch(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n activeStateElements: ReadonlySet<IStateElement>,\n depth: number,\n): readonly IScanPlan[] {\n // 発火対象でない state(書き込みの後に切断された)の `on` scan の保留 reset を捨てる(D6)。\n // drain のゲートより前に置く — 切断で最後の scan がゲートから外れても、その書き込みの保留は残っている\n discardSkippedScanResets(batch, activeStateElements);\n if (getScanDrainGateCount() === 0) {\n return NO_PLANS;\n }\n const groups = new Map<IScanEntry, IScanGroup>();\n for (const absAddress of batch) {\n const stateElement = absAddress.absolutePathInfo.stateElement;\n if (!activeStateElements.has(stateElement)) {\n continue;\n }\n const registry = getScanRegistry(stateElement);\n if (typeof registry === \"undefined\") {\n continue;\n }\n const pathInfo = absAddress.absolutePathInfo.pathInfo;\n const fromEntries = registry.byFromPath.get(pathInfo.path);\n if (typeof fromEntries !== \"undefined\") {\n let indexes: number[] = [];\n if (pathInfo.wildcardCount > 0) {\n if (absAddress.listIndex === null) {\n // 行が特定できないヒット(リストの依存展開で載る中間アドレス等)。`$watch` と同じく落とす\n continue;\n }\n indexes = getScopedIndexes(absAddress.listIndex, pathInfo.wildcardCount);\n }\n for (const entry of fromEntries) {\n groupOf(groups, stateElement, entry).rows.push({ absAddress, indexes });\n }\n }\n const resetEntries = registry.byResetPath.get(pathInfo.path);\n if (typeof resetEntries !== \"undefined\") {\n for (const entry of resetEntries) {\n groupOf(groups, stateElement, entry).reset = true;\n }\n }\n }\n if (groups.size === 0) {\n return NO_PLANS;\n }\n const ordered = Array.from(groups.values()).sort((a, b) => a.entry.order - b.entry.order);\n const plans: IScanPlan[] = [];\n beginWatchFiring(depth);\n try {\n for (const group of ordered) {\n const plan = planGroup(group, batch, activeStateElements);\n if (plan !== null) {\n plans.push(plan);\n }\n }\n } finally {\n endWatchFiring();\n }\n return plans;\n}\n\n/**\n * 相 2: 計画を宣言順に書く(D18)。同じ drain の `$watch` の発火より前(D11)。\n * scan の書き込みも連鎖深さに数える。\n */\nexport function commitScanPlans(\n plans: readonly IScanPlan[],\n activeStateElements: ReadonlySet<IStateElement>,\n depth: number,\n): void {\n if (plans.length === 0) {\n return;\n }\n beginWatchFiring(depth);\n try {\n for (const plan of plans) {\n commitPlan(plan, activeStateElements);\n }\n } finally {\n endWatchFiring();\n }\n}\n","/**\n * watch/watchRuntime.ts\n *\n * `$watch` の発火(docs/state-watch-hook-design.md §3 / §7)。\n *\n * updater の drain 終了フックに 1 つだけリスナーを登録し、バッチに載った絶対アドレスと\n * 宣言済み watch パスを突き合わせて発火する。**binding の有無に関係なくバッチへ載る**ので、\n * これが headless 購読の実体になる(binding 駆動の `$updatedCallback` との違い)。\n *\n * 実行順序(設計書 §3-2):\n * - 機構間は優先度で固定(`$updatedCallback` → `$scan` → `$watch` → `$streams` restart)。\n * `$updatedCallback` が先なのは binding 適用ループの内側で呼ばれる構造的必然。\n * `$scan` の `from` / `resetOn` は同じリスナーの中で `$watch` より先に畳んで書く\n * (docs/state-scan-design.md D11 / D18)。\n * - watch ハンドラ間は `$watch` の宣言順(entry.order)。利用者が順序に意思を持てる唯一の層。\n * - 同一パスの複数行は indexes 昇順。\n *\n * 収集と発火を 2 相に分ける理由:\n * 1. ハンドラ内の書き込みが registry / active 集合を同期的に変えうる(`_state` 再 set・切断)\n * ため、発火直前に live 再チェックが要る(`$streams` の restart hits と同型)。\n * 2. 上記の順序規約のために hits をソートする必要がある(バッチの反復順は enqueue 順)。\n */\n\nimport { absoluteAddressOf } from \"../address/liftAddress\";\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { MAX_WATCH_CHAIN_DEPTH, WATCH_LISTENER_PRIORITY } from \"../define\";\nimport { devtoolsSink } from \"../platform/devtoolsSink\";\nimport { getScopedIndexes } from \"../list/wildcardLevel\";\nimport type { IStateProxy } from \"../proxy/types\";\nimport { registerEnqueueListener, registerUpdateBatchListener } from \"../updater/updater\";\nimport { beginWatchFiring, consumeWatchChainDepth, endWatchFiring, noteEnqueueForWatchChain } from \"./chainDepth\";\nimport { getComputedSnapshot, setComputedSnapshot } from \"./computedSnapshots\";\nimport { clearPrevValues, getPrevValue } from \"./prevValues\";\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { STATE_SCAN_NAME, STATE_WATCH_NAME } from \"../define\";\nimport { inSsr } from \"../config\";\nimport { clearComputedSnapshots } from \"./computedSnapshots\";\nimport { assertValidWatchPath, processWatchDeclaration } from \"./processWatchDeclaration\";\nimport { addVolumeWatchEntries, clearWatchRegistry, deactivateWatch } from \"./watchRegistry\";\nimport { setVolumeWatchSupport } from \"../bridge/featureBridge\";\nimport { registerFeatureHooks } from \"../core/addressHooks\";\nimport { watchAddressHooks } from \"./addressHooks\";\nimport { hasRetiredRow, selectLandedRows } from \"./rowLanding\";\nimport { addActiveWatchStateElement, getActiveWatchStateElements, getVolumeWatchEntries, getWatchEntries } from \"./watchRegistry\";\nimport { hasScanDrainWork } from \"../scan/scanRegistry\";\nimport { commitScanPlans, discardSkippedScanResets, planScansOnUpdateBatch } from \"../scan/scanRuntime\";\nimport type { IWatchEntry } from \"./types\";\n\ninterface IWatchHit {\n readonly stateElement: IStateElement;\n readonly entry: IWatchEntry;\n readonly absAddress: IAbsoluteStateAddress;\n readonly indexes: number[];\n}\n\n/**\n * この stateElement の `$watch` を有効化する(`State.connectedCallback` /接続中の\n * `_state` 再 set から呼ばれる。無効化は `clearWatchRegistry`)。\n *\n * `addActiveWatchStateElement` の薄いラッパではなく、**State が runtime を import する\n * 経路をここに一本化する**意味がある: drain リスナーの登録はこのモジュールの\n * 初期化副作用なので、registry だけを import すると発火機構ごと落ちる。\n * `$streams` の `startStreams` と対称の位置づけ。\n *\n * **宣言が 1 つも無ければ active 集合に入れない**(`startStreams` の\n * `entries.size === 0` early return と同型)。ここを無条件にすると active 集合が\n * 「接続中の全 `<wcs-state>`」になり、`fireWatchOnUpdateBatch` の early return が\n * 実アプリで効かなくなる = `$watch` 未使用アプリの drain にも収集ループが乗る\n * (ゼロコスト契約、設計書 §10 / 実装計画 P16)。\n *\n * `$scan` の `from` / `resetOn` も同じ drain リスナーで発火するので、それだけを宣言した\n * state も発火対象に載せる(docs/state-scan-design.md D11)。\n */\nexport function startWatch(stateElement: IStateElement): void {\n // 初回の宣言起動で listener を確実に載せる(bootstrapState() を経ない経路の保険。冪等)\n installWatchRuntime();\n if (getWatchEntries(stateElement).size === 0 && getVolumeWatchEntries(stateElement).size === 0 && !hasScanDrainWork(stateElement)) {\n return;\n }\n addActiveWatchStateElement(stateElement);\n primeComputedWatches(stateElement);\n}\n\n/**\n * watch 対象の computed(getter)を 1 回評価する(設計書 §5-2 の eager 化、C-3)。\n *\n * これが要るのは、getter の依存(dynamicDependency)が**評価時にしか張られない**ため。\n * 一度も評価されていない getter は依存グラフに載らず、依存の書き込みが walkDependency で\n * そのパスへ到達しないので、バッチにも載らず watch が永久に発火しない。ここで 1 回\n * 読むことで依存が張られ、同時に `prev` の初期スナップショットが埋まる。\n *\n * **これが「watch した getter は lazy でなくなる」の実体**であり、設計書 §5-2 で\n * 規範として明記している副作用(毎バッチ評価・例外の表面化・依存の再登録)の起点。\n *\n * ワイルドカードを含む getter パス(`items.*.tax` など)は対象外: 初回評価に行ごとの\n * indexes が要り、全行評価は宣言しただけでリスト全体を舐めることになる。この形は\n * 「DOM にバインドされていれば発火する」ままとし、§5-3 に制約として書く。\n */\nfunction primeComputedWatches(stateElement: IStateElement): void {\n // 宣言(watch か scan)が 1 つ以上あることは startWatch が保証済み。scan だけなら targets は空\n const targets: IWatchEntry[] = [];\n for (const entry of getWatchEntries(stateElement).values()) {\n if (isScalarComputed(stateElement, entry)) {\n targets.push(entry);\n }\n }\n for (const entries of getVolumeWatchEntries(stateElement).values()) {\n for (const entry of entries) {\n if (isScalarComputed(stateElement, entry)) {\n targets.push(entry);\n }\n }\n }\n if (targets.length === 0) {\n // getter を watch していないなら createState ごと省く(宣言の大半はこちら)\n return;\n }\n stateElement.createState(\"readonly\", (state) => {\n for (const entry of targets) {\n try {\n // ワイルドカードを含まない watch パスなので、listIndex は常に null\n setComputedSnapshot(stateElement, absoluteAddressOf(stateElement, entry.pathInfo, null), state[entry.path]);\n } catch (e) {\n // 初回評価の throw は接続を巻き添えにしない(発火時と同じ隔離方針、§7-1)\n reportWatchError(stateElement, entry.path, \"prime\", e);\n }\n }\n });\n}\n\n\n/**\n * 前回評価値のスナップショット台帳(computedSnapshots)に載せる entry か。\n *\n * ワイルドカードを含む getter を**除く**のが要点。除かないと台帳のキーが行ごとの\n * 絶対アドレス(= listIndex を強参照)になり、prune 経路が `_state` 再 set しか\n * 無いため、行が入れ替わり続けるページで単調増加する(リスト置換 5 回で 2→10 件を実測)。\n * そもそもワイルドカード getter は eager 化の対象外(設計書 §5-3)なので、\n * 「初回評価もしない・前回値も持たない」で primeComputedWatches と対称になる。\n * この形の `prev` は常に undefined(getter は setByAddress を通らない)。\n */\nfunction isScalarComputed(stateElement: IStateElement, entry: IWatchEntry): boolean {\n return entry.pathInfo.wildcardCount === 0 && stateElement.getterPaths.has(entry.path);\n}\n\n/**\n * throw を報告する(設計書 §7-1)。\n *\n * `console.error` だけだと **devtools からは「静かに握られた失敗」が見えない**。\n * watch は drain フックを `$streams` と共有しており、例外を watch 側で閉じるのが\n * 前提なので、閉じた事実をここで観測可能にしておく必要がある。\n * イベント生成は必ず `devtoolsSink !== null` の内側で行う(sink のコスト規範)。\n */\nconst WATCH_ERROR_SUBJECT: Readonly<Record<\"prime\" | \"evaluate\" | \"handler\", string>> = {\n prime: \"initial evaluation of\",\n evaluate: \"evaluation of\",\n handler: \"handler for\",\n};\n\nfunction reportWatchError(\n stateElement: IStateElement,\n path: string,\n phase: \"prime\" | \"evaluate\" | \"handler\",\n error: unknown,\n): void {\n console.error(`[@wcstack/state] $watch ${WATCH_ERROR_SUBJECT[phase]} \"${path}\" threw.`, error);\n if (devtoolsSink !== null) {\n devtoolsSink({\n type: \"state:watch-error\",\n phase,\n path,\n error,\n });\n }\n}\n\nfunction fireWatchOnUpdateBatch(batch: ReadonlySet<IAbsoluteStateAddress>): void {\n const activeStateElements = getActiveWatchStateElements();\n try {\n if (activeStateElements.size === 0) {\n // watch 未使用アプリの drain に配列・イテレータ割り当てのコストを載せない。\n // ここも finally を通す: 宣言済みの state が切断されている間(active からは\n // 外れるが watchPaths は残る)の書き込みで台帳に旧値が積まれるため、\n // クリアを早期 return の外に置くと次のバッチどころか永久に残る。\n // 書き込みの後・drain の前に切断された state の `on` scan の保留 reset も、このバッチでは\n // 発火しないので捨てる(scan/eventReset.ts)。\n discardSkippedScanResets(batch, activeStateElements);\n return;\n }\n const depth = consumeWatchChainDepth();\n if (depth > MAX_WATCH_CHAIN_DEPTH) {\n // 打ち切るのは同じリスナーの発火(`$scan` の from / resetOn と `$watch`)のみ。\n // 値と binding 適用は巻き戻さない(伝播 hop 上限超過時の quarantine と同じ姿勢、§7-2)。\n // `on` scan の保留 reset もこのバッチでは効かせない(`from` の scan が reset しないのと揃える)。\n discardSkippedScanResets(batch, null);\n const paths = Array.from(batch, (absAddress) => absAddress.absolutePathInfo.pathInfo.path);\n console.error(\n `[@wcstack/state] $watch chain depth limit exceeded; $scan folds and $watch handlers for this batch were skipped.`,\n { maxDepth: MAX_WATCH_CHAIN_DEPTH, paths },\n );\n if (devtoolsSink !== null) {\n devtoolsSink({ type: \"state:watch-chain-limit\", maxDepth: MAX_WATCH_CHAIN_DEPTH, paths });\n }\n return;\n }\n\n // `$scan` の from / resetOn を `$watch` より先に畳んで書く(docs/state-scan-design.md D11 / D18)。\n // scan の書き込みは次のバッチに乗るので、この drain の `$watch` の収集には影響しない。同じ drain の\n // `$watch` ハンドラは書いた後の出力を読み、ハンドラが出力へ書いた値はそのまま残る。\n commitScanPlans(planScansOnUpdateBatch(batch, activeStateElements, depth), activeStateElements, depth);\n fireWatchHits(batch, activeStateElements, depth);\n } finally {\n // 旧値台帳はこの drain 限りのもの。次のバッチへ持ち越さない(§4-1)。\n clearPrevValues();\n }\n}\n\n/** バッチの `$watch` ヒットを集めて(収集フェーズ)、宣言順・indexes 昇順に発火する(発火フェーズ)。 */\nfunction fireWatchHits(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n activeStateElements: ReadonlySet<IStateElement>,\n depth: number,\n): void {\n // --- 収集フェーズ ---\n const hits: IWatchHit[] = [];\n for (const absAddress of batch) {\n // stateElement 参照で引く。TreePath は\n // stateElement 単位でキャッシュされるので、同名 state が複数の rootNode に\n // 居ても取り違えない(address/TreePath.ts)。他 state のアドレスは\n // ここで自然に落ちる = 越境しない(設計 D8)。\n const stateElement = absAddress.absolutePathInfo.stateElement;\n if (!activeStateElements.has(stateElement)) {\n continue;\n }\n const path = absAddress.absolutePathInfo.pathInfo.path;\n const own = getWatchEntries(stateElement).get(path);\n const fromVolumes = getVolumeWatchEntries(stateElement).get(path);\n if (typeof own === \"undefined\" && typeof fromVolumes === \"undefined\") {\n continue;\n }\n const matched: IWatchEntry[] = typeof own === \"undefined\" ? [] : [own];\n if (typeof fromVolumes !== \"undefined\") {\n matched.push(...fromVolumes);\n }\n for (const entry of matched) {\n let indexes: number[] = [];\n if (entry.pathInfo.wildcardCount > 0) {\n if (absAddress.listIndex === null) {\n // ワイルドカードパスなのに行が特定できないヒット(リストの依存展開で載る\n // 中間アドレス等)。indexes を空のまま発火すると cur の解決($resolve)が\n // 「indexes 不足」で throw し、例外隔離に落ちて console.error だけが残る。\n // 行が定まらない以上ハンドラに渡せる意味が無いので、収集段階で落とす。\n continue;\n }\n indexes = getScopedIndexes(absAddress.listIndex, entry.pathInfo.wildcardCount);\n }\n hits.push({ stateElement, entry, absAddress, indexes });\n }\n }\n if (hits.length === 0) {\n return;\n }\n hits.sort(compareHits);\n const landed = selectWatchLandings(hits);\n\n // --- 発火フェーズ ---\n beginWatchFiring(depth);\n try {\n for (const hit of landed) {\n // 先行ハンドラが同期的に切断や `_state` 再 set を行い得るため、発火直前に\n // 「まだ active か」「entry が現行 registry のものか」を再確認する。\n if (!activeStateElements.has(hit.stateElement)) {\n continue;\n }\n const stillOwn = getWatchEntries(hit.stateElement).get(hit.entry.path) === hit.entry;\n const stillVolume = getVolumeWatchEntries(hit.stateElement).get(hit.entry.path)?.includes(hit.entry) === true;\n if (!stillOwn && !stillVolume) {\n continue;\n }\n fireOne(hit);\n }\n } finally {\n endWatchFiring();\n }\n}\n\n/**\n * ワイルドカードの watch の行の着地を、いまのリストの位置 1 つにつき 1 つに絞る(`$scan` の `from` と\n * 同じ選別 — watch/rowLanding.ts・#274)。`hits` は compareHits でソート済みで、戻り値もその順を保つ。\n *\n * 位置を引くにはリストを読むので、引くのは退役した行を含むヒットがあるか、同じ entry・同じ indexes の\n * ヒットが並ぶ(ソート済みなので隣り合う)entry だけ。行の値を書くだけのバッチ(大多数)は\n * WeakSet の引きだけで抜ける。\n */\nfunction selectWatchLandings(hits: IWatchHit[]): IWatchHit[] {\n let entries: Set<IWatchEntry> | null = null;\n for (let i = 0; i < hits.length; i++) {\n const hit = hits[i];\n if (hit.entry.pathInfo.wildcardCount === 0) {\n continue;\n }\n const previous = hits[i - 1];\n // ワイルドカードの hit は収集の段階で listIndex を持つものに限っている\n if (hasRetiredRow(hit.absAddress.listIndex!)\n || (previous?.entry === hit.entry && isSameIndexes(previous.indexes, hit.indexes))) {\n (entries ??= new Set()).add(hit.entry);\n }\n }\n if (entries === null) {\n return hits;\n }\n const dropped = new Set<IWatchHit>();\n for (const entry of entries) {\n // entry は 1 つの state 要素の registry に属するので、group の state 要素は 1 つ\n const group = hits.filter((hit) => hit.entry === entry);\n const stateElement = group[0].stateElement;\n try {\n stateElement.createState(\"readonly\", (state) => {\n const kept = new Set(selectLandedRows(state, entry.pathInfo, group));\n for (const hit of group) {\n if (!kept.has(hit)) {\n dropped.add(hit);\n }\n }\n });\n } catch (e) {\n // 位置を引く読み(リストのパスの getter など)が throw した。同じリストを通る cur も読めないので、\n // この entry のヒットは発火せず、評価の失敗として 1 回報告する(他の watch は続行する)\n reportWatchError(stateElement, entry.path, \"evaluate\", e);\n for (const hit of group) {\n dropped.add(hit);\n }\n }\n }\n return hits.filter((hit) => !dropped.has(hit));\n}\n\n/** 同じ entry の hit どうし(indexes の長さは等しい) */\nfunction isSameIndexes(a: readonly number[], b: readonly number[]): boolean {\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * 層 2(宣言順)→ 層 3(indexes 昇順)の順に比較する(設計書 §3-3)。\n */\nfunction compareHits(a: IWatchHit, b: IWatchHit): number {\n if (a.entry.order !== b.entry.order) {\n return a.entry.order - b.entry.order;\n }\n const length = Math.min(a.indexes.length, b.indexes.length);\n for (let i = 0; i < length; i++) {\n if (a.indexes[i] !== b.indexes[i]) {\n return a.indexes[i] - b.indexes[i];\n }\n }\n return a.indexes.length - b.indexes.length;\n}\n\n/**\n * ハンドラ 1 つを発火する。**例外はここで閉じる**(設計書 §7-1)。\n *\n * drain リスナーの throw は握りつぶさない契約(updater.ts)なので、watch 側で捕まえないと\n * 1 つのユーザー例外が他の watch と `$streams` の restart を巻き添えにする。\n * `$connectedCallback` / `$updatedCallback` の loud fail とは意図的に異なる扱い。\n *\n * 報告は throw 元で分ける: `cur` の解決(watch した getter の強制評価 = §5-2 の副作用 b)と\n * ハンドラ本体では原因も直し方も違うため、同じ文言に丸めない。\n */\nfunction fireOne(hit: IWatchHit): void {\n const { stateElement, entry, absAddress, indexes } = hit;\n // スカラ getter は setByAddress を通らないので旧値台帳に載らない。前回評価値の\n // スナップショット(バッチを跨いで生きる別台帳)から prev を取る(§5-2)。\n const isComputed = isScalarComputed(stateElement, entry);\n try {\n stateElement.createState(\"writable\", (state) => {\n let cur: unknown;\n try {\n // 強制評価はここ。dirty なら再計算され、その結果が cur になる\n cur = readCurrentValue(state, entry, indexes);\n } catch (e) {\n // cur が得られない以上ハンドラは呼べない。次の hit へ進む\n reportWatchError(stateElement, entry.path, \"evaluate\", e);\n return;\n }\n const prev = isComputed ? getComputedSnapshot(stateElement, absAddress) : getPrevValue(absAddress);\n if (isComputed) {\n // ハンドラ本体が throw しても次回の prev は「今回の評価値」であるべきなので、\n // handler 呼び出しより前に更新する\n setComputedSnapshot(stateElement, absAddress, cur);\n }\n // 正常発火の観測(設計書 §11 の予約イベント・配線カバレッジの実測面)。\n // 値は載せない。イベント生成は sink 接続時のみ(ゼロコスト契約)。\n // stateElement は発火元ツリーの識別(protocol v2 追補)— これが無いと\n // 複数ツリーが同名 watch パスを宣言するページで実測が合算される。\n if (devtoolsSink !== null) {\n devtoolsSink({ type: \"state:watch-fired\", path: entry.path, stateElement });\n }\n entry.handler.call(state, cur, prev, ...indexes);\n });\n } catch (e) {\n reportWatchError(stateElement, entry.path, \"handler\", e);\n }\n}\n\nfunction readCurrentValue(state: IStateProxy, entry: IWatchEntry, indexes: number[]): unknown {\n if (entry.pathInfo.wildcardCount === 0) {\n return state[entry.path];\n }\n // ワイルドカードを含むパスは素の読みでは解決できない。getScopedIndexes が返した列は\n // そのまま $resolve の引数として使える(list/wildcardLevel.ts の往復契約)。\n return state.$resolve(entry.path, indexes);\n}\n\n// drain 終了 listener の登録。優先度で `$streams` の restart より先に固定する(設計書 §3-2 層 1)。\n// モジュール評価時には登録しない: import しただけの利用(ヘルパーだけの import・分割エントリ)に\n// 副作用を残さないため、full / auto エントリの bootstrapState() が呼ぶ(冪等)。\nlet watchRuntimeInstalled = false;\nexport function installWatchRuntime(): void {\n if (watchRuntimeInstalled) return;\n watchRuntimeInstalled = true;\n registerFeatureHooks(\"watch\", watchAddressHooks);\n registerDeclarationHooks(\"watch\", watchDeclarationHooks);\n registerUpdateBatchListener(fireWatchOnUpdateBatch, WATCH_LISTENER_PRIORITY);\n // ハンドラ実行中の書き込みだけを連鎖としてマークする(chainDepth.ts)。ハンドラ実行中でなければ即 return\n registerEnqueueListener(noteEnqueueForWatchChain);\n // ボリュームの `$watch` 接頭辞登録(webComponent/volume.ts)はここ経由で呼ばれる。\n // scopes が watch を静的 import すると、scopes だけのページに temporal ランタイムが\n // 丸ごと乗る(要件 B13 / bridge/featureBridge.ts のヘッダ)\n setVolumeWatchSupport({\n assertValidPath: assertValidWatchPath,\n addEntries: addVolumeWatchEntries,\n start: startWatch,\n });\n}\n\n/**\n * `$watch` の宣言とライフサイクル(設計案 H4)。従来 `State` の `_state` セッターと\n * connectedCallback / disconnectedCallback に直書きされていた分岐で、順序の理由は各所に残した。\n */\nexport const watchDeclarationHooks: IDeclarationHooks = {\n // stream より先に起動し、後に停止する(受け口が deactivate を逆順で回す)\n order: 10,\n register(element, value) {\n // $watch: 旧宣言のハンドラが残らないよう registry を落としてから新宣言を解析する。\n // _pathSet.clear() の後であること(依存グラフ登録をやり直す必要がある、\n // docs/state-watch-hook-design.md §8)。宣言が無ければ watchPaths は null で、\n // setByAddress の旧値キャプチャには一切入らない(§10 のゼロコスト契約)。\n clearWatchRegistry(element);\n // computed の前回評価値も宣言と寿命を共にする(旧宣言の値を新しい watch の\n // prev として渡さない)。切断では消さない — 再接続の初回評価が上書きする。\n clearComputedSnapshots(element);\n const watchPaths = processWatchDeclaration(element, value);\n element.setWatchPaths?.(watchPaths);\n if (watchPaths !== null || element.scanPaths != null) {\n // 旧値の台帳(`$watch` の prev・`$scan` の from)は watch 機能の hook が書き込み時に記録する\n element.attachAddressHooks?.(\"watch\", watchPaths !== null ? STATE_WATCH_NAME : STATE_SCAN_NAME);\n }\n },\n activate(element, captured) {\n // SSR では走らせない — ハンドラの副作用がサーバとクライアントで二重に実行されるため\n // (docs/state-watch-hook-design.md §11)。rootNode ガード: $connectedCallback の await 中に\n // 切断された場合は起動しない。世代ガード(接続末尾のみ): await 中に「切断 → 即再接続」された\n // 場合、新 connect が rootNode を再設定済みでガードを素通りするため、世代不一致で陳腐化した\n // connect の再開を検出して skip する。\n // 再入不要: 接続中の再 set は下の宣言側で startWatch 済みだが、startWatch は Set への add で\n // 冪等なので $streams のような世代ガードは要らない。\n if (inSsr() || element.connectedRootNode == null) {\n return;\n }\n if (captured === null ? element.initialized !== true : captured !== element.connectGeneration) {\n return;\n }\n startWatch(element);\n },\n deactivate(element) {\n // watch は発火対象から外すだけで registry は保持する(stream の abortAllStreams と\n // 同じ二段構え、設計書 §9)。registry まで捨てると、_state セッターが再度走らない\n // 再接続で宣言を作り直せず watch が二度と発火しない。\n deactivateWatch(element);\n },\n};\n\nexport const __private__ = {\n fireWatchOnUpdateBatch,\n compareHits,\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":["registryByStateElement","WeakMap","drainActive","Set","eventResetActive","hasDrainWork","registry","byFromPath","size","byResetPath","pushEntry","map","key","entry","list","get","set","push","getScanRegistry","stateElement","clearScanRegistry","deactivateScanGates","delete","pendingResets","WeakSet","pendingResetCount","eventResetEntriesAt","absAddress","absolutePathInfo","eventResetByPath","pathInfo","path","noteEnqueueForScanReset","has","entries","markPendingScanReset","add","consumePendingScanReset","ARRAY_INDEX","isEnumerableData","target","descriptor","Object","getOwnPropertyDescriptor","enumerable","plainKind","value","isFrozen","proto","getPrototypeOf","Array","isArray","prototype","Reflect","ownKeys","every","test","cloneValue","copies","kind","source","known","copy","length","create","keys","cloneInitial","initial","Map","sameValue","current","compared","is","left","right","seen","index","hasOwnProperty","call","isSameAsInitial","outputNamesByFunction","recordOutputValue","name","names","wasPlacedOnOutput","SCAN_FAILURE_MESSAGE","STATE_SCAN_NAME","threw","write","SCAN_FAILURE_PHASE","sendToDevtools","phase","error","devtoolsSink","type","reportScanError","failure","console","isThenable","then","reportScanThenable","undefined","TypeError","lateGetterReported","INVALID","NO_RESET","freeze","entryLabel","findGetterOnPath","getterPaths","cumulativePaths","computedMessage","label","field","getter","includes","WILDCARD","LINT_HINT","assertValidScanPath","raiseError","startsWith","getPathInfo","segment","segments","wildcardCount","MAX_WILDCARD_DEPTH","assertOutputName","setterPaths","streamNames","DELIMITER","STATE_STREAM_NAME","assertNoMethodConflict","functionValues","definition","parseSource","eventTokenNames","writeOnlyPaths","recursion","hasFrom","from","hasOn","on","tokenName","STATE_EVENT_TOKENS_NAME","didYouMean","recursiveGetterOwning","setter","writeOnlyMessage","parseResetOn","raw","paths","item","parseScanDeclaration","state","declared","getAllPropertyDescriptors","normalizeDeclarationAliases","streams","collectStreamNames","order","def","fold","resetOn","outputs","next","root","start","chain","n","join","assertNoOutputReferences","createEventFold","event","indexes","proxy","reset","hasPendingScanReset","acc","registerScans","carry","setScanRegistry","carried","some","getUpdater","hasQueuedPath","fromPaths","setPathInfo","SCAN_ENTRIES","scanDeclarationHooks","validate","_element","ctx","applyEarly","element","materializeScanOutputs","getOrCreateEventToken","subscribe","subscribeScanEvents","register","_value","unregisterScans","setScanPaths","installed","NO_EDGES","NO_SCANS","collectReachablePaths","reachable","queue","pop","children","staticDependency","dependents","dynamicDependency","downstream","scan","UNCERTAIN","Symbol","lastNotifiedByStateElement","pruneLastNotified","liveNames","lastMap","invalidateLastNotified","last","status","activeStateElements","deleteActiveStateElement","getStreamEntries","abortAllStreams","values","controller","abort","latestFold","_acc","chunk","NO_STREAM_NAMES","processStreamsDeclaration","descriptors","hasFold","args","depAddresses","setStreamEntries","statusNamespaceByStateElement","errorNamespaceByStateElement","createStreamNamespaceProxy","namespaceName","pick","Proxy","_target","prop","configurable","deleteProperty","getStreamStatusNamespace","cached","STATE_STREAM_STATUS_NAMESPACE_NAME","getStreamErrorNamespace","STATE_STREAM_ERROR_NAMESPACE_NAME","clearStreamNamespace","collector","walkNamespace","namespace","i","streamAddressHooks","read","address","liftAddress","collectStreamDependency","firstSegment","NOT_HANDLED","handler","async","consumeSource","signal","sink","iterator","onAbort","return","addEventListener","once","produced","getReader","stream","reader","cancel","catch","done","removeEventListener","releaseLock","readableToAsyncIterable","asyncIterator","iterate","aborted","result","e","fail","startStreams","installStreamRuntime","addActiveStateElement","startStream","AbortController","argsValue","argsFn","clear","previousCollector","captured","createState","Promise","selfStatusPath","selfErrorPath","dep","traceArgs","streamEntry","depPath","assertNoScanFeedback","updateStreamStatus","getLastNotified","statusChanged","errorChanged","setLastNotified","$postUpdate","restartStreamsOnUpdateBatch","batch","hits","streamRuntimeInstalled","startedGenerationByElement","streamDeclarationHooks","apply","attachAddressHooks","activate","inSsr","connectedRootNode","initialized","connectGeneration","deactivate","registerFeatureHooks","registerDeclarationHooks","registerUpdateBatchListener","STREAM_LISTENER_PRIORITY","firingDepth","pendingDepth","beginWatchFiring","depth","endWatchFiring","noteEnqueueForWatchChain","snapshotsByStateElement","setComputedSnapshot","snapshots","prevValueByAbsoluteStateAddress","recordPrevValue","oldValue","getPrevValue","volumeEntriesByStateElement","EMPTY_ENTRIES","getWatchEntries","addActiveWatchStateElement","hasEventResetWork","activateScanGates","getActiveWatchStateElements","addVolumeWatchEntries","byPath","EMPTY_VOLUME_ENTRIES","getVolumeWatchEntries","assertValidWatchPath","STATE_WATCH_NAME","processWatchDeclaration","setWatchEntries","watchAddressHooks","writeObserve","hasOldValue","watchPaths","scanPaths","swapped","_stateElement","elementAbsAddress","displacedAbsAddress","hasRetiredRow","listIndex","row","parentListIndex","isRetiredListIndex","placementOf","placement","level","getByAddressSymbol","createStateAddress","wildcardParentPathInfos","getListIndexesByList","own","listIndexAtWildcard","isSameListIndexValue","selectLandedRows","rows","byPosition","rank","kept","NO_PLANS","groupOf","groups","group","compareRows","a","b","isLive","dropPendingReset","isQueuedForNextBatch","discardSkippedScanResets","firing","isQueued","discardPendingScanResets","readSource","$resolve","planGroup","hasGetterOnPath","message","Error","reportLateGetterSource","rootName","isStreamRestartPending","plan","sort","cur","commitPlan","planScansOnUpdateBatch","fromEntries","getScopedIndexes","resetEntries","ordered","plans","startWatch","installWatchRuntime","hasScanDrainWork","targets","isScalarComputed","absoluteAddressOf","reportWatchError","primeComputedWatches","WATCH_ERROR_SUBJECT","prime","evaluate","fireWatchOnUpdateBatch","consumeWatchChainDepth","MAX_WATCH_CHAIN_DEPTH","maxDepth","commitScanPlans","fromVolumes","matched","compareHits","landed","hit","previous","isSameIndexes","dropped","filter","selectWatchLandings","stillOwn","stillVolume","fireOne","fireWatchHits","Math","min","isComputed","readCurrentValue","prev","getComputedSnapshot","watchRuntimeInstalled","watchDeclarationHooks","WATCH_LISTENER_PRIORITY","registerEnqueueListener","setVolumeWatchSupport","assertValidPath","addEntries","clearComputedSnapshots","setWatchPaths","temporal","install"],"mappings":"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"}