@outputai/core 0.8.2-next.e1cd79b.0 → 0.8.2-next.e658cc2.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 (108) hide show
  1. package/package.json +11 -11
  2. package/src/bus.js +1 -1
  3. package/src/consts.js +5 -2
  4. package/src/helpers/component.js +12 -0
  5. package/src/helpers/component.spec.js +54 -0
  6. package/src/helpers/fetch.js +105 -0
  7. package/src/helpers/fetch.spec.js +203 -0
  8. package/src/helpers/function.js +15 -0
  9. package/src/helpers/function.spec.js +48 -0
  10. package/src/helpers/object.js +98 -0
  11. package/src/helpers/object.spec.js +377 -0
  12. package/src/helpers/promise.js +29 -0
  13. package/src/helpers/promise.spec.js +35 -0
  14. package/src/helpers/string.js +30 -0
  15. package/src/helpers/string.spec.js +64 -0
  16. package/src/hooks/index.d.ts +102 -30
  17. package/src/hooks/index.js +16 -1
  18. package/src/hooks/index.spec.js +55 -1
  19. package/src/index.d.ts +2 -2
  20. package/src/interface/evaluator.d.ts +2 -2
  21. package/src/interface/evaluator.js +14 -12
  22. package/src/interface/evaluator.spec.js +10 -6
  23. package/src/interface/index.d.ts +7 -6
  24. package/src/interface/index.js +2 -0
  25. package/src/interface/logger.d.ts +61 -0
  26. package/src/interface/logger.js +73 -0
  27. package/src/interface/logger.spec.js +172 -0
  28. package/src/interface/step.d.ts +1 -1
  29. package/src/interface/step.js +15 -12
  30. package/src/interface/step.spec.js +10 -6
  31. package/src/interface/webhook.d.ts +21 -2
  32. package/src/interface/workflow.d.ts +2 -2
  33. package/src/interface/workflow.js +85 -78
  34. package/src/interface/workflow.spec.js +11 -4
  35. package/src/internal_activities/index.js +38 -35
  36. package/src/internal_activities/index.spec.js +27 -4
  37. package/src/logger/development.js +2 -2
  38. package/src/logger/development.spec.js +19 -2
  39. package/src/logger/production.js +1 -1
  40. package/src/logger/production.spec.js +24 -5
  41. package/src/sdk/README.md +47 -0
  42. package/src/sdk/helpers/component_metadata.d.ts +17 -0
  43. package/src/sdk/helpers/component_metadata.js +6 -0
  44. package/src/sdk/helpers/component_metadata.spec.js +30 -0
  45. package/src/sdk/helpers/index.d.ts +12 -0
  46. package/src/sdk/helpers/index.js +3 -0
  47. package/src/sdk/helpers/objects.d.ts +51 -0
  48. package/src/sdk/helpers/objects.js +8 -0
  49. package/src/sdk/helpers/objects.spec.js +16 -0
  50. package/src/sdk/helpers/path.d.ts +11 -0
  51. package/src/sdk/helpers/path.js +32 -0
  52. package/src/{utils/resolve_invocation_dir.spec.js → sdk/helpers/path.spec.js} +9 -9
  53. package/src/sdk/runtime/context.d.ts +30 -0
  54. package/src/sdk/runtime/context.js +15 -0
  55. package/src/{activity_integration → sdk/runtime}/context.spec.js +5 -5
  56. package/src/sdk/runtime/events.d.ts +15 -0
  57. package/src/sdk/runtime/events.js +18 -0
  58. package/src/{activity_integration → sdk/runtime}/events.spec.js +8 -9
  59. package/src/sdk/runtime/index.d.ts +12 -0
  60. package/src/sdk/runtime/index.js +3 -0
  61. package/src/sdk/runtime/tracing.d.ts +46 -0
  62. package/src/sdk/runtime/tracing.js +11 -0
  63. package/src/tracing/processors/s3/redis_client.spec.js +0 -6
  64. package/src/tracing/processors/s3/s3_client.spec.js +0 -6
  65. package/src/tracing/trace_engine.js +1 -1
  66. package/src/worker/catalog_workflow/catalog_job.js +1 -1
  67. package/src/worker/catalog_workflow/index.spec.js +8 -11
  68. package/src/worker/configs.js +1 -1
  69. package/src/worker/connection_monitor.js +1 -1
  70. package/src/worker/global_functions.js +14 -0
  71. package/src/worker/global_functions.spec.js +55 -0
  72. package/src/worker/index.js +4 -1
  73. package/src/worker/index.spec.js +7 -0
  74. package/src/worker/interceptors/activity.js +8 -11
  75. package/src/worker/interceptors/activity.spec.js +25 -26
  76. package/src/worker/interceptors/workflow.js +3 -3
  77. package/src/worker/interceptors/workflow.spec.js +1 -1
  78. package/src/worker/loader/matchers.js +1 -1
  79. package/src/worker/loader/tools.js +1 -1
  80. package/src/worker/loader/tools.spec.js +1 -1
  81. package/src/worker/log_hooks.js +14 -0
  82. package/src/worker/log_hooks.spec.js +83 -2
  83. package/src/worker/sinks.js +7 -1
  84. package/src/worker/sinks.spec.js +203 -0
  85. package/src/activity_integration/context.d.ts +0 -23
  86. package/src/activity_integration/context.js +0 -18
  87. package/src/activity_integration/event_id_integration.spec.js +0 -52
  88. package/src/activity_integration/events.d.ts +0 -10
  89. package/src/activity_integration/events.js +0 -15
  90. package/src/activity_integration/index.d.ts +0 -9
  91. package/src/activity_integration/index.js +0 -3
  92. package/src/activity_integration/tracing.d.ts +0 -40
  93. package/src/activity_integration/tracing.js +0 -48
  94. package/src/utils/index.d.ts +0 -180
  95. package/src/utils/index.js +0 -2
  96. package/src/utils/resolve_invocation_dir.js +0 -34
  97. package/src/utils/utils.js +0 -334
  98. package/src/utils/utils.spec.js +0 -723
  99. /package/src/{internal_utils → helpers}/aggregations.js +0 -0
  100. /package/src/{internal_utils → helpers}/aggregations.spec.js +0 -0
  101. /package/src/{internal_utils → helpers}/errors.js +0 -0
  102. /package/src/{internal_utils → helpers}/errors.spec.js +0 -0
  103. /package/src/{internal_utils → helpers}/temporal_context.js +0 -0
  104. /package/src/{internal_utils → helpers}/temporal_context.spec.ts +0 -0
  105. /package/src/{internal_utils → helpers}/trace_info.js +0 -0
  106. /package/src/{internal_utils → helpers}/trace_info.spec.js +0 -0
  107. /package/src/{internal_utils → helpers}/workflow_context.js +0 -0
  108. /package/src/{internal_utils → helpers}/workflow_context.spec.js +0 -0
