@openfn/ws-worker 0.2.7 → 0.2.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # ws-worker
2
2
 
3
+ ## 0.2.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 54d0017: Start ws-worker using node (not pnpm) by default
8
+ - 6f78b7a: Add env var for WORKER_REPO_DIR
9
+ - Updated dependencies [4a17048]
10
+ - @openfn/engine-multi@0.2.0
11
+ - @openfn/runtime@0.2.0
12
+
13
+ ## 0.2.8
14
+
15
+ ### Patch Changes
16
+
17
+ - Tweak typings
18
+
3
19
  ## 0.2.7
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -48,7 +48,7 @@ You can start a dev server (which rebuilds on save) by running:
48
48
  pnpm start:watch
49
49
  ```
50
50
 
51
- This will wrap a real runtime engine into the server (?). It will rebuild when the Worker Engine code changes (although you'll have to `pnpm build:watch` in `runtime-manager`). This will use the repo at `ENGINE_REPO_DIR` or `/tmp/openfn/repo`.
51
+ This will wrap a real runtime engine into the server. It will rebuild when the Worker Engine code changes (although you'll have to `pnpm build:watch` in `runtime-manager`). This will use the repo at `WORKER_REPO_DIR` (or a default path in /tmp)
52
52
 
53
53
  ### Disabling auto-fetch
54
54
 
package/dist/index.d.ts CHANGED
@@ -17,6 +17,40 @@ type ExitReason = {
17
17
  error_type: string | null;
18
18
  };
19
19
 
20
+ type Node = {
21
+ id: string;
22
+ body?: string;
23
+ adaptor?: string;
24
+ credential_id?: any; // TODO tighten this up, string or object
25
+ type?: 'webhook' | 'cron'; // trigger only
26
+ state?: any; // Initial state / defaults
27
+ };
28
+
29
+ interface Edge {
30
+ id: string;
31
+ source_job_id?: string;
32
+ source_trigger_id?: string;
33
+ target_job_id: string;
34
+ name?: string;
35
+ condition?: string;
36
+ error_path?: boolean;
37
+ errors?: any;
38
+ enabled?: boolean;
39
+ }
40
+
41
+ // An attempt object returned by Lightning
42
+ type Attempt = {
43
+ id: string;
44
+ dataclip_id: string;
45
+ starting_node_id: string;
46
+
47
+ triggers: Node[];
48
+ jobs: Node[];
49
+ edges: Edge[];
50
+
51
+ options?: AttemptOptions;
52
+ };
53
+
20
54
  type AttemptOptions = {
21
55
  timeout?: number;
22
56
  sanitize?: SanitizePolicies;
@@ -45,13 +79,6 @@ type ReceiveHook = {
45
79
  ) => ReceiveHook;
46
80
  };
47
81
 
48
- // export declare class Socket extends PhxSocket {
49
- // constructor(endpoint: string, options: { params: any });
50
- // onOpen(callback: () => void): void;
51
- // connect(): void;
52
- // channel(channelName: string, params: any): Channel;
53
- // }
54
-
55
82
  interface Channel extends Channel$1 {
56
83
  // on: (event: string, fn: (evt: any) => void) => void;
57
84
 
@@ -67,10 +94,66 @@ declare type Context = {
67
94
  onFinish: (result: any) => void;
68
95
  };
69
96
 
70
- declare type CLAIM_ATTEMPT = {
97
+ declare const CLAIM = "claim";
98
+ declare type ClaimPayload = {
99
+ demand?: number;
100
+ };
101
+ declare type ClaimReply = {
102
+ attempts: Array<ClaimAttempt>;
103
+ };
104
+ declare type ClaimAttempt = {
71
105
  id: string;
72
106
  token: string;
73
107
  };
108
+ declare const GET_ATTEMPT = "fetch:attempt";
109
+ declare type GetAttemptPayload = void;
110
+ declare type GetAttemptReply = Attempt;
111
+ declare const GET_CREDENTIAL = "fetch:credential";
112
+ declare type GetCredentialPayload = {
113
+ id: string;
114
+ };
115
+ declare type GetCredentialReply = {};
116
+ declare const GET_DATACLIP = "fetch:dataclip";
117
+ declare type GetDataclipPayload = {
118
+ id: string;
119
+ };
120
+ declare type GetDataClipReply = Uint8Array;
121
+ declare const ATTEMPT_START = "attempt:start";
122
+ declare type AttemptStartPayload = void;
123
+ declare type AttemptStartReply = {};
124
+ declare const ATTEMPT_COMPLETE = "attempt:complete";
125
+ declare type AttemptCompletePayload = ExitReason & {
126
+ final_dataclip_id?: string;
127
+ };
128
+ declare type AttemptCompleteReply = undefined;
129
+ declare const ATTEMPT_LOG = "attempt:log";
130
+ declare type AttemptLogPayload = {
131
+ message: Array<string | object>;
132
+ timestamp: string;
133
+ attempt_id: string;
134
+ level?: string;
135
+ source?: string;
136
+ job_id?: string;
137
+ run_id?: string;
138
+ };
139
+ declare type AttemptLogReply = void;
140
+ declare const RUN_START = "run:start";
141
+ declare type RunStartPayload = {
142
+ job_id: string;
143
+ run_id: string;
144
+ attempt_id?: string;
145
+ input_dataclip_id?: string;
146
+ };
147
+ declare type RunStartReply = void;
148
+ declare const RUN_COMPLETE = "run:complete";
149
+ declare type RunCompletePayload = ExitReason & {
150
+ attempt_id?: string;
151
+ job_id: string;
152
+ run_id: string;
153
+ output_dataclip?: string;
154
+ output_dataclip_id?: string;
155
+ };
156
+ declare type RunCompleteReply = void;
74
157
 
75
158
  declare type ServerOptions = {
76
159
  maxWorkflows?: number;
@@ -89,10 +172,10 @@ interface ServerApp extends Koa {
89
172
  socket: any;
90
173
  channel: Channel;
91
174
  workflows: Record<string, true | Context>;
92
- execute: ({ id, token }: CLAIM_ATTEMPT) => Promise<void>;
175
+ execute: ({ id, token }: ClaimAttempt) => Promise<void>;
93
176
  destroy: () => void;
94
177
  killWorkloop?: () => void;
95
178
  }
96
179
  declare function createServer(engine: RuntimeEngine, options?: ServerOptions): ServerApp;
97
180
 
98
- export { createServer as default };
181
+ export { ATTEMPT_COMPLETE, ATTEMPT_LOG, ATTEMPT_START, AttemptCompletePayload, AttemptCompleteReply, AttemptLogPayload, AttemptLogReply, AttemptStartPayload, AttemptStartReply, CLAIM, ClaimAttempt, ClaimPayload, ClaimReply, GET_ATTEMPT, GET_CREDENTIAL, GET_DATACLIP, GetAttemptPayload, GetAttemptReply, GetCredentialPayload, GetCredentialReply, GetDataClipReply, GetDataclipPayload, RUN_COMPLETE, RUN_START, RunCompletePayload, RunCompleteReply, RunStartPayload, RunStartReply, createServer as default };
package/dist/index.js CHANGED
@@ -661,5 +661,14 @@ var server_default = createServer;
661
661
  // src/index.ts
662
662
  var src_default = server_default;
663
663
  export {
664
+ ATTEMPT_COMPLETE,
665
+ ATTEMPT_LOG,
666
+ ATTEMPT_START,
667
+ CLAIM,
668
+ GET_ATTEMPT,
669
+ GET_CREDENTIAL,
670
+ GET_DATACLIP,
671
+ RUN_COMPLETE,
672
+ RUN_START,
664
673
  src_default as default
665
674
  };
package/dist/start.js CHANGED
@@ -4864,8 +4864,8 @@ import createLogger from "@openfn/logger";
4864
4864
  import createRTE from "@openfn/engine-multi";
4865
4865
 
4866
4866
  // src/mock/runtime-engine.ts
4867
- import crypto from "node:crypto";
4868
4867
  import { EventEmitter } from "node:events";
4868
+ import run from "@openfn/runtime";
4869
4869
 
4870
4870
  // src/mock/resolvers.ts
4871
4871
  var mockResolveCredential = (_credId) => new Promise(
@@ -4887,6 +4887,10 @@ var resolvers_default = {
4887
4887
  };
4888
4888
 
4889
4889
  // src/mock/runtime-engine.ts
4890
+ var helpers = {
4891
+ fn: (f) => (s) => f(s),
4892
+ wait: (duration) => (s) => new Promise((resolve5) => setTimeout(() => resolve5(s), duration))
4893
+ };
4890
4894
  async function createMock() {
4891
4895
  const activeWorkflows = {};
4892
4896
  const bus = new EventEmitter();
@@ -4902,73 +4906,59 @@ async function createMock() {
4902
4906
  const listen = (planId, events) => {
4903
4907
  listeners[planId] = events;
4904
4908
  };
4905
- const executeJob = async (workflowId, job, initialState = {}, resolvers = resolvers_default) => {
4906
- const { id, expression, configuration, adaptor } = job;
4907
- if (!expression && !adaptor) {
4908
- return initialState;
4909
- }
4910
- const runId = crypto.randomUUID();
4911
- const jobId = id;
4912
- if (typeof configuration === "string") {
4913
- await resolvers.credential?.(configuration);
4914
- }
4915
- const info = (...message) => {
4916
- dispatch("workflow-log", {
4917
- workflowId,
4918
- message,
4919
- level: "info",
4920
- time: (BigInt(Date.now()) * BigInt(1e3)).toString(),
4921
- name: "mck"
4922
- });
4923
- };
4924
- dispatch("job-start", { workflowId, jobId, runId });
4925
- info("Running job " + jobId);
4926
- let nextState = initialState;
4927
- if (expression?.startsWith?.("wait@")) {
4928
- const [_, delay] = expression.split("@");
4929
- nextState = initialState;
4930
- await new Promise((resolve5) => {
4931
- setTimeout(() => resolve5(), parseInt(delay));
4932
- });
4933
- } else {
4934
- try {
4935
- nextState = JSON.parse(expression);
4936
- info("Parsing expression as JSON state");
4937
- info(nextState);
4938
- } catch (e) {
4939
- nextState = initialState;
4940
- }
4941
- }
4942
- dispatch("job-complete", {
4943
- workflowId,
4944
- jobId,
4945
- state: nextState,
4946
- runId,
4947
- next: []
4948
- });
4949
- return nextState;
4950
- };
4951
- const execute2 = (xplan, options = {
4909
+ const execute2 = async (xplan, options = {
4952
4910
  resolvers: resolvers_default
4953
4911
  }) => {
4954
- if (options.throw) {
4955
- throw new Error("test error");
4956
- }
4957
- const { id, jobs, initialState } = xplan;
4958
- const workflowId = id;
4912
+ const { id, jobs } = xplan;
4959
4913
  activeWorkflows[id] = true;
4960
- setTimeout(() => {
4961
- dispatch("workflow-start", { workflowId });
4962
- setTimeout(async () => {
4963
- let state = initialState || {};
4964
- for (const job of jobs) {
4965
- state = await executeJob(id, job, state, options.resolvers);
4914
+ for (const job of jobs) {
4915
+ if (typeof job.configuration === "string") {
4916
+ job.configuration = await options.resolvers?.credential?.(
4917
+ job.configuration
4918
+ );
4919
+ }
4920
+ if (typeof job.expression === "string" && !job.expression.match(/export default \[/)) {
4921
+ job.expression = `export default [${job.expression}];`;
4922
+ }
4923
+ }
4924
+ const jobLogger = {
4925
+ log: (...args2) => {
4926
+ dispatch("workflow-log", {
4927
+ workflowId: id,
4928
+ level: "info",
4929
+ json: true,
4930
+ message: args2,
4931
+ time: Date.now()
4932
+ });
4933
+ }
4934
+ };
4935
+ const opts = {
4936
+ strict: false,
4937
+ jobLogger,
4938
+ ...options,
4939
+ globals: helpers,
4940
+ callbacks: {
4941
+ notify: (name, payload) => {
4942
+ dispatch(name, {
4943
+ workflowId: id,
4944
+ ...payload
4945
+ });
4966
4946
  }
4967
- setTimeout(() => {
4968
- delete activeWorkflows[id];
4969
- dispatch("workflow-complete", { workflowId });
4970
- }, 1);
4971
- }, 1);
4947
+ }
4948
+ };
4949
+ setTimeout(async () => {
4950
+ dispatch("workflow-start", { workflowId: id });
4951
+ try {
4952
+ await run(xplan, void 0, opts);
4953
+ } catch (e) {
4954
+ dispatch("workflow-error", {
4955
+ workflowId: id,
4956
+ type: e.name,
4957
+ message: e.message
4958
+ });
4959
+ }
4960
+ delete activeWorkflows[id];
4961
+ dispatch("workflow-complete", { workflowId: id });
4972
4962
  }, 1);
4973
4963
  };
4974
4964
  const getStatus = () => {
@@ -5105,10 +5095,10 @@ var startWorkloop = (app, logger2, minBackoff2, maxBackoff2, maxWorkers) => {
5105
5095
  var workloop_default = startWorkloop;
5106
5096
 
5107
5097
  // src/api/execute.ts
5108
- import crypto3 from "node:crypto";
5098
+ import crypto2 from "node:crypto";
5109
5099
 
5110
5100
  // src/util/convert-attempt.ts
5111
- import crypto2 from "node:crypto";
5101
+ import crypto from "node:crypto";
5112
5102
  var conditions = {
5113
5103
  on_job_success: "!state.errors",
5114
5104
  on_job_failure: "state.errors",
@@ -5153,7 +5143,7 @@ var convert_attempt_default = (attempt) => {
5153
5143
  }
5154
5144
  if (attempt.jobs?.length) {
5155
5145
  attempt.jobs.forEach((job) => {
5156
- const id = job.id || crypto2.randomUUID();
5146
+ const id = job.id || crypto.randomUUID();
5157
5147
  nodes[id] = {
5158
5148
  id,
5159
5149
  configuration: job.credential_id,
@@ -5336,7 +5326,7 @@ var sendEvent = (channel, event, payload) => new Promise((resolve5, reject) => {
5336
5326
  channel.push(event, payload).receive("error", reject).receive("timeout", () => reject(new Error("timeout"))).receive("ok", resolve5);
5337
5327
  });
5338
5328
  function onJobStart({ channel, state }, event) {
5339
- state.activeRun = crypto3.randomUUID();
5329
+ state.activeRun = crypto2.randomUUID();
5340
5330
  state.activeJob = event.jobId;
5341
5331
  const input_dataclip_id = state.inputDataclips[event.jobId];
5342
5332
  return sendEvent(channel, RUN_START, {
@@ -5354,7 +5344,7 @@ function onJobError(context, event) {
5354
5344
  }
5355
5345
  }
5356
5346
  function onJobComplete({ channel, state }, event, error) {
5357
- const dataclipId = crypto3.randomUUID();
5347
+ const dataclipId = crypto2.randomUUID();
5358
5348
  const run_id = state.activeRun;
5359
5349
  const job_id = state.activeJob;
5360
5350
  if (!state.dataclips) {
@@ -5647,6 +5637,7 @@ function createServer(engine, options = {}) {
5647
5637
  var server_default = createServer;
5648
5638
 
5649
5639
  // src/start.ts
5640
+ var { WORKER_REPO_DIR, WORKER_SECRET } = process.env;
5650
5641
  var args = yargs_default(hideBin(process.argv)).command("server", "Start a ws-worker server").option("port", {
5651
5642
  alias: "p",
5652
5643
  description: "Port to run the server on",
@@ -5658,7 +5649,8 @@ var args = yargs_default(hideBin(process.argv)).command("server", "Start a ws-wo
5658
5649
  default: "ws://localhost:4000/worker"
5659
5650
  }).option("repo-dir", {
5660
5651
  alias: "d",
5661
- description: "Path to the runtime repo (where modules will be installed)"
5652
+ description: "Path to the runtime repo (where modules will be installed)",
5653
+ default: WORKER_REPO_DIR
5662
5654
  }).option("secret", {
5663
5655
  alias: "s",
5664
5656
  description: "Worker secret (comes from WORKER_SECRET by default)"
@@ -5689,7 +5681,6 @@ if (args.lightning === "mock") {
5689
5681
  args.secret = "abdefg";
5690
5682
  }
5691
5683
  } else if (!args.secret) {
5692
- const { WORKER_SECRET } = process.env;
5693
5684
  if (!WORKER_SECRET) {
5694
5685
  logger.error("WORKER_SECRET is not set");
5695
5686
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/ws-worker",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "A Websocket Worker to connect Lightning to a Runtime Engine",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -21,9 +21,9 @@
21
21
  "koa-logger": "^3.2.1",
22
22
  "phoenix": "^1.7.7",
23
23
  "ws": "^8.14.1",
24
- "@openfn/engine-multi": "0.1.11",
25
- "@openfn/runtime": "0.1.4",
26
- "@openfn/logger": "0.0.19"
24
+ "@openfn/engine-multi": "0.2.0",
25
+ "@openfn/logger": "0.0.19",
26
+ "@openfn/runtime": "0.2.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/koa": "^2.13.5",
@@ -40,7 +40,7 @@
40
40
  "tsup": "^6.2.3",
41
41
  "typescript": "^4.6.4",
42
42
  "yargs": "^17.6.2",
43
- "@openfn/lightning-mock": "1.0.12"
43
+ "@openfn/lightning-mock": "1.1.2"
44
44
  },
45
45
  "files": [
46
46
  "dist",