effect 2.4.0 → 2.4.2

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 (103) hide show
  1. package/dist/cjs/Context.js.map +1 -1
  2. package/dist/cjs/Duration.js +9 -1
  3. package/dist/cjs/Duration.js.map +1 -1
  4. package/dist/cjs/Effect.js +83 -5
  5. package/dist/cjs/Effect.js.map +1 -1
  6. package/dist/cjs/Either.js.map +1 -1
  7. package/dist/cjs/FiberMap.js +31 -5
  8. package/dist/cjs/FiberMap.js.map +1 -1
  9. package/dist/cjs/FiberSet.js +31 -5
  10. package/dist/cjs/FiberSet.js.map +1 -1
  11. package/dist/cjs/Logger.js +50 -1
  12. package/dist/cjs/Logger.js.map +1 -1
  13. package/dist/cjs/Option.js.map +1 -1
  14. package/dist/cjs/Predicate.js +40 -3
  15. package/dist/cjs/Predicate.js.map +1 -1
  16. package/dist/cjs/Request.js +4 -4
  17. package/dist/cjs/SortedSet.js +7 -1
  18. package/dist/cjs/SortedSet.js.map +1 -1
  19. package/dist/cjs/Struct.js +7 -6
  20. package/dist/cjs/Struct.js.map +1 -1
  21. package/dist/cjs/internal/core-effect.js.map +1 -1
  22. package/dist/cjs/internal/fiberRuntime.js +26 -1
  23. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  24. package/dist/cjs/internal/logger.js +64 -2
  25. package/dist/cjs/internal/logger.js.map +1 -1
  26. package/dist/cjs/internal/version.js +1 -1
  27. package/dist/dts/Context.d.ts +10 -11
  28. package/dist/dts/Context.d.ts.map +1 -1
  29. package/dist/dts/Duration.d.ts +1 -1
  30. package/dist/dts/Duration.d.ts.map +1 -1
  31. package/dist/dts/Effect.d.ts +55 -15
  32. package/dist/dts/Effect.d.ts.map +1 -1
  33. package/dist/dts/Either.d.ts +18 -3
  34. package/dist/dts/Either.d.ts.map +1 -1
  35. package/dist/dts/FiberMap.d.ts +22 -2
  36. package/dist/dts/FiberMap.d.ts.map +1 -1
  37. package/dist/dts/FiberSet.d.ts +20 -0
  38. package/dist/dts/FiberSet.d.ts.map +1 -1
  39. package/dist/dts/Logger.d.ts +61 -0
  40. package/dist/dts/Logger.d.ts.map +1 -1
  41. package/dist/dts/Option.d.ts +13 -3
  42. package/dist/dts/Option.d.ts.map +1 -1
  43. package/dist/dts/Predicate.d.ts +37 -2
  44. package/dist/dts/Predicate.d.ts.map +1 -1
  45. package/dist/dts/Request.d.ts +7 -7
  46. package/dist/dts/Request.d.ts.map +1 -1
  47. package/dist/dts/STM.d.ts +1 -1
  48. package/dist/dts/STM.d.ts.map +1 -1
  49. package/dist/dts/SortedSet.d.ts +6 -0
  50. package/dist/dts/SortedSet.d.ts.map +1 -1
  51. package/dist/dts/Struct.d.ts +18 -2
  52. package/dist/dts/Struct.d.ts.map +1 -1
  53. package/dist/dts/Types.d.ts +4 -0
  54. package/dist/dts/Types.d.ts.map +1 -1
  55. package/dist/dts/internal/logger.d.ts +1 -0
  56. package/dist/dts/internal/logger.d.ts.map +1 -1
  57. package/dist/esm/Context.js.map +1 -1
  58. package/dist/esm/Duration.js +9 -1
  59. package/dist/esm/Duration.js.map +1 -1
  60. package/dist/esm/Effect.js +78 -1
  61. package/dist/esm/Effect.js.map +1 -1
  62. package/dist/esm/Either.js.map +1 -1
  63. package/dist/esm/FiberMap.js +29 -4
  64. package/dist/esm/FiberMap.js.map +1 -1
  65. package/dist/esm/FiberSet.js +29 -4
  66. package/dist/esm/FiberSet.js.map +1 -1
  67. package/dist/esm/Logger.js +49 -0
  68. package/dist/esm/Logger.js.map +1 -1
  69. package/dist/esm/Option.js.map +1 -1
  70. package/dist/esm/Predicate.js +37 -2
  71. package/dist/esm/Predicate.js.map +1 -1
  72. package/dist/esm/Request.js +4 -4
  73. package/dist/esm/SortedSet.js +5 -0
  74. package/dist/esm/SortedSet.js.map +1 -1
  75. package/dist/esm/Struct.js +7 -4
  76. package/dist/esm/Struct.js.map +1 -1
  77. package/dist/esm/internal/core-effect.js.map +1 -1
  78. package/dist/esm/internal/fiberRuntime.js +25 -0
  79. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  80. package/dist/esm/internal/logger.js +61 -1
  81. package/dist/esm/internal/logger.js.map +1 -1
  82. package/dist/esm/internal/version.js +1 -1
  83. package/package.json +2 -2
  84. package/src/Context.ts +10 -11
  85. package/src/Duration.ts +17 -1
  86. package/src/Effect.ts +124 -22
  87. package/src/Either.ts +19 -3
  88. package/src/FiberMap.ts +44 -6
  89. package/src/FiberSet.ts +38 -4
  90. package/src/Logger.ts +77 -0
  91. package/src/Option.ts +14 -3
  92. package/src/Predicate.ts +39 -2
  93. package/src/Request.ts +7 -7
  94. package/src/STM.ts +1 -1
  95. package/src/SortedSet.ts +7 -0
  96. package/src/Struct.ts +40 -21
  97. package/src/Types.ts +5 -0
  98. package/src/internal/core-effect.ts +9 -9
  99. package/src/internal/core.ts +5 -5
  100. package/src/internal/fiberRuntime.ts +68 -0
  101. package/src/internal/logger.ts +76 -1
  102. package/src/internal/request.ts +2 -2
  103. package/src/internal/version.ts +1 -1
