@nicolastoulemont/std 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +232 -33
- package/dist/adt/index.d.mts +2 -2
- package/dist/adt/index.mjs +1 -1
- package/dist/adt-DajUZvJe.mjs +2 -0
- package/dist/adt-DajUZvJe.mjs.map +1 -0
- package/dist/brand/index.d.mts +2 -2
- package/dist/brand/index.mjs +1 -1
- package/dist/brand-Bia3Vj6l.mjs +2 -0
- package/dist/brand-Bia3Vj6l.mjs.map +1 -0
- package/dist/context/index.d.mts +2 -0
- package/dist/context/index.mjs +1 -0
- package/dist/context-CCHj1nab.mjs +2 -0
- package/dist/context-CCHj1nab.mjs.map +1 -0
- package/dist/context-r8ESJiFn.d.mts +176 -0
- package/dist/context-r8ESJiFn.d.mts.map +1 -0
- package/dist/data/index.d.mts +2 -2
- package/dist/data/index.mjs +1 -1
- package/dist/data-BLXO4XwS.mjs +2 -0
- package/dist/data-BLXO4XwS.mjs.map +1 -0
- package/dist/data.tagged-error.types-CGiKD-ES.d.mts +29 -0
- package/dist/data.tagged-error.types-CGiKD-ES.d.mts.map +1 -0
- package/dist/{discriminator.types-9PxvrZki.d.mts → discriminator.types-CTURejXz.d.mts} +1 -1
- package/dist/discriminator.types-CTURejXz.d.mts.map +1 -0
- package/dist/dual-CZhzZslG.mjs +2 -0
- package/dist/dual-CZhzZslG.mjs.map +1 -0
- package/dist/either/index.d.mts +2 -2
- package/dist/either/index.mjs +1 -1
- package/dist/either-BMLPfvMl.mjs +2 -0
- package/dist/either-BMLPfvMl.mjs.map +1 -0
- package/dist/{equality-CD4_A1Op.mjs → equality-CoyUHWh9.mjs} +1 -1
- package/dist/{equality-CD4_A1Op.mjs.map → equality-CoyUHWh9.mjs.map} +1 -1
- package/dist/{flow-CYjiodlC.mjs → flow-D8_tllWl.mjs} +1 -1
- package/dist/flow-D8_tllWl.mjs.map +1 -0
- package/dist/functions/index.d.mts +2 -0
- package/dist/functions/index.mjs +1 -0
- package/dist/functions-BkevX2Dw.mjs +2 -0
- package/dist/functions-BkevX2Dw.mjs.map +1 -0
- package/dist/fx/index.d.mts +2 -3
- package/dist/fx/index.mjs +1 -1
- package/dist/fx-K-a9Smhn.mjs +2 -0
- package/dist/fx-K-a9Smhn.mjs.map +1 -0
- package/dist/fx.runtime-DclEDyjY.mjs +2 -0
- package/dist/fx.runtime-DclEDyjY.mjs.map +1 -0
- package/dist/{fx.types-CDVjDn_3.mjs → fx.types-Bg-Mmdm5.mjs} +1 -1
- package/dist/fx.types-Bg-Mmdm5.mjs.map +1 -0
- package/dist/{fx.types-B34asVRX.d.mts → fx.types-DeEWEltG.d.mts} +2 -2
- package/dist/{fx.types-B34asVRX.d.mts.map → fx.types-DeEWEltG.d.mts.map} +1 -1
- package/dist/index-7Lv982Om.d.mts +217 -0
- package/dist/index-7Lv982Om.d.mts.map +1 -0
- package/dist/{index-CklRfom5.d.mts → index-B1-tBzc0.d.mts} +263 -368
- package/dist/index-B1-tBzc0.d.mts.map +1 -0
- package/dist/index-BNQ9xSAz.d.mts +464 -0
- package/dist/index-BNQ9xSAz.d.mts.map +1 -0
- package/dist/index-B_iY5tq0.d.mts +241 -0
- package/dist/index-B_iY5tq0.d.mts.map +1 -0
- package/dist/index-B_wWGszy.d.mts +129 -0
- package/dist/index-B_wWGszy.d.mts.map +1 -0
- package/dist/index-BiiE8NS7.d.mts +108 -0
- package/dist/index-BiiE8NS7.d.mts.map +1 -0
- package/dist/index-By6dNRc4.d.mts +277 -0
- package/dist/index-By6dNRc4.d.mts.map +1 -0
- package/dist/{index-BzYtgdX0.d.mts → index-CGiLfREk.d.mts} +123 -16
- package/dist/index-CGiLfREk.d.mts.map +1 -0
- package/dist/index-CUZn-ohG.d.mts +490 -0
- package/dist/index-CUZn-ohG.d.mts.map +1 -0
- package/dist/index-Cq2IFito.d.mts +121 -0
- package/dist/index-Cq2IFito.d.mts.map +1 -0
- package/dist/{index-B2l8_CiD.d.mts → index-DEAWPlcI.d.mts} +155 -216
- package/dist/index-DEAWPlcI.d.mts.map +1 -0
- package/dist/{index-C4v_3f3-.d.mts → index-DKS1g1oC.d.mts} +95 -42
- package/dist/index-DKS1g1oC.d.mts.map +1 -0
- package/dist/{index-jeC5jyRh.d.mts → index-DXbYlSnB.d.mts} +64 -101
- package/dist/index-DXbYlSnB.d.mts.map +1 -0
- package/dist/{index-CjZ95Dsv.d.mts → index-UzMbg1dh.d.mts} +188 -202
- package/dist/index-UzMbg1dh.d.mts.map +1 -0
- package/dist/index.d.mts +23 -16
- package/dist/index.mjs +1 -1
- package/dist/layer/index.d.mts +2 -0
- package/dist/layer/index.mjs +1 -0
- package/dist/layer-BttmtDrs.mjs +2 -0
- package/dist/layer-BttmtDrs.mjs.map +1 -0
- package/dist/layer.types-DgpCIsk_.d.mts +100 -0
- package/dist/layer.types-DgpCIsk_.d.mts.map +1 -0
- package/dist/multithread/index.d.mts +2 -0
- package/dist/multithread/index.mjs +1 -0
- package/dist/multithread-xUUh4eLn.mjs +19 -0
- package/dist/multithread-xUUh4eLn.mjs.map +1 -0
- package/dist/option/index.d.mts +2 -3
- package/dist/option/index.mjs +1 -1
- package/dist/option-Tfbo4wty.mjs +2 -0
- package/dist/option-Tfbo4wty.mjs.map +1 -0
- package/dist/option.types-D1mm0zUb.mjs +2 -0
- package/dist/option.types-D1mm0zUb.mjs.map +1 -0
- package/dist/{option.types-ClJiBTdg.d.mts → option.types-qPevEZQd.d.mts} +7 -12
- package/dist/option.types-qPevEZQd.d.mts.map +1 -0
- package/dist/order/index.d.mts +2 -0
- package/dist/order/index.mjs +1 -0
- package/dist/order-D5c4QChk.mjs +2 -0
- package/dist/order-D5c4QChk.mjs.map +1 -0
- package/dist/pipeable-COGyGMUV.mjs +2 -0
- package/dist/pipeable-COGyGMUV.mjs.map +1 -0
- package/dist/{pipeable-B4YJA56p.d.mts → pipeable-rfqacPxZ.d.mts} +2 -9
- package/dist/{pipeable-B4YJA56p.d.mts.map → pipeable-rfqacPxZ.d.mts.map} +1 -1
- package/dist/predicate/index.d.mts +2 -2
- package/dist/predicate/index.mjs +1 -1
- package/dist/predicate-DUhhQqWY.mjs +2 -0
- package/dist/predicate-DUhhQqWY.mjs.map +1 -0
- package/dist/provide/index.d.mts +2 -0
- package/dist/provide/index.mjs +1 -0
- package/dist/provide-C2cWOx2B.mjs +2 -0
- package/dist/provide-C2cWOx2B.mjs.map +1 -0
- package/dist/queue/index.d.mts +2 -0
- package/dist/queue/index.mjs +1 -0
- package/dist/queue-Sg6KJerl.mjs +2 -0
- package/dist/queue-Sg6KJerl.mjs.map +1 -0
- package/dist/queue.types-CD2LOu37.d.mts +36 -0
- package/dist/queue.types-CD2LOu37.d.mts.map +1 -0
- package/dist/result/index.d.mts +2 -3
- package/dist/result/index.mjs +1 -1
- package/dist/result-BEzV0DYC.mjs +2 -0
- package/dist/result-BEzV0DYC.mjs.map +1 -0
- package/dist/{result.types-HHDzgSTV.d.mts → result.types-_xDAei3-.d.mts} +5 -97
- package/dist/result.types-_xDAei3-.d.mts.map +1 -0
- package/dist/schedule/index.d.mts +2 -0
- package/dist/schedule/index.mjs +1 -0
- package/dist/schedule-C6tjcJ1O.mjs +2 -0
- package/dist/schedule-C6tjcJ1O.mjs.map +1 -0
- package/dist/schedule-DlX2Dg69.d.mts +144 -0
- package/dist/schedule-DlX2Dg69.d.mts.map +1 -0
- package/dist/scope/index.d.mts +2 -0
- package/dist/scope/index.mjs +1 -0
- package/dist/scope-CZdp4wKX.d.mts +79 -0
- package/dist/scope-CZdp4wKX.d.mts.map +1 -0
- package/dist/scope-D_kzd1nT.mjs +2 -0
- package/dist/scope-D_kzd1nT.mjs.map +1 -0
- package/dist/service/index.d.mts +2 -0
- package/dist/service/index.mjs +1 -0
- package/dist/service-3PYQTUdH.mjs +2 -0
- package/dist/service-3PYQTUdH.mjs.map +1 -0
- package/dist/service-DrXU7KJG.d.mts +69 -0
- package/dist/service-DrXU7KJG.d.mts.map +1 -0
- package/dist/service-resolution-C19smeaO.mjs +2 -0
- package/dist/service-resolution-C19smeaO.mjs.map +1 -0
- package/package.json +50 -12
- package/dist/adt-CkRcY_GA.mjs +0 -2
- package/dist/adt-CkRcY_GA.mjs.map +0 -1
- package/dist/apply-fn.types-0g_9eXRy.d.mts +0 -8
- package/dist/apply-fn.types-0g_9eXRy.d.mts.map +0 -1
- package/dist/brand-Gy0kW6-n.mjs +0 -2
- package/dist/brand-Gy0kW6-n.mjs.map +0 -1
- package/dist/data-C0_3MGwm.mjs +0 -2
- package/dist/data-C0_3MGwm.mjs.map +0 -1
- package/dist/discriminator.types-9PxvrZki.d.mts.map +0 -1
- package/dist/either-CPzK-s8W.mjs +0 -2
- package/dist/either-CPzK-s8W.mjs.map +0 -1
- package/dist/err/index.d.mts +0 -2
- package/dist/err/index.mjs +0 -1
- package/dist/err-3KpQ4pj9.mjs +0 -2
- package/dist/err-3KpQ4pj9.mjs.map +0 -1
- package/dist/flow/index.d.mts +0 -2
- package/dist/flow/index.mjs +0 -1
- package/dist/flow-CYjiodlC.mjs.map +0 -1
- package/dist/fx-vqywVJhV.mjs +0 -2
- package/dist/fx-vqywVJhV.mjs.map +0 -1
- package/dist/fx.types-CDVjDn_3.mjs.map +0 -1
- package/dist/index-8Ne4GdOG.d.mts +0 -288
- package/dist/index-8Ne4GdOG.d.mts.map +0 -1
- package/dist/index-B2l8_CiD.d.mts.map +0 -1
- package/dist/index-BOrJQBPO.d.mts +0 -80
- package/dist/index-BOrJQBPO.d.mts.map +0 -1
- package/dist/index-BsXtpnw-.d.mts +0 -225
- package/dist/index-BsXtpnw-.d.mts.map +0 -1
- package/dist/index-BzYtgdX0.d.mts.map +0 -1
- package/dist/index-C4v_3f3-.d.mts.map +0 -1
- package/dist/index-CjZ95Dsv.d.mts.map +0 -1
- package/dist/index-CklRfom5.d.mts.map +0 -1
- package/dist/index-DZdmFtjA.d.mts +0 -79
- package/dist/index-DZdmFtjA.d.mts.map +0 -1
- package/dist/index-a4MEBZZ1.d.mts +0 -850
- package/dist/index-a4MEBZZ1.d.mts.map +0 -1
- package/dist/index-jeC5jyRh.d.mts.map +0 -1
- package/dist/option-DawZC1cE.mjs +0 -2
- package/dist/option-DawZC1cE.mjs.map +0 -1
- package/dist/option.types-ClJiBTdg.d.mts.map +0 -1
- package/dist/pipe/index.d.mts +0 -2
- package/dist/pipe/index.mjs +0 -1
- package/dist/pipe-BPpJyZf7.mjs +0 -2
- package/dist/pipe-BPpJyZf7.mjs.map +0 -1
- package/dist/pipeable-BA0mXhs4.mjs +0 -2
- package/dist/pipeable-BA0mXhs4.mjs.map +0 -1
- package/dist/predicate-Cy_oHA1Q.mjs +0 -2
- package/dist/predicate-Cy_oHA1Q.mjs.map +0 -1
- package/dist/result-CgGYLp0L.mjs +0 -2
- package/dist/result-CgGYLp0L.mjs.map +0 -1
- package/dist/result.types-HHDzgSTV.d.mts.map +0 -1
- /package/dist/{chunk-DAexk1S7.mjs → chunk-C934ptG5.mjs} +0 -0
- /package/dist/{option-Bb-taghv.mjs → option-CBCwzF0L.mjs} +0 -0
- /package/dist/{result-fiJhwVGz.mjs → result-B5WbPg8C.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-K-a9Smhn.mjs","names":["gen","result","makeQueue","gen","result","resultOk","resultErr","resultTry","optionFromNullable"],"sources":["../src/fx/foreach.ts","../src/fx/fx.ts"],"sourcesContent":["import { NoSuchElementError } from \"../option/option.types\"\nimport { make as makeQueue, QueueAbortedError, QueueClosedError, QueueTaskAbortedError } from \"../queue/queue\"\nimport type { Concurrency } from \"../queue/queue.types\"\nimport { asServiceRequest } from \"../service/service-resolution\"\nimport { dual } from \"../shared/dual\"\nimport { FxTypeId } from \"./fx.types\"\nimport type { AsyncFx, FxError, FxRequirements, FxValue, FxYield, RunnableFx } from \"./fx.types\"\n\n/* oxlint-disable no-await-in-loop -- Fx.forEach coordinates child iterators and queue scheduling sequentially at specific yield points. */\n\ntype ForEachValue<Discard extends boolean, B> = Discard extends true ? void : Array<B>\n\ntype FxForEachOptions<Discard extends boolean = false> = {\n readonly concurrency?: Concurrency\n readonly discard?: Discard\n}\n\ntype ForEachFx<\n F extends (a: never, i: number) => RunnableFx<unknown, unknown, unknown>,\n Discard extends boolean,\n> = AsyncFx<ForEachValue<Discard, FxValue<ReturnType<F>>>, FxError<ReturnType<F>>, FxRequirements<ReturnType<F>>>\n\ntype FxForEach = {\n <A, F extends (a: A, i: number) => RunnableFx<unknown, unknown, unknown>, const Discard extends boolean = false>(\n self: Iterable<A>,\n f: F,\n options?: FxForEachOptions<Discard>,\n ): ForEachFx<F, Discard>\n <A, F extends (a: A, i: number) => RunnableFx<unknown, unknown, unknown>, const Discard extends boolean = false>(\n f: F,\n options?: FxForEachOptions<Discard>,\n ): (self: Iterable<A>) => ForEachFx<F, Discard>\n}\n\ntype ServiceRequestEntry<E, R> = {\n readonly yielded: FxYield<E, R>\n readonly signal: AbortSignal\n readonly resolve: (value: unknown) => void\n readonly reject: (reason: Error) => void\n}\n\ntype ResultErrShape = {\n readonly _tag: \"Err\"\n readonly error: unknown\n}\n\nclass TypedFailure<E> extends Error {\n readonly _tag = \"TypedFailure\"\n\n constructor(readonly error: E) {\n super(\"TypedFailure\")\n this.name = \"TypedFailure\"\n }\n}\n\nconst isTypedFailure = <E>(value: unknown): value is TypedFailure<E> => value instanceof TypedFailure\n\nconst isResultErr = (value: unknown): value is ResultErrShape =>\n typeof value === \"object\" && value !== null && \"_tag\" in value && value._tag === \"Err\" && \"error\" in value\n\nconst toFailureValue = (yielded: unknown): unknown => {\n if (yielded instanceof NoSuchElementError) {\n return yielded\n }\n\n if (isResultErr(yielded)) {\n return yielded.error\n }\n\n return yielded\n}\n\nconst isIterable = (value: unknown): value is Iterable<unknown> =>\n value !== null &&\n value !== undefined &&\n typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === \"function\"\n\nconst queueTaskAbortedError = (signal: AbortSignal): QueueTaskAbortedError =>\n new QueueTaskAbortedError({ reason: signal.reason })\n\nconst toError = (reason: unknown): Error =>\n reason instanceof Error ? reason : new Error(\"Fx.forEach defect was not an Error\", { cause: reason })\n\nconst unreachableType = (): never => {\n throw new Error(\"Unreachable: Fx type marker should never execute at runtime\")\n}\n\nconst typeMarker = <A>(): (() => A) => unreachableType\n\nconst runMappedFx = async <B, E, R>(\n fx: RunnableFx<B, E, R>,\n signal: AbortSignal,\n requestService: (yielded: FxYield<E, R>, signal: AbortSignal) => Promise<unknown>,\n): Promise<B> => {\n if (fx._tag === \"AsyncFx\") {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n\n while (result.done !== true) {\n if (signal.aborted) {\n throw queueTaskAbortedError(signal)\n }\n\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = await requestService(yielded, signal)\n result = await gen.next(injected)\n continue\n }\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- failure channel values come from generic E at runtime.\n throw new TypedFailure<E>(toFailureValue(yielded) as E)\n }\n\n return result.value\n }\n\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n if (signal.aborted) {\n throw queueTaskAbortedError(signal)\n }\n\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = await requestService(yielded, signal)\n result = gen.next(injected)\n continue\n }\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- failure channel values come from generic E at runtime.\n throw new TypedFailure<E>(toFailureValue(yielded) as E)\n }\n\n return result.value\n}\n\nconst fxForEach = dual(\n (args) => isIterable(args[0]) && typeof args[1] === \"function\",\n <A, B, E, R>(\n self: Iterable<A>,\n f: (a: A, i: number) => RunnableFx<B, E, R>,\n options?: FxForEachOptions<boolean>,\n ): AsyncFx<Array<B> | void, E, R> => {\n const items = [...self]\n const discard = options?.discard === true\n\n const program: AsyncFx<Array<B> | void, E, R> = {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: typeMarker<Array<B> | void>(),\n _E: typeMarker<E>(),\n _R: typeMarker<R>(),\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, Array<B> | void, unknown> {\n if (items.length === 0) {\n return discard ? undefined : []\n }\n\n const queue = makeQueue({ concurrency: options?.concurrency ?? \"unbounded\" })\n const results: Array<B> | undefined = discard ? undefined : []\n\n let remaining = items.length\n let firstFailure: E | undefined\n let firstDefect: Error | undefined\n let queueAborted = false\n\n const serviceRequests: ServiceRequestEntry<E, R>[] = []\n const eventWaiters = new Set<() => void>()\n\n const notifyEvent = () => {\n for (const resolve of eventWaiters) {\n resolve()\n }\n eventWaiters.clear()\n }\n\n const waitForEvent = () =>\n new Promise<void>((resolve) => {\n eventWaiters.add(resolve)\n })\n\n const requestService = (yielded: FxYield<E, R>, signal: AbortSignal): Promise<unknown> => {\n if (signal.aborted) {\n return Promise.reject(queueTaskAbortedError(signal))\n }\n\n return new Promise<unknown>((resolve, reject) => {\n const entry: ServiceRequestEntry<E, R> = {\n yielded,\n signal,\n resolve: (value) => {\n signal.removeEventListener(\"abort\", onAbort)\n resolve(value)\n },\n reject: (reason) => {\n signal.removeEventListener(\"abort\", onAbort)\n reject(reason)\n },\n }\n\n const onAbort = () => {\n const index = serviceRequests.indexOf(entry)\n if (index !== -1) {\n serviceRequests.splice(index, 1)\n }\n reject(queueTaskAbortedError(signal))\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true })\n serviceRequests.push(entry)\n notifyEvent()\n })\n }\n\n const rejectPendingServiceRequests = (reason: Error) => {\n const pending = serviceRequests.splice(0)\n for (const request of pending) {\n request.reject(reason)\n }\n }\n\n const abortQueue = (reason: unknown) => {\n if (queueAborted) {\n return\n }\n\n queueAborted = true\n void queue.shutdown({ mode: \"abort\", reason }).catch(() => {\n // no-op: fail-fast cleanup should never interrupt parent error handling\n })\n }\n\n const onTaskFailure = (error: unknown) => {\n if (isTypedFailure<E>(error)) {\n if (firstFailure === undefined && firstDefect === undefined) {\n firstFailure = error.error\n abortQueue(error.error)\n }\n return\n }\n\n if (\n (error instanceof QueueAbortedError ||\n error instanceof QueueTaskAbortedError ||\n error instanceof QueueClosedError) &&\n (firstFailure !== undefined || firstDefect !== undefined)\n ) {\n return\n }\n\n if (firstDefect === undefined && firstFailure === undefined) {\n const defect = toError(error)\n firstDefect = defect\n abortQueue(defect)\n }\n }\n\n const onTaskSettled = () => {\n remaining -= 1\n notifyEvent()\n }\n\n for (const [index, item] of items.entries()) {\n void queue\n .enqueue(async ({ signal }) => {\n const value = await runMappedFx(f(item, index), signal, requestService)\n if (results !== undefined) {\n results[index] = value\n }\n })\n .catch(onTaskFailure)\n .finally(onTaskSettled)\n }\n\n while (true) {\n if (firstDefect !== undefined) {\n rejectPendingServiceRequests(firstDefect)\n throw new Error(\"Fx.forEach defect\", { cause: firstDefect })\n }\n\n if (firstFailure !== undefined) {\n rejectPendingServiceRequests(new QueueAbortedError({ reason: firstFailure }))\n yield firstFailure\n throw new Error(\"Unreachable: Fx runtime short-circuits on first failure\")\n }\n\n const request = serviceRequests.shift()\n if (request !== undefined) {\n if (request.signal.aborted) {\n request.reject(queueTaskAbortedError(request.signal))\n continue\n }\n\n try {\n const injected = yield request.yielded\n request.resolve(injected)\n } catch (error) {\n request.reject(toError(error))\n }\n continue\n }\n\n if (remaining === 0) {\n break\n }\n\n await waitForEvent()\n }\n\n return discard ? undefined : results\n },\n }\n\n return program\n },\n) as FxForEach\n\nexport { fxForEach as forEach }\n\n/* oxlint-enable no-await-in-loop */\n","/**\n * Lightweight effect runtime with typed success, error, and requirement channels.\n *\n * **Mental model**\n * - `Fx<A, E, R>` models computations that may fail and require services.\n * - Build with `Fx.gen`, run with `Fx.run`, and compose with `Layer`/`Provide`.\n *\n * **Common tasks**\n * - Create workflows with `Fx.gen`.\n * - Execute with `Fx.run` or `Fx.fn`.\n * - Retry with `Fx.retry` and match outcomes with `Fx.match`.\n *\n * **Gotchas**\n * - Dependencies (`R`) must be provided before execution.\n * - `Fx.run` returns `Exit`, not raw values.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const program = Fx.gen(function* () {\n * const value = yield* Fx.ok(2)\n * return value + 1\n * })\n * const exit = Fx.run(program)\n * // => { _tag: \"Ok\", value: 3 }\n * ```\n *\n * @module\n */\nimport { fromNullable as optionFromNullable } from \"../option/option\"\nimport { ok as resultOk, err as resultErr, fromTry as resultTry } from \"../result/result\"\nimport type { RetrySchedule, SyncRetrySchedule } from \"../schedule/schedule\"\nimport { asServiceRequest } from \"../service/service-resolution\"\nimport { dual } from \"../shared/dual\"\nimport type { Exit as ExitType } from \"./exit\"\nimport { forEach as fxForEach } from \"./foreach\"\nimport { runSync, runAsync } from \"./fx.runtime\"\nimport { FxTypeId } from \"./fx.types\"\nimport type { RunnableFx, SyncFx, AsyncFx, FxYield, Fx as FxProtocol, FxGenerator, AsyncFxGenerator } from \"./fx.types\"\nexport {\n /**\n * `Exit` utilities namespace for `Fx.run` outcomes.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const exit = Fx.Exit.ok(1)\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n *\n * @category Re-exports\n */\n Exit,\n} from \"./exit\"\nexport {\n /**\n * Type guard for Fx service requests.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const request = { _tag: \"ServiceRequest\", serviceKey: \"Logger\" } as Fx.ServiceRequest<unknown>\n * const isRequest = Fx.isServiceRequest(request)\n * // => true\n * ```\n *\n * @category Guards\n */\n isServiceRequest,\n} from \"./fx.types\"\nexport {\n /**\n * Runtime unique symbol identifying Fx values.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const marker = { [Fx.FxTypeId]: true }\n * // => Object.getOwnPropertySymbols(marker).includes(Fx.FxTypeId)\n * ```\n *\n * @category Re-exports\n */\n FxTypeId,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported core Fx protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.Fx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type Fx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported synchronous Fx type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.SyncFx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type SyncFx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported asynchronous Fx type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.AsyncFx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type AsyncFx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported runnable Fx union type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.RunnableFx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type RunnableFx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported service-request protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.ServiceRequest<unknown>\n * ```\n *\n * @category Re-exports\n */\n type ServiceRequest,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported helper extracting Fx success type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxValue<Fx.SyncFx<number>>\n * ```\n *\n * @category Re-exports\n */\n type FxValue,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported helper extracting Fx error type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxError<Fx.SyncFx<number, string>>\n * ```\n *\n * @category Re-exports\n */\n type FxError,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported helper extracting Fx requirements type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxRequirements<Fx.SyncFx<number, never, { readonly svc: unknown }>>\n * ```\n *\n * @category Re-exports\n */\n type FxRequirements,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported generator yield union for Fx internals.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxYield<unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type FxYield,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported sync generator signature used by `Fx.gen`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxGenerator<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type FxGenerator,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported async generator signature used by `Fx.gen`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.AsyncFxGenerator<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type AsyncFxGenerator,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported sync Fx yieldable protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxYieldable<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type FxYieldable,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported async Fx yieldable protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.AsyncFxYieldable<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type AsyncFxYieldable,\n} from \"./fx.types\"\n\n/* oxlint-disable no-unsafe-type-assertion, no-unsafe-assignment, no-unsafe-call, no-unsafe-member-access, no-unsafe-return, no-unsafe-argument, no-unnecessary-type-assertion -- Fx runtime adapters intentionally traverse erased generator channels and rehydrate typed effects through controlled dynamic boundaries. */\n\n// ============================================================================\n// Fx.run - Execute computations\n// ============================================================================\n\n/**\n * Execute a sync Fx computation and return the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * Only available when R = never (all dependencies provided).\n *\n * @param fx - The sync computation to execute\n * @returns Exit<A, E>\n */\nfunction fxRun<A, E>(fx: SyncFx<A, E>): ExitType<A, E>\n\n/**\n * Execute an async Fx computation and return a Promise of the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * Only available when R = never (all dependencies provided).\n *\n * @param fx - The async computation to execute\n * @returns Promise<Exit<A, E>>\n */\nfunction fxRun<A, E>(fx: AsyncFx<A, E>): Promise<ExitType<A, E>>\n\n/**\n * Execute an Fx computation (union type).\n * Returns Exit for sync, Promise<Exit> for async.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n */\nfunction fxRun<A, E>(fx: RunnableFx<A, E>): ExitType<A, E> | Promise<ExitType<A, E>>\n\n/**\n * Implementation of Fx.run.\n * Detects sync vs async and executes appropriately.\n */\nfunction fxRun<A, E>(fx: RunnableFx<A, E>): ExitType<A, E> | Promise<ExitType<A, E>> {\n if (fx._tag === \"AsyncFx\") {\n return runAsync(fx)\n }\n return runSync(fx)\n}\n\n// ============================================================================\n// Fx.retry - Retry failed computations\n// ============================================================================\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nconst sleepIfNeeded = async (ms: number): Promise<void> => {\n if (ms <= 0) {\n return\n }\n await sleep(ms)\n}\n\nconst closeSyncAttempt = (gen: Generator<unknown, unknown, unknown>) => {\n if (typeof gen.return === \"function\") {\n gen.return(undefined)\n }\n}\n\nconst closeAsyncAttempt = async (\n gen: Generator<unknown, unknown, unknown> | AsyncGenerator<unknown, unknown, unknown>,\n) => {\n if (typeof gen.return === \"function\") {\n await gen.return(undefined)\n }\n}\n\nconst makeSyncRetryFx = <A, E, R>(fx: SyncFx<A, E, R>, schedule: SyncRetrySchedule): SyncFx<A, E, R> => ({\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n *[Symbol.iterator](): Generator<FxYield<E, R>, A, unknown> {\n let retryAttempt = 0\n attemptLoop: while (true) {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = yield yielded as FxYield<E, R>\n result = gen.next(injected)\n continue\n }\n\n retryAttempt += 1\n if (retryAttempt <= schedule.maxRetries) {\n closeSyncAttempt(gen)\n continue attemptLoop\n }\n\n // Forward the terminal typed failure to the outer runtime.\n yield yielded as FxYield<E, R>\n return undefined as never\n }\n\n return result.value\n }\n },\n})\n\n/* oxlint-disable no-await-in-loop -- retry execution is intentionally sequential across attempts and iterator steps. */\nconst makeAsyncRetryFx = <A, E, R>(fx: RunnableFx<A, E, R>, schedule: RetrySchedule): AsyncFx<A, E, R> => ({\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, A, unknown> {\n let retryAttempt = 0\n\n attemptLoop: while (true) {\n if (fx._tag === \"AsyncFx\") {\n const gen = fx[Symbol.asyncIterator]()\n // Sequential async iterator protocol: each step depends on the previous one.\n let result = await gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = yield yielded as FxYield<E, R>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(injected)\n continue\n }\n\n retryAttempt += 1\n if (retryAttempt <= schedule.maxRetries) {\n const delayMs = schedule.delayForAttempt(retryAttempt)\n await sleepIfNeeded(delayMs)\n await closeAsyncAttempt(gen)\n continue attemptLoop\n }\n\n // Forward the terminal typed failure to the outer runtime.\n yield yielded as FxYield<E, R>\n return undefined as never\n }\n\n return result.value\n }\n\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = yield yielded as FxYield<E, R>\n result = gen.next(injected)\n continue\n }\n\n retryAttempt += 1\n if (retryAttempt <= schedule.maxRetries) {\n const delayMs = schedule.delayForAttempt(retryAttempt)\n await sleepIfNeeded(delayMs)\n await closeAsyncAttempt(gen)\n continue attemptLoop\n }\n\n // Forward the terminal typed failure to the outer runtime.\n yield yielded as FxYield<E, R>\n return undefined as never\n }\n\n return result.value\n }\n },\n})\n/* oxlint-enable no-await-in-loop */\n\n/**\n * Retry a computation according to the given schedule.\n *\n * Retries only typed failures (Err channel). Defects are not retried.\n */\ntype RetryResult<Fx extends RunnableFx<unknown, unknown, unknown>, S extends RetrySchedule> =\n Fx extends AsyncFx<infer A, infer E, infer R>\n ? AsyncFx<A, E, R>\n : S extends SyncRetrySchedule\n ? Fx extends SyncFx<infer A, infer E, infer R>\n ? SyncFx<A, E, R>\n : never\n : Fx extends SyncFx<infer A, infer E, infer R>\n ? AsyncFx<A, E, R>\n : never\n\nconst fxRetry: {\n <Fx extends RunnableFx<unknown, unknown, unknown>, S extends RetrySchedule>(fx: Fx, schedule: S): RetryResult<Fx, S>\n <S extends RetrySchedule>(\n schedule: S,\n ): <Fx extends RunnableFx<unknown, unknown, unknown>>(fx: Fx) => RetryResult<Fx, S>\n} = dual(\n 2,\n <Fx extends RunnableFx<unknown, unknown, unknown>, S extends RetrySchedule>(\n fx: Fx,\n schedule: S,\n ): RetryResult<Fx, S> => {\n if (fx._tag === \"AsyncFx\" || !schedule._sync) {\n return makeAsyncRetryFx(fx, schedule) as RetryResult<Fx, S>\n }\n return makeSyncRetryFx(fx as SyncFx<unknown, unknown, unknown>, schedule as SyncRetrySchedule) as RetryResult<Fx, S>\n },\n)\n\n// ============================================================================\n// Fx.gen - Create composable computations\n// ============================================================================\n\ntype FxGenError<Yielded> = Yielded extends FxProtocol<unknown, infer E, unknown> ? E : Yielded\ntype FxGenRequirements<Yielded> = Yielded extends FxProtocol<unknown, unknown, infer R> ? R : never\n\n/**\n * Create a composable computation from a sync generator function.\n * Returns a SyncFx that can be stored, passed around, and executed later.\n *\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that returns a sync generator\n * @returns SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const getUser = (id: string) => Fx.gen(function* () {\n * const db = yield* Database\n * const logger = yield* Logger\n *\n * logger.info(`Fetching user ${id}`)\n * return yield* db.query<User>(`SELECT * FROM users WHERE id = '${id}'`)\n * })\n * // Type: SyncFx<User[], DatabaseError, Database | Logger>\n *\n * // Execute later with dependencies provided\n * const exit = pipe(getUser(\"123\"), Provide.layer(AppLayer)).run()\n * ```\n */\nfunction fxGen<Yielded, A>(\n generatorFn: () => Generator<Yielded, A, unknown>,\n): SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Create a composable computation from an async generator function.\n * Returns an AsyncFx that can be stored, passed around, and executed later.\n *\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that returns an async generator\n * @returns AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const fetchData = (url: string) => Fx.gen(async function* () {\n * const logger = yield* Logger\n *\n * logger.info(`Fetching ${url}`)\n * const response = await fetch(url)\n * return yield* Result.try(async () => await response.json())\n * })\n * // Type: AsyncFx<unknown, Error, Logger>\n * ```\n */\nfunction fxGen<Yielded, A>(\n generatorFn: () => AsyncGenerator<Yielded, A, unknown>,\n): AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Create a composable computation from a sync generator function that takes parameters.\n * Returns a factory function that, when called with parameters, produces a SyncFx.\n *\n * @template P - The parameter types (must be non-empty)\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that takes parameters and returns a sync generator\n * @returns A factory function that produces SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const getUser = Fx.gen(function* ({userId}: {userId: string}) {\n * const db = yield* Database\n * return yield* db.query(`SELECT * FROM users WHERE id = '${userId}'`)\n * })\n * // Type: (params: {userId: string}) => SyncFx<...>\n *\n * const exit = Fx.run(pipe(getUser({userId: \"123\"}), Provide.layer(DbLayer)))\n * ```\n */\nfunction fxGen<P extends [unknown, ...unknown[]], Yielded, A>(\n generatorFn: (...params: P) => Generator<Yielded, A, unknown>,\n): (...params: P) => SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Create a composable computation from an async generator function that takes parameters.\n * Returns a factory function that, when called with parameters, produces an AsyncFx.\n *\n * @template P - The parameter types (must be non-empty)\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that takes parameters and returns an async generator\n * @returns A factory function that produces AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const fetchUser = Fx.gen(async function* ({url}: {url: string}) {\n * const response = await fetch(url)\n * return yield* Result.try(async () => await response.json())\n * })\n * // Type: (params: {url: string}) => AsyncFx<...>\n * ```\n */\nfunction fxGen<P extends [unknown, ...unknown[]], Yielded, A>(\n generatorFn: (...params: P) => AsyncGenerator<Yielded, A, unknown>,\n): (...params: P) => AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Implementation of unified Fx.gen function.\n * Detects sync vs async generator and returns appropriate computation type.\n * For parameterized generators (length > 0), returns a factory function.\n */\n// oxlint-disable-next-line no-explicit-any\nfunction fxGen(generatorFn: (...args: any[]) => any): any {\n if (generatorFn.length > 0) {\n return (...params: unknown[]) => fxGen(() => generatorFn(...params))\n }\n\n // Check if we're dealing with async generator\n const testGen = generatorFn()\n const isAsync = Symbol.asyncIterator in testGen\n\n if (isAsync) {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined,\n _E: () => undefined,\n _R: () => undefined,\n },\n // oxlint-disable-next-line no-explicit-any\n async *[Symbol.asyncIterator](): AsyncGenerator<any, any, unknown> {\n const gen = generatorFn()\n let result = await gen.next()\n\n while (result.done !== true) {\n // Pass through yields (errors or services as Fx values)\n const injected = yield result.value\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(injected)\n }\n\n return result.value\n },\n }\n }\n\n // Sync generator\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined,\n _E: () => undefined,\n _R: () => undefined,\n },\n // oxlint-disable-next-line no-explicit-any\n *[Symbol.iterator](): Generator<any, any, unknown> {\n const gen = generatorFn()\n let result = gen.next()\n\n while (result.done !== true) {\n const injected = yield result.value\n result = gen.next(injected)\n }\n\n return result.value\n },\n }\n}\n\n// ============================================================================\n// Fx.fn - Execute computations immediately\n// ============================================================================\n\ntype FxRunResult<F extends RunnableFx<unknown, unknown, unknown>> =\n F extends AsyncFx<infer A, infer E, unknown>\n ? Promise<ExitType<A, E>>\n : F extends SyncFx<infer A, infer E, unknown>\n ? ExitType<A, E>\n : never\n\n/**\n * Execute a sync computation immediately and return the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * For computations without service dependencies.\n *\n * @template A - The success value type\n * @template E - The error type\n * @param generatorFn - A function that returns a sync generator\n * @returns Exit<A, E>\n *\n * @example\n * ```ts\n * const exit = Fx.fn(function* () {\n * const a = yield* Result.ok(10)\n * const b = yield* Result.ok(20)\n * return a + b\n * })\n * // Type: Exit<number, never>\n * // exit = { _tag: \"Ok\", value: 30 }\n * ```\n */\nfunction fxFn<A, E>(generatorFn: () => FxGenerator<A, E, never>): ExitType<A, E>\n\n/**\n * Execute an async computation immediately and return a Promise of the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * For computations without service dependencies.\n *\n * @template A - The success value type\n * @template E - The error type\n * @param generatorFn - A function that returns an async generator\n * @returns Promise<Exit<A, E>>\n *\n * @example\n * ```ts\n * const exit = await Fx.fn(async function* () {\n * const response = await fetch(\"/api/users\")\n * const data = yield* Result.try(async () => await response.json())\n * return data\n * })\n * // Type: Promise<Exit<unknown, Error>>\n * ```\n */\nfunction fxFn<A, E>(generatorFn: () => AsyncFxGenerator<A, E, never>): Promise<ExitType<A, E>>\n\n/**\n * Execute a sync computation with service dependencies immediately.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * The second argument is required when the computation has service requirements (R ≠ never).\n *\n * @template A - The success value type\n * @template E - The error type from the computation\n * @template R - The required services type\n * @param generatorFn - A function that returns a sync generator with service requirements\n * @param provider - A function that provides the services (e.g., Provide.layer(AppLayer))\n * @returns Exit result from running the provided Fx (sync or async depending on provider output)\n *\n * @example\n * ```ts\n * const exit = Fx.fn(function* () {\n * const config = yield* Config\n * const logger = yield* Logger\n * logger.info(`DB URL: ${config.dbUrl}`)\n * return config.dbUrl\n * }, Provide.layer(AppLayer))\n * // Type: Exit<string, never>\n * ```\n */\nfunction fxFn<A, E, R, ProvidedFx extends RunnableFx<unknown, unknown, unknown>>(\n generatorFn: () => FxGenerator<A, E, R>,\n provider: (fx: SyncFx<A, E, R>) => ProvidedFx,\n): FxRunResult<ProvidedFx>\n\n/**\n * Execute an async computation with service dependencies immediately.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * The second argument is required when the computation has service requirements (R ≠ never).\n *\n * @template A - The success value type\n * @template E - The error type from the computation\n * @template R - The required services type\n * @param generatorFn - A function that returns an async generator with service requirements\n * @param provider - A function that provides the services (e.g., Provide.layer(AppLayer))\n * @returns Exit result from running the provided Fx (sync or async depending on provider output)\n *\n * @example\n * ```ts\n * const exit = await Fx.fn(async function* () {\n * const config = yield* Config\n * await doAsyncWork()\n * return config.dbUrl\n * }, Provide.layer(AppLayer))\n * // Type: Promise<Exit<string, never>>\n * ```\n */\nfunction fxFn<A, E, R, ProvidedFx extends RunnableFx<unknown, unknown, unknown>>(\n generatorFn: () => AsyncFxGenerator<A, E, R>,\n provider: (fx: AsyncFx<A, E, R>) => ProvidedFx,\n): FxRunResult<ProvidedFx>\n\n/**\n * Implementation of Fx.fn.\n * Reuses fxGen() for Fx creation and fxRun() for execution to ensure consistent behavior.\n */\nfunction fxFn<A, E, E2, R>(\n generatorFn: () => FxGenerator<A, E, R> | AsyncFxGenerator<A, E, R>,\n provider?: ((fx: SyncFx<A, E, R>) => RunnableFx<A, E | E2>) | ((fx: AsyncFx<A, E, R>) => RunnableFx<A, E | E2>),\n): ExitType<A, E | E2> | Promise<ExitType<A, E | E2>> {\n // Create the Fx using fxGen (single source of truth for Fx creation)\n // Type cast needed because fxGen infers E/R from yielded Fx values,\n // while fxFn receives E/R as explicit type parameters\n // oxlint-disable-next-line no-explicit-any\n const fx = fxGen(generatorFn as any) as RunnableFx<A, E, R>\n\n if (provider) {\n // Apply provider and run\n const provided =\n fx._tag === \"AsyncFx\"\n ? (provider as (fx: AsyncFx<A, E, R>) => RunnableFx<A, E | E2>)(fx)\n : (provider as (fx: SyncFx<A, E, R>) => RunnableFx<A, E | E2>)(fx)\n return fxRun(provided as RunnableFx<A, E | E2>) as ExitType<A, E | E2> | Promise<ExitType<A, E | E2>>\n }\n\n // No provider - run directly (R must be never at the type level)\n return fxRun(fx as RunnableFx<A, E | E2>) as ExitType<A, E | E2> | Promise<ExitType<A, E | E2>>\n}\n\n// ============================================================================\n// Fx.ok / Fx.err / Fx.option - Convenience aliases\n// ============================================================================\n\n/**\n * Convenience alias for Result.ok.\n * Creates a successful Result that can be yielded in an Fx computation.\n *\n * @param value - The success value\n * @returns Result<T, never>\n *\n * @example\n * ```ts\n * const workflow = Fx.gen(function* () {\n * const value = yield* Fx.ok(42)\n * return value * 2\n * })\n * ```\n */\nconst fxOk = resultOk\n\n/**\n * Convenience alias for Result.err.\n * Creates an error Result that can be yielded in an Fx computation.\n *\n * @param error - The error value\n * @returns Result<never, E>\n *\n * @example\n * ```ts\n * const workflow = Fx.gen(function* () {\n * const config = yield* Config\n *\n * if (!config.dbUrl) {\n * return yield* Fx.err(new ValidationError({ field: \"dbUrl\" }))\n * }\n *\n * return config.dbUrl\n * })\n * ```\n */\nconst fxErr = resultErr\n\n/**\n * Convenience alias for Result.try.\n * Creates a Result that can be yielded in an Fx computation.\n *\n * @param fn - A function that returns a value or throws an error\n * @returns Result<T, E>\n *\n * @example\n * ```ts\n * const result = Fx.try(() => {\n * return 42\n * })\n *\n * const workflow = Fx.gen(function* () {\n * const result = yield* Fx.try(() => {\n * return 42\n * })\n * return result\n * })\n * ```\n */\nconst fxTry = resultTry\n\n/**\n * Convenience alias for Option.fromNullable.\n * Converts nullable values into an Option that can be yielded in an Fx computation.\n *\n * @param value - A possibly nullish value\n * @returns Option<NonNullable<T>>\n *\n * @example\n * ```ts\n * const workflow = Fx.gen(function* () {\n * const apiKey = yield* Fx.option(request.headers[\"x-api-key\"])\n * return apiKey\n * })\n * ```\n */\nconst fxOption = optionFromNullable\n\n// ============================================================================\n// Fx.match - Universal pattern matching\n// ============================================================================\n\n/**\n * Handler functions for matching on a tagged union by `_tag` discriminator.\n * Each handler receives the narrowed variant corresponding to its tag key.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx\n * ```\n *\n * @category Type-level\n */\nexport type TaggedMatch<T extends { readonly _tag: string }, R> = {\n readonly [K in T[\"_tag\"]]: (variant: Extract<T, { readonly _tag: K }>) => R\n}\n\n/**\n * Generic pattern matcher for any `_tag`-based discriminated union.\n *\n * Works with Exit, tagged errors, or any type with a `readonly _tag` discriminator.\n * Each handler receives the full narrowed variant object for its tag.\n *\n * Supports both data-first and data-last (pipe) calling styles.\n *\n * @example\n * ```ts\n * // Match on Exit\n * Fx.match(exit, {\n * Ok: (ok) => ok.value,\n * Err: (err) =>\n * Fx.match(err.error, {\n * DatabaseError: (e) => e.message,\n * NotFoundError: (e) => e.resourceId,\n * }),\n * Defect: (d) => String(d.defect),\n * })\n *\n * // Data-last with pipe\n * pipe(exit, Fx.match({\n * Ok: (ok) => ok.value,\n * Err: (err) => \"error\",\n * Defect: (d) => \"defect\",\n * }))\n * ```\n */\nconst fxMatch: {\n <T extends { readonly _tag: string }, R>(value: T, handlers: TaggedMatch<T, R>): R\n <T extends { readonly _tag: string }, R>(handlers: TaggedMatch<T, R>): (value: T) => R\n} = dual(\n 2,\n // oxlint-disable-next-line no-explicit-any\n (value: any, handlers: any): any => handlers[value._tag](value),\n)\n\n// ============================================================================\n// Exports\n// ============================================================================\n\n/**\n * Build typed computations from generator functions.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const program = Fx.gen(function* () {\n * const value = yield* Fx.ok(2)\n * return value + 1\n * })\n * const exit = Fx.run(program)\n * // => { _tag: \"Ok\", value: 3 }\n * ```\n *\n * @category Constructors\n */\nexport const gen = fxGen\n\n/**\n * Run a generator function immediately and return its `Exit`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const exit = Fx.fn(function* () {\n * return yield* Fx.ok(2)\n * })\n * // => { _tag: \"Ok\", value: 2 }\n * ```\n *\n * @category Utilities\n */\nexport const fn = fxFn\n\n/**\n * Execute an existing `Fx` value and produce an `Exit`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const exit = Fx.run(Fx.gen(function* () {\n * return 1\n * }))\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n *\n * @category Utilities\n */\nexport const run = fxRun\n\n/**\n * Retry failed computations according to a schedule.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const retried = Fx.retry(\n * Fx.gen(function* () {\n * return yield* Fx.err(\"boom\")\n * }),\n * Schedule.recurs(2),\n * )\n * const exit = Fx.run(retried)\n * // => { _tag: \"Err\", error: \"boom\" }\n * ```\n *\n * @category Error Handling\n */\nexport const retry = fxRetry\n\n/**\n * Run an effectful function for each item in a collection.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const fx = Fx.forEach([1, 2, 3], (n) => Fx.gen(function* () {\n * return n * 2\n * }))\n * // => AsyncFx<readonly number[], ...>\n * ```\n *\n * @category Sequencing\n */\nexport const forEach = fxForEach\n\n/**\n * Alias for `Result.ok` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.ok(42)\n * // => { _tag: \"Ok\", value: 42 }\n * ```\n *\n * @category Constructors\n */\nexport const ok = fxOk\n\n/**\n * Alias for `Result.err` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.err(\"boom\")\n * // => { _tag: \"Err\", error: \"boom\" }\n * ```\n *\n * @category Constructors\n */\nexport const err = fxErr\n\n/**\n * Alias for `Option.fromNullable` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.option(\"token\")\n * // => { _tag: \"Some\", value: \"token\" }\n * ```\n *\n * @category Conversions\n */\nexport const option = fxOption\n\nconst try_ = fxTry\n\nexport {\n /**\n * Alias for `Result.fromTry` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const parsed = Fx.try(() => Number.parseInt(\"42\", 10))\n * // => { _tag: \"Ok\", value: 42 }\n * ```\n *\n * @category Constructors\n */\n try_ as try,\n}\n\n/**\n * Pattern matching helper for tagged unions.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.match({ _tag: \"Ok\", value: 2 } as const, {\n * Ok: (ok) => ok.value + 1,\n * })\n * // => 3\n * ```\n *\n * @category Pattern Matching\n */\nexport const match = fxMatch\n\n/* oxlint-enable no-unsafe-type-assertion, no-unsafe-assignment, no-unsafe-call, no-unsafe-member-access, no-unsafe-return, no-unsafe-argument, no-unnecessary-type-assertion */\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{t as e}from"./dual-CZhzZslG.mjs";import{t}from"./option.types-D1mm0zUb.mjs";import{t as n}from"./service-resolution-C19smeaO.mjs";const r=e=>({_tag:`Ok`,value:e}),i=e=>({_tag:`Err`,error:e}),a=e=>({_tag:`Defect`,defect:e}),o={ok:r,err:i,defect:a,isOk:e=>e._tag===`Ok`,isErr:e=>e._tag===`Err`,isDefect:e=>e._tag===`Defect`,match:e(2,(e,t)=>{switch(e._tag){case`Ok`:return t.Ok(e.value);case`Err`:return t.Err(e.error);case`Defect`:return t.Defect(e.defect)}}),getOrThrow:e=>{switch(e._tag){case`Ok`:return e.value;case`Err`:throw e.error;case`Defect`:throw e.defect}}};function s(e){try{let o=e[Symbol.iterator]().next();if(o.done!==!0){let e=o.value,r=n(e);return r===void 0?e instanceof t?i(e):typeof e==`object`&&e&&`_tag`in e&&e._tag===`Err`?i(e.error):i(e):a(Error(`Service "${r.key}" not provided. Use Provide.layer() to inject services.`))}return r(o.value)}catch(e){return a(e)}}async function c(e){try{let o=await e[Symbol.asyncIterator]().next();if(o.done!==!0){let e=o.value,r=n(e);return r===void 0?e instanceof t?i(e):typeof e==`object`&&e&&`_tag`in e&&e._tag===`Err`?i(e.error):i(e):a(Error(`Service "${r.key}" not provided. Use Provide.layer() to inject services.`))}return r(o.value)}catch(e){return a(e)}}export{s as n,o as r,c as t};
|
|
2
|
+
//# sourceMappingURL=fx.runtime-DclEDyjY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx.runtime-DclEDyjY.mjs","names":["exitDefect","exitErr","exitOk"],"sources":["../src/fx/exit.ts","../src/fx/fx.runtime.ts"],"sourcesContent":["import { dual } from \"../shared/dual\"\nimport type { Err, Ok } from \"../shared/type-utils.types\"\n\n// ============================================================================\n// Exit Types - Flat 3-variant discriminated union\n// ============================================================================\n\n/**\n * Represents an unexpected thrown exception (defect) caught during Fx execution.\n */\ntype Defect = {\n readonly _tag: \"Defect\"\n readonly defect: unknown\n}\n\n/**\n * Exit represents the outcome of an Fx computation.\n * A flat 3-variant discriminated union that cleanly separates:\n * - `Ok<A>`: successful result with value of type A\n * - `Err<E>`: typed failure with error of type E\n * - `Defect`: unexpected thrown exception (defect)\n *\n * @example\n * ```ts\n * const exit = Fx.run(computation)\n * switch (exit._tag) {\n * case \"Ok\": exit.value // A\n * case \"Err\": exit.error // E (clean!)\n * case \"Defect\": exit.defect // unknown\n * }\n * ```\n */\nexport type Exit<A, E> = Ok<A> | Err<E> | Defect\n\n// ============================================================================\n// Constructors\n// ============================================================================\n\n/**\n * Create a successful Exit.\n */\nexport const ok = <A>(value: A): Ok<A> => ({ _tag: \"Ok\", value })\n\n/**\n * Create a typed failure Exit.\n */\nexport const err = <E>(error: E): Err<E> => ({ _tag: \"Err\", error })\n\n/**\n * Create a defect Exit from an unexpected thrown value.\n */\nexport const defect = (thrown: unknown): Defect => ({ _tag: \"Defect\", defect: thrown })\n\n// ============================================================================\n// Guards\n// ============================================================================\n\n/**\n * Check if an Exit is a successful result.\n */\nconst isOk = <A, E>(exit: Exit<A, E>): exit is Ok<A> => exit._tag === \"Ok\"\n\n/**\n * Check if an Exit is a typed failure.\n */\nconst isErr = <A, E>(exit: Exit<A, E>): exit is Err<E> => exit._tag === \"Err\"\n\n/**\n * Check if an Exit is an unexpected defect.\n */\nconst isDefect = <A, E>(exit: Exit<A, E>): exit is Defect => exit._tag === \"Defect\"\n\n// ============================================================================\n// Match\n// ============================================================================\n\n/**\n * Handler functions for Exit.match.\n */\ntype ExitMatch<A, E, R> = {\n readonly Ok: (value: A) => R\n readonly Err: (error: E) => R\n readonly Defect: (defect: unknown) => R\n}\n\n/**\n * Pattern match on an Exit value.\n *\n * @example\n * ```ts\n * // Data-first\n * Exit.match(exit, {\n * Ok: (value) => `Success: ${value}`,\n * Err: (error) => `Error: ${error}`,\n * Defect: (defect) => `Defect: ${defect}`,\n * })\n *\n * // Data-last (pipe)\n * pipe(exit, Exit.match({\n * Ok: (value) => `Success: ${value}`,\n * Err: (error) => `Error: ${error}`,\n * Defect: (defect) => `Defect: ${defect}`,\n * }))\n * ```\n */\nconst match: {\n <A, E, R>(exit: Exit<A, E>, handlers: ExitMatch<A, E, R>): R\n <A, E, R>(handlers: ExitMatch<A, E, R>): (exit: Exit<A, E>) => R\n} = dual(2, <A, E, R>(exit: Exit<A, E>, handlers: ExitMatch<A, E, R>): R => {\n switch (exit._tag) {\n case \"Ok\":\n return handlers.Ok(exit.value)\n case \"Err\":\n return handlers.Err(exit.error)\n case \"Defect\":\n return handlers.Defect(exit.defect)\n }\n})\n\n// ============================================================================\n// Utility\n// ============================================================================\n\n/**\n * Extract the value from an Ok exit, or throw.\n * Useful for tests and scripts where you expect success.\n *\n * @throws The error for Err exits, or the defect for Defect exits\n */\nconst getOrThrow = <A, E>(exit: Exit<A, E>): A => {\n switch (exit._tag) {\n case \"Ok\":\n return exit.value\n case \"Err\":\n // oxlint-disable-next-line only-throw-error -- E is intentionally generic and may be a non-Error domain value.\n throw exit.error\n case \"Defect\":\n throw exit.defect\n }\n}\n\n// ============================================================================\n// Namespace\n// ============================================================================\n\n/**\n * Exit namespace containing all Exit utilities.\n */\nexport const Exit = {\n ok,\n err,\n defect,\n isOk,\n isErr,\n isDefect,\n match,\n getOrThrow,\n} as const\n","import { NoSuchElementError } from \"../option/option.types\"\nimport { asServiceRequest } from \"../service/service-resolution\"\nimport { ok as exitOk, err as exitErr, defect as exitDefect } from \"./exit\"\nimport type { Exit } from \"./exit\"\nimport type { AsyncFx, SyncFx } from \"./fx.types\"\n\nexport function runSync<A, E>(fx: SyncFx<A, E>): Exit<A, E> {\n try {\n const gen = fx[Symbol.iterator]()\n const result = gen.next()\n\n if (result.done !== true) {\n const yielded = result.value as unknown\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n return exitDefect(\n new Error(`Service \"${serviceRequest.key}\" not provided. Use Provide.layer() to inject services.`),\n )\n }\n\n if (yielded instanceof NoSuchElementError) {\n return exitErr(yielded as E)\n }\n\n if (typeof yielded === \"object\" && yielded !== null && \"_tag\" in yielded && yielded._tag === \"Err\") {\n return exitErr((yielded as Record<string, unknown>)[\"error\"] as E)\n }\n\n return exitErr(yielded as E)\n }\n\n return exitOk(result.value)\n } catch (thrown) {\n return exitDefect(thrown)\n }\n}\n\nexport async function runAsync<A, E>(fx: AsyncFx<A, E>): Promise<Exit<A, E>> {\n try {\n const gen = fx[Symbol.asyncIterator]()\n const result = await gen.next()\n\n if (result.done !== true) {\n const yielded = result.value as unknown\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n return exitDefect(\n new Error(`Service \"${serviceRequest.key}\" not provided. Use Provide.layer() to inject services.`),\n )\n }\n\n if (yielded instanceof NoSuchElementError) {\n return exitErr(yielded as E)\n }\n\n if (typeof yielded === \"object\" && yielded !== null && \"_tag\" in yielded && yielded._tag === \"Err\") {\n return exitErr((yielded as Record<string, unknown>)[\"error\"] as E)\n }\n\n return exitErr(yielded as E)\n }\n\n return exitOk(result.value)\n } catch (thrown) {\n return exitDefect(thrown)\n }\n}\n"],"mappings":"yIAyCA,MAAa,EAAS,IAAqB,CAAE,KAAM,KAAM,QAAO,EAKnD,EAAU,IAAsB,CAAE,KAAM,MAAO,QAAO,EAKtD,EAAU,IAA6B,CAAE,KAAM,SAAU,OAAQ,EAAQ,EAiGzE,EAAO,CAClB,KACA,MACA,SACA,KA5FkB,GAAoC,EAAK,OAAS,KA6FpE,MAxFmB,GAAqC,EAAK,OAAS,MAyFtE,SApFsB,GAAqC,EAAK,OAAS,SAqFzE,MA/CE,EAAK,GAAa,EAAkB,IAAoC,CAC1E,OAAQ,EAAK,KAAb,CACE,IAAK,KACH,OAAO,EAAS,GAAG,EAAK,MAAM,CAChC,IAAK,MACH,OAAO,EAAS,IAAI,EAAK,MAAM,CACjC,IAAK,SACH,OAAO,EAAS,OAAO,EAAK,OAAO,GAEvC,CAuCA,WA3BwB,GAAwB,CAChD,OAAQ,EAAK,KAAb,CACE,IAAK,KACH,OAAO,EAAK,MACd,IAAK,MAEH,MAAM,EAAK,MACb,IAAK,SACH,MAAM,EAAK,SAoBhB,CCvJD,SAAgB,EAAc,EAA8B,CAC1D,GAAI,CAEF,IAAM,EADM,EAAG,OAAO,WAAW,CACd,MAAM,CAEzB,GAAI,EAAO,OAAS,GAAM,CACxB,IAAM,EAAU,EAAO,MACjB,EAAiB,EAAiB,EAAQ,CAehD,OAdI,IAAmB,IAAA,GAMnB,aAAmB,EACdC,EAAQ,EAAa,CAG1B,OAAO,GAAY,UAAY,GAAoB,SAAU,GAAW,EAAQ,OAAS,MACpFA,EAAS,EAAoC,MAAc,CAG7DA,EAAQ,EAAa,CAbnBD,EACD,MAAM,YAAY,EAAe,IAAI,yDAAyD,CACnG,CAcL,OAAOE,EAAO,EAAO,MAAM,OACpB,EAAQ,CACf,OAAOF,EAAW,EAAO,EAI7B,eAAsB,EAAe,EAAwC,CAC3E,GAAI,CAEF,IAAM,EAAS,MADH,EAAG,OAAO,gBAAgB,CACb,MAAM,CAE/B,GAAI,EAAO,OAAS,GAAM,CACxB,IAAM,EAAU,EAAO,MACjB,EAAiB,EAAiB,EAAQ,CAehD,OAdI,IAAmB,IAAA,GAMnB,aAAmB,EACdC,EAAQ,EAAa,CAG1B,OAAO,GAAY,UAAY,GAAoB,SAAU,GAAW,EAAQ,OAAS,MACpFA,EAAS,EAAoC,MAAc,CAG7DA,EAAQ,EAAa,CAbnBD,EACD,MAAM,YAAY,EAAe,IAAI,yDAAyD,CACnG,CAcL,OAAOE,EAAO,EAAO,MAAM,OACpB,EAAQ,CACf,OAAOF,EAAW,EAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
const e=Symbol.for(`@repo/std/fx/FxTypeId`),t=e=>typeof e==`object`&&!!e&&`_tag`in e&&e._tag===`ServiceRequest`;export{t as n,e as t};
|
|
2
|
-
//# sourceMappingURL=fx.types-
|
|
2
|
+
//# sourceMappingURL=fx.types-Bg-Mmdm5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx.types-Bg-Mmdm5.mjs","names":[],"sources":["../src/fx/fx.types.ts"],"sourcesContent":["// ============================================================================\n// Service Request\n// ============================================================================\n\n/**\n * Unique symbol for Fx type identification.\n */\nexport const FxTypeId: unique symbol = Symbol.for(\"@repo/std/fx/FxTypeId\")\nexport type FxTypeId = typeof FxTypeId\n\n/**\n * Fx<A, E, R> is the base protocol for all effect types.\n * Explicitly carries type parameters for proper inference in generators.\n *\n * @template A - Success value type\n * @template E - Error type\n * @template R - Requirements type (services needed)\n */\nexport type Fx<out A, out E = never, out R = never> = {\n readonly [FxTypeId]: {\n readonly _A: () => A\n readonly _E: () => E\n readonly _R: () => R\n }\n}\n\n/**\n * ServiceRequest is yielded when accessing a service via yield*.\n * The runtime intercepts these and injects the service from context.\n * Implements Fx protocol with A=S, E=never, R=S (requires service S to produce S).\n */\nexport type ServiceRequest<S> = Fx<S, never, S> & {\n readonly _tag: \"ServiceRequest\"\n /** Phantom type for service identification */\n readonly _service: S\n readonly serviceKey: string\n}\n\n/**\n * Check if a value is a ServiceRequest.\n */\nexport const isServiceRequest = (value: unknown): value is ServiceRequest<unknown> =>\n typeof value === \"object\" && value !== null && \"_tag\" in value && value._tag === \"ServiceRequest\"\n\n/**\n * Extract the success type from an Fx.\n */\nexport type FxValue<T> = T extends Fx<infer A, unknown, unknown> ? A : never\n\n/**\n * Extract the error type from an Fx.\n */\nexport type FxError<T> = T extends Fx<unknown, infer E, unknown> ? E : never\n\n/**\n * Extract the requirements type from an Fx.\n */\nexport type FxRequirements<T> = T extends Fx<unknown, unknown, infer R> ? R : never\n\n// ============================================================================\n// Core Fx Types\n// ============================================================================\n\n/**\n * The type yielded by Fx generators at runtime.\n *\n * This union represents what flows through generator yield points:\n * - E: Error values that propagate through the computation\n * - ServiceClass<R>: Service requests that get intercepted and resolved from context\n *\n * Used for generator type annotations in Fx.gen(), Provide.layer(), and Layer implementations.\n */\nexport type FxYield<E, R> = E | ServiceClass<R>\n\n/**\n * ServiceClass type imported for FxYield.\n * This is a structural type that matches service classes.\n */\ntype ServiceClass<S> = Fx<S, never, S> & { _tag: \"Service\"; key: string }\n\n/**\n * SyncFx<A, E, R> represents a synchronous computation that:\n * - Produces a value of type A on success\n * - May fail with an error of type E\n * - Requires services of type R to run\n *\n * Use Fx.run() to execute when R = never (all dependencies provided).\n */\nexport type SyncFx<A, E = never, R = never> = Fx<A, E, R> & {\n readonly _tag: \"SyncFx\"\n\n /**\n * Iterator for yield* support in gen computations.\n * Yields error Results or ServiceClasses for service injection.\n */\n [Symbol.iterator](): Generator<FxYield<E, R>, A, unknown>\n}\n\n/**\n * AsyncFx<A, E, R> represents an asynchronous computation that:\n * - Produces a value of type A on success\n * - May fail with an error of type E\n * - Requires services of type R to run\n *\n * Use Fx.run() to execute when R = never (all dependencies provided).\n */\nexport type AsyncFx<A, E = never, R = never> = Fx<A, E, R> & {\n readonly _tag: \"AsyncFx\"\n\n /**\n * Async iterator for yield* support in async gen computations.\n * Yields error Results or ServiceClasses for service injection.\n */\n [Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, A, unknown>\n}\n\n/**\n * RunnableFx<A, E, R> is a union of executable Fx types (sync or async).\n * Use this for functions that execute effects like Fx.run().\n */\nexport type RunnableFx<A, E = never, R = never> = SyncFx<A, E, R> | AsyncFx<A, E, R>\n\n// ============================================================================\n// Generator Types for Fx\n// ============================================================================\n\n/**\n * Sync generator type for Fx.gen.\n * Yields error Results or ServiceClasses, returns value of type A.\n */\nexport type FxGenerator<A, E, R> = Generator<FxYield<E, R>, A, unknown>\n\n/**\n * Async generator type for Fx.gen.\n * Yields error Results or ServiceClasses, returns value of type A.\n */\nexport type AsyncFxGenerator<A, E, R> = AsyncGenerator<FxYield<E, R>, A, unknown>\n\n// ============================================================================\n// Yieldable Types (for compatibility with existing gen module)\n// ============================================================================\n\n/**\n * FxYieldable extends the existing Yieldable protocol to support Fx values.\n */\nexport type FxYieldable<A, E = never, R = never> = Fx<A, E, R> & {\n [Symbol.iterator](): Generator<FxYield<E, R>, A, unknown>\n}\n\n/**\n * AsyncFxYieldable for async computations with Fx values.\n */\nexport type AsyncFxYieldable<A, E = never, R = never> = Fx<A, E, R> & {\n [Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, A, unknown>\n}\n"],"mappings":"AAOA,MAAa,EAA0B,OAAO,IAAI,wBAAwB,CAkC7D,EAAoB,GAC/B,OAAO,GAAU,YAAY,GAAkB,SAAU,GAAS,EAAM,OAAS"}
|
|
@@ -53,7 +53,7 @@ type FxRequirements<T> = T extends Fx<unknown, unknown, infer R> ? R : never;
|
|
|
53
53
|
* - E: Error values that propagate through the computation
|
|
54
54
|
* - ServiceClass<R>: Service requests that get intercepted and resolved from context
|
|
55
55
|
*
|
|
56
|
-
* Used for generator type annotations in Fx.gen(),
|
|
56
|
+
* Used for generator type annotations in Fx.gen(), Provide.layer(), and Layer implementations.
|
|
57
57
|
*/
|
|
58
58
|
type FxYield<E, R> = E | ServiceClass<R>;
|
|
59
59
|
/**
|
|
@@ -125,4 +125,4 @@ type AsyncFxYieldable<A, E = never, R = never> = Fx<A, E, R> & {
|
|
|
125
125
|
};
|
|
126
126
|
//#endregion
|
|
127
127
|
export { FxError as a, FxTypeId as c, FxYieldable as d, RunnableFx as f, isServiceRequest as h, Fx as i, FxValue as l, SyncFx as m, AsyncFxGenerator as n, FxGenerator as o, ServiceRequest as p, AsyncFxYieldable as r, FxRequirements as s, AsyncFx as t, FxYield as u };
|
|
128
|
-
//# sourceMappingURL=fx.types-
|
|
128
|
+
//# sourceMappingURL=fx.types-DeEWEltG.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx.types-
|
|
1
|
+
{"version":3,"file":"fx.types-DeEWEltG.d.mts","names":[],"sources":["../src/fx/fx.types.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { f as RunnableFx, m as SyncFx, t as AsyncFx } from "./fx.types-DeEWEltG.mjs";
|
|
2
|
+
import { t as ServiceClass } from "./service-DrXU7KJG.mjs";
|
|
3
|
+
import { n as ScopeService, t as ExcludeScope } from "./scope-CZdp4wKX.mjs";
|
|
4
|
+
import { a as UnprovidedDeps, i as MergeROut, n as Layer, r as MergeError, t as AllSync } from "./layer.types-DgpCIsk_.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/layer/layer.d.ts
|
|
7
|
+
declare namespace layer_d_exports {
|
|
8
|
+
export { err, fx, merge, ok, provide, scoped };
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a layer from an Fx computation (can have dependencies).
|
|
12
|
+
* The Sync type parameter is inferred from the input fx:
|
|
13
|
+
* - SyncFx input → Layer with Sync=true
|
|
14
|
+
* - AsyncFx input → Layer with Sync=false
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
19
|
+
*
|
|
20
|
+
* import { Fx, Service } from "@nicolastoulemont/std"
|
|
21
|
+
*
|
|
22
|
+
* const Port = Service.tag<number>("Port")
|
|
23
|
+
* const portLayer = Layer.fx(Port)(Fx.gen(function* () {
|
|
24
|
+
* return 3000
|
|
25
|
+
* }))
|
|
26
|
+
* // => effect-backed layer
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @category Constructors
|
|
30
|
+
*/
|
|
31
|
+
declare function layerFx<S>(service: ServiceClass<S>): {
|
|
32
|
+
<E, R>(fx: SyncFx<S, E, R>): Layer<S, E, R, true>;
|
|
33
|
+
<E, R>(fx: AsyncFx<S, E, R>): Layer<S, E, R, false>;
|
|
34
|
+
<E, R>(fx: RunnableFx<S, E, R>): Layer<S, E, R>;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Create a scoped layer (with resource cleanup).
|
|
38
|
+
* The Sync type parameter is inferred from the input fx.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
43
|
+
*
|
|
44
|
+
* import { Fx, Service } from "@nicolastoulemont/std"
|
|
45
|
+
*
|
|
46
|
+
* const Resource = Service.tag<{ close: () => void }>("Resource")
|
|
47
|
+
* const resourceLayer = Layer.scoped(Resource)(Fx.gen(function* () {
|
|
48
|
+
* return { close: () => undefined }
|
|
49
|
+
* }) as never)
|
|
50
|
+
* // => scoped layer with finalization support
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @category Constructors
|
|
54
|
+
*/
|
|
55
|
+
declare function layerScoped<S>(service: ServiceClass<S>): {
|
|
56
|
+
<E, R>(fx: SyncFx<S, E, R | ScopeService>): Layer<S, E, ExcludeScope<R>, true>;
|
|
57
|
+
<E, R>(fx: AsyncFx<S, E, R | ScopeService>): Layer<S, E, ExcludeScope<R>, false>;
|
|
58
|
+
<E, R>(fx: RunnableFx<S, E, R | ScopeService>): Layer<S, E, ExcludeScope<R>>;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Provide dependencies to a layer and merge outputs.
|
|
62
|
+
* Sync is preserved only if both the deps layer and the consuming layer are sync.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
67
|
+
*
|
|
68
|
+
* import { Service } from "@nicolastoulemont/std"
|
|
69
|
+
*
|
|
70
|
+
* const Logger = Service.tag<{ log: (message: string) => void }>("Logger")
|
|
71
|
+
* const App = Service.tag<{ start: () => void }>("App")
|
|
72
|
+
* const loggerLayer = Layer.ok(Logger, { log: () => undefined })
|
|
73
|
+
* const appLayer = Layer.ok(App, { start: () => undefined })
|
|
74
|
+
* const provided = Layer.provide(loggerLayer)(appLayer)
|
|
75
|
+
* // => composed layer
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @category Sequencing
|
|
79
|
+
*/
|
|
80
|
+
declare function layerProvide<DepsROut, DepsE, DepsRIn, DepsSync extends boolean>(deps: Layer<DepsROut, DepsE, DepsRIn, DepsSync>): {
|
|
81
|
+
<ROut, E, RIn extends DepsROut, LayerSync extends boolean>(layer: Layer<ROut, E, RIn, LayerSync>): Layer<ROut | DepsROut, E | DepsE, DepsRIn, LayerSync extends true ? DepsSync : false>;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Merge multiple layers with automatic dependency resolution.
|
|
85
|
+
* The merged layer is sync only if ALL input layers are sync.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
90
|
+
*
|
|
91
|
+
* import { Service } from "@nicolastoulemont/std"
|
|
92
|
+
*
|
|
93
|
+
* const Logger = Service.tag<{ log: (message: string) => void }>("Logger")
|
|
94
|
+
* const Clock = Service.tag<{ now: () => number }>("Clock")
|
|
95
|
+
* const merged = Layer.merge(
|
|
96
|
+
* Layer.ok(Logger, { log: () => undefined }),
|
|
97
|
+
* Layer.ok(Clock, { now: () => Date.now() }),
|
|
98
|
+
* )
|
|
99
|
+
* // => layer that provides Logger | Clock
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @category Combining
|
|
103
|
+
*/
|
|
104
|
+
declare function layerMerge<L extends Layer<unknown, unknown, unknown>[]>(...layers: L): Layer<MergeROut<L>, MergeError<L>, UnprovidedDeps<L>, AllSync<L>>;
|
|
105
|
+
/**
|
|
106
|
+
* Create a successful no-dependency layer from a plain service value.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
111
|
+
*
|
|
112
|
+
* import { Service } from "@nicolastoulemont/std"
|
|
113
|
+
*
|
|
114
|
+
* const Port = Service.tag<number>("Port")
|
|
115
|
+
* const portLayer = Layer.ok(Port, 3000)
|
|
116
|
+
* // => layer that provides Port
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @category Constructors
|
|
120
|
+
*/
|
|
121
|
+
declare const ok: <S>(service: ServiceClass<S>, impl: S) => Layer<S, never, never, true>;
|
|
122
|
+
/**
|
|
123
|
+
* Create a layer that always fails with an error.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
128
|
+
*
|
|
129
|
+
* const failingLayer = Layer.err("missing-config")
|
|
130
|
+
* // => layer that always fails with Err("missing-config")
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @category Constructors
|
|
134
|
+
*/
|
|
135
|
+
declare const err: <E>(error: E) => Layer<never, E, never, true>;
|
|
136
|
+
/**
|
|
137
|
+
* Create a layer from an effectful service builder.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
142
|
+
*
|
|
143
|
+
* import { Fx, Service } from "@nicolastoulemont/std"
|
|
144
|
+
*
|
|
145
|
+
* const Port = Service.tag<number>("Port")
|
|
146
|
+
* const portLayer = Layer.fx(Port)(Fx.gen(function* () {
|
|
147
|
+
* return 3000
|
|
148
|
+
* }))
|
|
149
|
+
* // => effect-backed layer
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* @category Constructors
|
|
153
|
+
*/
|
|
154
|
+
declare const fx: typeof layerFx;
|
|
155
|
+
/**
|
|
156
|
+
* Create a scoped layer that registers resource finalizers.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
161
|
+
*
|
|
162
|
+
* import { Fx, Service } from "@nicolastoulemont/std"
|
|
163
|
+
*
|
|
164
|
+
* const Resource = Service.tag<{ close: () => void }>("Resource")
|
|
165
|
+
* const resourceLayer = Layer.scoped(Resource)(Fx.gen(function* () {
|
|
166
|
+
* return { close: () => undefined }
|
|
167
|
+
* }) as never)
|
|
168
|
+
* // => scoped layer with finalization support
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @category Constructors
|
|
172
|
+
*/
|
|
173
|
+
declare const scoped: typeof layerScoped;
|
|
174
|
+
/**
|
|
175
|
+
* Provide one layer to another, satisfying dependencies.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
180
|
+
*
|
|
181
|
+
* import { Service } from "@nicolastoulemont/std"
|
|
182
|
+
*
|
|
183
|
+
* const Logger = Service.tag<{ log: (message: string) => void }>("Logger")
|
|
184
|
+
* const App = Service.tag<{ start: () => void }>("App")
|
|
185
|
+
* const loggerLayer = Layer.ok(Logger, { log: () => undefined })
|
|
186
|
+
* const appLayer = Layer.ok(App, { start: () => undefined })
|
|
187
|
+
* const provided = Layer.provide(loggerLayer)(appLayer)
|
|
188
|
+
* // => composed layer
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* @category Sequencing
|
|
192
|
+
*/
|
|
193
|
+
declare const provide: typeof layerProvide;
|
|
194
|
+
/**
|
|
195
|
+
* Merge multiple layers into a single composite layer.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import { Layer } from "@nicolastoulemont/std"
|
|
200
|
+
*
|
|
201
|
+
* import { Service } from "@nicolastoulemont/std"
|
|
202
|
+
*
|
|
203
|
+
* const Logger = Service.tag<{ log: (message: string) => void }>("Logger")
|
|
204
|
+
* const Clock = Service.tag<{ now: () => number }>("Clock")
|
|
205
|
+
* const merged = Layer.merge(
|
|
206
|
+
* Layer.ok(Logger, { log: () => undefined }),
|
|
207
|
+
* Layer.ok(Clock, { now: () => Date.now() }),
|
|
208
|
+
* )
|
|
209
|
+
* // => layer that provides Logger | Clock
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @category Combining
|
|
213
|
+
*/
|
|
214
|
+
declare const merge: typeof layerMerge;
|
|
215
|
+
//#endregion
|
|
216
|
+
export { layer_d_exports as t };
|
|
217
|
+
//# sourceMappingURL=index-7Lv982Om.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-7Lv982Om.d.mts","names":[],"sources":["../src/layer/layer.ts"],"sourcesContent":[],"mappings":"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"}
|