@highstate/backend 0.18.0 → 0.20.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.
Files changed (120) hide show
  1. package/dist/{chunk-JT4KWE3B.js → chunk-52MY2TCE.js} +348 -19
  2. package/dist/chunk-52MY2TCE.js.map +1 -0
  3. package/dist/{chunk-I7BWSAN6.js → chunk-UAWBPTDW.js} +3 -3
  4. package/dist/{chunk-I7BWSAN6.js.map → chunk-UAWBPTDW.js.map} +1 -1
  5. package/dist/highstate.manifest.json +4 -4
  6. package/dist/index.js +4159 -785
  7. package/dist/index.js.map +1 -1
  8. package/dist/library/worker/main.js +5 -2
  9. package/dist/library/worker/main.js.map +1 -1
  10. package/dist/shared/index.js +2 -2
  11. package/package.json +7 -7
  12. package/prisma/backend/_schema/object.prisma +12 -0
  13. package/prisma/backend/sqlite/migrations/20260222113554_add_object_tracking/migration.sql +7 -0
  14. package/prisma/project/artifact.prisma +3 -0
  15. package/prisma/project/entity.prisma +125 -0
  16. package/prisma/project/instance.prisma +6 -0
  17. package/prisma/project/migrations/20260301210131_add_entity_tracking/migration.sql +70 -0
  18. package/prisma/project/migrations/20260302212734_add_resource_hooks_flag/migration.sql +1 -0
  19. package/prisma/project/operation.prisma +3 -0
  20. package/src/business/artifact.test.ts +22 -2
  21. package/src/business/artifact.ts +7 -1
  22. package/src/business/entity-snapshot.test.ts +684 -0
  23. package/src/business/entity-snapshot.ts +904 -0
  24. package/src/business/evaluation.test.ts +56 -0
  25. package/src/business/evaluation.ts +102 -22
  26. package/src/business/global-search.test.ts +344 -0
  27. package/src/business/global-search.ts +902 -0
  28. package/src/business/index.ts +4 -0
  29. package/src/business/instance-lock.ts +58 -74
  30. package/src/business/instance-state.test.ts +15 -1
  31. package/src/business/instance-state.ts +37 -14
  32. package/src/business/object-ref-index.test.ts +140 -0
  33. package/src/business/object-ref-index.ts +193 -0
  34. package/src/business/operation.test.ts +15 -1
  35. package/src/business/operation.ts +4 -0
  36. package/src/business/project-model.ts +154 -13
  37. package/src/business/project-unlock.ts +25 -2
  38. package/src/business/project.ts +9 -0
  39. package/src/business/secret.test.ts +35 -2
  40. package/src/business/secret.ts +32 -9
  41. package/src/business/settings.ts +761 -0
  42. package/src/business/unit-output.test.ts +477 -0
  43. package/src/business/unit-output.ts +461 -0
  44. package/src/business/worker.ts +55 -4
  45. package/src/database/_generated/backend/postgresql/browser.ts +6 -0
  46. package/src/database/_generated/backend/postgresql/client.ts +6 -0
  47. package/src/database/_generated/backend/postgresql/internal/class.ts +23 -5
  48. package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +89 -5
  49. package/src/database/_generated/backend/postgresql/internal/prismaNamespaceBrowser.ts +9 -0
  50. package/src/database/_generated/backend/postgresql/models/Object.ts +1076 -0
  51. package/src/database/_generated/backend/postgresql/models.ts +1 -0
  52. package/src/database/_generated/backend/sqlite/browser.ts +6 -0
  53. package/src/database/_generated/backend/sqlite/client.ts +6 -0
  54. package/src/database/_generated/backend/sqlite/internal/class.ts +23 -5
  55. package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +89 -5
  56. package/src/database/_generated/backend/sqlite/internal/prismaNamespaceBrowser.ts +9 -0
  57. package/src/database/_generated/backend/sqlite/models/Object.ts +1074 -0
  58. package/src/database/_generated/backend/sqlite/models.ts +1 -0
  59. package/src/database/_generated/project/browser.ts +23 -0
  60. package/src/database/_generated/project/client.ts +23 -0
  61. package/src/database/_generated/project/commonInputTypes.ts +87 -53
  62. package/src/database/_generated/project/enums.ts +8 -0
  63. package/src/database/_generated/project/internal/class.ts +53 -5
  64. package/src/database/_generated/project/internal/prismaNamespace.ts +367 -13
  65. package/src/database/_generated/project/internal/prismaNamespaceBrowser.ts +48 -1
  66. package/src/database/_generated/project/models/Artifact.ts +199 -11
  67. package/src/database/_generated/project/models/Entity.ts +1274 -0
  68. package/src/database/_generated/project/models/EntitySnapshot.ts +2389 -0
  69. package/src/database/_generated/project/models/EntitySnapshotContent.ts +1260 -0
  70. package/src/database/_generated/project/models/EntitySnapshotReference.ts +1449 -0
  71. package/src/database/_generated/project/models/InstanceState.ts +361 -1
  72. package/src/database/_generated/project/models/Operation.ts +148 -3
  73. package/src/database/_generated/project/models/OperationLog.ts +0 -4
  74. package/src/database/_generated/project/models.ts +4 -0
  75. package/src/database/migration.ts +3 -0
  76. package/src/library/worker/evaluator.ts +7 -1
  77. package/src/orchestrator/manager.ts +7 -0
  78. package/src/orchestrator/operation-context.captured-outputs.test.ts +118 -0
  79. package/src/orchestrator/operation-context.ts +154 -16
  80. package/src/orchestrator/operation-plan.destroy.test.md +33 -12
  81. package/src/orchestrator/operation-plan.destroy.test.ts +140 -2
  82. package/src/orchestrator/operation-plan.fixtures.ts +2 -0
  83. package/src/orchestrator/operation-plan.md +4 -1
  84. package/src/orchestrator/operation-plan.ts +286 -92
  85. package/src/orchestrator/operation-plan.update.test.md +286 -11
  86. package/src/orchestrator/operation-plan.update.test.ts +656 -5
  87. package/src/orchestrator/operation-workset.ts +72 -22
  88. package/src/orchestrator/operation.cancel.test.ts +4 -0
  89. package/src/orchestrator/operation.composite.test.ts +341 -0
  90. package/src/orchestrator/operation.destroy.test.ts +4 -0
  91. package/src/orchestrator/operation.output-validation.failure.test.ts +124 -0
  92. package/src/orchestrator/operation.preview.test.ts +4 -0
  93. package/src/orchestrator/operation.refresh.test.ts +4 -0
  94. package/src/orchestrator/operation.test-utils.ts +52 -13
  95. package/src/orchestrator/operation.ts +228 -68
  96. package/src/orchestrator/operation.update.failure.test.ts +4 -0
  97. package/src/orchestrator/operation.update.skip.test.ts +110 -0
  98. package/src/orchestrator/operation.update.test.ts +4 -0
  99. package/src/orchestrator/plan-test-builder.ts +1 -0
  100. package/src/orchestrator/unit-input-values.test.ts +450 -0
  101. package/src/orchestrator/unit-input-values.ts +281 -0
  102. package/src/pubsub/manager.ts +3 -0
  103. package/src/runner/abstractions.ts +23 -54
  104. package/src/runner/local.ts +109 -85
  105. package/src/services.ts +52 -1
  106. package/src/shared/models/prisma.ts +1 -0
  107. package/src/shared/models/project/entity.ts +121 -0
  108. package/src/shared/models/project/index.ts +1 -0
  109. package/src/shared/models/project/operation.ts +61 -3
  110. package/src/shared/models/project/state.ts +10 -0
  111. package/src/shared/models/project/worker.ts +7 -0
  112. package/src/shared/resolvers/effective-output-type.test.ts +494 -0
  113. package/src/shared/resolvers/effective-output-type.ts +162 -0
  114. package/src/shared/resolvers/index.ts +1 -0
  115. package/src/shared/resolvers/input.ts +61 -9
  116. package/src/shared/utils/index.ts +1 -0
  117. package/src/shared/utils/stable-json.ts +41 -0
  118. package/src/terminal/manager.ts +6 -0
  119. package/src/worker/manager.ts +97 -1
  120. package/dist/chunk-JT4KWE3B.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { z, commonObjectMetaSchema, genericNameSchema, timestampsSchema, objectMetaSchema, serviceAccountMetaSchema, instanceIdSchema, instanceModelSchema, hubModelSchema, pageBlockSchema, globalCommonObjectMetaSchema, terminalSpecSchema, isUnitModel, parseArgumentValue } from '@highstate/contract';