package/src/Logger.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * @since 2.0.0
3
3
  */
4
4
  import type * as Cause from "./Cause.js"
5
+ import type { DurationInput } from "./Duration.js"
5
6
  import type { Effect } from "./Effect.js"
6
7
  import type * as FiberId from "./FiberId.js"
7
8
  import type * as FiberRefs from "./FiberRefs.js"
@@ -158,6 +159,39 @@ export const map: {
158
159
  ): Logger<Message, Output2>
159
160
  } = internal.map
160
161
 
162
+ /**
163
+ * @since 2.0.0
164
+ * @category mapping
165
+ * @example
166
+ * import { Console, Effect, Logger } from "effect";
167
+ *
168
+ * const LoggerLive = Logger.replaceScoped(
169
+ * Logger.defaultLogger,
170
+ * Logger.logfmtLogger.pipe(
171
+ * Logger.batched("500 millis", (messages) =>
172
+ * Console.log("BATCH", messages.join("\n"))
173
+ * )
174
+ * )
175
+ * );
176
+ *
177
+ * Effect.gen(function* (_) {
178
+ * yield* _(Effect.log("one"));
179
+ * yield* _(Effect.log("two"));
180
+ * yield* _(Effect.log("three"));
181
+ * }).pipe(Effect.provide(LoggerLive), Effect.runFork);
182
+ */
183
+ export const batched: {
184
+ <Output, R>(
185
+ window: DurationInput,
186
+ f: (messages: Array<Types.NoInfer<Output>>) => Effect<void, never, R>
187
+ ): <Message>(self: Logger<Message, Output>) => Effect<Logger<Message, void>, never, R | Scope>
188
+ <Message, Output, R>(
189
+ self: Logger<Message, Output>,
190
+ window: DurationInput,
191
+ f: (messages: Array<Types.NoInfer<Output>>) => Effect<void, never, R>
192
+ ): Effect<Logger<Message, void>, never, Scope | R>
193
+ } = fiberRuntime.batchedLogger
194
+
161
195
  /**
162
196
  * A logger that does nothing in response to logging events.
163
197
  *
@@ -298,6 +332,12 @@ export const zipRight: {
298
332
  */
299
333
  export const defaultLogger: Logger<unknown, void> = fiberRuntime.defaultLogger
300
334
 
335
+ /**
336
+ * @since 2.0.0
337
+ * @category constructors
338
+ */
339
+ export const jsonLogger: Logger<unknown, string> = internal.jsonLogger
340
+
301
341
  /**
302
342
  * @since 2.0.0
303
343
  * @category constructors
@@ -310,20 +350,57 @@ export const logfmtLogger: Logger<unknown, string> = internal.logfmtLogger
310
350
  */
311
351
  export const stringLogger: Logger<unknown, string> = internal.stringLogger
312
352
 
353
+ /**
354
+ * @since 2.0.0
355
+ * @category constructors
356
+ */
357
+ export const structuredLogger: Logger<
358
+ unknown,
359
+ {
360
+ readonly logLevel: string
361
+ readonly fiberId: string
362
+ readonly timestamp: string
363
+ readonly message: unknown
364
+ readonly cause: string | undefined
365
+ readonly annotations: Record<string, unknown>
366
+ readonly spans: Record<string, number>
367
+ }
368
+ > = internal.structuredLogger
369
+
313
370
  /**
314
371
  * @since 2.0.0
315
372
  * @category constructors
316
373
  */
317
374
  export const tracerLogger: Logger<unknown, void> = fiberRuntime.tracerLogger
