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