@highstate/backend-api 0.28.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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "sourceHashes": {
3
- "./dist/index.js": 4288203316
3
+ "./dist/index.js": 85375231
4
4
  }
5
5
  }
package/dist/index.js CHANGED
@@ -235,7 +235,6 @@ function toInstance(instance) {
235
235
  ])),
236
236
  injectionInputs: (instance.injectionInputs ?? []).map((value) => ({ hubId: value.hubId })),
237
237
  position: instance.position ?? undefined,
238
- resolvedInputs: toInstanceReferenceMap(instance.resolvedInputs),
239
238
  parentId: instance.parentId,
240
239
  outputs: toInstanceReferenceMap(instance.outputs),
241
240
  resolvedOutputs: toInstanceReferenceMap(instance.resolvedOutputs)
@@ -336,7 +335,6 @@ function toHubPatch(hub, paths) {
336
335
  }
337
336
  function toInstanceState(state) {
338
337
  const model = state.model ? instanceModelSchema.parse(state.model) : undefined;
339
- const resolvedInputs = state.resolvedInputs ? fromUnknownInstanceReferenceMap(state.resolvedInputs) : undefined;
340
338
  return create2(InstanceStateSchema, {
341
339
  id: state.id,
342
340
  instanceId: state.instanceId,
@@ -357,7 +355,6 @@ function toInstanceState(state) {
357
355
  currentResourceCount: state.lastOperationState.currentResourceCount ?? undefined,
358
356
  totalResourceCount: state.lastOperationState.totalResourceCount ?? undefined,
359
357
  model: toInstance(instanceModelSchema.parse(state.lastOperationState.model)),
360
- resolvedInputs: toInstanceReferenceMap(fromUnknownInstanceReferenceMap(state.lastOperationState.resolvedInputs)),
361
358
  startedAt: toNullableTimestamp(state.lastOperationState.startedAt),
362
359
  finishedAt: toNullableTimestamp(state.lastOperationState.finishedAt)
363
360
  } : undefined,
@@ -369,8 +366,7 @@ function toInstanceState(state) {
369
366
  currentResourceCount: state.currentResourceCount ?? undefined,
370
367
  hasResourceHooks: state.hasResourceHooks,
371
368
  statusFields: state.statusFields ? fromJson(ValueSchema, jsonValueSchema.parse(state.statusFields)) : undefined,
372
- model: model ? toInstance(model) : undefined,
373
- resolvedInputs: toInstanceReferenceMap(resolvedInputs)
369
+ model: model ? toInstance(model) : undefined
374
370
  });
375
371
  }
376
372
  function toInstanceCustomStatus(status) {
@@ -446,22 +442,28 @@ function toLibrary(library) {
446
442
  });
447
443
  }
448
444
  function toComponent(component) {
449
- return create2(ComponentSchema, {
450
- type: component.type,
451
- kind: toComponentKind(component.kind),
452
- arguments: Object.fromEntries(Object.entries(component.args).map(([name, argument]) => [
453
- name,
454
- {
455
- schema: jsonObjectSchema.parse(argument.schema),
456
- required: argument.required,
457
- meta: argument.meta
458
- }
459
- ])),
460
- inputs: Object.fromEntries(Object.entries(component.inputs).map(([name, port]) => [name, toComponentPort(port)])),
461
- outputs: Object.fromEntries(Object.entries(component.outputs).map(([name, port]) => [name, toComponentPort(port)])),
462
- meta: component.meta,
463
- definitionHash: component.definitionHash
464
- });
445
+ try {
446
+ return create2(ComponentSchema, {
447
+ type: component.type,
448
+ kind: toComponentKind(component.kind),
449
+ arguments: Object.fromEntries(Object.entries(component.args).map(([name, argument]) => [
450
+ name,
451
+ {
452
+ schema: jsonObjectSchema.parse(argument.schema),
453
+ required: argument.required,
454
+ meta: argument.meta
455
+ }
456
+ ])),
457
+ inputs: Object.fromEntries(Object.entries(component.inputs).map(([name, port]) => [name, toComponentPort(port)])),
458
+ outputs: Object.fromEntries(Object.entries(component.outputs).map(([name, port]) => [name, toComponentPort(port)])),
459
+ meta: component.meta,
460
+ definitionHash: component.definitionHash
461
+ });
462
+ } catch (error) {
463
+ throw new Error(`Failed to convert component "${component.type}" to an API message`, {
464
+ cause: error
465
+ });
466
+ }
465
467
  }
