@rivetkit/effect 2.3.3-rc.1 → 2.3.3-rc.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 (63) hide show
  1. package/dist/Actor.d.ts +2 -3
  2. package/dist/Actor.d.ts.map +1 -1
  3. package/dist/Actor.js +2 -2
  4. package/dist/Actor.js.map +1 -1
  5. package/dist/Client.d.ts.map +1 -1
  6. package/dist/Client.js +6 -4
  7. package/dist/Client.js.map +1 -1
  8. package/dist/Registry.d.ts +69 -7
  9. package/dist/Registry.d.ts.map +1 -1
  10. package/dist/Registry.js +93 -40
  11. package/dist/Registry.js.map +1 -1
  12. package/dist/RivetError.d.ts +18 -3
  13. package/dist/RivetError.d.ts.map +1 -1
  14. package/dist/RivetError.js +31 -0
  15. package/dist/RivetError.js.map +1 -1
  16. package/dist/RivetLogger.d.ts +41 -0
  17. package/dist/RivetLogger.d.ts.map +1 -0
  18. package/dist/RivetLogger.js +41 -0
  19. package/dist/RivetLogger.js.map +1 -0
  20. package/dist/State.d.ts +92 -56
  21. package/dist/State.d.ts.map +1 -1
  22. package/dist/State.js +51 -57
  23. package/dist/State.js.map +1 -1
  24. package/dist/internal/ActorInstanceManager.d.ts.map +1 -1
  25. package/dist/internal/ActorInstanceManager.js +4 -4
  26. package/dist/internal/ActorInstanceManager.js.map +1 -1
  27. package/dist/internal/ActorStateAdapter.d.ts +1 -1
  28. package/dist/internal/ActorStateAdapter.d.ts.map +1 -1
  29. package/dist/internal/ActorStateAdapter.js +2 -7
  30. package/dist/internal/ActorStateAdapter.js.map +1 -1
  31. package/dist/internal/StateOptions.d.ts +1 -0
  32. package/dist/internal/StateOptions.d.ts.map +1 -1
  33. package/dist/internal/logging.d.ts +6 -7
  34. package/dist/internal/logging.d.ts.map +1 -1
  35. package/dist/internal/logging.js +78 -102
  36. package/dist/internal/logging.js.map +1 -1
  37. package/dist/mod.d.ts +1 -1
  38. package/dist/mod.d.ts.map +1 -1
  39. package/dist/mod.js +1 -1
  40. package/dist/mod.js.map +1 -1
  41. package/package.json +3 -3
  42. package/src/Actor.test-d.ts +32 -0
  43. package/src/Actor.ts +29 -4
  44. package/src/Client.test.ts +21 -18
  45. package/src/Client.ts +6 -4
  46. package/src/Registry.test.ts +7 -11
  47. package/src/Registry.ts +116 -50
  48. package/src/RivetError.test.ts +11 -0
  49. package/src/RivetError.ts +37 -0
  50. package/src/RivetLogger.ts +60 -0
  51. package/src/State.test.ts +163 -4
  52. package/src/State.ts +293 -97
  53. package/src/internal/ActorInstanceManager.ts +4 -10
  54. package/src/internal/ActorStateAdapter.ts +5 -11
  55. package/src/internal/StateOptions.ts +4 -0
  56. package/src/internal/logging.test.ts +65 -88
  57. package/src/internal/logging.ts +103 -143
  58. package/src/mod.ts +1 -1
  59. package/dist/Logger.d.ts +0 -29
  60. package/dist/Logger.d.ts.map +0 -1
  61. package/dist/Logger.js +0 -31
  62. package/dist/Logger.js.map +0 -1
  63. package/src/Logger.ts +0 -43
