@nicolastoulemont/std 0.3.0 → 0.5.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/dist/adt/index.d.mts +1 -1
- package/dist/adt/index.mjs +1 -3
- package/dist/adt-DZmVJG4P.mjs +2 -0
- package/dist/adt-DZmVJG4P.mjs.map +1 -0
- package/dist/{apply-fn.types-CXDoeA7D.d.mts → apply-fn.types-CMgY6WQe.d.mts} +1 -1
- package/dist/{apply-fn.types-CXDoeA7D.d.mts.map → apply-fn.types-CMgY6WQe.d.mts.map} +1 -1
- package/dist/brand/index.d.mts +2 -2
- package/dist/brand/index.mjs +1 -3
- package/dist/brand-BUqMmkzC.mjs +2 -0
- package/dist/{brand-CTaxGuU9.mjs.map → brand-BUqMmkzC.mjs.map} +1 -1
- package/dist/data/index.d.mts +1 -1
- package/dist/data/index.mjs +1 -3
- package/dist/data-DzqKBCQg.mjs +2 -0
- package/dist/data-DzqKBCQg.mjs.map +1 -0
- package/dist/discriminator.types-DkThfvNE.d.mts +7 -0
- package/dist/discriminator.types-DkThfvNE.d.mts.map +1 -0
- package/dist/either/index.d.mts +2 -2
- package/dist/either/index.mjs +1 -3
- package/dist/either-BDY9T5oz.mjs +2 -0
- package/dist/either-BDY9T5oz.mjs.map +1 -0
- package/dist/equality-D2EJvZm4.mjs +2 -0
- package/dist/equality-D2EJvZm4.mjs.map +1 -0
- package/dist/err/index.d.mts +2 -2
- package/dist/err/index.mjs +1 -3
- package/dist/err-CYs4b1RV.mjs +2 -0
- package/dist/err-CYs4b1RV.mjs.map +1 -0
- package/dist/flow/index.d.mts +1 -1
- package/dist/flow/index.mjs +1 -3
- package/dist/flow-CxKQ5yac.mjs +2 -0
- package/dist/flow-CxKQ5yac.mjs.map +1 -0
- package/dist/fx/index.d.mts +3 -0
- package/dist/fx/index.mjs +1 -0
- package/dist/fx-C4UuWCqP.mjs +2 -0
- package/dist/fx-C4UuWCqP.mjs.map +1 -0
- package/dist/fx.types-CXTwEa1G.mjs +2 -0
- package/dist/fx.types-CXTwEa1G.mjs.map +1 -0
- package/dist/fx.types-DO-8yG4c.d.mts +133 -0
- package/dist/fx.types-DO-8yG4c.d.mts.map +1 -0
- package/dist/index-78LWwTds.d.mts +288 -0
- package/dist/index-78LWwTds.d.mts.map +1 -0
- package/dist/index-BQ5wVDSP.d.mts +441 -0
- package/dist/index-BQ5wVDSP.d.mts.map +1 -0
- package/dist/{index-tkgTLCoq.d.mts → index-BahMvQpA.d.mts} +2 -2
- package/dist/{index-tkgTLCoq.d.mts.map → index-BahMvQpA.d.mts.map} +1 -1
- package/dist/index-Bs5TTFlK.d.mts +882 -0
- package/dist/index-Bs5TTFlK.d.mts.map +1 -0
- package/dist/index-BuLJRX1e.d.mts +476 -0
- package/dist/index-BuLJRX1e.d.mts.map +1 -0
- package/dist/{index-BR7takNf.d.mts → index-CDio8mJY.d.mts} +65 -26
- package/dist/index-CDio8mJY.d.mts.map +1 -0
- package/dist/{index-Cp_4sFun.d.mts → index-DLlx9jiG.d.mts} +38 -43
- package/dist/index-DLlx9jiG.d.mts.map +1 -0
- package/dist/index-DQoTXLSm.d.mts +846 -0
- package/dist/index-DQoTXLSm.d.mts.map +1 -0
- package/dist/index-DjjJIDaA.d.mts +221 -0
- package/dist/index-DjjJIDaA.d.mts.map +1 -0
- package/dist/{index-BCrD3pEs.d.mts → index-DtAPrec7.d.mts} +18 -18
- package/dist/index-DtAPrec7.d.mts.map +1 -0
- package/dist/{index-zC2zAtZY.d.mts → index-IdejL485.d.mts} +2 -2
- package/dist/{index-zC2zAtZY.d.mts.map → index-IdejL485.d.mts.map} +1 -1
- package/dist/index.d.mts +16 -802
- package/dist/index.mjs +1 -1393
- package/dist/option/index.d.mts +3 -3
- package/dist/option/index.mjs +1 -3
- package/dist/option-Qiv7Ls7L.mjs +2 -0
- package/dist/option-Qiv7Ls7L.mjs.map +1 -0
- package/dist/option.types-By5UOfC2.mjs +2 -0
- package/dist/option.types-By5UOfC2.mjs.map +1 -0
- package/dist/option.types-Cluybn30.d.mts +167 -0
- package/dist/option.types-Cluybn30.d.mts.map +1 -0
- package/dist/pipe/index.d.mts +1 -1
- package/dist/pipe/index.mjs +1 -3
- package/dist/pipe-BROILDeC.mjs +2 -0
- package/dist/{pipe-GYxZNkPB.mjs.map → pipe-BROILDeC.mjs.map} +1 -1
- package/dist/pipeable-KHu4D8ol.d.mts +27 -0
- package/dist/pipeable-KHu4D8ol.d.mts.map +1 -0
- package/dist/pipeable-rQvolRqh.mjs +2 -0
- package/dist/pipeable-rQvolRqh.mjs.map +1 -0
- package/dist/predicate/index.d.mts +2 -2
- package/dist/predicate/index.mjs +1 -3
- package/dist/predicate-DvXnfmeJ.mjs +2 -0
- package/dist/{predicate-BZkZmo-W.mjs.map → predicate-DvXnfmeJ.mjs.map} +1 -1
- package/dist/result/index.d.mts +3 -3
- package/dist/result/index.mjs +1 -3
- package/dist/result-B68pxC7l.mjs +2 -0
- package/dist/result-B68pxC7l.mjs.map +1 -0
- package/dist/result-uRORQlAQ.mjs +1 -0
- package/dist/result.types-fIbuBwVQ.d.mts +259 -0
- package/dist/result.types-fIbuBwVQ.d.mts.map +1 -0
- package/package.json +1 -9
- package/dist/adt-DraJkmij.mjs +0 -318
- package/dist/adt-DraJkmij.mjs.map +0 -1
- package/dist/brand-CTaxGuU9.mjs +0 -165
- package/dist/data-DgzWI4R_.mjs +0 -244
- package/dist/data-DgzWI4R_.mjs.map +0 -1
- package/dist/discriminator.types-DCkkrCj4.d.mts +0 -7
- package/dist/discriminator.types-DCkkrCj4.d.mts.map +0 -1
- package/dist/either-CnOBUH7a.mjs +0 -598
- package/dist/either-CnOBUH7a.mjs.map +0 -1
- package/dist/equality/index.d.mts +0 -86
- package/dist/equality/index.d.mts.map +0 -1
- package/dist/equality/index.mjs +0 -3
- package/dist/equality-YMebYwm1.mjs +0 -201
- package/dist/equality-YMebYwm1.mjs.map +0 -1
- package/dist/err-BqQApH9r.mjs +0 -169
- package/dist/err-BqQApH9r.mjs.map +0 -1
- package/dist/flow-pRdnqmMY.mjs +0 -21
- package/dist/flow-pRdnqmMY.mjs.map +0 -1
- package/dist/fn/index.d.mts +0 -2
- package/dist/fn/index.mjs +0 -3
- package/dist/fn-DFHj-EVA.mjs +0 -10
- package/dist/fn-DFHj-EVA.mjs.map +0 -1
- package/dist/gen/index.d.mts +0 -3
- package/dist/gen/index.mjs +0 -3
- package/dist/gen-DF-FXNdy.mjs +0 -99
- package/dist/gen-DF-FXNdy.mjs.map +0 -1
- package/dist/index-B3z7T6Dz.d.mts +0 -57
- package/dist/index-B3z7T6Dz.d.mts.map +0 -1
- package/dist/index-BCrD3pEs.d.mts.map +0 -1
- package/dist/index-BFhV56qy.d.mts +0 -105
- package/dist/index-BFhV56qy.d.mts.map +0 -1
- package/dist/index-BLG9B4bn.d.mts +0 -116
- package/dist/index-BLG9B4bn.d.mts.map +0 -1
- package/dist/index-BR7takNf.d.mts.map +0 -1
- package/dist/index-BiFc2xWF.d.mts +0 -211
- package/dist/index-BiFc2xWF.d.mts.map +0 -1
- package/dist/index-BwVaI5d0.d.mts +0 -79
- package/dist/index-BwVaI5d0.d.mts.map +0 -1
- package/dist/index-CckxkaUd.d.mts +0 -80
- package/dist/index-CckxkaUd.d.mts.map +0 -1
- package/dist/index-Cp_4sFun.d.mts.map +0 -1
- package/dist/index-DbfMra4p.d.mts +0 -72
- package/dist/index-DbfMra4p.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/is-promise-BEl3eGZg.mjs +0 -11
- package/dist/is-promise-BEl3eGZg.mjs.map +0 -1
- package/dist/option-CKHDOVea.mjs +0 -410
- package/dist/option-CKHDOVea.mjs.map +0 -1
- package/dist/option.types-eqVODMIy.d.mts +0 -89
- package/dist/option.types-eqVODMIy.d.mts.map +0 -1
- package/dist/pipe-GYxZNkPB.mjs +0 -10
- package/dist/predicate-BZkZmo-W.mjs +0 -293
- package/dist/result-C5tPWR60.mjs +0 -422
- package/dist/result-C5tPWR60.mjs.map +0 -1
- package/dist/result-D7XJ96pv.mjs +0 -1
- package/dist/result.types-Bd8a43Fg.d.mts +0 -174
- package/dist/result.types-Bd8a43Fg.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,1393 +1 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { n as data, r as record } from "./adt-DraJkmij.mjs";
|
|
3
|
-
import { t as Brand } from "./brand-CTaxGuU9.mjs";
|
|
4
|
-
import { i as tagged, n as tuple, r as struct, t as array } from "./data-DgzWI4R_.mjs";
|
|
5
|
-
import { n as ensureRefinement, r as gen, t as ensure } from "./gen-DF-FXNdy.mjs";
|
|
6
|
-
import { t as Option } from "./option-CKHDOVea.mjs";
|
|
7
|
-
import { t as Either } from "./either-CnOBUH7a.mjs";
|
|
8
|
-
import { n as TaggedError, t as Err } from "./err-BqQApH9r.mjs";
|
|
9
|
-
import { t as flow } from "./flow-pRdnqmMY.mjs";
|
|
10
|
-
import "./flow/index.mjs";
|
|
11
|
-
import { t as pipe } from "./pipe-GYxZNkPB.mjs";
|
|
12
|
-
import { t as Predicate } from "./predicate-BZkZmo-W.mjs";
|
|
13
|
-
import { t as fn } from "./fn-DFHj-EVA.mjs";
|
|
14
|
-
|
|
15
|
-
//#region src/fx/fx.ts
|
|
16
|
-
/**
|
|
17
|
-
* Implementation of unified Fx.gen function.
|
|
18
|
-
* Detects sync vs async generator and returns appropriate computation type.
|
|
19
|
-
*/
|
|
20
|
-
function fxGen(generatorFn) {
|
|
21
|
-
const testGen = generatorFn();
|
|
22
|
-
if (Symbol.asyncIterator in testGen) return {
|
|
23
|
-
_tag: "AsyncFx",
|
|
24
|
-
run: async () => {
|
|
25
|
-
const result = await generatorFn().next();
|
|
26
|
-
if (result.done !== true) {
|
|
27
|
-
const yielded = result.value;
|
|
28
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") throw new Error(`Service "${yielded.serviceKey}" not provided. Use provide() to inject services.`);
|
|
29
|
-
return err(yielded);
|
|
30
|
-
}
|
|
31
|
-
return ok(result.value);
|
|
32
|
-
},
|
|
33
|
-
async *[Symbol.asyncIterator]() {
|
|
34
|
-
const gen$1 = generatorFn();
|
|
35
|
-
let result = await gen$1.next();
|
|
36
|
-
while (!result.done) {
|
|
37
|
-
const injected = yield result.value;
|
|
38
|
-
result = await gen$1.next(injected);
|
|
39
|
-
}
|
|
40
|
-
return result.value;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
return {
|
|
44
|
-
_tag: "SyncFx",
|
|
45
|
-
run: () => {
|
|
46
|
-
const result = generatorFn().next();
|
|
47
|
-
if (result.done !== true) {
|
|
48
|
-
const yielded = result.value;
|
|
49
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") throw new Error(`Service "${yielded.serviceKey}" not provided. Use provide() to inject services.`);
|
|
50
|
-
return err(yielded);
|
|
51
|
-
}
|
|
52
|
-
return ok(result.value);
|
|
53
|
-
},
|
|
54
|
-
*[Symbol.iterator]() {
|
|
55
|
-
const gen$1 = generatorFn();
|
|
56
|
-
let result = gen$1.next();
|
|
57
|
-
while (!result.done) {
|
|
58
|
-
const injected = yield result.value;
|
|
59
|
-
result = gen$1.next(injected);
|
|
60
|
-
}
|
|
61
|
-
return result.value;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Implementation of Fx.fn.
|
|
67
|
-
*/
|
|
68
|
-
function fxFn(generatorFn, provider) {
|
|
69
|
-
const testGen = generatorFn();
|
|
70
|
-
const isAsync = Symbol.asyncIterator in testGen;
|
|
71
|
-
if (provider) if (isAsync) return provider({
|
|
72
|
-
_tag: "AsyncFx",
|
|
73
|
-
run: async () => {
|
|
74
|
-
throw new Error("Should not be called directly - use provider");
|
|
75
|
-
},
|
|
76
|
-
async *[Symbol.asyncIterator]() {
|
|
77
|
-
const gen$1 = generatorFn();
|
|
78
|
-
let result$1 = await gen$1.next();
|
|
79
|
-
while (!result$1.done) {
|
|
80
|
-
const injected = yield result$1.value;
|
|
81
|
-
result$1 = await gen$1.next(injected);
|
|
82
|
-
}
|
|
83
|
-
return result$1.value;
|
|
84
|
-
}
|
|
85
|
-
}).run();
|
|
86
|
-
else return provider({
|
|
87
|
-
_tag: "SyncFx",
|
|
88
|
-
run: () => {
|
|
89
|
-
throw new Error("Should not be called directly - use provider");
|
|
90
|
-
},
|
|
91
|
-
*[Symbol.iterator]() {
|
|
92
|
-
const gen$1 = generatorFn();
|
|
93
|
-
let result$1 = gen$1.next();
|
|
94
|
-
while (!result$1.done) {
|
|
95
|
-
const injected = yield result$1.value;
|
|
96
|
-
result$1 = gen$1.next(injected);
|
|
97
|
-
}
|
|
98
|
-
return result$1.value;
|
|
99
|
-
}
|
|
100
|
-
}).run();
|
|
101
|
-
if (isAsync) return (async () => {
|
|
102
|
-
let result$1 = await generatorFn().next();
|
|
103
|
-
while (!result$1.done) return err(result$1.value);
|
|
104
|
-
return ok(result$1.value);
|
|
105
|
-
})();
|
|
106
|
-
let result = generatorFn().next();
|
|
107
|
-
while (!result.done) return err(result.value);
|
|
108
|
-
return ok(result.value);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Convenience alias for Result.ok.
|
|
112
|
-
* Creates a successful Result that can be yielded in an Fx computation.
|
|
113
|
-
*
|
|
114
|
-
* @param value - The success value
|
|
115
|
-
* @returns Result<T, never>
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```ts
|
|
119
|
-
* const workflow = Fx.gen(function* () {
|
|
120
|
-
* const value = yield* Fx.ok(42)
|
|
121
|
-
* return value * 2
|
|
122
|
-
* })
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
const fxOk = ok;
|
|
126
|
-
/**
|
|
127
|
-
* Convenience alias for Result.err.
|
|
128
|
-
* Creates an error Result that can be yielded in an Fx computation.
|
|
129
|
-
*
|
|
130
|
-
* @param error - The error value
|
|
131
|
-
* @returns Result<never, E>
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* ```ts
|
|
135
|
-
* const workflow = Fx.gen(function* () {
|
|
136
|
-
* const config = yield* Config
|
|
137
|
-
*
|
|
138
|
-
* if (!config.dbUrl) {
|
|
139
|
-
* return yield* Fx.err(new ValidationError({ field: "dbUrl" }))
|
|
140
|
-
* }
|
|
141
|
-
*
|
|
142
|
-
* return config.dbUrl
|
|
143
|
-
* })
|
|
144
|
-
* ```
|
|
145
|
-
*/
|
|
146
|
-
const fxErr = err;
|
|
147
|
-
/**
|
|
148
|
-
* Fx namespace containing utilities for creating and running effectful computations.
|
|
149
|
-
*
|
|
150
|
-
* Fx provides a minimal API inspired by Effect.ts:
|
|
151
|
-
* - `Fx.gen()` - Create composable computations with service dependencies
|
|
152
|
-
* - `Fx.fn()` - Execute computations immediately
|
|
153
|
-
* - `Fx.ok()` - Create successful results (alias for Result.ok)
|
|
154
|
-
* - `Fx.err()` - Create error results (alias for Result.err)
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```ts
|
|
158
|
-
* import { Fx, Service, Layer, provide, pipe } from "@repo/std"
|
|
159
|
-
*
|
|
160
|
-
* // Define services
|
|
161
|
-
* class Config extends Service<Config>()("Config") {
|
|
162
|
-
* readonly dbUrl!: string
|
|
163
|
-
* }
|
|
164
|
-
*
|
|
165
|
-
* class Logger extends Service<Logger>()("Logger") {
|
|
166
|
-
* readonly info!: (msg: string) => void
|
|
167
|
-
* }
|
|
168
|
-
*
|
|
169
|
-
* // Create layers
|
|
170
|
-
* const ConfigLive = Layer.ok(Config, { dbUrl: "postgres://..." })
|
|
171
|
-
* const LoggerLive = Layer.fx(Logger)(
|
|
172
|
-
* Fx.gen(function* () {
|
|
173
|
-
* const config = yield* Config
|
|
174
|
-
* return { info: (msg) => console.log(`[${config.dbUrl}] ${msg}`) }
|
|
175
|
-
* })
|
|
176
|
-
* )
|
|
177
|
-
*
|
|
178
|
-
* // Create workflow
|
|
179
|
-
* const myWorkflow = Fx.gen(function* () {
|
|
180
|
-
* const logger = yield* Logger
|
|
181
|
-
* logger.info("Hello from Fx!")
|
|
182
|
-
* return "done"
|
|
183
|
-
* })
|
|
184
|
-
*
|
|
185
|
-
* // Compose and run
|
|
186
|
-
* const AppLayer = pipe(ConfigLive, Layer.provide(LoggerLive))
|
|
187
|
-
* const result = pipe(myWorkflow, provide(AppLayer)).run()
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
const Fx = {
|
|
191
|
-
gen: fxGen,
|
|
192
|
-
fn: fxFn,
|
|
193
|
-
ok: fxOk,
|
|
194
|
-
err: fxErr
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
//#endregion
|
|
198
|
-
//#region src/fx/service.ts
|
|
199
|
-
/**
|
|
200
|
-
* Define a service with a unique key.
|
|
201
|
-
* The returned class acts as both a type and a runtime tag for lookup.
|
|
202
|
-
*
|
|
203
|
-
* Usage follows a double-invocation pattern:
|
|
204
|
-
* - First call provides the Self type parameter
|
|
205
|
-
* - Second call provides the unique key
|
|
206
|
-
*
|
|
207
|
-
* @example
|
|
208
|
-
* ```ts
|
|
209
|
-
* class Config extends Service<Config>()("Config") {
|
|
210
|
-
* readonly dbUrl!: string
|
|
211
|
-
* readonly logLevel!: "debug" | "info" | "error"
|
|
212
|
-
* }
|
|
213
|
-
*
|
|
214
|
-
* class Logger extends Service<Logger>()("Logger") {
|
|
215
|
-
* readonly info!: (msg: string) => void
|
|
216
|
-
* readonly error!: (msg: string) => void
|
|
217
|
-
* }
|
|
218
|
-
*
|
|
219
|
-
* // Use in Fx.gen:
|
|
220
|
-
* const workflow = Fx.gen(function* () {
|
|
221
|
-
* const config = yield* Config
|
|
222
|
-
* const logger = yield* Logger
|
|
223
|
-
* logger.info(`DB URL: ${config.dbUrl}`)
|
|
224
|
-
* })
|
|
225
|
-
* ```
|
|
226
|
-
*/
|
|
227
|
-
function Service() {
|
|
228
|
-
return (key) => {
|
|
229
|
-
const ServiceBase = class {
|
|
230
|
-
static _tag = "Service";
|
|
231
|
-
static key = key;
|
|
232
|
-
static _Self = void 0;
|
|
233
|
-
/**
|
|
234
|
-
* Yielding the class returns a ServiceRequest.
|
|
235
|
-
* The runtime intercepts this and provides the actual service instance.
|
|
236
|
-
*/
|
|
237
|
-
static *[Symbol.iterator]() {
|
|
238
|
-
return yield {
|
|
239
|
-
_tag: "ServiceRequest",
|
|
240
|
-
_service: void 0,
|
|
241
|
-
serviceKey: key
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
return ServiceBase;
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Create a service tag without class syntax.
|
|
250
|
-
* Useful for simple services that don't need class inheritance.
|
|
251
|
-
*
|
|
252
|
-
* @example
|
|
253
|
-
* ```ts
|
|
254
|
-
* interface ConfigService {
|
|
255
|
-
* readonly dbUrl: string
|
|
256
|
-
* readonly logLevel: "debug" | "info" | "error"
|
|
257
|
-
* }
|
|
258
|
-
*
|
|
259
|
-
* const Config = serviceTag<ConfigService>("Config")
|
|
260
|
-
*
|
|
261
|
-
* // Use in Fx.gen:
|
|
262
|
-
* const workflow = Fx.gen(function* () {
|
|
263
|
-
* const config = yield* Config
|
|
264
|
-
* console.log(config.dbUrl)
|
|
265
|
-
* })
|
|
266
|
-
* ```
|
|
267
|
-
*/
|
|
268
|
-
function serviceTag(key) {
|
|
269
|
-
return {
|
|
270
|
-
_tag: "Service",
|
|
271
|
-
key,
|
|
272
|
-
_Self: void 0,
|
|
273
|
-
*[Symbol.iterator]() {
|
|
274
|
-
return yield {
|
|
275
|
-
_tag: "ServiceRequest",
|
|
276
|
-
_service: void 0,
|
|
277
|
-
serviceKey: key
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
//#endregion
|
|
284
|
-
//#region src/fx/context.ts
|
|
285
|
-
/**
|
|
286
|
-
* Create an empty context with no services.
|
|
287
|
-
*/
|
|
288
|
-
const empty = () => ({
|
|
289
|
-
_tag: "Context",
|
|
290
|
-
_services: /* @__PURE__ */ new Map(),
|
|
291
|
-
_Services: void 0
|
|
292
|
-
});
|
|
293
|
-
/**
|
|
294
|
-
* Create a context with a single service.
|
|
295
|
-
*
|
|
296
|
-
* @param service - The service class (tag)
|
|
297
|
-
* @param impl - The service implementation
|
|
298
|
-
* @returns A context containing the service
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* ```ts
|
|
302
|
-
* const ctx = Context.make(Config, { dbUrl: "postgres://...", logLevel: "info" })
|
|
303
|
-
* ```
|
|
304
|
-
*/
|
|
305
|
-
const make = (service, impl) => ({
|
|
306
|
-
_tag: "Context",
|
|
307
|
-
_services: new Map([[service.key, impl]]),
|
|
308
|
-
_Services: void 0
|
|
309
|
-
});
|
|
310
|
-
/**
|
|
311
|
-
* Add a service to an existing context (returns new context).
|
|
312
|
-
* Curried for use with pipe.
|
|
313
|
-
*
|
|
314
|
-
* @param service - The service class (tag)
|
|
315
|
-
* @param impl - The service implementation
|
|
316
|
-
* @returns A function that takes a context and returns a new context with the service added
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```ts
|
|
320
|
-
* const ctx = pipe(
|
|
321
|
-
* Context.empty(),
|
|
322
|
-
* Context.add(Config, configImpl),
|
|
323
|
-
* Context.add(Logger, loggerImpl),
|
|
324
|
-
* )
|
|
325
|
-
* ```
|
|
326
|
-
*/
|
|
327
|
-
const add = (service, impl) => (ctx) => ({
|
|
328
|
-
_tag: "Context",
|
|
329
|
-
_services: new Map([...ctx._services, [service.key, impl]]),
|
|
330
|
-
_Services: void 0
|
|
331
|
-
});
|
|
332
|
-
/**
|
|
333
|
-
* Merge two contexts together.
|
|
334
|
-
* If both contexts have the same service, the second context's implementation wins.
|
|
335
|
-
*
|
|
336
|
-
* @param a - First context
|
|
337
|
-
* @param b - Second context
|
|
338
|
-
* @returns A new context with services from both
|
|
339
|
-
*
|
|
340
|
-
* @example
|
|
341
|
-
* ```ts
|
|
342
|
-
* const ctx = Context.merge(configContext, loggerContext)
|
|
343
|
-
* ```
|
|
344
|
-
*/
|
|
345
|
-
const merge = (a, b) => ({
|
|
346
|
-
_tag: "Context",
|
|
347
|
-
_services: new Map([...a._services, ...b._services]),
|
|
348
|
-
_Services: void 0
|
|
349
|
-
});
|
|
350
|
-
function get(ctxOrService, maybeService) {
|
|
351
|
-
if (maybeService === void 0) {
|
|
352
|
-
const service$1 = ctxOrService;
|
|
353
|
-
return (ctx$1) => {
|
|
354
|
-
const impl$1 = ctx$1._services.get(service$1.key);
|
|
355
|
-
if (impl$1 === void 0) throw new Error(`Service "${service$1.key}" not found in context. Available services: [${[...ctx$1._services.keys()].join(", ")}]`);
|
|
356
|
-
return impl$1;
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
const ctx = ctxOrService;
|
|
360
|
-
const service = maybeService;
|
|
361
|
-
const impl = ctx._services.get(service.key);
|
|
362
|
-
if (impl === void 0) throw new Error(`Service "${service.key}" not found in context. Available services: [${[...ctx._services.keys()].join(", ")}]`);
|
|
363
|
-
return impl;
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Unsafely get a service from a context by key string.
|
|
367
|
-
* Used internally by the runtime when resolving ServiceRequests.
|
|
368
|
-
* Returns undefined if not found (caller should handle).
|
|
369
|
-
*/
|
|
370
|
-
const unsafeGet = (ctx, key) => ctx._services.get(key);
|
|
371
|
-
/**
|
|
372
|
-
* Check if a context contains a specific service.
|
|
373
|
-
*
|
|
374
|
-
* @param ctx - The context to check
|
|
375
|
-
* @param service - The service class (tag)
|
|
376
|
-
* @returns true if the service is in the context
|
|
377
|
-
*/
|
|
378
|
-
const has = (ctx, service) => ctx._services.has(service.key);
|
|
379
|
-
/**
|
|
380
|
-
* Get all service keys in a context.
|
|
381
|
-
*/
|
|
382
|
-
const keys = (ctx) => [...ctx._services.keys()];
|
|
383
|
-
/**
|
|
384
|
-
* Get the size (number of services) in a context.
|
|
385
|
-
*/
|
|
386
|
-
const size = (ctx) => ctx._services.size;
|
|
387
|
-
/**
|
|
388
|
-
* Check if a value is a Context.
|
|
389
|
-
*/
|
|
390
|
-
const isContext = (value) => typeof value === "object" && value !== null && "_tag" in value && value._tag === "Context";
|
|
391
|
-
/**
|
|
392
|
-
* Context namespace containing utilities for managing service contexts.
|
|
393
|
-
*
|
|
394
|
-
* A Context is an immutable map of services that can be provided to Fx computations.
|
|
395
|
-
* Services are identified by their unique keys.
|
|
396
|
-
*
|
|
397
|
-
* @example
|
|
398
|
-
* ```ts
|
|
399
|
-
* import { Context, Service } from "@repo/std"
|
|
400
|
-
*
|
|
401
|
-
* class Config extends Service<Config>()("Config") {
|
|
402
|
-
* readonly dbUrl!: string
|
|
403
|
-
* }
|
|
404
|
-
*
|
|
405
|
-
* class Logger extends Service<Logger>()("Logger") {
|
|
406
|
-
* readonly info!: (msg: string) => void
|
|
407
|
-
* }
|
|
408
|
-
*
|
|
409
|
-
* // Create a context with services
|
|
410
|
-
* const ctx = pipe(
|
|
411
|
-
* Context.empty(),
|
|
412
|
-
* Context.add(Config, { dbUrl: "postgres://..." }),
|
|
413
|
-
* Context.add(Logger, { info: console.log }),
|
|
414
|
-
* )
|
|
415
|
-
*
|
|
416
|
-
* // Or use make and merge
|
|
417
|
-
* const configCtx = Context.make(Config, { dbUrl: "postgres://..." })
|
|
418
|
-
* const loggerCtx = Context.make(Logger, { info: console.log })
|
|
419
|
-
* const fullCtx = Context.merge(configCtx, loggerCtx)
|
|
420
|
-
* ```
|
|
421
|
-
*/
|
|
422
|
-
const Context = {
|
|
423
|
-
empty,
|
|
424
|
-
make,
|
|
425
|
-
add,
|
|
426
|
-
merge,
|
|
427
|
-
get,
|
|
428
|
-
unsafeGet,
|
|
429
|
-
has,
|
|
430
|
-
keys,
|
|
431
|
-
size,
|
|
432
|
-
isContext
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
//#endregion
|
|
436
|
-
//#region src/fx/layer.ts
|
|
437
|
-
/**
|
|
438
|
-
* Create a layer from a synchronous value (no dependencies).
|
|
439
|
-
*/
|
|
440
|
-
const layerOk = (service, impl) => ({
|
|
441
|
-
_tag: "Layer",
|
|
442
|
-
_ROut: void 0,
|
|
443
|
-
_E: void 0,
|
|
444
|
-
_RIn: void 0,
|
|
445
|
-
build: () => ({
|
|
446
|
-
_tag: "SyncFx",
|
|
447
|
-
run: () => ok(Context.make(service, impl)),
|
|
448
|
-
*[Symbol.iterator]() {
|
|
449
|
-
return Context.make(service, impl);
|
|
450
|
-
}
|
|
451
|
-
})
|
|
452
|
-
});
|
|
453
|
-
/**
|
|
454
|
-
* Create a layer that always fails with an error.
|
|
455
|
-
*/
|
|
456
|
-
const layerErr = (error) => ({
|
|
457
|
-
_tag: "Layer",
|
|
458
|
-
_ROut: void 0,
|
|
459
|
-
_E: void 0,
|
|
460
|
-
_RIn: void 0,
|
|
461
|
-
build: () => ({
|
|
462
|
-
_tag: "SyncFx",
|
|
463
|
-
run: () => ({
|
|
464
|
-
ok: false,
|
|
465
|
-
error,
|
|
466
|
-
*[Symbol.iterator]() {
|
|
467
|
-
yield error;
|
|
468
|
-
throw new Error("Unreachable");
|
|
469
|
-
}
|
|
470
|
-
}),
|
|
471
|
-
*[Symbol.iterator]() {
|
|
472
|
-
yield error;
|
|
473
|
-
throw new Error("Unreachable");
|
|
474
|
-
}
|
|
475
|
-
})
|
|
476
|
-
});
|
|
477
|
-
/**
|
|
478
|
-
* Create a layer from an Fx computation (can have dependencies).
|
|
479
|
-
*/
|
|
480
|
-
const layerFx = (service) => (fx) => ({
|
|
481
|
-
_tag: "Layer",
|
|
482
|
-
_ROut: void 0,
|
|
483
|
-
_E: void 0,
|
|
484
|
-
_RIn: void 0,
|
|
485
|
-
build: () => {
|
|
486
|
-
if (fx._tag === "AsyncFx") return {
|
|
487
|
-
_tag: "AsyncFx",
|
|
488
|
-
run: async () => {
|
|
489
|
-
throw new Error("Layer build should use iterator");
|
|
490
|
-
},
|
|
491
|
-
async *[Symbol.asyncIterator]() {
|
|
492
|
-
const gen$1 = fx[Symbol.asyncIterator]();
|
|
493
|
-
let result = await gen$1.next();
|
|
494
|
-
while (!result.done) {
|
|
495
|
-
const value = yield result.value;
|
|
496
|
-
result = await gen$1.next(value);
|
|
497
|
-
}
|
|
498
|
-
return Context.make(service, result.value);
|
|
499
|
-
}
|
|
500
|
-
};
|
|
501
|
-
return {
|
|
502
|
-
_tag: "SyncFx",
|
|
503
|
-
run: () => {
|
|
504
|
-
throw new Error("Layer build should use iterator");
|
|
505
|
-
},
|
|
506
|
-
*[Symbol.iterator]() {
|
|
507
|
-
const gen$1 = fx[Symbol.iterator]();
|
|
508
|
-
let result = gen$1.next();
|
|
509
|
-
while (!result.done) {
|
|
510
|
-
const value = yield result.value;
|
|
511
|
-
result = gen$1.next(value);
|
|
512
|
-
}
|
|
513
|
-
return Context.make(service, result.value);
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
/**
|
|
519
|
-
* Create a scoped layer (with resource cleanup).
|
|
520
|
-
*/
|
|
521
|
-
const layerScoped = (service) => (fx) => ({
|
|
522
|
-
_tag: "Layer",
|
|
523
|
-
_ROut: void 0,
|
|
524
|
-
_E: void 0,
|
|
525
|
-
_RIn: void 0,
|
|
526
|
-
build: (_memoMap, scope) => {
|
|
527
|
-
if (fx._tag === "AsyncFx") return {
|
|
528
|
-
_tag: "AsyncFx",
|
|
529
|
-
run: async () => {
|
|
530
|
-
throw new Error("Layer build should use iterator");
|
|
531
|
-
},
|
|
532
|
-
async *[Symbol.asyncIterator]() {
|
|
533
|
-
const gen$1 = fx[Symbol.asyncIterator]();
|
|
534
|
-
let result = await gen$1.next();
|
|
535
|
-
while (!result.done) {
|
|
536
|
-
const yielded = result.value;
|
|
537
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest" && yielded.serviceKey === "@std/Scope") result = await gen$1.next(scope);
|
|
538
|
-
else {
|
|
539
|
-
const value = yield yielded;
|
|
540
|
-
result = await gen$1.next(value);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
return Context.make(service, result.value);
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
return {
|
|
547
|
-
_tag: "SyncFx",
|
|
548
|
-
run: () => {
|
|
549
|
-
throw new Error("Layer build should use iterator");
|
|
550
|
-
},
|
|
551
|
-
*[Symbol.iterator]() {
|
|
552
|
-
const gen$1 = fx[Symbol.iterator]();
|
|
553
|
-
let result = gen$1.next();
|
|
554
|
-
while (!result.done) {
|
|
555
|
-
const yielded = result.value;
|
|
556
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest" && yielded.serviceKey === "@std/Scope") result = gen$1.next(scope);
|
|
557
|
-
else {
|
|
558
|
-
const value = yield yielded;
|
|
559
|
-
result = gen$1.next(value);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return Context.make(service, result.value);
|
|
563
|
-
}
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
/**
|
|
568
|
-
* Provide dependencies to a layer and merge outputs.
|
|
569
|
-
*/
|
|
570
|
-
const layerProvide = (deps) => (layer) => ({
|
|
571
|
-
_tag: "Layer",
|
|
572
|
-
_ROut: void 0,
|
|
573
|
-
_E: void 0,
|
|
574
|
-
_RIn: void 0,
|
|
575
|
-
build: (memoMap, scope) => {
|
|
576
|
-
const depsBuildFx = deps.build(memoMap, scope);
|
|
577
|
-
if (depsBuildFx._tag === "AsyncFx") return {
|
|
578
|
-
_tag: "AsyncFx",
|
|
579
|
-
run: async () => {
|
|
580
|
-
throw new Error("Layer build should use iterator");
|
|
581
|
-
},
|
|
582
|
-
async *[Symbol.asyncIterator]() {
|
|
583
|
-
const depsGen = depsBuildFx[Symbol.asyncIterator]();
|
|
584
|
-
let depsResult = await depsGen.next();
|
|
585
|
-
while (!depsResult.done) {
|
|
586
|
-
const value = yield depsResult.value;
|
|
587
|
-
depsResult = await depsGen.next(value);
|
|
588
|
-
}
|
|
589
|
-
const depsCtx = depsResult.value;
|
|
590
|
-
const layerBuildFx = layer.build(memoMap, scope);
|
|
591
|
-
if (layerBuildFx._tag === "AsyncFx") {
|
|
592
|
-
const layerGen$1 = layerBuildFx[Symbol.asyncIterator]();
|
|
593
|
-
let layerResult$1 = await layerGen$1.next();
|
|
594
|
-
while (!layerResult$1.done) {
|
|
595
|
-
const yielded = layerResult$1.value;
|
|
596
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
597
|
-
const service = depsCtx._services.get(yielded.serviceKey);
|
|
598
|
-
if (service !== void 0) {
|
|
599
|
-
layerResult$1 = await layerGen$1.next(service);
|
|
600
|
-
continue;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
const value = yield yielded;
|
|
604
|
-
layerResult$1 = await layerGen$1.next(value);
|
|
605
|
-
}
|
|
606
|
-
return Context.merge(depsCtx, layerResult$1.value);
|
|
607
|
-
}
|
|
608
|
-
const layerGen = layerBuildFx[Symbol.iterator]();
|
|
609
|
-
let layerResult = layerGen.next();
|
|
610
|
-
while (!layerResult.done) {
|
|
611
|
-
const yielded = layerResult.value;
|
|
612
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
613
|
-
const service = depsCtx._services.get(yielded.serviceKey);
|
|
614
|
-
if (service !== void 0) {
|
|
615
|
-
layerResult = layerGen.next(service);
|
|
616
|
-
continue;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
const value = yield yielded;
|
|
620
|
-
layerResult = layerGen.next(value);
|
|
621
|
-
}
|
|
622
|
-
return Context.merge(depsCtx, layerResult.value);
|
|
623
|
-
}
|
|
624
|
-
};
|
|
625
|
-
return {
|
|
626
|
-
_tag: "SyncFx",
|
|
627
|
-
run: () => {
|
|
628
|
-
throw new Error("Layer build should use iterator");
|
|
629
|
-
},
|
|
630
|
-
*[Symbol.iterator]() {
|
|
631
|
-
const depsGen = depsBuildFx[Symbol.iterator]();
|
|
632
|
-
let depsResult = depsGen.next();
|
|
633
|
-
while (!depsResult.done) {
|
|
634
|
-
const value = yield depsResult.value;
|
|
635
|
-
depsResult = depsGen.next(value);
|
|
636
|
-
}
|
|
637
|
-
const depsCtx = depsResult.value;
|
|
638
|
-
const layerBuildFx = layer.build(memoMap, scope);
|
|
639
|
-
if (layerBuildFx._tag === "SyncFx") {
|
|
640
|
-
const syncGen = layerBuildFx[Symbol.iterator]();
|
|
641
|
-
let layerResult = syncGen.next();
|
|
642
|
-
while (!layerResult.done) {
|
|
643
|
-
const yielded = layerResult.value;
|
|
644
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
645
|
-
const service = depsCtx._services.get(yielded.serviceKey);
|
|
646
|
-
if (service !== void 0) {
|
|
647
|
-
layerResult = syncGen.next(service);
|
|
648
|
-
continue;
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
const value = yield yielded;
|
|
652
|
-
layerResult = syncGen.next(value);
|
|
653
|
-
}
|
|
654
|
-
return Context.merge(depsCtx, layerResult.value);
|
|
655
|
-
}
|
|
656
|
-
throw new Error("Cannot use async layer in sync context");
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
});
|
|
661
|
-
/**
|
|
662
|
-
* Merge multiple layers with automatic dependency resolution.
|
|
663
|
-
*/
|
|
664
|
-
const layerMerge = (...layers) => ({
|
|
665
|
-
_tag: "Layer",
|
|
666
|
-
_ROut: void 0,
|
|
667
|
-
_E: void 0,
|
|
668
|
-
_RIn: void 0,
|
|
669
|
-
build: (memoMap, scope) => {
|
|
670
|
-
if (layers.some((l) => l.build(memoMap, scope)._tag === "AsyncFx")) return {
|
|
671
|
-
_tag: "AsyncFx",
|
|
672
|
-
run: async () => {
|
|
673
|
-
throw new Error("Layer build should use iterator");
|
|
674
|
-
},
|
|
675
|
-
async *[Symbol.asyncIterator]() {
|
|
676
|
-
let ctx = Context.empty();
|
|
677
|
-
for (const layer of layers) {
|
|
678
|
-
const buildFx = layer.build(memoMap, scope);
|
|
679
|
-
if (buildFx._tag === "AsyncFx") {
|
|
680
|
-
const gen$1 = buildFx[Symbol.asyncIterator]();
|
|
681
|
-
let result = await gen$1.next();
|
|
682
|
-
while (!result.done) {
|
|
683
|
-
const yielded = result.value;
|
|
684
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
685
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
686
|
-
if (service !== void 0) {
|
|
687
|
-
result = await gen$1.next(service);
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
const value = yield yielded;
|
|
692
|
-
result = await gen$1.next(value);
|
|
693
|
-
}
|
|
694
|
-
ctx = Context.merge(ctx, result.value);
|
|
695
|
-
} else {
|
|
696
|
-
const gen$1 = buildFx[Symbol.iterator]();
|
|
697
|
-
let result = gen$1.next();
|
|
698
|
-
while (!result.done) {
|
|
699
|
-
const yielded = result.value;
|
|
700
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
701
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
702
|
-
if (service !== void 0) {
|
|
703
|
-
result = gen$1.next(service);
|
|
704
|
-
continue;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
const value = yield yielded;
|
|
708
|
-
result = gen$1.next(value);
|
|
709
|
-
}
|
|
710
|
-
ctx = Context.merge(ctx, result.value);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
return ctx;
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
return {
|
|
717
|
-
_tag: "SyncFx",
|
|
718
|
-
run: () => {
|
|
719
|
-
throw new Error("Layer build should use iterator");
|
|
720
|
-
},
|
|
721
|
-
*[Symbol.iterator]() {
|
|
722
|
-
let ctx = Context.empty();
|
|
723
|
-
for (const layer of layers) {
|
|
724
|
-
const buildFx = layer.build(memoMap, scope);
|
|
725
|
-
if (buildFx._tag !== "SyncFx") throw new Error("Expected sync layer in sync context");
|
|
726
|
-
const gen$1 = buildFx[Symbol.iterator]();
|
|
727
|
-
let result = gen$1.next();
|
|
728
|
-
while (!result.done) {
|
|
729
|
-
const yielded = result.value;
|
|
730
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
731
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
732
|
-
if (service !== void 0) {
|
|
733
|
-
result = gen$1.next(service);
|
|
734
|
-
continue;
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
const value = yield yielded;
|
|
738
|
-
result = gen$1.next(value);
|
|
739
|
-
}
|
|
740
|
-
ctx = Context.merge(ctx, result.value);
|
|
741
|
-
}
|
|
742
|
-
return ctx;
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
});
|
|
747
|
-
const Layer = {
|
|
748
|
-
ok: layerOk,
|
|
749
|
-
err: layerErr,
|
|
750
|
-
fx: layerFx,
|
|
751
|
-
scoped: layerScoped,
|
|
752
|
-
provide: layerProvide,
|
|
753
|
-
merge: layerMerge
|
|
754
|
-
};
|
|
755
|
-
|
|
756
|
-
//#endregion
|
|
757
|
-
//#region src/fx/scope.ts
|
|
758
|
-
var ScopeTag = class extends Service()("@std/Scope") {};
|
|
759
|
-
/**
|
|
760
|
-
* Create a new Scope instance.
|
|
761
|
-
* This is the concrete implementation of the ScopeService interface.
|
|
762
|
-
*/
|
|
763
|
-
function createScope() {
|
|
764
|
-
const finalizers = [];
|
|
765
|
-
let closed = false;
|
|
766
|
-
const children = [];
|
|
767
|
-
return {
|
|
768
|
-
addFinalizer(finalizer) {
|
|
769
|
-
return {
|
|
770
|
-
_tag: "SyncFx",
|
|
771
|
-
get run() {
|
|
772
|
-
return (() => {
|
|
773
|
-
if (!closed) finalizers.push(finalizer);
|
|
774
|
-
return ok(void 0);
|
|
775
|
-
});
|
|
776
|
-
},
|
|
777
|
-
*[Symbol.iterator]() {
|
|
778
|
-
if (!closed) finalizers.push(finalizer);
|
|
779
|
-
}
|
|
780
|
-
};
|
|
781
|
-
},
|
|
782
|
-
close(exit) {
|
|
783
|
-
if (finalizers.some((f) => {
|
|
784
|
-
return f()._tag === "AsyncFx";
|
|
785
|
-
})) return {
|
|
786
|
-
_tag: "AsyncFx",
|
|
787
|
-
get run() {
|
|
788
|
-
return (async () => {
|
|
789
|
-
if (closed) return ok(void 0);
|
|
790
|
-
closed = true;
|
|
791
|
-
for (const child of [...children].toReversed()) {
|
|
792
|
-
const childClose = child.close(exit);
|
|
793
|
-
if (childClose._tag === "AsyncFx") await childClose.run();
|
|
794
|
-
else childClose.run();
|
|
795
|
-
}
|
|
796
|
-
const reversed = [...finalizers].toReversed();
|
|
797
|
-
for (const finalizer of reversed) {
|
|
798
|
-
const fx = finalizer();
|
|
799
|
-
if (fx._tag === "AsyncFx") await fx.run();
|
|
800
|
-
else fx.run();
|
|
801
|
-
}
|
|
802
|
-
return ok(void 0);
|
|
803
|
-
});
|
|
804
|
-
},
|
|
805
|
-
async *[Symbol.asyncIterator]() {
|
|
806
|
-
if (closed) return;
|
|
807
|
-
closed = true;
|
|
808
|
-
for (const child of [...children].toReversed()) {
|
|
809
|
-
const childClose = child.close(exit);
|
|
810
|
-
if (childClose._tag === "AsyncFx") await childClose.run();
|
|
811
|
-
else childClose.run();
|
|
812
|
-
}
|
|
813
|
-
const reversed = [...finalizers].toReversed();
|
|
814
|
-
for (const finalizer of reversed) {
|
|
815
|
-
const fx = finalizer();
|
|
816
|
-
if (fx._tag === "AsyncFx") await fx.run();
|
|
817
|
-
else fx.run();
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
};
|
|
821
|
-
return {
|
|
822
|
-
_tag: "SyncFx",
|
|
823
|
-
get run() {
|
|
824
|
-
return (() => {
|
|
825
|
-
if (closed) return ok(void 0);
|
|
826
|
-
closed = true;
|
|
827
|
-
for (const child of [...children].toReversed()) child.close(exit).run();
|
|
828
|
-
const reversed = [...finalizers].toReversed();
|
|
829
|
-
for (const finalizer of reversed) finalizer().run();
|
|
830
|
-
return ok(void 0);
|
|
831
|
-
});
|
|
832
|
-
},
|
|
833
|
-
*[Symbol.iterator]() {
|
|
834
|
-
if (closed) return;
|
|
835
|
-
closed = true;
|
|
836
|
-
for (const child of [...children].toReversed()) child.close(exit).run();
|
|
837
|
-
const reversed = [...finalizers].toReversed();
|
|
838
|
-
for (const finalizer of reversed) finalizer().run();
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
},
|
|
842
|
-
fork() {
|
|
843
|
-
const child = createScope();
|
|
844
|
-
children.push(child);
|
|
845
|
-
return child;
|
|
846
|
-
}
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
//#endregion
|
|
851
|
-
//#region src/fx/memo-map.ts
|
|
852
|
-
/**
|
|
853
|
-
* MemoMap caches built layers so each layer is only built once.
|
|
854
|
-
* Multiple dependents share the same service instance.
|
|
855
|
-
*
|
|
856
|
-
* This implements the "service singleton" pattern where a service
|
|
857
|
-
* is instantiated once and shared across all consumers.
|
|
858
|
-
*
|
|
859
|
-
* @example
|
|
860
|
-
* ```ts
|
|
861
|
-
* // Database is built once, shared by DocumentService and TeamService
|
|
862
|
-
* const AppLayer = Layer.merge(
|
|
863
|
-
* ConfigLive,
|
|
864
|
-
* LoggerLive,
|
|
865
|
-
* DatabaseLive, // Built once
|
|
866
|
-
* DocumentServiceLive, // Uses shared Database
|
|
867
|
-
* TeamServiceLive, // Uses same Database instance
|
|
868
|
-
* )
|
|
869
|
-
* ```
|
|
870
|
-
*/
|
|
871
|
-
var MemoMap = class {
|
|
872
|
-
cache = /* @__PURE__ */ new Map();
|
|
873
|
-
/**
|
|
874
|
-
* Get a cached context or build the layer if not cached.
|
|
875
|
-
*
|
|
876
|
-
* @param layer - The layer to get or build
|
|
877
|
-
* @param scope - The scope for resource management
|
|
878
|
-
* @param deps - Context containing the layer's dependencies
|
|
879
|
-
* @returns An Fx producing the layer's context
|
|
880
|
-
*/
|
|
881
|
-
getOrBuild(layer, scope, deps) {
|
|
882
|
-
const cached = this.cache.get(layer);
|
|
883
|
-
if (cached?.context) return {
|
|
884
|
-
_tag: "SyncFx",
|
|
885
|
-
run: () => ok(cached.context),
|
|
886
|
-
*[Symbol.iterator]() {
|
|
887
|
-
return cached.context;
|
|
888
|
-
}
|
|
889
|
-
};
|
|
890
|
-
if (cached?.promise) return {
|
|
891
|
-
_tag: "AsyncFx",
|
|
892
|
-
run: async () => {
|
|
893
|
-
return ok(await cached.promise);
|
|
894
|
-
},
|
|
895
|
-
async *[Symbol.asyncIterator]() {
|
|
896
|
-
return await cached.promise;
|
|
897
|
-
}
|
|
898
|
-
};
|
|
899
|
-
this.cache.set(layer, { building: true });
|
|
900
|
-
const buildFx = layer.build(this, scope);
|
|
901
|
-
const cacheRef = this.cache;
|
|
902
|
-
if (buildFx._tag === "AsyncFx") {
|
|
903
|
-
const buildPromise = (async () => {
|
|
904
|
-
const gen$1 = buildFx[Symbol.asyncIterator]();
|
|
905
|
-
let result = await gen$1.next();
|
|
906
|
-
while (!result.done) {
|
|
907
|
-
const yielded = result.value;
|
|
908
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
909
|
-
const service = deps._services.get(yielded.serviceKey);
|
|
910
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found during layer build`);
|
|
911
|
-
result = await gen$1.next(service);
|
|
912
|
-
} else throw yielded;
|
|
913
|
-
}
|
|
914
|
-
const ctx = result.value;
|
|
915
|
-
cacheRef.set(layer, { context: ctx });
|
|
916
|
-
return ctx;
|
|
917
|
-
})();
|
|
918
|
-
this.cache.set(layer, { promise: buildPromise });
|
|
919
|
-
return {
|
|
920
|
-
_tag: "AsyncFx",
|
|
921
|
-
run: async () => {
|
|
922
|
-
try {
|
|
923
|
-
return ok(await buildPromise);
|
|
924
|
-
} catch (e) {
|
|
925
|
-
return {
|
|
926
|
-
ok: false,
|
|
927
|
-
error: e,
|
|
928
|
-
*[Symbol.iterator]() {
|
|
929
|
-
yield e;
|
|
930
|
-
throw new Error("Unreachable");
|
|
931
|
-
}
|
|
932
|
-
};
|
|
933
|
-
}
|
|
934
|
-
},
|
|
935
|
-
async *[Symbol.asyncIterator]() {
|
|
936
|
-
try {
|
|
937
|
-
return await buildPromise;
|
|
938
|
-
} catch (e) {
|
|
939
|
-
yield e;
|
|
940
|
-
throw new Error("Unreachable", { cause: e });
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
return {
|
|
946
|
-
_tag: "SyncFx",
|
|
947
|
-
run: () => {
|
|
948
|
-
const gen$1 = buildFx[Symbol.iterator]();
|
|
949
|
-
let result = gen$1.next();
|
|
950
|
-
while (!result.done) {
|
|
951
|
-
const yielded = result.value;
|
|
952
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
953
|
-
const service = deps._services.get(yielded.serviceKey);
|
|
954
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found during layer build`);
|
|
955
|
-
result = gen$1.next(service);
|
|
956
|
-
} else return {
|
|
957
|
-
ok: false,
|
|
958
|
-
error: yielded,
|
|
959
|
-
*[Symbol.iterator]() {
|
|
960
|
-
yield yielded;
|
|
961
|
-
throw new Error("Unreachable");
|
|
962
|
-
}
|
|
963
|
-
};
|
|
964
|
-
}
|
|
965
|
-
const ctx = result.value;
|
|
966
|
-
cacheRef.set(layer, { context: ctx });
|
|
967
|
-
return ok(ctx);
|
|
968
|
-
},
|
|
969
|
-
*[Symbol.iterator]() {
|
|
970
|
-
const gen$1 = buildFx[Symbol.iterator]();
|
|
971
|
-
let result = gen$1.next();
|
|
972
|
-
while (!result.done) {
|
|
973
|
-
const yielded = result.value;
|
|
974
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
975
|
-
const service = deps._services.get(yielded.serviceKey);
|
|
976
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found during layer build`);
|
|
977
|
-
result = gen$1.next(service);
|
|
978
|
-
} else {
|
|
979
|
-
yield yielded;
|
|
980
|
-
throw new Error("Unreachable");
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
cacheRef.set(layer, { context: result.value });
|
|
984
|
-
return result.value;
|
|
985
|
-
}
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Clear the cache.
|
|
990
|
-
* Useful for testing.
|
|
991
|
-
*/
|
|
992
|
-
clear() {
|
|
993
|
-
this.cache.clear();
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* Get the number of cached layers.
|
|
997
|
-
*/
|
|
998
|
-
get size() {
|
|
999
|
-
return this.cache.size;
|
|
1000
|
-
}
|
|
1001
|
-
};
|
|
1002
|
-
|
|
1003
|
-
//#endregion
|
|
1004
|
-
//#region src/fx/provide.ts
|
|
1005
|
-
/**
|
|
1006
|
-
* Provide a layer to an Fx computation, resolving all service requirements.
|
|
1007
|
-
* Creates a new scope for resource management.
|
|
1008
|
-
*
|
|
1009
|
-
* @param layer - The layer providing services (must have no external requirements)
|
|
1010
|
-
* @returns A function that takes an Fx and returns an Fx with dependencies resolved
|
|
1011
|
-
*
|
|
1012
|
-
* @example
|
|
1013
|
-
* ```ts
|
|
1014
|
-
* const result = pipe(
|
|
1015
|
-
* updateDocumentWorkflow(userId, docId, data),
|
|
1016
|
-
* provide(AppLayer)
|
|
1017
|
-
* ).run()
|
|
1018
|
-
* ```
|
|
1019
|
-
*/
|
|
1020
|
-
const provide = (layer) => (fx) => {
|
|
1021
|
-
const memoMap = new MemoMap();
|
|
1022
|
-
const scope = createScope();
|
|
1023
|
-
const layerBuildFx = layer.build(memoMap, scope);
|
|
1024
|
-
if (layerBuildFx._tag === "AsyncFx" || fx._tag === "AsyncFx") return {
|
|
1025
|
-
_tag: "AsyncFx",
|
|
1026
|
-
get run() {
|
|
1027
|
-
return (async () => {
|
|
1028
|
-
try {
|
|
1029
|
-
let ctx;
|
|
1030
|
-
if (layerBuildFx._tag === "AsyncFx") {
|
|
1031
|
-
const gen$1 = layerBuildFx[Symbol.asyncIterator]();
|
|
1032
|
-
let result = await gen$1.next();
|
|
1033
|
-
while (!result.done) result = await gen$1.next(void 0);
|
|
1034
|
-
ctx = result.value;
|
|
1035
|
-
} else {
|
|
1036
|
-
const gen$1 = layerBuildFx[Symbol.iterator]();
|
|
1037
|
-
let result = gen$1.next();
|
|
1038
|
-
while (!result.done) result = gen$1.next(void 0);
|
|
1039
|
-
ctx = result.value;
|
|
1040
|
-
}
|
|
1041
|
-
if (fx._tag === "AsyncFx") {
|
|
1042
|
-
const fxGen$2 = fx[Symbol.asyncIterator]();
|
|
1043
|
-
let fxResult$1 = await fxGen$2.next();
|
|
1044
|
-
while (!fxResult$1.done) {
|
|
1045
|
-
const yielded = fxResult$1.value;
|
|
1046
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1047
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1048
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1049
|
-
fxResult$1 = await fxGen$2.next(service);
|
|
1050
|
-
} else return err(yielded);
|
|
1051
|
-
}
|
|
1052
|
-
return ok(fxResult$1.value);
|
|
1053
|
-
}
|
|
1054
|
-
const fxGen$1 = fx[Symbol.iterator]();
|
|
1055
|
-
let fxResult = fxGen$1.next();
|
|
1056
|
-
while (!fxResult.done) {
|
|
1057
|
-
const yielded = fxResult.value;
|
|
1058
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1059
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1060
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1061
|
-
fxResult = fxGen$1.next(service);
|
|
1062
|
-
} else return err(yielded);
|
|
1063
|
-
}
|
|
1064
|
-
return ok(fxResult.value);
|
|
1065
|
-
} finally {
|
|
1066
|
-
const closeResult = scope.close({
|
|
1067
|
-
_tag: "Success",
|
|
1068
|
-
value: void 0
|
|
1069
|
-
});
|
|
1070
|
-
if (closeResult._tag === "AsyncFx") await closeResult.run();
|
|
1071
|
-
else closeResult.run();
|
|
1072
|
-
}
|
|
1073
|
-
});
|
|
1074
|
-
},
|
|
1075
|
-
async *[Symbol.asyncIterator]() {
|
|
1076
|
-
try {
|
|
1077
|
-
let ctx;
|
|
1078
|
-
if (layerBuildFx._tag === "AsyncFx") {
|
|
1079
|
-
const gen$1 = layerBuildFx[Symbol.asyncIterator]();
|
|
1080
|
-
let result = await gen$1.next();
|
|
1081
|
-
while (!result.done) {
|
|
1082
|
-
yield result.value;
|
|
1083
|
-
result = await gen$1.next(void 0);
|
|
1084
|
-
}
|
|
1085
|
-
ctx = result.value;
|
|
1086
|
-
} else {
|
|
1087
|
-
const gen$1 = layerBuildFx[Symbol.iterator]();
|
|
1088
|
-
let result = gen$1.next();
|
|
1089
|
-
while (!result.done) {
|
|
1090
|
-
yield result.value;
|
|
1091
|
-
result = gen$1.next(void 0);
|
|
1092
|
-
}
|
|
1093
|
-
ctx = result.value;
|
|
1094
|
-
}
|
|
1095
|
-
if (fx._tag === "AsyncFx") {
|
|
1096
|
-
const fxGen$2 = fx[Symbol.asyncIterator]();
|
|
1097
|
-
let fxResult$1 = await fxGen$2.next();
|
|
1098
|
-
while (!fxResult$1.done) {
|
|
1099
|
-
const yielded = fxResult$1.value;
|
|
1100
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1101
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1102
|
-
if (service !== void 0) {
|
|
1103
|
-
fxResult$1 = await fxGen$2.next(service);
|
|
1104
|
-
continue;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
const value = yield yielded;
|
|
1108
|
-
fxResult$1 = await fxGen$2.next(value);
|
|
1109
|
-
}
|
|
1110
|
-
return fxResult$1.value;
|
|
1111
|
-
}
|
|
1112
|
-
const fxGen$1 = fx[Symbol.iterator]();
|
|
1113
|
-
let fxResult = fxGen$1.next();
|
|
1114
|
-
while (!fxResult.done) {
|
|
1115
|
-
const yielded = fxResult.value;
|
|
1116
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1117
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1118
|
-
if (service !== void 0) {
|
|
1119
|
-
fxResult = fxGen$1.next(service);
|
|
1120
|
-
continue;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
const value = yield yielded;
|
|
1124
|
-
fxResult = fxGen$1.next(value);
|
|
1125
|
-
}
|
|
1126
|
-
return fxResult.value;
|
|
1127
|
-
} finally {
|
|
1128
|
-
const closeResult = scope.close({
|
|
1129
|
-
_tag: "Success",
|
|
1130
|
-
value: void 0
|
|
1131
|
-
});
|
|
1132
|
-
if (closeResult._tag === "AsyncFx") await closeResult.run();
|
|
1133
|
-
else closeResult.run();
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
};
|
|
1137
|
-
return {
|
|
1138
|
-
_tag: "SyncFx",
|
|
1139
|
-
get run() {
|
|
1140
|
-
return (() => {
|
|
1141
|
-
try {
|
|
1142
|
-
const layerGen = layerBuildFx[Symbol.iterator]();
|
|
1143
|
-
let layerResult = layerGen.next();
|
|
1144
|
-
while (!layerResult.done) layerResult = layerGen.next(void 0);
|
|
1145
|
-
const ctx = layerResult.value;
|
|
1146
|
-
const fxGen$1 = fx[Symbol.iterator]();
|
|
1147
|
-
let fxResult = fxGen$1.next();
|
|
1148
|
-
while (!fxResult.done) {
|
|
1149
|
-
const yielded = fxResult.value;
|
|
1150
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1151
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1152
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1153
|
-
fxResult = fxGen$1.next(service);
|
|
1154
|
-
} else return err(yielded);
|
|
1155
|
-
}
|
|
1156
|
-
return ok(fxResult.value);
|
|
1157
|
-
} finally {
|
|
1158
|
-
scope.close({
|
|
1159
|
-
_tag: "Success",
|
|
1160
|
-
value: void 0
|
|
1161
|
-
}).run();
|
|
1162
|
-
}
|
|
1163
|
-
});
|
|
1164
|
-
},
|
|
1165
|
-
*[Symbol.iterator]() {
|
|
1166
|
-
try {
|
|
1167
|
-
const layerGen = layerBuildFx[Symbol.iterator]();
|
|
1168
|
-
let layerResult = layerGen.next();
|
|
1169
|
-
while (!layerResult.done) {
|
|
1170
|
-
yield layerResult.value;
|
|
1171
|
-
layerResult = layerGen.next(void 0);
|
|
1172
|
-
}
|
|
1173
|
-
const ctx = layerResult.value;
|
|
1174
|
-
const fxGen$1 = fx[Symbol.iterator]();
|
|
1175
|
-
let fxResult = fxGen$1.next();
|
|
1176
|
-
while (!fxResult.done) {
|
|
1177
|
-
const yielded = fxResult.value;
|
|
1178
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1179
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1180
|
-
if (service !== void 0) {
|
|
1181
|
-
fxResult = fxGen$1.next(service);
|
|
1182
|
-
continue;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
const value = yield yielded;
|
|
1186
|
-
fxResult = fxGen$1.next(value);
|
|
1187
|
-
}
|
|
1188
|
-
return fxResult.value;
|
|
1189
|
-
} finally {
|
|
1190
|
-
scope.close({
|
|
1191
|
-
_tag: "Success",
|
|
1192
|
-
value: void 0
|
|
1193
|
-
}).run();
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
};
|
|
1197
|
-
};
|
|
1198
|
-
/**
|
|
1199
|
-
* Provide a context directly to an Fx computation.
|
|
1200
|
-
*
|
|
1201
|
-
* @param ctx - The context containing services
|
|
1202
|
-
* @returns A function that takes an Fx and returns an Fx with dependencies resolved
|
|
1203
|
-
*
|
|
1204
|
-
* @example
|
|
1205
|
-
* ```ts
|
|
1206
|
-
* const ctx = Context.make(Config, configImpl)
|
|
1207
|
-
* const result = pipe(
|
|
1208
|
-
* myWorkflow,
|
|
1209
|
-
* provideContext(ctx)
|
|
1210
|
-
* ).run()
|
|
1211
|
-
* ```
|
|
1212
|
-
*/
|
|
1213
|
-
const provideContext = (ctx) => (fx) => {
|
|
1214
|
-
if (fx._tag === "AsyncFx") return {
|
|
1215
|
-
_tag: "AsyncFx",
|
|
1216
|
-
get run() {
|
|
1217
|
-
return (async () => {
|
|
1218
|
-
const gen$1 = fx[Symbol.asyncIterator]();
|
|
1219
|
-
let result = await gen$1.next();
|
|
1220
|
-
while (!result.done) {
|
|
1221
|
-
const yielded = result.value;
|
|
1222
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1223
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1224
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1225
|
-
result = await gen$1.next(service);
|
|
1226
|
-
} else return err(yielded);
|
|
1227
|
-
}
|
|
1228
|
-
return ok(result.value);
|
|
1229
|
-
});
|
|
1230
|
-
},
|
|
1231
|
-
async *[Symbol.asyncIterator]() {
|
|
1232
|
-
const gen$1 = fx[Symbol.asyncIterator]();
|
|
1233
|
-
let result = await gen$1.next();
|
|
1234
|
-
while (!result.done) {
|
|
1235
|
-
const yielded = result.value;
|
|
1236
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1237
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1238
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1239
|
-
result = await gen$1.next(service);
|
|
1240
|
-
} else {
|
|
1241
|
-
yield yielded;
|
|
1242
|
-
result = await gen$1.next(void 0);
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
return result.value;
|
|
1246
|
-
}
|
|
1247
|
-
};
|
|
1248
|
-
return {
|
|
1249
|
-
_tag: "SyncFx",
|
|
1250
|
-
get run() {
|
|
1251
|
-
return (() => {
|
|
1252
|
-
const gen$1 = fx[Symbol.iterator]();
|
|
1253
|
-
let result = gen$1.next();
|
|
1254
|
-
while (!result.done) {
|
|
1255
|
-
const yielded = result.value;
|
|
1256
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1257
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1258
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1259
|
-
result = gen$1.next(service);
|
|
1260
|
-
} else return err(yielded);
|
|
1261
|
-
}
|
|
1262
|
-
return ok(result.value);
|
|
1263
|
-
});
|
|
1264
|
-
},
|
|
1265
|
-
*[Symbol.iterator]() {
|
|
1266
|
-
const gen$1 = fx[Symbol.iterator]();
|
|
1267
|
-
let result = gen$1.next();
|
|
1268
|
-
while (!result.done) {
|
|
1269
|
-
const yielded = result.value;
|
|
1270
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") {
|
|
1271
|
-
const service = ctx._services.get(yielded.serviceKey);
|
|
1272
|
-
if (service === void 0) throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1273
|
-
result = gen$1.next(service);
|
|
1274
|
-
} else {
|
|
1275
|
-
yield yielded;
|
|
1276
|
-
result = gen$1.next(void 0);
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
return result.value;
|
|
1280
|
-
}
|
|
1281
|
-
};
|
|
1282
|
-
};
|
|
1283
|
-
/**
|
|
1284
|
-
* Provide a single service to an Fx computation.
|
|
1285
|
-
*
|
|
1286
|
-
* @param service - The service class (tag)
|
|
1287
|
-
* @param impl - The service implementation
|
|
1288
|
-
* @returns A function that takes an Fx and returns an Fx with the service provided
|
|
1289
|
-
*
|
|
1290
|
-
* @example
|
|
1291
|
-
* ```ts
|
|
1292
|
-
* const result = pipe(
|
|
1293
|
-
* myWorkflow,
|
|
1294
|
-
* provideService(Config, configImpl),
|
|
1295
|
-
* provideService(Logger, loggerImpl),
|
|
1296
|
-
* ).run()
|
|
1297
|
-
* ```
|
|
1298
|
-
*/
|
|
1299
|
-
const provideService = (service, impl) => (fx) => {
|
|
1300
|
-
if (fx._tag === "AsyncFx") return {
|
|
1301
|
-
_tag: "AsyncFx",
|
|
1302
|
-
get run() {
|
|
1303
|
-
return (async () => {
|
|
1304
|
-
const gen$1 = fx[Symbol.asyncIterator]();
|
|
1305
|
-
let result = await gen$1.next();
|
|
1306
|
-
while (!result.done) {
|
|
1307
|
-
const yielded = result.value;
|
|
1308
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest" && yielded.serviceKey === service.key) result = await gen$1.next(impl);
|
|
1309
|
-
else if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1310
|
-
else return err(yielded);
|
|
1311
|
-
}
|
|
1312
|
-
return ok(result.value);
|
|
1313
|
-
});
|
|
1314
|
-
},
|
|
1315
|
-
async *[Symbol.asyncIterator]() {
|
|
1316
|
-
const gen$1 = fx[Symbol.asyncIterator]();
|
|
1317
|
-
let result = await gen$1.next();
|
|
1318
|
-
while (!result.done) {
|
|
1319
|
-
const yielded = result.value;
|
|
1320
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest" && yielded.serviceKey === service.key) result = await gen$1.next(impl);
|
|
1321
|
-
else {
|
|
1322
|
-
const value = yield yielded;
|
|
1323
|
-
result = await gen$1.next(value);
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
return result.value;
|
|
1327
|
-
}
|
|
1328
|
-
};
|
|
1329
|
-
return {
|
|
1330
|
-
_tag: "SyncFx",
|
|
1331
|
-
get run() {
|
|
1332
|
-
return (() => {
|
|
1333
|
-
const gen$1 = fx[Symbol.iterator]();
|
|
1334
|
-
let result = gen$1.next();
|
|
1335
|
-
while (!result.done) {
|
|
1336
|
-
const yielded = result.value;
|
|
1337
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest" && yielded.serviceKey === service.key) result = gen$1.next(impl);
|
|
1338
|
-
else if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest") throw new Error(`Service "${yielded.serviceKey}" not found`);
|
|
1339
|
-
else return err(yielded);
|
|
1340
|
-
}
|
|
1341
|
-
return ok(result.value);
|
|
1342
|
-
});
|
|
1343
|
-
},
|
|
1344
|
-
*[Symbol.iterator]() {
|
|
1345
|
-
const gen$1 = fx[Symbol.iterator]();
|
|
1346
|
-
let result = gen$1.next();
|
|
1347
|
-
while (!result.done) {
|
|
1348
|
-
const yielded = result.value;
|
|
1349
|
-
if (typeof yielded === "object" && yielded !== null && "_tag" in yielded && yielded._tag === "ServiceRequest" && yielded.serviceKey === service.key) result = gen$1.next(impl);
|
|
1350
|
-
else {
|
|
1351
|
-
const value = yield yielded;
|
|
1352
|
-
result = gen$1.next(value);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
return result.value;
|
|
1356
|
-
}
|
|
1357
|
-
};
|
|
1358
|
-
};
|
|
1359
|
-
|
|
1360
|
-
//#endregion
|
|
1361
|
-
//#region src/std.ts
|
|
1362
|
-
/**
|
|
1363
|
-
* Main Std namespace containing all utility functions and types.
|
|
1364
|
-
*/
|
|
1365
|
-
const Std = {
|
|
1366
|
-
array,
|
|
1367
|
-
data,
|
|
1368
|
-
flow,
|
|
1369
|
-
fn,
|
|
1370
|
-
gen,
|
|
1371
|
-
pipe,
|
|
1372
|
-
record,
|
|
1373
|
-
struct,
|
|
1374
|
-
tagged,
|
|
1375
|
-
tuple,
|
|
1376
|
-
...Result,
|
|
1377
|
-
Option,
|
|
1378
|
-
Either,
|
|
1379
|
-
Err,
|
|
1380
|
-
TaggedError,
|
|
1381
|
-
Predicate,
|
|
1382
|
-
Brand,
|
|
1383
|
-
Fx,
|
|
1384
|
-
Service,
|
|
1385
|
-
Layer,
|
|
1386
|
-
Context,
|
|
1387
|
-
Scope: ScopeTag,
|
|
1388
|
-
provide
|
|
1389
|
-
};
|
|
1390
|
-
|
|
1391
|
-
//#endregion
|
|
1392
|
-
export { Brand, Context, Either, Err, Fx, Layer, Option, Predicate, Result, ScopeTag as Scope, Service, Std, TaggedError, array, data, ensure, ensureRefinement, flow, fn, gen, pipe, provide, provideContext, provideService, record, serviceTag, struct, tagged, tuple };
|
|
1393
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
import{t as e}from"./pipeable-rQvolRqh.mjs";import{t}from"./flow-CxKQ5yac.mjs";import{t as n}from"./result-B68pxC7l.mjs";import{n as r,r as i}from"./adt-DZmVJG4P.mjs";import{t as a}from"./brand-BUqMmkzC.mjs";import{i as o,n as s,r as c,t as l}from"./data-DzqKBCQg.mjs";import{t as u}from"./option-Qiv7Ls7L.mjs";import{t as d}from"./either-BDY9T5oz.mjs";import{n as f,t as p}from"./err-CYs4b1RV.mjs";import"./flow/index.mjs";import{t as m}from"./pipe-BROILDeC.mjs";import{t as h}from"./predicate-DvXnfmeJ.mjs";import{b as g,c as _,f as v,l as y,n as b,o as x,p as S,r as C,t as w,u as T}from"./fx-C4UuWCqP.mjs";export{a as Brand,y as Context,d as Either,p as Err,g as Exit,S as Fx,_ as Layer,u as Option,h as Predicate,n as Result,x as Scope,T as Service,f as TaggedError,l as array,r as data,t as flow,m as pipe,e as pipeMethod,w as provide,b as provideContext,C as provideService,i as record,v as serviceTag,c as struct,o as tagged,s as tuple};
|