@@ -79,6 +79,47 @@ export interface WorkflowDetails {
79
79
  attempt: number;
80
80
  }
81
81
 
82
+ /**
83
+ * Attribute totals collected while an activity executes.
84
+ */
85
+ export interface Aggregations {
86
+ /** Cost totals collected from HTTP request cost and LLM usage attributes. */
87
+ cost: {
88
+ total: number;
89
+ };
90
+ /** Token totals collected from LLM usage attributes. */
91
+ tokens: {
92
+ [tokenType: string]: number | undefined;
93
+ total: number;
94
+ };
95
+ /** HTTP request count totals. */
96
+ httpRequests: {
97
+ total: number;
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Common lifecycle hook payload fields for events associated with a workflow.
103
+ */
104
+ export interface HookPayloadBase {
105
+ /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
106
+ eventId: string;
107
+ /** Timestamp of the event */
108
+ eventDate: number;
109
+ /** Information about the current workflow execution */
110
+ workflowDetails: WorkflowDetails;
111
+ }
112
+
113
+ /**
114
+ * Common hook payload fields for events associated with an activity.
115
+ */
116
+ export interface ActivityPayloadBase extends HookPayloadBase {
117
+ /** Temporal's activityInfo(). */
118
+ activityInfo: Info;
119
+ /** Output component kind for the activity, e.g. step or evaluator. */
120
+ outputActivityKind: string;
121
+ }
122
+
82
123
  /**
83
124
  * Payload passed to the onError() handler when a workflow, activity or runtime error occurs.
84
125
  */
@@ -95,6 +136,8 @@ export interface ErrorHookPayload {
95
136
  activityInfo?: Info;
96
137
  /** Output component kind for the activity, e.g. step, evaluator, or internal_step. */
97
138
  outputActivityKind?: string;
139
+ /** Attribute totals collected during the activity execution. */
140
+ aggregations?: Aggregations | null;
98
141
  /** The error thrown. */
99
142
  error: Error;
100
143
  }
@@ -102,37 +145,45 @@ export interface ErrorHookPayload {
102
145
  /**
103
146
  * Payload passed to the onWorkflowStart() handler when a workflow run begins.
104
147
  */
105
- export interface WorkflowStartHookPayload {
106
- /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
107
- eventId: string;
108
- /** Timestamp of the event */
109
- eventDate: number;
110
- /** Information about the current workflow execution */
111
- workflowDetails: WorkflowDetails;
112
- }
148
+ export type WorkflowStartHookPayload = HookPayloadBase;
113
149
 
114
150
  /**
115
151
  * Payload passed to the onWorkflowEnd() handler when a workflow run completes successfully.
116
152
  */
117
- export interface WorkflowEndHookPayload {
118
- /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
119
- eventId: string;
120
- /** Timestamp of the event */
121
- eventDate: number;
122
- /** Information about the current workflow execution */
123
- workflowDetails: WorkflowDetails;
124
- }
153
+ export type WorkflowEndHookPayload = HookPayloadBase;
125
154
 
126
155
  /**
127
156
  * Payload passed to the onWorkflowError() handler when a workflow run fails.
128
157
  */
129
- export interface WorkflowErrorHookPayload {
130
- /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
131
- eventId: string;
132
- /** Timestamp of the event */
133
- eventDate: number;
134
- /** Information about the current workflow execution */
135
- workflowDetails: WorkflowDetails;
158
+ export interface WorkflowErrorHookPayload extends HookPayloadBase {
159
+ /** The error thrown. */
160
+ error: Error;
161
+ }
162
+
163
+ /**
164
+ * Common activity lifecycle hook payload fields.
165
+ */
166
+ export type ActivityHookPayload = ActivityPayloadBase;
167
+
168
+ /**
169
+ * Payload passed to the onActivityStart() handler when an activity starts.
170
+ */
171
+ export type ActivityStartHookPayload = ActivityHookPayload;
172
+
173
+ /**
174
+ * Payload passed to the onActivityEnd() handler when an activity completes successfully.
175
+ */
176
+ export interface ActivityEndHookPayload extends ActivityHookPayload {
177
+ /** Attribute totals collected during the activity execution. */
178
+ aggregations: Aggregations | null;
179
+ }
180
+
181
+ /**
182
+ * Payload passed to the onActivityError() handler when an activity fails.
183
+ */
184
+ export interface ActivityErrorHookPayload extends ActivityHookPayload {
185
+ /** Attribute totals collected during the activity execution. */
186
+ aggregations: Aggregations | null;
136
187
  /** The error thrown. */
137
188
  error: Error;
138
189
  }
@@ -179,16 +230,37 @@ export declare function onWorkflowEnd( handler: ( payload: WorkflowEndHookPayloa
179
230
  */
180
231
  export declare function onWorkflowError( handler: ( payload: WorkflowErrorHookPayload ) => void ): void;
181
232
 
233
+ /**
234
+ * Register a handler to be invoked when an activity starts.
235
+ *
236
+ * Excludes internal activities.
237
+ *
238
+ * @param handler - Function called with the activity start payload.
239
+ */
240
+ export declare function onActivityStart( handler: ( payload: ActivityStartHookPayload ) => void ): void;
241
+
242
+ /**
243
+ * Register a handler to be invoked when an activity completes successfully.
244
+ *
245
+ * Excludes internal activities.
246
+ *
247
+ * @param handler - Function called with the activity end payload.
248
+ */
249
+ export declare function onActivityEnd( handler: ( payload: ActivityEndHookPayload ) => void ): void;
250
+
251
+ /**
252
+ * Register a handler to be invoked when an activity fails.
253
+ *
254
+ * Excludes internal activities.
255
+ *
256
+ * @param handler - Function called with the activity error payload.
257
+ */
258
+ export declare function onActivityError( handler: ( payload: ActivityErrorHookPayload ) => void ): void;
259
+
182
260
  /**
183
261
  * Framework-managed envelope added to payloads passed to on() handlers.
184
262
  */
185
- export interface OnHookEnvelope {
186
- /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
187
- eventId: string;
188
- /** Timestamp of the event */
189
- eventDate: number;
190
- /** Information about the current workflow execution */
191
- workflowDetails: WorkflowDetails;
263
+ export interface OnHookEnvelope extends HookPayloadBase {
192
264
  /** Temporal's activityInfo(). */
193
265
  activityInfo: Info;
194
266
  /** Output component kind for the activity, e.g. step, evaluator, or internal_step. */
@@ -1,5 +1,5 @@
1
1
  import { messageBus } from '#bus';
2
- import { BusEventType, WORKFLOW_CATALOG } from '#consts';
2
+ import { BusEventType, ComponentType, WORKFLOW_CATALOG } from '#consts';
3
3
  import { createChildLogger } from '#logger';
4
4
 
5
5
  const log = createChildLogger( 'Hooks' );
@@ -48,6 +48,21 @@ export const onWorkflowEnd = handler => messageBus.on( BusEventType.WORKFLOW_END
48
48
  export const onWorkflowError = handler => messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, ...eventFields } ) =>
49
49
  shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowError' ) : null );
50
50
 
51
+ /** Internal activities do not trigger hooks */
52
+ const shouldEmitActivityEvent = outputActivityKind => outputActivityKind !== ComponentType.INTERNAL_STEP;
53
+
54
+ /** Listen to workflow start events, excludes catalog workflow */
55
+ export const onActivityStart = handler => messageBus.on( BusEventType.ACTIVITY_START, ( { outputActivityKind, ...eventFields } ) =>
56
+ shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityStart' ) : null );
57
+
58
+ /** Listen to workflow end events, excludes catalog workflow */
59
+ export const onActivityEnd = handler => messageBus.on( BusEventType.ACTIVITY_END, ( { outputActivityKind, ...eventFields } ) =>
60
+ shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityEnd' ) : null );
61
+
62
+ /** Listen to workflow error events, excludes catalog workflow */
63
+ export const onActivityError = handler => messageBus.on( BusEventType.ACTIVITY_ERROR, ( { outputActivityKind, ...eventFields } ) =>
64
+ shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityError' ) : null );
65
+
51
66
  /** Generic listener for events emitted elsewhere (outside core) */
52
67
  export const on = ( eventName, handler ) => messageBus.on( `external:${eventName}`, payload =>
53
68
  safeInvoke( handler, payload, eventName ) );
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { BusEventType, WORKFLOW_CATALOG } from '#consts';
2
+ import { BusEventType, ComponentType, WORKFLOW_CATALOG } from '#consts';
3
3
 
4
4
  const logErrorMock = vi.hoisted( () => vi.fn() );
5
5
  const createChildLoggerMock = vi.hoisted( () =>
@@ -18,6 +18,9 @@ vi.mock( '#bus', () => ( { messageBus: messageBusMock } ) );
18
18
 
19
19
  import {
20
20
  on,
21
+ onActivityEnd,
22
+ onActivityError,
23
+ onActivityStart,
21
24
  onBeforeWorkerStart,
22
25
  onError,
23
26
  onWorkflowEnd,
@@ -49,6 +52,12 @@ const activityInfo = {
49
52
 
50
53
  const eventDate = 1710000001234;
51
54
 
55
+ const aggregations = {
56
+ cost: { total: 0 },
57
+ tokens: { total: 0 },
58
+ httpRequests: { total: 1 }
59
+ };
60
+
52
61
  describe( 'hooks/index', () => {
53
62
  beforeEach( () => {
54
63
  vi.clearAllMocks();
@@ -198,6 +207,51 @@ describe( 'hooks/index', () => {
198
207
  } );
199
208
  } );
200
209
 
210
+ describe( 'activity lifecycle hooks', () => {
211
+ const cases = [
212
+ [ 'onActivityStart', onActivityStart, BusEventType.ACTIVITY_START, undefined ],
213
+ [ 'onActivityEnd', onActivityEnd, BusEventType.ACTIVITY_END, { aggregations } ],
214
+ [ 'onActivityError', onActivityError, BusEventType.ACTIVITY_ERROR, { error: new Error( 'activity failed' ) } ]
215
+ ];
216
+
217
+ it.each( cases )( '%s skips internal activities and forwards bus fields', async ( _name, registerHook, eventType, extraFields = {} ) => {
218
+ const handler = vi.fn().mockResolvedValue( undefined );
219
+ registerHook( handler );
220
+
221
+ expect( messageBusMock.on ).toHaveBeenCalledWith( eventType, expect.any( Function ) );
222
+
223
+ await Promise.resolve( onHandlers[eventType]( {
224
+ eventId: 'evt-ignored',
225
+ eventDate,
226
+ activityInfo,
227
+ workflowDetails,
228
+ outputActivityKind: ComponentType.INTERNAL_STEP,
229
+ ...extraFields
230
+ } ) );
231
+ expect( handler ).not.toHaveBeenCalled();
232
+
233
+ await Promise.resolve( onHandlers[eventType]( {
234
+ eventId: 'evt-activity-1',
235
+ eventDate,
236
+ activityInfo,
237
+ workflowDetails,
238
+ outputActivityKind: ComponentType.STEP,
239
+ extra: 'passthrough',
240
+ ...extraFields
241
+ } ) );
242
+
243
+ expect( handler ).toHaveBeenCalledWith( {
244
+ eventId: 'evt-activity-1',
245
+ eventDate,
246
+ activityInfo,
247
+ workflowDetails,
248
+ outputActivityKind: ComponentType.STEP,
249
+ extra: 'passthrough',
250
+ ...extraFields
251
+ } );
252
+ } );
253
+ } );
254
+
201
255
  describe( 'on', () => {
202
256
  it( 'subscribes to external event channel and forwards payload', async () => {
203
257
  const handler = vi.fn().mockResolvedValue( undefined );
package/src/index.d.ts CHANGED
@@ -2,12 +2,12 @@
2
2
  * Export all types from the interface
3
3
  *
4
4
  */
5
- export * from './interface/index.d.ts';
5
+ export * from './interface/index.js';
6
6
 
7
7
  /**
8
8
  * Exports all errors
9
9
  */
10
- export * from './errors.d.ts';
10
+ export * from './errors.js';
11
11
 
12
12
  /**
13
13
  * Expose z from Zod as a convenience.
@@ -22,7 +22,7 @@ export type EvaluatorOptions = {
22
22
  */
23
23
  export type EvaluatorFunction<
24
24
  InputSchema extends AnyZodSchema | undefined = undefined,
25
- Result extends EvaluationResult
25
+ Result extends EvaluationResult = EvaluationResult
26
26
  > = InputSchema extends AnyZodSchema ?
27
27
  ( input: z.infer<InputSchema> ) => Promise<Result> :
28
28
  () => Promise<Result>;
@@ -34,7 +34,7 @@ export type EvaluatorFunction<
34
34
  *
35
35
  * It adds input validation based on the `inputSchema`.
36
36
  */
37
- export type EvaluatorFunctionWrapper<EvaluatorFunction> =
37
+ export type EvaluatorFunctionWrapper<EvaluatorFunction extends ( ...args: any ) => any> = // eslint-disable-line @typescript-eslint/no-explicit-any
38
38
  Parameters<EvaluatorFunction> extends [infer Input] ?
39
39
  ( input: Input ) => ReturnType<EvaluatorFunction> :
40
40
  () => ReturnType<EvaluatorFunction>;
@@ -1,6 +1,5 @@
1
1
  import { EvaluatorValidator } from './validations/index.js';
2
- import { setMetadata } from '#utils';
3
- import { ComponentType } from '#consts';
2
+ import { createEvaluator } from '#helpers/component';
4
3
 
5
4
  /**
6
5
  * Create a new evaluator (activity flavor) and return a wrapper function around its fn handler
@@ -9,13 +8,16 @@ export function evaluator( { name, description, inputSchema, fn, options } ) {
9
8
  EvaluatorValidator.validateDefinition( { name, description, inputSchema, fn, options } );
10
9
  const validator = new EvaluatorValidator( { name, inputSchema } );
11
10
 
12
- const wrapper = async input => {
13
- validator.validateInput( input );
14
- const output = await fn( input );
15
- validator.validateOutput( output );
16
- return output;
17
- };
18
-
19
- setMetadata( wrapper, { name, description, inputSchema, type: ComponentType.EVALUATOR, options } );
20
- return wrapper;
21
- };
11
+ return createEvaluator( {
12
+ name,
13
+ description,
14
+ inputSchema,
15
+ options,
16
+ handler: async input => {
17
+ validator.validateInput( input );
18
+ const output = await fn( input );
19
+ validator.validateOutput( output );
20
+ return output;
21
+ }
22
+ } );
23
+ }
@@ -7,12 +7,12 @@ import {
7
7
  EvaluationFeedback
8
8
  } from './evaluation_result.js';
9
9
  import { ValidationError } from '#errors';
10
- import { ComponentType } from '#consts';
11
10
 
12
11
  const validateDefinitionMock = vi.hoisted( () => vi.fn() );
13
12
  const validateInputMock = vi.hoisted( () => vi.fn() );
14
13
  const validateOutputMock = vi.hoisted( () => vi.fn() );
15
14
  const validatorConstructorMock = vi.hoisted( () => vi.fn() );
15
+ const createEvaluatorMock = vi.hoisted( () => vi.fn( ( { handler } ) => handler ) );
16
16
 
17
17
  vi.mock( './validations/index.js', () => {
18
18
  class EvaluatorValidator {
@@ -30,12 +30,16 @@ vi.mock( './validations/index.js', () => {
30
30
  return { EvaluatorValidator };
31
31
  } );
32
32
 
33
+ vi.mock( '#helpers/component', () => ( {
34
+ createEvaluator: createEvaluatorMock
35
+ } ) );
36
+
33
37
  describe( 'evaluator()', () => {
34
38
  beforeEach( () => {
35
39
  vi.clearAllMocks();
36
40
  } );
37
41
 
38
- it( 'validates the definition, creates a runtime validator, and attaches metadata', async () => {
42
+ it( 'validates the definition, creates a runtime validator, and creates an evaluator component', async () => {
39
43
  const { evaluator } = await import( './evaluator.js' );
40
44
  const inputSchema = { safeParse: vi.fn() };
41
45
  const fn = vi.fn().mockResolvedValue( new EvaluationResult( { value: 'ok', confidence: 1 } ) );
@@ -61,14 +65,14 @@ describe( 'evaluator()', () => {
61
65
  inputSchema
62
66
  } );
63
67
 
64
- const [ metadataSymbol ] = Object.getOwnPropertySymbols( wrapper );
65
- expect( wrapper[metadataSymbol] ).toEqual( {
68
+ expect( createEvaluatorMock ).toHaveBeenCalledWith( {
66
69
  name: 'test_evaluator',
67
70
  description: 'Test evaluator',
68
71
  inputSchema,
69
- type: ComponentType.EVALUATOR,
70
- options
72
+ options,
73
+ handler: expect.any( Function )
71
74
  } );
75
+ expect( wrapper ).toBe( createEvaluatorMock.mock.calls[0][0].handler );
72
76
  } );
73
77
 
74
78
  it( 'validates input and output around the evaluator function', async () => {
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Exports all public methods from the interface
3
3
  */
4
- export * from './webhook.d.ts';
5
- export * from './workflow_utils.d.ts';
6
- export * from './step.d.ts';
7
- export * from './evaluator.d.ts';
8
- export * from './workflow.d.ts';
9
- export * from './evaluation_result.d.ts';
4
+ export * from './webhook.js';
5
+ export * from './workflow_utils.js';
6
+ export * from './step.js';
7
+ export * from './evaluator.js';
8
+ export * from './workflow.js';
9
+ export * from './evaluation_result.js';
10
+ export * from './logger.js';
@@ -10,11 +10,13 @@ import { step } from './step.js';
10
10
  import { workflow } from './workflow.js';
11
11
  import { executeInParallel } from './workflow_utils.js';
12
12
  import { sendHttpRequest, sendPostRequestAndAwaitWebhook } from './webhook.js';
13
+ import { Logger } from './logger.js';
13
14
 
14
15
  export {
15
16
  evaluator,
16
17
  step,
17
18
  workflow,
19
+ Logger,
18
20
  EvaluationNumberResult,
19
21
  EvaluationStringResult,
20
22
  EvaluationBooleanResult,
@@ -0,0 +1,61 @@
1
+ type Logger = {
2
+ /**
3
+ * Log an error (level 0)
4
+ * @param message Log message
5
+ * @param metadata Additional information to be displayed
6
+ */
7
+ error( message: string, metadata?: Record<string, unknown> ) : void,
8
+
9
+ /**
10
+ * Log a warn (level 1)
11
+ * @param message Log message
12
+ * @param metadata Additional information to be displayed
13
+ */
14
+ warn( message: string, metadata?: Record<string, unknown> ) : void,
15
+
16
+ /**
17
+ * Log an info (level 2)
18
+ * @param message Log message
19
+ * @param metadata Additional information to be displayed
20
+ */
21
+ info( message: string, metadata?: Record<string, unknown> ) : void,
22
+
23
+ /**
24
+ * Log http (level 3)
25
+ * @param message Log message
26
+ * @param metadata Additional information to be displayed
27
+ */
28
+ http( message: string, metadata?: Record<string, unknown> ) : void,
29
+
30
+ /**
31
+ * Log verbose (level 4)
32
+ * @param message Log message
33
+ * @param metadata Additional information to be displayed
34
+ */
35
+ verbose( message: string, metadata?: Record<string, unknown> ) : void,
36
+
37
+ /**
38
+ * Log debug (level 5)
39
+ * @param message Log message
40
+ * @param metadata Additional information to be displayed
41
+ */
42
+ debug( message: string, metadata?: Record<string, unknown> ) : void,
43
+
44
+ /**
45
+ * Log silly (level 6)
46
+ * @param message Log message
47
+ * @param metadata Additional information to be displayed
48
+ */
49
+ silly( message: string, metadata?: Record<string, unknown> ) : void,
50
+
51
+ /**
52
+ * Creates a new Logger with a namespace value preset for all emitted logs.
53
+ * @param namespace
54
+ */
55
+ createLogger( namespace: string ) : Logger
56
+ };
57
+
58
+ /**
59
+ * Logger tool. Can be used in activities or workflows. Logs together with the framework's own logs.
60
+ */
61
+ export declare const Logger : Logger;
@@ -0,0 +1,73 @@
1
+ import { inWorkflowContext } from '@temporalio/workflow';
2
+ import { proxySinks } from '@temporalio/workflow';
3
+ import { ACTIVITY_LOGGER_SYMBOL } from '#consts';
4
+ import { isPlainObject } from '#helpers/object';
5
+
6
+ const reservedMetadataFields = new Set( [
7
+ // Winston fields
8
+ 'label',
9
+ 'level',
10
+ 'message',
11
+ 'metadata',
12
+ 'splat',
13
+ 'stack',
14
+ 'timestamp',
15
+ // reserved fields enriched by us
16
+ 'workflowId',
17
+ 'workflowType',
18
+ 'runId',
19
+ 'activityId',
20
+ 'activityType',
21
+ 'service',
22
+ 'environment'
23
+ ] );
24
+
25
+ // This is inoffensive and can be used outside workflow sandbox
26
+ const sinks = proxySinks();
27
+
28
+ // Winston uses npm levels by default: https://github.com/winstonjs/winston#logging-levels
29
+ // Convert npm log levels to console levels
30
+ const levelToConsole = {
31
+ error: 'error',
32
+ warn: 'warn',
33
+ info: 'info',
34
+ http: 'log',
35
+ verbose: 'log',
36
+ debug: 'debug',
37
+ silly: 'log'
38
+ };
39
+ const levels = Object.keys( levelToConsole );
40
+
41
+ /** Drops reserved keys from object */
42
+ const removeReservedFields = obj => Object.fromEntries( Object.entries( obj ).filter( ( [ k ] ) => !reservedMetadataFields.has( k ) ) );
43
+
44
+ /** Dispatch the log message downstream */
45
+ const log = ( level, namespace, message, metadata ) => {
46
+ const baseMetadata = namespace ? { namespace } : {};
47
+ const sanitized = {
48
+ message: String( message ),
49
+ metadata: { ...baseMetadata, ...isPlainObject( metadata ) ? removeReservedFields( metadata ) : {} }
50
+ };
51
+
52
+ // When inside workflow, use sinks to send logs out
53
+ if ( inWorkflowContext() ) {
54
+ sinks.workflow.log( { level, ...sanitized } );
55
+ // When inside activities, use the global function to ship logs
56
+ } else if ( typeof globalThis[ACTIVITY_LOGGER_SYMBOL] === 'function' ) {
57
+ globalThis[ACTIVITY_LOGGER_SYMBOL]( { level, ...sanitized } );
58
+ // This fallback is used on unit tests
59
+ } else {
60
+ console[levelToConsole[level]]( sanitized.message, sanitized.metadata );
61
+ }
62
+ };
63
+
64
+ /** Creates a new logger. It uses the npm levels, and for each level, bind the log function */
65
+ const createLogger = namespace => ( {
66
+ ...Object.fromEntries( levels.map( l => [ l, log.bind( null, l, namespace ) ] ) ),
67
+ createLogger
68
+ } );
69
+
70
+ /** This is the default logger instance */
71
+ const logger = createLogger( null );
72
+
73
+ export { logger as Logger };