@highstate/backend-api 0.21.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/highstate.manifest.json +1 -1
- package/dist/index.js +66 -37
- package/package.json +5 -5
- package/src/handlers/panel.ts +28 -0
- package/src/handlers/worker.ts +44 -37
- package/src/index.ts +3 -1
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// src/index.ts
|
|
3
3
|
import { rm } from "fs/promises";
|
|
4
4
|
import { InstanceServiceDefinition } from "@highstate/api/instance.v1";
|
|
5
|
+
import { PanelServiceDefinition } from "@highstate/api/panel.v1";
|
|
5
6
|
import { SecretServiceDefinition } from "@highstate/api/secret.v1";
|
|
6
7
|
import { WorkerServiceDefinition } from "@highstate/api/worker.v1";
|
|
7
8
|
import { createServer } from "nice-grpc";
|
|
@@ -73,6 +74,23 @@ function createInstanceService(services) {
|
|
|
73
74
|
};
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
// src/handlers/panel.ts
|
|
78
|
+
import { panelInputSchema } from "@highstate/backend/shared";
|
|
79
|
+
import { z as z2 } from "@highstate/contract";
|
|
80
|
+
function createPanelService(services) {
|
|
81
|
+
return {
|
|
82
|
+
async setUnitPanels(request, context) {
|
|
83
|
+
const [projectId, apiKey] = await authenticate(services, context);
|
|
84
|
+
const workerVersionId = parseArgument(request, "workerVersionId", z2.cuid2());
|
|
85
|
+
const workerInstanceId = parseArgument(request, "workerInstanceId", z2.cuid2());
|
|
86
|
+
const stateId = parseArgument(request, "stateId", z2.cuid2());
|
|
87
|
+
const panels = parseArgument(request, "panels", z2.array(panelInputSchema));
|
|
88
|
+
const panelIds = await services.panelService.setUnitPanels(projectId, stateId, apiKey.id, workerVersionId, panels, workerInstanceId);
|
|
89
|
+
return { panelIds };
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
76
94
|
// src/handlers/secret.ts
|
|
77
95
|
function createSecretService(services) {
|
|
78
96
|
return {
|
|
@@ -84,10 +102,10 @@ function createSecretService(services) {
|
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
// src/handlers/worker.ts
|
|
87
|
-
import { commonObjectMetaSchema, serviceAccountMetaSchema, z as
|
|
88
|
-
var workerMetaUpdatePayloadSchema =
|
|
105
|
+
import { commonObjectMetaSchema, serviceAccountMetaSchema, z as z3 } from "@highstate/contract";
|
|
106
|
+
var workerMetaUpdatePayloadSchema = z3.union([
|
|
89
107
|
commonObjectMetaSchema,
|
|
90
|
-
|
|
108
|
+
z3.object({
|
|
91
109
|
workerMeta: commonObjectMetaSchema,
|
|
92
110
|
serviceAccountMeta: serviceAccountMetaSchema
|
|
93
111
|
})
|
|
@@ -95,56 +113,66 @@ var workerMetaUpdatePayloadSchema = z2.union([
|
|
|
95
113
|
function createWorkerService(services) {
|
|
96
114
|
return {
|
|
97
115
|
async* connect(request, context) {
|
|
98
|
-
const [projectId] = await authenticate(services, context);
|
|
99
|
-
const workerVersionId = parseArgument(request, "workerVersionId",
|
|
100
|
-
|
|
116
|
+
const [projectId, apiKey] = await authenticate(services, context);
|
|
117
|
+
const workerVersionId = parseArgument(request, "workerVersionId", z3.cuid2());
|
|
118
|
+
const workerInstanceId = parseArgument(request, "workerInstanceId", z3.cuid2());
|
|
119
|
+
const dataEndpoint = parseArgument(request, "dataEndpoint", z3.string().min(1));
|
|
101
120
|
const database = await services.database.forProject(projectId);
|
|
102
|
-
const
|
|
103
|
-
where: { workerVersionId },
|
|
104
|
-
select: {
|
|
121
|
+
const workerVersion = await database.workerVersion.findFirst({
|
|
122
|
+
where: { id: workerVersionId, apiKeyId: apiKey.id },
|
|
123
|
+
select: { id: true }
|
|
105
124
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
event: {
|
|
109
|
-
$case: "unitRegistration",
|
|
110
|
-
value: {
|
|
111
|
-
stateId: registration.stateId,
|
|
112
|
-
params: registration.params
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
};
|
|
125
|
+
if (!workerVersion) {
|
|
126
|
+
throw new Error(`Worker version "${workerVersionId}" is not owned by the API key`);
|
|
116
127
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
workerVersionId
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
services.workerManager.assertWorkerInstance(projectId, workerVersionId, workerInstanceId);
|
|
129
|
+
services.panelEndpointManager.connect(projectId, workerVersionId, workerInstanceId, dataEndpoint);
|
|
130
|
+
try {
|
|
131
|
+
await services.workerManager.setWorkerRunning(projectId, workerVersionId, workerInstanceId);
|
|
132
|
+
const existingRegistrations = await database.workerUnitRegistration.findMany({
|
|
133
|
+
where: { workerVersionId },
|
|
134
|
+
select: { stateId: true, params: true }
|
|
135
|
+
});
|
|
136
|
+
for (const registration of existingRegistrations) {
|
|
124
137
|
yield {
|
|
125
138
|
event: {
|
|
126
139
|
$case: "unitRegistration",
|
|
127
140
|
value: {
|
|
128
|
-
|
|
129
|
-
params:
|
|
141
|
+
stateId: registration.stateId,
|
|
142
|
+
params: registration.params
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
145
|
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
146
|
+
}
|
|
147
|
+
const registrationStream = await services.pubsubManager.subscribe([
|
|
148
|
+
"worker-unit-registration",
|
|
149
|
+
projectId,
|
|
150
|
+
workerVersionId
|
|
151
|
+
]);
|
|
152
|
+
for await (const event of registrationStream) {
|
|
153
|
+
if (event.type === "registered") {
|
|
154
|
+
yield {
|
|
155
|
+
event: {
|
|
156
|
+
$case: "unitRegistration",
|
|
157
|
+
value: { stateId: event.stateId, params: event.params }
|
|
139
158
|
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
159
|
+
};
|
|
160
|
+
} else if (event.type === "deregistered") {
|
|
161
|
+
yield {
|
|
162
|
+
event: {
|
|
163
|
+
$case: "unitDeregistration",
|
|
164
|
+
value: { stateId: event.stateId }
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
142
168
|
}
|
|
169
|
+
} finally {
|
|
170
|
+
services.panelEndpointManager.disconnect(workerInstanceId);
|
|
143
171
|
}
|
|
144
172
|
},
|
|
145
173
|
async updateWorkerVersionMeta(request, context) {
|
|
146
174
|
const [projectId] = await authenticate(services, context);
|
|
147
|
-
const workerVersionId = parseArgument(request, "workerVersionId",
|
|
175
|
+
const workerVersionId = parseArgument(request, "workerVersionId", z3.string());
|
|
148
176
|
const payload = parseArgument(request, "meta", workerMetaUpdatePayloadSchema);
|
|
149
177
|
const workerMeta = "workerMeta" in payload ? payload.workerMeta : payload;
|
|
150
178
|
const serviceAccountMeta = "serviceAccountMeta" in payload ? payload.serviceAccountMeta : undefined;
|
|
@@ -159,6 +187,7 @@ async function startBackedApi(services) {
|
|
|
159
187
|
const server = createServer();
|
|
160
188
|
server.use(createErrorHandlingMiddleware(services));
|
|
161
189
|
server.add(InstanceServiceDefinition, createInstanceService(services));
|
|
190
|
+
server.add(PanelServiceDefinition, createPanelService(services));
|
|
162
191
|
server.add(SecretServiceDefinition, createSecretService(services));
|
|
163
192
|
server.add(WorkerServiceDefinition, createWorkerService(services));
|
|
164
193
|
const uid = process.geteuid?.();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@highstate/backend-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@bufbuild/protobuf": "^2.6.1",
|
|
44
|
-
"@highstate/api": "0.
|
|
45
|
-
"@highstate/backend": "0.
|
|
46
|
-
"@highstate/cli": "0.
|
|
47
|
-
"@highstate/contract": "0.
|
|
44
|
+
"@highstate/api": "0.25.0",
|
|
45
|
+
"@highstate/backend": "0.25.0",
|
|
46
|
+
"@highstate/cli": "0.25.0",
|
|
47
|
+
"@highstate/contract": "0.25.0",
|
|
48
48
|
"abort-controller-x": "^0.4.3",
|
|
49
49
|
"nice-grpc": "^2.1.12",
|
|
50
50
|
"nice-grpc-common": "^2.0.2",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PanelServiceImplementation } from "@highstate/api/panel.v1"
|
|
2
|
+
import type { Services } from "@highstate/backend"
|
|
3
|
+
import { panelInputSchema } from "@highstate/backend/shared"
|
|
4
|
+
import { z } from "@highstate/contract"
|
|
5
|
+
import { authenticate, parseArgument } from "../shared"
|
|
6
|
+
|
|
7
|
+
export function createPanelService(services: Services): PanelServiceImplementation {
|
|
8
|
+
return {
|
|
9
|
+
async setUnitPanels(request, context) {
|
|
10
|
+
const [projectId, apiKey] = await authenticate(services, context)
|
|
11
|
+
const workerVersionId = parseArgument(request, "workerVersionId", z.cuid2())
|
|
12
|
+
const workerInstanceId = parseArgument(request, "workerInstanceId", z.cuid2())
|
|
13
|
+
const stateId = parseArgument(request, "stateId", z.cuid2())
|
|
14
|
+
const panels = parseArgument(request, "panels", z.array(panelInputSchema))
|
|
15
|
+
|
|
16
|
+
const panelIds = await services.panelService.setUnitPanels(
|
|
17
|
+
projectId,
|
|
18
|
+
stateId,
|
|
19
|
+
apiKey.id,
|
|
20
|
+
workerVersionId,
|
|
21
|
+
panels,
|
|
22
|
+
workerInstanceId,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
return { panelIds }
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/handlers/worker.ts
CHANGED
|
@@ -14,62 +14,69 @@ const workerMetaUpdatePayloadSchema = z.union([
|
|
|
14
14
|
export function createWorkerService(services: Services): WorkerServiceImplementation {
|
|
15
15
|
return {
|
|
16
16
|
async *connect(request, context) {
|
|
17
|
-
const [projectId] = await authenticate(services, context)
|
|
17
|
+
const [projectId, apiKey] = await authenticate(services, context)
|
|
18
18
|
|
|
19
19
|
const workerVersionId = parseArgument(request, "workerVersionId", z.cuid2())
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
services.workerManager.setWorkerRunning(projectId, workerVersionId)
|
|
23
|
-
|
|
24
|
-
// get existing registrations for this worker version
|
|
20
|
+
const workerInstanceId = parseArgument(request, "workerInstanceId", z.cuid2())
|
|
21
|
+
const dataEndpoint = parseArgument(request, "dataEndpoint", z.string().min(1))
|
|
25
22
|
const database = await services.database.forProject(projectId)
|
|
26
|
-
const
|
|
27
|
-
where: { workerVersionId },
|
|
28
|
-
select: {
|
|
23
|
+
const workerVersion = await database.workerVersion.findFirst({
|
|
24
|
+
where: { id: workerVersionId, apiKeyId: apiKey.id },
|
|
25
|
+
select: { id: true },
|
|
29
26
|
})
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
for (const registration of existingRegistrations) {
|
|
33
|
-
yield {
|
|
34
|
-
event: {
|
|
35
|
-
$case: "unitRegistration",
|
|
36
|
-
value: {
|
|
37
|
-
stateId: registration.stateId,
|
|
38
|
-
params: registration.params,
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
}
|
|
27
|
+
if (!workerVersion) {
|
|
28
|
+
throw new Error(`Worker version "${workerVersionId}" is not owned by the API key`)
|
|
42
29
|
}
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"worker-unit-registration",
|
|
31
|
+
services.workerManager.assertWorkerInstance(projectId, workerVersionId, workerInstanceId)
|
|
32
|
+
services.panelEndpointManager.connect(
|
|
47
33
|
projectId,
|
|
48
34
|
workerVersionId,
|
|
49
|
-
|
|
35
|
+
workerInstanceId,
|
|
36
|
+
dataEndpoint,
|
|
37
|
+
)
|
|
50
38
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
try {
|
|
40
|
+
await services.workerManager.setWorkerRunning(projectId, workerVersionId, workerInstanceId)
|
|
41
|
+
const existingRegistrations = await database.workerUnitRegistration.findMany({
|
|
42
|
+
where: { workerVersionId },
|
|
43
|
+
select: { stateId: true, params: true },
|
|
44
|
+
})
|
|
45
|
+
for (const registration of existingRegistrations) {
|
|
54
46
|
yield {
|
|
55
47
|
event: {
|
|
56
48
|
$case: "unitRegistration",
|
|
57
49
|
value: {
|
|
58
|
-
|
|
59
|
-
params:
|
|
50
|
+
stateId: registration.stateId,
|
|
51
|
+
params: registration.params,
|
|
60
52
|
},
|
|
61
53
|
},
|
|
62
54
|
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
}
|
|
56
|
+
const registrationStream = await services.pubsubManager.subscribe([
|
|
57
|
+
"worker-unit-registration",
|
|
58
|
+
projectId,
|
|
59
|
+
workerVersionId,
|
|
60
|
+
])
|
|
61
|
+
for await (const event of registrationStream) {
|
|
62
|
+
if (event.type === "registered") {
|
|
63
|
+
yield {
|
|
64
|
+
event: {
|
|
65
|
+
$case: "unitRegistration",
|
|
66
|
+
value: { stateId: event.stateId, params: event.params },
|
|
69
67
|
},
|
|
70
|
-
}
|
|
68
|
+
}
|
|
69
|
+
} else if (event.type === "deregistered") {
|
|
70
|
+
yield {
|
|
71
|
+
event: {
|
|
72
|
+
$case: "unitDeregistration",
|
|
73
|
+
value: { stateId: event.stateId },
|
|
74
|
+
},
|
|
75
|
+
}
|
|
71
76
|
}
|
|
72
77
|
}
|
|
78
|
+
} finally {
|
|
79
|
+
services.panelEndpointManager.disconnect(workerInstanceId)
|
|
73
80
|
}
|
|
74
81
|
},
|
|
75
82
|
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Services } from "@highstate/backend"
|
|
2
2
|
import { rm } from "node:fs/promises"
|
|
3
3
|
import { InstanceServiceDefinition } from "@highstate/api/instance.v1"
|
|
4
|
+
import { PanelServiceDefinition } from "@highstate/api/panel.v1"
|
|
4
5
|
import { SecretServiceDefinition } from "@highstate/api/secret.v1"
|
|
5
6
|
import { WorkerServiceDefinition } from "@highstate/api/worker.v1"
|
|
6
7
|
import { createServer } from "nice-grpc"
|
|
7
8
|
import { createInstanceService } from "./handlers/instance"
|
|
9
|
+
import { createPanelService } from "./handlers/panel"
|
|
8
10
|
import { createSecretService } from "./handlers/secret"
|
|
9
11
|
import { createWorkerService } from "./handlers/worker"
|
|
10
12
|
import { createErrorHandlingMiddleware } from "./shared"
|
|
@@ -14,6 +16,7 @@ export async function startBackedApi(services: Services) {
|
|
|
14
16
|
server.use(createErrorHandlingMiddleware(services))
|
|
15
17
|
|
|
16
18
|
server.add(InstanceServiceDefinition, createInstanceService(services))
|
|
19
|
+
server.add(PanelServiceDefinition, createPanelService(services))
|
|
17
20
|
server.add(SecretServiceDefinition, createSecretService(services))
|
|
18
21
|
server.add(WorkerServiceDefinition, createWorkerService(services))
|
|
19
22
|
|
|
@@ -29,7 +32,6 @@ export async function startBackedApi(services: Services) {
|
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
await server.listen(`unix:${sockPath}`)
|
|
32
|
-
|
|
33
35
|
services.workerManager.config.HIGHSTATE_WORKER_API_PATH = sockPath
|
|
34
36
|
services.logger.info(`api listening at %s`, sockPath)
|
|
35
37
|
}
|