318
375
 
376
+ /**
377
+ * @since 2.0.0
378
+ * @category constructors
379
+ */
380
+ export const json: Layer.Layer<never> = replace(fiberRuntime.defaultLogger, fiberRuntime.jsonLogger)
381
+
319
382
  /**
320
383
  * @since 2.0.0
321
384
  * @category constructors
322
385
  */
323
386
  export const logFmt: Layer.Layer<never> = replace(fiberRuntime.defaultLogger, fiberRuntime.logFmtLogger)
324
387
 
388
+ /**
389
+ * @since 2.0.0
390
+ * @category constructors
391
+ */
392
+ export const structured: Layer.Layer<never> = replace(fiberRuntime.defaultLogger, fiberRuntime.structuredLogger)
393
+
325
394
  /**
326
395
  * @since 2.0.0
327
396
  * @category context
328
397
  */
329
398
  export const minimumLogLevel: (level: LogLevel.LogLevel) => Layer.Layer<never> = circular.minimumLogLevel
399
+
400
+ /**
401
+ * Returns `true` if the specified value is a `Logger`, otherwise returns `false`.
402
+ *
403
+ * @since 1.0.0
404
+ * @category guards
405
+ */
406
+ export const isLogger: (u: unknown) => u is Logger<unknown, unknown> = internal.isLogger
package/src/Option.ts CHANGED
@@ -14,7 +14,7 @@ import type { Order } from "./Order.js"
14
14
  import * as order from "./Order.js"
15
15
  import type { Pipeable } from "./Pipeable.js"
16
16
  import type { Predicate, Refinement } from "./Predicate.js"
17
- import type { Covariant, NoInfer } from "./Types.js"
17
+ import type { Covariant, NoInfer, NotFunction } from "./Types.js"
18
18
  import type * as Unify from "./Unify.js"
19
19
  import * as Gen from "./Utils.js"
20
20
 
@@ -75,6 +75,17 @@ export interface OptionUnify<A extends { [Unify.typeSymbol]?: any }> {
75
75
  Option?: () => A[Unify.typeSymbol] extends Option<infer A0> | infer _ ? Option<A0> : never
76
76
  }
77
77
 
78
+ /**
79
+ * @since 2.0.0
80
+ */
81
+ export declare namespace Option {
82
+ /**
83
+ * @since 2.0.0
84
+ * @category type-level
85
+ */
86
+ export type Value<T extends Option<any>> = [T] extends [Option<infer _A>] ? _A : never
87
+ }
88
+
78
89
  /**
79
90
  * @category models
80
91
  * @since 2.0.0
@@ -649,11 +660,11 @@ export const andThen: {
649
660
  <A, B>(f: (a: A) => Option<B>): (self: Option<A>) => Option<B>
650
661
  <B>(f: Option<B>): <A>(self: Option<A>) => Option<B>
651
662
  <A, B>(f: (a: A) => B): (self: Option<A>) => Option<B>
652
- <B>(f: B): <A>(self: Option<A>) => Option<B>
663
+ <B>(f: NotFunction<B>): <A>(self: Option<A>) => Option<B>
653
664
  <A, B>(self: Option<A>, f: (a: A) => Option<B>): Option<B>
654
665
  <A, B>(self: Option<A>, f: Option<B>): Option<B>
655
666
  <A, B>(self: Option<A>, f: (a: A) => B): Option<B>
656
- <A, B>(self: Option<A>, f: B): Option<B>
667
+ <A, B>(self: Option<A>, f: NotFunction<B>): Option<B>
657
668
  } = dual(
658
669
  2,
659
670
  <A, B>(self: Option<A>, f: (a: A) => Option<B> | Option<B>): Option<B> =>
package/src/Predicate.ts CHANGED
@@ -53,6 +53,43 @@ export const mapInput: {
53
53
  <A, B>(self: Predicate<A>, f: (b: B) => A): Predicate<B>
54
54
  } = dual(2, <A, B>(self: Predicate<A>, f: (b: B) => A): Predicate<B> => (b) => self(f(b)))
55
55
 
56
+ /**
57
+ * Tests if a value is a `Set`.
58
+ *
59
+ * @param input - The value to test.
60
+ *
61
+ * @example
62
+ * import { isSet } from "effect/Predicate"
63
+ *
64
+ * assert.deepStrictEqual(isSet(new Set([1, 2])), true)
65
+ * assert.deepStrictEqual(isSet(new Set()), true)
66
+ * assert.deepStrictEqual(isSet({}), false)
67
+ * assert.deepStrictEqual(isSet(null), false)
68
+ * assert.deepStrictEqual(isSet(undefined), false)
69
+ *
70
+ * @category guards
71
+ * @since 2.0.0
72
+ */
73
+ export const isSet = (input: unknown): input is Set<unknown> => input instanceof Set
74
+
75
+ /**
76
+ * Tests if a value is a `Map`.
77
+ *
78
+ * @param input - The value to test.
79
+ *
80
+ * @example
81
+ * import { isMap } from "effect/Predicate"
82
+ *
83
+ * assert.deepStrictEqual(isMap(new Map()), true)
84
+ * assert.deepStrictEqual(isMap({}), false)
85
+ * assert.deepStrictEqual(isMap(null), false)
86
+ * assert.deepStrictEqual(isMap(undefined), false)
87
+ *
88
+ * @category guards
89
+ * @since 2.0.0
90
+ */
91
+ export const isMap = (input: unknown): input is Map<unknown, unknown> => input instanceof Map
92
+
56
93
  /**
57
94
  * Tests if a value is a `string`.
58
95
  *
@@ -192,7 +229,7 @@ export const isUndefined = (input: unknown): input is undefined => input === und
192
229
  export const isNotUndefined = <A>(input: A): input is Exclude<A, undefined> => input !== undefined
193
230
 
194
231
  /**
195
- * Tests if a value is `undefined`.
232
+ * Tests if a value is `null`.
196
233
  *
197
234
  * @param input - The value to test.
198
235
  *
@@ -210,7 +247,7 @@ export const isNotUndefined = <A>(input: A): input is Exclude<A, undefined> => i
210
247
  export const isNull = (input: unknown): input is null => input === null
211
248
 
212
249
  /**
213
- * Tests if a value is not `undefined`.
250
+ * Tests if a value is not `null`.
214
251
  *
215
252
  * @param input - The value to test.
216
253
  *
package/src/Request.ts CHANGED
@@ -57,7 +57,7 @@ export declare namespace Request {
57
57
  * @category models
58
58
  */
