@nicolastoulemont/std 0.8.2 → 0.9.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.
- package/README.md +24 -1
- package/dist/adt/index.d.mts +1 -1
- package/dist/adt/index.mjs +1 -1
- package/dist/adt-CY8wLJJI.mjs +2 -0
- package/dist/adt-CY8wLJJI.mjs.map +1 -0
- package/dist/data/index.d.mts +1 -1
- package/dist/data/index.mjs +1 -1
- package/dist/data-DqACNS_g.mjs +2 -0
- package/dist/data-DqACNS_g.mjs.map +1 -0
- package/dist/duration/index.d.mts +1 -1
- package/dist/duration/index.mjs +1 -1
- package/dist/{duration-CYoDHcOR.mjs → duration-Bas3mi1N.mjs} +2 -2
- package/dist/{duration-CYoDHcOR.mjs.map → duration-Bas3mi1N.mjs.map} +1 -1
- package/dist/fx/index.d.mts +1 -1
- package/dist/fx/index.mjs +1 -1
- package/dist/{fx-DUXDxwsU.mjs → fx-C_RTDEpv.mjs} +2 -2
- package/dist/{fx-DUXDxwsU.mjs.map → fx-C_RTDEpv.mjs.map} +1 -1
- package/dist/{index-C4DOLLaU.d.mts → index-BD-els5J.d.mts} +2 -2
- package/dist/{index-C4DOLLaU.d.mts.map → index-BD-els5J.d.mts.map} +1 -1
- package/dist/{index-C6W3_n_Q.d.mts → index-BaRJVkLo.d.mts} +2 -2
- package/dist/{index-C6W3_n_Q.d.mts.map → index-BaRJVkLo.d.mts.map} +1 -1
- package/dist/{index-B41_sFR6.d.mts → index-BipW0MC3.d.mts} +2 -2
- package/dist/index-BipW0MC3.d.mts.map +1 -0
- package/dist/index-CIvNgjsx.d.mts.map +1 -1
- package/dist/{index-B0flvtFB.d.mts → index-CVmgBpDt.d.mts} +2 -2
- package/dist/{index-B0flvtFB.d.mts.map → index-CVmgBpDt.d.mts.map} +1 -1
- package/dist/{index-B2Z7-XGR.d.mts → index-D6pjHqlK.d.mts} +48 -2
- package/dist/index-D6pjHqlK.d.mts.map +1 -0
- package/dist/{index-crtzMG48.d.mts → index-D8gcYvR9.d.mts} +38 -3
- package/dist/index-D8gcYvR9.d.mts.map +1 -0
- package/dist/{index-DCUGtEcj.d.mts → index-DfAqfnY0.d.mts} +2 -2
- package/dist/{index-DCUGtEcj.d.mts.map → index-DfAqfnY0.d.mts.map} +1 -1
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +1 -1
- package/dist/{equality-BX6BUidG.mjs → is-plain-object-BoFjRafL.mjs} +2 -2
- package/dist/is-plain-object-BoFjRafL.mjs.map +1 -0
- package/dist/layer/index.mjs +1 -1
- package/dist/{layer-CKtH7TRL.mjs → layer-C5A-EM0h.mjs} +2 -2
- package/dist/{layer-CKtH7TRL.mjs.map → layer-C5A-EM0h.mjs.map} +1 -1
- package/dist/provide/index.d.mts +1 -1
- package/dist/provide/index.mjs +1 -1
- package/dist/provide-CuccogWx.mjs +2 -0
- package/dist/provide-CuccogWx.mjs.map +1 -0
- package/dist/queue/index.d.mts +1 -1
- package/dist/queue/index.mjs +1 -1
- package/dist/{queue-apiEOlRD.mjs → queue-GYVrD39q.mjs} +2 -2
- package/dist/{queue-apiEOlRD.mjs.map → queue-GYVrD39q.mjs.map} +1 -1
- package/dist/schedule/index.d.mts +1 -1
- package/dist/schedule/index.mjs +1 -1
- package/dist/{schedule-C6iN3oMt.mjs → schedule-B7qV60tO.mjs} +2 -2
- package/dist/{schedule-C6iN3oMt.mjs.map → schedule-B7qV60tO.mjs.map} +1 -1
- package/dist/{schedule-D2651VJY.d.mts → schedule-BzPjvMXc.d.mts} +3 -3
- package/dist/{schedule-D2651VJY.d.mts.map → schedule-BzPjvMXc.d.mts.map} +1 -1
- package/dist/schema/index.d.mts +1 -1
- package/dist/schema-DstB1_VK.mjs.map +1 -1
- package/dist/{schema.types-E1pjcc0Y.d.mts → schema.types-w1WK4kGS.d.mts} +2 -2
- package/dist/schema.types-w1WK4kGS.d.mts.map +1 -0
- package/package.json +1 -1
- package/dist/adt-CPG_sa8q.mjs +0 -2
- package/dist/adt-CPG_sa8q.mjs.map +0 -1
- package/dist/data-BHYPdqWZ.mjs +0 -2
- package/dist/data-BHYPdqWZ.mjs.map +0 -1
- package/dist/equality-BX6BUidG.mjs.map +0 -1
- package/dist/index-B2Z7-XGR.d.mts.map +0 -1
- package/dist/index-B41_sFR6.d.mts.map +0 -1
- package/dist/index-crtzMG48.d.mts.map +0 -1
- package/dist/provide--yZE8x-n.mjs +0 -2
- package/dist/provide--yZE8x-n.mjs.map +0 -1
- package/dist/schema.types-E1pjcc0Y.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer-CKtH7TRL.mjs","names":["Context.make","fx","layerGen","layerResult","Context.merge","Context.empty"],"sources":["../src/layer/layer.ts"],"sourcesContent":["/**\n * Layer construction and composition for service dependency graphs.\n *\n * **Mental model**\n * - A `Layer` builds one or more services, potentially requiring other services.\n * - Compose layers and provide dependencies before running `Fx`.\n *\n * **Common tasks**\n * - Build from values with `Layer.ok`.\n * - Build from effects with `Layer.fx` or `Layer.scoped`.\n * - Compose with `Layer.provide` and `Layer.merge`.\n *\n * **Gotchas**\n * - Async layers force async execution paths.\n * - Scoped layers require scope finalization.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(Layer.ok(Port, 3000))(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n *\n * @module\n */\nimport * as Context from \"../context/context\"\nimport type { Context as ContextType } from \"../context/context\"\nimport { FxTypeId } from \"../fx/fx.types\"\nimport type { RunnableFx, SyncFx, AsyncFx, FxYield } from \"../fx/fx.types\"\nimport type { ScopeService, ExcludeScope } from \"../scope/scope\"\nimport type { ServiceClass } from \"../service/service\"\nimport { asServiceRequest, resolveService } from \"../service/service-resolution\"\nimport type { Layer as LayerType, MergeROut, MergeError, UnprovidedDeps, AllSync } from \"./layer.types\"\n\n/* oxlint-disable no-unsafe-type-assertion -- Layer composition carries erased generic channels and phantom type slots that require assertion-based reconstruction. */\n\n/**\n * Create a layer from a synchronous value (no dependencies).\n */\nconst layerOk = <S>(service: ServiceClass<S>, impl: S): LayerType<S, never, never, true> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as S,\n _E: undefined as never,\n _RIn: undefined as never,\n _Sync: undefined as unknown as true,\n build: (): SyncFx<ContextType<S>> => ({\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as never,\n _R: () => undefined as never,\n },\n // oxlint-disable-next-line require-yield\n *[Symbol.iterator](): Generator<never, ContextType<S>, unknown> {\n return Context.make(service, impl)\n },\n }),\n})\n\n/**\n * Create a layer that always fails with an error.\n */\nconst layerErr = <E>(error: E): LayerType<never, E, never, true> => ({\n _tag: \"Layer\",\n _ROut: undefined as never,\n _E: undefined as unknown as E,\n _RIn: undefined as never,\n _Sync: undefined as unknown as true,\n build: (): SyncFx<ContextType, E> => ({\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as never,\n _E: () => error,\n _R: () => undefined as never,\n },\n *[Symbol.iterator](): Generator<E, never, unknown> {\n yield error\n throw new Error(\"Unreachable\")\n },\n }),\n})\n\n/**\n * Create a layer from an Fx computation (can have dependencies).\n * The Sync type parameter is inferred from the input fx:\n * - SyncFx input → Layer with Sync=true\n * - AsyncFx input → Layer with Sync=false\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const portLayer = Layer.fx(Port)(Fx.gen(function* () {\n * return 3000\n * }))\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(portLayer)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nfunction layerFx<S>(service: ServiceClass<S>): {\n <E, R>(fx: SyncFx<S, E, R>): LayerType<S, E, R, true>\n <E, R>(fx: AsyncFx<S, E, R>): LayerType<S, E, R, false>\n <E, R>(fx: RunnableFx<S, E, R>): LayerType<S, E, R>\n}\nfunction layerFx<S>(service: ServiceClass<S>) {\n return <E, R>(fx: RunnableFx<S, E, R>): LayerType<S, E, R> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as S,\n _E: undefined as unknown as E,\n _RIn: undefined as unknown as R,\n _Sync: undefined as unknown as boolean,\n build: (): RunnableFx<ContextType<S>, E, R> => {\n if (fx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, ContextType<S>, unknown> {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n while (result.done !== true) {\n const value = yield result.value\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n return Context.make(service, result.value)\n },\n } as AsyncFx<ContextType<S>, E, R>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n *[Symbol.iterator](): Generator<FxYield<E, R>, ContextType<S>, unknown> {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const value = yield result.value\n result = gen.next(value)\n }\n return Context.make(service, result.value)\n },\n } as SyncFx<ContextType<S>, E, R>\n },\n })\n}\n\n/**\n * Create a scoped layer (with resource cleanup).\n * The Sync type parameter is inferred from the input fx.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Scope, Service } from \"@nicolastoulemont/std\"\n *\n * const Resource = Service.tag<{ readonly id: number }>(\"Resource\")\n * const ScopeTag = Service.tag<Scope.ScopeService>(\"@std/Scope\")\n * let finalized = 0\n *\n * const resourceLayer = Layer.scoped(Resource)(Fx.gen(function* () {\n * const scope = yield* ScopeTag\n * yield* scope.addFinalizer(() =>\n * Fx.gen(function* () {\n * finalized += 1\n * }),\n * )\n * return { id: 1 }\n * }))\n * const program = Fx.gen(function* () {\n * return (yield* Resource).id\n * })\n * const exit = Fx.run(Provide.layer(resourceLayer)(program))\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n */\nfunction layerScoped<S>(service: ServiceClass<S>): {\n <E, R>(fx: SyncFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>, true>\n <E, R>(fx: AsyncFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>, false>\n <E, R>(fx: RunnableFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>>\n}\nfunction layerScoped<S>(service: ServiceClass<S>) {\n return <E, R>(fx: RunnableFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as S,\n _E: undefined as unknown as E,\n _RIn: undefined as unknown as ExcludeScope<R>,\n _Sync: undefined as unknown as boolean,\n build: (_memoMap, scope): RunnableFx<ContextType<S>, E, ExcludeScope<R>> => {\n if (fx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as ExcludeScope<R>,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, ExcludeScope<R>>, ContextType<S>, unknown> {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest?.key === \"@std/Scope\") {\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(scope)\n } else {\n const value = yield yielded as FxYield<E, ExcludeScope<R>>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n }\n return Context.make(service, result.value)\n },\n } as AsyncFx<ContextType<S>, E, ExcludeScope<R>>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as ExcludeScope<R>,\n },\n *[Symbol.iterator](): Generator<FxYield<E, ExcludeScope<R>>, ContextType<S>, unknown> {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest?.key === \"@std/Scope\") {\n result = gen.next(scope)\n } else {\n const value = yield yielded as FxYield<E, ExcludeScope<R>>\n result = gen.next(value)\n }\n }\n return Context.make(service, result.value)\n },\n } as SyncFx<ContextType<S>, E, ExcludeScope<R>>\n },\n })\n}\n\n// ============================================================================\n// Layer Composition\n// ============================================================================\n\n/**\n * Provide dependencies to a layer and merge outputs.\n * Sync is preserved only if both the deps layer and the consuming layer are sync.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const Server = Service.tag<{ readonly port: number }>(\"Server\")\n * const portLayer = Layer.ok(Port, 3000)\n * const serverLayer = Layer.fx(Server)(Fx.gen(function* () {\n * const port = yield* Port\n * return { port }\n * }))\n * const provided = Layer.provide(portLayer)(serverLayer)\n * const program = Fx.gen(function* () {\n * return (yield* Server).port\n * })\n * const exit = Fx.run(Provide.layer(provided)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nfunction layerProvide<DepsROut, DepsE, DepsRIn, DepsSync extends boolean>(\n deps: LayerType<DepsROut, DepsE, DepsRIn, DepsSync>,\n): {\n <ROut, E, RIn extends DepsROut, LayerSync extends boolean>(\n layer: LayerType<ROut, E, RIn, LayerSync>,\n ): LayerType<ROut | DepsROut, E | DepsE, DepsRIn, LayerSync extends true ? DepsSync : false>\n}\nfunction layerProvide<DepsROut, DepsE, DepsRIn>(deps: LayerType<DepsROut, DepsE, DepsRIn>) {\n return <ROut, E, RIn extends DepsROut>(\n layer: LayerType<ROut, E, RIn>,\n ): LayerType<ROut | DepsROut, E | DepsE, DepsRIn> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as ROut | DepsROut,\n _E: undefined as unknown as E | DepsE,\n _RIn: undefined as unknown as DepsRIn,\n _Sync: undefined as unknown as boolean,\n build: (memoMap, scope): RunnableFx<ContextType<ROut | DepsROut>, E | DepsE, DepsRIn> => {\n const depsBuildFx = deps.build(memoMap, scope)\n\n if (depsBuildFx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<ROut | DepsROut>,\n _E: () => undefined as unknown as E | DepsE,\n _R: () => undefined as unknown as DepsRIn,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<\n FxYield<E | DepsE, DepsRIn>,\n ContextType<ROut | DepsROut>,\n unknown\n > {\n const depsGen = depsBuildFx[Symbol.asyncIterator]()\n let depsResult = await depsGen.next()\n while (depsResult.done !== true) {\n const value = yield depsResult.value\n // oxlint-disable-next-line no-await-in-loop\n depsResult = await depsGen.next(value)\n }\n const depsCtx = depsResult.value\n\n const layerBuildFx = layer.build(memoMap, scope)\n if (layerBuildFx._tag === \"AsyncFx\") {\n const layerGen = layerBuildFx[Symbol.asyncIterator]()\n let layerResult = await layerGen.next()\n while (layerResult.done !== true) {\n const yielded = layerResult.value\n const service = resolveService(depsCtx, yielded)\n if (service !== undefined) {\n // oxlint-disable-next-line no-await-in-loop\n layerResult = await layerGen.next(service)\n continue\n }\n const value = yield yielded as FxYield<E, DepsRIn>\n // oxlint-disable-next-line no-await-in-loop\n layerResult = await layerGen.next(value)\n }\n return Context.merge(depsCtx, layerResult.value)\n }\n\n const layerGen = layerBuildFx[Symbol.iterator]()\n let layerResult = layerGen.next()\n while (layerResult.done !== true) {\n const yielded = layerResult.value\n const service = resolveService(depsCtx, yielded)\n if (service !== undefined) {\n layerResult = layerGen.next(service)\n continue\n }\n const value = yield yielded as FxYield<E, DepsRIn>\n layerResult = layerGen.next(value)\n }\n return Context.merge(depsCtx, layerResult.value)\n },\n } as AsyncFx<ContextType<ROut | DepsROut>, E | DepsE, DepsRIn>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<ROut | DepsROut>,\n _E: () => undefined as unknown as E | DepsE,\n _R: () => undefined as unknown as DepsRIn,\n },\n *[Symbol.iterator](): Generator<FxYield<E | DepsE, DepsRIn>, ContextType<ROut | DepsROut>, unknown> {\n const depsGen = depsBuildFx[Symbol.iterator]()\n let depsResult = depsGen.next()\n while (depsResult.done !== true) {\n const value = yield depsResult.value\n depsResult = depsGen.next(value)\n }\n const depsCtx = depsResult.value\n\n const layerBuildFx = layer.build(memoMap, scope)\n if (layerBuildFx._tag === \"SyncFx\") {\n const syncGen = layerBuildFx[Symbol.iterator]()\n let layerResult = syncGen.next()\n while (layerResult.done !== true) {\n const yielded = layerResult.value\n const service = resolveService(depsCtx, yielded)\n if (service !== undefined) {\n layerResult = syncGen.next(service)\n continue\n }\n const value = yield yielded as FxYield<E, DepsRIn>\n layerResult = syncGen.next(value)\n }\n return Context.merge(depsCtx, layerResult.value)\n }\n throw new Error(\"Cannot use async layer in sync context\")\n },\n } as SyncFx<ContextType<ROut | DepsROut>, E | DepsE, DepsRIn>\n },\n })\n}\n\n/**\n * Merge multiple layers with automatic dependency resolution.\n * The merged layer is sync only if ALL input layers are sync.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ readonly prefix: string }>(\"Logger\")\n * const Clock = Service.tag<{ readonly now: () => number }>(\"Clock\")\n * const merged = Layer.merge(\n * Layer.ok(Logger, { prefix: \"dev\" }),\n * Layer.ok(Clock, { now: () => 123 }),\n * )\n * const program = Fx.gen(function* () {\n * const logger = yield* Logger\n * const clock = yield* Clock\n * return `${logger.prefix}:${clock.now()}`\n * })\n * const exit = Fx.run(Provide.layer(merged)(program))\n * // => { _tag: \"Ok\", value: \"dev:123\" }\n * ```\n */\nfunction layerMerge<L extends LayerType<unknown, unknown, unknown>[]>(\n ...layers: L\n): LayerType<MergeROut<L>, MergeError<L>, UnprovidedDeps<L>, AllSync<L>>\nfunction layerMerge<L extends LayerType<unknown, unknown, unknown>[]>(\n ...layers: L\n): LayerType<MergeROut<L>, MergeError<L>, UnprovidedDeps<L>> {\n return {\n _tag: \"Layer\",\n _ROut: undefined as unknown as MergeROut<L>,\n _E: undefined as unknown as MergeError<L>,\n _RIn: undefined as unknown as UnprovidedDeps<L>,\n _Sync: undefined as unknown as boolean,\n build: (memoMap, scope): RunnableFx<ContextType<MergeROut<L>>, MergeError<L>, UnprovidedDeps<L>> => {\n const hasAsync = layers.some((l) => l.build(memoMap, scope)._tag === \"AsyncFx\")\n\n if (hasAsync) {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<MergeROut<L>>,\n _E: () => undefined as unknown as MergeError<L>,\n _R: () => undefined as unknown as UnprovidedDeps<L>,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<\n FxYield<MergeError<L>, UnprovidedDeps<L>>,\n ContextType<MergeROut<L>>,\n unknown\n > {\n let ctx = Context.empty() as ContextType<unknown>\n for (const layer of layers) {\n const buildFx = layer.build(memoMap, scope)\n if (buildFx._tag === \"AsyncFx\") {\n const gen = buildFx[Symbol.asyncIterator]()\n // oxlint-disable-next-line no-await-in-loop\n let result = await gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(service)\n continue\n }\n const value = yield yielded as FxYield<MergeError<L>, UnprovidedDeps<L>>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n ctx = Context.merge(ctx, result.value)\n } else {\n const gen = buildFx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n result = gen.next(service)\n continue\n }\n const value = yield yielded as FxYield<MergeError<L>, UnprovidedDeps<L>>\n result = gen.next(value)\n }\n ctx = Context.merge(ctx, result.value)\n }\n }\n return ctx as ContextType<MergeROut<L>>\n },\n } as AsyncFx<ContextType<MergeROut<L>>, MergeError<L>, UnprovidedDeps<L>>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<MergeROut<L>>,\n _E: () => undefined as unknown as MergeError<L>,\n _R: () => undefined as unknown as UnprovidedDeps<L>,\n },\n *[Symbol.iterator](): Generator<FxYield<MergeError<L>, UnprovidedDeps<L>>, ContextType<MergeROut<L>>, unknown> {\n let ctx = Context.empty() as ContextType<unknown>\n for (const layer of layers) {\n const buildFx = layer.build(memoMap, scope)\n if (buildFx._tag !== \"SyncFx\") {\n throw new Error(\"Expected sync layer in sync context\")\n }\n const gen = buildFx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n result = gen.next(service)\n continue\n }\n const value = yield yielded as FxYield<MergeError<L>, UnprovidedDeps<L>>\n result = gen.next(value)\n }\n ctx = Context.merge(ctx, result.value)\n }\n return ctx as ContextType<MergeROut<L>>\n },\n } as SyncFx<ContextType<MergeROut<L>>, MergeError<L>, UnprovidedDeps<L>>\n },\n }\n}\n\n/**\n * Create a successful no-dependency layer from a plain service value.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(Layer.ok(Port, 3000))(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const ok = layerOk\n\n/**\n * Create a layer that always fails with an error.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide } from \"@nicolastoulemont/std\"\n *\n * const program = Fx.gen(function* () {\n * return 1\n * })\n * const exit = Fx.run(Provide.layer(Layer.err(\"missing-config\"))(program))\n * // => { _tag: \"Err\", error: \"missing-config\" }\n * ```\n */\nexport const err = layerErr\n\n/**\n * Create a layer from an effectful service builder.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const portLayer = Layer.fx(Port)(Fx.gen(function* () {\n * return 3000\n * }))\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(portLayer)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const fx = layerFx\n\n/**\n * Create a scoped layer that registers resource finalizers.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Scope, Service } from \"@nicolastoulemont/std\"\n *\n * const Resource = Service.tag<{ readonly id: number }>(\"Resource\")\n * const ScopeTag = Service.tag<Scope.ScopeService>(\"@std/Scope\")\n * let finalized = 0\n *\n * const resourceLayer = Layer.scoped(Resource)(Fx.gen(function* () {\n * const scope = yield* ScopeTag\n * yield* scope.addFinalizer(() =>\n * Fx.gen(function* () {\n * finalized += 1\n * }),\n * )\n * return { id: 1 }\n * }))\n * const program = Fx.gen(function* () {\n * return (yield* Resource).id\n * })\n * const exit = Fx.run(Provide.layer(resourceLayer)(program))\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n */\nexport const scoped = layerScoped\n\n/**\n * Provide one layer to another, satisfying dependencies.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const Server = Service.tag<{ readonly port: number }>(\"Server\")\n * const portLayer = Layer.ok(Port, 3000)\n * const serverLayer = Layer.fx(Server)(Fx.gen(function* () {\n * const port = yield* Port\n * return { port }\n * }))\n * const provided = Layer.provide(portLayer)(serverLayer)\n * const program = Fx.gen(function* () {\n * return (yield* Server).port\n * })\n * const exit = Fx.run(Provide.layer(provided)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const provide = layerProvide\n\n/**\n * Merge multiple layers into a single composite layer.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ readonly prefix: string }>(\"Logger\")\n * const Clock = Service.tag<{ readonly now: () => number }>(\"Clock\")\n * const merged = Layer.merge(\n * Layer.ok(Logger, { prefix: \"dev\" }),\n * Layer.ok(Clock, { now: () => 123 }),\n * )\n * const program = Fx.gen(function* () {\n * const logger = yield* Logger\n * const clock = yield* Clock\n * return `${logger.prefix}:${clock.now()}`\n * })\n * const exit = Fx.run(Provide.layer(merged)(program))\n * // => { _tag: \"Ok\", value: \"dev:123\" }\n * ```\n */\nexport const merge = layerMerge\n\n/* oxlint-enable no-unsafe-type-assertion */\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"layer-C5A-EM0h.mjs","names":["Context.make","fx","layerGen","layerResult","Context.merge","Context.empty"],"sources":["../src/layer/layer.ts"],"sourcesContent":["/**\n * Layer construction and composition for service dependency graphs.\n *\n * **Mental model**\n * - A `Layer` builds one or more services, potentially requiring other services.\n * - Compose layers and provide dependencies before running `Fx`.\n *\n * **Common tasks**\n * - Build from values with `Layer.ok`.\n * - Build from effects with `Layer.fx` or `Layer.scoped`.\n * - Compose with `Layer.provide` and `Layer.merge`.\n *\n * **Gotchas**\n * - Async layers force async execution paths.\n * - Scoped layers require scope finalization.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(Layer.ok(Port, 3000))(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n *\n * @module\n */\nimport * as Context from \"../context/context\"\nimport type { Context as ContextType } from \"../context/context\"\nimport { FxTypeId } from \"../fx/fx.types\"\nimport type { RunnableFx, SyncFx, AsyncFx, FxYield } from \"../fx/fx.types\"\nimport type { ScopeService, ExcludeScope } from \"../scope/scope\"\nimport type { ServiceClass } from \"../service/service\"\nimport { asServiceRequest, resolveService } from \"../service/service-resolution\"\nimport type { Layer as LayerType, MergeROut, MergeError, UnprovidedDeps, AllSync } from \"./layer.types\"\n\n/* oxlint-disable no-unsafe-type-assertion -- Layer composition carries erased generic channels and phantom type slots that require assertion-based reconstruction. */\n\n/**\n * Create a layer from a synchronous value (no dependencies).\n */\nconst layerOk = <S>(service: ServiceClass<S>, impl: S): LayerType<S, never, never, true> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as S,\n _E: undefined as never,\n _RIn: undefined as never,\n _Sync: undefined as unknown as true,\n build: (): SyncFx<ContextType<S>> => ({\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as never,\n _R: () => undefined as never,\n },\n // oxlint-disable-next-line require-yield\n *[Symbol.iterator](): Generator<never, ContextType<S>, unknown> {\n return Context.make(service, impl)\n },\n }),\n})\n\n/**\n * Create a layer that always fails with an error.\n */\nconst layerErr = <E>(error: E): LayerType<never, E, never, true> => ({\n _tag: \"Layer\",\n _ROut: undefined as never,\n _E: undefined as unknown as E,\n _RIn: undefined as never,\n _Sync: undefined as unknown as true,\n build: (): SyncFx<ContextType, E> => ({\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as never,\n _E: () => error,\n _R: () => undefined as never,\n },\n *[Symbol.iterator](): Generator<E, never, unknown> {\n yield error\n throw new Error(\"Unreachable\")\n },\n }),\n})\n\n/**\n * Create a layer from an Fx computation (can have dependencies).\n * The Sync type parameter is inferred from the input fx:\n * - SyncFx input → Layer with Sync=true\n * - AsyncFx input → Layer with Sync=false\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const portLayer = Layer.fx(Port)(Fx.gen(function* () {\n * return 3000\n * }))\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(portLayer)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nfunction layerFx<S>(service: ServiceClass<S>): {\n <E, R>(fx: SyncFx<S, E, R>): LayerType<S, E, R, true>\n <E, R>(fx: AsyncFx<S, E, R>): LayerType<S, E, R, false>\n <E, R>(fx: RunnableFx<S, E, R>): LayerType<S, E, R>\n}\nfunction layerFx<S>(service: ServiceClass<S>) {\n return <E, R>(fx: RunnableFx<S, E, R>): LayerType<S, E, R> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as S,\n _E: undefined as unknown as E,\n _RIn: undefined as unknown as R,\n _Sync: undefined as unknown as boolean,\n build: (): RunnableFx<ContextType<S>, E, R> => {\n if (fx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, ContextType<S>, unknown> {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n while (result.done !== true) {\n const value = yield result.value\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n return Context.make(service, result.value)\n },\n } as AsyncFx<ContextType<S>, E, R>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n *[Symbol.iterator](): Generator<FxYield<E, R>, ContextType<S>, unknown> {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const value = yield result.value\n result = gen.next(value)\n }\n return Context.make(service, result.value)\n },\n } as SyncFx<ContextType<S>, E, R>\n },\n })\n}\n\n/**\n * Create a scoped layer (with resource cleanup).\n * The Sync type parameter is inferred from the input fx.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Scope, Service } from \"@nicolastoulemont/std\"\n *\n * const Resource = Service.tag<{ readonly id: number }>(\"Resource\")\n * const ScopeTag = Service.tag<Scope.ScopeService>(\"@std/Scope\")\n * let finalized = 0\n *\n * const resourceLayer = Layer.scoped(Resource)(Fx.gen(function* () {\n * const scope = yield* ScopeTag\n * yield* scope.addFinalizer(() =>\n * Fx.gen(function* () {\n * finalized += 1\n * }),\n * )\n * return { id: 1 }\n * }))\n * const program = Fx.gen(function* () {\n * return (yield* Resource).id\n * })\n * const exit = Fx.run(Provide.layer(resourceLayer)(program))\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n */\nfunction layerScoped<S>(service: ServiceClass<S>): {\n <E, R>(fx: SyncFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>, true>\n <E, R>(fx: AsyncFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>, false>\n <E, R>(fx: RunnableFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>>\n}\nfunction layerScoped<S>(service: ServiceClass<S>) {\n return <E, R>(fx: RunnableFx<S, E, R | ScopeService>): LayerType<S, E, ExcludeScope<R>> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as S,\n _E: undefined as unknown as E,\n _RIn: undefined as unknown as ExcludeScope<R>,\n _Sync: undefined as unknown as boolean,\n build: (_memoMap, scope): RunnableFx<ContextType<S>, E, ExcludeScope<R>> => {\n if (fx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as ExcludeScope<R>,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, ExcludeScope<R>>, ContextType<S>, unknown> {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest?.key === \"@std/Scope\") {\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(scope)\n } else {\n const value = yield yielded as FxYield<E, ExcludeScope<R>>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n }\n return Context.make(service, result.value)\n },\n } as AsyncFx<ContextType<S>, E, ExcludeScope<R>>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<S>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as ExcludeScope<R>,\n },\n *[Symbol.iterator](): Generator<FxYield<E, ExcludeScope<R>>, ContextType<S>, unknown> {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest?.key === \"@std/Scope\") {\n result = gen.next(scope)\n } else {\n const value = yield yielded as FxYield<E, ExcludeScope<R>>\n result = gen.next(value)\n }\n }\n return Context.make(service, result.value)\n },\n } as SyncFx<ContextType<S>, E, ExcludeScope<R>>\n },\n })\n}\n\n// ============================================================================\n// Layer Composition\n// ============================================================================\n\n/**\n * Provide dependencies to a layer and merge outputs.\n * Sync is preserved only if both the deps layer and the consuming layer are sync.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const Server = Service.tag<{ readonly port: number }>(\"Server\")\n * const portLayer = Layer.ok(Port, 3000)\n * const serverLayer = Layer.fx(Server)(Fx.gen(function* () {\n * const port = yield* Port\n * return { port }\n * }))\n * const provided = Layer.provide(portLayer)(serverLayer)\n * const program = Fx.gen(function* () {\n * return (yield* Server).port\n * })\n * const exit = Fx.run(Provide.layer(provided)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nfunction layerProvide<DepsROut, DepsE, DepsRIn, DepsSync extends boolean>(\n deps: LayerType<DepsROut, DepsE, DepsRIn, DepsSync>,\n): {\n <ROut, E, RIn extends DepsROut, LayerSync extends boolean>(\n layer: LayerType<ROut, E, RIn, LayerSync>,\n ): LayerType<ROut | DepsROut, E | DepsE, DepsRIn, LayerSync extends true ? DepsSync : false>\n}\nfunction layerProvide<DepsROut, DepsE, DepsRIn>(deps: LayerType<DepsROut, DepsE, DepsRIn>) {\n return <ROut, E, RIn extends DepsROut>(\n layer: LayerType<ROut, E, RIn>,\n ): LayerType<ROut | DepsROut, E | DepsE, DepsRIn> => ({\n _tag: \"Layer\",\n _ROut: undefined as unknown as ROut | DepsROut,\n _E: undefined as unknown as E | DepsE,\n _RIn: undefined as unknown as DepsRIn,\n _Sync: undefined as unknown as boolean,\n build: (memoMap, scope): RunnableFx<ContextType<ROut | DepsROut>, E | DepsE, DepsRIn> => {\n const depsBuildFx = deps.build(memoMap, scope)\n\n if (depsBuildFx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<ROut | DepsROut>,\n _E: () => undefined as unknown as E | DepsE,\n _R: () => undefined as unknown as DepsRIn,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<\n FxYield<E | DepsE, DepsRIn>,\n ContextType<ROut | DepsROut>,\n unknown\n > {\n const depsGen = depsBuildFx[Symbol.asyncIterator]()\n let depsResult = await depsGen.next()\n while (depsResult.done !== true) {\n const value = yield depsResult.value\n // oxlint-disable-next-line no-await-in-loop\n depsResult = await depsGen.next(value)\n }\n const depsCtx = depsResult.value\n\n const layerBuildFx = layer.build(memoMap, scope)\n if (layerBuildFx._tag === \"AsyncFx\") {\n const layerGen = layerBuildFx[Symbol.asyncIterator]()\n let layerResult = await layerGen.next()\n while (layerResult.done !== true) {\n const yielded = layerResult.value\n const service = resolveService(depsCtx, yielded)\n if (service !== undefined) {\n // oxlint-disable-next-line no-await-in-loop\n layerResult = await layerGen.next(service)\n continue\n }\n const value = yield yielded as FxYield<E, DepsRIn>\n // oxlint-disable-next-line no-await-in-loop\n layerResult = await layerGen.next(value)\n }\n return Context.merge(depsCtx, layerResult.value)\n }\n\n const layerGen = layerBuildFx[Symbol.iterator]()\n let layerResult = layerGen.next()\n while (layerResult.done !== true) {\n const yielded = layerResult.value\n const service = resolveService(depsCtx, yielded)\n if (service !== undefined) {\n layerResult = layerGen.next(service)\n continue\n }\n const value = yield yielded as FxYield<E, DepsRIn>\n layerResult = layerGen.next(value)\n }\n return Context.merge(depsCtx, layerResult.value)\n },\n } as AsyncFx<ContextType<ROut | DepsROut>, E | DepsE, DepsRIn>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<ROut | DepsROut>,\n _E: () => undefined as unknown as E | DepsE,\n _R: () => undefined as unknown as DepsRIn,\n },\n *[Symbol.iterator](): Generator<FxYield<E | DepsE, DepsRIn>, ContextType<ROut | DepsROut>, unknown> {\n const depsGen = depsBuildFx[Symbol.iterator]()\n let depsResult = depsGen.next()\n while (depsResult.done !== true) {\n const value = yield depsResult.value\n depsResult = depsGen.next(value)\n }\n const depsCtx = depsResult.value\n\n const layerBuildFx = layer.build(memoMap, scope)\n if (layerBuildFx._tag === \"SyncFx\") {\n const syncGen = layerBuildFx[Symbol.iterator]()\n let layerResult = syncGen.next()\n while (layerResult.done !== true) {\n const yielded = layerResult.value\n const service = resolveService(depsCtx, yielded)\n if (service !== undefined) {\n layerResult = syncGen.next(service)\n continue\n }\n const value = yield yielded as FxYield<E, DepsRIn>\n layerResult = syncGen.next(value)\n }\n return Context.merge(depsCtx, layerResult.value)\n }\n throw new Error(\"Cannot use async layer in sync context\")\n },\n } as SyncFx<ContextType<ROut | DepsROut>, E | DepsE, DepsRIn>\n },\n })\n}\n\n/**\n * Merge multiple layers with automatic dependency resolution.\n * The merged layer is sync only if ALL input layers are sync.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ readonly prefix: string }>(\"Logger\")\n * const Clock = Service.tag<{ readonly now: () => number }>(\"Clock\")\n * const merged = Layer.merge(\n * Layer.ok(Logger, { prefix: \"dev\" }),\n * Layer.ok(Clock, { now: () => 123 }),\n * )\n * const program = Fx.gen(function* () {\n * const logger = yield* Logger\n * const clock = yield* Clock\n * return `${logger.prefix}:${clock.now()}`\n * })\n * const exit = Fx.run(Provide.layer(merged)(program))\n * // => { _tag: \"Ok\", value: \"dev:123\" }\n * ```\n */\nfunction layerMerge<L extends LayerType<unknown, unknown, unknown>[]>(\n ...layers: L\n): LayerType<MergeROut<L>, MergeError<L>, UnprovidedDeps<L>, AllSync<L>>\nfunction layerMerge<L extends LayerType<unknown, unknown, unknown>[]>(\n ...layers: L\n): LayerType<MergeROut<L>, MergeError<L>, UnprovidedDeps<L>> {\n return {\n _tag: \"Layer\",\n _ROut: undefined as unknown as MergeROut<L>,\n _E: undefined as unknown as MergeError<L>,\n _RIn: undefined as unknown as UnprovidedDeps<L>,\n _Sync: undefined as unknown as boolean,\n build: (memoMap, scope): RunnableFx<ContextType<MergeROut<L>>, MergeError<L>, UnprovidedDeps<L>> => {\n const hasAsync = layers.some((l) => l.build(memoMap, scope)._tag === \"AsyncFx\")\n\n if (hasAsync) {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<MergeROut<L>>,\n _E: () => undefined as unknown as MergeError<L>,\n _R: () => undefined as unknown as UnprovidedDeps<L>,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<\n FxYield<MergeError<L>, UnprovidedDeps<L>>,\n ContextType<MergeROut<L>>,\n unknown\n > {\n let ctx = Context.empty() as ContextType<unknown>\n for (const layer of layers) {\n const buildFx = layer.build(memoMap, scope)\n if (buildFx._tag === \"AsyncFx\") {\n const gen = buildFx[Symbol.asyncIterator]()\n // oxlint-disable-next-line no-await-in-loop\n let result = await gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(service)\n continue\n }\n const value = yield yielded as FxYield<MergeError<L>, UnprovidedDeps<L>>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n ctx = Context.merge(ctx, result.value)\n } else {\n const gen = buildFx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n result = gen.next(service)\n continue\n }\n const value = yield yielded as FxYield<MergeError<L>, UnprovidedDeps<L>>\n result = gen.next(value)\n }\n ctx = Context.merge(ctx, result.value)\n }\n }\n return ctx as ContextType<MergeROut<L>>\n },\n } as AsyncFx<ContextType<MergeROut<L>>, MergeError<L>, UnprovidedDeps<L>>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as ContextType<MergeROut<L>>,\n _E: () => undefined as unknown as MergeError<L>,\n _R: () => undefined as unknown as UnprovidedDeps<L>,\n },\n *[Symbol.iterator](): Generator<FxYield<MergeError<L>, UnprovidedDeps<L>>, ContextType<MergeROut<L>>, unknown> {\n let ctx = Context.empty() as ContextType<unknown>\n for (const layer of layers) {\n const buildFx = layer.build(memoMap, scope)\n if (buildFx._tag !== \"SyncFx\") {\n throw new Error(\"Expected sync layer in sync context\")\n }\n const gen = buildFx[Symbol.iterator]()\n let result = gen.next()\n while (result.done !== true) {\n const yielded = result.value\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n result = gen.next(service)\n continue\n }\n const value = yield yielded as FxYield<MergeError<L>, UnprovidedDeps<L>>\n result = gen.next(value)\n }\n ctx = Context.merge(ctx, result.value)\n }\n return ctx as ContextType<MergeROut<L>>\n },\n } as SyncFx<ContextType<MergeROut<L>>, MergeError<L>, UnprovidedDeps<L>>\n },\n }\n}\n\n/**\n * Create a successful no-dependency layer from a plain service value.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(Layer.ok(Port, 3000))(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const ok = layerOk\n\n/**\n * Create a layer that always fails with an error.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide } from \"@nicolastoulemont/std\"\n *\n * const program = Fx.gen(function* () {\n * return 1\n * })\n * const exit = Fx.run(Provide.layer(Layer.err(\"missing-config\"))(program))\n * // => { _tag: \"Err\", error: \"missing-config\" }\n * ```\n */\nexport const err = layerErr\n\n/**\n * Create a layer from an effectful service builder.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const portLayer = Layer.fx(Port)(Fx.gen(function* () {\n * return 3000\n * }))\n * const program = Fx.gen(function* () {\n * return yield* Port\n * })\n * const exit = Fx.run(Provide.layer(portLayer)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const fx = layerFx\n\n/**\n * Create a scoped layer that registers resource finalizers.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Scope, Service } from \"@nicolastoulemont/std\"\n *\n * const Resource = Service.tag<{ readonly id: number }>(\"Resource\")\n * const ScopeTag = Service.tag<Scope.ScopeService>(\"@std/Scope\")\n * let finalized = 0\n *\n * const resourceLayer = Layer.scoped(Resource)(Fx.gen(function* () {\n * const scope = yield* ScopeTag\n * yield* scope.addFinalizer(() =>\n * Fx.gen(function* () {\n * finalized += 1\n * }),\n * )\n * return { id: 1 }\n * }))\n * const program = Fx.gen(function* () {\n * return (yield* Resource).id\n * })\n * const exit = Fx.run(Provide.layer(resourceLayer)(program))\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n */\nexport const scoped = layerScoped\n\n/**\n * Provide one layer to another, satisfying dependencies.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const Server = Service.tag<{ readonly port: number }>(\"Server\")\n * const portLayer = Layer.ok(Port, 3000)\n * const serverLayer = Layer.fx(Server)(Fx.gen(function* () {\n * const port = yield* Port\n * return { port }\n * }))\n * const provided = Layer.provide(portLayer)(serverLayer)\n * const program = Fx.gen(function* () {\n * return (yield* Server).port\n * })\n * const exit = Fx.run(Provide.layer(provided)(program))\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const provide = layerProvide\n\n/**\n * Merge multiple layers into a single composite layer.\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ readonly prefix: string }>(\"Logger\")\n * const Clock = Service.tag<{ readonly now: () => number }>(\"Clock\")\n * const merged = Layer.merge(\n * Layer.ok(Logger, { prefix: \"dev\" }),\n * Layer.ok(Clock, { now: () => 123 }),\n * )\n * const program = Fx.gen(function* () {\n * const logger = yield* Logger\n * const clock = yield* Clock\n * return `${logger.prefix}:${clock.now()}`\n * })\n * const exit = Fx.run(Provide.layer(merged)(program))\n * // => { _tag: \"Ok\", value: \"dev:123\" }\n * ```\n */\nexport const merge = layerMerge\n\n/* oxlint-enable no-unsafe-type-assertion */\n"],"mappings":"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"}
|
package/dist/provide/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as provide_d_exports } from "../index-
|
|
1
|
+
import { t as provide_d_exports } from "../index-D8gcYvR9.mjs";
|
|
2
2
|
export { provide_d_exports as Provide };
|
package/dist/provide/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"../provide
|
|
1
|
+
import{t as e}from"../provide-CuccogWx.mjs";export{e as Provide};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{t as e}from"./chunk-oQKkju2G.mjs";import{t}from"./fx.types-DyQVgTS8.mjs";import{i as n}from"./result-D3VY0qBG.mjs";import{n as r,t as i}from"./service-resolution-BefYr4nR.mjs";import{n as a,t as o}from"./fx.runtime-jQxh77s3.mjs";import{n as s}from"./layer-C5A-EM0h.mjs";import{t as c}from"./scope-gVt4PESc.mjs";var l=class{cache=new Map;getOrBuild(e,r,a){let o=this.cache.get(e);if(o?.context)return{_tag:`SyncFx`,[t]:{_A:()=>o.context,_E:()=>void 0,_R:()=>void 0},run:()=>n(o.context),*[Symbol.iterator](){return o.context}};if(o?.promise)return{_tag:`AsyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},run:async()=>n(await o.promise),async*[Symbol.asyncIterator](){return await o.promise}};this.cache.set(e,{building:!0});let s=e.build(this,r),c=this.cache;if(s._tag===`AsyncFx`){let r=(async()=>{let t=s[Symbol.asyncIterator](),n=await t.next();for(;n.done!==!0;){let e=n.value,r=i(e);if(r===void 0)throw e;let o=a._services.get(r.key);if(o===void 0)throw Error(`Service "${r.key}" not found during layer build`);n=await t.next(o)}let r=n.value;return c.set(e,{context:r}),r})();return this.cache.set(e,{promise:r}),{_tag:`AsyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},run:async()=>{try{return n(await r)}catch(e){return{ok:!1,error:e,*[Symbol.iterator](){throw yield e,Error(`Unreachable`)}}}},async*[Symbol.asyncIterator](){try{return await r}catch(e){throw yield e,Error(`Unreachable`,{cause:e})}}}}return{_tag:`SyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},run:()=>{let t=s[Symbol.iterator](),r=t.next();for(;r.done!==!0;){let e=r.value,n=i(e);if(n===void 0)return{ok:!1,error:e,*[Symbol.iterator](){throw yield e,Error(`Unreachable`)}};let o=a._services.get(n.key);if(o===void 0)throw Error(`Service "${n.key}" not found during layer build`);r=t.next(o)}let o=r.value;return c.set(e,{context:o}),n(o)},*[Symbol.iterator](){let t=s[Symbol.iterator](),n=t.next();for(;n.done!==!0;){let e=n.value,r=i(e);if(r===void 0)throw yield e,Error(`Unreachable`);let o=a._services.get(r.key);if(o===void 0)throw Error(`Service "${r.key}" not found during layer build`);n=t.next(o)}return c.set(e,{context:n.value}),n.value}}}clear(){this.cache.clear()}get size(){return this.cache.size}},u=e({context:()=>p,layer:()=>d,layers:()=>f,service:()=>m});function d(e){return i=>{let s=e.build(new l,c())._tag,u=()=>{let t=new l,n=c();return{scope:n,layerBuildFx:e.build(t,n)}};return s===`AsyncFx`||i._tag===`AsyncFx`?{_tag:`AsyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},async*[Symbol.asyncIterator](){let{scope:e,layerBuildFx:t}=u();try{let e;if(t._tag===`AsyncFx`){let n=t[Symbol.asyncIterator](),r=await n.next();for(;r.done!==!0;)yield r.value,r=await n.next(void 0);e=r.value}else{let n=t[Symbol.iterator](),r=n.next();for(;r.done!==!0;)yield r.value,r=n.next(void 0);e=r.value}if(i._tag===`AsyncFx`){let t=i[Symbol.asyncIterator](),n=await t.next();for(;n.done!==!0;){let i=n.value,a=r(e,i);if(a!==void 0){n=await t.next(a);continue}let o=yield i;n=await t.next(o)}return n.value}let n=i[Symbol.iterator](),a=n.next();for(;a.done!==!0;){let t=a.value,i=r(e,t);if(i!==void 0){a=n.next(i);continue}let o=yield t;a=n.next(o)}return a.value}finally{let t=e.close(n(void 0));t._tag===`AsyncFx`?await o(t):a(t)}}}:{_tag:`SyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},*[Symbol.iterator](){let{scope:e,layerBuildFx:t}=u();if(t._tag===`AsyncFx`)throw Error(`Provide.layer sync execution encountered an async layer build. Ensure async layers are treated as async at composition time.`);try{let e=t[Symbol.iterator](),n=e.next();for(;n.done!==!0;)yield n.value,n=e.next(void 0);let a=n.value,o=i[Symbol.iterator](),s=o.next();for(;s.done!==!0;){let e=s.value,t=r(a,e);if(t!==void 0){s=o.next(t);continue}let n=yield e;s=o.next(n)}return s.value}finally{a(e.close(n(void 0)))}}}}}function f(...e){return d(s(...e))}const p=e=>n=>n._tag===`AsyncFx`?{_tag:`AsyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},async*[Symbol.asyncIterator](){let t=n[Symbol.asyncIterator](),r=await t.next();for(;r.done!==!0;){let n=r.value,a=i(n);if(a===void 0){yield n,r=await t.next(void 0);continue}let o=e._services.get(a.key);if(o===void 0)throw Error(`Service "${a.key}" not found`);r=await t.next(o)}return r.value}}:{_tag:`SyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},*[Symbol.iterator](){let t=n[Symbol.iterator](),r=t.next();for(;r.done!==!0;){let n=r.value,a=i(n);if(a===void 0){yield n,r=t.next(void 0);continue}let o=e._services.get(a.key);if(o===void 0)throw Error(`Service "${a.key}" not found`);r=t.next(o)}return r.value}},m=(e,n)=>r=>r._tag===`AsyncFx`?{_tag:`AsyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},async*[Symbol.asyncIterator](){let t=r[Symbol.asyncIterator](),a=await t.next();for(;a.done!==!0;){let r=a.value;if(i(r)?.key===e.key)a=await t.next(n);else{let e=yield r;a=await t.next(e)}}return a.value}}:{_tag:`SyncFx`,[t]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},*[Symbol.iterator](){let t=r[Symbol.iterator](),a=t.next();for(;a.done!==!0;){let r=a.value;if(i(r)?.key===e.key)a=t.next(n);else{let e=yield r;a=t.next(e)}}return a.value}};export{u as t};
|
|
2
|
+
//# sourceMappingURL=provide-CuccogWx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provide-CuccogWx.mjs","names":["layer","service","layer","makeScope","fxGen","fxResult","service","layers","mergeLayers"],"sources":["../src/provide/memo-map.ts","../src/provide/provide.ts"],"sourcesContent":["import type { Context } from \"../context/context\"\nimport { FxTypeId } from \"../fx/fx.types\"\nimport type { RunnableFx, SyncFx, AsyncFx, FxYield } from \"../fx/fx.types\"\nimport type { Layer } from \"../layer/layer.types\"\nimport { ok } from \"../result/result\"\nimport type { ScopeService } from \"../scope/scope\"\nimport { asServiceRequest } from \"../service/service-resolution\"\n\n/* oxlint-disable no-unsafe-type-assertion, only-throw-error -- MemoMap bridges erased generic Fx channels and re-emits typed domain errors from generator boundaries. */\n\n// ============================================================================\n// MemoMap\n// ============================================================================\n\ntype AnyLayer = Layer<unknown, unknown, unknown>\n\n/**\n * MemoMap caches built layers so each layer is only built once.\n * Multiple dependents share the same service instance.\n *\n * This implements the \"service singleton\" pattern where a service\n * is instantiated once and shared across all consumers.\n *\n * @example\n * ```ts\n * // Database is built once, shared by DocumentService and TeamService\n * const AppLayer = Layer.merge(\n * ConfigLive,\n * LoggerLive,\n * DatabaseLive, // Built once\n * DocumentServiceLive, // Uses shared Database\n * TeamServiceLive, // Uses same Database instance\n * )\n * ```\n */\nexport class MemoMap {\n private cache = new Map<\n AnyLayer,\n {\n promise?: Promise<Context<unknown>>\n context?: Context<unknown>\n building?: boolean\n }\n >()\n\n /**\n * Get a cached context or build the layer if not cached.\n *\n * @param layer - The layer to get or build\n * @param scope - The scope for resource management\n * @param deps - Context containing the layer's dependencies\n * @returns A RunnableFx producing the layer's context\n */\n getOrBuild<ROut, E, RIn>(\n layer: Layer<ROut, E, RIn>,\n scope: ScopeService,\n deps: Context<RIn>,\n ): RunnableFx<Context<ROut>, E> {\n const cached = this.cache.get(layer as AnyLayer)\n\n // Already built - return cached context\n if (cached?.context) {\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => cached.context as Context<ROut>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as never,\n },\n run: () => ok(cached.context as Context<ROut>),\n // oxlint-disable-next-line require-yield\n *[Symbol.iterator](): Generator<FxYield<E, never>, Context<ROut>, unknown> {\n return cached.context as Context<ROut>\n },\n } as SyncFx<Context<ROut>, E>\n }\n\n // Building in progress (async) - wait for it\n if (cached?.promise) {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as Context<ROut>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as never,\n },\n run: async () => {\n const ctx = await cached.promise!\n return ok(ctx as Context<ROut>)\n },\n // oxlint-disable-next-line require-yield\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, never>, Context<ROut>, unknown> {\n const ctx = await cached.promise!\n return ctx as Context<ROut>\n },\n } as AsyncFx<Context<ROut>, E>\n }\n\n // Need to build - mark as building\n this.cache.set(layer as AnyLayer, { building: true })\n\n // Build the layer with provided dependencies\n const buildFx = layer.build(this, scope)\n const cacheRef = this.cache\n\n // Determine if async\n if (buildFx._tag === \"AsyncFx\") {\n // Create a promise for the build\n const buildPromise = (async () => {\n const gen = buildFx[Symbol.asyncIterator]()\n let result = await gen.next()\n\n // Resolve service requests from deps\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest === undefined) {\n // It's an error - rethrow\n throw yielded\n }\n const service = deps._services.get(serviceRequest.key)\n if (service === undefined) {\n throw new Error(`Service \"${serviceRequest.key}\" not found during layer build`)\n }\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(service)\n }\n\n const ctx = result.value\n cacheRef.set(layer as AnyLayer, { context: ctx })\n return ctx\n })()\n\n this.cache.set(layer as AnyLayer, { promise: buildPromise })\n\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as Context<ROut>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as never,\n },\n run: async () => {\n try {\n const ctx = await buildPromise\n return ok(ctx)\n } catch (e) {\n return {\n ok: false,\n error: e as E,\n *[Symbol.iterator]() {\n yield e as E\n throw new Error(\"Unreachable\")\n },\n }\n }\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, never>, Context<ROut>, unknown> {\n try {\n const ctx = await buildPromise\n return ctx\n } catch (e) {\n yield e as E\n throw new Error(\"Unreachable\", { cause: e })\n }\n },\n } as AsyncFx<Context<ROut>, E>\n }\n\n // Sync build\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as Context<ROut>,\n _E: () => undefined as unknown as E,\n _R: () => undefined as never,\n },\n run: () => {\n const gen = buildFx[Symbol.iterator]()\n let result = gen.next()\n\n // Resolve service requests from deps\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest === undefined) {\n // It's an error\n return {\n ok: false,\n error: yielded as E,\n *[Symbol.iterator]() {\n yield yielded as E\n throw new Error(\"Unreachable\")\n },\n }\n }\n const service = deps._services.get(serviceRequest.key)\n if (service === undefined) {\n throw new Error(`Service \"${serviceRequest.key}\" not found during layer build`)\n }\n result = gen.next(service)\n }\n\n const ctx = result.value\n cacheRef.set(layer as AnyLayer, { context: ctx })\n return ok(ctx)\n },\n *[Symbol.iterator](): Generator<FxYield<E, never>, Context<ROut>, unknown> {\n const gen = buildFx[Symbol.iterator]()\n let result = gen.next()\n\n // Resolve service requests from deps\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest === undefined) {\n // It's an error - yield it\n yield yielded as E\n throw new Error(\"Unreachable\")\n }\n const service = deps._services.get(serviceRequest.key)\n if (service === undefined) {\n throw new Error(`Service \"${serviceRequest.key}\" not found during layer build`)\n }\n result = gen.next(service)\n }\n\n cacheRef.set(layer as AnyLayer, { context: result.value })\n return result.value\n },\n } as SyncFx<Context<ROut>, E>\n }\n\n /**\n * Clear the cache.\n * Useful for testing.\n */\n clear(): void {\n this.cache.clear()\n }\n\n /**\n * Get the number of cached layers.\n */\n get size(): number {\n return this.cache.size\n }\n}\n\n/* oxlint-enable no-unsafe-type-assertion, only-throw-error */\n","import type { Context } from \"../context/context\"\nimport { runSync, runAsync } from \"../fx/fx.runtime\"\nimport { FxTypeId } from \"../fx/fx.types\"\nimport type { RunnableFx, SyncFx, AsyncFx, FxYield } from \"../fx/fx.types\"\nimport { merge as mergeLayers } from \"../layer/layer\"\nimport type { AllSync, Layer as LayerType, MergeError, MergeROut, UnprovidedDeps } from \"../layer/layer.types\"\nimport { ok } from \"../result/result\"\nimport { make as makeScope } from \"../scope/scope\"\nimport type { ServiceClass } from \"../service/service\"\nimport { asServiceRequest, resolveService } from \"../service/service-resolution\"\nimport { MemoMap } from \"./memo-map\"\n\n/* oxlint-disable no-unsafe-type-assertion -- layer/service re-thread generic Fx channels through runtime service injection points. */\n\n// ============================================================================\n// Provide Layer\n// ============================================================================\n\n/**\n * Extract the value type from an Fx.\n */\ntype FxValueType<F> = F extends RunnableFx<infer A, unknown, unknown> ? A : never\n\n/**\n * Extract the error type from an Fx.\n */\ntype FxErrorType<F> = F extends RunnableFx<unknown, infer E, unknown> ? E : never\n\n/**\n * Type for the result of provide based on layer sync and fx type.\n * Uses infer to extract A and E from the actual Fx type.\n * - Sync layer + SyncFx → SyncFx\n * - Sync layer + AsyncFx → AsyncFx\n * - Async layer + any fx → AsyncFx\n * - Unknown sync layer + any fx → RunnableFx (fallback)\n */\ntype ProvideResult<\n E2,\n LayerSync extends boolean,\n Fx extends RunnableFx<unknown, unknown, unknown>,\n> = LayerSync extends true\n ? Fx[\"_tag\"] extends \"SyncFx\"\n ? SyncFx<FxValueType<Fx>, FxErrorType<Fx> | E2>\n : AsyncFx<FxValueType<Fx>, FxErrorType<Fx> | E2>\n : LayerSync extends false\n ? AsyncFx<FxValueType<Fx>, FxErrorType<Fx> | E2>\n : RunnableFx<FxValueType<Fx>, FxErrorType<Fx> | E2>\n\ntype LayerList = [LayerType<unknown, unknown, unknown>, ...LayerType<unknown, unknown, unknown>[]]\ntype CompleteLayers<L extends LayerList> = UnprovidedDeps<L> extends never ? L : never\n\n/**\n * Provide a layer to an Fx computation, resolving all service requirements.\n * Creates a new scope for resource management.\n *\n * Type preservation:\n * - Sync layer + SyncFx → SyncFx\n * - Sync layer + AsyncFx → AsyncFx\n * - Async layer + any fx → AsyncFx\n * - Unknown sync layer + any fx → RunnableFx (fallback)\n *\n * @param layer - The layer providing services (must have no external requirements)\n * @returns A function that takes an Fx and returns an Fx with dependencies resolved\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const portLayer = Layer.ok(Port, 3000)\n * const readPort = Fx.gen(function* () {\n * return yield* Port\n * })\n * const provided = Provide.layer(portLayer)(readPort)\n * const exit = Fx.run(provided)\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport function layer<ROut, E2, LayerSync extends boolean>(\n layer: LayerType<ROut, E2, never, LayerSync>,\n): <Fx extends RunnableFx<unknown, unknown, ROut>>(fx: Fx) => ProvideResult<E2, LayerSync, Fx>\nexport function layer<ROut, E2>(layer: LayerType<ROut, E2>) {\n return <A, E, R extends ROut>(fx: RunnableFx<A, E, R>): RunnableFx<A, E | E2> => {\n // Build mode selection should remain stable for this wrapper,\n // while actual layer state (scope + memoization) must be per-execution.\n const layerBuildTag = layer.build(new MemoMap(), makeScope())._tag\n\n const createRunLayerState = (): {\n readonly scope: ReturnType<typeof makeScope>\n readonly layerBuildFx: ReturnType<typeof layer.build>\n } => {\n const memoMap = new MemoMap()\n const scope = makeScope()\n return {\n scope,\n layerBuildFx: layer.build(memoMap, scope),\n }\n }\n\n if (layerBuildTag === \"AsyncFx\" || fx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E | E2,\n _R: () => undefined as never,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E | E2, Exclude<R, ROut>>, A, unknown> {\n const { scope, layerBuildFx } = createRunLayerState()\n\n try {\n // Build the layer\n let ctx: Context<ROut>\n\n if (layerBuildFx._tag === \"AsyncFx\") {\n const gen = layerBuildFx[Symbol.asyncIterator]()\n let result = await gen.next()\n\n while (result.done !== true) {\n yield result.value as E2\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(undefined)\n }\n ctx = result.value\n } else {\n const gen = layerBuildFx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n yield result.value as E2\n result = gen.next(undefined)\n }\n ctx = result.value\n }\n\n // Run the fx with the context\n if (fx._tag === \"AsyncFx\") {\n const fxGen = fx[Symbol.asyncIterator]()\n let fxResult = await fxGen.next()\n\n while (fxResult.done !== true) {\n const yielded = fxResult.value\n\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n // oxlint-disable-next-line no-await-in-loop\n fxResult = await fxGen.next(service)\n continue\n }\n\n // Pass through (error or unsatisfied service)\n const value = yield yielded as FxYield<E, Exclude<R, ROut>>\n // oxlint-disable-next-line no-await-in-loop\n fxResult = await fxGen.next(value)\n }\n\n return fxResult.value\n }\n\n // Sync fx\n const fxGen = fx[Symbol.iterator]()\n let fxResult = fxGen.next()\n\n while (fxResult.done !== true) {\n const yielded = fxResult.value\n\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n fxResult = fxGen.next(service)\n continue\n }\n\n const value = yield yielded as FxYield<E, Exclude<R, ROut>>\n fxResult = fxGen.next(value)\n }\n\n return fxResult.value\n } finally {\n const closeResult = scope.close(ok(undefined))\n if (closeResult._tag === \"AsyncFx\") {\n await runAsync(closeResult)\n } else {\n runSync(closeResult)\n }\n }\n },\n } as AsyncFx<A, E | E2>\n }\n\n // Both sync\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E | E2,\n _R: () => undefined as never,\n },\n *[Symbol.iterator](): Generator<FxYield<E | E2, Exclude<R, ROut>>, A, unknown> {\n const { scope, layerBuildFx } = createRunLayerState()\n\n if (layerBuildFx._tag === \"AsyncFx\") {\n throw new Error(\n \"Provide.layer sync execution encountered an async layer build. Ensure async layers are treated as async at composition time.\",\n )\n }\n\n try {\n // Build the layer\n const layerGen = layerBuildFx[Symbol.iterator]()\n let layerResult = layerGen.next()\n\n while (layerResult.done !== true) {\n yield layerResult.value as E2\n layerResult = layerGen.next(undefined)\n }\n\n const ctx = layerResult.value\n\n // Run the fx with the context\n const fxGen = fx[Symbol.iterator]()\n let fxResult = fxGen.next()\n\n while (fxResult.done !== true) {\n const yielded = fxResult.value\n\n const service = resolveService(ctx, yielded)\n if (service !== undefined) {\n fxResult = fxGen.next(service)\n continue\n }\n\n const value = yield yielded as FxYield<E, Exclude<R, ROut>>\n fxResult = fxGen.next(value)\n }\n\n return fxResult.value\n } finally {\n const closeResult = scope.close(ok(undefined))\n // In sync-only branch, closeResult is always SyncFx\n runSync(closeResult as SyncFx<void>)\n }\n },\n } as SyncFx<A, E | E2>\n }\n}\n\n/**\n * Provide multiple layers to an Fx computation.\n * Equivalent to `Provide.layer(Layer.merge(...layers))`, but keeps the call site flatter.\n *\n * @param layers - Layers whose combined external requirements are fully satisfied\n * @returns A function that takes an Fx and returns an Fx with dependencies resolved\n *\n * @example\n * ```ts\n * import { Fx, Layer, Provide, Service, pipe } from \"@nicolastoulemont/std\"\n *\n * const Document = Service.tag<{ readonly getById: (id: string) => string }>(\"Document\")\n * const Team = Service.tag<{ readonly canRead: (id: string) => boolean }>(\"Team\")\n *\n * const program = Fx.gen(function* () {\n * const document = yield* Document\n * const team = yield* Team\n * return team.canRead(\"doc-1\") ? document.getById(\"doc-1\") : \"forbidden\"\n * })\n *\n * const exit = Fx.run(\n * pipe(\n * program,\n * Provide.layers(\n * Layer.ok(Document, { getById: (id) => id }),\n * Layer.ok(Team, { canRead: () => true }),\n * ),\n * ),\n * )\n * // => { _tag: \"Ok\", value: \"doc-1\" }\n * ```\n */\nexport function layers<L extends LayerList>(\n ...layers: CompleteLayers<L>\n): <Fx extends RunnableFx<unknown, unknown, MergeROut<L>>>(fx: Fx) => ProvideResult<MergeError<L>, AllSync<L>, Fx>\nexport function layers(...layers: LayerList) {\n return layer(mergeLayers(...layers))\n}\n\n// ============================================================================\n// Provide Context\n// ============================================================================\n\n/**\n * Provide a context directly to an Fx computation.\n *\n * @param ctx - The context containing services\n * @returns A function that takes an Fx and returns an Fx with dependencies resolved\n *\n * @example\n * ```ts\n * import { Context, Fx, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const ctx = Context.make(Port, 3000)\n * const readPort = Fx.gen(function* () {\n * return yield* Port\n * })\n * const provided = Provide.context(ctx)(readPort)\n * const exit = Fx.run(provided)\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const context =\n <R>(ctx: Context<R>) =>\n <A, E>(fx: RunnableFx<A, E, R>): RunnableFx<A, E> => {\n if (fx._tag === \"AsyncFx\") {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E,\n _R: () => undefined as never,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, never>, A, unknown> {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest === undefined) {\n yield yielded as E\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(undefined)\n continue\n }\n const service = ctx._services.get(serviceRequest.key)\n if (service === undefined) {\n throw new Error(`Service \"${serviceRequest.key}\" not found`)\n }\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(service)\n }\n\n return result.value\n },\n } as AsyncFx<A, E>\n }\n\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E,\n _R: () => undefined as never,\n },\n *[Symbol.iterator](): Generator<FxYield<E, never>, A, unknown> {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest === undefined) {\n yield yielded as E\n result = gen.next(undefined)\n continue\n }\n const service = ctx._services.get(serviceRequest.key)\n if (service === undefined) {\n throw new Error(`Service \"${serviceRequest.key}\" not found`)\n }\n result = gen.next(service)\n }\n\n return result.value\n },\n } as SyncFx<A, E>\n }\n\n// ============================================================================\n// Provide Service\n// ============================================================================\n\n/**\n * Provide a single service to an Fx computation.\n *\n * @param service - The service class (tag)\n * @param impl - The service implementation\n * @returns A function that takes an Fx and returns an Fx with the service provided\n *\n * @example\n * ```ts\n * import { Fx, Provide, Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const readPort = Fx.gen(function* () {\n * return yield* Port\n * })\n * const provided = Provide.service(Port, 3000)(readPort)\n * const exit = Fx.run(provided)\n * // => { _tag: \"Ok\", value: 3000 }\n * ```\n */\nexport const service =\n <S>(service: ServiceClass<S>, impl: S) =>\n <A, E, R>(fx: RunnableFx<A, E, R | S>): RunnableFx<A, E, Exclude<R, S>> => {\n if (fx._tag === \"AsyncFx\") {\n return {\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 Exclude<R, S>,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, Exclude<R, S>>, A, unknown> {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest?.key === service.key) {\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(impl)\n } else {\n const value = yield yielded as FxYield<E, Exclude<R, S>>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(value)\n }\n }\n\n return result.value\n },\n } as AsyncFx<A, E, Exclude<R, S>>\n }\n\n return {\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 Exclude<R, S>,\n },\n *[Symbol.iterator](): Generator<FxYield<E, Exclude<R, S>>, A, unknown> {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest?.key === service.key) {\n result = gen.next(impl)\n } else {\n const value = yield yielded as FxYield<E, Exclude<R, S>>\n result = gen.next(value)\n }\n }\n\n return result.value\n },\n } as SyncFx<A, E, Exclude<R, S>>\n }\n\n/* oxlint-enable no-unsafe-type-assertion */\n"],"mappings":"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"}
|
package/dist/queue/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as queue_d_exports } from "../index-
|
|
1
|
+
import { t as queue_d_exports } from "../index-CVmgBpDt.mjs";
|
|
2
2
|
export { queue_d_exports as Queue };
|
package/dist/queue/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e}from"../queue-
|
|
1
|
+
import{a as e}from"../queue-GYVrD39q.mjs";export{e as Queue};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./chunk-oQKkju2G.mjs";import{t}from"./data-
|
|
2
|
-
//# sourceMappingURL=queue-
|
|
1
|
+
import{t as e}from"./chunk-oQKkju2G.mjs";import{t}from"./data-DqACNS_g.mjs";var n=e({QueueAbortedError:()=>i,QueueClosedError:()=>r,QueueTaskAbortedError:()=>a,bounded:()=>h,is:()=>f,make:()=>m,unbounded:()=>g}),r=class extends t(`QueueClosedError`){},i=class extends t(`QueueAbortedError`){},a=class extends t(`QueueTaskAbortedError`){};const o=e=>{let t=e??`unbounded`;if(t===`unbounded`)return 1/0;if(!Number.isInteger(t)||t<=0)throw RangeError(`Queue concurrency must be a positive integer or "unbounded", received: ${String(t)}`);return t},s=e=>{if(e!==1/0&&(!Number.isInteger(e)||e<0))throw RangeError(`Queue maxSize must be an integer >= 0, received: ${String(e)}`)},c=e=>new a({reason:e.reason}),l=e=>new r({state:e}),u=e=>e instanceof Error?e:Error(`Queue rejection reason was not an Error`,{cause:e}),d=(e,t)=>{if(t===void 0)return e;if(t.aborted)return t;if(e.aborted)return e;let n=new AbortController,r=()=>{n.abort(e.reason),t.removeEventListener(`abort`,i)},i=()=>{n.abort(t.reason),e.removeEventListener(`abort`,r)};return e.addEventListener(`abort`,r,{once:!0}),t.addEventListener(`abort`,i,{once:!0}),n.signal.addEventListener(`abort`,()=>{e.removeEventListener(`abort`,r),t.removeEventListener(`abort`,i)},{once:!0}),n.signal},f=e=>typeof e==`object`&&!!e&&`_tag`in e&&e._tag===`Queue`,p=(e,t)=>{s(e);let n=o(t?.concurrency),r=`open`,a,f=t?.autoStart===!1,p=0,m=!1,h=[],g=[],_=new Set,v=new AbortController,y,b,x=()=>{if(!(p!==0||h.length>0)){for(let e of _)e();_.clear(),(r===`draining`||r===`aborted`)&&(r=`closed`,y?.(),y=void 0)}},S=e=>{if(g.length===0)return;let t=g.splice(0);for(let n of t)n.reject(e)},C=()=>{if(!(!Number.isFinite(e)||g.length===0))for(;g.length>0&&h.length<e&&r===`open`;){let e=g.shift();e!==void 0&&e.resolve()}},w=e=>{if(h.length===0)return;let t=new i({reason:e}),n=h.splice(0);for(let e of n)e.reject(t)},T=t=>!Number.isFinite(e)||h.length<e?Promise.resolve():new Promise((e,n)=>{let r={resolve:()=>{t!==void 0&&i!==void 0&&t.removeEventListener(`abort`,i),e()},reject:e=>{t!==void 0&&i!==void 0&&t.removeEventListener(`abort`,i),n(e)},signal:t},i=t===void 0?void 0:()=>{let e=g.indexOf(r);e!==-1&&g.splice(e,1),n(c(t))};if(t!==void 0&&t.aborted){n(c(t));return}t!==void 0&&i!==void 0&&t.addEventListener(`abort`,i,{once:!0}),g.push(r)}),E=()=>{(r===`draining`||r===`aborted`)&&p===0&&h.length===0&&x()},D=e=>{p+=1;let t=d(v.signal,e.signal),n;if(t.aborted)n=Promise.reject(c(t));else try{n=Promise.resolve(e.task({signal:t}))}catch(e){n=Promise.reject(u(e))}n.then(t=>{e.resolve(t)},t=>{e.reject(u(t))}).finally(()=>{--p,C(),O(),x()})},O=()=>{if(!m){m=!0;try{if(r===`aborted`){E();return}for(;!f&&p<n&&h.length>0;){let e=h.shift();if(e===void 0)break;C(),D(e)}E()}finally{m=!1}}},k=()=>l(a===void 0?r===`aborted`?`aborted`:r===`draining`?`draining`:r===`closed`?a??`draining`:`draining`:a);return{_tag:`Queue`,get pending(){return p},get size(){return h.length},get isPaused(){return f},get isShutdown(){return r!==`open`},enqueue(t,n){let i=n?.signal;if(i!==void 0&&i.aborted)return Promise.reject(c(i));if(r!==`open`)return Promise.reject(k());let a=()=>new Promise((e,n)=>{let r={task:t,resolve:e,reject:n,signal:i};h.push(r),O()});return!Number.isFinite(e)||h.length<e?a():T(i).then(()=>{if(i!==void 0&&i.aborted)throw c(i);if(r!==`open`)throw k();return a()})},pause(){f=!0},resume(){f&&(f=!1,O())},awaitIdle(){return p===0&&h.length===0?Promise.resolve():new Promise(e=>{_.add(e)})},shutdown(e){let t=e?.mode??`drain`;return b!==void 0&&(r===`draining`||r===`aborted`||r===`closed`)?(t===`abort`&&a!==`aborted`&&(a=`aborted`,r=`aborted`,v.abort(e?.reason),w(e?.reason),S(l(`aborted`)),E()),b):(b??=new Promise(e=>{y=e}),t===`abort`?(a=`aborted`,r=`aborted`,f=!1,v.abort(e?.reason),w(e?.reason),S(l(`aborted`))):(a=`draining`,r===`open`&&(r=`draining`),f=!1,S(l(`draining`))),O(),x(),b)}}},m=e=>p(1/0,e),h=(e,t)=>p(e,t),g=e=>p(1/0,e);export{n as a,m as i,r as n,a as r,i as t};
|
|
2
|
+
//# sourceMappingURL=queue-GYVrD39q.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue-apiEOlRD.mjs","names":["Data.TaggedError","options"],"sources":["../src/queue/queue.ts"],"sourcesContent":["/**\n * Promise-based work queue with bounded/unbounded capacity and shutdown modes.\n *\n * **Mental model**\n * - A queue coordinates concurrent task execution with backpressure.\n * - Enqueue returns a promise for each task result.\n *\n * **Common tasks**\n * - Create queues via `Queue.make`, `Queue.bounded`, or `Queue.unbounded`.\n * - Pause/resume processing and await idle state.\n * - Shutdown with drain or abort semantics.\n *\n * **Gotchas**\n * - Bounded queues can block enqueue when capacity is reached.\n * - Aborted queues reject queued and future tasks.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.make()\n * const pending = queue.pending\n * // => 0\n * ```\n *\n * @module\n */\nimport { Data } from \"../data\"\nimport type {\n Concurrency,\n Queue as QueueType,\n QueueBoundedOptions,\n QueueOptions,\n QueueShutdownMode,\n QueueShutdownOptions,\n QueueTask,\n} from \"./queue.types\"\n\n/* oxlint-disable max-classes-per-file -- Queue exports dedicated error classes for precise instanceof checks at call sites. */\n/**\n * Error raised when enqueueing into a non-open queue.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const error = new Queue.QueueClosedError({ state: \"draining\" })\n * // => { _tag: \"QueueClosedError\", state: \"draining\" }\n * ```\n */\nexport class QueueClosedError extends Data.TaggedError(\"QueueClosedError\")<{ state: \"draining\" | \"aborted\" }> {}\n/**\n * Error raised when queue processing is aborted.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const error = new Queue.QueueAbortedError({ reason: \"manual\" })\n * // => { _tag: \"QueueAbortedError\", reason: \"manual\" }\n * ```\n */\nexport class QueueAbortedError extends Data.TaggedError(\"QueueAbortedError\")<{ reason?: unknown }> {}\n/**\n * Error raised when a specific task is aborted.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const error = new Queue.QueueTaskAbortedError({ reason: \"signal\" })\n * // => { _tag: \"QueueTaskAbortedError\", reason: \"signal\" }\n * ```\n */\nexport class QueueTaskAbortedError extends Data.TaggedError(\"QueueTaskAbortedError\")<{ reason?: unknown }> {}\n\ntype QueueState = \"open\" | \"draining\" | \"aborted\" | \"closed\"\n\ntype TaskEntry<A> = {\n readonly task: QueueTask<A>\n resolve(value: A | PromiseLike<A>): void\n reject(reason: unknown): void\n readonly signal: AbortSignal | undefined\n}\n\ntype CapacityWaiter = {\n resolve(): void\n reject(reason: Error): void\n readonly signal: AbortSignal | undefined\n}\n\nconst asConcurrencyLimit = (concurrency: Concurrency | undefined): number => {\n const resolved = concurrency ?? \"unbounded\"\n if (resolved === \"unbounded\") {\n return Number.POSITIVE_INFINITY\n }\n\n if (!Number.isInteger(resolved) || resolved <= 0) {\n throw new RangeError(`Queue concurrency must be a positive integer or \"unbounded\", received: ${String(resolved)}`)\n }\n\n return resolved\n}\n\nconst assertMaxSize = (maxSize: number) => {\n if (maxSize === Number.POSITIVE_INFINITY) {\n return\n }\n\n if (!Number.isInteger(maxSize) || maxSize < 0) {\n throw new RangeError(`Queue maxSize must be an integer >= 0, received: ${String(maxSize)}`)\n }\n}\n\nconst queueTaskAbortedError = (signal: AbortSignal): QueueTaskAbortedError =>\n new QueueTaskAbortedError({ reason: signal.reason })\n\nconst queueClosedError = (state: \"draining\" | \"aborted\"): QueueClosedError => new QueueClosedError({ state })\n\nconst toError = (reason: unknown): Error =>\n reason instanceof Error ? reason : new Error(\"Queue rejection reason was not an Error\", { cause: reason })\n\nconst composeSignals = (queueSignal: AbortSignal, taskSignal: AbortSignal | undefined): AbortSignal => {\n if (taskSignal === undefined) {\n return queueSignal\n }\n\n if (taskSignal.aborted) {\n return taskSignal\n }\n\n if (queueSignal.aborted) {\n return queueSignal\n }\n\n const composite = new AbortController()\n\n const onQueueAbort = () => {\n composite.abort(queueSignal.reason)\n taskSignal.removeEventListener(\"abort\", onTaskAbort)\n }\n\n const onTaskAbort = () => {\n composite.abort(taskSignal.reason)\n queueSignal.removeEventListener(\"abort\", onQueueAbort)\n }\n\n queueSignal.addEventListener(\"abort\", onQueueAbort, { once: true })\n taskSignal.addEventListener(\"abort\", onTaskAbort, { once: true })\n\n composite.signal.addEventListener(\n \"abort\",\n () => {\n queueSignal.removeEventListener(\"abort\", onQueueAbort)\n taskSignal.removeEventListener(\"abort\", onTaskAbort)\n },\n { once: true },\n )\n\n return composite.signal\n}\n\n/**\n * Check if a value is a `Queue`.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.make()\n * const isQueue = Queue.is(queue)\n * // => true\n * ```\n */\nexport const is = (value: unknown): value is QueueType =>\n typeof value === \"object\" && value !== null && \"_tag\" in value && value._tag === \"Queue\"\n\nconst createQueue = (maxSize: number, options?: QueueOptions): QueueType => {\n assertMaxSize(maxSize)\n\n const concurrencyLimit = asConcurrencyLimit(options?.concurrency)\n let state: QueueState = \"open\"\n let closeState: \"draining\" | \"aborted\" | undefined\n let paused = options?.autoStart === false\n let pending = 0\n let draining = false\n\n const queuedTasks: TaskEntry<unknown>[] = []\n const capacityWaiters: CapacityWaiter[] = []\n const idleWaiters = new Set<() => void>()\n\n const queueAbortController = new AbortController()\n\n let shutdownResolver: (() => void) | undefined\n let shutdownPromise: Promise<void> | undefined\n\n const resolveIdleIfNeeded = () => {\n if (pending !== 0 || queuedTasks.length > 0) {\n return\n }\n\n for (const resolve of idleWaiters) {\n resolve()\n }\n idleWaiters.clear()\n\n if (state === \"draining\" || state === \"aborted\") {\n state = \"closed\"\n shutdownResolver?.()\n shutdownResolver = undefined\n }\n }\n\n const rejectCapacityWaiters = (reason: Error) => {\n if (capacityWaiters.length === 0) {\n return\n }\n\n const waiters = capacityWaiters.splice(0)\n for (const waiter of waiters) {\n waiter.reject(reason)\n }\n }\n\n const releaseCapacityWaiters = () => {\n if (!Number.isFinite(maxSize) || capacityWaiters.length === 0) {\n return\n }\n\n while (capacityWaiters.length > 0 && queuedTasks.length < maxSize && state === \"open\") {\n const waiter = capacityWaiters.shift()\n if (waiter !== undefined) {\n waiter.resolve()\n }\n }\n }\n\n const applyAbortToQueuedTasks = (reason: unknown) => {\n if (queuedTasks.length === 0) {\n return\n }\n\n const error = new QueueAbortedError({ reason })\n const tasks = queuedTasks.splice(0)\n for (const entry of tasks) {\n entry.reject(error)\n }\n }\n\n const waitForCapacity = (signal: AbortSignal | undefined): Promise<void> => {\n if (!Number.isFinite(maxSize)) {\n return Promise.resolve()\n }\n\n if (queuedTasks.length < maxSize) {\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve, reject) => {\n const waiter: CapacityWaiter = {\n resolve: () => {\n if (signal !== undefined && onAbort !== undefined) {\n signal.removeEventListener(\"abort\", onAbort)\n }\n resolve()\n },\n reject: (error) => {\n if (signal !== undefined && onAbort !== undefined) {\n signal.removeEventListener(\"abort\", onAbort)\n }\n reject(error)\n },\n signal,\n }\n\n const onAbort =\n signal === undefined\n ? undefined\n : () => {\n const index = capacityWaiters.indexOf(waiter)\n if (index !== -1) {\n capacityWaiters.splice(index, 1)\n }\n reject(queueTaskAbortedError(signal))\n }\n\n if (signal !== undefined && signal.aborted) {\n reject(queueTaskAbortedError(signal))\n return\n }\n\n if (signal !== undefined && onAbort !== undefined) {\n signal.addEventListener(\"abort\", onAbort, { once: true })\n }\n\n capacityWaiters.push(waiter)\n })\n }\n\n const closeIfNeeded = () => {\n if ((state === \"draining\" || state === \"aborted\") && pending === 0 && queuedTasks.length === 0) {\n resolveIdleIfNeeded()\n }\n }\n\n const runTask = <A>(entry: TaskEntry<A>) => {\n pending += 1\n\n const taskSignal = composeSignals(queueAbortController.signal, entry.signal)\n\n let taskResult: Promise<A>\n if (taskSignal.aborted) {\n taskResult = Promise.reject(queueTaskAbortedError(taskSignal))\n } else {\n try {\n taskResult = Promise.resolve(entry.task({ signal: taskSignal }))\n } catch (error) {\n taskResult = Promise.reject(toError(error))\n }\n }\n\n void taskResult\n .then(\n (value) => {\n entry.resolve(value)\n return undefined\n },\n (error: unknown) => {\n entry.reject(toError(error))\n return undefined\n },\n )\n .finally(() => {\n pending -= 1\n releaseCapacityWaiters()\n drainQueue()\n resolveIdleIfNeeded()\n })\n }\n\n const drainQueue = () => {\n if (draining) {\n return\n }\n\n draining = true\n try {\n if (state === \"aborted\") {\n closeIfNeeded()\n return\n }\n\n while (!paused && pending < concurrencyLimit && queuedTasks.length > 0) {\n const entry = queuedTasks.shift()\n if (entry === undefined) {\n break\n }\n releaseCapacityWaiters()\n runTask(entry)\n }\n\n closeIfNeeded()\n } finally {\n draining = false\n }\n }\n\n const enqueueErrorForState = (): QueueClosedError => {\n if (closeState !== undefined) {\n return queueClosedError(closeState)\n }\n\n if (state === \"aborted\") {\n return queueClosedError(\"aborted\")\n }\n\n if (state === \"draining\") {\n return queueClosedError(\"draining\")\n }\n\n if (state === \"closed\") {\n return queueClosedError(closeState ?? \"draining\")\n }\n\n return queueClosedError(\"draining\")\n }\n\n const queue: QueueType = {\n _tag: \"Queue\",\n\n get pending(): number {\n return pending\n },\n\n get size(): number {\n return queuedTasks.length\n },\n\n get isPaused(): boolean {\n return paused\n },\n\n get isShutdown(): boolean {\n return state !== \"open\"\n },\n\n enqueue<A>(task: QueueTask<A>, options?: { readonly signal?: AbortSignal }): Promise<A> {\n const signal = options?.signal\n\n if (signal !== undefined && signal.aborted) {\n return Promise.reject(queueTaskAbortedError(signal))\n }\n\n if (state !== \"open\") {\n return Promise.reject(enqueueErrorForState())\n }\n\n const enqueueTask = () =>\n new Promise<A>((resolve, reject) => {\n const entry: TaskEntry<A> = {\n task,\n resolve,\n reject,\n signal,\n }\n\n queuedTasks.push(entry)\n drainQueue()\n })\n\n if (!Number.isFinite(maxSize) || queuedTasks.length < maxSize) {\n return enqueueTask()\n }\n\n return waitForCapacity(signal).then(() => {\n if (signal !== undefined && signal.aborted) {\n throw queueTaskAbortedError(signal)\n }\n\n if (state !== \"open\") {\n throw enqueueErrorForState()\n }\n\n return enqueueTask()\n })\n },\n\n pause(): void {\n paused = true\n },\n\n resume(): void {\n if (!paused) {\n return\n }\n\n paused = false\n drainQueue()\n },\n\n awaitIdle(): Promise<void> {\n if (pending === 0 && queuedTasks.length === 0) {\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n idleWaiters.add(resolve)\n })\n },\n\n shutdown(options?: QueueShutdownOptions): Promise<void> {\n const mode: QueueShutdownMode = options?.mode ?? \"drain\"\n\n if (shutdownPromise !== undefined && (state === \"draining\" || state === \"aborted\" || state === \"closed\")) {\n if (mode === \"abort\" && closeState !== \"aborted\") {\n closeState = \"aborted\"\n state = \"aborted\"\n queueAbortController.abort(options?.reason)\n applyAbortToQueuedTasks(options?.reason)\n rejectCapacityWaiters(queueClosedError(\"aborted\"))\n closeIfNeeded()\n }\n\n return shutdownPromise\n }\n\n shutdownPromise =\n shutdownPromise ??\n new Promise<void>((resolve) => {\n shutdownResolver = resolve\n })\n\n if (mode === \"abort\") {\n closeState = \"aborted\"\n state = \"aborted\"\n paused = false\n queueAbortController.abort(options?.reason)\n applyAbortToQueuedTasks(options?.reason)\n rejectCapacityWaiters(queueClosedError(\"aborted\"))\n } else {\n closeState = \"draining\"\n if (state === \"open\") {\n state = \"draining\"\n }\n paused = false\n rejectCapacityWaiters(queueClosedError(\"draining\"))\n }\n\n drainQueue()\n resolveIdleIfNeeded()\n\n return shutdownPromise\n },\n }\n\n return queue\n}\n\n/**\n * Create a queue with default unbounded capacity.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.make()\n * const pending = queue.pending\n * // => 0\n * ```\n */\nexport const make = (options?: QueueOptions): QueueType => createQueue(Number.POSITIVE_INFINITY, options)\n\n/**\n * Create a queue with bounded capacity.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.bounded(2)\n * const size = queue.size\n * // => 0\n * ```\n */\nexport const bounded = (maxSize: number, options?: QueueBoundedOptions): QueueType => createQueue(maxSize, options)\n\n/**\n * Create a queue with explicit unbounded capacity.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.unbounded()\n * const paused = queue.isPaused\n * // => false\n * ```\n */\nexport const unbounded = (options?: QueueOptions): QueueType => createQueue(Number.POSITIVE_INFINITY, options)\n\n/* oxlint-enable max-classes-per-file */\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"queue-GYVrD39q.mjs","names":["Data.TaggedError","options"],"sources":["../src/queue/queue.ts"],"sourcesContent":["/**\n * Promise-based work queue with bounded/unbounded capacity and shutdown modes.\n *\n * **Mental model**\n * - A queue coordinates concurrent task execution with backpressure.\n * - Enqueue returns a promise for each task result.\n *\n * **Common tasks**\n * - Create queues via `Queue.make`, `Queue.bounded`, or `Queue.unbounded`.\n * - Pause/resume processing and await idle state.\n * - Shutdown with drain or abort semantics.\n *\n * **Gotchas**\n * - Bounded queues can block enqueue when capacity is reached.\n * - Aborted queues reject queued and future tasks.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.make()\n * const pending = queue.pending\n * // => 0\n * ```\n *\n * @module\n */\nimport { Data } from \"../data\"\nimport type {\n Concurrency,\n Queue as QueueType,\n QueueBoundedOptions,\n QueueOptions,\n QueueShutdownMode,\n QueueShutdownOptions,\n QueueTask,\n} from \"./queue.types\"\n\n/* oxlint-disable max-classes-per-file -- Queue exports dedicated error classes for precise instanceof checks at call sites. */\n/**\n * Error raised when enqueueing into a non-open queue.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const error = new Queue.QueueClosedError({ state: \"draining\" })\n * // => { _tag: \"QueueClosedError\", state: \"draining\" }\n * ```\n */\nexport class QueueClosedError extends Data.TaggedError(\"QueueClosedError\")<{ state: \"draining\" | \"aborted\" }> {}\n/**\n * Error raised when queue processing is aborted.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const error = new Queue.QueueAbortedError({ reason: \"manual\" })\n * // => { _tag: \"QueueAbortedError\", reason: \"manual\" }\n * ```\n */\nexport class QueueAbortedError extends Data.TaggedError(\"QueueAbortedError\")<{ reason?: unknown }> {}\n/**\n * Error raised when a specific task is aborted.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const error = new Queue.QueueTaskAbortedError({ reason: \"signal\" })\n * // => { _tag: \"QueueTaskAbortedError\", reason: \"signal\" }\n * ```\n */\nexport class QueueTaskAbortedError extends Data.TaggedError(\"QueueTaskAbortedError\")<{ reason?: unknown }> {}\n\ntype QueueState = \"open\" | \"draining\" | \"aborted\" | \"closed\"\n\ntype TaskEntry<A> = {\n readonly task: QueueTask<A>\n resolve(value: A | PromiseLike<A>): void\n reject(reason: unknown): void\n readonly signal: AbortSignal | undefined\n}\n\ntype CapacityWaiter = {\n resolve(): void\n reject(reason: Error): void\n readonly signal: AbortSignal | undefined\n}\n\nconst asConcurrencyLimit = (concurrency: Concurrency | undefined): number => {\n const resolved = concurrency ?? \"unbounded\"\n if (resolved === \"unbounded\") {\n return Number.POSITIVE_INFINITY\n }\n\n if (!Number.isInteger(resolved) || resolved <= 0) {\n throw new RangeError(`Queue concurrency must be a positive integer or \"unbounded\", received: ${String(resolved)}`)\n }\n\n return resolved\n}\n\nconst assertMaxSize = (maxSize: number) => {\n if (maxSize === Number.POSITIVE_INFINITY) {\n return\n }\n\n if (!Number.isInteger(maxSize) || maxSize < 0) {\n throw new RangeError(`Queue maxSize must be an integer >= 0, received: ${String(maxSize)}`)\n }\n}\n\nconst queueTaskAbortedError = (signal: AbortSignal): QueueTaskAbortedError =>\n new QueueTaskAbortedError({ reason: signal.reason })\n\nconst queueClosedError = (state: \"draining\" | \"aborted\"): QueueClosedError => new QueueClosedError({ state })\n\nconst toError = (reason: unknown): Error =>\n reason instanceof Error ? reason : new Error(\"Queue rejection reason was not an Error\", { cause: reason })\n\nconst composeSignals = (queueSignal: AbortSignal, taskSignal: AbortSignal | undefined): AbortSignal => {\n if (taskSignal === undefined) {\n return queueSignal\n }\n\n if (taskSignal.aborted) {\n return taskSignal\n }\n\n if (queueSignal.aborted) {\n return queueSignal\n }\n\n const composite = new AbortController()\n\n const onQueueAbort = () => {\n composite.abort(queueSignal.reason)\n taskSignal.removeEventListener(\"abort\", onTaskAbort)\n }\n\n const onTaskAbort = () => {\n composite.abort(taskSignal.reason)\n queueSignal.removeEventListener(\"abort\", onQueueAbort)\n }\n\n queueSignal.addEventListener(\"abort\", onQueueAbort, { once: true })\n taskSignal.addEventListener(\"abort\", onTaskAbort, { once: true })\n\n composite.signal.addEventListener(\n \"abort\",\n () => {\n queueSignal.removeEventListener(\"abort\", onQueueAbort)\n taskSignal.removeEventListener(\"abort\", onTaskAbort)\n },\n { once: true },\n )\n\n return composite.signal\n}\n\n/**\n * Check if a value is a `Queue`.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.make()\n * const isQueue = Queue.is(queue)\n * // => true\n * ```\n */\nexport const is = (value: unknown): value is QueueType =>\n typeof value === \"object\" && value !== null && \"_tag\" in value && value._tag === \"Queue\"\n\nconst createQueue = (maxSize: number, options?: QueueOptions): QueueType => {\n assertMaxSize(maxSize)\n\n const concurrencyLimit = asConcurrencyLimit(options?.concurrency)\n let state: QueueState = \"open\"\n let closeState: \"draining\" | \"aborted\" | undefined\n let paused = options?.autoStart === false\n let pending = 0\n let draining = false\n\n const queuedTasks: TaskEntry<unknown>[] = []\n const capacityWaiters: CapacityWaiter[] = []\n const idleWaiters = new Set<() => void>()\n\n const queueAbortController = new AbortController()\n\n let shutdownResolver: (() => void) | undefined\n let shutdownPromise: Promise<void> | undefined\n\n const resolveIdleIfNeeded = () => {\n if (pending !== 0 || queuedTasks.length > 0) {\n return\n }\n\n for (const resolve of idleWaiters) {\n resolve()\n }\n idleWaiters.clear()\n\n if (state === \"draining\" || state === \"aborted\") {\n state = \"closed\"\n shutdownResolver?.()\n shutdownResolver = undefined\n }\n }\n\n const rejectCapacityWaiters = (reason: Error) => {\n if (capacityWaiters.length === 0) {\n return\n }\n\n const waiters = capacityWaiters.splice(0)\n for (const waiter of waiters) {\n waiter.reject(reason)\n }\n }\n\n const releaseCapacityWaiters = () => {\n if (!Number.isFinite(maxSize) || capacityWaiters.length === 0) {\n return\n }\n\n while (capacityWaiters.length > 0 && queuedTasks.length < maxSize && state === \"open\") {\n const waiter = capacityWaiters.shift()\n if (waiter !== undefined) {\n waiter.resolve()\n }\n }\n }\n\n const applyAbortToQueuedTasks = (reason: unknown) => {\n if (queuedTasks.length === 0) {\n return\n }\n\n const error = new QueueAbortedError({ reason })\n const tasks = queuedTasks.splice(0)\n for (const entry of tasks) {\n entry.reject(error)\n }\n }\n\n const waitForCapacity = (signal: AbortSignal | undefined): Promise<void> => {\n if (!Number.isFinite(maxSize)) {\n return Promise.resolve()\n }\n\n if (queuedTasks.length < maxSize) {\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve, reject) => {\n const waiter: CapacityWaiter = {\n resolve: () => {\n if (signal !== undefined && onAbort !== undefined) {\n signal.removeEventListener(\"abort\", onAbort)\n }\n resolve()\n },\n reject: (error) => {\n if (signal !== undefined && onAbort !== undefined) {\n signal.removeEventListener(\"abort\", onAbort)\n }\n reject(error)\n },\n signal,\n }\n\n const onAbort =\n signal === undefined\n ? undefined\n : () => {\n const index = capacityWaiters.indexOf(waiter)\n if (index !== -1) {\n capacityWaiters.splice(index, 1)\n }\n reject(queueTaskAbortedError(signal))\n }\n\n if (signal !== undefined && signal.aborted) {\n reject(queueTaskAbortedError(signal))\n return\n }\n\n if (signal !== undefined && onAbort !== undefined) {\n signal.addEventListener(\"abort\", onAbort, { once: true })\n }\n\n capacityWaiters.push(waiter)\n })\n }\n\n const closeIfNeeded = () => {\n if ((state === \"draining\" || state === \"aborted\") && pending === 0 && queuedTasks.length === 0) {\n resolveIdleIfNeeded()\n }\n }\n\n const runTask = <A>(entry: TaskEntry<A>) => {\n pending += 1\n\n const taskSignal = composeSignals(queueAbortController.signal, entry.signal)\n\n let taskResult: Promise<A>\n if (taskSignal.aborted) {\n taskResult = Promise.reject(queueTaskAbortedError(taskSignal))\n } else {\n try {\n taskResult = Promise.resolve(entry.task({ signal: taskSignal }))\n } catch (error) {\n taskResult = Promise.reject(toError(error))\n }\n }\n\n void taskResult\n .then(\n (value) => {\n entry.resolve(value)\n return undefined\n },\n (error: unknown) => {\n entry.reject(toError(error))\n return undefined\n },\n )\n .finally(() => {\n pending -= 1\n releaseCapacityWaiters()\n drainQueue()\n resolveIdleIfNeeded()\n })\n }\n\n const drainQueue = () => {\n if (draining) {\n return\n }\n\n draining = true\n try {\n if (state === \"aborted\") {\n closeIfNeeded()\n return\n }\n\n while (!paused && pending < concurrencyLimit && queuedTasks.length > 0) {\n const entry = queuedTasks.shift()\n if (entry === undefined) {\n break\n }\n releaseCapacityWaiters()\n runTask(entry)\n }\n\n closeIfNeeded()\n } finally {\n draining = false\n }\n }\n\n const enqueueErrorForState = (): QueueClosedError => {\n if (closeState !== undefined) {\n return queueClosedError(closeState)\n }\n\n if (state === \"aborted\") {\n return queueClosedError(\"aborted\")\n }\n\n if (state === \"draining\") {\n return queueClosedError(\"draining\")\n }\n\n if (state === \"closed\") {\n return queueClosedError(closeState ?? \"draining\")\n }\n\n return queueClosedError(\"draining\")\n }\n\n const queue: QueueType = {\n _tag: \"Queue\",\n\n get pending(): number {\n return pending\n },\n\n get size(): number {\n return queuedTasks.length\n },\n\n get isPaused(): boolean {\n return paused\n },\n\n get isShutdown(): boolean {\n return state !== \"open\"\n },\n\n enqueue<A>(task: QueueTask<A>, options?: { readonly signal?: AbortSignal }): Promise<A> {\n const signal = options?.signal\n\n if (signal !== undefined && signal.aborted) {\n return Promise.reject(queueTaskAbortedError(signal))\n }\n\n if (state !== \"open\") {\n return Promise.reject(enqueueErrorForState())\n }\n\n const enqueueTask = () =>\n new Promise<A>((resolve, reject) => {\n const entry: TaskEntry<A> = {\n task,\n resolve,\n reject,\n signal,\n }\n\n queuedTasks.push(entry)\n drainQueue()\n })\n\n if (!Number.isFinite(maxSize) || queuedTasks.length < maxSize) {\n return enqueueTask()\n }\n\n return waitForCapacity(signal).then(() => {\n if (signal !== undefined && signal.aborted) {\n throw queueTaskAbortedError(signal)\n }\n\n if (state !== \"open\") {\n throw enqueueErrorForState()\n }\n\n return enqueueTask()\n })\n },\n\n pause(): void {\n paused = true\n },\n\n resume(): void {\n if (!paused) {\n return\n }\n\n paused = false\n drainQueue()\n },\n\n awaitIdle(): Promise<void> {\n if (pending === 0 && queuedTasks.length === 0) {\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n idleWaiters.add(resolve)\n })\n },\n\n shutdown(options?: QueueShutdownOptions): Promise<void> {\n const mode: QueueShutdownMode = options?.mode ?? \"drain\"\n\n if (shutdownPromise !== undefined && (state === \"draining\" || state === \"aborted\" || state === \"closed\")) {\n if (mode === \"abort\" && closeState !== \"aborted\") {\n closeState = \"aborted\"\n state = \"aborted\"\n queueAbortController.abort(options?.reason)\n applyAbortToQueuedTasks(options?.reason)\n rejectCapacityWaiters(queueClosedError(\"aborted\"))\n closeIfNeeded()\n }\n\n return shutdownPromise\n }\n\n shutdownPromise =\n shutdownPromise ??\n new Promise<void>((resolve) => {\n shutdownResolver = resolve\n })\n\n if (mode === \"abort\") {\n closeState = \"aborted\"\n state = \"aborted\"\n paused = false\n queueAbortController.abort(options?.reason)\n applyAbortToQueuedTasks(options?.reason)\n rejectCapacityWaiters(queueClosedError(\"aborted\"))\n } else {\n closeState = \"draining\"\n if (state === \"open\") {\n state = \"draining\"\n }\n paused = false\n rejectCapacityWaiters(queueClosedError(\"draining\"))\n }\n\n drainQueue()\n resolveIdleIfNeeded()\n\n return shutdownPromise\n },\n }\n\n return queue\n}\n\n/**\n * Create a queue with default unbounded capacity.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.make()\n * const pending = queue.pending\n * // => 0\n * ```\n */\nexport const make = (options?: QueueOptions): QueueType => createQueue(Number.POSITIVE_INFINITY, options)\n\n/**\n * Create a queue with bounded capacity.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.bounded(2)\n * const size = queue.size\n * // => 0\n * ```\n */\nexport const bounded = (maxSize: number, options?: QueueBoundedOptions): QueueType => createQueue(maxSize, options)\n\n/**\n * Create a queue with explicit unbounded capacity.\n *\n * @example\n * ```ts\n * import { Queue } from \"@nicolastoulemont/std\"\n *\n * const queue = Queue.unbounded()\n * const paused = queue.isPaused\n * // => false\n * ```\n */\nexport const unbounded = (options?: QueueOptions): QueueType => createQueue(Number.POSITIVE_INFINITY, options)\n\n/* oxlint-enable max-classes-per-file */\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as schedule_d_exports } from "../schedule-
|
|
1
|
+
import { r as schedule_d_exports } from "../schedule-BzPjvMXc.mjs";
|
|
2
2
|
export { schedule_d_exports as Schedule };
|
package/dist/schedule/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"../schedule-
|
|
1
|
+
import{t as e}from"../schedule-B7qV60tO.mjs";export{e as Schedule};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./chunk-oQKkju2G.mjs";import{r as t}from"./result-D3VY0qBG.mjs";import{t as n}from"./data-
|
|
2
|
-
//# sourceMappingURL=schedule-
|
|
1
|
+
import{t as e}from"./chunk-oQKkju2G.mjs";import{r as t}from"./result-D3VY0qBG.mjs";import{t as n}from"./data-DqACNS_g.mjs";import{n as r,r as i}from"./duration-Bas3mi1N.mjs";var a=e({ScheduleInvalidDelayError:()=>s,ScheduleInvalidFactorError:()=>c,ScheduleInvalidRetryCountError:()=>o,exponential:()=>g,fixed:()=>h,recurs:()=>m}),o=class extends n(`ScheduleInvalidRetryCountError`){},s=class extends n(`ScheduleInvalidDelayError`){},c=class extends n(`ScheduleInvalidFactorError`){};const l=e=>{if(!Number.isInteger(e)||e<0)throw new o({input:e,message:`Schedule retry count must be an integer >= 0, received: ${String(e)}`})},u=(e,n)=>{let a=r(n);if(t(a))throw new s({field:e,input:n,message:a.error.message,cause:a.error});let o=i(a.value);if(!Number.isFinite(o)||o<0)throw new s({field:e,input:n,message:`Schedule ${e} must be a finite number >= 0, received: ${String(o)}`});return o},d=(e,t)=>{if(!Number.isFinite(t)||t<=0)throw new c({input:t,message:`Schedule ${e} must be a finite number > 0, received: ${String(t)}`})},f=(e,t)=>({_tag:`RetrySchedule`,_sync:!0,maxRetries:e,delayForAttempt:t}),p=(e,t)=>({_tag:`RetrySchedule`,_sync:!1,maxRetries:e,delayForAttempt:t}),m=e=>(l(e),f(e,()=>0)),h=e=>{l(e.times);let t=u(`delay`,e.delay);return p(e.times,()=>t)},g=e=>{l(e.times);let t=u(`baseDelay`,e.baseDelay),n=e.factor??2;d(`factor`,n);let r;return e.maxDelay!==void 0&&(r=u(`maxDelay`,e.maxDelay)),p(e.times,e=>{let i=t*n**(e-1);return r===void 0?i:Math.min(i,r)})};export{a as t};
|
|
2
|
+
//# sourceMappingURL=schedule-B7qV60tO.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-
|
|
1
|
+
{"version":3,"file":"schedule-B7qV60tO.mjs","names":["Data.TaggedError","Duration.from","Result.isErr","Duration.toMillis"],"sources":["../src/schedule/schedule.ts"],"sourcesContent":["/**\n * Retry schedule constructors used by `Fx.retry`.\n *\n * **Mental model**\n * - A schedule defines retry count and per-attempt delay.\n * - Sync schedules have no async delay requirements.\n *\n * **Common tasks**\n * - Use `Schedule.recurs` for immediate retries.\n * - Use `Schedule.fixed` for constant-delay retries.\n * - Use `Schedule.exponential` for backoff.\n *\n * **Gotchas**\n * - `times` is the number of retries after the first attempt.\n * - Delay values must normalize to finite, non-negative milliseconds.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const schedule = Schedule.recurs(2)\n * const delay = schedule.delayForAttempt(1)\n * // => 0\n * ```\n *\n * @module\n */\n/* oxlint-disable eslint/max-classes-per-file -- TaggedError classes are exported alongside schedule constructors by design. */\nimport { Data } from \"../data\"\nimport { Duration } from \"../duration\"\nimport { Result } from \"../result\"\n/**\n * Retry schedule used by Fx.retry.\n *\n * A schedule defines:\n * - how many retries are allowed after the first attempt\n * - how long to wait before each retry attempt\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Schedule\n * ```\n */\nexport type RetrySchedule = SyncRetrySchedule | AsyncRetrySchedule\n\n/**\n * Schedule that never introduces async delays.\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Schedule\n * ```\n */\nexport type SyncRetrySchedule = {\n readonly _tag: \"RetrySchedule\"\n readonly _sync: true\n readonly maxRetries: number\n readonly delayForAttempt: (retryAttempt: number) => number\n}\n\n/**\n * Schedule that may delay retries, requiring async execution.\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Schedule\n * ```\n */\nexport type AsyncRetrySchedule = {\n readonly _tag: \"RetrySchedule\"\n readonly _sync: false\n readonly maxRetries: number\n readonly delayForAttempt: (retryAttempt: number) => number\n}\n\n/**\n * Tagged error for invalid retry counts.\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const error = new Schedule.ScheduleInvalidRetryCountError({\n * input: -1,\n * message: \"Schedule retry count must be an integer >= 0, received: -1\",\n * })\n * // => error._tag === \"ScheduleInvalidRetryCountError\"\n * ```\n */\nexport class ScheduleInvalidRetryCountError extends Data.TaggedError(\"ScheduleInvalidRetryCountError\")<{\n input: number\n message: string\n}> {}\n\n/**\n * Tagged error for invalid schedule delay inputs.\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const error = new Schedule.ScheduleInvalidDelayError({\n * field: \"delay\",\n * input: \"oops\",\n * message: \"Invalid duration string: oops\",\n * })\n * // => error._tag === \"ScheduleInvalidDelayError\"\n * ```\n */\nexport class ScheduleInvalidDelayError extends Data.TaggedError(\"ScheduleInvalidDelayError\")<{\n field: \"delay\" | \"baseDelay\" | \"maxDelay\"\n input: Duration.Input\n message: string\n cause?: Duration.InputError\n}> {}\n\n/**\n * Tagged error for invalid exponential factors.\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const error = new Schedule.ScheduleInvalidFactorError({\n * input: 0,\n * message: \"Schedule factor must be a finite number > 0, received: 0\",\n * })\n * // => error._tag === \"ScheduleInvalidFactorError\"\n * ```\n */\nexport class ScheduleInvalidFactorError extends Data.TaggedError(\"ScheduleInvalidFactorError\")<{\n input: number\n message: string\n}> {}\n\ntype FixedScheduleOptions = {\n readonly times: number\n /**\n * The delay for the fixed schedule.\n * in milliseconds.\n */\n readonly delay: Duration.Input\n}\n\ntype ExponentialScheduleOptions = {\n readonly times: number\n /**\n * The base delay for the exponential schedule.\n * in milliseconds.\n */\n readonly baseDelay: Duration.Input\n /**\n * The factor for the exponential schedule.\n * Default: 2\n */\n readonly factor?: number | undefined\n /**\n * The maximum delay for the exponential schedule.\n * in milliseconds.\n */\n readonly maxDelay?: Duration.Input | undefined\n}\n\nconst validateRetryCount = (times: number) => {\n if (!Number.isInteger(times) || times < 0) {\n throw new ScheduleInvalidRetryCountError({\n input: times,\n message: `Schedule retry count must be an integer >= 0, received: ${String(times)}`,\n })\n }\n}\n\nconst validateDelay = (field: \"delay\" | \"baseDelay\" | \"maxDelay\", input: Duration.Input): number => {\n const normalized = Duration.from(input)\n if (Result.isErr(normalized)) {\n throw new ScheduleInvalidDelayError({\n field,\n input,\n message: normalized.error.message,\n cause: normalized.error,\n })\n }\n\n const millis = Duration.toMillis(normalized.value)\n if (!Number.isFinite(millis) || millis < 0) {\n throw new ScheduleInvalidDelayError({\n field,\n input,\n message: `Schedule ${field} must be a finite number >= 0, received: ${String(millis)}`,\n })\n }\n\n return millis\n}\n\nconst validatePositiveFinite = (name: \"factor\", value: number) => {\n if (!Number.isFinite(value) || value <= 0) {\n throw new ScheduleInvalidFactorError({\n input: value,\n message: `Schedule ${name} must be a finite number > 0, received: ${String(value)}`,\n })\n }\n}\n\nconst makeSyncSchedule = (\n maxRetries: number,\n delayForAttempt: (retryAttempt: number) => number,\n): SyncRetrySchedule => ({\n _tag: \"RetrySchedule\",\n _sync: true,\n maxRetries,\n delayForAttempt,\n})\n\nconst makeAsyncSchedule = (\n maxRetries: number,\n delayForAttempt: (retryAttempt: number) => number,\n): AsyncRetrySchedule => ({\n _tag: \"RetrySchedule\",\n _sync: false,\n maxRetries,\n delayForAttempt,\n})\n\n/**\n * Retry immediately up to `times` times.\n *\n * @example\n * ```ts\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const schedule = Schedule.recurs(2)\n * const delay = schedule.delayForAttempt(1)\n * // => 0\n * ```\n */\nexport const recurs = (times: number): SyncRetrySchedule => {\n validateRetryCount(times)\n return makeSyncSchedule(times, () => 0)\n}\n\n/**\n * Retry with a fixed delay between attempts.\n *\n * @example\n * ```ts\n * import { Duration, Schedule } from \"@nicolastoulemont/std\"\n *\n * const schedule = Schedule.fixed({ times: 2, delay: Duration.millis(100) })\n * const delay = schedule.delayForAttempt(2)\n * // => 100\n * ```\n */\nexport const fixed = (options: FixedScheduleOptions): AsyncRetrySchedule => {\n validateRetryCount(options.times)\n const delay = validateDelay(\"delay\", options.delay)\n return makeAsyncSchedule(options.times, () => delay)\n}\n\n/**\n * Retry with exponential backoff:\n * `baseDelay * factor^(retryAttempt - 1)`, optionally capped by `maxDelay`.\n *\n * @example\n * ```ts\n * import { Duration, Schedule } from \"@nicolastoulemont/std\"\n *\n * const schedule = Schedule.exponential({ times: 3, baseDelay: Duration.millis(100) })\n * const delay = schedule.delayForAttempt(3)\n * // => 400\n * ```\n */\nexport const exponential = (options: ExponentialScheduleOptions): AsyncRetrySchedule => {\n validateRetryCount(options.times)\n const baseDelay = validateDelay(\"baseDelay\", options.baseDelay)\n\n const factor = options.factor ?? 2\n validatePositiveFinite(\"factor\", factor)\n\n let maxDelay: number | undefined\n if (options.maxDelay !== undefined) {\n maxDelay = validateDelay(\"maxDelay\", options.maxDelay)\n }\n\n return makeAsyncSchedule(options.times, (retryAttempt) => {\n const delay = baseDelay * Math.pow(factor, retryAttempt - 1)\n return maxDelay === undefined ? delay : Math.min(delay, maxDelay)\n })\n}\n"],"mappings":"0UAiGa,EAAb,cAAoDA,EAAiB,iCAAiC,AAGnG,GAiBU,EAAb,cAA+CA,EAAiB,4BAA4B,AAKzF,GAgBU,EAAb,cAAgDA,EAAiB,6BAA6B,AAG3F,GA8BH,MAAM,EAAsB,GAAkB,CAC5C,GAAI,CAAC,OAAO,UAAU,EAAM,EAAI,EAAQ,EACtC,MAAM,IAAI,EAA+B,CACvC,MAAO,EACP,QAAS,2DAA2D,OAAO,EAAM,GAClF,CAAC,EAIA,GAAiB,EAA2C,IAAkC,CAClG,IAAM,EAAaC,EAAc,EAAM,CACvC,GAAIC,EAAa,EAAW,CAC1B,MAAM,IAAI,EAA0B,CAClC,QACA,QACA,QAAS,EAAW,MAAM,QAC1B,MAAO,EAAW,MACnB,CAAC,CAGJ,IAAM,EAASC,EAAkB,EAAW,MAAM,CAClD,GAAI,CAAC,OAAO,SAAS,EAAO,EAAI,EAAS,EACvC,MAAM,IAAI,EAA0B,CAClC,QACA,QACA,QAAS,YAAY,EAAM,2CAA2C,OAAO,EAAO,GACrF,CAAC,CAGJ,OAAO,GAGH,GAA0B,EAAgB,IAAkB,CAChE,GAAI,CAAC,OAAO,SAAS,EAAM,EAAI,GAAS,EACtC,MAAM,IAAI,EAA2B,CACnC,MAAO,EACP,QAAS,YAAY,EAAK,0CAA0C,OAAO,EAAM,GAClF,CAAC,EAIA,GACJ,EACA,KACuB,CACvB,KAAM,gBACN,MAAO,GACP,aACA,kBACD,EAEK,GACJ,EACA,KACwB,CACxB,KAAM,gBACN,MAAO,GACP,aACA,kBACD,EAcY,EAAU,IACrB,EAAmB,EAAM,CAClB,EAAiB,MAAa,EAAE,EAe5B,EAAS,GAAsD,CAC1E,EAAmB,EAAQ,MAAM,CACjC,IAAM,EAAQ,EAAc,QAAS,EAAQ,MAAM,CACnD,OAAO,EAAkB,EAAQ,UAAa,EAAM,EAgBzC,EAAe,GAA4D,CACtF,EAAmB,EAAQ,MAAM,CACjC,IAAM,EAAY,EAAc,YAAa,EAAQ,UAAU,CAEzD,EAAS,EAAQ,QAAU,EACjC,EAAuB,SAAU,EAAO,CAExC,IAAI,EAKJ,OAJI,EAAQ,WAAa,IAAA,KACvB,EAAW,EAAc,WAAY,EAAQ,SAAS,EAGjD,EAAkB,EAAQ,MAAQ,GAAiB,CACxD,IAAM,EAAQ,EAAqB,IAAQ,EAAe,GAC1D,OAAO,IAAa,IAAA,GAAY,EAAQ,KAAK,IAAI,EAAO,EAAS,EACjE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as TaggedErrorFactory } from "./index-
|
|
2
|
-
import { n as InputError, t as Input } from "./index-
|
|
1
|
+
import { n as TaggedErrorFactory } from "./index-D6pjHqlK.mjs";
|
|
2
|
+
import { n as InputError, t as Input } from "./index-DfAqfnY0.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/schedule/schedule.d.ts
|
|
5
5
|
declare namespace schedule_d_exports {
|
|
@@ -180,4 +180,4 @@ declare const fixed: (options: FixedScheduleOptions) => AsyncRetrySchedule;
|
|
|
180
180
|
declare const exponential: (options: ExponentialScheduleOptions) => AsyncRetrySchedule;
|
|
181
181
|
//#endregion
|
|
182
182
|
export { SyncRetrySchedule as n, schedule_d_exports as r, RetrySchedule as t };
|
|
183
|
-
//# sourceMappingURL=schedule-
|
|
183
|
+
//# sourceMappingURL=schedule-BzPjvMXc.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule-
|
|
1
|
+
{"version":3,"file":"schedule-BzPjvMXc.d.mts","names":[],"sources":["../src/schedule/schedule.ts"],"sourcesContent":[],"mappings":";;;;;;;AAoPA;AAiBA;AAmBA;;;;;;;;;;;;KAzOY,aAAA,GAAgB,oBAAoB;;;;;;;;;;;KAYpC,iBAAA;;;;;;;;;;;;;;;;KAiBA,kBAAA;;;;;;cAKX,qCAAA;;;;;;;;;;;;;;;cAgBY,8BAAA,SAAuC;;;;cAG/C,gCAAA;;;;;;;;;;;;;;;;cAiBQ,yBAAA,SAAkC;;SAEtC;;UAEC;;cACL,iCAAA;;;;;;;;;;;;;;;cAgBQ,0BAAA,SAAmC;;;;KAK3C,oBAAA;;;;;;kBAMa;;KAGb,0BAAA;;;;;;sBAMiB;;;;;;;;;;sBAUA;;;;;;;;;;;;;;cA4ET,2BAA0B;;;;;;;;;;;;;cAiB1B,iBAAkB,yBAAuB;;;;;;;;;;;;;;cAmBzC,uBAAwB,+BAA6B"}
|
package/dist/schema/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as schema_d_exports } from "../index-
|
|
1
|
+
import { t as schema_d_exports } from "../index-BipW0MC3.mjs";
|
|
2
2
|
export { schema_d_exports as Schema };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-DstB1_VK.mjs","names":["Result.err"],"sources":["../src/schema/schema.ts"],"sourcesContent":["import { Result } from \"../result\"\nimport type { Result as ResultType } from \"../result/result.types\"\n/**\n * Standard Schema-backed parsing and refinement helpers.\n *\n * **Mental model**\n * - `Schema.parse` is for boundary validation and parsing.\n * - `Schema.is` is a sync-only proof guard for direct in-memory checks.\n * - `Schema.refine` is the reusable preserved-shape guard for higher-order APIs like `Array.filter`.\n *\n * **Common tasks**\n * - Parse loose external data into validated subtypes.\n * - Use `Schema.is` for direct control-flow checks against already-typed values.\n * - Reuse a schema as a preserved-shape predicate with `Schema.refine`.\n * - Name reusable narrowed types with `Schema.Refine<Base, typeof schema>` or exact schema outputs with `Schema.Infer<typeof schema>`.\n *\n * **Gotchas**\n * - `Schema.parse` may be sync or async based on the schema type you preserve.\n * - `Schema.refine` and `Schema.is` support both data-first and data-last styles.\n * - `Schema.refine` and `Schema.is` are sync-only.\n * - `Schema.is` and `Schema.refine` must only be used with proof schemas that validate the current value in place.\n * - Transforms, defaults, coercions, and other output-changing schemas should use `Schema.parse`.\n * - `Schema.is` narrows `unknown` to the exact schema output, but in direct control flow TypeScript preserves the current value shape.\n * - `Schema.refine` exists for the cases where you need that preserved shape to survive higher-order APIs like `Array.filter`.\n *\n * @module\n */\nimport { dual } from \"../shared/dual\"\nimport { isPromise } from \"../shared/is-promise\"\nimport { toThrownValidationError, toValidationResult, validateSync } from \"./schema.shared\"\nimport type {\n Input,\n Output,\n Refine as Refined,\n SyncRefinementSchema,\n SyncSchema,\n ValidationError,\n} from \"./schema.types\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\nexport type {\n Infer,\n Input,\n Output,\n Refine,\n RefinementSchema,\n SyncRefinementSchema,\n SyncSchema,\n ValidationError,\n ValidationIssue,\n} from \"./schema.types\"\n\n/**\n * Create a schema-backed parser.\n *\n * For sync schemas the returned parser is sync.\n * For general Standard Schema values the returned parser is async.\n */\nexport function parse<S extends SyncSchema>(schema: S): (value: Input<S>) => ResultType<Output<S>, ValidationError>\nexport function parse<S extends StandardSchemaV1>(\n schema: S,\n): (value: Input<S>) => Promise<ResultType<Output<S>, ValidationError>>\nexport function parse<S extends StandardSchemaV1>(schema: S) {\n return (value: Input<S>) => {\n try {\n const result = schema[\"~standard\"].validate(value)\n\n if (isPromise(result)) {\n return Promise.resolve(result).then(\n (validated) => toValidationResult(validated),\n (error) => Result.err(toThrownValidationError(error)),\n )\n }\n\n return toValidationResult(result)\n } catch (error) {\n return Result.err(toThrownValidationError(error))\n }\n }\n}\n\nexport type RefineFn = {\n <S extends SyncSchema, Base extends Input<S>>(value: Base, schema: S): value is Refined<Base, S>\n <S extends SyncSchema>(schema: S): <Base extends Input<S>>(value: Base) => value is Refined<Base, S>\n}\n\nexport type Is = {\n <Base, Sub extends Base>(value: Base, schema: SyncRefinementSchema<Base, Sub>): value is Sub\n <S extends SyncSchema>(value: unknown, schema: S): value is Output<S>\n <Base, Sub extends Base>(schema: SyncRefinementSchema<Base, Sub>): (value: Base) => value is Sub\n <S extends SyncSchema>(schema: S): (value: unknown) => value is Output<S>\n}\n\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- dual() requires a single implementation signature */\nconst refineImpl = dual(2, (value: unknown, schema: SyncSchema) => {\n return validateSync(schema, value, \"Schema.refine()\")._tag === \"Ok\"\n}) as RefineFn\n\n/**\n * Create a sync-only schema-backed reusable type guard that preserves the original value shape.\n *\n * Use this when a schema validates only a subset of a broader in-memory value\n * and you need the preserved shape to survive higher-order APIs like\n * `Array.filter`. The narrowed type is `Base & Output<typeof schema>`, not the\n * exact schema output.\n *\n * Supports both data-first and data-last styles:\n * - Data-first: `Schema.refine(value, schema)`\n * - Data-last: `Schema.refine(schema)(value)`\n *\n * Only use this with sync proof schemas that validate properties already\n * present on the original value. Transforms, defaults, and coercions are not\n * safe here because they can change the schema output without changing the\n * original input value.\n */\nexport function refine<S extends SyncSchema, Base extends Input<S>>(value: Base, schema: S): value is Refined<Base, S>\nexport function refine<S extends SyncSchema>(schema: S): <Base extends Input<S>>(value: Base) => value is Refined<Base, S>\nexport function refine(...args: [value: unknown, schema: SyncSchema] | [schema: SyncSchema]) {\n return (refineImpl as (...args: [unknown, SyncSchema] | [SyncSchema]) => boolean | ((value: unknown) => boolean))(...args)\n}\n\nconst isImpl = dual(2, (value: unknown, schema: SyncSchema) => {\n return validateSync(schema, value, \"Schema.is()\")._tag === \"Ok\"\n}) as Is\n\n/**\n * Create a sync-only schema-backed proof guard.\n *\n * On `unknown` values this narrows to the exact schema output. On already-typed\n * values, TypeScript preserves the current shape during direct control-flow\n * checks. Use `Schema.refine` when that preserved shape must survive\n * higher-order APIs like `Array.filter`.\n *\n * Supports both data-first and data-last styles:\n * - Data-first: `Schema.is(value, schema)`\n * - Data-last: `Schema.is(schema)(value)`\n */\nexport function is<Base, Sub extends Base>(value: Base, schema: SyncRefinementSchema<Base, Sub>): value is Sub\nexport function is<S extends SyncSchema>(value: unknown, schema: S): value is Output<S>\nexport function is<Base, Sub extends Base>(schema: SyncRefinementSchema<Base, Sub>): (value: Base) => value is Sub\nexport function is<S extends SyncSchema>(schema: S): (value: unknown) => value is Output<S>\nexport function is(...args: [value: unknown, schema: SyncSchema] | [schema: SyncSchema]) {\n return (isImpl as (...args: [unknown, SyncSchema] | [SyncSchema]) => boolean | ((value: unknown) => boolean))(...args)\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n"],"mappings":"qQA8DA,SAAgB,EAAkC,EAAW,CAC3D,MAAQ,IAAoB,CAC1B,GAAI,CACF,IAAM,EAAS,EAAO,aAAa,SAAS,EAAM,CASlD,OAPI,EAAU,EAAO,CACZ,QAAQ,QAAQ,EAAO,CAAC,KAC5B,GAAc,EAAmB,EAAU,CAC3C,GAAUA,EAAW,EAAwB,EAAM,CAAC,CACtD,CAGI,EAAmB,EAAO,OAC1B,EAAO,CACd,OAAOA,EAAW,EAAwB,EAAM,CAAC,GAkBvD,MAAM,EAAa,EAAK,GAAI,EAAgB,IACnC,EAAa,EAAQ,EAAO,kBAAkB,CAAC,OAAS,KAC/D,
|
|
1
|
+
{"version":3,"file":"schema-DstB1_VK.mjs","names":["Result.err"],"sources":["../src/schema/schema.ts"],"sourcesContent":["import { Result } from \"../result\"\nimport type { Result as ResultType } from \"../result/result.types\"\n/**\n * Standard Schema-backed parsing and refinement helpers.\n *\n * **Mental model**\n * - `Schema.parse` is for boundary validation and parsing.\n * - `Schema.is` is a sync-only proof guard for direct in-memory checks.\n * - `Schema.refine` is the reusable preserved-shape guard for higher-order APIs like `Array.filter`.\n *\n * **Common tasks**\n * - Parse loose external data into validated subtypes.\n * - Use `Schema.is` for direct control-flow checks against already-typed values.\n * - Reuse a schema as a preserved-shape predicate with `Schema.refine`.\n * - Name reusable narrowed types with `Schema.Refine<Base, typeof schema>` or exact schema outputs with `Schema.Infer<typeof schema>`.\n *\n * **Gotchas**\n * - `Schema.parse` may be sync or async based on the schema type you preserve.\n * - `Schema.refine` and `Schema.is` support both data-first and data-last styles.\n * - `Schema.refine` and `Schema.is` are sync-only.\n * - `Schema.is` and `Schema.refine` must only be used with proof schemas that validate the current value in place.\n * - Transforms, defaults, coercions, and other output-changing schemas should use `Schema.parse`.\n * - `Schema.is` narrows `unknown` to the exact schema output, but in direct control flow TypeScript preserves the current value shape.\n * - `Schema.refine` exists for the cases where you need that preserved shape to survive higher-order APIs like `Array.filter`.\n *\n * @module\n */\nimport { dual } from \"../shared/dual\"\nimport { isPromise } from \"../shared/is-promise\"\nimport { toThrownValidationError, toValidationResult, validateSync } from \"./schema.shared\"\nimport type {\n Input,\n Output,\n Refine as Refined,\n SyncRefinementSchema,\n SyncSchema,\n ValidationError,\n} from \"./schema.types\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\nexport type {\n Infer,\n Input,\n Output,\n Refine,\n RefinementSchema,\n SyncRefinementSchema,\n SyncSchema,\n ValidationError,\n ValidationIssue,\n} from \"./schema.types\"\n\n/**\n * Create a schema-backed parser.\n *\n * For sync schemas the returned parser is sync.\n * For general Standard Schema values the returned parser is async.\n */\nexport function parse<S extends SyncSchema>(schema: S): (value: Input<S>) => ResultType<Output<S>, ValidationError>\nexport function parse<S extends StandardSchemaV1>(\n schema: S,\n): (value: Input<S>) => Promise<ResultType<Output<S>, ValidationError>>\nexport function parse<S extends StandardSchemaV1>(schema: S) {\n return (value: Input<S>) => {\n try {\n const result = schema[\"~standard\"].validate(value)\n\n if (isPromise(result)) {\n return Promise.resolve(result).then(\n (validated) => toValidationResult(validated),\n (error) => Result.err(toThrownValidationError(error)),\n )\n }\n\n return toValidationResult(result)\n } catch (error) {\n return Result.err(toThrownValidationError(error))\n }\n }\n}\n\nexport type RefineFn = {\n <S extends SyncSchema, Base extends Input<S>>(value: Base, schema: S): value is Refined<Base, S>\n <S extends SyncSchema>(schema: S): <Base extends Input<S>>(value: Base) => value is Refined<Base, S>\n}\n\nexport type Is = {\n <Base, Sub extends Base>(value: Base, schema: SyncRefinementSchema<Base, Sub>): value is Sub\n <S extends SyncSchema>(value: unknown, schema: S): value is Output<S>\n <Base, Sub extends Base>(schema: SyncRefinementSchema<Base, Sub>): (value: Base) => value is Sub\n <S extends SyncSchema>(schema: S): (value: unknown) => value is Output<S>\n}\n\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- dual() requires a single implementation signature */\nconst refineImpl = dual(2, (value: unknown, schema: SyncSchema) => {\n return validateSync(schema, value, \"Schema.refine()\")._tag === \"Ok\"\n}) as RefineFn\n\n/**\n * Create a sync-only schema-backed reusable type guard that preserves the original value shape.\n *\n * Use this when a schema validates only a subset of a broader in-memory value\n * and you need the preserved shape to survive higher-order APIs like\n * `Array.filter`. The narrowed type is `Base & Output<typeof schema>`, not the\n * exact schema output.\n *\n * Supports both data-first and data-last styles:\n * - Data-first: `Schema.refine(value, schema)`\n * - Data-last: `Schema.refine(schema)(value)`\n *\n * Only use this with sync proof schemas that validate properties already\n * present on the original value. Transforms, defaults, and coercions are not\n * safe here because they can change the schema output without changing the\n * original input value.\n */\nexport function refine<S extends SyncSchema, Base extends Input<S>>(value: Base, schema: S): value is Refined<Base, S>\nexport function refine<S extends SyncSchema>(\n schema: S,\n): <Base extends Input<S>>(value: Base) => value is Refined<Base, S>\nexport function refine(...args: [value: unknown, schema: SyncSchema] | [schema: SyncSchema]) {\n return (refineImpl as (...args: [unknown, SyncSchema] | [SyncSchema]) => boolean | ((value: unknown) => boolean))(\n ...args,\n )\n}\n\nconst isImpl = dual(2, (value: unknown, schema: SyncSchema) => {\n return validateSync(schema, value, \"Schema.is()\")._tag === \"Ok\"\n}) as Is\n\n/**\n * Create a sync-only schema-backed proof guard.\n *\n * On `unknown` values this narrows to the exact schema output. On already-typed\n * values, TypeScript preserves the current shape during direct control-flow\n * checks. Use `Schema.refine` when that preserved shape must survive\n * higher-order APIs like `Array.filter`.\n *\n * Supports both data-first and data-last styles:\n * - Data-first: `Schema.is(value, schema)`\n * - Data-last: `Schema.is(schema)(value)`\n */\nexport function is<Base, Sub extends Base>(value: Base, schema: SyncRefinementSchema<Base, Sub>): value is Sub\nexport function is<S extends SyncSchema>(value: unknown, schema: S): value is Output<S>\nexport function is<Base, Sub extends Base>(schema: SyncRefinementSchema<Base, Sub>): (value: Base) => value is Sub\nexport function is<S extends SyncSchema>(schema: S): (value: unknown) => value is Output<S>\nexport function is(...args: [value: unknown, schema: SyncSchema] | [schema: SyncSchema]) {\n return (isImpl as (...args: [unknown, SyncSchema] | [SyncSchema]) => boolean | ((value: unknown) => boolean))(...args)\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n"],"mappings":"qQA8DA,SAAgB,EAAkC,EAAW,CAC3D,MAAQ,IAAoB,CAC1B,GAAI,CACF,IAAM,EAAS,EAAO,aAAa,SAAS,EAAM,CASlD,OAPI,EAAU,EAAO,CACZ,QAAQ,QAAQ,EAAO,CAAC,KAC5B,GAAc,EAAmB,EAAU,CAC3C,GAAUA,EAAW,EAAwB,EAAM,CAAC,CACtD,CAGI,EAAmB,EAAO,OAC1B,EAAO,CACd,OAAOA,EAAW,EAAwB,EAAM,CAAC,GAkBvD,MAAM,EAAa,EAAK,GAAI,EAAgB,IACnC,EAAa,EAAQ,EAAO,kBAAkB,CAAC,OAAS,KAC/D,CAuBF,SAAgB,EAAO,GAAG,EAAmE,CAC3F,OAAQ,EACN,GAAG,EACJ,CAGH,MAAM,EAAS,EAAK,GAAI,EAAgB,IAC/B,EAAa,EAAQ,EAAO,cAAc,CAAC,OAAS,KAC3D,CAkBF,SAAgB,EAAG,GAAG,EAAmE,CACvF,OAAQ,EAAsG,GAAG,EAAK"}
|
|
@@ -26,7 +26,7 @@ type Infer<S extends StandardSchemaV1> = Output<S>;
|
|
|
26
26
|
* direct control-flow checks when `Schema.is()` is used on an already-typed
|
|
27
27
|
* value.
|
|
28
28
|
*/
|
|
29
|
-
type Refine<Base, S extends StandardSchemaV1> = Base extends Input<S> ? Base extends unknown ? Prettify<Base & Output<S>> : never : never;
|
|
29
|
+
type Refine<Base, S extends StandardSchemaV1> = Base extends Input<S> ? (Base extends unknown ? Prettify<Base & Output<S>> : never) : never;
|
|
30
30
|
/**
|
|
31
31
|
* Normalized validation issue shape used across std modules.
|
|
32
32
|
*/
|
|
@@ -59,4 +59,4 @@ type RefinementSchema<Base, Sub extends Base> = StandardSchemaV1<Base, Sub>;
|
|
|
59
59
|
type SyncRefinementSchema<Base, Sub extends Base> = SyncSchema<Base, Sub>;
|
|
60
60
|
//#endregion
|
|
61
61
|
export { RefinementSchema as a, ValidationError as c, Refine as i, ValidationIssue as l, Input as n, SyncRefinementSchema as o, Output as r, SyncSchema as s, Infer as t };
|
|
62
|
-
//# sourceMappingURL=schema.types-
|
|
62
|
+
//# sourceMappingURL=schema.types-w1WK4kGS.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.types-w1WK4kGS.d.mts","names":[],"sources":["../src/schema/schema.types.ts"],"sourcesContent":[],"mappings":";;;;;;;AAMA;AAA4B,KAAhB,KAAgB,CAAA,UAAA,gBAAA,CAAA,GAAoB,WAApB,CAAgC,CAAhC,CAAA,WAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,OAAA,CAAA;;;;AAKhB,KAAA,MAAM,CAAA,UAAW,gBAAX,CAAA,GAA+B,WAA/B,CAA2C,CAA3C,CAAA,WAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,QAAA,CAAA;;;;;AAQlB;;AAAuD,KAA3C,KAA2C,CAAA,UAA3B,gBAA2B,CAAA,GAAP,MAAO,CAAA,CAAA,CAAA;;;AAUvD;;;;;;AAC2D,KAD/C,MAC+C,CAAA,IAAA,EAAA,UADxB,gBACwB,CAAA,GAAzD,IAAyD,SAA5C,KAA4C,CAAtC,CAAsC,CAAA,GAAA,CAAhC,IAAgC,SAAA,OAAA,GAAT,QAAS,CAAA,IAAA,GAAO,MAAP,CAAc,CAAd,CAAA,CAAA,GAAA,KAAA,CAAA,GAAA,KAAA;;;;AAAD,KAK9C,eAAA,GAL8C;EAK9C,SAAA,OAAA,EAAe,MAAA;EAQf,SAAA,IAAA,CAAA,EANM,aAMS,CANK,WAOC,CAAA,GAAA,SAAd;AAOnB,CAAA;;;;AAAkE,KARtD,eAAA,GAQsD;EAAL,SAAA,MAAA,EAP1C,aAO0C,CAP5B,eAO4B,CAAA;CACf;;;;;AACZ,KAFtB,UAEuC,CAAA,SAAA,OAAA,EAAA,UAFA,MAEA,CAAA,GAFU,IAEV,CAFe,gBAEf,CAFgC,MAEhC,EAFwC,OAExC,CAAA,EAAA,WAAA,CAAA,GAAA;EAAM,SAAA,WAAA,EADjC,IACiC,CAD5B,gBAC4B,CADX,MACW,EADH,OACG,CAAA,CAAA,WAAA,CAAA,EAAA,UAAA,CAAA,GAAA;IAO7C,QAAA,EAAA,CAAA,KAAgB,EAAA,OAAA,EAAA,GAPM,gBAAA,CAAiB,MAOvB,CAP8B,OAO9B,CAAA;EAAmB,CAAA;CAAyB;;;;AAK5D,KALA,gBAKoB,CAAA,IAAA,EAAA,YALe,IAKf,CAAA,GALuB,gBAKvB,CALwC,IAKxC,EAL8C,GAK9C,CAAA;;;;AAA2B,KAA/C,oBAA+C,CAAA,IAAA,EAAA,YAAR,IAAQ,CAAA,GAAA,UAAA,CAAW,IAAX,EAAiB,GAAjB,CAAA"}
|
package/package.json
CHANGED
package/dist/adt-CPG_sa8q.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./chunk-oQKkju2G.mjs";import{i as t,n,r,t as i}from"./equality-BX6BUidG.mjs";import{i as a,t as o}from"./result-D3VY0qBG.mjs";import{r as s}from"./schema.shared-Bjyroa6b.mjs";function c(e,t){let n=t[e._tag];return n(e)}function l(e){return typeof e!=`object`||!e?!1:Object.getPrototypeOf(e)===null||Object.getPrototypeOf(e)===Object.prototype}function u(e){return typeof e==`function`&&`_variant`in e&&e._variant===!0}function d(e,t,n){return s(e,t,`ADT variant "${n}"`)}function f(e){return t=>l(t)&&`_tag`in t&&t._tag===e}function p(e){let t=new Set(e);return e=>l(e)&&`_tag`in e&&typeof e._tag==`string`&&t.has(e._tag)}function m(e,t,n,r){return n!==void 0&&r!==void 0?{kind:e,message:t,cause:n,validationIssues:r}:n===void 0?r===void 0?{kind:e,message:t}:{kind:e,message:t,validationIssues:r}:{kind:e,message:t,cause:n}}function h(e){return{to:e=>JSON.stringify(e),from:e=>{try{let t=JSON.parse(e);if(typeof t==`object`&&t&&`_tag`in t){let{_tag:e,...n}=t;return n}return t}catch{return null}}}}function g(e,t,n){let r=h(e),i={json:n=>{let i=d(t,{...n,_tag:e},e);if(i._tag===`Err`)return o(m(`ValidationError`,`Cannot encode invalid data: ${i.error.issues.map(e=>e.message).join(`, `)}`,void 0,i.error.issues));try{return a(r.to(i.value))}catch(e){return o(m(`EncodingError`,`JSON encoding failed: ${e instanceof Error?e.message:String(e)}`,e))}}};if(n)for(let[r,s]of Object.entries(n))i[r]=n=>{let i=d(t,{...n,_tag:e},e);if(i._tag===`Err`)return o(m(`ValidationError`,`Cannot encode invalid data: ${i.error.issues.map(e=>e.message).join(`, `)}`,void 0,i.error.issues));try{return a(s.to(i.value))}catch(e){return o(m(`EncodingError`,`Encoding with codec '${r}' failed: ${e instanceof Error?e.message:String(e)}`,e))}};return i}function _(e,t,n){let r=h(e),i={json:n=>{let i=r.from(n);if(i===null)return o(m(`DecodingError`,`Invalid JSON format`));let s=d(t,{...i,_tag:e},e);return s._tag===`Err`?o(m(`ValidationError`,`Decoded data failed schema validation`,void 0,s.error.issues)):a({...s.value,_tag:e})}};if(n)for(let[r,s]of Object.entries(n))i[r]=n=>{let i;try{i=s.from(n)}catch(e){return o(m(`DecodingError`,`Decoding with codec '${r}' threw an error`,e))}if(i===null)return o(m(`DecodingError`,`Codec '${r}' failed to decode input`));let c=d(t,{...i,_tag:e},e);return c._tag===`Err`?o(m(`ValidationError`,`Decoded data failed schema validation`,void 0,c.error.issues)):a({...c.value,_tag:e})};return i}function v(e,n,i){let s=f(e),c=g(e,n,i),l=_(e,n,i),u=r(e),p=t(e),m=t=>{let r=d(n,{...t,_tag:e},e);return r._tag===`Err`?o(r.error):a({...r.value,_tag:e})};return m._variant=!0,m._tag=e,m.schema=n,i&&(m.codecs=i),m.is=s,m.to=c,m.from=l,m.equals=u,m.hash=p,m}function y(e,t){let r=Object.keys(t),a={};for(let[e,n]of Object.entries(t))u(n)?n._tag===e?a[e]=n:n.codecs?a[e]=v(e,n.schema,n.codecs):a[e]=v(e,n.schema):a[e]=v(e,n);return{_name:e,is:p(r),equals:i(r),hash:n(r),...a}}var b=e({match:()=>C,union:()=>x,variant:()=>S});const x=y,S=v,C=c;export{b as t};
|
|
2
|
-
//# sourceMappingURL=adt-CPG_sa8q.mjs.map
|