@hatchet-dev/typescript-sdk 1.1.8-alpha.2 → 1.2.0-alpha.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.
@@ -46,8 +46,6 @@ export declare const ClientConfigSchema: z.ZodObject<{
46
46
  log_level: z.ZodOptional<z.ZodEnum<["OFF", "DEBUG", "INFO", "WARN", "ERROR"]>>;
47
47
  tenant_id: z.ZodString;
48
48
  namespace: z.ZodOptional<z.ZodString>;
49
- grpc_max_send_message_length: z.ZodOptional<z.ZodNumber>;
50
- grpc_max_recv_message_length: z.ZodOptional<z.ZodNumber>;
51
49
  }, "strip", z.ZodTypeAny, {
52
50
  token: string;
53
51
  tls_config: {
@@ -62,8 +60,6 @@ export declare const ClientConfigSchema: z.ZodObject<{
62
60
  tenant_id: string;
63
61
  log_level?: "OFF" | "DEBUG" | "INFO" | "WARN" | "ERROR" | undefined;
64
62
  namespace?: string | undefined;
65
- grpc_max_send_message_length?: number | undefined;
66
- grpc_max_recv_message_length?: number | undefined;
67
63
  }, {
68
64
  token: string;
69
65
  tls_config: {
@@ -78,8 +74,6 @@ export declare const ClientConfigSchema: z.ZodObject<{
78
74
  tenant_id: string;
79
75
  log_level?: "OFF" | "DEBUG" | "INFO" | "WARN" | "ERROR" | undefined;
80
76
  namespace?: string | undefined;
81
- grpc_max_send_message_length?: number | undefined;
82
- grpc_max_recv_message_length?: number | undefined;
83
77
  }>;
84
78
  export type LogConstructor = (context: string, logLevel?: LogLevel) => Logger;
85
79
  export type ClientConfig = z.infer<typeof ClientConfigSchema> & {
@@ -17,6 +17,4 @@ exports.ClientConfigSchema = zod_1.z.object({
17
17
  log_level: zod_1.z.enum(['OFF', 'DEBUG', 'INFO', 'WARN', 'ERROR']).optional(),
18
18
  tenant_id: zod_1.z.string(),
19
19
  namespace: zod_1.z.string().optional(),
20
- grpc_max_send_message_length: zod_1.z.number().optional(),
21
- grpc_max_recv_message_length: zod_1.z.number().optional(),
22
20
  });
@@ -53,15 +53,13 @@ const cron_client_1 = require("./features/cron-client");
53
53
  const schedule_client_1 = require("./features/schedule-client");
54
54
  const durable_listener_client_1 = require("../listeners/durable-listener/durable-listener-client");
55
55
  const channelFactory = (config, credentials) => (0, nice_grpc_1.createChannel)(config.host_port, credentials, {
56
- 'grpc.max_send_message_length': config.grpc_max_send_message_length,
57
- 'grpc.max_receive_message_length': config.grpc_max_recv_message_length,
58
56
  'grpc.ssl_target_name_override': config.tls_config.server_name,
59
57
  'grpc.keepalive_timeout_ms': 60 * 1000,
60
58
  'grpc.client_idle_timeout_ms': 60 * 1000,
61
- 'grpc.http2.max_pings_without_data': 0,
62
- 'grpc.http2.min_recv_ping_interval_without_data_ms': 60 * 1000,
59
+ // Send keepalive pings every 10 seconds, default is 2 hours.
60
+ 'grpc.keepalive_time_ms': 10 * 1000,
61
+ // Allow keepalive pings when there are no gRPC calls.
63
62
  'grpc.keepalive_permit_without_calls': 1,
64
- 'grpc-node.max_session_memory': Number.MAX_SAFE_INTEGER,
65
63
  });
66
64
  exports.channelFactory = channelFactory;
67
65
  const addTokenMiddleware = (token) => function _(call, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatchet-dev/typescript-sdk",
3
- "version": "1.1.8-alpha.2",
3
+ "version": "1.2.0-alpha.1",
4
4
  "description": "Background task orchestration & visibility for developers",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -88,5 +88,6 @@
88
88
  "qs": "^6.14.0",
89
89
  "yaml": "^2.7.1",
90
90
  "zod": "^3.24.2"
91
- }
91
+ },
92
+ "packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
92
93
  }
@@ -44,7 +44,7 @@ const token_1 = require("./token");
44
44
  const DEFAULT_CONFIG_FILE = '.hatchet.yaml';
45
45
  class ConfigLoader {
46
46
  static loadClientConfig(override, config) {
47
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
47
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
48
48
  const yaml = this.loadYamlConfig(config === null || config === void 0 ? void 0 : config.path);
49
49
  const tlsConfig = (_a = override === null || override === void 0 ? void 0 : override.tls_config) !== null && _a !== void 0 ? _a : {
50
50
  tls_strategy: (_d = (_c = (_b = yaml === null || yaml === void 0 ? void 0 : yaml.tls_config) === null || _b === void 0 ? void 0 : _b.tls_strategy) !== null && _c !== void 0 ? _c : this.env('HATCHET_CLIENT_TLS_STRATEGY')) !== null && _d !== void 0 ? _d : 'tls',
@@ -76,18 +76,14 @@ class ConfigLoader {
76
76
  apiUrl = (_z = (_y = override === null || override === void 0 ? void 0 : override.api_url) !== null && _y !== void 0 ? _y : yaml === null || yaml === void 0 ? void 0 : yaml.api_url) !== null && _z !== void 0 ? _z : this.env('HATCHET_CLIENT_API_URL');
77
77
  }
78
78
  const namespace = (_1 = (_0 = override === null || override === void 0 ? void 0 : override.namespace) !== null && _0 !== void 0 ? _0 : yaml === null || yaml === void 0 ? void 0 : yaml.namespace) !== null && _1 !== void 0 ? _1 : this.env('HATCHET_CLIENT_NAMESPACE');
79
- const grpcMaxSendMessageLength = (_3 = (_2 = override === null || override === void 0 ? void 0 : override.grpc_max_send_message_length) !== null && _2 !== void 0 ? _2 : yaml === null || yaml === void 0 ? void 0 : yaml.grpc_max_send_message_length) !== null && _3 !== void 0 ? _3 : parseInt((_4 = this.env('HATCHET_CLIENT_GRPC_MAX_SEND_MESSAGE_LENGTH')) !== null && _4 !== void 0 ? _4 : '-1', 10);
80
- const grpcMaxRecvMessageLength = (_6 = (_5 = override === null || override === void 0 ? void 0 : override.grpc_max_recv_message_length) !== null && _5 !== void 0 ? _5 : yaml === null || yaml === void 0 ? void 0 : yaml.grpc_max_recv_message_length) !== null && _6 !== void 0 ? _6 : parseInt((_7 = this.env('HATCHET_CLIENT_GRPC_MAX_RECV_MESSAGE_LENGTH')) !== null && _7 !== void 0 ? _7 : '-1', 10);
81
79
  return {
82
- token: (_9 = (_8 = override === null || override === void 0 ? void 0 : override.token) !== null && _8 !== void 0 ? _8 : yaml === null || yaml === void 0 ? void 0 : yaml.token) !== null && _9 !== void 0 ? _9 : this.env('HATCHET_CLIENT_TOKEN'),
80
+ token: (_3 = (_2 = override === null || override === void 0 ? void 0 : override.token) !== null && _2 !== void 0 ? _2 : yaml === null || yaml === void 0 ? void 0 : yaml.token) !== null && _3 !== void 0 ? _3 : this.env('HATCHET_CLIENT_TOKEN'),
83
81
  host_port: grpcBroadcastAddress,
84
82
  api_url: apiUrl,
85
83
  tls_config: tlsConfig,
86
- log_level: (_12 = (_11 = (_10 = override === null || override === void 0 ? void 0 : override.log_level) !== null && _10 !== void 0 ? _10 : yaml === null || yaml === void 0 ? void 0 : yaml.log_level) !== null && _11 !== void 0 ? _11 : this.env('HATCHET_CLIENT_LOG_LEVEL')) !== null && _12 !== void 0 ? _12 : 'INFO',
84
+ log_level: (_6 = (_5 = (_4 = override === null || override === void 0 ? void 0 : override.log_level) !== null && _4 !== void 0 ? _4 : yaml === null || yaml === void 0 ? void 0 : yaml.log_level) !== null && _5 !== void 0 ? _5 : this.env('HATCHET_CLIENT_LOG_LEVEL')) !== null && _6 !== void 0 ? _6 : 'INFO',
87
85
  tenant_id: tenantId,
88
86
  namespace: namespace ? `${namespace}_`.toLowerCase() : '',
89
- grpc_max_send_message_length: grpcMaxSendMessageLength > 0 ? grpcMaxSendMessageLength : undefined,
90
- grpc_max_recv_message_length: grpcMaxRecvMessageLength > 0 ? grpcMaxRecvMessageLength : undefined,
91
87
  };
92
88
  }
93
89
  static get default_yaml_config_path() {
@@ -13,6 +13,11 @@ import { WorkflowsClient } from './features/workflows';
13
13
  import { RunsClient } from './features/runs';
14
14
  import { InputType, OutputType, UnknownInputType, StrictWorkflowOutputType } from '../types';
15
15
  import { RatelimitsClient } from './features';
16
+ import { Middleware } from '../next/middleware/middleware';
17
+ export interface RuntimeOpts {
18
+ middleware?: Middleware[];
19
+ }
20
+ type Config = Partial<ClientConfig> & RuntimeOpts;
16
21
  /**
17
22
  * HatchetV1 implements the main client interface for interacting with the Hatchet workflow engine.
18
23
  * It provides methods for creating and executing workflows, as well as managing workers.
@@ -21,6 +26,8 @@ export declare class HatchetClient implements IHatchetClient {
21
26
  /** The underlying v0 client instance */
22
27
  _v0: InternalHatchetClient;
23
28
  _api: Api;
29
+ private _middleware?;
30
+ get middleware(): Middleware[] | undefined;
24
31
  /**
25
32
  * @deprecated v0 client will be removed in a future release, please upgrade to v1
26
33
  */
@@ -35,7 +42,7 @@ export declare class HatchetClient implements IHatchetClient {
35
42
  * @param options - Optional client options
36
43
  * @param axiosConfig - Optional Axios configuration for HTTP requests
37
44
  */
38
- constructor(config?: Partial<ClientConfig>, options?: HatchetClientOptions, axiosConfig?: AxiosRequestConfig);
45
+ constructor(config?: Config, options?: HatchetClientOptions, axiosConfig?: AxiosRequestConfig);
39
46
  /**
40
47
  * Static factory method to create a new Hatchet client instance.
41
48
  * @param config - Optional configuration for the client
@@ -43,7 +50,7 @@ export declare class HatchetClient implements IHatchetClient {
43
50
  * @param axiosConfig - Optional Axios configuration for HTTP requests
44
51
  * @returns A new Hatchet client instance
45
52
  */
46
- static init(config?: Partial<ClientConfig>, options?: HatchetClientOptions, axiosConfig?: AxiosRequestConfig): HatchetClient;
53
+ static init(config?: Config, options?: HatchetClientOptions, axiosConfig?: AxiosRequestConfig): HatchetClient;
47
54
  /**
48
55
  * Creates a new workflow definition.
49
56
  * @template I - The input type for the workflow
@@ -98,7 +105,7 @@ export declare class HatchetClient implements IHatchetClient {
98
105
  * @param options - Configuration options for the workflow run
99
106
  * @returns A WorkflowRunRef containing the run ID and methods to interact with the run
100
107
  */
101
- runNoWait<I extends InputType = UnknownInputType, O extends OutputType = void>(workflow: BaseWorkflowDeclaration<I, O> | string | V0Workflow, input: I, options: RunOpts): WorkflowRunRef<O>;
108
+ runNoWait<I extends InputType = UnknownInputType, O extends OutputType = void>(workflow: BaseWorkflowDeclaration<I, O> | string | V0Workflow, input: I, options?: RunOpts): Promise<WorkflowRunRef<O>>;
102
109
  /**
103
110
  * @alias run
104
111
  * Triggers a workflow run and waits for the result.
@@ -212,3 +219,4 @@ export declare class HatchetClient implements IHatchetClient {
212
219
  webhooks(workflows: V0Workflow[]): import("../../clients/worker/handler").WebhookHandler;
213
220
  runRef<T extends Record<string, any> = any>(id: string): WorkflowRunRef<T>;
214
221
  }
222
+ export {};
@@ -3,10 +3,12 @@ import { MetricsClient } from './features/metrics';
3
3
  import { RunsClient } from './features/runs';
4
4
  import { WorkersClient } from './features/workers';
5
5
  import { WorkflowsClient } from './features/workflows';
6
+ import { Middleware } from '../next/middleware/middleware';
6
7
  export interface IHatchetClient {
7
8
  _v0: InternalHatchetClient;
8
9
  metrics: MetricsClient;
9
10
  runs: RunsClient;
10
11
  workflows: WorkflowsClient;
11
12
  workers: WorkersClient;
13
+ middleware?: Middleware[];
12
14
  }
@@ -28,11 +28,15 @@ const workers_1 = require("./features/workers");
28
28
  const workflows_1 = require("./features/workflows");
29
29
  const runs_1 = require("./features/runs");
30
30
  const features_1 = require("./features");
31
+ const middleware_1 = require("../next/middleware/middleware");
31
32
  /**
32
33
  * HatchetV1 implements the main client interface for interacting with the Hatchet workflow engine.
33
34
  * It provides methods for creating and executing workflows, as well as managing workers.
34
35
  */
35
36
  class HatchetClient {
37
+ get middleware() {
38
+ return this._middleware;
39
+ }
36
40
  /**
37
41
  * @deprecated v0 client will be removed in a future release, please upgrade to v1
38
42
  */
@@ -63,6 +67,9 @@ class HatchetClient {
63
67
  this.tenantId = clientConfig.tenant_id;
64
68
  this._api = (0, rest_1.default)(clientConfig.api_url, clientConfig.token, axiosConfig);
65
69
  this._v0 = new hatchet_client_1.InternalHatchetClient(clientConfig, options, axiosConfig, this.runs);
70
+ if (config === null || config === void 0 ? void 0 : config.middleware) {
71
+ this._middleware = config.middleware;
72
+ }
66
73
  }
67
74
  catch (e) {
68
75
  if (e instanceof zod_1.z.ZodError) {
@@ -113,18 +120,29 @@ class HatchetClient {
113
120
  * @param options - Configuration options for the workflow run
114
121
  * @returns A WorkflowRunRef containing the run ID and methods to interact with the run
115
122
  */
116
- runNoWait(workflow, input, options) {
117
- let name;
118
- if (typeof workflow === 'string') {
119
- name = workflow;
120
- }
121
- else if ('id' in workflow) {
122
- name = workflow.id;
123
- }
124
- else {
125
- throw new Error('unable to identify workflow');
126
- }
127
- return this._v0.admin.runWorkflow(name, input, options);
123
+ runNoWait(workflow_1, input_1) {
124
+ return __awaiter(this, arguments, void 0, function* (workflow, input, options = {}) {
125
+ let name;
126
+ if (typeof workflow === 'string') {
127
+ name = workflow;
128
+ }
129
+ else if ('id' in workflow) {
130
+ name = workflow.id;
131
+ }
132
+ else {
133
+ throw new Error('unable to identify workflow');
134
+ }
135
+ const serializedInput = yield (0, middleware_1.serializeInput)(input, this.middleware);
136
+ const runRef = this._v0.admin.runWorkflow(name, serializedInput, options);
137
+ // Wrap the runRef to apply output deserialization
138
+ const originalResult = runRef.result;
139
+ runRef.result = () => __awaiter(this, void 0, void 0, function* () {
140
+ const output = yield originalResult.call(runRef);
141
+ const deserializedOutput = yield (0, middleware_1.deserializeOutput)(output, this.middleware);
142
+ return deserializedOutput;
143
+ });
144
+ return runRef;
145
+ });
128
146
  }
129
147
  /**
130
148
  * @alias run
@@ -152,8 +170,11 @@ class HatchetClient {
152
170
  */
153
171
  run(workflow_1, input_1) {
154
172
  return __awaiter(this, arguments, void 0, function* (workflow, input, options = {}) {
155
- const run = this.runNoWait(workflow, input, options);
156
- return run.output;
173
+ const serializedInput = yield (0, middleware_1.serializeInput)(input, this.middleware);
174
+ const runRef = yield this.runNoWait(workflow, serializedInput, options);
175
+ const output = yield runRef.result();
176
+ const deserializedOutput = yield (0, middleware_1.deserializeOutput)(output, this.middleware);
177
+ return deserializedOutput;
157
178
  });
158
179
  }
159
180
  /**
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Worker = void 0;
13
13
  const declaration_1 = require("../declaration");
14
+ const middleware_1 = require("../next/middleware/middleware");
14
15
  const DEFAULT_DURABLE_SLOTS = 1000;
15
16
  /**
16
17
  * HatchetWorker class for workflow execution runtime
@@ -50,13 +51,14 @@ class Worker {
50
51
  return __awaiter(this, void 0, void 0, function* () {
51
52
  return Promise.all((workflows === null || workflows === void 0 ? void 0 : workflows.map((wf) => __awaiter(this, void 0, void 0, function* () {
52
53
  if (wf instanceof declaration_1.BaseWorkflowDeclaration) {
54
+ const withMiddleware = yield (0, middleware_1.bindMiddleware)(wf, this._v1);
53
55
  // TODO check if tenant is V1
54
- const register = this.nonDurable.registerWorkflowV1(wf);
56
+ const register = this.nonDurable.registerWorkflowV1(withMiddleware);
55
57
  if (wf.definition._durableTasks.length > 0) {
56
58
  if (!this.durable) {
57
59
  this.durable = yield this._v0.worker(`${this.name}-durable`, Object.assign(Object.assign({}, this.config), { maxRuns: this.config.durableSlots || DEFAULT_DURABLE_SLOTS }));
58
60
  }
59
- this.durable.registerDurableActionsV1(wf.definition);
61
+ this.durable.registerDurableActionsV1(withMiddleware.definition);
60
62
  }
61
63
  return register;
62
64
  }
@@ -172,7 +172,7 @@ export declare class BaseWorkflowDeclaration<I extends InputType = UnknownInputT
172
172
  * @returns A WorkflowRunRef containing the run ID and methods to get results and interact with the run.
173
173
  * @throws Error if the workflow is not bound to a Hatchet client.
174
174
  */
175
- runNoWait(input: I, options?: RunOpts, _standaloneTaskName?: string): WorkflowRunRef<O>;
175
+ runNoWait(input: I, options?: RunOpts, _standaloneTaskName?: string): Promise<WorkflowRunRef<O>>;
176
176
  /**
177
177
  * @alias run
178
178
  * Triggers a workflow run and waits for the result.
@@ -301,16 +301,9 @@ export declare class WorkflowDeclaration<I extends InputType = UnknownInputType,
301
301
  export declare class TaskWorkflowDeclaration<I extends InputType = UnknownInputType, O extends OutputType = void> extends BaseWorkflowDeclaration<I, O> {
302
302
  _standalone_task_name: string;
303
303
  constructor(options: CreateTaskWorkflowOpts<I, O>, client?: IHatchetClient);
304
+ runNoWait(input: I, options?: RunOpts): Promise<WorkflowRunRef<O>>;
304
305
  run(input: I, options?: RunOpts): Promise<O>;
305
306
  run(input: I[], options?: RunOpts): Promise<O[]>;
306
- /**
307
- * Triggers a workflow run without waiting for completion.
308
- * @param input The input data for the workflow.
309
- * @param options Optional configuration for this workflow run.
310
- * @returns A WorkflowRunRef containing the run ID and methods to get results and interact with the run.
311
- * @throws Error if the workflow is not bound to a Hatchet client.
312
- */
313
- runNoWait(input: I, options?: RunOpts): WorkflowRunRef<O>;
314
307
  get taskDef(): CreateWorkflowTaskOpts<any, any>;
315
308
  }
316
309
  /**
package/v1/declaration.js CHANGED
@@ -13,6 +13,7 @@ exports.TaskWorkflowDeclaration = exports.WorkflowDeclaration = exports.BaseWork
13
13
  exports.CreateTaskWorkflow = CreateTaskWorkflow;
14
14
  exports.CreateWorkflow = CreateWorkflow;
15
15
  exports.CreateDurableTaskWorkflow = CreateDurableTaskWorkflow;
16
+ const middleware_1 = require("./next/middleware/middleware");
16
17
  const UNBOUND_ERR = new Error('workflow unbound to hatchet client, hint: use client.run instead');
17
18
  /**
18
19
  * Represents a workflow that can be executed by Hatchet.
@@ -37,14 +38,25 @@ class BaseWorkflowDeclaration {
37
38
  * @throws Error if the workflow is not bound to a Hatchet client.
38
39
  */
39
40
  runNoWait(input, options, _standaloneTaskName) {
40
- if (!this.client) {
41
- throw UNBOUND_ERR;
42
- }
43
- const res = this.client._v0.admin.runWorkflow(this.name, input, options);
44
- if (_standaloneTaskName) {
45
- res._standalone_task_name = _standaloneTaskName;
46
- }
47
- return res;
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ if (!this.client) {
43
+ throw UNBOUND_ERR;
44
+ }
45
+ const serializedInput = yield (0, middleware_1.serializeInput)(input, this.client.middleware);
46
+ const res = this.client._v0.admin.runWorkflow(this.name, serializedInput, options);
47
+ if (_standaloneTaskName) {
48
+ res._standalone_task_name = _standaloneTaskName;
49
+ }
50
+ // Wrap the result method to apply output deserialization
51
+ const originalResult = res.result;
52
+ res.result = () => __awaiter(this, void 0, void 0, function* () {
53
+ var _a;
54
+ const output = yield originalResult.call(res);
55
+ const deserializedOutput = yield (0, middleware_1.deserializeOutput)(output, (_a = this.client) === null || _a === void 0 ? void 0 : _a.middleware);
56
+ return deserializedOutput;
57
+ });
58
+ return res;
59
+ });
48
60
  }
49
61
  runAndWait(input, options, _standaloneTaskName) {
50
62
  return __awaiter(this, void 0, void 0, function* () {
@@ -63,32 +75,16 @@ class BaseWorkflowDeclaration {
63
75
  throw UNBOUND_ERR;
64
76
  }
65
77
  if (Array.isArray(input)) {
66
- let resp = [];
67
- for (let i = 0; i < input.length; i += 500) {
68
- const batch = input.slice(i, i + 500);
69
- const batchResp = yield this.client._v0.admin.runWorkflows(batch.map((inp) => ({
70
- workflowName: this.definition.name,
71
- input: inp,
72
- options,
73
- })));
74
- resp = resp.concat(batchResp);
75
- }
76
- const res = [];
77
- resp.forEach((ref, index) => {
78
- const wf = input[index].workflow;
79
- if (wf instanceof TaskWorkflowDeclaration) {
80
- // eslint-disable-next-line no-param-reassign
81
- ref._standalone_task_name = wf._standalone_task_name;
82
- }
83
- res.push(ref.result());
84
- });
85
- return Promise.all(res);
78
+ return Promise.all(input.map((i) => this.run(i, options, _standaloneTaskName)));
86
79
  }
87
- const res = this.client._v0.admin.runWorkflow(this.definition.name, input, options);
80
+ const serializedInput = yield (0, middleware_1.serializeInput)(input, this.client.middleware);
81
+ const res = this.client._v0.admin.runWorkflow(this.name, serializedInput, options);
88
82
  if (_standaloneTaskName) {
89
83
  res._standalone_task_name = _standaloneTaskName;
90
84
  }
91
- return res.result();
85
+ const output = yield res.result();
86
+ const deserializedOutput = yield (0, middleware_1.deserializeOutput)(output, this.client.middleware);
87
+ return deserializedOutput;
92
88
  });
93
89
  }
94
90
  /**
@@ -308,26 +304,37 @@ class TaskWorkflowDeclaration extends BaseWorkflowDeclaration {
308
304
  this._standalone_task_name = options.name;
309
305
  this.definition._tasks.push(Object.assign({}, options));
310
306
  }
311
- run(input, options) {
307
+ runNoWait(input, options) {
312
308
  const _super = Object.create(null, {
313
- run: { get: () => super.run }
309
+ runNoWait: { get: () => super.runNoWait }
314
310
  });
315
311
  return __awaiter(this, void 0, void 0, function* () {
316
- return (yield _super.run.call(this, input, options, this._standalone_task_name));
312
+ if (!this.client) {
313
+ throw UNBOUND_ERR;
314
+ }
315
+ const res = yield _super.runNoWait.call(this, input, options, this._standalone_task_name);
316
+ // Wrap the result method to apply output deserialization
317
+ const originalResult = res.result;
318
+ res.result = () => __awaiter(this, void 0, void 0, function* () {
319
+ var _a;
320
+ const output = yield originalResult.call(res);
321
+ const deserializedOutput = yield (0, middleware_1.deserializeOutput)(output, (_a = this.client) === null || _a === void 0 ? void 0 : _a.middleware);
322
+ return deserializedOutput;
323
+ });
324
+ return res;
317
325
  });
318
326
  }
319
- /**
320
- * Triggers a workflow run without waiting for completion.
321
- * @param input The input data for the workflow.
322
- * @param options Optional configuration for this workflow run.
323
- * @returns A WorkflowRunRef containing the run ID and methods to get results and interact with the run.
324
- * @throws Error if the workflow is not bound to a Hatchet client.
325
- */
326
- runNoWait(input, options) {
327
- if (!this.client) {
328
- throw UNBOUND_ERR;
329
- }
330
- return super.runNoWait(input, options, this._standalone_task_name);
327
+ run(input, options) {
328
+ return __awaiter(this, void 0, void 0, function* () {
329
+ if (!this.client) {
330
+ throw UNBOUND_ERR;
331
+ }
332
+ if (Array.isArray(input)) {
333
+ return Promise.all(input.map((i) => this.run(i, options)));
334
+ }
335
+ const runRef = yield this.runNoWait(input, options);
336
+ return runRef.result();
337
+ });
331
338
  }
332
339
  get taskDef() {
333
340
  return this.definition._tasks[0];
@@ -20,8 +20,8 @@ const hatchet_client_1 = require("../hatchet-client");
20
20
  // ...
21
21
  function main() {
22
22
  return __awaiter(this, void 0, void 0, function* () {
23
- const run = workflow_1.cancellation.runNoWait({});
24
- const run1 = workflow_1.cancellation.runNoWait({});
23
+ const run = yield workflow_1.cancellation.runNoWait({});
24
+ const run1 = yield workflow_1.cancellation.runNoWait({});
25
25
  yield (0, sleep_1.default)(1000);
26
26
  yield run.cancel();
27
27
  const res = yield run.output;
@@ -32,8 +32,8 @@ function main() {
32
32
  yield run.replay();
33
33
  const resReplay = yield run.output;
34
34
  console.log(resReplay);
35
- const run2 = workflow_1.cancellation.runNoWait({}, { additionalMetadata: { test: 'abc' } });
36
- const run4 = workflow_1.cancellation.runNoWait({}, { additionalMetadata: { test: 'test' } });
35
+ const run2 = yield workflow_1.cancellation.runNoWait({}, { additionalMetadata: { test: 'abc' } });
36
+ const run4 = yield workflow_1.cancellation.runNoWait({}, { additionalMetadata: { test: 'test' } });
37
37
  yield (0, sleep_1.default)(1000);
38
38
  yield hatchet_client_1.hatchet.runs.cancel({
39
39
  filters: {
@@ -0,0 +1,2 @@
1
+ import { HatchetClient } from '../../client/client';
2
+ export declare const hatchet: HatchetClient;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hatchet = void 0;
4
+ const client_1 = require("../../client/client");
5
+ class EncodeSerializer {
6
+ deserialize(input) {
7
+ console.log('client-encode-deserialize', input);
8
+ if (input.encoded && typeof input.encoded === 'string') {
9
+ console.warn('WARNING THIS IS NOT REAL ENCRYPTION');
10
+ const decoded = Buffer.from(input.encoded, 'base64').toString('utf-8');
11
+ return JSON.parse(decoded);
12
+ }
13
+ return input;
14
+ }
15
+ serialize(input) {
16
+ console.warn('WARNING THIS IS NOT REAL ENCRYPTION');
17
+ const encoded = Buffer.from(JSON.stringify(input)).toString('base64');
18
+ console.log('client-encode-serialize', input);
19
+ return {
20
+ encoded,
21
+ };
22
+ }
23
+ }
24
+ class EncodeMiddleware {
25
+ constructor() {
26
+ this.input = new EncodeSerializer();
27
+ this.output = new EncodeSerializer();
28
+ }
29
+ }
30
+ exports.hatchet = client_1.HatchetClient.init({
31
+ middleware: [new EncodeMiddleware()],
32
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ /* eslint-disable no-console */
13
+ const workflow_1 = require("./workflow");
14
+ function main() {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ // ❓ Running a Task
17
+ const res = yield workflow_1.withMiddleware.run({
18
+ Message: 'HeLlO WoRlD',
19
+ });
20
+ // 👀 Access the results of the Task
21
+ console.log(res);
22
+ // !!
23
+ });
24
+ }
25
+ if (require.main === module) {
26
+ main()
27
+ .then(() => {
28
+ process.exit(0);
29
+ })
30
+ .catch((err) => {
31
+ console.error(err);
32
+ process.exit(1);
33
+ });
34
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ // ❓ Declaring a Worker
13
+ const hatchet_client_1 = require("./hatchet-client");
14
+ const workflow_1 = require("./workflow");
15
+ function main() {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const worker = yield hatchet_client_1.hatchet.worker('withMiddleware-worker', {
18
+ // 👀 Declare the workflows that the worker can execute
19
+ workflows: [workflow_1.withMiddleware],
20
+ // 👀 Declare the number of concurrent task runs the worker can accept
21
+ slots: 100,
22
+ });
23
+ yield worker.start();
24
+ });
25
+ }
26
+ if (require.main === module) {
27
+ main();
28
+ }
29
+ // !!
@@ -0,0 +1,9 @@
1
+ export type SimpleInput = {
2
+ Message: string;
3
+ };
4
+ export type SimpleOutput = {
5
+ TransformedMessage: string;
6
+ };
7
+ export declare const withMiddleware: import("../..").TaskWorkflowDeclaration<SimpleInput, {
8
+ TransformedMessage: string;
9
+ }>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withMiddleware = void 0;
4
+ const hatchet_client_1 = require("./hatchet-client");
5
+ exports.withMiddleware = hatchet_client_1.hatchet.task({
6
+ name: 'with-middleware',
7
+ middleware: [
8
+ {
9
+ input: {
10
+ deserialize: (input) => {
11
+ console.log('task-input-deserialize', input);
12
+ return input;
13
+ },
14
+ serialize: (input) => {
15
+ console.log('task-input-serialize', input);
16
+ return input;
17
+ },
18
+ },
19
+ output: {
20
+ deserialize: (input) => {
21
+ console.log('task-output-deserialize', input);
22
+ return input;
23
+ },
24
+ serialize: (input) => {
25
+ console.log('task-output-serialize', input);
26
+ return input;
27
+ },
28
+ },
29
+ },
30
+ ],
31
+ fn: (input) => {
32
+ return {
33
+ TransformedMessage: input.Message.toLowerCase(),
34
+ };
35
+ },
36
+ });
37
+ // !!
@@ -0,0 +1 @@
1
+ export * from './middleware/middleware';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./middleware/middleware"), exports);
@@ -0,0 +1,27 @@
1
+ import { JsonObject } from '../../types';
2
+ import { BaseWorkflowDeclaration } from '../../declaration';
3
+ import { HatchetClient } from '../../client/client';
4
+ type SingleMiddleware<T> = (input: JsonObject) => T | Promise<T>;
5
+ type SingleSerialize<T> = (input: T) => JsonObject | Promise<JsonObject>;
6
+ export interface Serializable<T = any> {
7
+ deserialize: SingleMiddleware<T>;
8
+ serialize: SingleSerialize<T>;
9
+ }
10
+ export interface Middleware {
11
+ input: Serializable;
12
+ output: Serializable;
13
+ }
14
+ export interface MiddlewareChain {
15
+ middlewares: Middleware[];
16
+ }
17
+ export type MiddlewareFn<T = any> = (input: any) => T | Promise<T>;
18
+ /**
19
+ * Binds middleware to a workflow's tasks
20
+ * @param wf - The workflow declaration to bind middleware to
21
+ * @param client - The HatchetClient instance
22
+ * @returns The workflow with middleware bound to its tasks
23
+ */
24
+ export declare function bindMiddleware(wf: BaseWorkflowDeclaration<any, any>, client: HatchetClient): Promise<BaseWorkflowDeclaration<any, any>>;
25
+ export declare function serializeInput(input: JsonObject, middleware?: Middleware[]): Promise<JsonObject>;
26
+ export declare function deserializeOutput(output: JsonObject, middleware?: Middleware[]): Promise<JsonObject>;
27
+ export {};
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.bindMiddleware = bindMiddleware;
13
+ exports.serializeInput = serializeInput;
14
+ exports.deserializeOutput = deserializeOutput;
15
+ // Helper to compose middleware functions
16
+ const composeMiddleware = (fns) => {
17
+ return (input) => __awaiter(void 0, void 0, void 0, function* () {
18
+ let result = input;
19
+ for (const fn of fns) {
20
+ result = yield fn(result);
21
+ }
22
+ return result;
23
+ });
24
+ };
25
+ // Get all deserialize functions in the correct order
26
+ const getDeserializeChain = (middleware) => {
27
+ return middleware.map((m) => m.input.deserialize);
28
+ };
29
+ // Get all serialize functions in the correct order
30
+ const getSerializeChain = (middleware) => {
31
+ return middleware.map((m) => m.input.serialize);
32
+ };
33
+ /**
34
+ * Binds middleware to a workflow's tasks
35
+ * @param wf - The workflow declaration to bind middleware to
36
+ * @param client - The HatchetClient instance
37
+ * @returns The workflow with middleware bound to its tasks
38
+ */
39
+ function bindMiddleware(wf, client) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ const tasks = wf.definition._tasks.map((task) => {
42
+ if (!task.middleware) {
43
+ // eslint-disable-next-line no-param-reassign
44
+ task.middleware = [
45
+ {
46
+ input: {
47
+ deserialize: (input) => input,
48
+ serialize: (input) => input,
49
+ },
50
+ output: {
51
+ deserialize: (input) => input,
52
+ serialize: (input) => input,
53
+ },
54
+ },
55
+ ];
56
+ }
57
+ const originalFn = task.fn;
58
+ // Build input middleware chain
59
+ let inputDeserializeChain = [];
60
+ let inputSerializeChain = [];
61
+ if (task.middleware) {
62
+ inputDeserializeChain = getDeserializeChain(task.middleware);
63
+ inputSerializeChain = getSerializeChain(task.middleware);
64
+ }
65
+ // Build output middleware chain
66
+ let outputDeserializeChain = [];
67
+ let outputSerializeChain = [];
68
+ if (task.middleware) {
69
+ outputDeserializeChain = getDeserializeChain(task.middleware);
70
+ outputSerializeChain = getSerializeChain(task.middleware);
71
+ }
72
+ // Add client middleware if present
73
+ if (client.middleware) {
74
+ inputDeserializeChain = [...getDeserializeChain(client.middleware), ...inputDeserializeChain];
75
+ inputSerializeChain = [...inputSerializeChain, ...getSerializeChain(client.middleware)];
76
+ outputDeserializeChain = [
77
+ ...getDeserializeChain(client.middleware),
78
+ ...outputDeserializeChain,
79
+ ];
80
+ outputSerializeChain = [...outputSerializeChain, ...getSerializeChain(client.middleware)];
81
+ }
82
+ // Compose the middleware with the original function
83
+ // eslint-disable-next-line no-param-reassign
84
+ task.fn = (input, ctx) => __awaiter(this, void 0, void 0, function* () {
85
+ console.log('fn input', input);
86
+ // Apply input deserialize chain
87
+ const deserializedInput = yield composeMiddleware(inputDeserializeChain)(input);
88
+ // Run the original function
89
+ const result = yield originalFn(deserializedInput, ctx);
90
+ // Apply output serialize chain
91
+ return composeMiddleware(outputSerializeChain)(result);
92
+ });
93
+ return task;
94
+ });
95
+ // eslint-disable-next-line no-param-reassign
96
+ wf.definition._tasks = tasks;
97
+ return wf;
98
+ });
99
+ }
100
+ function serializeInput(input, middleware) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ let serialized = input;
103
+ if (middleware) {
104
+ for (const m of middleware) {
105
+ serialized = yield m.input.serialize(serialized);
106
+ }
107
+ }
108
+ return serialized;
109
+ });
110
+ }
111
+ function deserializeOutput(output, middleware) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ let deserialized = output;
114
+ if (middleware) {
115
+ for (const m of middleware) {
116
+ deserialized = yield m.output.deserialize(deserialized);
117
+ }
118
+ }
119
+ return deserialized;
120
+ });
121
+ }
package/v1/task.d.ts CHANGED
@@ -3,6 +3,7 @@ import { Context, CreateStep, DurableContext } from '../step';
3
3
  import { Conditions } from './conditions';
4
4
  import { Duration } from './client/duration';
5
5
  import { InputType, OutputType, UnknownInputType } from './types';
6
+ import { Middleware } from './next/middleware/middleware';
6
7
  /**
7
8
  * Options for configuring the concurrency for a task.
8
9
  */
@@ -98,6 +99,10 @@ export type CreateBaseTaskOpts<I extends InputType = UnknownInputType, O extends
98
99
  * (optional) the concurrency options for the task
99
100
  */
100
101
  concurrency?: TaskConcurrency | TaskConcurrency[];
102
+ /**
103
+ * (optional) the middleware for the task
104
+ */
105
+ middleware?: Middleware[];
101
106
  };
102
107
  export type CreateWorkflowTaskOpts<I extends InputType = UnknownInputType, O extends OutputType = void, C extends TaskFn<I, O> | DurableTaskFn<I, O> = TaskFn<I, O>> = CreateBaseTaskOpts<I, O, C> & {
103
108
  /**
package/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const HATCHET_VERSION = "1.1.8-alpha.2";
1
+ export declare const HATCHET_VERSION = "1.2.0-alpha.1";
package/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HATCHET_VERSION = void 0;
4
- exports.HATCHET_VERSION = '1.1.8-alpha.2';
4
+ exports.HATCHET_VERSION = '1.2.0-alpha.1';