1
+ import { z, commonObjectMetaSchema, genericNameSchema, timestampsSchema, objectMetaSchema, serviceAccountMetaSchema, instanceIdSchema, instanceModelSchema, hubModelSchema, pageBlockSchema, globalCommonObjectMetaSchema, terminalSpecSchema, inputKey, isUnitModel, parseArgumentValue } from '@highstate/contract';
2
2
  import { z as z$1 } from 'zod';
3
3
  import { mapValues, constant, unique, fromEntries } from 'remeda';
4
4
  import { crc32 } from '@aws-crypto/crc32';
@@ -345,6 +345,91 @@ var instanceCustomStatusInputSchema = z$1.object({
345
345
  message: z$1.string().optional(),
346
346
  order: z$1.number().min(0).max(100).optional()
347
347
  });
348
+ var rawEntityMetaSchema = z$1.object({
349
+ identity: z$1.string().optional(),
350
+ title: z$1.string().optional(),
351
+ description: z$1.string().optional(),
352
+ icon: z$1.string().optional(),
353
+ iconColor: z$1.string().optional()
354
+ }).passthrough();
355
+ var entityOutputSchema = z$1.object({
356
+ id: z$1.string(),
357
+ type: z$1.string(),
358
+ identity: z$1.string(),
359
+ meta: commonObjectMetaSchema,
360
+ /**
361
+ * The ID of the last known entity snapshot.
362
+ */
363
+ snapshotId: z$1.string().optional(),
364
+ /**
365
+ * The timestamp of the last known entity snapshot.
366
+ */
367
+ createdAt: z$1.date().optional()
368
+ });
369
+ var entityQuerySchema = collectionQuerySchema.extend({
370
+ type: z$1.string().optional()
371
+ });
372
+ var entitySnapshotOutputSchema = z$1.object({
373
+ id: z$1.string(),
374
+ meta: commonObjectMetaSchema,
375
+ content: z$1.unknown(),
376
+ operationId: z$1.string(),
377
+ stateId: z$1.string(),
378
+ referencedInOutputs: z$1.string().array(),
379
+ exportedInOutputs: z$1.string().array(),
380
+ createdAt: z$1.date()
381
+ });
382
+ var entitySnapshotListItemOutputSchema = z$1.object({
383
+ id: z$1.string(),
384
+ meta: commonObjectMetaSchema,
385
+ operationId: z$1.string(),
386
+ stateId: z$1.string(),
387
+ createdAt: z$1.date()
388
+ });
389
+ var entitySnapshotDetailsOutputSchema = z$1.object({
390
+ entity: z$1.object({
391
+ id: z$1.string(),
392
+ type: z$1.string(),
393
+ identity: z$1.string()
394
+ }),
395
+ snapshot: entitySnapshotOutputSchema
396
+ });
397
+ var entityDetailsOutputSchema = z$1.object({
398
+ ...entityOutputSchema.shape,
399
+ /**
400
+ * The last known entity snapshot.
401
+ */
402
+ lastSnapshot: entitySnapshotOutputSchema.nullable()
403
+ });
404
+ var entityReferenceOutputSchema = z$1.object({
405
+ id: z$1.string(),
406
+ meta: commonObjectMetaSchema,
407
+ group: z$1.string(),
408
+ fromSnapshotId: z$1.string(),
409
+ fromEntityId: z$1.string(),
410
+ fromEntityType: z$1.string(),
411
+ fromEntityIdentity: z$1.string(),
412
+ fromEntityMeta: commonObjectMetaSchema,
413
+ toSnapshotId: z$1.string(),
414
+ toEntityId: z$1.string(),
415
+ toEntityType: z$1.string(),
416
+ toEntityIdentity: z$1.string(),
417
+ toEntityMeta: commonObjectMetaSchema
418
+ });
419
+ function toCommonEntityMeta(meta) {
420
+ const parsedRawMeta = rawEntityMetaSchema.safeParse(meta);
421
+ if (parsedRawMeta.success) {
422
+ return {
423
+ title: parsedRawMeta.data.title ?? parsedRawMeta.data.identity ?? "Unknown",
424
+ description: parsedRawMeta.data.description,
425
+ icon: parsedRawMeta.data.icon,
426
+ iconColor: parsedRawMeta.data.iconColor
427
+ };
428
+ }
429
+ return {
430
+ title: "Unknown"
431
+ };
432
+ }
348
433
  var instanceLockOutputSchema = z$1.object({
349
434
  stateId: z$1.cuid2(),
350
435
  meta: commonObjectMetaSchema,
@@ -410,15 +495,30 @@ var operationOptionsSchema = z.object({
410
495
  */
411
496
  forceUpdateDependencies: z.boolean().default(false),
412
497
  /**
413
- * Ignore dependencies and operate only on explicitly requested instances.
498
+ * Ignore only changed dependencies and keep failed/undeployed prerequisites.
414
499
  *
415
500
  * **Operation Behavior Impact:**
416
- * - skips dependency inclusion even when dependencies are failed or undeployed;
501
+ * - skips dependency inclusion when dependency is only changed;
502
+ * - still includes failed or undeployed dependencies to preserve safety for missing/broken prerequisites;
503
+ * - useful for targeted updates where stale-but-healthy dependencies are intentionally not traversed.
504
+ *
505
+ * **Usage with other options:**
506
+ * - mutually exclusive with `forceUpdateDependencies`;
507
+ * - mutually exclusive with `ignoreDependencies`;
508
+ * - independent of child/composite inclusion options.
509
+ */
510
+ ignoreChangedDependencies: z.boolean().default(false),
511
+ /**
512
+ * Ignore all dependencies and operate only on explicitly requested instances.
513
+ *
514
+ * **Operation Behavior Impact:**
515
+ * - skips dependency inclusion entirely, including failed and undeployed prerequisites;
417
516
  * - caller must explicitly include every prerequisite instance to avoid failures;
418
- * - complements on-demand or targeted updates where dependency safety is managed externally.
517
+ * - intended for fully manual execution flows.
419
518
  *
420
519
  * **Usage with other options:**
421
520
  * - mutually exclusive with `forceUpdateDependencies`;
521
+ * - mutually exclusive with `ignoreChangedDependencies`;
422
522
  * - independent of child/composite inclusion options.
423
523
  */
424
524
  ignoreDependencies: z.boolean().default(false),
@@ -435,6 +535,45 @@ var operationOptionsSchema = z.object({
435
535
  * - overrides `allowPartialCompositeInstanceCreation`: when enabled, **ALL** children are included regardless of existence.
436
536
  */
437
537
  forceUpdateChildren: z.boolean().default(false),
538
+ /**
539
+ * Run only ghost cleanup destroy phase and skip update phase entirely.
540
+ *
541
+ * **Operation Behavior Impact:**
542
+ * - applies to update operations only;
543
+ * - skips update phase even if normal update candidates exist;
544
+ * - keeps only ghost cleanup destroy phase for affected substantive composites.
545
+ *
546
+ * **Usage with other options:**
547
+ * - mutually exclusive with `firstDestroyGhosts`;
548
+ * - mutually exclusive with `ignoreGhosts`.
549
+ */
550
+ onlyDestroyGhosts: z.boolean().default(false),
551
+ /**
552
+ * Run ghost cleanup destroy phase before update phase.
553
+ *
554
+ * **Operation Behavior Impact:**
555
+ * - applies to update operations only;
556
+ * - keeps both phases but changes order to destroy ghosts first;
557
+ * - useful when stale ghost resources should be removed prior to update execution.
558
+ *
559
+ * **Usage with other options:**
560
+ * - mutually exclusive with `onlyDestroyGhosts`;
561
+ * - mutually exclusive with `ignoreGhosts`.
562
+ */
563
+ firstDestroyGhosts: z.boolean().default(false),
564
+ /**
565
+ * Ignore ghost cleanup and skip destroy phase for ghosts.
566
+ *
567
+ * **Operation Behavior Impact:**
568
+ * - applies to update operations only;
569
+ * - disables ghost cleanup destroy phase generation;
570
+ * - update phase remains unchanged.
571
+ *
572
+ * **Usage with other options:**
573
+ * - mutually exclusive with `onlyDestroyGhosts`;
574
+ * - mutually exclusive with `firstDestroyGhosts`.
575
+ */
576
+ ignoreGhosts: z.boolean().default(false),
438
577
  /**
439
578
  * Include dependent instances when destroying instances.
440
579
  *
@@ -657,7 +796,8 @@ var serviceAccountQuerySchema = collectionQuerySchema.extend({
657
796
  });
658
797
  var stableInstanceInputSchema = z$1.object({
659
798
  stateId: z$1.string(),
660
- output: z$1.string()
799
+ output: z$1.string(),
800
+ path: z$1.string().optional()
661
801
  });
662
802
  var instanceStateEventSchema = z$1.discriminatedUnion("type", [
663
803
  z$1.object({
@@ -669,6 +809,15 @@ var instanceStateEventSchema = z$1.discriminatedUnion("type", [
669
809
  stateId: z$1.string(),
670
810
  patch: z$1.custom()
671
811
  }),
812
+ z$1.object({
813
+ type: z$1.literal("patched-batch"),
814
+ patches: z$1.array(
815
+ z$1.object({
816
+ stateId: z$1.string(),
817
+ patch: z$1.custom()
818
+ })
819
+ )
820
+ }),
672
821
  z$1.object({
673
822
  type: z$1.literal("deleted"),
674
823
  stateId: z$1.string()
@@ -823,6 +972,10 @@ var workerVersionStatusSchema = z$1.enum([
823
972
  "stopped",
824
973
  "error"
825
974
  ]);
975
+ var workerVersionStatusEventSchema = z$1.object({
976
+ workerVersionId: z$1.cuid2(),
977
+ status: workerVersionStatusSchema
978
+ });
826
979
  var workerVersionOutputSchema = z$1.object({
827
980
  id: z$1.cuid2(),
828
981
  digest: z$1.string(),
@@ -858,6 +1011,102 @@ function toWorkerVersionOutput(version, apiKey) {
858
1011
  apiKeyMeta: apiKey.meta
859
1012
  };
860
1013
  }
1014
+
1015
+ // src/shared/resolvers/effective-output-type.ts
1016
+ function resolveEffectiveOutputType(options) {
1017
+ const visited = options.visited ?? /* @__PURE__ */ new Set();
1018
+ const producer = options.getInstanceContext(options.input.instanceId);
1019
+ if (!producer) {
1020
+ return resolveTypeByPathOrFallbackInclusion({
1021
+ rootType: options.fallbackType,
1022
+ path: options.input.path,
1023
+ entities: void 0,
1024
+ fallbackType: options.fallbackType
1025
+ });
1026
+ }
1027
+ const outputSpec = producer.component.outputs[options.input.output];
1028
+ if (!outputSpec) {
1029
+ return resolveTypeByPathOrFallbackInclusion({
1030
+ rootType: options.fallbackType,
1031
+ path: options.input.path,
1032
+ entities: producer.entities,
1033
+ fallbackType: options.fallbackType
1034
+ });
1035
+ }
1036
+ let effectiveType = outputSpec.type;
1037
+ if (outputSpec.fromInput) {
1038
+ const visitedKey = `${producer.instance.id}:${options.input.output}`;
1039
+ if (!visited.has(visitedKey)) {
1040
+ visited.add(visitedKey);
1041
+ const forwardedInputName = outputSpec.fromInput;
1042
+ const forwardedFallback = producer.component.inputs[forwardedInputName]?.type ?? effectiveType;
1043
+ const hasHubInputs = (producer.instance.hubInputs?.[forwardedInputName]?.length ?? 0) > 0;
1044
+ const hasInjectionInputs = (producer.instance.injectionInputs?.length ?? 0) > 0;
1045
+ const directInputs = producer.instance.inputs?.[forwardedInputName] ?? [];
1046
+ if (!hasHubInputs && !hasInjectionInputs && directInputs.length === 1) {
1047
+ const forwardedInput = directInputs[0];
1048
+ if (forwardedInput) {
1049
+ effectiveType = resolveEffectiveOutputType({
1050
+ input: forwardedInput,
1051
+ fallbackType: forwardedFallback,
1052
+ getInstanceContext: options.getInstanceContext,
1053
+ visited
1054
+ });
1055
+ } else {
1056
+ effectiveType = forwardedFallback;
1057
+ }
1058
+ } else {
1059
+ effectiveType = forwardedFallback;
1060
+ }
1061
+ }
1062
+ }
1063
+ return resolveTypeByPathOrFallbackInclusion({
1064
+ rootType: effectiveType,
1065
+ path: options.input.path,
1066
+ entities: producer.entities,
1067
+ fallbackType: options.fallbackType
1068
+ });
1069
+ }
1070
+ function resolveTypeByPathOrFallbackInclusion(options) {
1071
+ const { rootType, path, entities, fallbackType } = options;
1072
+ if (!path || !entities) {
1073
+ return resolveTypeByImplicitInclusion(rootType, fallbackType, entities);
1074
+ }
1075
+ let currentType = rootType;
1076
+ const segments = path.split(".");
1077
+ for (const segment of segments) {
1078
+ const entity = entities[currentType];
1079
+ if (!entity) {
1080
+ return rootType;
1081
+ }
1082
+ const inclusion = entity.inclusions?.find((inc) => inc.field === segment);
1083
+ if (!inclusion) {
1084
+ return rootType;
1085
+ }
1086
+ currentType = inclusion.type;
1087
+ }
1088
+ return currentType;
1089
+ }
1090
+ function resolveTypeByImplicitInclusion(rootType, fallbackType, entities) {
1091
+ if (!entities) {
1092
+ return rootType;
1093
+ }
1094
+ if (rootType === fallbackType) {
1095
+ return rootType;
1096
+ }
1097
+ const rootEntity = entities[rootType];
1098
+ if (!rootEntity) {
1099
+ return rootType;
1100
+ }
1101
+ if (rootEntity.extensions?.includes(fallbackType)) {
1102
+ return rootType;
1103
+ }
1104
+ const inclusion = rootEntity.inclusions?.find((inc) => inc.type === fallbackType);
1105
+ if (inclusion) {
1106
+ return fallbackType;
1107
+ }
1108
+ return rootType;
1109
+ }
861
1110
  var GraphResolver = class {
862
1111
  constructor(nodes, logger, outputHandler, dependentSetHandler) {
863
1112
  this.nodes = nodes;
@@ -1074,6 +1323,23 @@ var InputResolver = class extends GraphResolver {
1074
1323
  }
1075
1324
  return dependencies;
1076
1325
  }
1326
+ resolveOutputTypeForInput(input, fallbackType) {
1327
+ return resolveEffectiveOutputType({
1328
+ input,
1329
+ fallbackType,
1330
+ getInstanceContext: (instanceId) => {
1331
+ const output = this.outputs.get(`instance:${instanceId}`);
1332
+ if (!output || output.kind !== "instance") {
1333
+ return void 0;
1334
+ }
1335
+ return {
1336
+ instance: output.instance,
1337
+ component: output.component,
1338
+ entities: output.entities
1339
+ };
1340
+ }
1341
+ });
1342
+ }
1077
1343
  processNode(node) {
1078
1344
  const getHubOutput = (input) => {
1079
1345
  const output = this.outputs.get(`hub:${input.hubId}`);
@@ -1106,7 +1372,7 @@ var InputResolver = class extends GraphResolver {
1106
1372
  if (node.kind === "hub") {
1107
1373
  const hubResult = /* @__PURE__ */ new Map();
1108
1374
  const addHubResult = (input) => {
1109
- hubResult.set(`${input.input.instanceId}:${input.input.output}`, input);
1375
+ hubResult.set(inputKey(input.input), input);
1110
1376
  };
1111
1377
  for (const input of node.hub.inputs ?? []) {
1112
1378
  const { component } = getInstanceOutput(input);
@@ -1115,7 +1381,10 @@ var InputResolver = class extends GraphResolver {
1115
1381
  this.logger.warn({ msg: "output not found in the component", input, component });
1116
1382
  continue;
1117
1383
  }
1118
- addHubResult({ input, type: componentInput.type });
1384
+ addHubResult({
1385
+ input,
1386
+ type: this.resolveOutputTypeForInput(input, componentInput.type)
1387
+ });
1119
1388
  }
1120
1389
  for (const injectionInput of node.hub.injectionInputs ?? []) {
1121
1390
  const { resolvedInputs: resolvedInputs2 } = getHubOutput(injectionInput);
@@ -1125,6 +1394,7 @@ var InputResolver = class extends GraphResolver {
1125
1394
  }
1126
1395
  return {
1127
1396
  kind: "hub",
1397
+ hub: node.hub,
1128
1398
  resolvedInputs: Array.from(hubResult.values())
1129
1399
  };
1130
1400
  }
@@ -1133,6 +1403,7 @@ var InputResolver = class extends GraphResolver {
1133
1403
  kind: "instance",
1134
1404
  instance: node.instance,
1135
1405
  component: node.component,
1406
+ entities: node.entities,
1136
1407
  resolvedInputs: mapValues(node.instance.resolvedInputs, (inputs, inputName) => {
1137
1408
  const componentInput = node.component.inputs[inputName];
1138
1409
  if (!componentInput) {
@@ -1157,7 +1428,7 @@ var InputResolver = class extends GraphResolver {
1157
1428
  inputs = /* @__PURE__ */ new Map();
1158
1429
  resolvedInputsMap.set(inputName, inputs);
1159
1430
  }
1160
- inputs.set(`${input.input.instanceId}:${input.input.output}`, input);
1431
+ inputs.set(inputKey(input.input), input);
1161
1432
  };
1162
1433
  const addInstanceInput = (inputName, input) => {
1163
1434
  const componentInput = node.component.inputs[inputName];
@@ -1175,15 +1446,35 @@ var InputResolver = class extends GraphResolver {
1175
1446
  return;
1176
1447
  }
1177
1448
  if (isUnitModel(component)) {
1178
- addInstanceResult(inputName, { input, type: componentInput.type });
1449
+ addInstanceResult(inputName, {
1450
+ input,
1451
+ type: this.resolveOutputTypeForInput(input, componentInput.type)
1452
+ });
1179
1453
  return;
1180
1454
  }
1181
1455
  if (resolvedOutputs) {
1182
1456
  for (const output of resolvedOutputs) {
1183
- addInstanceResult(inputName, { input: output, type: componentInput.type });
1457
+ addInstanceResult(inputName, {
1458
+ input: {
1459
+ ...output,
1460
+ // keep explicit path from the edge while preserving already-resolved output path
1461
+ path: input.path ?? output.path
1462
+ },
1463
+ type: this.resolveOutputTypeForInput(
1464
+ {
1465
+ instanceId: input.instanceId,
1466
+ output: input.output,
1467
+ path: input.path ?? output.path
1468
+ },
1469
+ componentInput.type
1470
+ )
1471
+ });
1184
1472
  }
1185
1473
  } else {
1186
- addInstanceResult(inputName, { input, type: componentInput.type });
1474
+ addInstanceResult(inputName, {
1475
+ input,
1476
+ type: this.resolveOutputTypeForInput(input, componentInput.type)
1477
+ });
1187
1478
  }
1188
1479
  };
1189
1480
  for (const [inputName, inputs] of Object.entries(node.instance.inputs ?? {})) {
@@ -1196,7 +1487,7 @@ var InputResolver = class extends GraphResolver {
1196
1487
  for (const injectionInput of node.instance.injectionInputs ?? []) {
1197
1488
  const { resolvedInputs: resolvedInputs2 } = getHubOutput(injectionInput);
1198
1489
  for (const input of resolvedInputs2) {
1199
- injectionInputs.set(`${input.input.instanceId}:${input.input.output}`, input);
1490
+ injectionInputs.set(inputKey(input.input), input);
1200
1491
  }
1201
1492
  }
1202
1493
  for (const [inputName, componentInput] of Object.entries(node.component.inputs ?? {})) {
@@ -1205,13 +1496,13 @@ var InputResolver = class extends GraphResolver {
1205
1496
  for (const hubInput of hubInputs) {
1206
1497
  const { resolvedInputs: resolvedInputs2 } = getHubOutput(hubInput);
1207
1498
  for (const input of resolvedInputs2) {
1208
- allInputs.set(`${input.input.instanceId}:${input.input.output}`, input);
1499
+ allInputs.set(inputKey(input.input), input);
1209
1500
  }
1210
1501
  }
1211
1502
  for (const input of allInputs.values()) {
1212
1503
  if (input.type === componentInput.type) {
1213
1504
  addInstanceInput(inputName, input.input);
1214
- const key = `${input.input.instanceId}:${input.input.output}`;
1505
+ const key = inputKey(input.input);
1215
1506
  if (injectionInputs.has(key)) {
1216
1507
  matchedInjectionInputs.set(key, input);
1217
1508
  }
@@ -1228,6 +1519,7 @@ var InputResolver = class extends GraphResolver {
1228
1519
  kind: "instance",
1229
1520
  instance: node.instance,
1230
1521
  component: node.component,
1522
+ entities: node.entities,
1231
1523
  resolvedInputs,
1232
1524
  resolvedOutputs: node.instance.resolvedOutputs,
1233
1525
  resolvedInjectionInputs: Array.from(injectionInputs.values()),
@@ -1385,6 +1677,43 @@ async function waitAll(promises) {
1385
1677
  );
1386
1678
  }
1387
1679
 
1680
+ // src/shared/utils/stable-json.ts
1681
+ function stableJsonStringify(value) {
1682
+ if (value === null) {
1683
+ return "null";
1684
+ }
1685
+ if (Array.isArray(value)) {
1686
+ return `[${value.map(stableJsonStringify).join(",")}]`;
1687
+ }
1688
+ switch (typeof value) {
1689
+ case "string":
1690
+ return JSON.stringify(value);
1691
+ case "number": {
1692
+ if (!Number.isFinite(value)) {
1693
+ throw new Error("Snapshot content contains a non-finite number");
1694
+ }
1695
+ return JSON.stringify(value);
1696
+ }
1697
+ case "boolean":
1698
+ return value ? "true" : "false";
1699
+ case "object": {
1700
+ const record = value;
1701
+ const keys = Object.keys(record).sort();
1702
+ const parts = [];
1703
+ for (const key of keys) {
1704
+ const item = record[key];
1705
+ if (item === void 0) {
1706
+ throw new Error("Snapshot content contains undefined");
1707
+ }
1708
+ parts.push(`${JSON.stringify(key)}:${stableJsonStringify(item)}`);
1709
+ }
1710
+ return `{${parts.join(",")}}`;
1711
+ }
1712
+ default:
1713
+ throw new Error(`Snapshot content contains non-JSON value of type "${typeof value}"`);
1714
+ }
1715
+ }
1716
+
1388
1717
  // src/shared/resolvers/input-hash.ts
1389
1718
  var InputHashResolver = class extends GraphResolver {
1390
1719
  getNodeDependencies({ resolvedInputs }) {
@@ -1423,11 +1752,11 @@ var InputHashResolver = class extends GraphResolver {
1423
1752
  const inputHashSink = [...selfHashSink];
1424
1753
  const sortedInputs = Object.entries(resolvedInputs).sort(([a], [b]) => a.localeCompare(b));
1425
1754
  const dependencyInstanceIds = /* @__PURE__ */ new Set();
1426
- for (const [inputKey, inputs] of sortedInputs) {
1755
+ for (const [inputKey2, inputs] of sortedInputs) {
1427
1756
  if (Object.keys(inputs).length === 0) {
1428
1757
  continue;
1429
1758
  }
1430
- inputHashSink.push(Buffer.from(inputKey));
1759
+ inputHashSink.push(Buffer.from(inputKey2));
1431
1760
  const instanceIds = inputs.map((input) => input.input.instanceId).sort();
1432
1761
  for (const instanceId of instanceIds) {
1433
1762
  const dependency = this.outputs.get(instanceId);
@@ -1556,6 +1885,6 @@ var resolverFactories = {
1556
1885
  ValidationResolver
1557
1886
  };
1558
1887
 
1559
- export { AccessError, BackendError, BackendUnlockMethodNotFoundError, CannotDeleteLastBackendUnlockMethodError, CannotDeleteLastUnlockMethodError, GraphResolver, InputHashResolver, InputResolver, InstanceLockLostError, InstanceLockedError, InstanceNotFoundError, InstanceStateNotFoundError, InvalidInstanceKindError, MAX_WORKER_START_ATTEMPTS, OperationNotFoundError, ProjectLockedError, ProjectNotFoundError, PromiseTracker, SystemSecretNames, ValidationResolver, WorkerVersionNotFoundError, apiKeyMetaSchema, apiKeyOutputSchema, apiKeyQuerySchema, applyLibraryUpdate, artifactOutputSchema, artifactQuerySchema, backendUnlockMethodInputSchema, backendUnlockMethodMetaSchema, codebaseLibrary, codebaseProjectModelStorage, collectionQueryResult, collectionQuerySchema, createAsyncBatcher, databaseProjectModelStorage, diffLibraries, extractDigestFromImage, finalInstanceOperationStatuses, finalOperationStatuses, forSchema, getAllDependents, getMatchedInjectionInstanceInputs, getResolvedHubInputs, getResolvedInjectionInstanceInputs, getResolvedInstanceInputs, getResolvedInstanceOutputs, getWorkerIdentity, globalProjectSpace, hasObjectMeta, hostPulumiBackend, instanceCustomStatusInputSchema, instanceLockEventSchema, instanceLockOutputSchema, instanceStateEventSchema, int32ToBytes, isFinalOperationStatus, isInstanceDeployed, isTransientInstanceOperationStatus, isTransientOperationStatus, isVirtualGhostInstance, librarySpecSchema, operationEventSchema, operationLaunchInputSchema, operationMetaSchema, operationOptionsSchema, operationOutputSchema, operationPhaseInstanceSchema, operationPhaseSchema, operationPhaseTypeSchema, operationPlanInputSchema, operationStatusSchema, operationTypeSchema, pageDetailsOutputSchema, pageOutputSchema, pageQuerySchema, projectInputSchema, projectModelEventSchema, projectModelStorageSpecSchema, projectOutputSchema, projectUnlockStateSchema, projectUnlockSuiteSchema, pulumiBackendSpecSchema, resolverFactories, secretOutputSchema, secretQuerySchema, serviceAccountOutputSchema, serviceAccountQuerySchema, stableInstanceInputSchema, terminalDetailsOutputSchema, terminalOutputSchema, terminalQuerySchema, terminalSessionOutputSchema, terminalStatusSchema, toApiKeyOutput, toPageOutput, toSecretOutput, toTerminalDetailsOutput, toTerminalOutput, toTerminalSessionOutput, toWorkerOutput, toWorkerVersionOutput, triggerOutputSchema, triggerQuerySchema, unlockMethodInputSchema, unlockMethodMetaSchema, unlockMethodOutputSchema, unlockMethodType, waitAll, workerOutputSchema, workerQuerySchema, workerUnitRegistrationEventSchema, workerVersionOutputSchema, workerVersionStatusSchema };
1560
- //# sourceMappingURL=chunk-JT4KWE3B.js.map
1561
- //# sourceMappingURL=chunk-JT4KWE3B.js.map
1888
+ export { AccessError, BackendError, BackendUnlockMethodNotFoundError, CannotDeleteLastBackendUnlockMethodError, CannotDeleteLastUnlockMethodError, GraphResolver, InputHashResolver, InputResolver, InstanceLockLostError, InstanceLockedError, InstanceNotFoundError, InstanceStateNotFoundError, InvalidInstanceKindError, MAX_WORKER_START_ATTEMPTS, OperationNotFoundError, ProjectLockedError, ProjectNotFoundError, PromiseTracker, SystemSecretNames, ValidationResolver, WorkerVersionNotFoundError, apiKeyMetaSchema, apiKeyOutputSchema, apiKeyQuerySchema, applyLibraryUpdate, artifactOutputSchema, artifactQuerySchema, backendUnlockMethodInputSchema, backendUnlockMethodMetaSchema, codebaseLibrary, codebaseProjectModelStorage, collectionQueryResult, collectionQuerySchema, createAsyncBatcher, databaseProjectModelStorage, diffLibraries, entityDetailsOutputSchema, entityOutputSchema, entityQuerySchema, entityReferenceOutputSchema, entitySnapshotDetailsOutputSchema, entitySnapshotListItemOutputSchema, entitySnapshotOutputSchema, extractDigestFromImage, finalInstanceOperationStatuses, finalOperationStatuses, forSchema, getAllDependents, getMatchedInjectionInstanceInputs, getResolvedHubInputs, getResolvedInjectionInstanceInputs, getResolvedInstanceInputs, getResolvedInstanceOutputs, getWorkerIdentity, globalProjectSpace, hasObjectMeta, hostPulumiBackend, instanceCustomStatusInputSchema, instanceLockEventSchema, instanceLockOutputSchema, instanceStateEventSchema, int32ToBytes, isFinalOperationStatus, isInstanceDeployed, isTransientInstanceOperationStatus, isTransientOperationStatus, isVirtualGhostInstance, librarySpecSchema, operationEventSchema, operationLaunchInputSchema, operationMetaSchema, operationOptionsSchema, operationOutputSchema, operationPhaseInstanceSchema, operationPhaseSchema, operationPhaseTypeSchema, operationPlanInputSchema, operationStatusSchema, operationTypeSchema, pageDetailsOutputSchema, pageOutputSchema, pageQuerySchema, projectInputSchema, projectModelEventSchema, projectModelStorageSpecSchema, projectOutputSchema, projectUnlockStateSchema, projectUnlockSuiteSchema, pulumiBackendSpecSchema, resolveEffectiveOutputType, resolverFactories, secretOutputSchema, secretQuerySchema, serviceAccountOutputSchema, serviceAccountQuerySchema, stableInstanceInputSchema, stableJsonStringify, terminalDetailsOutputSchema, terminalOutputSchema, terminalQuerySchema, terminalSessionOutputSchema, terminalStatusSchema, toApiKeyOutput, toCommonEntityMeta, toPageOutput, toSecretOutput, toTerminalDetailsOutput, toTerminalOutput, toTerminalSessionOutput, toWorkerOutput, toWorkerVersionOutput, triggerOutputSchema, triggerQuerySchema, unlockMethodInputSchema, unlockMethodMetaSchema, unlockMethodOutputSchema, unlockMethodType, waitAll, workerOutputSchema, workerQuerySchema, workerUnitRegistrationEventSchema, workerVersionOutputSchema, workerVersionStatusEventSchema, workerVersionStatusSchema };
1889
+ //# sourceMappingURL=chunk-52MY2TCE.js.map
1890
+ //# sourceMappingURL=chunk-52MY2TCE.js.map