@astami/temporal-functions 0.2.2 → 0.3.1

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.
@@ -1,5 +1,5 @@
1
- import { g as ClientConfig, j as TFNClient } from '../types-Curq8YlS.mjs';
2
- export { S as StartWorkflowOptions, i as WorkflowHandle } from '../types-Curq8YlS.mjs';
1
+ import { g as ClientConfig, j as TFNClient } from '../types-DY4y7IE5.mjs';
2
+ export { S as StartWorkflowOptions, i as WorkflowHandle } from '../types-DY4y7IE5.mjs';
3
3
 
4
4
  /**
5
5
  * Temporal Functions - Client Package
@@ -1,5 +1,5 @@
1
- import { g as ClientConfig, j as TFNClient } from '../types-Curq8YlS.js';
2
- export { S as StartWorkflowOptions, i as WorkflowHandle } from '../types-Curq8YlS.js';
1
+ import { g as ClientConfig, j as TFNClient } from '../types-DY4y7IE5.js';
2
+ export { S as StartWorkflowOptions, i as WorkflowHandle } from '../types-DY4y7IE5.js';
3
3
 
4
4
  /**
5
5
  * Temporal Functions - Client Package
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FunctionOptions, a as FunctionDef, W as WorkflowHandler, b as WorkflowOptions, c as WorkflowDef, H as HttpTriggerOptions, C as CronTriggerOptions, R as Registry } from './types-Curq8YlS.mjs';
2
- export { g as ClientConfig, f as RetryPolicy, S as StartWorkflowOptions, j as TFNClient, k as TFNWorker, T as TemporalConfig, h as WorkerConfig, d as WorkflowContext, i as WorkflowHandle, e as WorkflowInfo } from './types-Curq8YlS.mjs';
1
+ import { F as FunctionOptions, a as FunctionDef, W as WorkflowHandler, b as WorkflowOptions, c as WorkflowDef, H as HttpTriggerOptions, C as CronTriggerOptions, R as Registry } from './types-DY4y7IE5.mjs';
2
+ export { g as ClientConfig, f as RetryPolicy, S as StartWorkflowOptions, j as TFNClient, k as TFNWorker, T as TemporalConfig, h as WorkerConfig, d as WorkflowContext, i as WorkflowHandle, e as WorkflowInfo } from './types-DY4y7IE5.mjs';
3
3
 
4
4
  /**
5
5
  * Temporal Functions - Main Entry Point
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FunctionOptions, a as FunctionDef, W as WorkflowHandler, b as WorkflowOptions, c as WorkflowDef, H as HttpTriggerOptions, C as CronTriggerOptions, R as Registry } from './types-Curq8YlS.js';
2
- export { g as ClientConfig, f as RetryPolicy, S as StartWorkflowOptions, j as TFNClient, k as TFNWorker, T as TemporalConfig, h as WorkerConfig, d as WorkflowContext, i as WorkflowHandle, e as WorkflowInfo } from './types-Curq8YlS.js';
1
+ import { F as FunctionOptions, a as FunctionDef, W as WorkflowHandler, b as WorkflowOptions, c as WorkflowDef, H as HttpTriggerOptions, C as CronTriggerOptions, R as Registry } from './types-DY4y7IE5.js';
2
+ export { g as ClientConfig, f as RetryPolicy, S as StartWorkflowOptions, j as TFNClient, k as TFNWorker, T as TemporalConfig, h as WorkerConfig, d as WorkflowContext, i as WorkflowHandle, e as WorkflowInfo } from './types-DY4y7IE5.js';
3
3
 
4
4
  /**
5
5
  * Temporal Functions - Main Entry Point
@@ -0,0 +1,66 @@
1
+ import { l as WorkerInterceptors } from '../types-DY4y7IE5.mjs';
2
+ export { OpenTelemetryActivityInboundInterceptor } from '@temporalio/interceptors-opentelemetry';
3
+ export { OpenTelemetryInboundInterceptor, OpenTelemetryInternalsInterceptor, OpenTelemetryOutboundInterceptor } from '@temporalio/interceptors-opentelemetry/lib/workflow';
4
+
5
+ /**
6
+ * Temporal Functions - Observability Package
7
+ *
8
+ * OpenTelemetry integration for Temporal workers with trace context propagation.
9
+ * Import from '@astami/temporal-functions/observability'.
10
+ */
11
+
12
+ interface WorkerInterceptorsConfig {
13
+ /** Service/processor name for logging */
14
+ serviceName: string;
15
+ /** Optional custom logger (defaults to console) */
16
+ logger?: {
17
+ info: (obj: Record<string, unknown>, msg: string) => void;
18
+ error: (obj: Record<string, unknown>, msg: string) => void;
19
+ };
20
+ }
21
+ /**
22
+ * Creates worker interceptors configuration with OpenTelemetry trace propagation
23
+ *
24
+ * This returns a WorkerInterceptors object that can be passed directly to
25
+ * the worker configuration. It includes:
26
+ * - Activity inbound interceptors for tracing and logging
27
+ *
28
+ * **IMPORTANT**: For end-to-end trace propagation from client -> workflow -> activities,
29
+ * your workflow module must also export an `interceptors` factory function:
30
+ *
31
+ * ```typescript
32
+ * // In your workflows/index.ts
33
+ * import type { WorkflowInterceptorsFactory } from '@temporalio/workflow';
34
+ * import {
35
+ * OpenTelemetryInboundInterceptor,
36
+ * OpenTelemetryOutboundInterceptor,
37
+ * OpenTelemetryInternalsInterceptor,
38
+ * } from '@temporalio/interceptors-opentelemetry/lib/workflow';
39
+ *
40
+ * export const interceptors: WorkflowInterceptorsFactory = () => ({
41
+ * inbound: [new OpenTelemetryInboundInterceptor()],
42
+ * outbound: [new OpenTelemetryOutboundInterceptor()],
43
+ * internals: [new OpenTelemetryInternalsInterceptor()],
44
+ * });
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * import { createWorker } from '@astami/temporal-functions/worker';
50
+ * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';
51
+ * import * as activities from './activities';
52
+ *
53
+ * const worker = createWorker({
54
+ * temporal: { address: 'localhost:7233', namespace: 'loop' },
55
+ * taskQueue: 'stripe-payments',
56
+ * workflowsPath: './dist/workflows/index.js',
57
+ * activities,
58
+ * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),
59
+ * });
60
+ *
61
+ * await worker.start();
62
+ * ```
63
+ */
64
+ declare function createWorkerInterceptors(config: WorkerInterceptorsConfig): WorkerInterceptors;
65
+
66
+ export { type WorkerInterceptorsConfig, createWorkerInterceptors };
@@ -0,0 +1,66 @@
1
+ import { l as WorkerInterceptors } from '../types-DY4y7IE5.js';
2
+ export { OpenTelemetryActivityInboundInterceptor } from '@temporalio/interceptors-opentelemetry';
3
+ export { OpenTelemetryInboundInterceptor, OpenTelemetryInternalsInterceptor, OpenTelemetryOutboundInterceptor } from '@temporalio/interceptors-opentelemetry/lib/workflow';
4
+
5
+ /**
6
+ * Temporal Functions - Observability Package
7
+ *
8
+ * OpenTelemetry integration for Temporal workers with trace context propagation.
9
+ * Import from '@astami/temporal-functions/observability'.
10
+ */
11
+
12
+ interface WorkerInterceptorsConfig {
13
+ /** Service/processor name for logging */
14
+ serviceName: string;
15
+ /** Optional custom logger (defaults to console) */
16
+ logger?: {
17
+ info: (obj: Record<string, unknown>, msg: string) => void;
18
+ error: (obj: Record<string, unknown>, msg: string) => void;
19
+ };
20
+ }
21
+ /**
22
+ * Creates worker interceptors configuration with OpenTelemetry trace propagation
23
+ *
24
+ * This returns a WorkerInterceptors object that can be passed directly to
25
+ * the worker configuration. It includes:
26
+ * - Activity inbound interceptors for tracing and logging
27
+ *
28
+ * **IMPORTANT**: For end-to-end trace propagation from client -> workflow -> activities,
29
+ * your workflow module must also export an `interceptors` factory function:
30
+ *
31
+ * ```typescript
32
+ * // In your workflows/index.ts
33
+ * import type { WorkflowInterceptorsFactory } from '@temporalio/workflow';
34
+ * import {
35
+ * OpenTelemetryInboundInterceptor,
36
+ * OpenTelemetryOutboundInterceptor,
37
+ * OpenTelemetryInternalsInterceptor,
38
+ * } from '@temporalio/interceptors-opentelemetry/lib/workflow';
39
+ *
40
+ * export const interceptors: WorkflowInterceptorsFactory = () => ({
41
+ * inbound: [new OpenTelemetryInboundInterceptor()],
42
+ * outbound: [new OpenTelemetryOutboundInterceptor()],
43
+ * internals: [new OpenTelemetryInternalsInterceptor()],
44
+ * });
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * import { createWorker } from '@astami/temporal-functions/worker';
50
+ * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';
51
+ * import * as activities from './activities';
52
+ *
53
+ * const worker = createWorker({
54
+ * temporal: { address: 'localhost:7233', namespace: 'loop' },
55
+ * taskQueue: 'stripe-payments',
56
+ * workflowsPath: './dist/workflows/index.js',
57
+ * activities,
58
+ * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),
59
+ * });
60
+ *
61
+ * await worker.start();
62
+ * ```
63
+ */
64
+ declare function createWorkerInterceptors(config: WorkerInterceptorsConfig): WorkerInterceptors;
65
+
66
+ export { type WorkerInterceptorsConfig, createWorkerInterceptors };
@@ -0,0 +1,93 @@
1
+ 'use strict';
2
+
3
+ var api = require('@opentelemetry/api');
4
+ var interceptorsOpentelemetry = require('@temporalio/interceptors-opentelemetry');
5
+ var workflow = require('@temporalio/interceptors-opentelemetry/lib/workflow');
6
+
7
+ // src/observability/index.ts
8
+ var TracingActivityInterceptor = class {
9
+ otelInterceptor;
10
+ config;
11
+ ctx;
12
+ constructor(ctx, config) {
13
+ this.ctx = ctx;
14
+ this.config = config;
15
+ this.otelInterceptor = new interceptorsOpentelemetry.OpenTelemetryActivityInboundInterceptor(ctx);
16
+ }
17
+ async execute(input, next) {
18
+ const activityType = this.ctx.info.activityType;
19
+ const workflowId = this.ctx.info.workflowExecution.workflowId;
20
+ const startTime = Date.now();
21
+ const config = this.config;
22
+ const logger = config.logger ?? console;
23
+ const loggingNext = async (nextInput) => {
24
+ const currentSpan = api.trace.getActiveSpan();
25
+ const spanContext = currentSpan?.spanContext();
26
+ logger.info(
27
+ {
28
+ activity: activityType,
29
+ workflowId,
30
+ processor: config.serviceName,
31
+ trace_id: spanContext?.traceId,
32
+ span_id: spanContext?.spanId
33
+ },
34
+ "Activity started"
35
+ );
36
+ try {
37
+ const result = await next(nextInput);
38
+ logger.info(
39
+ {
40
+ activity: activityType,
41
+ workflowId,
42
+ duration: Date.now() - startTime,
43
+ trace_id: spanContext?.traceId,
44
+ span_id: spanContext?.spanId
45
+ },
46
+ "Activity completed"
47
+ );
48
+ return result;
49
+ } catch (error) {
50
+ logger.error(
51
+ {
52
+ activity: activityType,
53
+ workflowId,
54
+ error,
55
+ duration: Date.now() - startTime,
56
+ trace_id: spanContext?.traceId,
57
+ span_id: spanContext?.spanId
58
+ },
59
+ "Activity failed"
60
+ );
61
+ throw error;
62
+ }
63
+ };
64
+ return this.otelInterceptor.execute(input, loggingNext);
65
+ }
66
+ };
67
+ function createWorkerInterceptors(config) {
68
+ return {
69
+ activityInbound: [
70
+ (ctx) => new TracingActivityInterceptor(ctx, config)
71
+ ]
72
+ };
73
+ }
74
+
75
+ Object.defineProperty(exports, "OpenTelemetryActivityInboundInterceptor", {
76
+ enumerable: true,
77
+ get: function () { return interceptorsOpentelemetry.OpenTelemetryActivityInboundInterceptor; }
78
+ });
79
+ Object.defineProperty(exports, "OpenTelemetryInboundInterceptor", {
80
+ enumerable: true,
81
+ get: function () { return workflow.OpenTelemetryInboundInterceptor; }
82
+ });
83
+ Object.defineProperty(exports, "OpenTelemetryInternalsInterceptor", {
84
+ enumerable: true,
85
+ get: function () { return workflow.OpenTelemetryInternalsInterceptor; }
86
+ });
87
+ Object.defineProperty(exports, "OpenTelemetryOutboundInterceptor", {
88
+ enumerable: true,
89
+ get: function () { return workflow.OpenTelemetryOutboundInterceptor; }
90
+ });
91
+ exports.createWorkerInterceptors = createWorkerInterceptors;
92
+ //# sourceMappingURL=index.js.map
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/observability/index.ts"],"names":["OpenTelemetryActivityInboundInterceptor","trace"],"mappings":";;;;;;;AA2CA,IAAM,6BAAN,MAA4E;AAAA,EACzD,eAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAA;AAAA,EAEjB,WAAA,CAAY,KAAsB,MAAA,EAAkC;AAClE,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,IAAA,CAAK,eAAA,GAAkB,IAAIA,iEAAA,CAAwC,GAAG,CAAA;AAAA,EACxE;AAAA,EAEA,MAAM,OAAA,CACJ,KAAA,EACA,IAAA,EACkB;AAClB,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,YAAA;AACnC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,iBAAA,CAAkB,UAAA;AACnD,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,IAAA,MAAM,MAAA,GAAS,OAAO,MAAA,IAAU,OAAA;AAGhC,IAAA,MAAM,WAAA,GAAgE,OACpE,SAAA,KACG;AAEH,MAAA,MAAM,WAAA,GAAcC,UAAM,aAAA,EAAc;AACxC,MAAA,MAAM,WAAA,GAAc,aAAa,WAAA,EAAY;AAE7C,MAAA,MAAA,CAAO,IAAA;AAAA,QACL;AAAA,UACE,QAAA,EAAU,YAAA;AAAA,UACV,UAAA;AAAA,UACA,WAAW,MAAA,CAAO,WAAA;AAAA,UAClB,UAAU,WAAA,EAAa,OAAA;AAAA,UACvB,SAAS,WAAA,EAAa;AAAA,SACxB;AAAA,QACA;AAAA,OACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAS,CAAA;AAEnC,QAAA,MAAA,CAAO,IAAA;AAAA,UACL;AAAA,YACE,QAAA,EAAU,YAAA;AAAA,YACV,UAAA;AAAA,YACA,QAAA,EAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAAA,YACvB,UAAU,WAAA,EAAa,OAAA;AAAA,YACvB,SAAS,WAAA,EAAa;AAAA,WACxB;AAAA,UACA;AAAA,SACF;AAEA,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,MAAA,CAAO,KAAA;AAAA,UACL;AAAA,YACE,QAAA,EAAU,YAAA;AAAA,YACV,UAAA;AAAA,YACA,KAAA;AAAA,YACA,QAAA,EAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAAA,YACvB,UAAU,WAAA,EAAa,OAAA;AAAA,YACvB,SAAS,WAAA,EAAa;AAAA,WACxB;AAAA,UACA;AAAA,SACF;AAEA,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAA;AAIA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA;AAAA,EACxD;AACF,CAAA;AAiDO,SAAS,yBAAyB,MAAA,EAAsD;AAC7F,EAAA,OAAO;AAAA,IACL,eAAA,EAAiB;AAAA,MACf,CAAC,GAAA,KAAyB,IAAI,0BAAA,CAA2B,KAAK,MAAM;AAAA;AACtE,GACF;AACF","file":"index.js","sourcesContent":["/**\n * Temporal Functions - Observability Package\n *\n * OpenTelemetry integration for Temporal workers with trace context propagation.\n * Import from '@astami/temporal-functions/observability'.\n */\n\nimport { trace } from '@opentelemetry/api';\nimport {\n OpenTelemetryActivityInboundInterceptor,\n} from '@temporalio/interceptors-opentelemetry';\nimport type { Context as ActivityContext } from '@temporalio/activity';\nimport type {\n ActivityInboundCallsInterceptor,\n ActivityExecuteInput,\n Next,\n} from '@temporalio/worker';\nimport type { WorkerInterceptors } from '../types.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface WorkerInterceptorsConfig {\n /** Service/processor name for logging */\n serviceName: string;\n /** Optional custom logger (defaults to console) */\n logger?: {\n info: (obj: Record<string, unknown>, msg: string) => void;\n error: (obj: Record<string, unknown>, msg: string) => void;\n };\n}\n\n// =============================================================================\n// Tracing Activity Interceptor\n// =============================================================================\n\n/**\n * Creates an activity interceptor that combines OpenTelemetry tracing with structured logging\n *\n * Uses Temporal's OpenTelemetryActivityInboundInterceptor for trace propagation,\n * and wraps it with additional structured logging that includes trace IDs.\n */\nclass TracingActivityInterceptor implements ActivityInboundCallsInterceptor {\n private readonly otelInterceptor: OpenTelemetryActivityInboundInterceptor;\n private readonly config: WorkerInterceptorsConfig;\n private readonly ctx: ActivityContext;\n\n constructor(ctx: ActivityContext, config: WorkerInterceptorsConfig) {\n this.ctx = ctx;\n this.config = config;\n // Use Temporal's built-in OTel interceptor for proper trace context propagation\n this.otelInterceptor = new OpenTelemetryActivityInboundInterceptor(ctx);\n }\n\n async execute(\n input: ActivityExecuteInput,\n next: Next<ActivityInboundCallsInterceptor, 'execute'>\n ): Promise<unknown> {\n const activityType = this.ctx.info.activityType;\n const workflowId = this.ctx.info.workflowExecution.workflowId;\n const startTime = Date.now();\n const config = this.config;\n const logger = config.logger ?? console;\n\n // Wrap the next function to add logging INSIDE the OTel span context\n const loggingNext: Next<ActivityInboundCallsInterceptor, 'execute'> = async (\n nextInput: ActivityExecuteInput\n ) => {\n // Now we're inside the OTel interceptor's span context\n const currentSpan = trace.getActiveSpan();\n const spanContext = currentSpan?.spanContext();\n\n logger.info(\n {\n activity: activityType,\n workflowId,\n processor: config.serviceName,\n trace_id: spanContext?.traceId,\n span_id: spanContext?.spanId,\n },\n 'Activity started'\n );\n\n try {\n const result = await next(nextInput);\n\n logger.info(\n {\n activity: activityType,\n workflowId,\n duration: Date.now() - startTime,\n trace_id: spanContext?.traceId,\n span_id: spanContext?.spanId,\n },\n 'Activity completed'\n );\n\n return result;\n } catch (error) {\n logger.error(\n {\n activity: activityType,\n workflowId,\n error,\n duration: Date.now() - startTime,\n trace_id: spanContext?.traceId,\n span_id: spanContext?.spanId,\n },\n 'Activity failed'\n );\n\n throw error;\n }\n };\n\n // Delegate to Temporal's OTel interceptor which sets up the span context,\n // then our loggingNext will execute with the proper trace context\n return this.otelInterceptor.execute(input, loggingNext);\n }\n}\n\n// =============================================================================\n// Factory Functions\n// =============================================================================\n\n/**\n * Creates worker interceptors configuration with OpenTelemetry trace propagation\n *\n * This returns a WorkerInterceptors object that can be passed directly to\n * the worker configuration. It includes:\n * - Activity inbound interceptors for tracing and logging\n *\n * **IMPORTANT**: For end-to-end trace propagation from client -> workflow -> activities,\n * your workflow module must also export an `interceptors` factory function:\n *\n * ```typescript\n * // In your workflows/index.ts\n * import type { WorkflowInterceptorsFactory } from '@temporalio/workflow';\n * import {\n * OpenTelemetryInboundInterceptor,\n * OpenTelemetryOutboundInterceptor,\n * OpenTelemetryInternalsInterceptor,\n * } from '@temporalio/interceptors-opentelemetry/lib/workflow';\n *\n * export const interceptors: WorkflowInterceptorsFactory = () => ({\n * inbound: [new OpenTelemetryInboundInterceptor()],\n * outbound: [new OpenTelemetryOutboundInterceptor()],\n * internals: [new OpenTelemetryInternalsInterceptor()],\n * });\n * ```\n *\n * @example\n * ```typescript\n * import { createWorker } from '@astami/temporal-functions/worker';\n * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';\n * import * as activities from './activities';\n *\n * const worker = createWorker({\n * temporal: { address: 'localhost:7233', namespace: 'loop' },\n * taskQueue: 'stripe-payments',\n * workflowsPath: './dist/workflows/index.js',\n * activities,\n * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),\n * });\n *\n * await worker.start();\n * ```\n */\nexport function createWorkerInterceptors(config: WorkerInterceptorsConfig): WorkerInterceptors {\n return {\n activityInbound: [\n (ctx: ActivityContext) => new TracingActivityInterceptor(ctx, config),\n ],\n };\n}\n\n// =============================================================================\n// Re-exports from Temporal OTel package\n// =============================================================================\n\nexport {\n OpenTelemetryActivityInboundInterceptor,\n} from '@temporalio/interceptors-opentelemetry';\n\n// Re-export workflow interceptors for convenience\nexport {\n OpenTelemetryInboundInterceptor,\n OpenTelemetryOutboundInterceptor,\n OpenTelemetryInternalsInterceptor,\n} from '@temporalio/interceptors-opentelemetry/lib/workflow';\n"]}
@@ -0,0 +1,76 @@
1
+ import { trace } from '@opentelemetry/api';
2
+ import { OpenTelemetryActivityInboundInterceptor } from '@temporalio/interceptors-opentelemetry';
3
+ export { OpenTelemetryActivityInboundInterceptor } from '@temporalio/interceptors-opentelemetry';
4
+ export { OpenTelemetryInboundInterceptor, OpenTelemetryInternalsInterceptor, OpenTelemetryOutboundInterceptor } from '@temporalio/interceptors-opentelemetry/lib/workflow';
5
+
6
+ // src/observability/index.ts
7
+ var TracingActivityInterceptor = class {
8
+ otelInterceptor;
9
+ config;
10
+ ctx;
11
+ constructor(ctx, config) {
12
+ this.ctx = ctx;
13
+ this.config = config;
14
+ this.otelInterceptor = new OpenTelemetryActivityInboundInterceptor(ctx);
15
+ }
16
+ async execute(input, next) {
17
+ const activityType = this.ctx.info.activityType;
18
+ const workflowId = this.ctx.info.workflowExecution.workflowId;
19
+ const startTime = Date.now();
20
+ const config = this.config;
21
+ const logger = config.logger ?? console;
22
+ const loggingNext = async (nextInput) => {
23
+ const currentSpan = trace.getActiveSpan();
24
+ const spanContext = currentSpan?.spanContext();
25
+ logger.info(
26
+ {
27
+ activity: activityType,
28
+ workflowId,
29
+ processor: config.serviceName,
30
+ trace_id: spanContext?.traceId,
31
+ span_id: spanContext?.spanId
32
+ },
33
+ "Activity started"
34
+ );
35
+ try {
36
+ const result = await next(nextInput);
37
+ logger.info(
38
+ {
39
+ activity: activityType,
40
+ workflowId,
41
+ duration: Date.now() - startTime,
42
+ trace_id: spanContext?.traceId,
43
+ span_id: spanContext?.spanId
44
+ },
45
+ "Activity completed"
46
+ );
47
+ return result;
48
+ } catch (error) {
49
+ logger.error(
50
+ {
51
+ activity: activityType,
52
+ workflowId,
53
+ error,
54
+ duration: Date.now() - startTime,
55
+ trace_id: spanContext?.traceId,
56
+ span_id: spanContext?.spanId
57
+ },
58
+ "Activity failed"
59
+ );
60
+ throw error;
61
+ }
62
+ };
63
+ return this.otelInterceptor.execute(input, loggingNext);
64
+ }
65
+ };
66
+ function createWorkerInterceptors(config) {
67
+ return {
68
+ activityInbound: [
69
+ (ctx) => new TracingActivityInterceptor(ctx, config)
70
+ ]
71
+ };
72
+ }
73
+
74
+ export { createWorkerInterceptors };
75
+ //# sourceMappingURL=index.mjs.map
76
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/observability/index.ts"],"names":[],"mappings":";;;;;;AA2CA,IAAM,6BAAN,MAA4E;AAAA,EACzD,eAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAA;AAAA,EAEjB,WAAA,CAAY,KAAsB,MAAA,EAAkC;AAClE,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,IAAA,CAAK,eAAA,GAAkB,IAAI,uCAAA,CAAwC,GAAG,CAAA;AAAA,EACxE;AAAA,EAEA,MAAM,OAAA,CACJ,KAAA,EACA,IAAA,EACkB;AAClB,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,YAAA;AACnC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,iBAAA,CAAkB,UAAA;AACnD,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,IAAA,MAAM,MAAA,GAAS,OAAO,MAAA,IAAU,OAAA;AAGhC,IAAA,MAAM,WAAA,GAAgE,OACpE,SAAA,KACG;AAEH,MAAA,MAAM,WAAA,GAAc,MAAM,aAAA,EAAc;AACxC,MAAA,MAAM,WAAA,GAAc,aAAa,WAAA,EAAY;AAE7C,MAAA,MAAA,CAAO,IAAA;AAAA,QACL;AAAA,UACE,QAAA,EAAU,YAAA;AAAA,UACV,UAAA;AAAA,UACA,WAAW,MAAA,CAAO,WAAA;AAAA,UAClB,UAAU,WAAA,EAAa,OAAA;AAAA,UACvB,SAAS,WAAA,EAAa;AAAA,SACxB;AAAA,QACA;AAAA,OACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAS,CAAA;AAEnC,QAAA,MAAA,CAAO,IAAA;AAAA,UACL;AAAA,YACE,QAAA,EAAU,YAAA;AAAA,YACV,UAAA;AAAA,YACA,QAAA,EAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAAA,YACvB,UAAU,WAAA,EAAa,OAAA;AAAA,YACvB,SAAS,WAAA,EAAa;AAAA,WACxB;AAAA,UACA;AAAA,SACF;AAEA,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,MAAA,CAAO,KAAA;AAAA,UACL;AAAA,YACE,QAAA,EAAU,YAAA;AAAA,YACV,UAAA;AAAA,YACA,KAAA;AAAA,YACA,QAAA,EAAU,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAAA,YACvB,UAAU,WAAA,EAAa,OAAA;AAAA,YACvB,SAAS,WAAA,EAAa;AAAA,WACxB;AAAA,UACA;AAAA,SACF;AAEA,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAA;AAIA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA;AAAA,EACxD;AACF,CAAA;AAiDO,SAAS,yBAAyB,MAAA,EAAsD;AAC7F,EAAA,OAAO;AAAA,IACL,eAAA,EAAiB;AAAA,MACf,CAAC,GAAA,KAAyB,IAAI,0BAAA,CAA2B,KAAK,MAAM;AAAA;AACtE,GACF;AACF","file":"index.mjs","sourcesContent":["/**\n * Temporal Functions - Observability Package\n *\n * OpenTelemetry integration for Temporal workers with trace context propagation.\n * Import from '@astami/temporal-functions/observability'.\n */\n\nimport { trace } from '@opentelemetry/api';\nimport {\n OpenTelemetryActivityInboundInterceptor,\n} from '@temporalio/interceptors-opentelemetry';\nimport type { Context as ActivityContext } from '@temporalio/activity';\nimport type {\n ActivityInboundCallsInterceptor,\n ActivityExecuteInput,\n Next,\n} from '@temporalio/worker';\nimport type { WorkerInterceptors } from '../types.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface WorkerInterceptorsConfig {\n /** Service/processor name for logging */\n serviceName: string;\n /** Optional custom logger (defaults to console) */\n logger?: {\n info: (obj: Record<string, unknown>, msg: string) => void;\n error: (obj: Record<string, unknown>, msg: string) => void;\n };\n}\n\n// =============================================================================\n// Tracing Activity Interceptor\n// =============================================================================\n\n/**\n * Creates an activity interceptor that combines OpenTelemetry tracing with structured logging\n *\n * Uses Temporal's OpenTelemetryActivityInboundInterceptor for trace propagation,\n * and wraps it with additional structured logging that includes trace IDs.\n */\nclass TracingActivityInterceptor implements ActivityInboundCallsInterceptor {\n private readonly otelInterceptor: OpenTelemetryActivityInboundInterceptor;\n private readonly config: WorkerInterceptorsConfig;\n private readonly ctx: ActivityContext;\n\n constructor(ctx: ActivityContext, config: WorkerInterceptorsConfig) {\n this.ctx = ctx;\n this.config = config;\n // Use Temporal's built-in OTel interceptor for proper trace context propagation\n this.otelInterceptor = new OpenTelemetryActivityInboundInterceptor(ctx);\n }\n\n async execute(\n input: ActivityExecuteInput,\n next: Next<ActivityInboundCallsInterceptor, 'execute'>\n ): Promise<unknown> {\n const activityType = this.ctx.info.activityType;\n const workflowId = this.ctx.info.workflowExecution.workflowId;\n const startTime = Date.now();\n const config = this.config;\n const logger = config.logger ?? console;\n\n // Wrap the next function to add logging INSIDE the OTel span context\n const loggingNext: Next<ActivityInboundCallsInterceptor, 'execute'> = async (\n nextInput: ActivityExecuteInput\n ) => {\n // Now we're inside the OTel interceptor's span context\n const currentSpan = trace.getActiveSpan();\n const spanContext = currentSpan?.spanContext();\n\n logger.info(\n {\n activity: activityType,\n workflowId,\n processor: config.serviceName,\n trace_id: spanContext?.traceId,\n span_id: spanContext?.spanId,\n },\n 'Activity started'\n );\n\n try {\n const result = await next(nextInput);\n\n logger.info(\n {\n activity: activityType,\n workflowId,\n duration: Date.now() - startTime,\n trace_id: spanContext?.traceId,\n span_id: spanContext?.spanId,\n },\n 'Activity completed'\n );\n\n return result;\n } catch (error) {\n logger.error(\n {\n activity: activityType,\n workflowId,\n error,\n duration: Date.now() - startTime,\n trace_id: spanContext?.traceId,\n span_id: spanContext?.spanId,\n },\n 'Activity failed'\n );\n\n throw error;\n }\n };\n\n // Delegate to Temporal's OTel interceptor which sets up the span context,\n // then our loggingNext will execute with the proper trace context\n return this.otelInterceptor.execute(input, loggingNext);\n }\n}\n\n// =============================================================================\n// Factory Functions\n// =============================================================================\n\n/**\n * Creates worker interceptors configuration with OpenTelemetry trace propagation\n *\n * This returns a WorkerInterceptors object that can be passed directly to\n * the worker configuration. It includes:\n * - Activity inbound interceptors for tracing and logging\n *\n * **IMPORTANT**: For end-to-end trace propagation from client -> workflow -> activities,\n * your workflow module must also export an `interceptors` factory function:\n *\n * ```typescript\n * // In your workflows/index.ts\n * import type { WorkflowInterceptorsFactory } from '@temporalio/workflow';\n * import {\n * OpenTelemetryInboundInterceptor,\n * OpenTelemetryOutboundInterceptor,\n * OpenTelemetryInternalsInterceptor,\n * } from '@temporalio/interceptors-opentelemetry/lib/workflow';\n *\n * export const interceptors: WorkflowInterceptorsFactory = () => ({\n * inbound: [new OpenTelemetryInboundInterceptor()],\n * outbound: [new OpenTelemetryOutboundInterceptor()],\n * internals: [new OpenTelemetryInternalsInterceptor()],\n * });\n * ```\n *\n * @example\n * ```typescript\n * import { createWorker } from '@astami/temporal-functions/worker';\n * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';\n * import * as activities from './activities';\n *\n * const worker = createWorker({\n * temporal: { address: 'localhost:7233', namespace: 'loop' },\n * taskQueue: 'stripe-payments',\n * workflowsPath: './dist/workflows/index.js',\n * activities,\n * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),\n * });\n *\n * await worker.start();\n * ```\n */\nexport function createWorkerInterceptors(config: WorkerInterceptorsConfig): WorkerInterceptors {\n return {\n activityInbound: [\n (ctx: ActivityContext) => new TracingActivityInterceptor(ctx, config),\n ],\n };\n}\n\n// =============================================================================\n// Re-exports from Temporal OTel package\n// =============================================================================\n\nexport {\n OpenTelemetryActivityInboundInterceptor,\n} from '@temporalio/interceptors-opentelemetry';\n\n// Re-export workflow interceptors for convenience\nexport {\n OpenTelemetryInboundInterceptor,\n OpenTelemetryOutboundInterceptor,\n OpenTelemetryInternalsInterceptor,\n} from '@temporalio/interceptors-opentelemetry/lib/workflow';\n"]}
@@ -1,4 +1,4 @@
1
- import { a as FunctionDef, c as WorkflowDef, d as WorkflowContext } from '../types-Curq8YlS.mjs';
1
+ import { a as FunctionDef, c as WorkflowDef, d as WorkflowContext } from '../types-DY4y7IE5.mjs';
2
2
 
3
3
  /**
4
4
  * Temporal Functions - Testing Utilities
@@ -1,4 +1,4 @@
1
- import { a as FunctionDef, c as WorkflowDef, d as WorkflowContext } from '../types-Curq8YlS.js';
1
+ import { a as FunctionDef, c as WorkflowDef, d as WorkflowContext } from '../types-DY4y7IE5.js';
2
2
 
3
3
  /**
4
4
  * Temporal Functions - Testing Utilities
@@ -194,6 +194,30 @@ interface ClientInterceptors {
194
194
  /** Workflow client interceptors (e.g., for OpenTelemetry trace propagation) */
195
195
  workflow?: any[];
196
196
  }
197
+ /**
198
+ * Worker interceptors configuration
199
+ *
200
+ * Supports both activity interceptors and workflow module interceptors
201
+ * for OpenTelemetry trace propagation and custom instrumentation.
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';
206
+ *
207
+ * const worker = tfn.worker({
208
+ * temporal: { address: 'localhost:7233' },
209
+ * taskQueue: 'payments',
210
+ * workflowsPath: './dist/workflows.js',
211
+ * interceptors: createWorkerInterceptors({ serviceName: 'stripe-processor' }),
212
+ * });
213
+ * ```
214
+ */
215
+ interface WorkerInterceptors {
216
+ /** Activity inbound interceptors (e.g., for logging, tracing) */
217
+ activityInbound?: ((ctx: any) => any)[];
218
+ /** Workflow interceptor module paths for bundling (e.g., '@temporalio/interceptors-opentelemetry/lib/workflow') */
219
+ workflowModules?: string[];
220
+ }
197
221
  /**
198
222
  * Client configuration options
199
223
  */
@@ -274,6 +298,12 @@ interface WorkerConfig {
274
298
  temporal: TemporalConfig;
275
299
  /** Task queue to poll */
276
300
  taskQueue: string;
301
+ /** Path to compiled workflow module (for external workflow files) */
302
+ workflowsPath?: string;
303
+ /** Activities object to register */
304
+ activities?: Record<string, (...args: any[]) => Promise<any>>;
305
+ /** Worker interceptors for observability and custom instrumentation */
306
+ interceptors?: WorkerInterceptors;
277
307
  /** Maximum concurrent activity executions */
278
308
  maxConcurrentActivities?: number;
279
309
  /** Maximum concurrent workflow executions */
@@ -330,4 +360,4 @@ interface Registry {
330
360
  workflows: Map<string, WorkflowDef>;
331
361
  }
332
362
 
333
- export type { CronTriggerOptions as C, FunctionOptions as F, HttpTriggerOptions as H, Registry as R, StartWorkflowOptions as S, TemporalConfig as T, WorkflowHandler as W, FunctionDef as a, WorkflowOptions as b, WorkflowDef as c, WorkflowContext as d, WorkflowInfo as e, RetryPolicy as f, ClientConfig as g, WorkerConfig as h, WorkflowHandle as i, TFNClient as j, TFNWorker as k };
363
+ export type { CronTriggerOptions as C, FunctionOptions as F, HttpTriggerOptions as H, Registry as R, StartWorkflowOptions as S, TemporalConfig as T, WorkflowHandler as W, FunctionDef as a, WorkflowOptions as b, WorkflowDef as c, WorkflowContext as d, WorkflowInfo as e, RetryPolicy as f, ClientConfig as g, WorkerConfig as h, WorkflowHandle as i, TFNClient as j, TFNWorker as k, WorkerInterceptors as l };
@@ -194,6 +194,30 @@ interface ClientInterceptors {
194
194
  /** Workflow client interceptors (e.g., for OpenTelemetry trace propagation) */
195
195
  workflow?: any[];
196
196
  }
197
+ /**
198
+ * Worker interceptors configuration
199
+ *
200
+ * Supports both activity interceptors and workflow module interceptors
201
+ * for OpenTelemetry trace propagation and custom instrumentation.
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';
206
+ *
207
+ * const worker = tfn.worker({
208
+ * temporal: { address: 'localhost:7233' },
209
+ * taskQueue: 'payments',
210
+ * workflowsPath: './dist/workflows.js',
211
+ * interceptors: createWorkerInterceptors({ serviceName: 'stripe-processor' }),
212
+ * });
213
+ * ```
214
+ */
215
+ interface WorkerInterceptors {
216
+ /** Activity inbound interceptors (e.g., for logging, tracing) */
217
+ activityInbound?: ((ctx: any) => any)[];
218
+ /** Workflow interceptor module paths for bundling (e.g., '@temporalio/interceptors-opentelemetry/lib/workflow') */
219
+ workflowModules?: string[];
220
+ }
197
221
  /**
198
222
  * Client configuration options
199
223
  */
@@ -274,6 +298,12 @@ interface WorkerConfig {
274
298
  temporal: TemporalConfig;
275
299
  /** Task queue to poll */
276
300
  taskQueue: string;
301
+ /** Path to compiled workflow module (for external workflow files) */
302
+ workflowsPath?: string;
303
+ /** Activities object to register */
304
+ activities?: Record<string, (...args: any[]) => Promise<any>>;
305
+ /** Worker interceptors for observability and custom instrumentation */
306
+ interceptors?: WorkerInterceptors;
277
307
  /** Maximum concurrent activity executions */
278
308
  maxConcurrentActivities?: number;
279
309
  /** Maximum concurrent workflow executions */
@@ -330,4 +360,4 @@ interface Registry {
330
360
  workflows: Map<string, WorkflowDef>;
331
361
  }
332
362
 
333
- export type { CronTriggerOptions as C, FunctionOptions as F, HttpTriggerOptions as H, Registry as R, StartWorkflowOptions as S, TemporalConfig as T, WorkflowHandler as W, FunctionDef as a, WorkflowOptions as b, WorkflowDef as c, WorkflowContext as d, WorkflowInfo as e, RetryPolicy as f, ClientConfig as g, WorkerConfig as h, WorkflowHandle as i, TFNClient as j, TFNWorker as k };
363
+ export type { CronTriggerOptions as C, FunctionOptions as F, HttpTriggerOptions as H, Registry as R, StartWorkflowOptions as S, TemporalConfig as T, WorkflowHandler as W, FunctionDef as a, WorkflowOptions as b, WorkflowDef as c, WorkflowContext as d, WorkflowInfo as e, RetryPolicy as f, ClientConfig as g, WorkerConfig as h, WorkflowHandle as i, TFNClient as j, TFNWorker as k, WorkerInterceptors as l };
@@ -1,4 +1,4 @@
1
- import { h as WorkerConfig, k as TFNWorker } from '../types-Curq8YlS.mjs';
1
+ import { h as WorkerConfig, k as TFNWorker } from '../types-DY4y7IE5.mjs';
2
2
 
3
3
  /**
4
4
  * Temporal Functions - Worker Package
@@ -12,19 +12,34 @@ import { h as WorkerConfig, k as TFNWorker } from '../types-Curq8YlS.mjs';
12
12
  *
13
13
  * @example
14
14
  * ```typescript
15
+ * // Option 1: Using registered functions (tfn pattern)
15
16
  * import { tfn } from 'temporal-functions/worker';
16
17
  * import { validateOrder, processOrder } from './functions';
17
18
  *
18
19
  * const worker = tfn.worker({
19
- * temporal: {
20
- * address: 'localhost:7233',
21
- * namespace: 'default',
22
- * },
20
+ * temporal: { address: 'localhost:7233', namespace: 'default' },
23
21
  * taskQueue: 'my-queue',
24
22
  * });
25
23
  *
26
24
  * worker.register(validateOrder);
27
25
  * worker.register(processOrder);
26
+ * await worker.start();
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Option 2: Using external workflowsPath and activities (processor pattern)
32
+ * import { createWorker } from '@astami/temporal-functions/worker';
33
+ * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';
34
+ * import * as activities from './activities';
35
+ *
36
+ * const worker = createWorker({
37
+ * temporal: { address: 'localhost:7233', namespace: 'loop' },
38
+ * taskQueue: 'stripe-payments',
39
+ * workflowsPath: './dist/workflows/index.js',
40
+ * activities,
41
+ * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),
42
+ * });
28
43
  *
29
44
  * await worker.start();
30
45
  * ```
@@ -1,4 +1,4 @@
1
- import { h as WorkerConfig, k as TFNWorker } from '../types-Curq8YlS.js';
1
+ import { h as WorkerConfig, k as TFNWorker } from '../types-DY4y7IE5.js';
2
2
 
3
3
  /**
4
4
  * Temporal Functions - Worker Package
@@ -12,19 +12,34 @@ import { h as WorkerConfig, k as TFNWorker } from '../types-Curq8YlS.js';
12
12
  *
13
13
  * @example
14
14
  * ```typescript
15
+ * // Option 1: Using registered functions (tfn pattern)
15
16
  * import { tfn } from 'temporal-functions/worker';
16
17
  * import { validateOrder, processOrder } from './functions';
17
18
  *
18
19
  * const worker = tfn.worker({
19
- * temporal: {
20
- * address: 'localhost:7233',
21
- * namespace: 'default',
22
- * },
20
+ * temporal: { address: 'localhost:7233', namespace: 'default' },
23
21
  * taskQueue: 'my-queue',
24
22
  * });
25
23
  *
26
24
  * worker.register(validateOrder);
27
25
  * worker.register(processOrder);
26
+ * await worker.start();
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Option 2: Using external workflowsPath and activities (processor pattern)
32
+ * import { createWorker } from '@astami/temporal-functions/worker';
33
+ * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';
34
+ * import * as activities from './activities';
35
+ *
36
+ * const worker = createWorker({
37
+ * temporal: { address: 'localhost:7233', namespace: 'loop' },
38
+ * taskQueue: 'stripe-payments',
39
+ * workflowsPath: './dist/workflows/index.js',
40
+ * activities,
41
+ * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),
42
+ * });
28
43
  *
29
44
  * await worker.start();
30
45
  * ```
@@ -198,15 +198,22 @@ var TemporalFunctionsWorker = class {
198
198
  * Start the worker
199
199
  */
200
200
  async start() {
201
- if (this.functions.size === 0 && this.workflows.size === 0) {
202
- throw new Error("No functions or workflows registered. Call register() before start().");
201
+ const hasRegisteredFunctions = this.functions.size > 0 || this.workflows.size > 0;
202
+ const hasExternalConfig = this.config.workflowsPath || this.config.activities;
203
+ if (!hasRegisteredFunctions && !hasExternalConfig) {
204
+ throw new Error("No functions, workflows, or external config provided. Either call register() or provide workflowsPath/activities.");
203
205
  }
204
206
  console.log(`Starting Temporal Functions worker...`);
205
207
  console.log(` Temporal: ${this.config.temporal.address}`);
206
208
  console.log(` Namespace: ${this.config.temporal.namespace}`);
207
209
  console.log(` Task Queue: ${this.config.taskQueue}`);
208
- console.log(` Functions: ${this.functions.size}`);
209
- console.log(` Workflows: ${this.workflows.size}`);
210
+ if (this.config.workflowsPath) {
211
+ console.log(` Workflows Path: ${this.config.workflowsPath}`);
212
+ }
213
+ if (hasRegisteredFunctions) {
214
+ console.log(` Registered Functions: ${this.functions.size}`);
215
+ console.log(` Registered Workflows: ${this.workflows.size}`);
216
+ }
210
217
  const connection = await worker.NativeConnection.connect({
211
218
  address: this.config.temporal.address,
212
219
  tls: this.config.temporal.tls ? {
@@ -220,17 +227,39 @@ var TemporalFunctionsWorker = class {
220
227
  } : void 0
221
228
  } : void 0
222
229
  });
223
- const activities = this.buildActivities();
224
- this.worker = await worker.Worker.create({
230
+ const registeredActivities = this.buildActivities();
231
+ const activities = {
232
+ ...registeredActivities,
233
+ ...this.config.activities
234
+ };
235
+ const workerOptions = {
225
236
  connection,
226
237
  namespace: this.config.temporal.namespace,
227
238
  taskQueue: this.config.taskQueue,
228
- activities,
229
- // workflowsPath will need to be provided by the user
230
- // or we need to implement dynamic bundling
239
+ activities: Object.keys(activities).length > 0 ? activities : void 0,
231
240
  maxConcurrentActivityTaskExecutions: this.config.maxConcurrentActivities,
232
241
  maxConcurrentWorkflowTaskExecutions: this.config.maxConcurrentWorkflows
233
- });
242
+ };
243
+ if (this.config.workflowsPath) {
244
+ workerOptions.workflowsPath = this.config.workflowsPath;
245
+ }
246
+ if (this.config.interceptors || this.config.workflowsPath) {
247
+ workerOptions.interceptors = {};
248
+ if (this.config.interceptors?.activityInbound) {
249
+ workerOptions.interceptors.activityInbound = this.config.interceptors.activityInbound;
250
+ }
251
+ const workflowModules = [];
252
+ if (this.config.interceptors?.workflowModules) {
253
+ workflowModules.push(...this.config.interceptors.workflowModules);
254
+ }
255
+ if (this.config.workflowsPath) {
256
+ workflowModules.push(this.config.workflowsPath);
257
+ }
258
+ if (workflowModules.length > 0) {
259
+ workerOptions.interceptors.workflowModules = workflowModules;
260
+ }
261
+ }
262
+ this.worker = await worker.Worker.create(workerOptions);
234
263
  const shutdown = async () => {
235
264
  if (this.shutdownRequested) return;
236
265
  this.shutdownRequested = true;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/worker/index.ts"],"names":["NativeConnection","Worker"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Temporal Functions - Main Entry Point\n *\n * This module provides the core API for defining functions and workflows.\n * Import from 'temporal-functions' for function/workflow definitions.\n * Import from 'temporal-functions/client' for triggering workflows.\n * Import from 'temporal-functions/worker' for running workers.\n */\n\nimport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowHandler,\n Registry,\n HttpTriggerOptions,\n CronTriggerOptions,\n} from './types.js';\n\n// =============================================================================\n// Global Registry\n// =============================================================================\n\n/**\n * Global registry for all defined functions and workflows\n */\nexport const registry: Registry = {\n functions: new Map(),\n workflows: new Map(),\n};\n\n// =============================================================================\n// Function Definition\n// =============================================================================\n\n/**\n * Define a function (maps to a Temporal Activity)\n *\n * @example\n * ```typescript\n * export const sendEmail = tfn.fn(\n * 'sendEmail',\n * async (params: EmailParams) => {\n * return await emailService.send(params);\n * },\n * { timeout: '30s', retries: 3 }\n * );\n * ```\n */\nfunction fn<TInput, TOutput>(\n name: string,\n handler: (input: TInput) => Promise<TOutput>,\n options: FunctionOptions = {}\n): FunctionDef<TInput, TOutput> {\n const def: FunctionDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n startToCloseTimeout: '1m',\n ...options,\n },\n __type: 'function',\n };\n\n registry.functions.set(name, def as FunctionDef);\n return def;\n}\n\n// =============================================================================\n// Workflow Definition\n// =============================================================================\n\n/**\n * Define a workflow\n *\n * @example\n * ```typescript\n * export const processOrder = tfn.workflow(\n * 'processOrder',\n * async (ctx, order: Order) => {\n * const validated = await ctx.run(validateOrder, order);\n * const paid = await ctx.run(chargePayment, validated);\n * return { orderId: paid.id, status: 'complete' };\n * }\n * );\n * ```\n */\nfunction workflow<TInput, TOutput>(\n name: string,\n handler: WorkflowHandler<TInput, TOutput>,\n options: WorkflowOptions = {}\n): WorkflowDef<TInput, TOutput> {\n const def: WorkflowDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n taskQueue: 'default',\n ...options,\n },\n __type: 'workflow',\n };\n\n registry.workflows.set(name, def as WorkflowDef);\n return def;\n}\n\n// =============================================================================\n// Trigger Definitions (Declarative)\n// =============================================================================\n\ninterface HttpTriggerDef {\n type: 'http';\n method: string;\n path: string;\n workflow: WorkflowDef;\n options: HttpTriggerOptions;\n}\n\ninterface CronTriggerDef {\n type: 'cron';\n schedule: string;\n workflow: WorkflowDef;\n options: CronTriggerOptions;\n}\n\ninterface SignalTriggerDef {\n type: 'signal';\n signalName: string;\n handler: (payload: unknown) => void | Promise<void>;\n}\n\ntype TriggerDef = HttpTriggerDef | CronTriggerDef | SignalTriggerDef;\n\n/**\n * Registry for trigger definitions\n */\nexport const triggers: TriggerDef[] = [];\n\n/**\n * Define an HTTP trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.http('POST', '/api/orders', processOrder);\n * ```\n */\nfunction http<TInput, TOutput>(\n method: string,\n path: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: HttpTriggerOptions = {}\n): void {\n triggers.push({\n type: 'http',\n method: method.toUpperCase(),\n path,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define a cron/scheduled trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.cron('0 9 * * *', dailyReport); // Every day at 9am\n * ```\n */\nfunction cron<TInput, TOutput>(\n schedule: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n triggers.push({\n type: 'cron',\n schedule,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define an interval trigger (convenience wrapper around cron)\n *\n * @example\n * ```typescript\n * tfn.interval('5m', healthCheck); // Every 5 minutes\n * ```\n */\nfunction interval<TInput, TOutput>(\n duration: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n // Convert duration to cron expression\n const cronSchedule = durationToCron(duration);\n cron(cronSchedule, workflow, options);\n}\n\n/**\n * Define a signal trigger\n *\n * @example\n * ```typescript\n * tfn.signal('order.cancel', handleCancellation);\n * ```\n */\nfunction signal(\n signalName: string,\n handler: (payload: unknown) => void | Promise<void>\n): void {\n triggers.push({\n type: 'signal',\n signalName,\n handler,\n });\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Convert a duration string to a cron expression\n */\nfunction durationToCron(duration: string): string {\n const match = duration.match(/^(\\d+)(s|m|h|d)$/);\n if (!match) {\n throw new Error(`Invalid duration format: ${duration}. Use format like '5m', '1h', '30s'`);\n }\n\n const value = parseInt(match[1], 10);\n const unit = match[2];\n\n switch (unit) {\n case 's':\n if (value < 60) {\n return `*/${value} * * * * *`; // Every N seconds (non-standard)\n }\n throw new Error('Seconds interval must be less than 60');\n case 'm':\n return `*/${value} * * * *`; // Every N minutes\n case 'h':\n return `0 */${value} * * *`; // Every N hours\n case 'd':\n return `0 0 */${value} * *`; // Every N days\n default:\n throw new Error(`Unknown duration unit: ${unit}`);\n }\n}\n\n/**\n * Check if a definition is a function\n */\nexport function isFunction(def: unknown): def is FunctionDef {\n return (def as FunctionDef)?.__type === 'function';\n}\n\n/**\n * Check if a definition is a workflow\n */\nexport function isWorkflow(def: unknown): def is WorkflowDef {\n return (def as WorkflowDef)?.__type === 'workflow';\n}\n\n// =============================================================================\n// Main API Export\n// =============================================================================\n\n/**\n * The main Temporal Functions API\n */\nexport const tfn = {\n /** Define a function (activity) */\n fn,\n /** Define a workflow */\n workflow,\n /** Define an HTTP trigger */\n http,\n /** Define a cron trigger */\n cron,\n /** Define an interval trigger */\n interval,\n /** Define a signal trigger */\n signal,\n};\n\n// Re-export types\nexport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowContext,\n WorkflowHandler,\n WorkflowInfo,\n RetryPolicy,\n HttpTriggerOptions,\n CronTriggerOptions,\n TemporalConfig,\n ClientConfig,\n WorkerConfig,\n StartWorkflowOptions,\n WorkflowHandle,\n TFNClient,\n TFNWorker,\n} from './types.js';\n\nexport default tfn;\n","/**\n * Temporal Functions - Worker Package\n *\n * Full worker implementation for executing functions and workflows.\n * Import from 'temporal-functions/worker'.\n */\n\nimport { Worker, NativeConnection } from '@temporalio/worker';\nimport type {\n WorkerConfig,\n FunctionDef,\n WorkflowDef,\n TFNWorker,\n} from '../types.js';\nimport { isFunction, isWorkflow } from '../index.js';\n\n// =============================================================================\n// Worker Implementation\n// =============================================================================\n\nclass TemporalFunctionsWorker implements TFNWorker {\n private config: WorkerConfig;\n private functions: Map<string, FunctionDef> = new Map();\n private workflows: Map<string, WorkflowDef> = new Map();\n private worker: Worker | null = null;\n private shutdownRequested = false;\n\n constructor(config: WorkerConfig) {\n this.config = {\n ...config,\n temporal: {\n namespace: 'default',\n ...config.temporal,\n },\n maxConcurrentActivities: config.maxConcurrentActivities ?? 100,\n maxConcurrentWorkflows: config.maxConcurrentWorkflows ?? 50,\n };\n }\n\n /**\n * Register a function or workflow\n */\n register(def: FunctionDef | WorkflowDef): void {\n if (isFunction(def)) {\n this.functions.set(def.name, def);\n } else if (isWorkflow(def)) {\n this.workflows.set(def.name, def);\n } else {\n throw new Error('Invalid definition: must be a function or workflow created with tfn.fn() or tfn.workflow()');\n }\n }\n\n /**\n * Register all exported functions and workflows from a module\n */\n registerModule(module: Record<string, unknown>): void {\n for (const [, value] of Object.entries(module)) {\n if (isFunction(value) || isWorkflow(value)) {\n this.register(value);\n }\n }\n }\n\n /**\n * Build activities object from registered functions\n */\n private buildActivities(): Record<string, (...args: unknown[]) => Promise<unknown>> {\n const activities: Record<string, (...args: unknown[]) => Promise<unknown>> = {};\n\n for (const [name, def] of this.functions) {\n activities[name] = async (input: unknown) => {\n return def.handler(input);\n };\n }\n\n return activities;\n }\n\n /**\n * Generate workflow wrapper code for Temporal\n *\n * This creates the workflow module that Temporal requires,\n * wrapping our user-defined workflow handlers with the proper\n * Temporal workflow context.\n */\n private generateWorkflowBundle(): string {\n const workflowNames = Array.from(this.workflows.keys());\n\n // Generate the workflow module code\n const code = `\n import { proxyActivities, sleep, workflowInfo, setHandler, defineSignal, defineQuery, condition, CancellationScope } from '@temporalio/workflow';\n\n // Proxy all activities\n const activities = proxyActivities({\n startToCloseTimeout: '1 minute',\n });\n\n // Create workflow context\n function createContext() {\n const signalHandlers = new Map();\n const queryHandlers = new Map();\n const signalPayloads = new Map();\n const signalReceived = new Map();\n\n return {\n run: async (fn, input, options = {}) => {\n const activity = activities[fn.name];\n if (!activity) {\n throw new Error(\\`Function \\${fn.name} not registered\\`);\n }\n return activity(input);\n },\n sleep: async (duration) => {\n if (typeof duration === 'string') {\n const ms = parseDuration(duration);\n return sleep(ms);\n }\n return sleep(duration);\n },\n now: () => new Date(),\n startChild: async (workflow, input, options = {}) => {\n throw new Error('startChild not yet implemented');\n },\n continueAsNew: async (input) => {\n throw new Error('continueAsNew not yet implemented');\n },\n onSignal: (signalName, handler) => {\n signalHandlers.set(signalName, handler);\n const signal = defineSignal(signalName);\n setHandler(signal, handler);\n },\n waitForSignal: async (signalName, options = {}) => {\n // Register signal handler if not already registered\n if (!signalReceived.has(signalName)) {\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n const signal = defineSignal(signalName);\n setHandler(signal, (payload) => {\n signalPayloads.set(signalName, payload);\n signalReceived.set(signalName, true);\n });\n }\n\n // Wait for signal with optional timeout\n const timeoutMs = options.timeout ? parseDuration(options.timeout) : undefined;\n const received = await condition(() => signalReceived.get(signalName), timeoutMs);\n\n if (!received) {\n throw new Error(\\`Timeout waiting for signal: \\${signalName}\\`);\n }\n\n // Reset for potential reuse\n const payload = signalPayloads.get(signalName);\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n\n return payload;\n },\n onQuery: (queryName, handler) => {\n queryHandlers.set(queryName, handler);\n const query = defineQuery(queryName);\n setHandler(query, handler);\n },\n get info() {\n const info = workflowInfo();\n return {\n workflowId: info.workflowId,\n runId: info.runId,\n taskQueue: info.taskQueue,\n workflowType: info.workflowType,\n namespace: info.namespace,\n };\n },\n };\n }\n\n // Parse duration string to milliseconds\n function parseDuration(duration) {\n const match = duration.match(/^(\\\\d+(?:\\\\.\\\\d+)?)(ms|s|m|h|d)$/);\n if (!match) {\n throw new Error(\\`Invalid duration: \\${duration}\\`);\n }\n const value = parseFloat(match[1]);\n const unit = match[2];\n switch (unit) {\n case 'ms': return value;\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n case 'd': return value * 24 * 60 * 60 * 1000;\n default: throw new Error(\\`Unknown duration unit: \\${unit}\\`);\n }\n }\n\n // Export workflow functions\n ${workflowNames.map((name) => `\n export async function ${name}(input) {\n const ctx = createContext();\n const handler = __workflowHandlers__.get('${name}');\n if (!handler) {\n throw new Error('Workflow handler not found: ${name}');\n }\n return handler(ctx, input);\n }\n `).join('\\n')}\n `;\n\n return code;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n if (this.functions.size === 0 && this.workflows.size === 0) {\n throw new Error('No functions or workflows registered. Call register() before start().');\n }\n\n console.log(`Starting Temporal Functions worker...`);\n console.log(` Temporal: ${this.config.temporal.address}`);\n console.log(` Namespace: ${this.config.temporal.namespace}`);\n console.log(` Task Queue: ${this.config.taskQueue}`);\n console.log(` Functions: ${this.functions.size}`);\n console.log(` Workflows: ${this.workflows.size}`);\n\n // Connect to Temporal\n const connection = await NativeConnection.connect({\n address: this.config.temporal.address,\n tls: this.config.temporal.tls\n ? {\n clientCertPair: this.config.temporal.tls.clientCertPath\n ? {\n crt: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientCertPath!)\n ),\n key: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientKeyPath!)\n ),\n }\n : undefined,\n }\n : undefined,\n });\n\n // Build activities\n const activities = this.buildActivities();\n\n // For now, we'll use a simplified approach where workflows\n // are bundled separately. In a full implementation, we'd\n // generate the workflow bundle dynamically.\n //\n // TODO: Implement dynamic workflow bundling\n // const workflowBundle = this.generateWorkflowBundle();\n\n // Create worker\n this.worker = await Worker.create({\n connection,\n namespace: this.config.temporal.namespace,\n taskQueue: this.config.taskQueue,\n activities,\n // workflowsPath will need to be provided by the user\n // or we need to implement dynamic bundling\n maxConcurrentActivityTaskExecutions: this.config.maxConcurrentActivities,\n maxConcurrentWorkflowTaskExecutions: this.config.maxConcurrentWorkflows,\n });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n if (this.shutdownRequested) return;\n this.shutdownRequested = true;\n console.log('\\nShutting down worker...');\n await this.shutdown();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n console.log('\\nWorker started. Press Ctrl+C to stop.\\n');\n\n // Run the worker (blocks until shutdown)\n await this.worker.run();\n }\n\n /**\n * Gracefully shutdown the worker\n */\n async shutdown(): Promise<void> {\n if (this.worker) {\n this.worker.shutdown();\n this.worker = null;\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a Temporal Functions worker\n *\n * @example\n * ```typescript\n * import { tfn } from 'temporal-functions/worker';\n * import { validateOrder, processOrder } from './functions';\n *\n * const worker = tfn.worker({\n * temporal: {\n * address: 'localhost:7233',\n * namespace: 'default',\n * },\n * taskQueue: 'my-queue',\n * });\n *\n * worker.register(validateOrder);\n * worker.register(processOrder);\n *\n * await worker.start();\n * ```\n */\nfunction createWorker(config: WorkerConfig): TFNWorker {\n return new TemporalFunctionsWorker(config);\n}\n\n// =============================================================================\n// Export\n// =============================================================================\n\nexport const tfn = {\n worker: createWorker,\n};\n\nexport { createWorker };\nexport type { WorkerConfig, TFNWorker };\nexport default tfn;\n"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/worker/index.ts"],"names":["NativeConnection","Worker"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Temporal Functions - Main Entry Point\n *\n * This module provides the core API for defining functions and workflows.\n * Import from 'temporal-functions' for function/workflow definitions.\n * Import from 'temporal-functions/client' for triggering workflows.\n * Import from 'temporal-functions/worker' for running workers.\n */\n\nimport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowHandler,\n Registry,\n HttpTriggerOptions,\n CronTriggerOptions,\n} from './types.js';\n\n// =============================================================================\n// Global Registry\n// =============================================================================\n\n/**\n * Global registry for all defined functions and workflows\n */\nexport const registry: Registry = {\n functions: new Map(),\n workflows: new Map(),\n};\n\n// =============================================================================\n// Function Definition\n// =============================================================================\n\n/**\n * Define a function (maps to a Temporal Activity)\n *\n * @example\n * ```typescript\n * export const sendEmail = tfn.fn(\n * 'sendEmail',\n * async (params: EmailParams) => {\n * return await emailService.send(params);\n * },\n * { timeout: '30s', retries: 3 }\n * );\n * ```\n */\nfunction fn<TInput, TOutput>(\n name: string,\n handler: (input: TInput) => Promise<TOutput>,\n options: FunctionOptions = {}\n): FunctionDef<TInput, TOutput> {\n const def: FunctionDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n startToCloseTimeout: '1m',\n ...options,\n },\n __type: 'function',\n };\n\n registry.functions.set(name, def as FunctionDef);\n return def;\n}\n\n// =============================================================================\n// Workflow Definition\n// =============================================================================\n\n/**\n * Define a workflow\n *\n * @example\n * ```typescript\n * export const processOrder = tfn.workflow(\n * 'processOrder',\n * async (ctx, order: Order) => {\n * const validated = await ctx.run(validateOrder, order);\n * const paid = await ctx.run(chargePayment, validated);\n * return { orderId: paid.id, status: 'complete' };\n * }\n * );\n * ```\n */\nfunction workflow<TInput, TOutput>(\n name: string,\n handler: WorkflowHandler<TInput, TOutput>,\n options: WorkflowOptions = {}\n): WorkflowDef<TInput, TOutput> {\n const def: WorkflowDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n taskQueue: 'default',\n ...options,\n },\n __type: 'workflow',\n };\n\n registry.workflows.set(name, def as WorkflowDef);\n return def;\n}\n\n// =============================================================================\n// Trigger Definitions (Declarative)\n// =============================================================================\n\ninterface HttpTriggerDef {\n type: 'http';\n method: string;\n path: string;\n workflow: WorkflowDef;\n options: HttpTriggerOptions;\n}\n\ninterface CronTriggerDef {\n type: 'cron';\n schedule: string;\n workflow: WorkflowDef;\n options: CronTriggerOptions;\n}\n\ninterface SignalTriggerDef {\n type: 'signal';\n signalName: string;\n handler: (payload: unknown) => void | Promise<void>;\n}\n\ntype TriggerDef = HttpTriggerDef | CronTriggerDef | SignalTriggerDef;\n\n/**\n * Registry for trigger definitions\n */\nexport const triggers: TriggerDef[] = [];\n\n/**\n * Define an HTTP trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.http('POST', '/api/orders', processOrder);\n * ```\n */\nfunction http<TInput, TOutput>(\n method: string,\n path: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: HttpTriggerOptions = {}\n): void {\n triggers.push({\n type: 'http',\n method: method.toUpperCase(),\n path,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define a cron/scheduled trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.cron('0 9 * * *', dailyReport); // Every day at 9am\n * ```\n */\nfunction cron<TInput, TOutput>(\n schedule: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n triggers.push({\n type: 'cron',\n schedule,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define an interval trigger (convenience wrapper around cron)\n *\n * @example\n * ```typescript\n * tfn.interval('5m', healthCheck); // Every 5 minutes\n * ```\n */\nfunction interval<TInput, TOutput>(\n duration: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n // Convert duration to cron expression\n const cronSchedule = durationToCron(duration);\n cron(cronSchedule, workflow, options);\n}\n\n/**\n * Define a signal trigger\n *\n * @example\n * ```typescript\n * tfn.signal('order.cancel', handleCancellation);\n * ```\n */\nfunction signal(\n signalName: string,\n handler: (payload: unknown) => void | Promise<void>\n): void {\n triggers.push({\n type: 'signal',\n signalName,\n handler,\n });\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Convert a duration string to a cron expression\n */\nfunction durationToCron(duration: string): string {\n const match = duration.match(/^(\\d+)(s|m|h|d)$/);\n if (!match) {\n throw new Error(`Invalid duration format: ${duration}. Use format like '5m', '1h', '30s'`);\n }\n\n const value = parseInt(match[1], 10);\n const unit = match[2];\n\n switch (unit) {\n case 's':\n if (value < 60) {\n return `*/${value} * * * * *`; // Every N seconds (non-standard)\n }\n throw new Error('Seconds interval must be less than 60');\n case 'm':\n return `*/${value} * * * *`; // Every N minutes\n case 'h':\n return `0 */${value} * * *`; // Every N hours\n case 'd':\n return `0 0 */${value} * *`; // Every N days\n default:\n throw new Error(`Unknown duration unit: ${unit}`);\n }\n}\n\n/**\n * Check if a definition is a function\n */\nexport function isFunction(def: unknown): def is FunctionDef {\n return (def as FunctionDef)?.__type === 'function';\n}\n\n/**\n * Check if a definition is a workflow\n */\nexport function isWorkflow(def: unknown): def is WorkflowDef {\n return (def as WorkflowDef)?.__type === 'workflow';\n}\n\n// =============================================================================\n// Main API Export\n// =============================================================================\n\n/**\n * The main Temporal Functions API\n */\nexport const tfn = {\n /** Define a function (activity) */\n fn,\n /** Define a workflow */\n workflow,\n /** Define an HTTP trigger */\n http,\n /** Define a cron trigger */\n cron,\n /** Define an interval trigger */\n interval,\n /** Define a signal trigger */\n signal,\n};\n\n// Re-export types\nexport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowContext,\n WorkflowHandler,\n WorkflowInfo,\n RetryPolicy,\n HttpTriggerOptions,\n CronTriggerOptions,\n TemporalConfig,\n ClientConfig,\n WorkerConfig,\n StartWorkflowOptions,\n WorkflowHandle,\n TFNClient,\n TFNWorker,\n} from './types.js';\n\nexport default tfn;\n","/**\n * Temporal Functions - Worker Package\n *\n * Full worker implementation for executing functions and workflows.\n * Import from 'temporal-functions/worker'.\n */\n\nimport { Worker, NativeConnection } from '@temporalio/worker';\nimport type {\n WorkerConfig,\n FunctionDef,\n WorkflowDef,\n TFNWorker,\n} from '../types.js';\nimport { isFunction, isWorkflow } from '../index.js';\n\n// =============================================================================\n// Worker Implementation\n// =============================================================================\n\nclass TemporalFunctionsWorker implements TFNWorker {\n private config: WorkerConfig;\n private functions: Map<string, FunctionDef> = new Map();\n private workflows: Map<string, WorkflowDef> = new Map();\n private worker: Worker | null = null;\n private shutdownRequested = false;\n\n constructor(config: WorkerConfig) {\n this.config = {\n ...config,\n temporal: {\n namespace: 'default',\n ...config.temporal,\n },\n maxConcurrentActivities: config.maxConcurrentActivities ?? 100,\n maxConcurrentWorkflows: config.maxConcurrentWorkflows ?? 50,\n };\n }\n\n /**\n * Register a function or workflow\n */\n register(def: FunctionDef | WorkflowDef): void {\n if (isFunction(def)) {\n this.functions.set(def.name, def);\n } else if (isWorkflow(def)) {\n this.workflows.set(def.name, def);\n } else {\n throw new Error('Invalid definition: must be a function or workflow created with tfn.fn() or tfn.workflow()');\n }\n }\n\n /**\n * Register all exported functions and workflows from a module\n */\n registerModule(module: Record<string, unknown>): void {\n for (const [, value] of Object.entries(module)) {\n if (isFunction(value) || isWorkflow(value)) {\n this.register(value);\n }\n }\n }\n\n /**\n * Build activities object from registered functions\n */\n private buildActivities(): Record<string, (...args: unknown[]) => Promise<unknown>> {\n const activities: Record<string, (...args: unknown[]) => Promise<unknown>> = {};\n\n for (const [name, def] of this.functions) {\n activities[name] = async (input: unknown) => {\n return def.handler(input);\n };\n }\n\n return activities;\n }\n\n /**\n * Generate workflow wrapper code for Temporal\n *\n * This creates the workflow module that Temporal requires,\n * wrapping our user-defined workflow handlers with the proper\n * Temporal workflow context.\n */\n private generateWorkflowBundle(): string {\n const workflowNames = Array.from(this.workflows.keys());\n\n // Generate the workflow module code\n const code = `\n import { proxyActivities, sleep, workflowInfo, setHandler, defineSignal, defineQuery, condition, CancellationScope } from '@temporalio/workflow';\n\n // Proxy all activities\n const activities = proxyActivities({\n startToCloseTimeout: '1 minute',\n });\n\n // Create workflow context\n function createContext() {\n const signalHandlers = new Map();\n const queryHandlers = new Map();\n const signalPayloads = new Map();\n const signalReceived = new Map();\n\n return {\n run: async (fn, input, options = {}) => {\n const activity = activities[fn.name];\n if (!activity) {\n throw new Error(\\`Function \\${fn.name} not registered\\`);\n }\n return activity(input);\n },\n sleep: async (duration) => {\n if (typeof duration === 'string') {\n const ms = parseDuration(duration);\n return sleep(ms);\n }\n return sleep(duration);\n },\n now: () => new Date(),\n startChild: async (workflow, input, options = {}) => {\n throw new Error('startChild not yet implemented');\n },\n continueAsNew: async (input) => {\n throw new Error('continueAsNew not yet implemented');\n },\n onSignal: (signalName, handler) => {\n signalHandlers.set(signalName, handler);\n const signal = defineSignal(signalName);\n setHandler(signal, handler);\n },\n waitForSignal: async (signalName, options = {}) => {\n // Register signal handler if not already registered\n if (!signalReceived.has(signalName)) {\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n const signal = defineSignal(signalName);\n setHandler(signal, (payload) => {\n signalPayloads.set(signalName, payload);\n signalReceived.set(signalName, true);\n });\n }\n\n // Wait for signal with optional timeout\n const timeoutMs = options.timeout ? parseDuration(options.timeout) : undefined;\n const received = await condition(() => signalReceived.get(signalName), timeoutMs);\n\n if (!received) {\n throw new Error(\\`Timeout waiting for signal: \\${signalName}\\`);\n }\n\n // Reset for potential reuse\n const payload = signalPayloads.get(signalName);\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n\n return payload;\n },\n onQuery: (queryName, handler) => {\n queryHandlers.set(queryName, handler);\n const query = defineQuery(queryName);\n setHandler(query, handler);\n },\n get info() {\n const info = workflowInfo();\n return {\n workflowId: info.workflowId,\n runId: info.runId,\n taskQueue: info.taskQueue,\n workflowType: info.workflowType,\n namespace: info.namespace,\n };\n },\n };\n }\n\n // Parse duration string to milliseconds\n function parseDuration(duration) {\n const match = duration.match(/^(\\\\d+(?:\\\\.\\\\d+)?)(ms|s|m|h|d)$/);\n if (!match) {\n throw new Error(\\`Invalid duration: \\${duration}\\`);\n }\n const value = parseFloat(match[1]);\n const unit = match[2];\n switch (unit) {\n case 'ms': return value;\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n case 'd': return value * 24 * 60 * 60 * 1000;\n default: throw new Error(\\`Unknown duration unit: \\${unit}\\`);\n }\n }\n\n // Export workflow functions\n ${workflowNames.map((name) => `\n export async function ${name}(input) {\n const ctx = createContext();\n const handler = __workflowHandlers__.get('${name}');\n if (!handler) {\n throw new Error('Workflow handler not found: ${name}');\n }\n return handler(ctx, input);\n }\n `).join('\\n')}\n `;\n\n return code;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n // Allow starting with external workflowsPath and activities\n const hasRegisteredFunctions = this.functions.size > 0 || this.workflows.size > 0;\n const hasExternalConfig = this.config.workflowsPath || this.config.activities;\n\n if (!hasRegisteredFunctions && !hasExternalConfig) {\n throw new Error('No functions, workflows, or external config provided. Either call register() or provide workflowsPath/activities.');\n }\n\n console.log(`Starting Temporal Functions worker...`);\n console.log(` Temporal: ${this.config.temporal.address}`);\n console.log(` Namespace: ${this.config.temporal.namespace}`);\n console.log(` Task Queue: ${this.config.taskQueue}`);\n if (this.config.workflowsPath) {\n console.log(` Workflows Path: ${this.config.workflowsPath}`);\n }\n if (hasRegisteredFunctions) {\n console.log(` Registered Functions: ${this.functions.size}`);\n console.log(` Registered Workflows: ${this.workflows.size}`);\n }\n\n // Connect to Temporal\n const connection = await NativeConnection.connect({\n address: this.config.temporal.address,\n tls: this.config.temporal.tls\n ? {\n clientCertPair: this.config.temporal.tls.clientCertPath\n ? {\n crt: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientCertPath!)\n ),\n key: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientKeyPath!)\n ),\n }\n : undefined,\n }\n : undefined,\n });\n\n // Build activities - merge registered functions with external activities\n const registeredActivities = this.buildActivities();\n const activities = {\n ...registeredActivities,\n ...this.config.activities,\n };\n\n // Build worker options\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const workerOptions: any = {\n connection,\n namespace: this.config.temporal.namespace,\n taskQueue: this.config.taskQueue,\n activities: Object.keys(activities).length > 0 ? activities : undefined,\n maxConcurrentActivityTaskExecutions: this.config.maxConcurrentActivities,\n maxConcurrentWorkflowTaskExecutions: this.config.maxConcurrentWorkflows,\n };\n\n // Add workflowsPath if provided (for external workflow files)\n if (this.config.workflowsPath) {\n workerOptions.workflowsPath = this.config.workflowsPath;\n }\n\n // Add interceptors if provided\n if (this.config.interceptors || this.config.workflowsPath) {\n workerOptions.interceptors = {};\n\n if (this.config.interceptors?.activityInbound) {\n workerOptions.interceptors.activityInbound = this.config.interceptors.activityInbound;\n }\n\n // Build workflow modules list:\n // 1. Include any explicitly configured workflowModules\n // 2. IMPORTANT: Also include the workflowsPath so its `interceptors` export is picked up\n // This enables OpenTelemetry trace propagation from the workflow module\n const workflowModules: string[] = [];\n\n if (this.config.interceptors?.workflowModules) {\n workflowModules.push(...this.config.interceptors.workflowModules);\n }\n\n // Auto-include the workflows module as an interceptor module\n // This allows the workflow module to export an `interceptors` factory function\n // that will be automatically invoked by the Temporal runtime\n if (this.config.workflowsPath) {\n workflowModules.push(this.config.workflowsPath);\n }\n\n if (workflowModules.length > 0) {\n workerOptions.interceptors.workflowModules = workflowModules;\n }\n }\n\n // Create worker\n this.worker = await Worker.create(workerOptions);\n\n // Handle graceful shutdown\n const shutdown = async () => {\n if (this.shutdownRequested) return;\n this.shutdownRequested = true;\n console.log('\\nShutting down worker...');\n await this.shutdown();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n console.log('\\nWorker started. Press Ctrl+C to stop.\\n');\n\n // Run the worker (blocks until shutdown)\n await this.worker.run();\n }\n\n /**\n * Gracefully shutdown the worker\n */\n async shutdown(): Promise<void> {\n if (this.worker) {\n this.worker.shutdown();\n this.worker = null;\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a Temporal Functions worker\n *\n * @example\n * ```typescript\n * // Option 1: Using registered functions (tfn pattern)\n * import { tfn } from 'temporal-functions/worker';\n * import { validateOrder, processOrder } from './functions';\n *\n * const worker = tfn.worker({\n * temporal: { address: 'localhost:7233', namespace: 'default' },\n * taskQueue: 'my-queue',\n * });\n *\n * worker.register(validateOrder);\n * worker.register(processOrder);\n * await worker.start();\n * ```\n *\n * @example\n * ```typescript\n * // Option 2: Using external workflowsPath and activities (processor pattern)\n * import { createWorker } from '@astami/temporal-functions/worker';\n * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';\n * import * as activities from './activities';\n *\n * const worker = createWorker({\n * temporal: { address: 'localhost:7233', namespace: 'loop' },\n * taskQueue: 'stripe-payments',\n * workflowsPath: './dist/workflows/index.js',\n * activities,\n * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),\n * });\n *\n * await worker.start();\n * ```\n */\nfunction createWorker(config: WorkerConfig): TFNWorker {\n return new TemporalFunctionsWorker(config);\n}\n\n// =============================================================================\n// Export\n// =============================================================================\n\nexport const tfn = {\n worker: createWorker,\n};\n\nexport { createWorker };\nexport type { WorkerConfig, TFNWorker };\nexport default tfn;\n"]}
@@ -194,15 +194,22 @@ var TemporalFunctionsWorker = class {
194
194
  * Start the worker
195
195
  */
196
196
  async start() {
197
- if (this.functions.size === 0 && this.workflows.size === 0) {
198
- throw new Error("No functions or workflows registered. Call register() before start().");
197
+ const hasRegisteredFunctions = this.functions.size > 0 || this.workflows.size > 0;
198
+ const hasExternalConfig = this.config.workflowsPath || this.config.activities;
199
+ if (!hasRegisteredFunctions && !hasExternalConfig) {
200
+ throw new Error("No functions, workflows, or external config provided. Either call register() or provide workflowsPath/activities.");
199
201
  }
200
202
  console.log(`Starting Temporal Functions worker...`);
201
203
  console.log(` Temporal: ${this.config.temporal.address}`);
202
204
  console.log(` Namespace: ${this.config.temporal.namespace}`);
203
205
  console.log(` Task Queue: ${this.config.taskQueue}`);
204
- console.log(` Functions: ${this.functions.size}`);
205
- console.log(` Workflows: ${this.workflows.size}`);
206
+ if (this.config.workflowsPath) {
207
+ console.log(` Workflows Path: ${this.config.workflowsPath}`);
208
+ }
209
+ if (hasRegisteredFunctions) {
210
+ console.log(` Registered Functions: ${this.functions.size}`);
211
+ console.log(` Registered Workflows: ${this.workflows.size}`);
212
+ }
206
213
  const connection = await NativeConnection.connect({
207
214
  address: this.config.temporal.address,
208
215
  tls: this.config.temporal.tls ? {
@@ -216,17 +223,39 @@ var TemporalFunctionsWorker = class {
216
223
  } : void 0
217
224
  } : void 0
218
225
  });
219
- const activities = this.buildActivities();
220
- this.worker = await Worker.create({
226
+ const registeredActivities = this.buildActivities();
227
+ const activities = {
228
+ ...registeredActivities,
229
+ ...this.config.activities
230
+ };
231
+ const workerOptions = {
221
232
  connection,
222
233
  namespace: this.config.temporal.namespace,
223
234
  taskQueue: this.config.taskQueue,
224
- activities,
225
- // workflowsPath will need to be provided by the user
226
- // or we need to implement dynamic bundling
235
+ activities: Object.keys(activities).length > 0 ? activities : void 0,
227
236
  maxConcurrentActivityTaskExecutions: this.config.maxConcurrentActivities,
228
237
  maxConcurrentWorkflowTaskExecutions: this.config.maxConcurrentWorkflows
229
- });
238
+ };
239
+ if (this.config.workflowsPath) {
240
+ workerOptions.workflowsPath = this.config.workflowsPath;
241
+ }
242
+ if (this.config.interceptors || this.config.workflowsPath) {
243
+ workerOptions.interceptors = {};
244
+ if (this.config.interceptors?.activityInbound) {
245
+ workerOptions.interceptors.activityInbound = this.config.interceptors.activityInbound;
246
+ }
247
+ const workflowModules = [];
248
+ if (this.config.interceptors?.workflowModules) {
249
+ workflowModules.push(...this.config.interceptors.workflowModules);
250
+ }
251
+ if (this.config.workflowsPath) {
252
+ workflowModules.push(this.config.workflowsPath);
253
+ }
254
+ if (workflowModules.length > 0) {
255
+ workerOptions.interceptors.workflowModules = workflowModules;
256
+ }
257
+ }
258
+ this.worker = await Worker.create(workerOptions);
230
259
  const shutdown = async () => {
231
260
  if (this.shutdownRequested) return;
232
261
  this.shutdownRequested = true;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/worker/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Temporal Functions - Main Entry Point\n *\n * This module provides the core API for defining functions and workflows.\n * Import from 'temporal-functions' for function/workflow definitions.\n * Import from 'temporal-functions/client' for triggering workflows.\n * Import from 'temporal-functions/worker' for running workers.\n */\n\nimport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowHandler,\n Registry,\n HttpTriggerOptions,\n CronTriggerOptions,\n} from './types.js';\n\n// =============================================================================\n// Global Registry\n// =============================================================================\n\n/**\n * Global registry for all defined functions and workflows\n */\nexport const registry: Registry = {\n functions: new Map(),\n workflows: new Map(),\n};\n\n// =============================================================================\n// Function Definition\n// =============================================================================\n\n/**\n * Define a function (maps to a Temporal Activity)\n *\n * @example\n * ```typescript\n * export const sendEmail = tfn.fn(\n * 'sendEmail',\n * async (params: EmailParams) => {\n * return await emailService.send(params);\n * },\n * { timeout: '30s', retries: 3 }\n * );\n * ```\n */\nfunction fn<TInput, TOutput>(\n name: string,\n handler: (input: TInput) => Promise<TOutput>,\n options: FunctionOptions = {}\n): FunctionDef<TInput, TOutput> {\n const def: FunctionDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n startToCloseTimeout: '1m',\n ...options,\n },\n __type: 'function',\n };\n\n registry.functions.set(name, def as FunctionDef);\n return def;\n}\n\n// =============================================================================\n// Workflow Definition\n// =============================================================================\n\n/**\n * Define a workflow\n *\n * @example\n * ```typescript\n * export const processOrder = tfn.workflow(\n * 'processOrder',\n * async (ctx, order: Order) => {\n * const validated = await ctx.run(validateOrder, order);\n * const paid = await ctx.run(chargePayment, validated);\n * return { orderId: paid.id, status: 'complete' };\n * }\n * );\n * ```\n */\nfunction workflow<TInput, TOutput>(\n name: string,\n handler: WorkflowHandler<TInput, TOutput>,\n options: WorkflowOptions = {}\n): WorkflowDef<TInput, TOutput> {\n const def: WorkflowDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n taskQueue: 'default',\n ...options,\n },\n __type: 'workflow',\n };\n\n registry.workflows.set(name, def as WorkflowDef);\n return def;\n}\n\n// =============================================================================\n// Trigger Definitions (Declarative)\n// =============================================================================\n\ninterface HttpTriggerDef {\n type: 'http';\n method: string;\n path: string;\n workflow: WorkflowDef;\n options: HttpTriggerOptions;\n}\n\ninterface CronTriggerDef {\n type: 'cron';\n schedule: string;\n workflow: WorkflowDef;\n options: CronTriggerOptions;\n}\n\ninterface SignalTriggerDef {\n type: 'signal';\n signalName: string;\n handler: (payload: unknown) => void | Promise<void>;\n}\n\ntype TriggerDef = HttpTriggerDef | CronTriggerDef | SignalTriggerDef;\n\n/**\n * Registry for trigger definitions\n */\nexport const triggers: TriggerDef[] = [];\n\n/**\n * Define an HTTP trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.http('POST', '/api/orders', processOrder);\n * ```\n */\nfunction http<TInput, TOutput>(\n method: string,\n path: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: HttpTriggerOptions = {}\n): void {\n triggers.push({\n type: 'http',\n method: method.toUpperCase(),\n path,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define a cron/scheduled trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.cron('0 9 * * *', dailyReport); // Every day at 9am\n * ```\n */\nfunction cron<TInput, TOutput>(\n schedule: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n triggers.push({\n type: 'cron',\n schedule,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define an interval trigger (convenience wrapper around cron)\n *\n * @example\n * ```typescript\n * tfn.interval('5m', healthCheck); // Every 5 minutes\n * ```\n */\nfunction interval<TInput, TOutput>(\n duration: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n // Convert duration to cron expression\n const cronSchedule = durationToCron(duration);\n cron(cronSchedule, workflow, options);\n}\n\n/**\n * Define a signal trigger\n *\n * @example\n * ```typescript\n * tfn.signal('order.cancel', handleCancellation);\n * ```\n */\nfunction signal(\n signalName: string,\n handler: (payload: unknown) => void | Promise<void>\n): void {\n triggers.push({\n type: 'signal',\n signalName,\n handler,\n });\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Convert a duration string to a cron expression\n */\nfunction durationToCron(duration: string): string {\n const match = duration.match(/^(\\d+)(s|m|h|d)$/);\n if (!match) {\n throw new Error(`Invalid duration format: ${duration}. Use format like '5m', '1h', '30s'`);\n }\n\n const value = parseInt(match[1], 10);\n const unit = match[2];\n\n switch (unit) {\n case 's':\n if (value < 60) {\n return `*/${value} * * * * *`; // Every N seconds (non-standard)\n }\n throw new Error('Seconds interval must be less than 60');\n case 'm':\n return `*/${value} * * * *`; // Every N minutes\n case 'h':\n return `0 */${value} * * *`; // Every N hours\n case 'd':\n return `0 0 */${value} * *`; // Every N days\n default:\n throw new Error(`Unknown duration unit: ${unit}`);\n }\n}\n\n/**\n * Check if a definition is a function\n */\nexport function isFunction(def: unknown): def is FunctionDef {\n return (def as FunctionDef)?.__type === 'function';\n}\n\n/**\n * Check if a definition is a workflow\n */\nexport function isWorkflow(def: unknown): def is WorkflowDef {\n return (def as WorkflowDef)?.__type === 'workflow';\n}\n\n// =============================================================================\n// Main API Export\n// =============================================================================\n\n/**\n * The main Temporal Functions API\n */\nexport const tfn = {\n /** Define a function (activity) */\n fn,\n /** Define a workflow */\n workflow,\n /** Define an HTTP trigger */\n http,\n /** Define a cron trigger */\n cron,\n /** Define an interval trigger */\n interval,\n /** Define a signal trigger */\n signal,\n};\n\n// Re-export types\nexport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowContext,\n WorkflowHandler,\n WorkflowInfo,\n RetryPolicy,\n HttpTriggerOptions,\n CronTriggerOptions,\n TemporalConfig,\n ClientConfig,\n WorkerConfig,\n StartWorkflowOptions,\n WorkflowHandle,\n TFNClient,\n TFNWorker,\n} from './types.js';\n\nexport default tfn;\n","/**\n * Temporal Functions - Worker Package\n *\n * Full worker implementation for executing functions and workflows.\n * Import from 'temporal-functions/worker'.\n */\n\nimport { Worker, NativeConnection } from '@temporalio/worker';\nimport type {\n WorkerConfig,\n FunctionDef,\n WorkflowDef,\n TFNWorker,\n} from '../types.js';\nimport { isFunction, isWorkflow } from '../index.js';\n\n// =============================================================================\n// Worker Implementation\n// =============================================================================\n\nclass TemporalFunctionsWorker implements TFNWorker {\n private config: WorkerConfig;\n private functions: Map<string, FunctionDef> = new Map();\n private workflows: Map<string, WorkflowDef> = new Map();\n private worker: Worker | null = null;\n private shutdownRequested = false;\n\n constructor(config: WorkerConfig) {\n this.config = {\n ...config,\n temporal: {\n namespace: 'default',\n ...config.temporal,\n },\n maxConcurrentActivities: config.maxConcurrentActivities ?? 100,\n maxConcurrentWorkflows: config.maxConcurrentWorkflows ?? 50,\n };\n }\n\n /**\n * Register a function or workflow\n */\n register(def: FunctionDef | WorkflowDef): void {\n if (isFunction(def)) {\n this.functions.set(def.name, def);\n } else if (isWorkflow(def)) {\n this.workflows.set(def.name, def);\n } else {\n throw new Error('Invalid definition: must be a function or workflow created with tfn.fn() or tfn.workflow()');\n }\n }\n\n /**\n * Register all exported functions and workflows from a module\n */\n registerModule(module: Record<string, unknown>): void {\n for (const [, value] of Object.entries(module)) {\n if (isFunction(value) || isWorkflow(value)) {\n this.register(value);\n }\n }\n }\n\n /**\n * Build activities object from registered functions\n */\n private buildActivities(): Record<string, (...args: unknown[]) => Promise<unknown>> {\n const activities: Record<string, (...args: unknown[]) => Promise<unknown>> = {};\n\n for (const [name, def] of this.functions) {\n activities[name] = async (input: unknown) => {\n return def.handler(input);\n };\n }\n\n return activities;\n }\n\n /**\n * Generate workflow wrapper code for Temporal\n *\n * This creates the workflow module that Temporal requires,\n * wrapping our user-defined workflow handlers with the proper\n * Temporal workflow context.\n */\n private generateWorkflowBundle(): string {\n const workflowNames = Array.from(this.workflows.keys());\n\n // Generate the workflow module code\n const code = `\n import { proxyActivities, sleep, workflowInfo, setHandler, defineSignal, defineQuery, condition, CancellationScope } from '@temporalio/workflow';\n\n // Proxy all activities\n const activities = proxyActivities({\n startToCloseTimeout: '1 minute',\n });\n\n // Create workflow context\n function createContext() {\n const signalHandlers = new Map();\n const queryHandlers = new Map();\n const signalPayloads = new Map();\n const signalReceived = new Map();\n\n return {\n run: async (fn, input, options = {}) => {\n const activity = activities[fn.name];\n if (!activity) {\n throw new Error(\\`Function \\${fn.name} not registered\\`);\n }\n return activity(input);\n },\n sleep: async (duration) => {\n if (typeof duration === 'string') {\n const ms = parseDuration(duration);\n return sleep(ms);\n }\n return sleep(duration);\n },\n now: () => new Date(),\n startChild: async (workflow, input, options = {}) => {\n throw new Error('startChild not yet implemented');\n },\n continueAsNew: async (input) => {\n throw new Error('continueAsNew not yet implemented');\n },\n onSignal: (signalName, handler) => {\n signalHandlers.set(signalName, handler);\n const signal = defineSignal(signalName);\n setHandler(signal, handler);\n },\n waitForSignal: async (signalName, options = {}) => {\n // Register signal handler if not already registered\n if (!signalReceived.has(signalName)) {\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n const signal = defineSignal(signalName);\n setHandler(signal, (payload) => {\n signalPayloads.set(signalName, payload);\n signalReceived.set(signalName, true);\n });\n }\n\n // Wait for signal with optional timeout\n const timeoutMs = options.timeout ? parseDuration(options.timeout) : undefined;\n const received = await condition(() => signalReceived.get(signalName), timeoutMs);\n\n if (!received) {\n throw new Error(\\`Timeout waiting for signal: \\${signalName}\\`);\n }\n\n // Reset for potential reuse\n const payload = signalPayloads.get(signalName);\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n\n return payload;\n },\n onQuery: (queryName, handler) => {\n queryHandlers.set(queryName, handler);\n const query = defineQuery(queryName);\n setHandler(query, handler);\n },\n get info() {\n const info = workflowInfo();\n return {\n workflowId: info.workflowId,\n runId: info.runId,\n taskQueue: info.taskQueue,\n workflowType: info.workflowType,\n namespace: info.namespace,\n };\n },\n };\n }\n\n // Parse duration string to milliseconds\n function parseDuration(duration) {\n const match = duration.match(/^(\\\\d+(?:\\\\.\\\\d+)?)(ms|s|m|h|d)$/);\n if (!match) {\n throw new Error(\\`Invalid duration: \\${duration}\\`);\n }\n const value = parseFloat(match[1]);\n const unit = match[2];\n switch (unit) {\n case 'ms': return value;\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n case 'd': return value * 24 * 60 * 60 * 1000;\n default: throw new Error(\\`Unknown duration unit: \\${unit}\\`);\n }\n }\n\n // Export workflow functions\n ${workflowNames.map((name) => `\n export async function ${name}(input) {\n const ctx = createContext();\n const handler = __workflowHandlers__.get('${name}');\n if (!handler) {\n throw new Error('Workflow handler not found: ${name}');\n }\n return handler(ctx, input);\n }\n `).join('\\n')}\n `;\n\n return code;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n if (this.functions.size === 0 && this.workflows.size === 0) {\n throw new Error('No functions or workflows registered. Call register() before start().');\n }\n\n console.log(`Starting Temporal Functions worker...`);\n console.log(` Temporal: ${this.config.temporal.address}`);\n console.log(` Namespace: ${this.config.temporal.namespace}`);\n console.log(` Task Queue: ${this.config.taskQueue}`);\n console.log(` Functions: ${this.functions.size}`);\n console.log(` Workflows: ${this.workflows.size}`);\n\n // Connect to Temporal\n const connection = await NativeConnection.connect({\n address: this.config.temporal.address,\n tls: this.config.temporal.tls\n ? {\n clientCertPair: this.config.temporal.tls.clientCertPath\n ? {\n crt: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientCertPath!)\n ),\n key: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientKeyPath!)\n ),\n }\n : undefined,\n }\n : undefined,\n });\n\n // Build activities\n const activities = this.buildActivities();\n\n // For now, we'll use a simplified approach where workflows\n // are bundled separately. In a full implementation, we'd\n // generate the workflow bundle dynamically.\n //\n // TODO: Implement dynamic workflow bundling\n // const workflowBundle = this.generateWorkflowBundle();\n\n // Create worker\n this.worker = await Worker.create({\n connection,\n namespace: this.config.temporal.namespace,\n taskQueue: this.config.taskQueue,\n activities,\n // workflowsPath will need to be provided by the user\n // or we need to implement dynamic bundling\n maxConcurrentActivityTaskExecutions: this.config.maxConcurrentActivities,\n maxConcurrentWorkflowTaskExecutions: this.config.maxConcurrentWorkflows,\n });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n if (this.shutdownRequested) return;\n this.shutdownRequested = true;\n console.log('\\nShutting down worker...');\n await this.shutdown();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n console.log('\\nWorker started. Press Ctrl+C to stop.\\n');\n\n // Run the worker (blocks until shutdown)\n await this.worker.run();\n }\n\n /**\n * Gracefully shutdown the worker\n */\n async shutdown(): Promise<void> {\n if (this.worker) {\n this.worker.shutdown();\n this.worker = null;\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a Temporal Functions worker\n *\n * @example\n * ```typescript\n * import { tfn } from 'temporal-functions/worker';\n * import { validateOrder, processOrder } from './functions';\n *\n * const worker = tfn.worker({\n * temporal: {\n * address: 'localhost:7233',\n * namespace: 'default',\n * },\n * taskQueue: 'my-queue',\n * });\n *\n * worker.register(validateOrder);\n * worker.register(processOrder);\n *\n * await worker.start();\n * ```\n */\nfunction createWorker(config: WorkerConfig): TFNWorker {\n return new TemporalFunctionsWorker(config);\n}\n\n// =============================================================================\n// Export\n// =============================================================================\n\nexport const tfn = {\n worker: createWorker,\n};\n\nexport { createWorker };\nexport type { WorkerConfig, TFNWorker };\nexport default tfn;\n"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/worker/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Temporal Functions - Main Entry Point\n *\n * This module provides the core API for defining functions and workflows.\n * Import from 'temporal-functions' for function/workflow definitions.\n * Import from 'temporal-functions/client' for triggering workflows.\n * Import from 'temporal-functions/worker' for running workers.\n */\n\nimport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowHandler,\n Registry,\n HttpTriggerOptions,\n CronTriggerOptions,\n} from './types.js';\n\n// =============================================================================\n// Global Registry\n// =============================================================================\n\n/**\n * Global registry for all defined functions and workflows\n */\nexport const registry: Registry = {\n functions: new Map(),\n workflows: new Map(),\n};\n\n// =============================================================================\n// Function Definition\n// =============================================================================\n\n/**\n * Define a function (maps to a Temporal Activity)\n *\n * @example\n * ```typescript\n * export const sendEmail = tfn.fn(\n * 'sendEmail',\n * async (params: EmailParams) => {\n * return await emailService.send(params);\n * },\n * { timeout: '30s', retries: 3 }\n * );\n * ```\n */\nfunction fn<TInput, TOutput>(\n name: string,\n handler: (input: TInput) => Promise<TOutput>,\n options: FunctionOptions = {}\n): FunctionDef<TInput, TOutput> {\n const def: FunctionDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n startToCloseTimeout: '1m',\n ...options,\n },\n __type: 'function',\n };\n\n registry.functions.set(name, def as FunctionDef);\n return def;\n}\n\n// =============================================================================\n// Workflow Definition\n// =============================================================================\n\n/**\n * Define a workflow\n *\n * @example\n * ```typescript\n * export const processOrder = tfn.workflow(\n * 'processOrder',\n * async (ctx, order: Order) => {\n * const validated = await ctx.run(validateOrder, order);\n * const paid = await ctx.run(chargePayment, validated);\n * return { orderId: paid.id, status: 'complete' };\n * }\n * );\n * ```\n */\nfunction workflow<TInput, TOutput>(\n name: string,\n handler: WorkflowHandler<TInput, TOutput>,\n options: WorkflowOptions = {}\n): WorkflowDef<TInput, TOutput> {\n const def: WorkflowDef<TInput, TOutput> = {\n name,\n handler,\n options: {\n taskQueue: 'default',\n ...options,\n },\n __type: 'workflow',\n };\n\n registry.workflows.set(name, def as WorkflowDef);\n return def;\n}\n\n// =============================================================================\n// Trigger Definitions (Declarative)\n// =============================================================================\n\ninterface HttpTriggerDef {\n type: 'http';\n method: string;\n path: string;\n workflow: WorkflowDef;\n options: HttpTriggerOptions;\n}\n\ninterface CronTriggerDef {\n type: 'cron';\n schedule: string;\n workflow: WorkflowDef;\n options: CronTriggerOptions;\n}\n\ninterface SignalTriggerDef {\n type: 'signal';\n signalName: string;\n handler: (payload: unknown) => void | Promise<void>;\n}\n\ntype TriggerDef = HttpTriggerDef | CronTriggerDef | SignalTriggerDef;\n\n/**\n * Registry for trigger definitions\n */\nexport const triggers: TriggerDef[] = [];\n\n/**\n * Define an HTTP trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.http('POST', '/api/orders', processOrder);\n * ```\n */\nfunction http<TInput, TOutput>(\n method: string,\n path: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: HttpTriggerOptions = {}\n): void {\n triggers.push({\n type: 'http',\n method: method.toUpperCase(),\n path,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define a cron/scheduled trigger for a workflow\n *\n * @example\n * ```typescript\n * tfn.cron('0 9 * * *', dailyReport); // Every day at 9am\n * ```\n */\nfunction cron<TInput, TOutput>(\n schedule: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n triggers.push({\n type: 'cron',\n schedule,\n workflow: workflow as WorkflowDef,\n options,\n });\n}\n\n/**\n * Define an interval trigger (convenience wrapper around cron)\n *\n * @example\n * ```typescript\n * tfn.interval('5m', healthCheck); // Every 5 minutes\n * ```\n */\nfunction interval<TInput, TOutput>(\n duration: string,\n workflow: WorkflowDef<TInput, TOutput>,\n options: CronTriggerOptions = {}\n): void {\n // Convert duration to cron expression\n const cronSchedule = durationToCron(duration);\n cron(cronSchedule, workflow, options);\n}\n\n/**\n * Define a signal trigger\n *\n * @example\n * ```typescript\n * tfn.signal('order.cancel', handleCancellation);\n * ```\n */\nfunction signal(\n signalName: string,\n handler: (payload: unknown) => void | Promise<void>\n): void {\n triggers.push({\n type: 'signal',\n signalName,\n handler,\n });\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Convert a duration string to a cron expression\n */\nfunction durationToCron(duration: string): string {\n const match = duration.match(/^(\\d+)(s|m|h|d)$/);\n if (!match) {\n throw new Error(`Invalid duration format: ${duration}. Use format like '5m', '1h', '30s'`);\n }\n\n const value = parseInt(match[1], 10);\n const unit = match[2];\n\n switch (unit) {\n case 's':\n if (value < 60) {\n return `*/${value} * * * * *`; // Every N seconds (non-standard)\n }\n throw new Error('Seconds interval must be less than 60');\n case 'm':\n return `*/${value} * * * *`; // Every N minutes\n case 'h':\n return `0 */${value} * * *`; // Every N hours\n case 'd':\n return `0 0 */${value} * *`; // Every N days\n default:\n throw new Error(`Unknown duration unit: ${unit}`);\n }\n}\n\n/**\n * Check if a definition is a function\n */\nexport function isFunction(def: unknown): def is FunctionDef {\n return (def as FunctionDef)?.__type === 'function';\n}\n\n/**\n * Check if a definition is a workflow\n */\nexport function isWorkflow(def: unknown): def is WorkflowDef {\n return (def as WorkflowDef)?.__type === 'workflow';\n}\n\n// =============================================================================\n// Main API Export\n// =============================================================================\n\n/**\n * The main Temporal Functions API\n */\nexport const tfn = {\n /** Define a function (activity) */\n fn,\n /** Define a workflow */\n workflow,\n /** Define an HTTP trigger */\n http,\n /** Define a cron trigger */\n cron,\n /** Define an interval trigger */\n interval,\n /** Define a signal trigger */\n signal,\n};\n\n// Re-export types\nexport type {\n FunctionDef,\n FunctionOptions,\n WorkflowDef,\n WorkflowOptions,\n WorkflowContext,\n WorkflowHandler,\n WorkflowInfo,\n RetryPolicy,\n HttpTriggerOptions,\n CronTriggerOptions,\n TemporalConfig,\n ClientConfig,\n WorkerConfig,\n StartWorkflowOptions,\n WorkflowHandle,\n TFNClient,\n TFNWorker,\n} from './types.js';\n\nexport default tfn;\n","/**\n * Temporal Functions - Worker Package\n *\n * Full worker implementation for executing functions and workflows.\n * Import from 'temporal-functions/worker'.\n */\n\nimport { Worker, NativeConnection } from '@temporalio/worker';\nimport type {\n WorkerConfig,\n FunctionDef,\n WorkflowDef,\n TFNWorker,\n} from '../types.js';\nimport { isFunction, isWorkflow } from '../index.js';\n\n// =============================================================================\n// Worker Implementation\n// =============================================================================\n\nclass TemporalFunctionsWorker implements TFNWorker {\n private config: WorkerConfig;\n private functions: Map<string, FunctionDef> = new Map();\n private workflows: Map<string, WorkflowDef> = new Map();\n private worker: Worker | null = null;\n private shutdownRequested = false;\n\n constructor(config: WorkerConfig) {\n this.config = {\n ...config,\n temporal: {\n namespace: 'default',\n ...config.temporal,\n },\n maxConcurrentActivities: config.maxConcurrentActivities ?? 100,\n maxConcurrentWorkflows: config.maxConcurrentWorkflows ?? 50,\n };\n }\n\n /**\n * Register a function or workflow\n */\n register(def: FunctionDef | WorkflowDef): void {\n if (isFunction(def)) {\n this.functions.set(def.name, def);\n } else if (isWorkflow(def)) {\n this.workflows.set(def.name, def);\n } else {\n throw new Error('Invalid definition: must be a function or workflow created with tfn.fn() or tfn.workflow()');\n }\n }\n\n /**\n * Register all exported functions and workflows from a module\n */\n registerModule(module: Record<string, unknown>): void {\n for (const [, value] of Object.entries(module)) {\n if (isFunction(value) || isWorkflow(value)) {\n this.register(value);\n }\n }\n }\n\n /**\n * Build activities object from registered functions\n */\n private buildActivities(): Record<string, (...args: unknown[]) => Promise<unknown>> {\n const activities: Record<string, (...args: unknown[]) => Promise<unknown>> = {};\n\n for (const [name, def] of this.functions) {\n activities[name] = async (input: unknown) => {\n return def.handler(input);\n };\n }\n\n return activities;\n }\n\n /**\n * Generate workflow wrapper code for Temporal\n *\n * This creates the workflow module that Temporal requires,\n * wrapping our user-defined workflow handlers with the proper\n * Temporal workflow context.\n */\n private generateWorkflowBundle(): string {\n const workflowNames = Array.from(this.workflows.keys());\n\n // Generate the workflow module code\n const code = `\n import { proxyActivities, sleep, workflowInfo, setHandler, defineSignal, defineQuery, condition, CancellationScope } from '@temporalio/workflow';\n\n // Proxy all activities\n const activities = proxyActivities({\n startToCloseTimeout: '1 minute',\n });\n\n // Create workflow context\n function createContext() {\n const signalHandlers = new Map();\n const queryHandlers = new Map();\n const signalPayloads = new Map();\n const signalReceived = new Map();\n\n return {\n run: async (fn, input, options = {}) => {\n const activity = activities[fn.name];\n if (!activity) {\n throw new Error(\\`Function \\${fn.name} not registered\\`);\n }\n return activity(input);\n },\n sleep: async (duration) => {\n if (typeof duration === 'string') {\n const ms = parseDuration(duration);\n return sleep(ms);\n }\n return sleep(duration);\n },\n now: () => new Date(),\n startChild: async (workflow, input, options = {}) => {\n throw new Error('startChild not yet implemented');\n },\n continueAsNew: async (input) => {\n throw new Error('continueAsNew not yet implemented');\n },\n onSignal: (signalName, handler) => {\n signalHandlers.set(signalName, handler);\n const signal = defineSignal(signalName);\n setHandler(signal, handler);\n },\n waitForSignal: async (signalName, options = {}) => {\n // Register signal handler if not already registered\n if (!signalReceived.has(signalName)) {\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n const signal = defineSignal(signalName);\n setHandler(signal, (payload) => {\n signalPayloads.set(signalName, payload);\n signalReceived.set(signalName, true);\n });\n }\n\n // Wait for signal with optional timeout\n const timeoutMs = options.timeout ? parseDuration(options.timeout) : undefined;\n const received = await condition(() => signalReceived.get(signalName), timeoutMs);\n\n if (!received) {\n throw new Error(\\`Timeout waiting for signal: \\${signalName}\\`);\n }\n\n // Reset for potential reuse\n const payload = signalPayloads.get(signalName);\n signalReceived.set(signalName, false);\n signalPayloads.set(signalName, undefined);\n\n return payload;\n },\n onQuery: (queryName, handler) => {\n queryHandlers.set(queryName, handler);\n const query = defineQuery(queryName);\n setHandler(query, handler);\n },\n get info() {\n const info = workflowInfo();\n return {\n workflowId: info.workflowId,\n runId: info.runId,\n taskQueue: info.taskQueue,\n workflowType: info.workflowType,\n namespace: info.namespace,\n };\n },\n };\n }\n\n // Parse duration string to milliseconds\n function parseDuration(duration) {\n const match = duration.match(/^(\\\\d+(?:\\\\.\\\\d+)?)(ms|s|m|h|d)$/);\n if (!match) {\n throw new Error(\\`Invalid duration: \\${duration}\\`);\n }\n const value = parseFloat(match[1]);\n const unit = match[2];\n switch (unit) {\n case 'ms': return value;\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n case 'd': return value * 24 * 60 * 60 * 1000;\n default: throw new Error(\\`Unknown duration unit: \\${unit}\\`);\n }\n }\n\n // Export workflow functions\n ${workflowNames.map((name) => `\n export async function ${name}(input) {\n const ctx = createContext();\n const handler = __workflowHandlers__.get('${name}');\n if (!handler) {\n throw new Error('Workflow handler not found: ${name}');\n }\n return handler(ctx, input);\n }\n `).join('\\n')}\n `;\n\n return code;\n }\n\n /**\n * Start the worker\n */\n async start(): Promise<void> {\n // Allow starting with external workflowsPath and activities\n const hasRegisteredFunctions = this.functions.size > 0 || this.workflows.size > 0;\n const hasExternalConfig = this.config.workflowsPath || this.config.activities;\n\n if (!hasRegisteredFunctions && !hasExternalConfig) {\n throw new Error('No functions, workflows, or external config provided. Either call register() or provide workflowsPath/activities.');\n }\n\n console.log(`Starting Temporal Functions worker...`);\n console.log(` Temporal: ${this.config.temporal.address}`);\n console.log(` Namespace: ${this.config.temporal.namespace}`);\n console.log(` Task Queue: ${this.config.taskQueue}`);\n if (this.config.workflowsPath) {\n console.log(` Workflows Path: ${this.config.workflowsPath}`);\n }\n if (hasRegisteredFunctions) {\n console.log(` Registered Functions: ${this.functions.size}`);\n console.log(` Registered Workflows: ${this.workflows.size}`);\n }\n\n // Connect to Temporal\n const connection = await NativeConnection.connect({\n address: this.config.temporal.address,\n tls: this.config.temporal.tls\n ? {\n clientCertPair: this.config.temporal.tls.clientCertPath\n ? {\n crt: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientCertPath!)\n ),\n key: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientKeyPath!)\n ),\n }\n : undefined,\n }\n : undefined,\n });\n\n // Build activities - merge registered functions with external activities\n const registeredActivities = this.buildActivities();\n const activities = {\n ...registeredActivities,\n ...this.config.activities,\n };\n\n // Build worker options\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const workerOptions: any = {\n connection,\n namespace: this.config.temporal.namespace,\n taskQueue: this.config.taskQueue,\n activities: Object.keys(activities).length > 0 ? activities : undefined,\n maxConcurrentActivityTaskExecutions: this.config.maxConcurrentActivities,\n maxConcurrentWorkflowTaskExecutions: this.config.maxConcurrentWorkflows,\n };\n\n // Add workflowsPath if provided (for external workflow files)\n if (this.config.workflowsPath) {\n workerOptions.workflowsPath = this.config.workflowsPath;\n }\n\n // Add interceptors if provided\n if (this.config.interceptors || this.config.workflowsPath) {\n workerOptions.interceptors = {};\n\n if (this.config.interceptors?.activityInbound) {\n workerOptions.interceptors.activityInbound = this.config.interceptors.activityInbound;\n }\n\n // Build workflow modules list:\n // 1. Include any explicitly configured workflowModules\n // 2. IMPORTANT: Also include the workflowsPath so its `interceptors` export is picked up\n // This enables OpenTelemetry trace propagation from the workflow module\n const workflowModules: string[] = [];\n\n if (this.config.interceptors?.workflowModules) {\n workflowModules.push(...this.config.interceptors.workflowModules);\n }\n\n // Auto-include the workflows module as an interceptor module\n // This allows the workflow module to export an `interceptors` factory function\n // that will be automatically invoked by the Temporal runtime\n if (this.config.workflowsPath) {\n workflowModules.push(this.config.workflowsPath);\n }\n\n if (workflowModules.length > 0) {\n workerOptions.interceptors.workflowModules = workflowModules;\n }\n }\n\n // Create worker\n this.worker = await Worker.create(workerOptions);\n\n // Handle graceful shutdown\n const shutdown = async () => {\n if (this.shutdownRequested) return;\n this.shutdownRequested = true;\n console.log('\\nShutting down worker...');\n await this.shutdown();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n console.log('\\nWorker started. Press Ctrl+C to stop.\\n');\n\n // Run the worker (blocks until shutdown)\n await this.worker.run();\n }\n\n /**\n * Gracefully shutdown the worker\n */\n async shutdown(): Promise<void> {\n if (this.worker) {\n this.worker.shutdown();\n this.worker = null;\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a Temporal Functions worker\n *\n * @example\n * ```typescript\n * // Option 1: Using registered functions (tfn pattern)\n * import { tfn } from 'temporal-functions/worker';\n * import { validateOrder, processOrder } from './functions';\n *\n * const worker = tfn.worker({\n * temporal: { address: 'localhost:7233', namespace: 'default' },\n * taskQueue: 'my-queue',\n * });\n *\n * worker.register(validateOrder);\n * worker.register(processOrder);\n * await worker.start();\n * ```\n *\n * @example\n * ```typescript\n * // Option 2: Using external workflowsPath and activities (processor pattern)\n * import { createWorker } from '@astami/temporal-functions/worker';\n * import { createWorkerInterceptors } from '@astami/temporal-functions/observability';\n * import * as activities from './activities';\n *\n * const worker = createWorker({\n * temporal: { address: 'localhost:7233', namespace: 'loop' },\n * taskQueue: 'stripe-payments',\n * workflowsPath: './dist/workflows/index.js',\n * activities,\n * interceptors: createWorkerInterceptors({ serviceName: 'stripe' }),\n * });\n *\n * await worker.start();\n * ```\n */\nfunction createWorker(config: WorkerConfig): TFNWorker {\n return new TemporalFunctionsWorker(config);\n}\n\n// =============================================================================\n// Export\n// =============================================================================\n\nexport const tfn = {\n worker: createWorker,\n};\n\nexport { createWorker };\nexport type { WorkerConfig, TFNWorker };\nexport default tfn;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astami/temporal-functions",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "A lightweight TypeScript framework providing lambda-like DX on top of Temporal's durable execution engine",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -25,6 +25,11 @@
25
25
  "types": "./dist/testing/index.d.ts",
26
26
  "import": "./dist/testing/index.mjs",
27
27
  "require": "./dist/testing/index.js"
28
+ },
29
+ "./observability": {
30
+ "types": "./dist/observability/index.d.ts",
31
+ "import": "./dist/observability/index.mjs",
32
+ "require": "./dist/observability/index.js"
28
33
  }
29
34
  },
30
35
  "files": [
@@ -64,7 +69,9 @@
64
69
  "peerDependencies": {
65
70
  "@temporalio/client": "^1.9.0",
66
71
  "@temporalio/worker": "^1.9.0",
67
- "@temporalio/workflow": "^1.9.0"
72
+ "@temporalio/workflow": "^1.9.0",
73
+ "@temporalio/interceptors-opentelemetry": "^1.9.0",
74
+ "@opentelemetry/api": "^1.0.0"
68
75
  },
69
76
  "peerDependenciesMeta": {
70
77
  "@temporalio/worker": {
@@ -72,6 +79,12 @@
72
79
  },
73
80
  "@temporalio/workflow": {
74
81
  "optional": true
82
+ },
83
+ "@temporalio/interceptors-opentelemetry": {
84
+ "optional": true
85
+ },
86
+ "@opentelemetry/api": {
87
+ "optional": true
75
88
  }
76
89
  },
77
90
  "devDependencies": {
@@ -79,6 +92,8 @@
79
92
  "@temporalio/worker": "^1.11.7",
80
93
  "@temporalio/workflow": "^1.11.7",
81
94
  "@temporalio/activity": "^1.11.7",
95
+ "@temporalio/interceptors-opentelemetry": "^1.11.7",
96
+ "@opentelemetry/api": "^1.9.0",
82
97
  "@types/node": "^20.11.0",
83
98
  "tsup": "^8.0.1",
84
99
  "typescript": "^5.3.3",