{"version":3,"names":["action","createMemo","onCleanup","refresh","readOption","createAsyncSource","options","query","activeController","lastError","lastSettledItems","items","q","abort","ctrl","AbortController","undefined","p","fetch","signal","then","v","e","lazy","name","unobserved","commitControllers","Set","controller","clear","commit","value","add","delete","_value","refreshItems","api","snapshotFn","out","status","error","Object","defineProperty","enumerable","configurable","writable"],"sources":["create-async-source.ts"],"sourcesContent":["// fallow-ignore-file unused-file\n// Async substrate for solidify.md §1 (headless primitives) + §4 (suspense-native\n// async). Will be consumed by `createComboboxItem` / `createSelectItem`\n// async-iterable paths once §1 lands.\n\nimport {\n\ttype Accessor,\n\taction,\n\tcreateMemo,\n\tonCleanup,\n\trefresh,\n\ttype SourceAccessor,\n} from \"solid-js\";\nimport { type MaybeAccessor, readOption } from \"../maybe-accessor\";\n\n// Stage 03 — async-compound shape spike.\n//\n// Validates the four axes from the stage stub against a minimal data\n// primitive that's small enough to test in isolation but exercises every\n// concern that the live Combobox-async port will hit:\n//\n//   S — `commit` exposed as an `action()`-typed setter (visible in the\n//       type, no \"transparent upgrade\").\n//   U — resource-owning memo gated by `lazy: true` + `unobserved` teardown,\n//       which lets us hang an AbortController off the *one* signal that\n//       represents subscription liveness.\n//   W — `items()` is async (`createMemo` returning a Promise). Reads\n//       outside `<Loading>` throw `ASYNC_OUTSIDE_LOADING_BOUNDARY`. The\n//       primitive does NOT bake in a wrapper-internal `<Loading>`.\n//   Stage 02 error contract — fetcher throws/rejects propagate through\n//       the graph to `<Errored>`. The primitive does not catch.\n//\n// `createProjection` (axis T) is intentionally not exercised here; for\n// scalar selection there's nothing to project. The retro carries this\n// forward as deferred.\n//\n// Companion doc: work-left/primitive-template.md §2.4.\n\nexport interface CreateAsyncSourceOptions<Q, V> {\n\t/**\n\t * Reactive query. Each settled flip re-runs the fetcher; in-flight\n\t * fetches against the prior query are aborted.\n\t */\n\tquery: MaybeAccessor<Q>;\n\t/**\n\t * Async fetcher. `signal` aborts when:\n\t *   1. `query` flips before the fetch resolves (last-start-wins).\n\t *   2. The `items` memo loses every subscriber (`unobserved`).\n\t *   3. The owning scope disposes (`onCleanup`).\n\t *\n\t * Throwing or rejecting propagates through the graph to the nearest\n\t * `<Errored>` boundary. The primitive does not swallow.\n\t */\n\tfetch: (query: Q, signal: AbortSignal) => Promise<readonly V[]>;\n\t/**\n\t * Optional async commit. Exposed on the API as an `action()`-typed\n\t * setter — consumers awaiting it participate in the same transition\n\t * as the items memo, and `isPending(() => c.items())` reflects\n\t * commit-driven invalidations.\n\t */\n\tcommit?: (value: V, signal: AbortSignal) => Promise<void>;\n}\n\nexport interface AsyncSourceApi<Q, V> {\n\tquery: Accessor<Q>;\n\t/**\n\t * Async accessor. Reads inside a `<Loading>` ancestor suspend during\n\t * the initial fetch and reveal stale-while-revalidating during\n\t * re-fetches. Reads outside any `<Loading>` ancestor throw\n\t * `ASYNC_OUTSIDE_LOADING_BOUNDARY`.\n\t *\n\t * Fetcher rejections re-throw on every read until the next successful\n\t * fetch — wrap in `<Errored>` (stage 02 contract).\n\t */\n\titems: Accessor<readonly V[]>;\n\t/**\n\t * `action()`-typed commit. Async generator under the hood — the\n\t * returned promise resolves when the action's transition settles.\n\t * Visible in the type signature (no \"transparent upgrade\" — the\n\t * action-ness is part of the public surface, axis S).\n\t */\n\tcommit: (value: V) => Promise<void>;\n\t/**\n\t * Imperatively re-run the items fetcher. Useful after a server write\n\t * that doesn't flip `query`. Equivalent to `refresh(c.items)` but\n\t * keeps the memo handle private.\n\t */\n\trefresh: () => void;\n}\n\nexport function createAsyncSource<Q, V>(\n\toptions: CreateAsyncSourceOptions<Q, V>,\n): AsyncSourceApi<Q, V> {\n\tconst query: Accessor<Q> = () => readOption(options.query);\n\n\t// `lazy: true` defers the first fetch until something reads `items()`.\n\t// Combined with `unobserved`, the resource lifecycle is:\n\t//\n\t//   first read → fetch starts (controller A live).\n\t//   query flip → memo re-runs → onCleanup aborts A → fetch starts B.\n\t//   all readers go away → unobserved → abort B + null out.\n\t//   reader returns → memo recomputes → fresh controller C.\n\t//\n\t// The AbortController is held in a closure-local that the unobserved\n\t// callback can reach. Per RFC 01, `unobserved` is per-signal/memo —\n\t// hanging it off the resource-owning memo gives compound-level\n\t// teardown semantics for free.\n\tlet activeController: AbortController | null = null;\n\t// Snapshot bookkeeping — `lastError` is the most recent fetch rejection\n\t// (cleared whenever a new fetch starts). Reading `items()` outside a\n\t// `<Loading>` boundary throws a runtime sentinel that's not a real\n\t// rejection; this flag lets `snapshot()` distinguish \"fetch in flight\"\n\t// from \"fetch rejected\" without inspecting Solid-internal error types.\n\tlet lastError: unknown;\n\tlet lastSettledItems: readonly V[] | undefined;\n\n\ttype AsyncMemoAccessor<T> = SourceAccessor<Promise<T>> & SourceAccessor<T>;\n\tconst items: SourceAccessor<readonly V[]> = createMemo<Promise<readonly V[]>>(\n\t\t() => {\n\t\t\tconst q = query();\n\n\t\t\tactiveController?.abort();\n\t\t\tconst ctrl = new AbortController();\n\t\t\tactiveController = ctrl;\n\n\t\t\t// Fires when the memo re-evaluates (dependency change) or\n\t\t\t// when its owner disposes. Belt-and-braces with `unobserved`:\n\t\t\t// onCleanup covers re-runs and dispose, unobserved covers\n\t\t\t// \"all subscribers gone\" without re-evaluation.\n\t\t\tonCleanup(() => {\n\t\t\t\tif (activeController === ctrl) activeController = null;\n\t\t\t\tctrl.abort();\n\t\t\t});\n\n\t\t\tlastError = undefined;\n\t\t\tconst p = options.fetch(q, ctrl.signal);\n\t\t\tp.then(\n\t\t\t\t(v) => {\n\t\t\t\t\tif (activeController === ctrl) lastSettledItems = v;\n\t\t\t\t},\n\t\t\t\t(e) => {\n\t\t\t\t\tif (activeController === ctrl) lastError = e;\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn p;\n\t\t},\n\t\t{\n\t\t\tlazy: true,\n\t\t\tname: \"async-source.items\",\n\t\t\tunobserved: () => {\n\t\t\t\tactiveController?.abort();\n\t\t\t\tactiveController = null;\n\t\t\t},\n\t\t},\n\t) as AsyncMemoAccessor<readonly V[]>;\n\t// Cast: the memo's compute returns Promise<readonly V[]>, but Solid 2\n\t// async-memos surface the resolved value at the read site (suspending\n\t// in <Loading> until ready). The runtime type is the unwrapped form;\n\t// the declared compute type is the promise. This matches RFC 05 —\n\t// `createMemo(() => fetchUser())` reads as `User`, not `Promise<User>`.\n\t//\n\t// Cast target is `SourceAccessor` (= `Refreshable<Accessor<…>>`), not a\n\t// bare `Accessor` — `createMemo` returns the refreshable brand and we\n\t// keep it so `refresh(items)` below type-checks against the live memo.\n\n\t// `action()` wraps an async generator. The returned function is a\n\t// regular `(value: V) => Promise<void>` — visible in the type — that\n\t// runs inside a transition. Aborts cascade through the same controller\n\t// pattern as the fetch path; consumers can branch on `signal.aborted`\n\t// inside their commit fn. Beta.28 routes generator rejections to the\n\t// returned promise without the local signals patch older betas required.\n\tconst commitControllers = new Set<AbortController>();\n\tonCleanup(() => {\n\t\tfor (const controller of commitControllers) controller.abort();\n\t\tcommitControllers.clear();\n\t});\n\n\tconst commit = options.commit\n\t\t? action(async function* (\n\t\t\t\tvalue: V,\n\t\t\t): AsyncGenerator<unknown, void, unknown> {\n\t\t\t\tconst ctrl = new AbortController();\n\t\t\t\tcommitControllers.add(ctrl);\n\t\t\t\ttry {\n\t\t\t\t\tawait (options.commit as NonNullable<typeof options.commit>)(\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tctrl.signal,\n\t\t\t\t\t);\n\t\t\t\t\tyield;\n\t\t\t\t} finally {\n\t\t\t\t\tcommitControllers.delete(ctrl);\n\t\t\t\t}\n\t\t\t})\n\t\t: async (_value: V): Promise<void> => undefined;\n\n\tconst refreshItems = (): void => {\n\t\t// `refresh()` re-runs the memo even when `query` is unchanged.\n\t\t// `items` keeps its `Refreshable` brand from `createMemo`, so this\n\t\t// needs no cast.\n\t\tvoid refresh(items);\n\t};\n\n\tconst api: AsyncSourceApi<Q, V> = {\n\t\tquery,\n\t\titems,\n\t\tcommit,\n\t\trefresh: refreshItems,\n\t};\n\t// Custom snapshot override — async compounds use a `{ status, items,\n\t// error }` projection per template §2.5. Reading `items()` outside a\n\t// `<Loading>` boundary throws (a Promise for pending, an Error for\n\t// rejection); we catch both and surface them as data so observability\n\t// tools can call `snapshot(c)` from anywhere.\n\t//\n\t// Defined non-enumerable: `snapshot` is metadata, not part of the\n\t// compound's primary surface (`Object.keys(c)` should still report only\n\t// the four functional keys).\n\tconst snapshotFn = (): Record<string, unknown> => {\n\t\tconst out: Record<string, unknown> = { query: query() };\n\t\tif (lastError !== undefined) {\n\t\t\tout.status = \"error\";\n\t\t\tout.error = lastError;\n\t\t} else if (lastSettledItems !== undefined) {\n\t\t\tout.status = \"settled\";\n\t\t\tout.items = lastSettledItems;\n\t\t} else {\n\t\t\tout.status = \"pending\";\n\t\t}\n\t\treturn out;\n\t};\n\tObject.defineProperty(api as object, \"snapshot\", {\n\t\tvalue: snapshotFn,\n\t\tenumerable: false,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t});\n\treturn api;\n}\n"],"mappings":"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","ignoreList":[]}