@hatchet-dev/typescript-sdk 0.0.3 → 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.
@@ -5,9 +5,7 @@ export declare class AdminClient {
5
5
  config: ClientConfig;
6
6
  client: WorkflowServiceClient;
7
7
  constructor(config: ClientConfig, channel: Channel, factory: ClientFactory);
8
- put_workflow(workflow: CreateWorkflowVersionOpts, options?: {
9
- autoVersion?: boolean;
10
- }): Promise<void>;
8
+ put_workflow(workflow: CreateWorkflowVersionOpts): Promise<void>;
11
9
  schedule_workflow(workflowId: string, options?: {
12
10
  schedules?: Date[];
13
11
  }): void;
@@ -20,11 +20,8 @@ class AdminClient {
20
20
  this.config = config;
21
21
  this.client = factory.create(workflows_1.WorkflowServiceDefinition, channel);
22
22
  }
23
- put_workflow(workflow, options) {
23
+ put_workflow(workflow) {
24
24
  return __awaiter(this, void 0, void 0, function* () {
25
- if (workflow.version === '' && !(options === null || options === void 0 ? void 0 : options.autoVersion)) {
26
- throw new hatchet_error_1.default('PutWorkflow error: workflow version is required, or use autoVersion');
27
- }
28
25
  try {
29
26
  yield this.client.putWorkflow({
30
27
  opts: workflow,
@@ -11,6 +11,8 @@ export interface Action {
11
11
  actionId: string;
12
12
  actionType: number;
13
13
  actionPayload: string;
14
+ workflowRunId: string;
15
+ getGroupKeyRunId: string;
14
16
  }
15
17
  export declare class ActionListener {
16
18
  config: ClientConfig;
@@ -1,6 +1,7 @@
1
1
  import { Channel, ClientFactory } from 'nice-grpc';
2
- import { DispatcherClient as PbDispatcherClient, ActionEvent } from '../../protoc/dispatcher';
2
+ import { DispatcherClient as PbDispatcherClient, StepActionEvent, GroupKeyActionEvent } from '../../protoc/dispatcher';
3
3
  import { ClientConfig } from '../hatchet-client/client-config';
4
+ import { Logger } from '../../util/logger';
4
5
  import { ActionListener } from './action-listener';
5
6
  interface GetActionListenerOptions {
6
7
  workerName: string;
@@ -10,8 +11,10 @@ interface GetActionListenerOptions {
10
11
  export declare class DispatcherClient {
11
12
  config: ClientConfig;
12
13
  client: PbDispatcherClient;
14
+ logger: Logger;
13
15
  constructor(config: ClientConfig, channel: Channel, factory: ClientFactory);
14
- get_action_listener(options: GetActionListenerOptions): Promise<ActionListener>;
15
- send_action_event(in_: ActionEvent): Promise<import("../../protoc/dispatcher").ActionEventResponse>;
16
+ getActionListener(options: GetActionListenerOptions): Promise<ActionListener>;
17
+ sendStepActionEvent(in_: StepActionEvent): Promise<import("../../protoc/dispatcher").ActionEventResponse>;
18
+ sendGroupKeyActionEvent(in_: GroupKeyActionEvent): Promise<import("../../protoc/dispatcher").ActionEventResponse>;
16
19
  }
17
20
  export {};
@@ -15,13 +15,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.DispatcherClient = void 0;
16
16
  const dispatcher_1 = require("../../protoc/dispatcher");
17
17
  const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
18
+ const logger_1 = require("../../util/logger");
18
19
  const action_listener_1 = require("./action-listener");
19
20
  class DispatcherClient {
20
21
  constructor(config, channel, factory) {
21
22
  this.config = config;
22
23
  this.client = factory.create(dispatcher_1.DispatcherDefinition, channel);
24
+ this.logger = new logger_1.Logger(`Dispatcher`, config.log_level);
23
25
  }
24
- get_action_listener(options) {
26
+ getActionListener(options) {
25
27
  return __awaiter(this, void 0, void 0, function* () {
26
28
  // Register the worker
27
29
  const registration = yield this.client.register(Object.assign({}, options));
@@ -32,10 +34,20 @@ class DispatcherClient {
32
34
  return new action_listener_1.ActionListener(this, listener, registration.workerId);
33
35
  });
34
36
  }
35
- send_action_event(in_) {
37
+ sendStepActionEvent(in_) {
36
38
  return __awaiter(this, void 0, void 0, function* () {
37
39
  try {
38
- return this.client.sendActionEvent(in_);
40
+ return this.client.sendStepActionEvent(in_);
41
+ }
42
+ catch (e) {
43
+ throw new hatchet_error_1.default(e.message);
44
+ }
45
+ });
46
+ }
47
+ sendGroupKeyActionEvent(in_) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ try {
50
+ return this.client.sendGroupKeyActionEvent(in_);
39
51
  }
40
52
  catch (e) {
41
53
  throw new hatchet_error_1.default(e.message);
@@ -1,9 +1,11 @@
1
1
  import { Channel, ClientFactory } from 'nice-grpc';
2
2
  import { EventsServiceClient } from '../../protoc/events/events';
3
3
  import { ClientConfig } from '../hatchet-client/client-config';
4
+ import { Logger } from '../../util/logger';
4
5
  export declare class EventClient {
5
6
  config: ClientConfig;
6
7
  client: EventsServiceClient;
8
+ logger: Logger;
7
9
  constructor(config: ClientConfig, channel: Channel, factory: ClientFactory);
8
10
  push<T>(type: string, input: T): Promise<import("../../protoc/events/events").Event>;
9
11
  }
@@ -6,10 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.EventClient = void 0;
7
7
  const events_1 = require("../../protoc/events/events");
8
8
  const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
9
+ const logger_1 = require("../../util/logger");
9
10
  class EventClient {
10
11
  constructor(config, channel, factory) {
11
12
  this.config = config;
12
13
  this.client = factory.create(events_1.EventsServiceDefinition, channel);
14
+ this.logger = new logger_1.Logger(`Dispatcher`, config.log_level);
13
15
  }
14
16
  push(type, input) {
15
17
  const req = {
@@ -18,7 +20,9 @@ class EventClient {
18
20
  eventTimestamp: new Date(),
19
21
  };
20
22
  try {
21
- return this.client.push(req);
23
+ const e = this.client.push(req);
24
+ this.logger.info(`Event pushed: ${type}`);
25
+ return e;
22
26
  }
23
27
  catch (e) {
24
28
  throw new hatchet_error_1.default(e.message);
@@ -123,7 +123,7 @@ class HatchetClient {
123
123
  name,
124
124
  });
125
125
  if (typeof workflow !== 'string') {
126
- yield worker.register_workflow(workflow);
126
+ yield worker.registerWorkflow(workflow);
127
127
  return worker;
128
128
  }
129
129
  return worker;
@@ -1,9 +1,10 @@
1
1
  import { HatchetClient } from '../hatchet-client';
2
2
  import { Action, ActionListener } from '../dispatcher/action-listener';
3
- import { ActionEvent, ActionEventType } from '../../protoc/dispatcher';
3
+ import { StepActionEvent, StepActionEventType, GroupKeyActionEvent, GroupKeyActionEventType } from '../../protoc/dispatcher';
4
4
  import HatchetPromise from '../../util/hatchet-promise/hatchet-promise';
5
5
  import { Workflow } from '../../workflow';
6
6
  import { Logger } from '../../util/logger';
7
+ import { Context } from '../../step';
7
8
  export type ActionRegistry = Record<Action['actionId'], Function>;
8
9
  export declare class Worker {
9
10
  serviceName: string;
@@ -12,20 +13,22 @@ export declare class Worker {
12
13
  killing: boolean;
13
14
  handle_kill: boolean;
14
15
  action_registry: ActionRegistry;
16
+ concurrency_action_registry: ActionRegistry;
15
17
  listener: ActionListener | undefined;
16
18
  futures: Record<Action['stepRunId'], HatchetPromise<any>>;
19
+ contexts: Record<Action['stepRunId'], Context<any>>;
17
20
  logger: Logger;
18
21
  constructor(client: HatchetClient, options: {
19
22
  name: string;
20
23
  handleKill?: boolean;
21
24
  });
22
- register_workflow(workflow: Workflow, options?: {
23
- autoVersion?: boolean;
24
- }): Promise<void>;
25
- handle_start_step_run(action: Action): void;
26
- get_action_event(action: Action, eventType: ActionEventType, payload?: any): ActionEvent;
27
- handle_cancel_step_run(action: Action): void;
25
+ registerWorkflow(workflow: Workflow): Promise<void>;
26
+ handleStartStepRun(action: Action): void;
27
+ handleStartGroupKeyRun(action: Action): void;
28
+ getStepActionEvent(action: Action, eventType: StepActionEventType, payload?: any): StepActionEvent;
29
+ getGroupKeyActionEvent(action: Action, eventType: GroupKeyActionEventType, payload?: any): GroupKeyActionEvent;
30
+ handleCancelStepRun(action: Action): void;
28
31
  stop(): Promise<void>;
29
- exit_gracefully(): Promise<void>;
32
+ exitGracefully(): Promise<void>;
30
33
  start(): Promise<void>;
31
34
  }
@@ -23,6 +23,7 @@ exports.Worker = void 0;
23
23
  const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
24
24
  const dispatcher_1 = require("../../protoc/dispatcher");
25
25
  const hatchet_promise_1 = __importDefault(require("../../util/hatchet-promise/hatchet-promise"));
26
+ const workflows_1 = require("../../protoc/workflows");
26
27
  const logger_1 = require("../../util/logger");
27
28
  const sleep_1 = __importDefault(require("../../util/sleep"));
28
29
  const step_1 = require("../../step");
@@ -30,44 +31,53 @@ class Worker {
30
31
  constructor(client, options) {
31
32
  this.serviceName = 'default';
32
33
  this.futures = {};
34
+ this.contexts = {};
33
35
  this.client = client;
34
36
  this.name = options.name;
35
37
  this.action_registry = {};
36
- process.on('SIGTERM', () => this.exit_gracefully());
37
- process.on('SIGINT', () => this.exit_gracefully());
38
+ this.concurrency_action_registry = {};
39
+ process.on('SIGTERM', () => this.exitGracefully());
40
+ process.on('SIGINT', () => this.exitGracefully());
38
41
  this.killing = false;
39
42
  this.handle_kill = options.handleKill === undefined ? true : options.handleKill;
40
43
  this.logger = new logger_1.Logger(`Worker/${this.name}`, this.client.config.log_level);
41
44
  }
42
- register_workflow(workflow, options) {
45
+ registerWorkflow(workflow) {
46
+ var _a, _b;
43
47
  return __awaiter(this, void 0, void 0, function* () {
44
48
  try {
49
+ const concurrency = ((_a = workflow.concurrency) === null || _a === void 0 ? void 0 : _a.action)
50
+ ? {
51
+ action: `${this.serviceName}:${workflow.concurrency.action}`,
52
+ maxRuns: workflow.concurrency.maxRuns || 1,
53
+ limitStrategy: workflow.concurrency.limitStrategy || workflows_1.ConcurrencyLimitStrategy.CANCEL_IN_PROGRESS,
54
+ }
55
+ : undefined;
45
56
  yield this.client.admin.put_workflow({
46
57
  name: workflow.id,
47
58
  description: workflow.description,
48
- version: 'v0.55.0', // FIXME workflow.version,
59
+ version: workflow.version || '',
49
60
  eventTriggers: workflow.on.event ? [workflow.on.event] : [],
50
61
  cronTriggers: workflow.on.cron ? [workflow.on.cron] : [],
51
62
  scheduledTriggers: [],
63
+ concurrency,
52
64
  jobs: [
53
65
  {
54
- name: 'my-job', // FIXME variable names
55
- timeout: '60s',
56
- description: 'my-job',
66
+ name: workflow.id,
67
+ timeout: workflow.timeout || '60s',
68
+ description: workflow.description,
57
69
  steps: workflow.steps.map((step) => {
58
70
  var _a;
59
71
  return ({
60
72
  readableId: step.name,
61
73
  action: `${this.serviceName}:${step.name}`,
62
- timeout: '60s',
74
+ timeout: step.timeout || '60s',
63
75
  inputs: '{}',
64
76
  parents: (_a = step.parents) !== null && _a !== void 0 ? _a : [],
65
77
  });
66
78
  }),
67
79
  },
68
80
  ],
69
- }, {
70
- autoVersion: !(options === null || options === void 0 ? void 0 : options.autoVersion),
71
81
  });
72
82
  }
73
83
  catch (e) {
@@ -77,11 +87,17 @@ class Worker {
77
87
  acc[`${this.serviceName}:${step.name}`] = step.run;
78
88
  return acc;
79
89
  }, {});
90
+ this.concurrency_action_registry = ((_b = workflow.concurrency) === null || _b === void 0 ? void 0 : _b.action)
91
+ ? {
92
+ [`${this.serviceName}:${workflow.concurrency.action}`]: workflow.concurrency.key,
93
+ }
94
+ : {};
80
95
  });
81
96
  }
82
- handle_start_step_run(action) {
97
+ handleStartStepRun(action) {
83
98
  const { actionId } = action;
84
99
  const context = new step_1.Context(action.actionPayload);
100
+ this.contexts[action.stepRunId] = context;
85
101
  const step = this.action_registry[actionId];
86
102
  if (!step) {
87
103
  this.logger.error(`Could not find step '${actionId}'`);
@@ -94,8 +110,8 @@ class Worker {
94
110
  this.logger.info(`Step run ${action.stepRunId} succeeded`);
95
111
  try {
96
112
  // Send the action event to the dispatcher
97
- const event = this.get_action_event(action, dispatcher_1.ActionEventType.STEP_EVENT_TYPE_COMPLETED, result);
98
- this.client.dispatcher.send_action_event(event);
113
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_COMPLETED, result);
114
+ this.client.dispatcher.sendStepActionEvent(event);
99
115
  // delete the run from the futures
100
116
  delete this.futures[action.stepRunId];
101
117
  }
@@ -107,8 +123,8 @@ class Worker {
107
123
  this.logger.error(`Step run ${action.stepRunId} failed: ${error.message}`);
108
124
  try {
109
125
  // Send the action event to the dispatcher
110
- const event = this.get_action_event(action, dispatcher_1.ActionEventType.STEP_EVENT_TYPE_FAILED, error);
111
- this.client.dispatcher.send_action_event(event);
126
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_FAILED, error);
127
+ this.client.dispatcher.sendStepActionEvent(event);
112
128
  // delete the run from the futures
113
129
  delete this.futures[action.stepRunId];
114
130
  }
@@ -120,14 +136,64 @@ class Worker {
120
136
  this.futures[action.stepRunId] = future;
121
137
  try {
122
138
  // Send the action event to the dispatcher
123
- const event = this.get_action_event(action, dispatcher_1.ActionEventType.STEP_EVENT_TYPE_STARTED);
124
- this.client.dispatcher.send_action_event(event);
139
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_STARTED);
140
+ this.client.dispatcher.sendStepActionEvent(event);
125
141
  }
126
142
  catch (e) {
127
143
  this.logger.error(`Could not send action event: ${e.message}`);
128
144
  }
129
145
  }
130
- get_action_event(action, eventType, payload = '') {
146
+ handleStartGroupKeyRun(action) {
147
+ const { actionId } = action;
148
+ const context = new step_1.Context(action.actionPayload);
149
+ const key = action.getGroupKeyRunId;
150
+ this.contexts[key] = context;
151
+ const step = this.action_registry[actionId];
152
+ if (!step) {
153
+ this.logger.error(`Could not find step '${actionId}'`);
154
+ return;
155
+ }
156
+ const run = () => __awaiter(this, void 0, void 0, function* () {
157
+ return step(context);
158
+ });
159
+ const success = (result) => {
160
+ this.logger.info(`Step run ${action.stepRunId} succeeded`);
161
+ try {
162
+ // Send the action event to the dispatcher
163
+ const event = this.getGroupKeyActionEvent(action, dispatcher_1.GroupKeyActionEventType.GROUP_KEY_EVENT_TYPE_COMPLETED, result);
164
+ this.client.dispatcher.sendGroupKeyActionEvent(event);
165
+ // delete the run from the futures
166
+ delete this.futures[key];
167
+ }
168
+ catch (e) {
169
+ this.logger.error(`Could not send action event: ${e.message}`);
170
+ }
171
+ };
172
+ const failure = (error) => {
173
+ this.logger.error(`Step run ${key} failed: ${error.message}`);
174
+ try {
175
+ // Send the action event to the dispatcher
176
+ const event = this.getGroupKeyActionEvent(action, dispatcher_1.GroupKeyActionEventType.GROUP_KEY_EVENT_TYPE_FAILED, error);
177
+ this.client.dispatcher.sendGroupKeyActionEvent(event);
178
+ // delete the run from the futures
179
+ delete this.futures[key];
180
+ }
181
+ catch (e) {
182
+ this.logger.error(`Could not send action event: ${e.message}`);
183
+ }
184
+ };
185
+ const future = new hatchet_promise_1.default(run().then(success).catch(failure));
186
+ this.futures[action.getGroupKeyRunId] = future;
187
+ try {
188
+ // Send the action event to the dispatcher
189
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_STARTED);
190
+ this.client.dispatcher.sendStepActionEvent(event);
191
+ }
192
+ catch (e) {
193
+ this.logger.error(`Could not send action event: ${e.message}`);
194
+ }
195
+ }
196
+ getStepActionEvent(action, eventType, payload = '') {
131
197
  return {
132
198
  workerId: this.name,
133
199
  jobId: action.jobId,
@@ -140,9 +206,26 @@ class Worker {
140
206
  eventPayload: JSON.stringify(payload),
141
207
  };
142
208
  }
143
- handle_cancel_step_run(action) {
209
+ getGroupKeyActionEvent(action, eventType, payload = '') {
210
+ return {
211
+ workerId: this.name,
212
+ workflowRunId: action.workflowRunId,
213
+ getGroupKeyRunId: action.getGroupKeyRunId,
214
+ actionId: action.actionId,
215
+ eventTimestamp: new Date(),
216
+ eventType,
217
+ eventPayload: JSON.stringify(payload),
218
+ };
219
+ }
220
+ handleCancelStepRun(action) {
144
221
  const { stepRunId } = action;
145
222
  const future = this.futures[stepRunId];
223
+ const context = this.contexts[stepRunId];
224
+ // TODO send cancel signal to context
225
+ // if (context && context.cancel) {
226
+ // context.cancel();
227
+ // delete this.contexts[stepRunId];
228
+ // }
146
229
  if (future) {
147
230
  future.cancel();
148
231
  delete this.futures[stepRunId];
@@ -150,10 +233,10 @@ class Worker {
150
233
  }
151
234
  stop() {
152
235
  return __awaiter(this, void 0, void 0, function* () {
153
- yield this.exit_gracefully();
236
+ yield this.exitGracefully();
154
237
  });
155
238
  }
156
- exit_gracefully() {
239
+ exitGracefully() {
157
240
  var _a;
158
241
  return __awaiter(this, void 0, void 0, function* () {
159
242
  this.killing = true;
@@ -179,7 +262,7 @@ class Worker {
179
262
  let retries = 0;
180
263
  while (retries < 5) {
181
264
  try {
182
- this.listener = yield this.client.dispatcher.get_action_listener({
265
+ this.listener = yield this.client.dispatcher.getActionListener({
183
266
  workerName: this.name,
184
267
  services: ['default'],
185
268
  actions: Object.keys(this.action_registry),
@@ -191,12 +274,18 @@ class Worker {
191
274
  _c = generator_1_1.value;
192
275
  _d = false;
193
276
  const action = _c;
194
- this.logger.info(`Worker ${this.name} received action ${action.actionId}`);
277
+ this.logger.info(`Worker ${this.name} received action ${action.actionId}:${action.actionType}`);
195
278
  if (action.actionType === dispatcher_1.ActionType.START_STEP_RUN) {
196
- this.handle_start_step_run(action);
279
+ this.handleStartStepRun(action);
197
280
  }
198
281
  else if (action.actionType === dispatcher_1.ActionType.CANCEL_STEP_RUN) {
199
- this.handle_cancel_step_run(action);
282
+ this.handleCancelStepRun(action);
283
+ }
284
+ else if (action.actionType === dispatcher_1.ActionType.START_GET_GROUP_KEY) {
285
+ this.handleStartGroupKeyRun(action);
286
+ }
287
+ else {
288
+ this.logger.error(`Worker ${this.name} received unknown action type ${action.actionType}`);
200
289
  }
201
290
  }
202
291
  }
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@hatchet-dev/typescript-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Background task orchestration & visibility for developers",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "!**/*.test.js",
10
+ "!**/*.test.d.ts"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/hatchet-dev/hatchet.git"
15
+ },
16
+ "scripts": {
17
+ "prepare": "npm run build",
18
+ "build": "tsc && resolve-tspaths",
19
+ "test": "jest",
20
+ "test:watch": "jest --watch",
21
+ "generate": "./generate-protoc.sh",
22
+ "lint:check": "npm run eslint:check && npm run prettier:check",
23
+ "lint:fix": "npm run eslint:fix && npm run prettier:fix",
24
+ "eslint:check": "eslint \"{hatchet,tests}/**/*.{ts,tsx,js}\"",
25
+ "eslint:fix": "eslint \"{hatchet,tests}/**/*.{ts,tsx,js}\" --fix",
26
+ "prettier:check": "prettier \"hatchet/**/*.{ts,tsx}\" --list-different",
27
+ "prettier:fix": "prettier \"hatchet/**/*.{ts,tsx}\" --write",
28
+ "exec": "npx dotenv -- ts-node -r tsconfig-paths/register --project tsconfig.json",
29
+ "example:event": "npm run exec -- ./examples/example-event.ts",
30
+ "worker:simple": "npm run exec -- ./examples/simple-worker.ts",
31
+ "worker:dag": "npm run exec -- ./examples/dag-worker.ts",
32
+ "worker:concurrency": "npm run exec -- ./examples/concurrency/concurrency-worker.ts",
33
+ "event:concurrency": "npm run exec -- ./examples/concurrency/concurrency-event.ts",
34
+ "prepublish": "cp package.json dist/package.json",
35
+ "publish": "npm publish dist --access public"
36
+ },
37
+ "keywords": [],
38
+ "author": "",
39
+ "license": "MIT",
40
+ "devDependencies": {
41
+ "@types/jest": "^29.5.11",
42
+ "@typescript-eslint/eslint-plugin": "^6.4.0",
43
+ "autoprefixer": "^10.4.16",
44
+ "dotenv-cli": "^7.3.0",
45
+ "eslint": "^8.56.0",
46
+ "eslint-config-airbnb-typescript": "^17.1.0",
47
+ "eslint-config-prettier": "^9.1.0",
48
+ "eslint-config-standard-with-typescript": "^43.0.0",
49
+ "eslint-import-resolver-typescript": "^3.6.1",
50
+ "eslint-plugin-import": "^2.29.1",
51
+ "eslint-plugin-jest": "^27.6.3",
52
+ "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
53
+ "eslint-plugin-prettier": "^5.0.1",
54
+ "eslint-plugin-promise": "^6.0.0",
55
+ "eslint-plugin-unused-imports": "^3.0.0",
56
+ "grpc-tools": "^1.12.4",
57
+ "jest": "^29.7.0",
58
+ "prettier": "^3.1.1",
59
+ "resolve-tspaths": "^0.8.17",
60
+ "ts-jest": "^29.1.1",
61
+ "ts-node": "^10.9.2",
62
+ "ts-proto": "^1.167.0",
63
+ "typescript": "^5.3.3"
64
+ },
65
+ "dependencies": {
66
+ "long": "^5.2.3",
67
+ "nice-grpc": "^2.1.7",
68
+ "nice-grpc-common": "^2.0.2",
69
+ "protobufjs": "^7.2.6",
70
+ "yaml": "^2.3.4",
71
+ "zod": "^3.22.4"
72
+ }
73
+ }