59
59
  export interface Constructor<R extends Request<any, any>, T extends keyof R = never> {
60
- (args: Omit<R, T | keyof (Request.Variance<Request.Error<R>, Request.Success<R>>)>): R
60
+ (args: Omit<R, T | keyof (Request.Variance<Request.Success<R>, Request.Error<R>>)>): R
61
61
  }
62
62
 
63
63
  /**
@@ -127,17 +127,17 @@ export const tagged: <R extends Request<any, any> & { _tag: string }>(
127
127
  * @example
128
128
  * import * as Request from "effect/Request"
129
129
  *
130
- * type Error = never
131
130
  * type Success = string
131
+ * type Error = never
132
132
  *
133
- * class MyRequest extends Request.Class<Error, Success, {
133
+ * class MyRequest extends Request.Class<Success, Error, {
134
134
  * readonly id: string
135
135
  * }> {}
136
136
  *
137
137
  * @since 2.0.0
138
138
  * @category constructors
139
139
  */
140
- export const Class: new<Error, Success, A extends Record<string, any>>(
140
+ export const Class: new<Success, Error, A extends Record<string, any>>(
141
141
  args: Types.Equals<Omit<A, keyof Request<unknown, unknown>>, {}> extends true ? void
142
142
  : { readonly [P in keyof A as P extends keyof Request<unknown, unknown> ? never : P]: A[P] }
143
143
  ) => Request<Success, Error> & Readonly<A> = internal.Class as any
@@ -148,10 +148,10 @@ export const Class: new<Error, Success, A extends Record<string, any>>(
148
148
  * @example
149
149
  * import * as Request from "effect/Request"
150
150
  *
151
- * type Error = never
152
151
  * type Success = string
152
+ * type Error = never
153
153
  *
154
- * class MyRequest extends Request.TaggedClass("MyRequest")<Error, Success, {
154
+ * class MyRequest extends Request.TaggedClass("MyRequest")<Success, Error, {
155
155
  * readonly name: string
156
156
  * }> {}
157
157
  *
@@ -160,7 +160,7 @@ export const Class: new<Error, Success, A extends Record<string, any>>(
160
160
  */
161
161
  export const TaggedClass: <Tag extends string>(
162
162
  tag: Tag
163
- ) => new<Error, Success, A extends Record<string, any>>(
163
+ ) => new<Success, Error, A extends Record<string, any>>(
164
164
  args: Types.Equals<Omit<A, keyof Request<unknown, unknown>>, {}> extends true ? void
165
165
  : { readonly [P in keyof A as P extends "_tag" | keyof Request<unknown, unknown> ? never : P]: A[P] }
166
166
  ) => Request<Success, Error> & Readonly<A> & { readonly _tag: Tag } = internal.TaggedClass as any
package/src/STM.ts CHANGED
@@ -103,7 +103,7 @@ export interface STMTypeLambda extends TypeLambda {
103
103
  * @category models
104
104
  */
105
105
  declare module "./Context.js" {
106
- interface Tag<Identifier, Service> extends STM<Service, never, Identifier> {}
106
+ interface Tag<Id, Value> extends STM<Value, never, Id> {}
107
107
  }
108
108
 
109
109
  /**
package/src/SortedSet.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * @since 2.0.0
3
3
  */
4
4
  import * as Equal from "./Equal.js"
5
+ import type * as Equivalence from "./Equivalence.js"
5
6
  import * as Dual from "./Function.js"
6
7
  import { pipe } from "./Function.js"
7
8
  import * as Hash from "./Hash.js"
@@ -381,3 +382,9 @@ export const union: {
381
382
  * @category getters
382
383
  */
383
384
  export const values = <A>(self: SortedSet<A>): IterableIterator<A> => RBT.keys(self.keyTree)
385
+
386
+ /**
387
+ * @since 2.0.0
388
+ * @category equivalence
389
+ */
390
+ export const getEquivalence = <A>(): Equivalence.Equivalence<SortedSet<A>> => (a, b) => isSubset(a, b) && isSubset(b, a)
package/src/Struct.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  import * as Equivalence from "./Equivalence.js"
8
8
  import { dual } from "./Function.js"
9
9
  import * as order from "./Order.js"
10
+ import * as Predicate from "./Predicate.js"
10
11
  import type { MatchRecord, Simplify } from "./Types.js"
11
12
 
12
13
  /**
@@ -17,23 +18,32 @@ import type { MatchRecord, Simplify } from "./Types.js"
17
18
  * import { pipe } from "effect/Function"
18
19
  *
19
20
  * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, pick("a", "b")), { a: "a", b: 1 })
21
+ * assert.deepStrictEqual(pick({ a: "a", b: 1, c: true }, "a", "b"), { a: "a", b: 1 })
20
22
  *
21
23
  * @since 2.0.0
22
24
  */
23
- export const pick = <Keys extends Array<PropertyKey>>(
24
- ...keys: Keys
25
- ) =>
26
- <S extends { [K in Keys[number]]?: any }>(
27
- s: S
28
- ): MatchRecord<S, { [K in Keys[number]]?: S[K] }, Simplify<Pick<S, Keys[number]>>> => {
29
- const out: any = {}
30
- for (const k of keys) {
31
- if (k in s) {
32
- out[k] = (s as any)[k]
25
+ export const pick: {
26
+ <Keys extends Array<PropertyKey>>(
27
+ ...keys: Keys
28
+ ): <S extends { [K in Keys[number]]?: any }>(
29
+ s: S
30
+ ) => MatchRecord<S, { [K in Keys[number]]?: S[K] }, Simplify<Pick<S, Keys[number]>>>
31
+ <S extends object, Keys extends Array<keyof S>>(
32
+ s: S,
33
+ ...keys: Keys
34
+ ): MatchRecord<S, { [K in Keys[number]]?: S[K] }, Simplify<Pick<S, Keys[number]>>>
35
+ } = dual(
36
+ (args) => Predicate.isObject(args[0]),
37
+ <S extends object, Keys extends Array<keyof S>>(s: S, ...keys: Keys) => {
38
+ const out: any = {}
39
+ for (const k of keys) {
40
+ if (k in s) {
41
+ out[k] = (s as any)[k]
42
+ }
33
43
  }
44
+ return out
34
45
  }
35
- return out
36
- }
46
+ )
37
47
 
38
48
  /**
39
49
  * Create a new object by omitting properties of an existing object.
@@ -43,19 +53,28 @@ export const pick = <Keys extends Array<PropertyKey>>(
43
53
  * import { pipe } from "effect/Function"
44
54
  *
45
55
  * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, omit("c")), { a: "a", b: 1 })
56
+ * assert.deepStrictEqual(omit({ a: "a", b: 1, c: true }, "c"), { a: "a", b: 1 })
46
57
  *
47
58
  * @since 2.0.0
48
59
  */
49
- export const omit = <Keys extends Array<PropertyKey>>(
50
- ...keys: Keys
51
- ) =>
52
- <S extends { [K in Keys[number]]?: any }>(s: S): Simplify<Omit<S, Keys[number]>> => {
53
- const out: any = { ...s }
54
- for (const k of keys) {
55
- delete out[k]
60
+ export const omit: {
61
+ <Keys extends Array<PropertyKey>>(
62
+ ...keys: Keys
63
+ ): <S extends { [K in Keys[number]]?: any }>(s: S) => Simplify<Omit<S, Keys[number]>>
64
+ <S extends object, Keys extends Array<keyof S>>(
65
+ s: S,
66
+ ...keys: Keys
67
+ ): Simplify<Omit<S, Keys[number]>>
68
+ } = dual(
69
+ (args) => Predicate.isObject(args[0]),
70
+ <S extends object, Keys extends Array<keyof S>>(s: S, ...keys: Keys) => {
71
+ const out: any = { ...s }
72
+ for (const k of keys) {
73
+ delete out[k]
74
+ }
75
+ return out
56
76
  }
57
- return out
58
- }
77
+ )
59
78
 
60
79
  /**
61
80
  * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct
package/src/Types.ts CHANGED
@@ -190,3 +190,8 @@ export type Contravariant<A> = (_: A) => void
190
190
  * @since 2.0.0
191
191
  */
192
192
  export type MatchRecord<S, onTrue, onFalse> = {} extends S ? onTrue : onFalse
193
+
194
+ /**
195
+ * @since 2.0.0
196
+ */
197
+ export type NotFunction<T> = T extends Function ? never : T
@@ -1871,10 +1871,10 @@ export const serviceFunction = <T extends Effect.Effect<any, any, any>, Args ext
1871
1871
  export const serviceFunctions = <S, SE, SR>(
1872
1872
  getService: Effect.Effect<S, SE, SR>
1873
1873
  ): {
1874
- [k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect.Effect<any, any, any> ? k : never }[keyof S]]:
1875
- S[k] extends (...args: infer Args) => Effect.Effect<infer A, infer E, infer R>
1876
- ? (...args: Args) => Effect.Effect<A, E | SE, R | SR>
1877
- : never
1874
+ [k in keyof S as S[k] extends (...args: Array<any>) => Effect.Effect<any, any, any> ? k : never]: S[k] extends
1875
+ (...args: infer Args) => Effect.Effect<infer A, infer E, infer R>
1876
+ ? (...args: Args) => Effect.Effect<A, E | SE, R | SR>
1877
+ : never
1878
1878
  } =>
1879
1879
  new Proxy({} as any, {
1880
1880
  get(_target: any, prop: any, _receiver) {
@@ -1899,10 +1899,10 @@ export const serviceConstants = <S, SE, SR>(
1899
1899
  /** @internal */
1900
1900
  export const serviceMembers = <S, SE, SR>(getService: Effect.Effect<S, SE, SR>): {
1901
1901
  functions: {
1902
- [k in { [k in keyof S]: S[k] extends (...args: Array<any>) => Effect.Effect<any, any, any> ? k : never }[keyof S]]:
1903
- S[k] extends (...args: infer Args) => Effect.Effect<infer A, infer E, infer R>
1904
- ? (...args: Args) => Effect.Effect<A, E | SE, R | SR>
1905
- : never
1902
+ [k in keyof S as S[k] extends (...args: Array<any>) => Effect.Effect<any, any, any> ? k : never]: S[k] extends
1903
+ (...args: infer Args) => Effect.Effect<infer A, infer E, infer R>
1904
+ ? (...args: Args) => Effect.Effect<A, E | SE, R | SR>
1905
+ : never
1906
1906
  }
1907
1907
  constants: {
1908
1908
  [k in { [k in keyof S]: k }[keyof S]]: S[k] extends Effect.Effect<infer A, infer E, infer R> ?
@@ -1910,7 +1910,7 @@ export const serviceMembers = <S, SE, SR>(getService: Effect.Effect<S, SE, SR>):
1910
1910
  Effect.Effect<S[k], SE, SR>
1911
1911
  }
1912
1912
  } => ({
1913
- functions: serviceFunctions(getService),
1913
+ functions: serviceFunctions(getService) as any,
1914
1914
  constants: serviceConstants(getService)
1915
1915
  })
1916
1916
 
@@ -35,7 +35,7 @@ import type * as RuntimeFlags from "../RuntimeFlags.js"
35
35
  import * as RuntimeFlagsPatch from "../RuntimeFlagsPatch.js"
36
36
  import type * as Scope from "../Scope.js"
37
37
  import type * as Tracer from "../Tracer.js"
38
- import type { NoInfer } from "../Types.js"
38
+ import type { NoInfer, NotFunction } from "../Types.js"
39
39
  import * as _blockedRequests from "./blockedRequests.js"
40
40
  import * as internalCause from "./cause.js"
41
41
  import * as deferred from "./deferred.js"
@@ -697,7 +697,7 @@ export const andThen: {
697
697
  : [X] extends [Promise<infer A1>] ? Effect.Effect<A1, E | Cause.UnknownException, R>
698
698
  : Effect.Effect<X, E, R>
699
699
  <X>(
700
- f: X
700
+ f: NotFunction<X>
701
701
  ): <A, E, R>(
702
702
  self: Effect.Effect<A, E, R>
703
703
  ) => [X] extends [Effect.Effect<infer A1, infer E1, infer R1>] ? Effect.Effect<A1, E | E1, R | R1>
@@ -711,7 +711,7 @@ export const andThen: {
711
711
  : Effect.Effect<X, E, R>
712
712
  <A, E, R, X>(
713
713
  self: Effect.Effect<A, E, R>,
714
- f: X
714
+ f: NotFunction<X>
715
715
  ): [X] extends [Effect.Effect<infer A1, infer E1, infer R1>] ? Effect.Effect<A1, E | E1, R | R1>
716
716
  : [X] extends [Promise<infer A1>] ? Effect.Effect<A1, E | Cause.UnknownException, R>
717
717
  : Effect.Effect<X, E, R>
@@ -1169,7 +1169,7 @@ export const tap = dual<
1169
1169
  : [X] extends [Promise<infer _A1>] ? Effect.Effect<A, E | Cause.UnknownException, R>
1170
1170
  : Effect.Effect<A, E, R>
1171
1171
  <X>(
1172
- f: X
1172
+ f: NotFunction<X>
1173
1173
  ): <A, E, R>(
1174
1174
  self: Effect.Effect<A, E, R>
1175
1175
  ) => [X] extends [Effect.Effect<infer _A1, infer E1, infer R1>] ? Effect.Effect<A, E | E1, R | R1>
@@ -1185,7 +1185,7 @@ export const tap = dual<
1185
1185
  : Effect.Effect<A, E, R>
1186
1186
  <A, E, R, X>(
1187
1187
  self: Effect.Effect<A, E, R>,
1188
- f: X
1188
+ f: NotFunction<X>
1189
1189
  ): [X] extends [Effect.Effect<infer _A1, infer E1, infer R1>] ? Effect.Effect<A, E | E1, R | R1>
1190
1190
  : [X] extends [Promise<infer _A1>] ? Effect.Effect<A, E | Cause.UnknownException, R>
1191
1191
  : Effect.Effect<A, E, R>
@@ -5,6 +5,7 @@ import type * as Clock from "../Clock.js"
5
5
  import type { ConfigProvider } from "../ConfigProvider.js"
6
6
  import * as Context from "../Context.js"
7
7
  import * as Deferred from "../Deferred.js"
8
+ import type * as Duration from "../Duration.js"
8
9
  import type * as Effect from "../Effect.js"
9
10
  import { EffectTypeId } from "../Effectable.js"
10
11
  import type * as Either from "../Either.js"
@@ -1361,6 +1362,16 @@ export const defaultLogger: Logger<unknown, void> = globalValue(
1361
1362
  })
1362
1363
  )
1363
1364
 
1365
+ /** @internal */
1366
+ export const jsonLogger: Logger<unknown, void> = globalValue(
1367
+ Symbol.for("effect/Logger/jsonLogger"),
1368
+ () =>
1369
+ internalLogger.makeLogger((options) => {
1370
+ const formatted = internalLogger.jsonLogger.log(options)
1371
+ getConsole(options.context).log(formatted)
1372
+ })
1373
+ )
1374
+
1364
1375
  /** @internal */
1365
1376
  export const logFmtLogger: Logger<unknown, void> = globalValue(
1366
1377
  Symbol.for("effect/Logger/logFmtLogger"),
@@ -1371,6 +1382,16 @@ export const logFmtLogger: Logger<unknown, void> = globalValue(
1371
1382
  })
1372
1383
  )
1373
1384
 
1385
+ /** @internal */
1386
+ export const structuredLogger: Logger<unknown, void> = globalValue(
1387
+ Symbol.for("effect/Logger/structuredLogger"),
1388
+ () =>
1389
+ internalLogger.makeLogger((options) => {
1390
+ const formatted = internalLogger.structuredLogger.log(options)
1391
+ getConsole(options.context).log(formatted)
1392
+ })
1393
+ )
1394
+
1374
1395
  /** @internal */
1375
1396
  export const tracerLogger = globalValue(
1376
1397
  Symbol.for("effect/Logger/tracerLogger"),
@@ -1434,6 +1455,53 @@ export const currentLoggers: FiberRef.FiberRef<
1434
1455
  () => core.fiberRefUnsafeMakeHashSet(HashSet.make(defaultLogger, tracerLogger))
1435
1456
  )
1436
1457
 
1458
+ /** @internal */
1459
+ export const batchedLogger = dual<
1460
+ <Output, R>(
1461
+ window: Duration.DurationInput,
1462
+ f: (messages: Array<NoInfer<Output>>) => Effect.Effect<void, never, R>
1463
+ ) => <Message>(
1464
+ self: Logger<Message, Output>
1465
+ ) => Effect.Effect<Logger<Message, void>, never, Scope.Scope | R>,
1466
+ <Message, Output, R>(
1467
+ self: Logger<Message, Output>,
1468
+ window: Duration.DurationInput,
1469
+ f: (messages: Array<NoInfer<Output>>) => Effect.Effect<void, never, R>
1470
+ ) => Effect.Effect<Logger<Message, void>, never, Scope.Scope | R>
1471
+ >(3, <Message, Output, R>(
1472
+ self: Logger<Message, Output>,
1473
+ window: Duration.DurationInput,
1474
+ f: (messages: Array<NoInfer<Output>>) => Effect.Effect<void, never, R>
1475
+ ): Effect.Effect<Logger<Message, void>, never, Scope.Scope | R> =>
1476
+ core.flatMap(scope, (scope) => {
1477
+ let buffer: Array<Output> = []
1478
+ const flush = core.suspend(() => {
1479
+ if (buffer.length === 0) {
1480
+ return core.unit
1481
+ }
1482
+ const arr = buffer
1483
+ buffer = []
1484
+ return f(arr)
1485
+ })
1486
+
1487
+ return core.uninterruptibleMask((restore) =>
1488
+ pipe(
1489
+ internalEffect.sleep(window),
1490
+ core.zipRight(flush),
1491
+ internalEffect.forever,
1492
+ restore,
1493
+ forkDaemon,
1494
+ core.flatMap((fiber) => core.scopeAddFinalizer(scope, core.interruptFiber(fiber))),
1495
+ core.zipRight(addFinalizer(() => flush)),
1496
+ core.as(
1497
+ internalLogger.makeLogger((options) => {
1498
+ buffer.push(self.log(options))
1499
+ })
1500
+ )
1501
+ )
1502
+ )
1503
+ }))
1504
+
1437
1505
  // circular with Effect
1438
1506
 
1439
1507
  /* @internal */
@@ -215,7 +215,7 @@ export const stringLogger: Logger.Logger<unknown, string> = makeLogger<unknown,
215
215
 
216
216
  export const serializeUnknown = (u: unknown): string => {
217
217
  try {
218
- return typeof u === "object" ? JSON.stringify(u) : String(u)
218
+ return typeof u === "object" ? jsonStringifyCircular(u) : String(u)
219
219
  } catch (_) {
220
220
  return String(u)
221
221
  }
@@ -288,6 +288,76 @@ export const logfmtLogger = makeLogger<unknown, string>(
288
288
  }
289
289
  )
290
290
 
291
+ /** @internal */
292
+ export const structuredLogger = makeLogger<unknown, {
293
+ readonly logLevel: string
294
+ readonly fiberId: string
295
+ readonly timestamp: string
296
+ readonly message: unknown
297
+ readonly cause: string | undefined
298
+ readonly annotations: Record<string, unknown>
299
+ readonly spans: Record<string, number>
300
+ }>(
301
+ ({ annotations, cause, date, fiberId, logLevel, message, spans }) => {
302
+ const now = date.getTime()
303
+ const annotationsObj: Record<string, unknown> = {}
304
+ const spansObj: Record<string, number> = {}
305
+
306
+ if (HashMap.size(annotations) > 0) {
307
+ for (const [k, v] of annotations) {
308
+ annotationsObj[k] = structuredMessage(v)
309
+ }
310
+ }
311
+
312
+ if (List.isCons(spans)) {
313
+ for (const span of spans) {
314
+ spansObj[span.label] = now - span.startTime
315
+ }
316
+ }
317
+
318
+ return {
319
+ message: structuredMessage(message),
320
+ logLevel: logLevel.label,
321
+ timestamp: date.toISOString(),
322
+ cause: Cause.isEmpty(cause) ? undefined : Cause.pretty(cause),
323
+ annotations: annotationsObj,
324
+ spans: spansObj,
325
+ fiberId: _fiberId.threadName(fiberId)
326
+ }
327
+ }
328
+ )
329
+
330
+ export const structuredMessage = (u: unknown): unknown => {
331
+ switch (typeof u) {
332
+ case "bigint":
333
+ case "function":
334
+ case "symbol": {
335
+ return String(u)
336
+ }
337
+ default: {
338
+ return u
339
+ }
340
+ }
341
+ }
342
+
343
+ const jsonStringifyCircular = (obj: unknown) => {
344
+ let cache: Array<unknown> = []
345
+ const retVal = JSON.stringify(
346
+ obj,
347
+ (_key, value) =>
348
+ typeof value === "object" && value !== null
349
+ ? cache.includes(value)
350
+ ? undefined // circular reference
351
+ : cache.push(value) && value
352
+ : value
353
+ )
354
+ ;(cache as any) = undefined
355
+ return retVal
356
+ }
357
+
358
+ /** @internal */
359
+ export const jsonLogger = map(structuredLogger, jsonStringifyCircular)
360
+
291
361
  /** @internal */
292
362
  const filterKeyName = (key: string) => key.replace(/[\s="]/g, "_")
293
363
 
@@ -303,3 +373,8 @@ const renderLogSpanLogfmt = (now: number) => (self: LogSpan.LogSpan): string =>
303
373
  const label = filterKeyName(self.label)
304
374
  return `${label}=${now - self.startTime}ms`
305
375
  }
376
+
377
+ /** @internal */
378
+ export const isLogger = (u: unknown): u is Logger.Logger<unknown, unknown> => {
379
+ return typeof u === "object" && u != null && LoggerTypeId in u
380
+ }