@@ -77,7 +77,9 @@ export const make = Effect.fnUntraced(function* <
77
77
  const scope = yield* Scope.make();
78
78
  return yield* Effect.gen(function* () {
79
79
  const state = stateAdapter
80
- ? yield* stateAdapter.makeStateView(c)
80
+ ? yield* stateAdapter
81
+ .makeStateView(c)
82
+ .pipe(Effect.provideService(Scope.Scope, scope))
81
83
  : undefined;
82
84
  const context = makeContext(c, scope);
83
85
  const actionHandlers = yield* wakeHandler(
@@ -105,15 +107,7 @@ export const make = Effect.fnUntraced(function* <
105
107
  return {
106
108
  get: (actorId: string) => instances.get(actorId),
107
109
  onWake: async (c: WakeContext<StateDefinition, Database>) => {
108
- await runPromise(
109
- makeInstance(c).pipe(
110
- Effect.tap((instance) =>
111
- Effect.sync(() => {
112
- instances.set(c.actorId, instance);
113
- }),
114
- ),
115
- ),
116
- );
110
+ instances.set(c.actorId, await runPromise(makeInstance(c)));
117
111
  },
118
112
  onStateChange: stateAdapter
119
113
  ? (
@@ -1,10 +1,11 @@
1
- import { Effect, type Fiber, Schema, Semaphore } from "effect";
1
+ import { Effect, type Fiber, Schema } from "effect";
2
2
  import * as State from "../State.ts";
3
3
  import type * as StateOptions from "./StateOptions.ts";
4
4
 
5
5
  export type ActorState<StateDefinition extends StateOptions.Any> = State.State<
6
6
  StateOptions.Decoded<StateDefinition>,
7
- Schema.SchemaError
7
+ Schema.SchemaError,
8
+ StateOptions.Services<StateDefinition>
8
9
  >;
9
10
 
10
11
  type StateInstance<StateDefinition extends StateOptions.Any> = {
@@ -71,15 +72,8 @@ export const make = Effect.fnUntraced(function* <
71
72
  const state = yield* Effect.fromNullishOr(
72
73
  instance.state,
73
74
  ).pipe(Effect.orDie);
74
-
75
- yield* Semaphore.withPermit(
76
- state.semaphore,
77
- Effect.gen(function* () {
78
- const decoded = yield* stateCodec
79
- .decodeUnknown(newState)
80
- .pipe(Effect.orDie);
81
- State.publishUnsafe(state, decoded);
82
- }),
75
+ yield* state[State.RuntimeTypeId].publishEffect(
76
+ stateCodec.decodeUnknown(newState).pipe(Effect.orDie),
83
77
  );
84
78
  }),
85
79
  );
@@ -10,6 +10,10 @@ export interface Any {
10
10
  readonly initialValue: () => unknown;
11
11
  }
12
12
 
13
+ export type Services<State extends Any> =
14
+ | State["schema"]["DecodingServices"]
15
+ | State["schema"]["EncodingServices"];
16
+
13
17
  export type Encoded<State extends Any> =
14
18
  | State["schema"]["Encoded"]
15
19
  | ([State] extends [never] ? undefined : never);
@@ -1,13 +1,6 @@
1
1
  import { assert, describe, it } from "@effect/vitest";
2
- import {
3
- Config,
4
- ConfigProvider,
5
- Effect,
6
- Layer,
7
- Logger as EffectLogger,
8
- References,
9
- } from "effect";
10
- import type { Logger as PinoLogger } from "rivetkit/log";
2
+ import { ConfigProvider, Effect, Logger, References } from "effect";
3
+ import * as RivetkitLog from "rivetkit/log";
11
4
  import * as Logging from "./logging.ts";
12
5
 
13
6
  type LogEntry = {
@@ -16,7 +9,7 @@ type LogEntry = {
16
9
  readonly msg: string | undefined;
17
10
  };
18
11
 
19
- function makeTestLogger(entries: Array<LogEntry>): PinoLogger {
12
+ function makeTestLogger(entries: Array<LogEntry>): RivetkitLog.Logger {
20
13
  const logger: Record<string, unknown> = {};
21
14
  for (const level of ["trace", "debug", "info", "warn", "error", "fatal"]) {
22
15
  logger[level] = (
@@ -27,7 +20,7 @@ function makeTestLogger(entries: Array<LogEntry>): PinoLogger {
27
20
  };
28
21
  }
29
22
 
30
- return logger as unknown as PinoLogger;
23
+ return logger as unknown as RivetkitLog.Logger;
31
24
  }
32
25
 
33
26
  describe("internal/logging", () => {
@@ -65,23 +58,21 @@ describe("internal/logging", () => {
65
58
  key: "room-1",
66
59
  actorId: "actor-1",
67
60
  }),
68
- Effect.provide(
69
- EffectLogger.layer([Logging.makeEffectLogger(baseLogger)]),
70
- ),
61
+ Effect.provide(Logger.layer([Logging.makeLogger(baseLogger)])),
71
62
  );
72
63
 
73
- assert.deepStrictEqual(entries, [
74
- {
75
- level: "info",
76
- fields: {
77
- roomId: "abc",
78
- actor: "ChatRoom",
79
- key: "room-1",
80
- actorId: "actor-1",
81
- },
82
- msg: "room awake",
83
- },
84
- ]);
64
+ const entry = entries[0];
65
+ assert.ok(entry !== undefined);
66
+ assert.strictEqual(entry.level, "info");
67
+ assert.strictEqual(entry.msg, "room awake");
68
+ assert.deepStrictEqual(entry.fields, {
69
+ roomId: "abc",
70
+ actor: "ChatRoom",
71
+ key: "room-1",
72
+ actorId: "actor-1",
73
+ fiberId: entry.fields.fiberId,
74
+ });
75
+ assert.strictEqual(typeof entry.fields.fiberId, "string");
85
76
  }),
86
77
  );
87
78
 
@@ -92,9 +83,7 @@ describe("internal/logging", () => {
92
83
  const error = new Error("room failed to wake");
93
84
 
94
85
  yield* Effect.logError(error).pipe(
95
- Effect.provide(
96
- EffectLogger.layer([Logging.makeEffectLogger(baseLogger)]),
97
- ),
86
+ Effect.provide(Logger.layer([Logging.makeLogger(baseLogger)])),
98
87
  );
99
88
 
100
89
  const entry = entries[0];
@@ -115,9 +104,7 @@ describe("internal/logging", () => {
115
104
  actorId: "actor-1",
116
105
  action: "SendMessage",
117
106
  }).pipe(
118
- Effect.provide(
119
- EffectLogger.layer([Logging.makeEffectLogger(baseLogger)]),
120
- ),
107
+ Effect.provide(Logger.layer([Logging.makeLogger(baseLogger)])),
121
108
  );
122
109
 
123
110
  const entry = entries[0];
@@ -130,17 +117,7 @@ describe("internal/logging", () => {
130
117
  }),
131
118
  );
132
119
 
133
- it.effect(
134
- "uses References.MinimumLogLevel when creating the base logger",
135
- () =>
136
- Effect.gen(function* () {
137
- const baseLogger = yield* Logging.makeDefaultBaseLogger;
138
-
139
- assert.strictEqual(baseLogger.level, "debug");
140
- }).pipe(Effect.provideService(References.MinimumLogLevel, "Debug")),
141
- );
142
-
143
- it.effect("accepts the shared Pino RIVET_LOG_LEVEL values", () =>
120
+ it.effect("accepts RIVET_LOG_LEVEL values", () =>
144
121
  Effect.gen(function* () {
145
122
  const baseLogger = yield* Logging.makeDefaultBaseLogger;
146
123
 
@@ -157,25 +134,24 @@ describe("internal/logging", () => {
157
134
  ),
158
135
  );
159
136
 
160
- it.effect("prefers References.MinimumLogLevel over shared env values", () =>
137
+ it.effect("accepts uppercase RIVET_LOG_LEVEL values", () =>
161
138
  Effect.gen(function* () {
162
139
  const baseLogger = yield* Logging.makeDefaultBaseLogger;
163
140
 
164
141
  assert.strictEqual(baseLogger.level, "debug");
165
142
  }).pipe(
166
- Effect.provideService(References.MinimumLogLevel, "Debug"),
167
143
  Effect.provideService(
168
144
  ConfigProvider.ConfigProvider,
169
145
  ConfigProvider.fromEnv({
170
146
  env: {
171
- RIVET_LOG_LEVEL: "silent",
147
+ RIVET_LOG_LEVEL: "DEBUG",
172
148
  },
173
149
  }),
174
150
  ),
175
151
  ),
176
152
  );
177
153
 
178
- it.effect("preserves an explicit Info minimum log level", () =>
154
+ it.effect("ignores Effect-only RIVET_LOG_LEVEL values", () =>
179
155
  Effect.gen(function* () {
180
156
  const baseLogger = yield* Logging.makeDefaultBaseLogger;
181
157
 
@@ -186,36 +162,45 @@ describe("internal/logging", () => {
186
162
  ConfigProvider.ConfigProvider,
187
163
  ConfigProvider.fromEnv({
188
164
  env: {
189
- RIVET_LOG_LEVEL: "silent",
165
+ RIVET_LOG_LEVEL: "None",
190
166
  },
191
167
  }),
192
168
  ),
193
169
  ),
194
170
  );
195
171
 
196
- it.effect(
197
- "uses Config.logLevel values provided to References.MinimumLogLevel",
198
- () =>
199
- Effect.gen(function* () {
200
- const baseLogger = yield* Logging.makeDefaultBaseLogger;
172
+ it.effect("falls back to References.MinimumLogLevel without env", () =>
173
+ Effect.gen(function* () {
174
+ const baseLogger = yield* Logging.makeDefaultBaseLogger;
201
175
 
202
- assert.strictEqual(baseLogger.level, "trace");
203
- }).pipe(
204
- Effect.provide(
205
- Layer.effect(
206
- References.MinimumLogLevel,
207
- Config.logLevel("RIVET_LOG_LEVEL"),
208
- ),
209
- ),
210
- Effect.provideService(
211
- ConfigProvider.ConfigProvider,
212
- ConfigProvider.fromEnv({
213
- env: {
214
- RIVET_LOG_LEVEL: "Trace",
215
- },
216
- }),
217
- ),
176
+ assert.strictEqual(baseLogger.level, "debug");
177
+ }).pipe(
178
+ Effect.provideService(References.MinimumLogLevel, "Debug"),
179
+ Effect.provideService(
180
+ ConfigProvider.ConfigProvider,
181
+ ConfigProvider.fromEnv({
182
+ env: {},
183
+ }),
218
184
  ),
185
+ ),
186
+ );
187
+
188
+ it.effect("RIVET_LOG_LEVEL overrides References.MinimumLogLevel", () =>
189
+ Effect.gen(function* () {
190
+ const baseLogger = yield* Logging.makeDefaultBaseLogger;
191
+
192
+ assert.strictEqual(baseLogger.level, "silent");
193
+ }).pipe(
194
+ Effect.provideService(References.MinimumLogLevel, "Debug"),
195
+ Effect.provideService(
196
+ ConfigProvider.ConfigProvider,
197
+ ConfigProvider.fromEnv({
198
+ env: {
199
+ RIVET_LOG_LEVEL: "silent",
200
+ },
201
+ }),
202
+ ),
203
+ ),
219
204
  );
220
205
 
221
206
  it.effect(
@@ -229,19 +214,18 @@ describe("internal/logging", () => {
229
214
  Effect.provideService(References.CurrentLogLevel, "Debug"),
230
215
  Effect.provideService(References.MinimumLogLevel, "Debug"),
231
216
  Effect.provide(
232
- EffectLogger.layer([
233
- Logging.makeEffectLogger(baseLogger),
234
- ]),
217
+ Logger.layer([Logging.makeLogger(baseLogger)]),
235
218
  ),
236
219
  );
237
220
 
238
- assert.deepStrictEqual(entries, [
239
- {
240
- level: "debug",
241
- fields: {},
242
- msg: "plain log",
243
- },
244
- ]);
221
+ const entry = entries[0];
222
+ assert.ok(entry !== undefined);
223
+ assert.strictEqual(entry.level, "debug");
224
+ assert.strictEqual(entry.msg, "plain log");
225
+ assert.deepStrictEqual(entry.fields, {
226
+ fiberId: entry.fields.fiberId,
227
+ });
228
+ assert.strictEqual(typeof entry.fields.fiberId, "string");
245
229
  }),
246
230
  );
247
231
 
@@ -256,9 +240,7 @@ describe("internal/logging", () => {
256
240
  Effect.provideService(References.CurrentLogLevel, "None"),
257
241
  Effect.provideService(References.MinimumLogLevel, "All"),
258
242
  Effect.provide(
259
- EffectLogger.layer([
260
- Logging.makeEffectLogger(baseLogger),
261
- ]),
243
+ Logger.layer([Logging.makeLogger(baseLogger)]),
262
244
  ),
263
245
  );
264
246
 
@@ -276,18 +258,13 @@ describe("internal/logging", () => {
276
258
  yield* Effect.logInfo("checkout complete").pipe(
277
259
  Effect.withLogSpan("checkout"),
278
260
  Effect.provide(
279
- EffectLogger.layer([
280
- Logging.makeEffectLogger(baseLogger),
281
- ]),
261
+ Logger.layer([Logging.makeLogger(baseLogger)]),
282
262
  ),
283
263
  );
284
264
 
285
265
  assert.strictEqual(entries.length, 1);
286
266
  assert.strictEqual(entries[0]?.level, "info");
287
267
  assert.strictEqual(entries[0]?.msg, "checkout complete");
288
- assert.deepStrictEqual(Object.keys(entries[0]?.fields ?? {}), [
289
- "spans",
290
- ]);
291
268
  const spans = entries[0]?.fields.spans as
292
269
  | Record<string, unknown>
293
270
  | undefined;
@@ -1,19 +1,16 @@
1
1
  import {
2
- Cause,
3
2
  Config,
4
3
  Context,
5
4
  Effect,
6
- Logger as EffectLogger,
5
+ Logger,
6
+ Option,
7
+ Predicate,
8
+ Record as EffectRecord,
7
9
  type LogLevel,
8
10
  References,
9
11
  } from "effect";
10
12
  import type * as Rivetkit from "rivetkit";
11
- import {
12
- configureDefaultLogger,
13
- getBaseLogger,
14
- type Logger as PinoLogger,
15
- type LogLevel as PinoLogLevel,
16
- } from "rivetkit/log";
13
+ import * as RivetkitLog from "rivetkit/log";
17
14
 
18
15
  const EMPTY_KEY = "/";
19
16
  const KEY_SEPARATOR = "/";
@@ -24,25 +21,14 @@ type ActorLogContext = {
24
21
  readonly actorId: string;
25
22
  };
26
23
 
27
- export class BaseLogger extends Context.Service<BaseLogger, PinoLogger>()(
28
- "@rivetkit/effect/Logger/BaseLogger",
29
- ) {}
30
-
31
- const PinoLevelByEffectLevel: Record<LogLevel.LogLevel, PinoLogLevel> = {
32
- All: "trace",
33
- Trace: "trace",
34
- Debug: "debug",
35
- Info: "info",
36
- Warn: "warn",
37
- Error: "error",
38
- Fatal: "fatal",
39
- None: "silent",
40
- };
24
+ export class BaseLogger extends Context.Service<
25
+ BaseLogger,
26
+ RivetkitLog.Logger
27
+ >()("@rivetkit/effect/RivetLogger/BaseLogger") {}
41
28
 
42
- export const toPinoLevel = (logLevel: LogLevel.LogLevel): PinoLogLevel =>
43
- PinoLevelByEffectLevel[logLevel];
29
+ const RivetkitLogLevels = RivetkitLog.LogLevelSchema.options;
44
30
 
45
- const EffectLevelByPinoLevel: Record<PinoLogLevel, LogLevel.LogLevel> = {
31
+ const EffectLevelByRivetkitLevel = {
46
32
  trace: "Trace",
47
33
  debug: "Debug",
48
34
  info: "Info",
@@ -50,56 +36,54 @@ const EffectLevelByPinoLevel: Record<PinoLogLevel, LogLevel.LogLevel> = {
50
36
  error: "Error",
51
37
  fatal: "Fatal",
52
38
  silent: "None",
53
- };
39
+ } as const satisfies Record<
40
+ RivetkitLog.LogLevel,
41
+ Exclude<LogLevel.LogLevel, "All">
42
+ >;
43
+
44
+ const RivetkitLevelByEffectLevel = {
45
+ ...Object.fromEntries(
46
+ RivetkitLogLevels.map((level) => [
47
+ EffectLevelByRivetkitLevel[level],
48
+ level,
49
+ ]),
50
+ ),
51
+ All: "trace",
52
+ } as Record<LogLevel.LogLevel, RivetkitLog.LogLevel>;
54
53
 
55
- const pinoLogLevelFromEnv = Config.string("RIVET_LOG_LEVEL").pipe(
56
- Config.map((value) => {
57
- const pinoLevel = value.toLowerCase();
58
- if (pinoLevel in EffectLevelByPinoLevel) {
59
- return EffectLevelByPinoLevel[pinoLevel as PinoLogLevel];
60
- }
54
+ const rivetLogLevelFromEnv = Config.string("RIVET_LOG_LEVEL").pipe(
55
+ Effect.option,
56
+ Effect.map((maybeRivetLogLevel) => {
57
+ if (Option.isNone(maybeRivetLogLevel)) return Option.none();
61
58
 
62
- return "Info";
59
+ const parsed = RivetkitLog.LogLevelSchema.safeParse(
60
+ maybeRivetLogLevel.value.toLowerCase(),
61
+ );
62
+ return parsed.success ? Option.some(parsed.data) : Option.none();
63
63
  }),
64
64
  );
65
65
 
66
- const logLevelFromEnv = Config.logLevel("RIVET_LOG_LEVEL").pipe(
67
- Config.orElse(() => pinoLogLevelFromEnv),
68
- Effect.option,
69
- );
66
+ export const makeDefaultBaseLogger: Effect.Effect<RivetkitLog.Logger> =
67
+ Effect.gen(function* () {
68
+ const maybeRivetLogLevel = yield* rivetLogLevelFromEnv;
69
+ const logLevel = Option.isSome(maybeRivetLogLevel)
70
+ ? maybeRivetLogLevel.value
71
+ : RivetkitLevelByEffectLevel[yield* References.MinimumLogLevel];
70
72
 
71
- export const makeDefaultBaseLogger: Effect.Effect<PinoLogger> = Effect.gen(
72
- function* () {
73
- const context = yield* Effect.context();
74
- const providedMinimumLogLevel = Context.getOrUndefined(
75
- context,
76
- References.MinimumLogLevel,
73
+ return yield* Effect.sync(() =>
74
+ RivetkitLog.makeDefaultLogger(logLevel),
77
75
  );
78
- const envLogLevel = yield* logLevelFromEnv;
79
- const logLevel =
80
- providedMinimumLogLevel !== undefined
81
- ? providedMinimumLogLevel
82
- : envLogLevel._tag === "Some"
83
- ? envLogLevel.value
84
- : yield* References.MinimumLogLevel;
85
-
86
- return yield* Effect.sync(() => {
87
- configureDefaultLogger(toPinoLevel(logLevel));
88
- return getBaseLogger();
89
- });
90
- },
91
- );
76
+ });
92
77
 
93
- export const getOrCreateBaseLogger: Effect.Effect<PinoLogger> = Effect.gen(
94
- function* () {
95
- const provided = yield* Effect.serviceOption(BaseLogger);
96
- if (provided._tag === "Some") {
97
- return provided.value;
78
+ export const getOrCreateBaseLogger: Effect.Effect<RivetkitLog.Logger> =
79
+ Effect.gen(function* () {
80
+ const maybeBaseLogger = yield* Effect.serviceOption(BaseLogger);
81
+ if (Option.isSome(maybeBaseLogger)) {
82
+ return maybeBaseLogger.value;
98
83
  }
99
84
 
100
85
  return yield* makeDefaultBaseLogger;
101
- },
102
- );
86
+ });
103
87
 
104
88
  export function makeActorLogAnnotations(context: ActorLogContext): {
105
89
  readonly actor: string;
@@ -131,59 +115,64 @@ export function serializeActorKey(key: Rivetkit.ActorKey): string {
131
115
  .join(KEY_SEPARATOR);
132
116
  }
133
117
 
134
- function structuredValue(value: unknown): unknown {
135
- if (value instanceof Error) {
136
- return value;
137
- }
118
+ export function makeLogger(
119
+ baseLogger: RivetkitLog.Logger,
120
+ ): Logger.Logger<unknown, void> {
121
+ return Logger.make((options) => {
122
+ if (options.logLevel === "None") return;
123
+ const rivetkitLevel = RivetkitLevelByEffectLevel[options.logLevel];
124
+ const structured = Logger.formatStructured.log(options);
125
+ const { msg, fields: messageFields } = extractMessage(
126
+ structured.message,
127
+ );
128
+ const fields: Record<string, unknown> = {
129
+ ...messageFields,
130
+ ...structured.annotations,
131
+ fiberId: structured.fiberId,
132
+ };
133
+
134
+ if (!EffectRecord.isEmptyRecord(structured.spans)) {
135
+ fields.spans = structured.spans;
136
+ }
137
+ if (structured.cause !== undefined) {
138
+ fields.cause = structured.cause;
139
+ }
138
140
 
139
- return value;
141
+ const logger = baseLogger[rivetkitLevel];
142
+ if (msg === undefined) {
143
+ logger.call(baseLogger, fields);
144
+ } else {
145
+ logger.call(baseLogger, fields, msg);
146
+ }
147
+ });
140
148
  }
141
149
 
142
- function extractMessageAndFields(message: unknown): {
150
+ function extractMessage(message: unknown): {
143
151
  readonly msg: string | undefined;
144
152
  readonly fields: Record<string, unknown>;
145
153
  } {
146
154
  const values = Array.isArray(message) ? message : [message];
147
- if (values.length === 0) {
148
- return { msg: undefined, fields: {} };
149
- }
150
-
151
- const [first, ...rest] = values;
152
155
  const fields: Record<string, unknown> = {};
156
+ const args: Array<unknown> = [];
153
157
  let msg: string | undefined;
154
158
 
155
- if (first instanceof Error) {
156
- fields.error = first;
157
- msg = first.message;
158
- } else if (first !== null && typeof first === "object") {
159
- const firstFields = first as Record<string, unknown>;
160
- for (const [key, value] of Object.entries(firstFields)) {
161
- if (key === "msg") {
162
- if (value !== undefined) {
163
- msg = String(value);
164
- }
165
- } else {
166
- fields[key] = structuredValue(value);
167
- }
168
- }
169
- } else if (first !== undefined) {
170
- msg = String(first);
171
- }
172
-
173
- const args: Array<unknown> = [];
174
- for (const value of rest) {
175
- if (value instanceof Error) {
159
+ for (const [index, value] of values.entries()) {
160
+ if (Predicate.isError(value)) {
161
+ fields.error = value;
162
+ if (index === 0) msg = value.message;
163
+ } else if (isStructuredError(value)) {
176
164
  fields.error = value;
177
- } else if (
178
- value !== null &&
179
- typeof value === "object" &&
180
- !Array.isArray(value)
181
- ) {
182
- for (const [key, fieldValue] of Object.entries(
183
- value as Record<string, unknown>,
184
- )) {
185
- fields[key] = structuredValue(fieldValue);
165
+ if (index === 0) msg = value.error;
166
+ } else if (Predicate.isObject(value)) {
167
+ if (index === 0) {
168
+ const { msg: valueMsg, ...rest } = value;
169
+ Object.assign(fields, rest);
170
+ if (valueMsg !== undefined) msg = String(valueMsg);
171
+ } else {
172
+ Object.assign(fields, value);
186
173
  }
174
+ } else if (index === 0) {
175
+ msg = value === undefined ? undefined : String(value);
187
176
  } else {
188
177
  args.push(value);
189
178
  }
@@ -196,42 +185,13 @@ function extractMessageAndFields(message: unknown): {
196
185
  return { msg, fields };
197
186
  }
198
187
 
199
- export function makeEffectLogger(
200
- baseLogger: PinoLogger,
201
- ): EffectLogger.Logger<unknown, void> {
202
- return EffectLogger.make(({ cause, date, fiber, logLevel, message }) => {
203
- const { msg, fields } = extractMessageAndFields(message);
204
-
205
- for (const [key, value] of Object.entries(
206
- fiber.getRef(References.CurrentLogAnnotations),
207
- )) {
208
- fields[key] = structuredValue(value);
209
- }
210
-
211
- const spans: Record<string, number> = {};
212
- for (const [label, startTime] of fiber.getRef(
213
- References.CurrentLogSpans,
214
- )) {
215
- spans[label] = date.getTime() - startTime;
216
- }
217
- if (Object.keys(spans).length > 0) {
218
- fields.spans = spans;
219
- }
220
-
221
- if (cause.reasons.length > 0) {
222
- fields.cause = Cause.pretty(cause);
223
- }
224
-
225
- const pinoLevel = toPinoLevel(logLevel);
226
- if (pinoLevel === "silent") {
227
- return;
228
- }
229
-
230
- const logger = baseLogger[pinoLevel];
231
- if (msg === undefined) {
232
- logger.call(baseLogger, fields);
233
- } else {
234
- logger.call(baseLogger, fields, msg);
235
- }
236
- });
188
+ function isStructuredError(
189
+ value: unknown,
190
+ ): value is { readonly error: string; readonly name: string } {
191
+ return (
192
+ Predicate.hasProperty(value, "error") &&
193
+ Predicate.hasProperty(value, "name") &&
194
+ Predicate.isString(value.error) &&
195
+ Predicate.isString(value.name)
196
+ );
237
197
  }
package/src/mod.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * as Action from "./Action.ts";
2
2
  export * as Actor from "./Actor.ts";
3
3
  export * as Client from "./Client.ts";
4
- export * as Logger from "./Logger.ts";
5
4
  export * as Registry from "./Registry.ts";
5
+ export * as RivetLogger from "./RivetLogger.ts";
6
6
  export * as RivetError from "./RivetError.ts";
7
7
  export * as State from "./State.ts";
package/dist/Logger.d.ts DELETED
@@ -1,29 +0,0 @@
1
- import { Layer } from "effect";
2
- import type { Logger as PinoLogger } from "rivetkit/log";
3
- import { BaseLogger } from "./internal/logging.ts";
4
- /**
5
- * Builds a logging layer from a custom Pino-compatible logger.
6
- *
7
- * The layer installs the matching Effect logger and configures the underlying
8
- * RivetKit TypeScript SDK logs to go through the same logger.
9
- *
10
- * @example
11
- * ```ts
12
- * import { Logger } from "@rivetkit/effect"
13
- * import { pino } from "pino"
14
- *
15
- * const LoggerLive = Logger.layerPino(
16
- * pino({ transport: { target: "pino-pretty" } })
17
- * )
18
- * ```
19
- */
20
- export declare const layerPino: (baseLogger: PinoLogger) => Layer.Layer<BaseLogger, never, never>;
21
- /**
22
- * Default RivetKit Effect logging layer.
23
- *
24
- * The layer creates a base logger from `References.MinimumLogLevel` and installs
25
- * the Effect logger adapter. Applications that want custom formatting or
26
- * transports should provide {@link layerPino} instead.
27
- */
28
- export declare const layer: Layer.Layer<never>;
29
- //# sourceMappingURL=Logger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../src/Logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EACN,UAAU,EAGV,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,GAAI,YAAY,UAAU,0CAO9C,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAEpC,CAAC"}