@highstate/backend-api 0.27.0 → 0.29.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 +1202 -93
- package/package.json +12 -10
- package/src/handlers/instance-state.ts +96 -0
- package/src/handlers/library.ts +63 -0
- package/src/handlers/operation.ts +108 -0
- package/src/handlers/panel.ts +7 -6
- package/src/handlers/project-model.ts +131 -0
- package/src/handlers/project.ts +46 -0
- package/src/handlers/secret.ts +6 -5
- package/src/handlers/worker.ts +29 -32
- package/src/index.ts +125 -19
- package/src/shared/api-error.ts +42 -0
- package/src/shared/authentication.ts +172 -12
- package/src/shared/authorization-header.test.ts +36 -0
- package/src/shared/authorization-header.ts +24 -0
- package/src/shared/conversion.test.ts +122 -0
- package/src/shared/conversion.ts +593 -0
- package/src/shared/error-handling.test.ts +138 -0
- package/src/shared/error-handling.ts +127 -14
- package/src/shared/field-mask.test.ts +37 -0
- package/src/shared/field-mask.ts +81 -0
- package/src/shared/index.ts +5 -0
- package/src/shared/serialization.test.ts +17 -0
- package/src/shared/serialization.ts +35 -0
- package/src/shared/validation.ts +45 -5
- package/src/handlers/instance.ts +0 -44
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InstanceState as BackendInstanceState,
|
|
3
|
+
Operation as BackendOperation,
|
|
4
|
+
OperationPhase as BackendOperationPhase,
|
|
5
|
+
FullProjectModel as BackendProjectModel,
|
|
6
|
+
ProjectOutput,
|
|
7
|
+
} from "@highstate/backend/shared"
|
|
8
|
+
import { create, fromJson, type JsonValue, toJson } from "@bufbuild/protobuf"
|
|
9
|
+
import { type Timestamp, timestampFromDate, ValueSchema } from "@bufbuild/protobuf/wkt"
|
|
10
|
+
import {
|
|
11
|
+
type Component,
|
|
12
|
+
ComponentKind,
|
|
13
|
+
ComponentSchema,
|
|
14
|
+
type Entity,
|
|
15
|
+
EntitySchema,
|
|
16
|
+
EvaluationStatus,
|
|
17
|
+
type Hub,
|
|
18
|
+
HubSchema,
|
|
19
|
+
type Instance,
|
|
20
|
+
type InstanceCustomStatus,
|
|
21
|
+
InstanceCustomStatusSchema,
|
|
22
|
+
InstanceOperationStatus,
|
|
23
|
+
InstanceSchema,
|
|
24
|
+
InstanceSource,
|
|
25
|
+
type InstanceState,
|
|
26
|
+
InstanceStateSchema,
|
|
27
|
+
InstanceStatus,
|
|
28
|
+
type Library,
|
|
29
|
+
LibrarySchema,
|
|
30
|
+
type Operation,
|
|
31
|
+
type OperationLog,
|
|
32
|
+
OperationLogSchema,
|
|
33
|
+
type OperationPhase,
|
|
34
|
+
OperationPhaseSchema,
|
|
35
|
+
OperationPhaseType,
|
|
36
|
+
OperationSchema,
|
|
37
|
+
OperationStatus,
|
|
38
|
+
OperationType,
|
|
39
|
+
type Project,
|
|
40
|
+
type ProjectModel,
|
|
41
|
+
ProjectModelSchema,
|
|
42
|
+
ProjectSchema,
|
|
43
|
+
} from "@highstate/api/v1"
|
|
44
|
+
import {
|
|
45
|
+
instanceCustomStatusInputSchema,
|
|
46
|
+
operationMetaSchema,
|
|
47
|
+
operationOptionsSchema,
|
|
48
|
+
operationPhaseSchema,
|
|
49
|
+
} from "@highstate/backend/shared"
|
|
50
|
+
import {
|
|
51
|
+
type ComponentModel,
|
|
52
|
+
type EntityModel,
|
|
53
|
+
type HubModel,
|
|
54
|
+
type HubModelPatch,
|
|
55
|
+
type InstanceModel,
|
|
56
|
+
type InstanceModelPatch,
|
|
57
|
+
instanceInputSchema,
|
|
58
|
+
instanceModelSchema,
|
|
59
|
+
z,
|
|
60
|
+
} from "@highstate/contract"
|
|
61
|
+
|
|
62
|
+
const jsonValueSchema: z.ZodType<JsonValue> = z.lazy(() =>
|
|
63
|
+
z.union([
|
|
64
|
+
z.string(),
|
|
65
|
+
z.number(),
|
|
66
|
+
z.boolean(),
|
|
67
|
+
z.null(),
|
|
68
|
+
z.array(jsonValueSchema),
|
|
69
|
+
z.record(z.string(), jsonValueSchema),
|
|
70
|
+
]),
|
|
71
|
+
)
|
|
72
|
+
const jsonObjectSchema = z.record(z.string(), jsonValueSchema)
|
|
73
|
+
|
|
74
|
+
export function toProject(project: ProjectOutput): Project {
|
|
75
|
+
return create(ProjectSchema, {
|
|
76
|
+
id: project.id,
|
|
77
|
+
name: project.name,
|
|
78
|
+
meta: project.meta,
|
|
79
|
+
spaceId: project.spaceId,
|
|
80
|
+
modelStorageId: project.modelStorageId,
|
|
81
|
+
libraryId: project.libraryId,
|
|
82
|
+
pulumiBackendId: project.pulumiBackendId,
|
|
83
|
+
createdAt: toTimestamp(project.createdAt),
|
|
84
|
+
updatedAt: toTimestamp(project.updatedAt),
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function toProjectModel(model: BackendProjectModel): ProjectModel {
|
|
89
|
+
return create(ProjectModelSchema, {
|
|
90
|
+
instances: [...model.instances, ...model.virtualInstances, ...model.ghostInstances].map(
|
|
91
|
+
toInstance,
|
|
92
|
+
),
|
|
93
|
+
hubs: model.hubs.map(toHub),
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function toInstance(instance: InstanceModel): Instance {
|
|
98
|
+
return create(InstanceSchema, {
|
|
99
|
+
id: instance.id,
|
|
100
|
+
kind: toComponentKind(instance.kind),
|
|
101
|
+
type: instance.type,
|
|
102
|
+
name: instance.name,
|
|
103
|
+
arguments: Object.entries(instance.args ?? {}).map(([key, value]) => ({
|
|
104
|
+
key,
|
|
105
|
+
value: fromJson(ValueSchema, value as JsonValue),
|
|
106
|
+
})),
|
|
107
|
+
inputs: toInstanceReferenceMap(instance.inputs),
|
|
108
|
+
hubInputs: Object.fromEntries(
|
|
109
|
+
Object.entries(instance.hubInputs ?? {}).map(([key, values]) => [
|
|
110
|
+
key,
|
|
111
|
+
{ values: values.map(value => ({ hubId: value.hubId })) },
|
|
112
|
+
]),
|
|
113
|
+
),
|
|
114
|
+
injectionInputs: (instance.injectionInputs ?? []).map(value => ({ hubId: value.hubId })),
|
|
115
|
+
position: instance.position ?? undefined,
|
|
116
|
+
parentId: instance.parentId,
|
|
117
|
+
outputs: toInstanceReferenceMap(instance.outputs),
|
|
118
|
+
resolvedOutputs: toInstanceReferenceMap(instance.resolvedOutputs),
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function fromInstance(instance: Instance): InstanceModel {
|
|
123
|
+
return instanceModelSchema.parse({
|
|
124
|
+
id: instance.id,
|
|
125
|
+
kind: fromComponentKind(instance.kind),
|
|
126
|
+
type: instance.type,
|
|
127
|
+
name: instance.name,
|
|
128
|
+
args: Object.fromEntries(
|
|
129
|
+
instance.arguments.map(argument => [
|
|
130
|
+
argument.key,
|
|
131
|
+
argument.value ? toJson(ValueSchema, argument.value) : null,
|
|
132
|
+
]),
|
|
133
|
+
),
|
|
134
|
+
inputs: fromInstanceReferenceMap(instance.inputs),
|
|
135
|
+
hubInputs: Object.fromEntries(
|
|
136
|
+
Object.entries(instance.hubInputs).map(([key, list]) => [
|
|
137
|
+
key,
|
|
138
|
+
list.values.map(value => ({ hubId: value.hubId })),
|
|
139
|
+
]),
|
|
140
|
+
),
|
|
141
|
+
injectionInputs: instance.injectionInputs.map(value => ({ hubId: value.hubId })),
|
|
142
|
+
position: instance.position,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function toHub(hub: HubModel): Hub {
|
|
147
|
+
return create(HubSchema, {
|
|
148
|
+
id: hub.id,
|
|
149
|
+
position: hub.position ?? undefined,
|
|
150
|
+
inputs: hub.inputs ?? [],
|
|
151
|
+
injectionInputs: (hub.injectionInputs ?? []).map(value => ({ hubId: value.hubId })),
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function fromHub(hub: Hub): HubModel {
|
|
156
|
+
return {
|
|
157
|
+
id: hub.id,
|
|
158
|
+
position: hub.position,
|
|
159
|
+
inputs: hub.inputs.map(fromInstanceReference),
|
|
160
|
+
injectionInputs: hub.injectionInputs.map(value => ({ hubId: value.hubId })),
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function toInstancePatch(instance: Instance, paths: readonly string[]): InstanceModelPatch {
|
|
165
|
+
const patch: InstanceModelPatch = {}
|
|
166
|
+
|
|
167
|
+
for (const path of paths) {
|
|
168
|
+
switch (path) {
|
|
169
|
+
case "arguments":
|
|
170
|
+
patch.args = Object.fromEntries(
|
|
171
|
+
instance.arguments.map(argument => [
|
|
172
|
+
argument.key,
|
|
173
|
+
argument.value ? toJson(ValueSchema, argument.value) : null,
|
|
174
|
+
]),
|
|
175
|
+
)
|
|
176
|
+
break
|
|
177
|
+
case "inputs":
|
|
178
|
+
patch.inputs = fromInstanceReferenceMap(instance.inputs)
|
|
179
|
+
break
|
|
180
|
+
case "hub_inputs":
|
|
181
|
+
patch.hubInputs = Object.fromEntries(
|
|
182
|
+
Object.entries(instance.hubInputs).map(([key, list]) => [
|
|
183
|
+
key,
|
|
184
|
+
list.values.map(value => ({ hubId: value.hubId })),
|
|
185
|
+
]),
|
|
186
|
+
)
|
|
187
|
+
break
|
|
188
|
+
case "injection_inputs":
|
|
189
|
+
patch.injectionInputs = instance.injectionInputs.map(value => ({ hubId: value.hubId }))
|
|
190
|
+
break
|
|
191
|
+
case "position":
|
|
192
|
+
patch.position = instance.position
|
|
193
|
+
? { x: instance.position.x, y: instance.position.y }
|
|
194
|
+
: null
|
|
195
|
+
break
|
|
196
|
+
case "position.x":
|
|
197
|
+
patch.position = { x: instance.position?.x ?? 0 }
|
|
198
|
+
break
|
|
199
|
+
case "position.y":
|
|
200
|
+
patch.position = { y: instance.position?.y ?? 0 }
|
|
201
|
+
break
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return patch
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function toHubPatch(hub: Hub, paths: readonly string[]): HubModelPatch {
|
|
209
|
+
const patch: HubModelPatch = {}
|
|
210
|
+
|
|
211
|
+
for (const path of paths) {
|
|
212
|
+
switch (path) {
|
|
213
|
+
case "position":
|
|
214
|
+
patch.position = hub.position ? { x: hub.position.x, y: hub.position.y } : null
|
|
215
|
+
break
|
|
216
|
+
case "position.x":
|
|
217
|
+
patch.position = { x: hub.position?.x ?? 0 }
|
|
218
|
+
break
|
|
219
|
+
case "position.y":
|
|
220
|
+
patch.position = { y: hub.position?.y ?? 0 }
|
|
221
|
+
break
|
|
222
|
+
case "inputs":
|
|
223
|
+
patch.inputs = hub.inputs.map(fromInstanceReference)
|
|
224
|
+
break
|
|
225
|
+
case "injection_inputs":
|
|
226
|
+
patch.injectionInputs = hub.injectionInputs.map(value => ({ hubId: value.hubId }))
|
|
227
|
+
break
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return patch
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function toInstanceState(state: BackendInstanceState): InstanceState {
|
|
235
|
+
const model = state.model ? instanceModelSchema.parse(state.model) : undefined
|
|
236
|
+
|
|
237
|
+
return create(InstanceStateSchema, {
|
|
238
|
+
id: state.id,
|
|
239
|
+
instanceId: state.instanceId,
|
|
240
|
+
status: toInstanceStatus(state.status),
|
|
241
|
+
source: toInstanceSource(state.source),
|
|
242
|
+
kind: toComponentKind(state.kind),
|
|
243
|
+
parentInstanceId: state.parentInstanceId ?? undefined,
|
|
244
|
+
evaluationState: state.evaluationState
|
|
245
|
+
? {
|
|
246
|
+
status: toEvaluationStatus(state.evaluationState.status),
|
|
247
|
+
message: state.evaluationState.message ?? undefined,
|
|
248
|
+
model: state.evaluationState.model
|
|
249
|
+
? toInstance(instanceModelSchema.parse(state.evaluationState.model))
|
|
250
|
+
: undefined,
|
|
251
|
+
evaluatedAt: toTimestamp(state.evaluationState.evaluatedAt),
|
|
252
|
+
}
|
|
253
|
+
: undefined,
|
|
254
|
+
lastOperationState: state.lastOperationState
|
|
255
|
+
? {
|
|
256
|
+
operationId: state.lastOperationState.operationId,
|
|
257
|
+
stateId: state.lastOperationState.stateId,
|
|
258
|
+
status: toInstanceOperationStatus(state.lastOperationState.status),
|
|
259
|
+
currentResourceCount: state.lastOperationState.currentResourceCount ?? undefined,
|
|
260
|
+
totalResourceCount: state.lastOperationState.totalResourceCount ?? undefined,
|
|
261
|
+
model: toInstance(instanceModelSchema.parse(state.lastOperationState.model)),
|
|
262
|
+
startedAt: toNullableTimestamp(state.lastOperationState.startedAt),
|
|
263
|
+
finishedAt: toNullableTimestamp(state.lastOperationState.finishedAt),
|
|
264
|
+
}
|
|
265
|
+
: undefined,
|
|
266
|
+
terminalIds: state.terminalIds ?? [],
|
|
267
|
+
pageIds: state.pageIds ?? [],
|
|
268
|
+
panelIds: state.panelIds ?? [],
|
|
269
|
+
secretNames: state.secretNames ?? [],
|
|
270
|
+
customStatuses: (state.customStatuses ?? []).map(toInstanceCustomStatus),
|
|
271
|
+
currentResourceCount: state.currentResourceCount ?? undefined,
|
|
272
|
+
hasResourceHooks: state.hasResourceHooks,
|
|
273
|
+
statusFields: state.statusFields
|
|
274
|
+
? fromJson(ValueSchema, jsonValueSchema.parse(state.statusFields))
|
|
275
|
+
: undefined,
|
|
276
|
+
model: model ? toInstance(model) : undefined,
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function toInstanceCustomStatus(
|
|
281
|
+
status: NonNullable<BackendInstanceState["customStatuses"]>[number],
|
|
282
|
+
): InstanceCustomStatus {
|
|
283
|
+
const meta = instanceCustomStatusInputSchema.shape.meta.parse(status.meta)
|
|
284
|
+
|
|
285
|
+
return create(InstanceCustomStatusSchema, {
|
|
286
|
+
name: status.name,
|
|
287
|
+
meta: {
|
|
288
|
+
title: meta.title ?? status.name,
|
|
289
|
+
description: meta.description,
|
|
290
|
+
icon: meta.icon,
|
|
291
|
+
iconColor: meta.iconColor,
|
|
292
|
+
},
|
|
293
|
+
value: status.value,
|
|
294
|
+
message: status.message ?? undefined,
|
|
295
|
+
order: status.order,
|
|
296
|
+
serviceAccountId: status.serviceAccountId,
|
|
297
|
+
createdAt: toTimestamp(status.createdAt),
|
|
298
|
+
updatedAt: toTimestamp(status.updatedAt),
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function toOperation(operation: BackendOperation): Operation {
|
|
303
|
+
const meta = operationMetaSchema.parse(operation.meta)
|
|
304
|
+
const options = operationOptionsSchema.partial().parse(operation.options)
|
|
305
|
+
const phases = operation.phases ? operationPhaseSchema.array().parse(operation.phases) : []
|
|
306
|
+
|
|
307
|
+
return create(OperationSchema, {
|
|
308
|
+
id: operation.id,
|
|
309
|
+
meta,
|
|
310
|
+
type: toOperationType(operation.type),
|
|
311
|
+
status: toOperationStatus(operation.status),
|
|
312
|
+
options: {
|
|
313
|
+
forceUpdateDependencies: options.forceUpdateDependencies ?? false,
|
|
314
|
+
ignoreChangedDependencies: options.ignoreChangedDependencies ?? false,
|
|
315
|
+
ignoreDependencies: options.ignoreDependencies ?? false,
|
|
316
|
+
forceUpdateChildren: options.forceUpdateChildren ?? false,
|
|
317
|
+
onlyDestroyGhosts: options.onlyDestroyGhosts ?? false,
|
|
318
|
+
firstDestroyGhosts: options.firstDestroyGhosts ?? false,
|
|
319
|
+
ignoreGhosts: options.ignoreGhosts ?? false,
|
|
320
|
+
destroyDependentInstances: options.destroyDependentInstances ?? false,
|
|
321
|
+
invokeDestroyTriggers: options.invokeDestroyTriggers ?? false,
|
|
322
|
+
deleteUnreachableResources: options.deleteUnreachableResources ?? false,
|
|
323
|
+
forceDeleteState: options.forceDeleteState ?? false,
|
|
324
|
+
allowPartialCompositeInstanceUpdate: options.allowPartialCompositeInstanceUpdate ?? false,
|
|
325
|
+
allowPartialCompositeInstanceDestruction:
|
|
326
|
+
options.allowPartialCompositeInstanceDestruction ?? false,
|
|
327
|
+
refresh: options.refresh ?? false,
|
|
328
|
+
debug: options.debug ?? false,
|
|
329
|
+
},
|
|
330
|
+
requestedInstanceIds: z.string().array().parse(operation.requestedInstanceIds),
|
|
331
|
+
phases: phases.map(toOperationPhase),
|
|
332
|
+
startedAt: toTimestamp(operation.startedAt),
|
|
333
|
+
updatedAt: toTimestamp(operation.updatedAt),
|
|
334
|
+
finishedAt: toNullableTimestamp(operation.finishedAt),
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function toOperationPhase(phase: BackendOperationPhase): OperationPhase {
|
|
339
|
+
return create(OperationPhaseSchema, {
|
|
340
|
+
type: toOperationPhaseType(phase.type),
|
|
341
|
+
instances: phase.instances,
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function toOperationLog(
|
|
346
|
+
operationId: string,
|
|
347
|
+
log: { id: string; stateId: string | null; content: string; isSystem?: boolean },
|
|
348
|
+
): OperationLog {
|
|
349
|
+
return create(OperationLogSchema, {
|
|
350
|
+
id: log.id,
|
|
351
|
+
operationId,
|
|
352
|
+
stateId: log.stateId ?? undefined,
|
|
353
|
+
isSystem: log.isSystem ?? false,
|
|
354
|
+
content: log.content,
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function toLibrary(library: {
|
|
359
|
+
components: Record<string, ComponentModel>
|
|
360
|
+
entities: Record<string, EntityModel>
|
|
361
|
+
}): Library {
|
|
362
|
+
return create(LibrarySchema, {
|
|
363
|
+
components: Object.fromEntries(
|
|
364
|
+
Object.entries(library.components).map(([type, component]) => [type, toComponent(component)]),
|
|
365
|
+
),
|
|
366
|
+
entities: Object.fromEntries(
|
|
367
|
+
Object.entries(library.entities).map(([type, entity]) => [type, toEntity(entity)]),
|
|
368
|
+
),
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export function toComponent(component: ComponentModel): Component {
|
|
373
|
+
try {
|
|
374
|
+
return create(ComponentSchema, {
|
|
375
|
+
type: component.type,
|
|
376
|
+
kind: toComponentKind(component.kind),
|
|
377
|
+
arguments: Object.fromEntries(
|
|
378
|
+
Object.entries(component.args).map(([name, argument]) => [
|
|
379
|
+
name,
|
|
380
|
+
{
|
|
381
|
+
schema: jsonObjectSchema.parse(argument.schema),
|
|
382
|
+
required: argument.required,
|
|
383
|
+
meta: argument.meta,
|
|
384
|
+
},
|
|
385
|
+
]),
|
|
386
|
+
),
|
|
387
|
+
inputs: Object.fromEntries(
|
|
388
|
+
Object.entries(component.inputs).map(([name, port]) => [name, toComponentPort(port)]),
|
|
389
|
+
),
|
|
390
|
+
outputs: Object.fromEntries(
|
|
391
|
+
Object.entries(component.outputs).map(([name, port]) => [name, toComponentPort(port)]),
|
|
392
|
+
),
|
|
393
|
+
meta: component.meta,
|
|
394
|
+
definitionHash: component.definitionHash,
|
|
395
|
+
})
|
|
396
|
+
} catch (error) {
|
|
397
|
+
throw new Error(`Failed to convert component "${component.type}" to an API message`, {
|
|
398
|
+
cause: error,
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export function toEntity(entity: EntityModel): Entity {
|
|
404
|
+
return create(EntitySchema, {
|
|
405
|
+
type: entity.type,
|
|
406
|
+
extensions: entity.extensions ?? [],
|
|
407
|
+
directExtensions: entity.directExtensions ?? [],
|
|
408
|
+
inclusions: entity.inclusions ?? [],
|
|
409
|
+
directInclusions: entity.directInclusions ?? [],
|
|
410
|
+
meta: entity.meta,
|
|
411
|
+
definitionHash: entity.definitionHash,
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export function toTimestamp(value: Date): Timestamp {
|
|
416
|
+
if (!Number.isFinite(value.getTime())) {
|
|
417
|
+
throw new Error("Cannot convert invalid date to timestamp")
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return timestampFromDate(value)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export function toNullableTimestamp(value: Date | null | undefined): Timestamp | undefined {
|
|
424
|
+
return value ? toTimestamp(value) : undefined
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function toComponentPort(port: ComponentModel["inputs"][string]) {
|
|
428
|
+
return {
|
|
429
|
+
entityType: port.type,
|
|
430
|
+
fromInput: port.fromInput,
|
|
431
|
+
required: port.required,
|
|
432
|
+
multiple: port.multiple,
|
|
433
|
+
meta: port.meta,
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function toInstanceReferenceMap(values?: InstanceModel["inputs"]) {
|
|
438
|
+
return Object.fromEntries(
|
|
439
|
+
Object.entries(values ?? {}).map(([key, references]) => [
|
|
440
|
+
key,
|
|
441
|
+
{
|
|
442
|
+
values: references,
|
|
443
|
+
},
|
|
444
|
+
]),
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function fromInstanceReferenceMap(
|
|
449
|
+
values: Instance["inputs"],
|
|
450
|
+
): NonNullable<InstanceModel["inputs"]> {
|
|
451
|
+
return Object.fromEntries(
|
|
452
|
+
Object.entries(values).map(([key, list]) => [key, list.values.map(fromInstanceReference)]),
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function fromInstanceReference(value: Instance["inputs"][string]["values"][number]) {
|
|
457
|
+
return instanceInputSchema.parse({
|
|
458
|
+
instanceId: value.instanceId,
|
|
459
|
+
output: value.output,
|
|
460
|
+
path: value.path,
|
|
461
|
+
})
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function toComponentKind(value: string): ComponentKind {
|
|
465
|
+
if (value === "unit") return ComponentKind.UNIT
|
|
466
|
+
if (value === "composite") return ComponentKind.COMPOSITE
|
|
467
|
+
throw new Error(`Unknown component kind "${value}"`)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function fromComponentKind(value: ComponentKind): "unit" | "composite" {
|
|
471
|
+
if (value === ComponentKind.UNIT) return "unit"
|
|
472
|
+
if (value === ComponentKind.COMPOSITE) return "composite"
|
|
473
|
+
throw new Error("Component kind must be specified")
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function toInstanceStatus(value: string): InstanceStatus {
|
|
477
|
+
const statuses = {
|
|
478
|
+
undeployed: InstanceStatus.UNDEPLOYED,
|
|
479
|
+
attempted: InstanceStatus.ATTEMPTED,
|
|
480
|
+
deployed: InstanceStatus.DEPLOYED,
|
|
481
|
+
failed: InstanceStatus.FAILED,
|
|
482
|
+
} as const
|
|
483
|
+
const status = statuses[value as keyof typeof statuses]
|
|
484
|
+
if (status === undefined) throw new Error(`Unknown instance status "${value}"`)
|
|
485
|
+
return status
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function toInstanceSource(value: string): InstanceSource {
|
|
489
|
+
if (value === "resident") return InstanceSource.RESIDENT
|
|
490
|
+
if (value === "virtual") return InstanceSource.VIRTUAL
|
|
491
|
+
throw new Error(`Unknown instance source "${value}"`)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function toEvaluationStatus(value: string): EvaluationStatus {
|
|
495
|
+
if (value === "evaluating") return EvaluationStatus.EVALUATING
|
|
496
|
+
if (value === "evaluated") return EvaluationStatus.EVALUATED
|
|
497
|
+
if (value === "error") return EvaluationStatus.ERROR
|
|
498
|
+
throw new Error(`Unknown evaluation status "${value}"`)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function toInstanceOperationStatus(value: string): InstanceOperationStatus {
|
|
502
|
+
const statuses = {
|
|
503
|
+
updating: InstanceOperationStatus.UPDATING,
|
|
504
|
+
processing_triggers: InstanceOperationStatus.PROCESSING_TRIGGERS,
|
|
505
|
+
previewing: InstanceOperationStatus.PREVIEWING,
|
|
506
|
+
destroying: InstanceOperationStatus.DESTROYING,
|
|
507
|
+
refreshing: InstanceOperationStatus.REFRESHING,
|
|
508
|
+
pending: InstanceOperationStatus.PENDING,
|
|
509
|
+
cancelling: InstanceOperationStatus.CANCELLING,
|
|
510
|
+
updated: InstanceOperationStatus.UPDATED,
|
|
511
|
+
previewed: InstanceOperationStatus.PREVIEWED,
|
|
512
|
+
skipped: InstanceOperationStatus.SKIPPED,
|
|
513
|
+
destroyed: InstanceOperationStatus.DESTROYED,
|
|
514
|
+
refreshed: InstanceOperationStatus.REFRESHED,
|
|
515
|
+
cancelled: InstanceOperationStatus.CANCELLED,
|
|
516
|
+
failed: InstanceOperationStatus.FAILED,
|
|
517
|
+
} as const
|
|
518
|
+
const status = statuses[value as keyof typeof statuses]
|
|
519
|
+
if (status === undefined) throw new Error(`Unknown instance operation status "${value}"`)
|
|
520
|
+
return status
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export function fromOperationType(value: OperationType) {
|
|
524
|
+
if (value === OperationType.UPDATE) return "update"
|
|
525
|
+
if (value === OperationType.PREVIEW) return "preview"
|
|
526
|
+
if (value === OperationType.DESTROY) return "destroy"
|
|
527
|
+
if (value === OperationType.RECREATE) return "recreate"
|
|
528
|
+
if (value === OperationType.REFRESH) return "refresh"
|
|
529
|
+
throw new Error("Operation type must be specified")
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export function fromOperationPhase(phase: OperationPhase): BackendOperationPhase {
|
|
533
|
+
return operationPhaseSchema.parse({
|
|
534
|
+
type: fromOperationPhaseType(phase.type),
|
|
535
|
+
instances: phase.instances.map(instance => ({
|
|
536
|
+
id: instance.id,
|
|
537
|
+
parentId: instance.parentId,
|
|
538
|
+
message: instance.message,
|
|
539
|
+
})),
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function toOperationType(value: string): OperationType {
|
|
544
|
+
const types = {
|
|
545
|
+
update: OperationType.UPDATE,
|
|
546
|
+
preview: OperationType.PREVIEW,
|
|
547
|
+
destroy: OperationType.DESTROY,
|
|
548
|
+
recreate: OperationType.RECREATE,
|
|
549
|
+
refresh: OperationType.REFRESH,
|
|
550
|
+
} as const
|
|
551
|
+
const type = types[value as keyof typeof types]
|
|
552
|
+
if (type === undefined) throw new Error(`Unknown operation type "${value}"`)
|
|
553
|
+
return type
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function toOperationStatus(value: string): OperationStatus {
|
|
557
|
+
const statuses = {
|
|
558
|
+
pending: OperationStatus.PENDING,
|
|
559
|
+
running: OperationStatus.RUNNING,
|
|
560
|
+
failing: OperationStatus.FAILING,
|
|
561
|
+
cancelling: OperationStatus.CANCELLING,
|
|
562
|
+
completed: OperationStatus.COMPLETED,
|
|
563
|
+
failed: OperationStatus.FAILED,
|
|
564
|
+
cancelled: OperationStatus.CANCELLED,
|
|
565
|
+
} as const
|
|
566
|
+
const status = statuses[value as keyof typeof statuses]
|
|
567
|
+
if (status === undefined) throw new Error(`Unknown operation status "${value}"`)
|
|
568
|
+
return status
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function toOperationPhaseType(value: string): OperationPhaseType {
|
|
572
|
+
const types = {
|
|
573
|
+
destroy: OperationPhaseType.DESTROY,
|
|
574
|
+
preview: OperationPhaseType.PREVIEW,
|
|
575
|
+
update: OperationPhaseType.UPDATE,
|
|
576
|
+
refresh: OperationPhaseType.REFRESH,
|
|
577
|
+
} as const
|
|
578
|
+
const type = types[value as keyof typeof types]
|
|
579
|
+
if (type === undefined) throw new Error(`Unknown operation phase type "${value}"`)
|
|
580
|
+
return type
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function fromOperationPhaseType(value: OperationPhaseType): BackendOperationPhase["type"] {
|
|
584
|
+
const types = {
|
|
585
|
+
[OperationPhaseType.DESTROY]: "destroy",
|
|
586
|
+
[OperationPhaseType.PREVIEW]: "preview",
|
|
587
|
+
[OperationPhaseType.UPDATE]: "update",
|
|
588
|
+
[OperationPhaseType.REFRESH]: "refresh",
|
|
589
|
+
} as const
|
|
590
|
+
const type = types[value as keyof typeof types]
|
|
591
|
+
if (!type) throw new Error("Operation phase type must be specified")
|
|
592
|
+
return type
|
|
593
|
+
}
|