@highstate/worker-sdk 0.9.16 → 0.9.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "sourceHashes": {
3
- "./dist/index.js": 2136108195
3
+ "./dist/index.js": 1796862525
4
4
  }
5
5
  }
package/dist/index.js CHANGED
@@ -1,26 +1,29 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import { createInterface } from 'node:readline/promises';
3
+ import { createAuthenticationMiddleware } from '@highstate/api';
3
4
  import { WorkerServiceDefinition } from '@highstate/api/worker.v1';
5
+ import { workerRunOptionsSchema } from '@highstate/contract';
4
6
  import { createClientFactory, createChannel } from 'nice-grpc';
5
- import { createAuthenticationMiddleware } from '@highstate/api';
6
7
 
7
8
  // src/index.ts
8
9
  var Worker = class _Worker {
9
- constructor(projectId, workerId, apiKey, apiUrl) {
10
- this.workerId = workerId;
11
- const authMiddleware = createAuthenticationMiddleware(apiKey, projectId);
10
+ constructor(options, runOptions) {
11
+ this.options = options;
12
+ this.runOptions = runOptions;
13
+ const authMiddleware = createAuthenticationMiddleware(runOptions.apiKey, runOptions.projectId);
12
14
  this.clientFactory = createClientFactory().use(authMiddleware);
13
- this.channel = createChannel(apiUrl);
15
+ this.channel = createChannel(runOptions.apiUrl);
14
16
  }
15
17
  eventEmitter = new EventEmitter();
16
18
  clientFactory;
17
19
  channel;
18
20
  onUnitRegistration(handler) {
19
- const handle = async (instanceId, params) => {
21
+ const handle = async (stateId, params) => {
20
22
  try {
21
- await handler(instanceId, params);
23
+ const parsedParams = this.options.paramsSchema.parse(params);
24
+ await handler(stateId, parsedParams);
22
25
  } catch (error) {
23
- console.error(`Error handling unit registration for instance ${instanceId}:`, error);
26
+ console.error(`Error handling unit registration for instance ${stateId}:`, error);
24
27
  }
25
28
  };
26
29
  this.eventEmitter.on(
@@ -29,11 +32,11 @@ var Worker = class _Worker {
29
32
  );
30
33
  }
31
34
  onUnitDeregistration(handler) {
32
- const handle = async (instanceId) => {
35
+ const handle = async (stateId) => {
33
36
  try {
34
- await handler(instanceId);
37
+ await handler(stateId);
35
38
  } catch (error) {
36
- console.error(`Error handling unit deregistration for instance ${instanceId}:`, error);
39
+ console.error(`Error handling unit deregistration for instance ${stateId}:`, error);
37
40
  }
38
41
  };
39
42
  this.eventEmitter.on("unitDeregistration", (instanceId) => void handle(instanceId));
@@ -43,42 +46,55 @@ var Worker = class _Worker {
43
46
  }
44
47
  async start() {
45
48
  const workerClient = this.createClient(WorkerServiceDefinition);
46
- for await (const { event } of workerClient.connect({ workerId: this.workerId })) {
49
+ await workerClient.updateWorkerVersionMeta({
50
+ workerVersionId: this.runOptions.workerVersionId,
51
+ meta: this.options
52
+ });
53
+ for await (const { event } of workerClient.connect({
54
+ workerVersionId: this.runOptions.workerVersionId
55
+ })) {
47
56
  switch (event?.$case) {
48
57
  case "unitRegistration": {
49
58
  this.eventEmitter.emit(
50
59
  "unitRegistration",
51
- event.value.instanceId,
60
+ event.value.stateId,
52
61
  event.value.params
53
62
  );
54
63
  break;
55
64
  }
56
65
  case "unitDeregistration": {
57
- this.eventEmitter.emit("unitDeregistration", event.value.instanceId);
66
+ this.eventEmitter.emit("unitDeregistration", event.value.stateId);
58
67
  break;
59
68
  }
60
69
  }
61
70
  }
62
71
  }
63
- static async create() {
72
+ /**
73
+ * Creates a new worker and connects it to the Highstate platform.
74
+ *
75
+ * @param metadata The metadata of the worker version to update.
76
+ * @param paramsSchema The Zod schema of the parameters accepted by the worker on each unit registration.
77
+ */
78
+ static async create(options) {
79
+ let runOptionsJson;
64
80
  for await (const line of createInterface({ input: process.stdin })) {
65
- let data;
66
81
  try {
67
- data = JSON.parse(line);
82
+ runOptionsJson = JSON.parse(line);
68
83
  } catch (error) {
69
- throw new Error("Failed to parse worker input", { cause: error });
70
- }
71
- if (!data.apiKey || !data.apiUrl || !data.projectId || !data.workerId) {
72
- throw new Error(
73
- "Worker input must contain apiKey, apiUrl, projectId, and workerId properties"
74
- );
84
+ throw new Error("Failed to parse worker run options", { cause: error });
75
85
  }
76
- if (typeof data.apiKey !== "string" || typeof data.apiUrl !== "string" || typeof data.projectId !== "string" || typeof data.workerId !== "string") {
77
- throw new Error("Worker input properties must be strings");
78
- }
79
- return new _Worker(data.projectId, data.workerId, data.apiKey, data.apiUrl);
86
+ break;
87
+ }
88
+ if (!runOptionsJson) {
89
+ throw new Error("No worker run options provided");
90
+ }
91
+ let runOptions;
92
+ try {
93
+ runOptions = workerRunOptionsSchema.parse(runOptionsJson);
94
+ } catch (error) {
95
+ throw new Error("Invalid worker run options", { cause: error });
80
96
  }
81
- throw new Error("Failed to read worker input from stdin");
97
+ return new _Worker(options, runOptions);
82
98
  }
83
99
  };
84
100
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventEmitter } from \"node:events\"\nimport { createInterface } from \"node:readline/promises\"\nimport { WorkerServiceDefinition } from \"@highstate/api/worker.v1\"\nimport {\n Channel,\n createChannel,\n createClientFactory,\n type ClientFactory,\n type CompatServiceDefinition,\n} from \"nice-grpc\"\nimport { createAuthenticationMiddleware } from \"@highstate/api\"\n\nexport class Worker<TParams extends Record<string, unknown> = Record<string, unknown>> {\n private readonly eventEmitter = new EventEmitter()\n private readonly clientFactory: ClientFactory\n private readonly channel: Channel\n\n private constructor(\n projectId: string,\n private readonly workerId: string,\n apiKey: string,\n apiUrl: string,\n ) {\n const authMiddleware = createAuthenticationMiddleware(apiKey, projectId)\n\n this.clientFactory = createClientFactory().use(authMiddleware)\n this.channel = createChannel(apiUrl)\n }\n\n onUnitRegistration(handler: (instanceId: string, params: TParams) => Promise<void> | void) {\n const handle = async (instanceId: string, params: TParams) => {\n try {\n await handler(instanceId, params)\n } catch (error) {\n console.error(`Error handling unit registration for instance ${instanceId}:`, error)\n }\n }\n\n this.eventEmitter.on(\n \"unitRegistration\",\n (instanceId: string, params: TParams) => void handle(instanceId, params),\n )\n }\n\n onUnitDeregistration(handler: (instanceId: string) => Promise<void> | void) {\n const handle = async (instanceId: string) => {\n try {\n await handler(instanceId)\n } catch (error) {\n console.error(`Error handling unit deregistration for instance ${instanceId}:`, error)\n }\n }\n\n this.eventEmitter.on(\"unitDeregistration\", (instanceId: string) => void handle(instanceId))\n }\n\n createClient<TService extends CompatServiceDefinition>(definition: TService) {\n return this.clientFactory.create(definition, this.channel)\n }\n\n async start(): Promise<void> {\n const workerClient = this.createClient(WorkerServiceDefinition)\n\n for await (const { event } of workerClient.connect({ workerId: this.workerId })) {\n switch (event?.$case) {\n case \"unitRegistration\": {\n this.eventEmitter.emit(\n \"unitRegistration\",\n event.value.instanceId,\n event.value.params as TParams,\n )\n break\n }\n case \"unitDeregistration\": {\n this.eventEmitter.emit(\"unitDeregistration\", event.value.instanceId)\n break\n }\n }\n }\n }\n\n static async create<TParams extends Record<string, unknown> = Record<string, unknown>>(): Promise<\n Worker<TParams>\n > {\n for await (const line of createInterface({ input: process.stdin })) {\n let data: Record<string, unknown>\n try {\n data = JSON.parse(line) as Record<string, unknown>\n } catch (error) {\n throw new Error(\"Failed to parse worker input\", { cause: error })\n }\n\n if (!data.apiKey || !data.apiUrl || !data.projectId || !data.workerId) {\n throw new Error(\n \"Worker input must contain apiKey, apiUrl, projectId, and workerId properties\",\n )\n }\n\n if (\n typeof data.apiKey !== \"string\" ||\n typeof data.apiUrl !== \"string\" ||\n typeof data.projectId !== \"string\" ||\n typeof data.workerId !== \"string\"\n ) {\n throw new Error(\"Worker input properties must be strings\")\n }\n\n return new Worker<TParams>(data.projectId, data.workerId, data.apiKey, data.apiUrl)\n }\n\n throw new Error(\"Failed to read worker input from stdin\")\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventEmitter } from \"node:events\"\nimport { createInterface } from \"node:readline/promises\"\nimport { createAuthenticationMiddleware } from \"@highstate/api\"\nimport { WorkerServiceDefinition } from \"@highstate/api/worker.v1\"\nimport {\n type CommonObjectMeta,\n type ServiceAccountMeta,\n type WorkerRunOptions,\n workerRunOptionsSchema,\n type z,\n} from \"@highstate/contract\"\nimport {\n type Channel,\n type ClientFactory,\n type CompatServiceDefinition,\n createChannel,\n createClientFactory,\n} from \"nice-grpc\"\n\nexport type RegistrationHandler<TParamsSchema extends z.ZodType> = (\n instanceId: string,\n params: z.infer<TParamsSchema>,\n) => Promise<void> | void\n\nexport type DeregistrationHandler = (instanceId: string) => Promise<void> | void\n\nexport type WorkerOptions<TParamsSchema extends z.ZodType = z.ZodType> = {\n workerMeta: CommonObjectMeta\n serviceAccountMeta: ServiceAccountMeta\n paramsSchema: TParamsSchema\n}\n\nexport class Worker<TParamsSchema extends z.ZodType> {\n private readonly eventEmitter = new EventEmitter()\n private readonly clientFactory: ClientFactory\n private readonly channel: Channel\n\n private constructor(\n private readonly options: WorkerOptions<TParamsSchema>,\n private readonly runOptions: WorkerRunOptions,\n ) {\n const authMiddleware = createAuthenticationMiddleware(runOptions.apiKey, runOptions.projectId)\n\n this.clientFactory = createClientFactory().use(authMiddleware)\n this.channel = createChannel(runOptions.apiUrl)\n }\n\n onUnitRegistration(handler: RegistrationHandler<TParamsSchema>) {\n const handle = async (stateId: string, params: unknown) => {\n try {\n const parsedParams = this.options.paramsSchema.parse(params)\n\n await handler(stateId, parsedParams)\n } catch (error) {\n console.error(`Error handling unit registration for instance ${stateId}:`, error)\n }\n }\n\n this.eventEmitter.on(\n \"unitRegistration\",\n (instanceId: string, params: TParamsSchema) => void handle(instanceId, params),\n )\n }\n\n onUnitDeregistration(handler: DeregistrationHandler) {\n const handle = async (stateId: string) => {\n try {\n await handler(stateId)\n } catch (error) {\n console.error(`Error handling unit deregistration for instance ${stateId}:`, error)\n }\n }\n\n this.eventEmitter.on(\"unitDeregistration\", (instanceId: string) => void handle(instanceId))\n }\n\n createClient<TService extends CompatServiceDefinition>(definition: TService) {\n return this.clientFactory.create(definition, this.channel)\n }\n\n async start(): Promise<void> {\n const workerClient = this.createClient(WorkerServiceDefinition)\n\n await workerClient.updateWorkerVersionMeta({\n workerVersionId: this.runOptions.workerVersionId,\n meta: this.options,\n })\n\n for await (const { event } of workerClient.connect({\n workerVersionId: this.runOptions.workerVersionId,\n })) {\n switch (event?.$case) {\n case \"unitRegistration\": {\n this.eventEmitter.emit(\n \"unitRegistration\",\n event.value.stateId,\n event.value.params as TParamsSchema,\n )\n break\n }\n case \"unitDeregistration\": {\n this.eventEmitter.emit(\"unitDeregistration\", event.value.stateId)\n break\n }\n }\n }\n }\n\n /**\n * Creates a new worker and connects it to the Highstate platform.\n *\n * @param metadata The metadata of the worker version to update.\n * @param paramsSchema The Zod schema of the parameters accepted by the worker on each unit registration.\n */\n static async create<TParamsSchema extends z.ZodType>(\n options: WorkerOptions<TParamsSchema>,\n ): Promise<Worker<TParamsSchema>> {\n let runOptionsJson: unknown\n for await (const line of createInterface({ input: process.stdin })) {\n try {\n runOptionsJson = JSON.parse(line)\n } catch (error) {\n throw new Error(\"Failed to parse worker run options\", { cause: error })\n }\n\n break\n }\n\n if (!runOptionsJson) {\n throw new Error(\"No worker run options provided\")\n }\n\n let runOptions: WorkerRunOptions\n try {\n runOptions = workerRunOptionsSchema.parse(runOptionsJson)\n } catch (error) {\n throw new Error(\"Invalid worker run options\", { cause: error })\n }\n\n return new Worker(options, runOptions)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highstate/worker-sdk",
3
- "version": "0.9.16",
3
+ "version": "0.9.19",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -19,15 +19,16 @@
19
19
  "build": "highstate build"
20
20
  },
21
21
  "devDependencies": {
22
- "@highstate/cli": "^0.9.16"
22
+ "@highstate/cli": "^0.9.19"
23
23
  },
24
24
  "dependencies": {
25
25
  "@bufbuild/protobuf": "^2.6.0",
26
- "@highstate/api": "^0.9.16",
26
+ "@highstate/api": "^0.9.19",
27
+ "@highstate/contract": "^0.9.19",
27
28
  "long": "^5.3.2",
28
29
  "nice-grpc": "^2.1.12",
29
30
  "nice-grpc-common": "^2.0.2",
30
31
  "protobufjs": "^7.5.3"
31
32
  },
32
- "gitHead": "458d6f1f9f6d4aec0ba75a2b2c4c01408cb9c8df"
33
+ "gitHead": "e77d292335556c6e5b6275acda1a3d1609d786a1"
33
34
  }
package/src/index.ts CHANGED
@@ -1,53 +1,73 @@
1
1
  import { EventEmitter } from "node:events"
2
2
  import { createInterface } from "node:readline/promises"
3
+ import { createAuthenticationMiddleware } from "@highstate/api"
3
4
  import { WorkerServiceDefinition } from "@highstate/api/worker.v1"
4
5
  import {
5
- Channel,
6
- createChannel,
7
- createClientFactory,
6
+ type CommonObjectMeta,
7
+ type ServiceAccountMeta,
8
+ type WorkerRunOptions,
9
+ workerRunOptionsSchema,
10
+ type z,
11
+ } from "@highstate/contract"
12
+ import {
13
+ type Channel,
8
14
  type ClientFactory,
9
15
  type CompatServiceDefinition,
16
+ createChannel,
17
+ createClientFactory,
10
18
  } from "nice-grpc"
11
- import { createAuthenticationMiddleware } from "@highstate/api"
12
19
 
13
- export class Worker<TParams extends Record<string, unknown> = Record<string, unknown>> {
20
+ export type RegistrationHandler<TParamsSchema extends z.ZodType> = (
21
+ instanceId: string,
22
+ params: z.infer<TParamsSchema>,
23
+ ) => Promise<void> | void
24
+
25
+ export type DeregistrationHandler = (instanceId: string) => Promise<void> | void
26
+
27
+ export type WorkerOptions<TParamsSchema extends z.ZodType = z.ZodType> = {
28
+ workerMeta: CommonObjectMeta
29
+ serviceAccountMeta: ServiceAccountMeta
30
+ paramsSchema: TParamsSchema
31
+ }
32
+
33
+ export class Worker<TParamsSchema extends z.ZodType> {
14
34
  private readonly eventEmitter = new EventEmitter()
15
35
  private readonly clientFactory: ClientFactory
16
36
  private readonly channel: Channel
17
37
 
18
38
  private constructor(
19
- projectId: string,
20
- private readonly workerId: string,
21
- apiKey: string,
22
- apiUrl: string,
39
+ private readonly options: WorkerOptions<TParamsSchema>,
40
+ private readonly runOptions: WorkerRunOptions,
23
41
  ) {
24
- const authMiddleware = createAuthenticationMiddleware(apiKey, projectId)
42
+ const authMiddleware = createAuthenticationMiddleware(runOptions.apiKey, runOptions.projectId)
25
43
 
26
44
  this.clientFactory = createClientFactory().use(authMiddleware)
27
- this.channel = createChannel(apiUrl)
45
+ this.channel = createChannel(runOptions.apiUrl)
28
46
  }
29
47
 
30
- onUnitRegistration(handler: (instanceId: string, params: TParams) => Promise<void> | void) {
31
- const handle = async (instanceId: string, params: TParams) => {
48
+ onUnitRegistration(handler: RegistrationHandler<TParamsSchema>) {
49
+ const handle = async (stateId: string, params: unknown) => {
32
50
  try {
33
- await handler(instanceId, params)
51
+ const parsedParams = this.options.paramsSchema.parse(params)
52
+
53
+ await handler(stateId, parsedParams)
34
54
  } catch (error) {
35
- console.error(`Error handling unit registration for instance ${instanceId}:`, error)
55
+ console.error(`Error handling unit registration for instance ${stateId}:`, error)
36
56
  }
37
57
  }
38
58
 
39
59
  this.eventEmitter.on(
40
60
  "unitRegistration",
41
- (instanceId: string, params: TParams) => void handle(instanceId, params),
61
+ (instanceId: string, params: TParamsSchema) => void handle(instanceId, params),
42
62
  )
43
63
  }
44
64
 
45
- onUnitDeregistration(handler: (instanceId: string) => Promise<void> | void) {
46
- const handle = async (instanceId: string) => {
65
+ onUnitDeregistration(handler: DeregistrationHandler) {
66
+ const handle = async (stateId: string) => {
47
67
  try {
48
- await handler(instanceId)
68
+ await handler(stateId)
49
69
  } catch (error) {
50
- console.error(`Error handling unit deregistration for instance ${instanceId}:`, error)
70
+ console.error(`Error handling unit deregistration for instance ${stateId}:`, error)
51
71
  }
52
72
  }
53
73
 
@@ -61,53 +81,62 @@ export class Worker<TParams extends Record<string, unknown> = Record<string, unk
61
81
  async start(): Promise<void> {
62
82
  const workerClient = this.createClient(WorkerServiceDefinition)
63
83
 
64
- for await (const { event } of workerClient.connect({ workerId: this.workerId })) {
84
+ await workerClient.updateWorkerVersionMeta({
85
+ workerVersionId: this.runOptions.workerVersionId,
86
+ meta: this.options,
87
+ })
88
+
89
+ for await (const { event } of workerClient.connect({
90
+ workerVersionId: this.runOptions.workerVersionId,
91
+ })) {
65
92
  switch (event?.$case) {
66
93
  case "unitRegistration": {
67
94
  this.eventEmitter.emit(
68
95
  "unitRegistration",
69
- event.value.instanceId,
70
- event.value.params as TParams,
96
+ event.value.stateId,
97
+ event.value.params as TParamsSchema,
71
98
  )
72
99
  break
73
100
  }
74
101
  case "unitDeregistration": {
75
- this.eventEmitter.emit("unitDeregistration", event.value.instanceId)
102
+ this.eventEmitter.emit("unitDeregistration", event.value.stateId)
76
103
  break
77
104
  }
78
105
  }
79
106
  }
80
107
  }
81
108
 
82
- static async create<TParams extends Record<string, unknown> = Record<string, unknown>>(): Promise<
83
- Worker<TParams>
84
- > {
109
+ /**
110
+ * Creates a new worker and connects it to the Highstate platform.
111
+ *
112
+ * @param metadata The metadata of the worker version to update.
113
+ * @param paramsSchema The Zod schema of the parameters accepted by the worker on each unit registration.
114
+ */
115
+ static async create<TParamsSchema extends z.ZodType>(
116
+ options: WorkerOptions<TParamsSchema>,
117
+ ): Promise<Worker<TParamsSchema>> {
118
+ let runOptionsJson: unknown
85
119
  for await (const line of createInterface({ input: process.stdin })) {
86
- let data: Record<string, unknown>
87
120
  try {
88
- data = JSON.parse(line) as Record<string, unknown>
121
+ runOptionsJson = JSON.parse(line)
89
122
  } catch (error) {
90
- throw new Error("Failed to parse worker input", { cause: error })
123
+ throw new Error("Failed to parse worker run options", { cause: error })
91
124
  }
92
125
 
93
- if (!data.apiKey || !data.apiUrl || !data.projectId || !data.workerId) {
94
- throw new Error(
95
- "Worker input must contain apiKey, apiUrl, projectId, and workerId properties",
96
- )
97
- }
126
+ break
127
+ }
98
128
 
99
- if (
100
- typeof data.apiKey !== "string" ||
101
- typeof data.apiUrl !== "string" ||
102
- typeof data.projectId !== "string" ||
103
- typeof data.workerId !== "string"
104
- ) {
105
- throw new Error("Worker input properties must be strings")
106
- }
129
+ if (!runOptionsJson) {
130
+ throw new Error("No worker run options provided")
131
+ }
107
132
 
108
- return new Worker<TParams>(data.projectId, data.workerId, data.apiKey, data.apiUrl)
133
+ let runOptions: WorkerRunOptions
134
+ try {
135
+ runOptions = workerRunOptionsSchema.parse(runOptionsJson)
136
+ } catch (error) {
137
+ throw new Error("Invalid worker run options", { cause: error })
109
138
  }
110
139
 
111
- throw new Error("Failed to read worker input from stdin")
140
+ return new Worker(options, runOptions)
112
141
  }
113
142
  }