@raspect/workflow-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ # @inspectica/workflow-sdk
2
+
3
+ Node.js SDK for Inspectica Workflow Server - Execute workflows and activities.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @inspectica/workflow-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { Worker, workflow, activity } from '@inspectica/workflow-sdk';
15
+
16
+ // Define an activity
17
+ const sayHello = activity.defn(async (input: { name: string }) => {
18
+ return { message: `Hello, ${input.name}!` };
19
+ });
20
+
21
+ // Define a workflow
22
+ @workflow.defn
23
+ class HelloWorldWorkflow {
24
+ @workflow.run
25
+ async run(input: { name: string }) {
26
+ const result = await workflow.executeActivity(sayHello, input);
27
+ return result;
28
+ }
29
+ }
30
+
31
+ // Create and start the worker
32
+ const worker = new Worker({
33
+ serverUrl: 'https://workflow.example.com',
34
+ apiKey: 'wk_your_api_key_here',
35
+ });
36
+
37
+ worker.register({
38
+ workflows: [HelloWorldWorkflow],
39
+ activities: [sayHello],
40
+ });
41
+
42
+ await worker.run();
43
+ ```
44
+
45
+ ## Configuration
46
+
47
+ ### Worker Configuration
48
+
49
+ ```typescript
50
+ const worker = new Worker({
51
+ serverUrl: 'https://workflow.example.com',
52
+ apiKey: 'wk_abc123...',
53
+ groupId: 'my-consumer-group', // optional, defaults to worker-id based
54
+ maxConcurrentWorkflows: 10, // optional, default 10
55
+ });
56
+ ```
57
+
58
+ ## Activities
59
+
60
+ Activities are the building blocks of workflows. They represent individual units of work.
61
+
62
+ ```typescript
63
+ import { activity } from '@inspectica/workflow-sdk';
64
+
65
+ // Simple activity
66
+ const processData = activity.defn(async (input: { data: number[] }) => {
67
+ const sum = input.data.reduce((a, b) => a + b, 0);
68
+ return { sum };
69
+ });
70
+
71
+ // Activity with custom name
72
+ const myActivity = activity.defn(
73
+ async (input: { value: string }) => {
74
+ return { processed: input.value.toUpperCase() };
75
+ },
76
+ 'custom_activity_name' // optional custom name
77
+ );
78
+ ```
79
+
80
+ ## Workflows
81
+
82
+ Workflows orchestrate activities and define the business logic.
83
+
84
+ ```typescript
85
+ import { workflow, activity } from '@inspectica/workflow-sdk';
86
+
87
+ const step1 = activity.defn(async (input: { data: string }) => {
88
+ return { result: input.data + '_step1' };
89
+ });
90
+
91
+ const step2 = activity.defn(async (input: { data: string }) => {
92
+ return { result: input.data + '_step2' };
93
+ });
94
+
95
+ @workflow.defn
96
+ class MyWorkflow {
97
+ @workflow.run
98
+ async run(input: { initialData: string }) {
99
+ // Execute activities sequentially
100
+ const result1 = await workflow.executeActivity(step1, { data: input.initialData });
101
+ const result2 = await workflow.executeActivity(step2, { data: result1.result });
102
+
103
+ return { finalResult: result2.result };
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### Accessing Workflow Context
109
+
110
+ You can access the workflow context to get metadata (like access tokens):
111
+
112
+ ```typescript
113
+ import { workflow, getCurrentContext } from '@inspectica/workflow-sdk';
114
+
115
+ @workflow.defn
116
+ class AuthenticatedWorkflow {
117
+ @workflow.run
118
+ async run(input: { projectId: string }) {
119
+ const ctx = getCurrentContext();
120
+
121
+ // Access metadata passed from the workflow submission
122
+ const accessToken = ctx.metadata.access_token;
123
+ const workflowId = ctx.workflowId;
124
+
125
+ // Use the token for authorization checks
126
+ // ...
127
+
128
+ return { success: true };
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### Cross-Worker Activity Execution
134
+
135
+ You can call activities registered on other workers by using the activity name as a string:
136
+
137
+ ```typescript
138
+ @workflow.defn
139
+ class CrossWorkerWorkflow {
140
+ @workflow.run
141
+ async run(input: { data: string }) {
142
+ // Call an activity on another worker by name
143
+ const result = await workflow.executeActivity(
144
+ 'remote_activity_name', // Activity registered on another worker
145
+ { data: input.data },
146
+ 120000 // timeout in ms
147
+ );
148
+
149
+ return result;
150
+ }
151
+ }
152
+ ```
153
+
154
+ ## API Reference
155
+
156
+ ### Worker
157
+
158
+ ```typescript
159
+ class Worker {
160
+ constructor(config: WorkerConfig);
161
+
162
+ // Register workflows and activities
163
+ register(options: {
164
+ workflows?: WorkflowClass[];
165
+ activities?: ActivityHandler[];
166
+ }): void;
167
+
168
+ // Start the worker (blocking)
169
+ run(): Promise<void>;
170
+
171
+ // Stop the worker gracefully
172
+ stop(): Promise<void>;
173
+ }
174
+
175
+ interface WorkerConfig {
176
+ serverUrl: string;
177
+ apiKey: string;
178
+ groupId?: string;
179
+ maxConcurrentWorkflows?: number;
180
+ }
181
+ ```
182
+
183
+ ### Activity
184
+
185
+ ```typescript
186
+ // Define an activity
187
+ activity.defn<TInput, TOutput>(
188
+ fn: (input: TInput) => Promise<TOutput> | TOutput,
189
+ activityName?: string
190
+ ): ActivityHandler<TInput, TOutput>;
191
+
192
+ // Get activity name
193
+ activity.getActivityName(fn: ActivityHandler | string): string;
194
+
195
+ // Check if function is an activity
196
+ activity.isActivity(fn: unknown): boolean;
197
+ ```
198
+
199
+ ### Workflow
200
+
201
+ ```typescript
202
+ // Class decorator to mark as workflow
203
+ @workflow.defn
204
+ class MyWorkflow { ... }
205
+
206
+ // Method decorator to mark as entry point
207
+ @workflow.run
208
+ async run(input: any) { ... }
209
+
210
+ // Execute an activity within a workflow
211
+ workflow.executeActivity<TInput, TOutput>(
212
+ activity: ActivityHandler<TInput, TOutput> | string,
213
+ inputData?: TInput,
214
+ startToCloseTimeoutMs?: number // default: 60000
215
+ ): Promise<TOutput>;
216
+
217
+ // Get current workflow context
218
+ getCurrentContext(): WorkflowContext;
219
+ ```
220
+
221
+ ### WorkflowContext
222
+
223
+ ```typescript
224
+ class WorkflowContext {
225
+ readonly workflowId: string;
226
+ readonly metadata: Record<string, unknown>;
227
+ readonly activityResults: unknown[];
228
+
229
+ executeActivity<TInput, TOutput>(
230
+ activity: ActivityHandler<TInput, TOutput> | string,
231
+ inputData?: TInput,
232
+ startToCloseTimeoutMs?: number
233
+ ): Promise<TOutput>;
234
+ }
235
+ ```
236
+
237
+ ## Features
238
+
239
+ - **Workflow Execution**: Define and execute complex workflows with multiple activities
240
+ - **Activity Replay**: Automatic replay of completed activities on workflow resume
241
+ - **Cross-Worker Routing**: Execute activities on different workers via the server
242
+ - **Concurrency Control**: Limit concurrent workflow executions to prevent OOM
243
+ - **AWS MSK IAM Support**: Built-in support for AWS MSK with IAM authentication
244
+ - **Graceful Shutdown**: Proper cleanup on SIGINT/SIGTERM signals
245
+ - **Heartbeat**: Automatic heartbeat to keep worker connection alive
246
+
247
+ ## License
248
+
249
+ MIT
@@ -0,0 +1,23 @@
1
+ import type { ActivityHandler } from './types';
2
+ /**
3
+ * Decorator to mark a function as an activity definition.
4
+ *
5
+ * Usage:
6
+ * import { activity } from '@inspectica/workflow-sdk';
7
+ *
8
+ * const myActivity = activity.defn(async (input: { name: string }) => {
9
+ * return { message: `Hello, ${input.name}!` };
10
+ * });
11
+ */
12
+ export declare function defn<TInput = unknown, TOutput = unknown>(fn: ActivityHandler<TInput, TOutput>, activityName?: string): ActivityHandler<TInput, TOutput> & {
13
+ __activityName__: string;
14
+ __isActivity__: boolean;
15
+ };
16
+ /**
17
+ * Get the activity name from a function
18
+ */
19
+ export declare function getActivityName(fn: ActivityHandler | string): string;
20
+ /**
21
+ * Check if a function is a decorated activity
22
+ */
23
+ export declare function isActivity(fn: unknown): boolean;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ // Activity decorators and utilities
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.defn = defn;
5
+ exports.getActivityName = getActivityName;
6
+ exports.isActivity = isActivity;
7
+ // Symbol to store activity metadata
8
+ const ACTIVITY_NAME = Symbol('activityName');
9
+ const IS_ACTIVITY = Symbol('isActivity');
10
+ /**
11
+ * Decorator to mark a function as an activity definition.
12
+ *
13
+ * Usage:
14
+ * import { activity } from '@inspectica/workflow-sdk';
15
+ *
16
+ * const myActivity = activity.defn(async (input: { name: string }) => {
17
+ * return { message: `Hello, ${input.name}!` };
18
+ * });
19
+ */
20
+ function defn(fn, activityName) {
21
+ const name = activityName || fn.name || 'anonymous';
22
+ const decorated = fn;
23
+ decorated.__activityName__ = name;
24
+ decorated.__isActivity__ = true;
25
+ decorated[ACTIVITY_NAME] = name;
26
+ decorated[IS_ACTIVITY] = true;
27
+ return decorated;
28
+ }
29
+ /**
30
+ * Get the activity name from a function
31
+ */
32
+ function getActivityName(fn) {
33
+ if (typeof fn === 'string') {
34
+ return fn;
35
+ }
36
+ return fn.__activityName__ || fn.name || 'anonymous';
37
+ }
38
+ /**
39
+ * Check if a function is a decorated activity
40
+ */
41
+ function isActivity(fn) {
42
+ return typeof fn === 'function' && fn.__isActivity__ === true;
43
+ }
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aXZpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWN0aXZpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLG9DQUFvQzs7QUFrQnBDLG9CQWdCQztBQUtELDBDQUtDO0FBS0QsZ0NBRUM7QUEvQ0Qsb0NBQW9DO0FBQ3BDLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUM3QyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7QUFFekM7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBZ0IsSUFBSSxDQUNsQixFQUFvQyxFQUNwQyxZQUFxQjtJQUVyQixNQUFNLElBQUksR0FBRyxZQUFZLElBQUksRUFBRSxDQUFDLElBQUksSUFBSSxXQUFXLENBQUM7SUFDcEQsTUFBTSxTQUFTLEdBQUcsRUFLakIsQ0FBQztJQUNGLFNBQVMsQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7SUFDbEMsU0FBUyxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7SUFDaEMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxHQUFHLElBQUksQ0FBQztJQUNoQyxTQUFTLENBQUMsV0FBVyxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQzlCLE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxFQUE0QjtJQUMxRCxJQUFJLE9BQU8sRUFBRSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzNCLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUNELE9BQVEsRUFBVSxDQUFDLGdCQUFnQixJQUFJLEVBQUUsQ0FBQyxJQUFJLElBQUksV0FBVyxDQUFDO0FBQ2hFLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLFVBQVUsQ0FBQyxFQUFXO0lBQ3BDLE9BQU8sT0FBTyxFQUFFLEtBQUssVUFBVSxJQUFLLEVBQVUsQ0FBQyxjQUFjLEtBQUssSUFBSSxDQUFDO0FBQ3pFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBBY3Rpdml0eSBkZWNvcmF0b3JzIGFuZCB1dGlsaXRpZXNcblxuaW1wb3J0IHR5cGUgeyBBY3Rpdml0eUhhbmRsZXIgfSBmcm9tICcuL3R5cGVzJztcblxuLy8gU3ltYm9sIHRvIHN0b3JlIGFjdGl2aXR5IG1ldGFkYXRhXG5jb25zdCBBQ1RJVklUWV9OQU1FID0gU3ltYm9sKCdhY3Rpdml0eU5hbWUnKTtcbmNvbnN0IElTX0FDVElWSVRZID0gU3ltYm9sKCdpc0FjdGl2aXR5Jyk7XG5cbi8qKlxuICogRGVjb3JhdG9yIHRvIG1hcmsgYSBmdW5jdGlvbiBhcyBhbiBhY3Rpdml0eSBkZWZpbml0aW9uLlxuICogXG4gKiBVc2FnZTpcbiAqICAgaW1wb3J0IHsgYWN0aXZpdHkgfSBmcm9tICdAaW5zcGVjdGljYS93b3JrZmxvdy1zZGsnO1xuICogICBcbiAqICAgY29uc3QgbXlBY3Rpdml0eSA9IGFjdGl2aXR5LmRlZm4oYXN5bmMgKGlucHV0OiB7IG5hbWU6IHN0cmluZyB9KSA9PiB7XG4gKiAgICAgcmV0dXJuIHsgbWVzc2FnZTogYEhlbGxvLCAke2lucHV0Lm5hbWV9IWAgfTtcbiAqICAgfSk7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWZuPFRJbnB1dCA9IHVua25vd24sIFRPdXRwdXQgPSB1bmtub3duPihcbiAgZm46IEFjdGl2aXR5SGFuZGxlcjxUSW5wdXQsIFRPdXRwdXQ+LFxuICBhY3Rpdml0eU5hbWU/OiBzdHJpbmdcbik6IEFjdGl2aXR5SGFuZGxlcjxUSW5wdXQsIFRPdXRwdXQ+ICYgeyBfX2FjdGl2aXR5TmFtZV9fOiBzdHJpbmc7IF9faXNBY3Rpdml0eV9fOiBib29sZWFuIH0ge1xuICBjb25zdCBuYW1lID0gYWN0aXZpdHlOYW1lIHx8IGZuLm5hbWUgfHwgJ2Fub255bW91cyc7XG4gIGNvbnN0IGRlY29yYXRlZCA9IGZuIGFzIEFjdGl2aXR5SGFuZGxlcjxUSW5wdXQsIFRPdXRwdXQ+ICYgeyBcbiAgICBfX2FjdGl2aXR5TmFtZV9fOiBzdHJpbmc7IFxuICAgIF9faXNBY3Rpdml0eV9fOiBib29sZWFuO1xuICAgIFtBQ1RJVklUWV9OQU1FXTogc3RyaW5nO1xuICAgIFtJU19BQ1RJVklUWV06IGJvb2xlYW47XG4gIH07XG4gIGRlY29yYXRlZC5fX2FjdGl2aXR5TmFtZV9fID0gbmFtZTtcbiAgZGVjb3JhdGVkLl9faXNBY3Rpdml0eV9fID0gdHJ1ZTtcbiAgZGVjb3JhdGVkW0FDVElWSVRZX05BTUVdID0gbmFtZTtcbiAgZGVjb3JhdGVkW0lTX0FDVElWSVRZXSA9IHRydWU7XG4gIHJldHVybiBkZWNvcmF0ZWQ7XG59XG5cbi8qKlxuICogR2V0IHRoZSBhY3Rpdml0eSBuYW1lIGZyb20gYSBmdW5jdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWN0aXZpdHlOYW1lKGZuOiBBY3Rpdml0eUhhbmRsZXIgfCBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAodHlwZW9mIGZuID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmbjtcbiAgfVxuICByZXR1cm4gKGZuIGFzIGFueSkuX19hY3Rpdml0eU5hbWVfXyB8fCBmbi5uYW1lIHx8ICdhbm9ueW1vdXMnO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIGEgZnVuY3Rpb24gaXMgYSBkZWNvcmF0ZWQgYWN0aXZpdHlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQWN0aXZpdHkoZm46IHVua25vd24pOiBib29sZWFuIHtcbiAgcmV0dXJuIHR5cGVvZiBmbiA9PT0gJ2Z1bmN0aW9uJyAmJiAoZm4gYXMgYW55KS5fX2lzQWN0aXZpdHlfXyA9PT0gdHJ1ZTtcbn1cbiJdfQ==
@@ -0,0 +1,5 @@
1
+ export { Worker } from './worker';
2
+ export * as activity from './activity';
3
+ export * as workflow from './workflow';
4
+ export { WorkflowContext, getCurrentContext } from './workflow';
5
+ export type { WorkerConfig, ActivityHandler, WorkflowClass, WorkflowInstance, WorkflowTask, ActivityTask, WorkflowResult, ActivityResult, WorkflowError, ActivityError, CompletedActivity, } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ // Workflow SDK - Node.js Worker for Workflows and Activities
3
+ //
4
+ // Usage:
5
+ // import { Worker, workflow, activity } from '@inspectica/workflow-sdk';
6
+ //
7
+ // const sayHello = activity.defn(async (input: { name: string }) => {
8
+ // return { message: `Hello, ${input.name}!` };
9
+ // });
10
+ //
11
+ // @workflow.defn
12
+ // class HelloWorldWorkflow {
13
+ // @workflow.run
14
+ // async run(input: { name: string }) {
15
+ // return await workflow.executeActivity(sayHello, input);
16
+ // }
17
+ // }
18
+ //
19
+ // const worker = new Worker({
20
+ // serverUrl: 'https://workflow.example.com',
21
+ // apiKey: 'wk_abc123...',
22
+ // });
23
+ // worker.register({ workflows: [HelloWorldWorkflow], activities: [sayHello] });
24
+ // await worker.run();
25
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ var desc = Object.getOwnPropertyDescriptor(m, k);
28
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29
+ desc = { enumerable: true, get: function() { return m[k]; } };
30
+ }
31
+ Object.defineProperty(o, k2, desc);
32
+ }) : (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ o[k2] = m[k];
35
+ }));
36
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
37
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
38
+ }) : function(o, v) {
39
+ o["default"] = v;
40
+ });
41
+ var __importStar = (this && this.__importStar) || (function () {
42
+ var ownKeys = function(o) {
43
+ ownKeys = Object.getOwnPropertyNames || function (o) {
44
+ var ar = [];
45
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
46
+ return ar;
47
+ };
48
+ return ownKeys(o);
49
+ };
50
+ return function (mod) {
51
+ if (mod && mod.__esModule) return mod;
52
+ var result = {};
53
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
54
+ __setModuleDefault(result, mod);
55
+ return result;
56
+ };
57
+ })();
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.getCurrentContext = exports.WorkflowContext = exports.workflow = exports.activity = exports.Worker = void 0;
60
+ var worker_1 = require("./worker");
61
+ Object.defineProperty(exports, "Worker", { enumerable: true, get: function () { return worker_1.Worker; } });
62
+ exports.activity = __importStar(require("./activity"));
63
+ exports.workflow = __importStar(require("./workflow"));
64
+ var workflow_1 = require("./workflow");
65
+ Object.defineProperty(exports, "WorkflowContext", { enumerable: true, get: function () { return workflow_1.WorkflowContext; } });
66
+ Object.defineProperty(exports, "getCurrentContext", { enumerable: true, get: function () { return workflow_1.getCurrentContext; } });
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDZEQUE2RDtBQUM3RCxFQUFFO0FBQ0YsU0FBUztBQUNULDJFQUEyRTtBQUMzRSxFQUFFO0FBQ0Ysd0VBQXdFO0FBQ3hFLG1EQUFtRDtBQUNuRCxRQUFRO0FBQ1IsRUFBRTtBQUNGLG1CQUFtQjtBQUNuQiwrQkFBK0I7QUFDL0Isb0JBQW9CO0FBQ3BCLDJDQUEyQztBQUMzQyxnRUFBZ0U7QUFDaEUsUUFBUTtBQUNSLE1BQU07QUFDTixFQUFFO0FBQ0YsZ0NBQWdDO0FBQ2hDLGlEQUFpRDtBQUNqRCw4QkFBOEI7QUFDOUIsUUFBUTtBQUNSLGtGQUFrRjtBQUNsRix3QkFBd0I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUV4QixtQ0FBa0M7QUFBekIsZ0dBQUEsTUFBTSxPQUFBO0FBQ2YsdURBQXVDO0FBQ3ZDLHVEQUF1QztBQUN2Qyx1Q0FBZ0U7QUFBdkQsMkdBQUEsZUFBZSxPQUFBO0FBQUUsNkdBQUEsaUJBQWlCLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBXb3JrZmxvdyBTREsgLSBOb2RlLmpzIFdvcmtlciBmb3IgV29ya2Zsb3dzIGFuZCBBY3Rpdml0aWVzXG4vL1xuLy8gVXNhZ2U6XG4vLyAgIGltcG9ydCB7IFdvcmtlciwgd29ya2Zsb3csIGFjdGl2aXR5IH0gZnJvbSAnQGluc3BlY3RpY2Evd29ya2Zsb3ctc2RrJztcbi8vXG4vLyAgIGNvbnN0IHNheUhlbGxvID0gYWN0aXZpdHkuZGVmbihhc3luYyAoaW5wdXQ6IHsgbmFtZTogc3RyaW5nIH0pID0+IHtcbi8vICAgICByZXR1cm4geyBtZXNzYWdlOiBgSGVsbG8sICR7aW5wdXQubmFtZX0hYCB9O1xuLy8gICB9KTtcbi8vXG4vLyAgIEB3b3JrZmxvdy5kZWZuXG4vLyAgIGNsYXNzIEhlbGxvV29ybGRXb3JrZmxvdyB7XG4vLyAgICAgQHdvcmtmbG93LnJ1blxuLy8gICAgIGFzeW5jIHJ1bihpbnB1dDogeyBuYW1lOiBzdHJpbmcgfSkge1xuLy8gICAgICAgcmV0dXJuIGF3YWl0IHdvcmtmbG93LmV4ZWN1dGVBY3Rpdml0eShzYXlIZWxsbywgaW5wdXQpO1xuLy8gICAgIH1cbi8vICAgfVxuLy9cbi8vICAgY29uc3Qgd29ya2VyID0gbmV3IFdvcmtlcih7XG4vLyAgICAgc2VydmVyVXJsOiAnaHR0cHM6Ly93b3JrZmxvdy5leGFtcGxlLmNvbScsXG4vLyAgICAgYXBpS2V5OiAnd2tfYWJjMTIzLi4uJyxcbi8vICAgfSk7XG4vLyAgIHdvcmtlci5yZWdpc3Rlcih7IHdvcmtmbG93czogW0hlbGxvV29ybGRXb3JrZmxvd10sIGFjdGl2aXRpZXM6IFtzYXlIZWxsb10gfSk7XG4vLyAgIGF3YWl0IHdvcmtlci5ydW4oKTtcblxuZXhwb3J0IHsgV29ya2VyIH0gZnJvbSAnLi93b3JrZXInO1xuZXhwb3J0ICogYXMgYWN0aXZpdHkgZnJvbSAnLi9hY3Rpdml0eSc7XG5leHBvcnQgKiBhcyB3b3JrZmxvdyBmcm9tICcuL3dvcmtmbG93JztcbmV4cG9ydCB7IFdvcmtmbG93Q29udGV4dCwgZ2V0Q3VycmVudENvbnRleHQgfSBmcm9tICcuL3dvcmtmbG93JztcbmV4cG9ydCB0eXBlIHtcbiAgV29ya2VyQ29uZmlnLFxuICBBY3Rpdml0eUhhbmRsZXIsXG4gIFdvcmtmbG93Q2xhc3MsXG4gIFdvcmtmbG93SW5zdGFuY2UsXG4gIFdvcmtmbG93VGFzayxcbiAgQWN0aXZpdHlUYXNrLFxuICBXb3JrZmxvd1Jlc3VsdCxcbiAgQWN0aXZpdHlSZXN1bHQsXG4gIFdvcmtmbG93RXJyb3IsXG4gIEFjdGl2aXR5RXJyb3IsXG4gIENvbXBsZXRlZEFjdGl2aXR5LFxufSBmcm9tICcuL3R5cGVzJztcbiJdfQ==
@@ -0,0 +1,106 @@
1
+ export interface WorkerConfig {
2
+ serverUrl: string;
3
+ apiKey: string;
4
+ groupId?: string;
5
+ maxConcurrentWorkflows?: number;
6
+ }
7
+ export type ActivityHandler<TInput = unknown, TOutput = unknown> = (input: TInput) => Promise<TOutput> | TOutput;
8
+ export type DecoratedActivity = ActivityHandler<any, any> & {
9
+ __activityName__: string;
10
+ __isActivity__: boolean;
11
+ };
12
+ export type WorkflowClass = new () => WorkflowInstance;
13
+ export interface WorkflowInstance {
14
+ run(input: unknown): Promise<unknown>;
15
+ }
16
+ export interface CompletedActivity {
17
+ index: number;
18
+ name: string;
19
+ output: unknown;
20
+ is_remote: boolean;
21
+ }
22
+ export interface WorkflowTask {
23
+ task_type: 'workflow';
24
+ task_id: string;
25
+ workflow_id: string;
26
+ workflow_name: string;
27
+ input: unknown;
28
+ timeout_ms: number;
29
+ created_at: string;
30
+ completed_activities?: CompletedActivity[];
31
+ metadata?: Record<string, unknown>;
32
+ }
33
+ export interface ActivityTask {
34
+ task_type?: 'activity';
35
+ task_id: string;
36
+ workflow_id: string;
37
+ activity_name: string;
38
+ activity_index: number;
39
+ input: unknown;
40
+ fan_out_index?: number;
41
+ fan_out_total?: number;
42
+ timeout_ms: number;
43
+ retry_count: number;
44
+ created_at: string;
45
+ requester_worker_id?: string;
46
+ correlation_id?: string;
47
+ }
48
+ export interface WorkflowResult {
49
+ task_id: string;
50
+ workflow_id: string;
51
+ workflow_name: string;
52
+ status: 'completed' | 'failed';
53
+ output?: unknown;
54
+ error?: WorkflowError;
55
+ started_at: string;
56
+ completed_at: string;
57
+ duration_ms: number;
58
+ worker_id: string;
59
+ }
60
+ export interface WorkflowError {
61
+ type: string;
62
+ message: string;
63
+ stack_trace?: string;
64
+ }
65
+ export interface ActivityResult {
66
+ task_id: string;
67
+ workflow_id: string;
68
+ activity_name: string;
69
+ activity_index: number;
70
+ fan_out_index?: number;
71
+ status: 'completed' | 'failed';
72
+ output?: unknown;
73
+ error?: ActivityError;
74
+ started_at: string;
75
+ completed_at: string;
76
+ duration_ms: number;
77
+ worker_id: string;
78
+ requester_worker_id?: string;
79
+ correlation_id?: string;
80
+ }
81
+ export interface ActivityError {
82
+ type: string;
83
+ message: string;
84
+ stack_trace?: string;
85
+ }
86
+ export interface KafkaConfig {
87
+ brokers: string[];
88
+ worker_topic: string;
89
+ result_topic: string;
90
+ auth?: {
91
+ type: 'plaintext' | 'sasl' | 'msk_iam';
92
+ region?: string;
93
+ access_key_id?: string;
94
+ secret_access_key?: string;
95
+ security_protocol?: string;
96
+ sasl_mechanism?: string;
97
+ sasl_username?: string;
98
+ sasl_password?: string;
99
+ };
100
+ }
101
+ export interface ConnectResponse {
102
+ worker_id: string;
103
+ instance_id: string;
104
+ heartbeat_interval_ms: number;
105
+ kafka: KafkaConfig;
106
+ }
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // Type definitions for Workflow SDK
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLG9DQUFvQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIFR5cGUgZGVmaW5pdGlvbnMgZm9yIFdvcmtmbG93IFNES1xuXG5leHBvcnQgaW50ZXJmYWNlIFdvcmtlckNvbmZpZyB7XG4gIHNlcnZlclVybDogc3RyaW5nO1xuICBhcGlLZXk6IHN0cmluZztcbiAgZ3JvdXBJZD86IHN0cmluZztcbiAgbWF4Q29uY3VycmVudFdvcmtmbG93cz86IG51bWJlcjtcbn1cblxuZXhwb3J0IHR5cGUgQWN0aXZpdHlIYW5kbGVyPFRJbnB1dCA9IHVua25vd24sIFRPdXRwdXQgPSB1bmtub3duPiA9IChcbiAgaW5wdXQ6IFRJbnB1dFxuKSA9PiBQcm9taXNlPFRPdXRwdXQ+IHwgVE91dHB1dDtcblxuZXhwb3J0IHR5cGUgRGVjb3JhdGVkQWN0aXZpdHkgPSBBY3Rpdml0eUhhbmRsZXI8YW55LCBhbnk+ICYge1xuICBfX2FjdGl2aXR5TmFtZV9fOiBzdHJpbmc7XG4gIF9faXNBY3Rpdml0eV9fOiBib29sZWFuO1xufTtcblxuZXhwb3J0IHR5cGUgV29ya2Zsb3dDbGFzcyA9IG5ldyAoKSA9PiBXb3JrZmxvd0luc3RhbmNlO1xuXG5leHBvcnQgaW50ZXJmYWNlIFdvcmtmbG93SW5zdGFuY2Uge1xuICBydW4oaW5wdXQ6IHVua25vd24pOiBQcm9taXNlPHVua25vd24+O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbXBsZXRlZEFjdGl2aXR5IHtcbiAgaW5kZXg6IG51bWJlcjtcbiAgbmFtZTogc3RyaW5nO1xuICBvdXRwdXQ6IHVua25vd247XG4gIGlzX3JlbW90ZTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXb3JrZmxvd1Rhc2sge1xuICB0YXNrX3R5cGU6ICd3b3JrZmxvdyc7XG4gIHRhc2tfaWQ6IHN0cmluZztcbiAgd29ya2Zsb3dfaWQ6IHN0cmluZztcbiAgd29ya2Zsb3dfbmFtZTogc3RyaW5nO1xuICBpbnB1dDogdW5rbm93bjtcbiAgdGltZW91dF9tczogbnVtYmVyO1xuICBjcmVhdGVkX2F0OiBzdHJpbmc7XG4gIGNvbXBsZXRlZF9hY3Rpdml0aWVzPzogQ29tcGxldGVkQWN0aXZpdHlbXTtcbiAgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY3Rpdml0eVRhc2sge1xuICB0YXNrX3R5cGU/OiAnYWN0aXZpdHknO1xuICB0YXNrX2lkOiBzdHJpbmc7XG4gIHdvcmtmbG93X2lkOiBzdHJpbmc7XG4gIGFjdGl2aXR5X25hbWU6IHN0cmluZztcbiAgYWN0aXZpdHlfaW5kZXg6IG51bWJlcjtcbiAgaW5wdXQ6IHVua25vd247XG4gIGZhbl9vdXRfaW5kZXg/OiBudW1iZXI7XG4gIGZhbl9vdXRfdG90YWw/OiBudW1iZXI7XG4gIHRpbWVvdXRfbXM6IG51bWJlcjtcbiAgcmV0cnlfY291bnQ6IG51bWJlcjtcbiAgY3JlYXRlZF9hdDogc3RyaW5nO1xuICByZXF1ZXN0ZXJfd29ya2VyX2lkPzogc3RyaW5nO1xuICBjb3JyZWxhdGlvbl9pZD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXb3JrZmxvd1Jlc3VsdCB7XG4gIHRhc2tfaWQ6IHN0cmluZztcbiAgd29ya2Zsb3dfaWQ6IHN0cmluZztcbiAgd29ya2Zsb3dfbmFtZTogc3RyaW5nO1xuICBzdGF0dXM6ICdjb21wbGV0ZWQnIHwgJ2ZhaWxlZCc7XG4gIG91dHB1dD86IHVua25vd247XG4gIGVycm9yPzogV29ya2Zsb3dFcnJvcjtcbiAgc3RhcnRlZF9hdDogc3RyaW5nO1xuICBjb21wbGV0ZWRfYXQ6IHN0cmluZztcbiAgZHVyYXRpb25fbXM6IG51bWJlcjtcbiAgd29ya2VyX2lkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV29ya2Zsb3dFcnJvciB7XG4gIHR5cGU6IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBzdGFja190cmFjZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY3Rpdml0eVJlc3VsdCB7XG4gIHRhc2tfaWQ6IHN0cmluZztcbiAgd29ya2Zsb3dfaWQ6IHN0cmluZztcbiAgYWN0aXZpdHlfbmFtZTogc3RyaW5nO1xuICBhY3Rpdml0eV9pbmRleDogbnVtYmVyO1xuICBmYW5fb3V0X2luZGV4PzogbnVtYmVyO1xuICBzdGF0dXM6ICdjb21wbGV0ZWQnIHwgJ2ZhaWxlZCc7XG4gIG91dHB1dD86IHVua25vd247XG4gIGVycm9yPzogQWN0aXZpdHlFcnJvcjtcbiAgc3RhcnRlZF9hdDogc3RyaW5nO1xuICBjb21wbGV0ZWRfYXQ6IHN0cmluZztcbiAgZHVyYXRpb25fbXM6IG51bWJlcjtcbiAgd29ya2VyX2lkOiBzdHJpbmc7XG4gIHJlcXVlc3Rlcl93b3JrZXJfaWQ/OiBzdHJpbmc7XG4gIGNvcnJlbGF0aW9uX2lkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFjdGl2aXR5RXJyb3Ige1xuICB0eXBlOiBzdHJpbmc7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgc3RhY2tfdHJhY2U/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgS2Fma2FDb25maWcge1xuICBicm9rZXJzOiBzdHJpbmdbXTtcbiAgd29ya2VyX3RvcGljOiBzdHJpbmc7XG4gIHJlc3VsdF90b3BpYzogc3RyaW5nO1xuICBhdXRoPzoge1xuICAgIHR5cGU6ICdwbGFpbnRleHQnIHwgJ3Nhc2wnIHwgJ21za19pYW0nO1xuICAgIHJlZ2lvbj86IHN0cmluZztcbiAgICBhY2Nlc3Nfa2V5X2lkPzogc3RyaW5nO1xuICAgIHNlY3JldF9hY2Nlc3Nfa2V5Pzogc3RyaW5nO1xuICAgIHNlY3VyaXR5X3Byb3RvY29sPzogc3RyaW5nO1xuICAgIHNhc2xfbWVjaGFuaXNtPzogc3RyaW5nO1xuICAgIHNhc2xfdXNlcm5hbWU/OiBzdHJpbmc7XG4gICAgc2FzbF9wYXNzd29yZD86IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0UmVzcG9uc2Uge1xuICB3b3JrZXJfaWQ6IHN0cmluZztcbiAgaW5zdGFuY2VfaWQ6IHN0cmluZztcbiAgaGVhcnRiZWF0X2ludGVydmFsX21zOiBudW1iZXI7XG4gIGthZmthOiBLYWZrYUNvbmZpZztcbn1cbiJdfQ==
@@ -0,0 +1,73 @@
1
+ import type { WorkerConfig, DecoratedActivity, WorkflowClass } from './types';
2
+ import { type WorkerInterface } from './workflow';
3
+ /**
4
+ * Worker that executes workflows and activities.
5
+ *
6
+ * Usage:
7
+ * import { Worker, workflow, activity } from '@inspectica/workflow-sdk';
8
+ *
9
+ * const sayHello = activity.defn(async (input: { name: string }) => {
10
+ * return { message: `Hello, ${input.name}!` };
11
+ * });
12
+ *
13
+ * @workflow.defn
14
+ * class HelloWorldWorkflow {
15
+ * @workflow.run
16
+ * async run(input: { name: string }) {
17
+ * return await workflow.executeActivity(sayHello, input);
18
+ * }
19
+ * }
20
+ *
21
+ * const worker = new Worker({
22
+ * serverUrl: 'https://workflow.example.com',
23
+ * apiKey: 'wk_abc123...',
24
+ * });
25
+ * worker.register({ workflows: [HelloWorldWorkflow], activities: [sayHello] });
26
+ * await worker.run();
27
+ */
28
+ export declare class Worker implements WorkerInterface {
29
+ private config;
30
+ private workflows;
31
+ private activities;
32
+ private workerId;
33
+ private instanceId;
34
+ private running;
35
+ private kafka;
36
+ private consumer;
37
+ private producer;
38
+ private heartbeatInterval;
39
+ private heartbeatIntervalMs;
40
+ private resultTopic;
41
+ private maxConcurrentWorkflows;
42
+ private activeWorkflows;
43
+ constructor(config: WorkerConfig);
44
+ /**
45
+ * Register workflows and activities.
46
+ */
47
+ register(options: {
48
+ workflows?: WorkflowClass[];
49
+ activities?: DecoratedActivity[];
50
+ }): void;
51
+ /**
52
+ * Start the worker (blocking).
53
+ */
54
+ run(): Promise<void>;
55
+ /**
56
+ * Stop the worker gracefully.
57
+ */
58
+ stop(): Promise<void>;
59
+ private connectToServer;
60
+ private createKafkaClient;
61
+ private startHeartbeat;
62
+ private disconnectFromServer;
63
+ private processMessage;
64
+ private processWorkflowTask;
65
+ private executeWorkflow;
66
+ private processActivityTask;
67
+ private sendWorkflowResult;
68
+ private sendActivityResult;
69
+ reportLocalActivityCompletion(workflowId: string, activityName: string, activityIndex: number, output: unknown, durationMs: number): Promise<void>;
70
+ reportLocalActivityFailure(workflowId: string, activityName: string, activityIndex: number, error: string, errorType: string, durationMs: number): Promise<void>;
71
+ executeRemoteActivity(workflowId: string, activityName: string, activityIndex: number, inputData: unknown, timeoutMs: number): Promise<unknown>;
72
+ private cleanup;
73
+ }