466
468
  function toEntity(entity) {
467
469
  return create2(EntitySchema, {
@@ -470,7 +472,6 @@ function toEntity(entity) {
470
472
  directExtensions: entity.directExtensions ?? [],
471
473
  inclusions: entity.inclusions ?? [],
472
474
  directInclusions: entity.directInclusions ?? [],
473
- schema: jsonObjectSchema.parse(entity.schema),
474
475
  meta: entity.meta,
475
476
  definitionHash: entity.definitionHash
476
477
  });
@@ -504,9 +505,6 @@ function toInstanceReferenceMap(values) {
504
505
  function fromInstanceReferenceMap(values) {
505
506
  return Object.fromEntries(Object.entries(values).map(([key, list]) => [key, list.values.map(fromInstanceReference)]));
506
507
  }
507
- function fromUnknownInstanceReferenceMap(value) {
508
- return instanceModelSchema.shape.inputs.unwrap().parse(value);
509
- }
510
508
  function fromInstanceReference(value) {
511
509
  return instanceInputSchema.parse({
512
510
  instanceId: value.instanceId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highstate/backend-api",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -113,7 +113,6 @@ export function toInstance(instance: InstanceModel): Instance {
113
113
  ),
114
114
  injectionInputs: (instance.injectionInputs ?? []).map(value => ({ hubId: value.hubId })),
115
115
  position: instance.position ?? undefined,
116
- resolvedInputs: toInstanceReferenceMap(instance.resolvedInputs),
117
116
  parentId: instance.parentId,
118
117
  outputs: toInstanceReferenceMap(instance.outputs),
119
118
  resolvedOutputs: toInstanceReferenceMap(instance.resolvedOutputs),
@@ -234,9 +233,6 @@ export function toHubPatch(hub: Hub, paths: readonly string[]): HubModelPatch {
234
233
 
235
234
  export function toInstanceState(state: BackendInstanceState): InstanceState {
236
235
  const model = state.model ? instanceModelSchema.parse(state.model) : undefined
237
- const resolvedInputs = state.resolvedInputs
238
- ? fromUnknownInstanceReferenceMap(state.resolvedInputs)
239
- : undefined
240
236
 
241
237
  return create(InstanceStateSchema, {
242
238
  id: state.id,
@@ -263,9 +259,6 @@ export function toInstanceState(state: BackendInstanceState): InstanceState {
263
259
  currentResourceCount: state.lastOperationState.currentResourceCount ?? undefined,
264
260
  totalResourceCount: state.lastOperationState.totalResourceCount ?? undefined,
265
261
  model: toInstance(instanceModelSchema.parse(state.lastOperationState.model)),
266
- resolvedInputs: toInstanceReferenceMap(
267
- fromUnknownInstanceReferenceMap(state.lastOperationState.resolvedInputs),
268
- ),
269
262
  startedAt: toNullableTimestamp(state.lastOperationState.startedAt),
270
263
  finishedAt: toNullableTimestamp(state.lastOperationState.finishedAt),
271
264
  }
@@ -281,7 +274,6 @@ export function toInstanceState(state: BackendInstanceState): InstanceState {
281
274
  ? fromJson(ValueSchema, jsonValueSchema.parse(state.statusFields))
282
275
  : undefined,
283
276
  model: model ? toInstance(model) : undefined,
284
- resolvedInputs: toInstanceReferenceMap(resolvedInputs),
285
277
  })
286
278
  }
287
279
 
@@ -378,28 +370,34 @@ export function toLibrary(library: {
378
370
  }
379
371
 
380
372
  export function toComponent(component: ComponentModel): Component {
381
- return create(ComponentSchema, {
382
- type: component.type,
383
- kind: toComponentKind(component.kind),
384
- arguments: Object.fromEntries(
385
- Object.entries(component.args).map(([name, argument]) => [
386
- name,
387
- {
388
- schema: jsonObjectSchema.parse(argument.schema),
389
- required: argument.required,
390
- meta: argument.meta,
391
- },
392
- ]),
393
- ),
394
- inputs: Object.fromEntries(
395
- Object.entries(component.inputs).map(([name, port]) => [name, toComponentPort(port)]),
396
- ),
397
- outputs: Object.fromEntries(
398
- Object.entries(component.outputs).map(([name, port]) => [name, toComponentPort(port)]),
399
- ),
400
- meta: component.meta,
401
- definitionHash: component.definitionHash,
402
- })
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
+ }
403
401
  }
404
402
 
405
403
  export function toEntity(entity: EntityModel): Entity {
@@ -409,7 +407,6 @@ export function toEntity(entity: EntityModel): Entity {
409
407
  directExtensions: entity.directExtensions ?? [],
410
408
  inclusions: entity.inclusions ?? [],
411
409
  directInclusions: entity.directInclusions ?? [],
412
- schema: jsonObjectSchema.parse(entity.schema),
413
410
  meta: entity.meta,
414
411
  definitionHash: entity.definitionHash,
415
412
  })
@@ -456,10 +453,6 @@ function fromInstanceReferenceMap(
456
453
  )
457
454
  }
458
455
 
459
- function fromUnknownInstanceReferenceMap(value: unknown): NonNullable<InstanceModel["inputs"]> {
460
- return instanceModelSchema.shape.inputs.unwrap().parse(value)
461
- }
462
-
463
456
  function fromInstanceReference(value: Instance["inputs"][string]["values"][number]) {
464
457
  return instanceInputSchema.parse({
465
458
  instanceId: value.instanceId,
@@ -3,6 +3,7 @@ import { BadRequestSchema, ErrorInfoSchema } from "@highstate/api/v1"
3
3
  import {
4
4
  BackendError,
5
5
  BackendErrorCategory,
6
+ InvalidOperationPlanError,
6
7
  InvalidPageSizeError,
7
8
  PermissionDeniedError,
8
9
  } from "@highstate/backend/shared"
@@ -35,6 +36,28 @@ describe("createErrorHandlingInterceptor", () => {
35
36
  }
36
37
  })
37
38
 
39
+ it("exposes operation planning validation errors", async () => {
40
+ const logger = { error: vi.fn() }
41
+ const interceptor = createErrorHandlingInterceptor({ logger } as never)
42
+ const handler = interceptor(async () => {
43
+ throw new InvalidOperationPlanError(
44
+ "Operation options are invalid: ghost options are supported only for updates",
45
+ )
46
+ })
47
+
48
+ const result = (await handler({
49
+ method: { name: "PlanOperation" },
50
+ header: new Headers(),
51
+ } as never).catch(error => error as ConnectError)) as ConnectError
52
+
53
+ expect(result.code).toBe(Code.InvalidArgument)
54
+ expect(result.rawMessage).toBe(
55
+ "Operation options are invalid: ghost options are supported only for updates",
56
+ )
57
+ expect(result.findDetails(ErrorInfoSchema)[0]?.reason).toBe("OPERATION_PLAN_INVALID")
58
+ expect(logger.error).not.toHaveBeenCalled()
59
+ })
60
+
38
61
  it("sanitizes and logs unexpected errors once", async () => {
39
62
  const logger = { error: vi.fn() }
40
63
  const interceptor = createErrorHandlingInterceptor({ logger } as never)