@highstate/backend 0.19.1 → 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-V2NILDHS.js → chunk-52MY2TCE.js} +347 -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 +59 -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-V2NILDHS.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);
@@ -1134,6 +1403,7 @@ var InputResolver = class extends GraphResolver {
1134
1403
  kind: "instance",
1135
1404
  instance: node.instance,
1136
1405
  component: node.component,
1406
+ entities: node.entities,
1137
1407
  resolvedInputs: mapValues(node.instance.resolvedInputs, (inputs, inputName) => {
1138
1408
  const componentInput = node.component.inputs[inputName];
1139
1409
  if (!componentInput) {
@@ -1158,7 +1428,7 @@ var InputResolver = class extends GraphResolver {
1158
1428
  inputs = /* @__PURE__ */ new Map();
1159
1429
  resolvedInputsMap.set(inputName, inputs);
1160
1430
  }
1161
- inputs.set(`${input.input.instanceId}:${input.input.output}`, input);
1431
+ inputs.set(inputKey(input.input), input);
1162
1432
  };
1163
1433
  const addInstanceInput = (inputName, input) => {
1164
1434
  const componentInput = node.component.inputs[inputName];
@@ -1176,15 +1446,35 @@ var InputResolver = class extends GraphResolver {
1176
1446
  return;
1177
1447
  }
1178
1448
  if (isUnitModel(component)) {
1179
- addInstanceResult(inputName, { input, type: componentInput.type });
1449
+ addInstanceResult(inputName, {
1450
+ input,
1451
+ type: this.resolveOutputTypeForInput(input, componentInput.type)
1452
+ });
1180
1453
  return;
1181
1454
  }
1182
1455
  if (resolvedOutputs) {
1183
1456
  for (const output of resolvedOutputs) {
1184
- 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
+ });
1185
1472
  }
1186
1473
  } else {
1187
- addInstanceResult(inputName, { input, type: componentInput.type });
1474
+ addInstanceResult(inputName, {
1475
+ input,
1476
+ type: this.resolveOutputTypeForInput(input, componentInput.type)
1477
+ });
1188
1478
  }
1189
1479
  };
1190
1480
  for (const [inputName, inputs] of Object.entries(node.instance.inputs ?? {})) {
@@ -1197,7 +1487,7 @@ var InputResolver = class extends GraphResolver {
1197
1487
  for (const injectionInput of node.instance.injectionInputs ?? []) {
1198
1488
  const { resolvedInputs: resolvedInputs2 } = getHubOutput(injectionInput);
1199
1489
  for (const input of resolvedInputs2) {
1200
- injectionInputs.set(`${input.input.instanceId}:${input.input.output}`, input);
1490
+ injectionInputs.set(inputKey(input.input), input);
1201
1491
  }
1202
1492
  }
1203
1493
  for (const [inputName, componentInput] of Object.entries(node.component.inputs ?? {})) {
@@ -1206,13 +1496,13 @@ var InputResolver = class extends GraphResolver {
1206
1496
  for (const hubInput of hubInputs) {
1207
1497
  const { resolvedInputs: resolvedInputs2 } = getHubOutput(hubInput);
1208
1498
  for (const input of resolvedInputs2) {
1209
- allInputs.set(`${input.input.instanceId}:${input.input.output}`, input);
1499
+ allInputs.set(inputKey(input.input), input);
1210
1500
  }
1211
1501
  }
1212
1502
  for (const input of allInputs.values()) {
1213
1503
  if (input.type === componentInput.type) {
1214
1504
  addInstanceInput(inputName, input.input);
1215
- const key = `${input.input.instanceId}:${input.input.output}`;
1505
+ const key = inputKey(input.input);
1216
1506
  if (injectionInputs.has(key)) {
1217
1507
  matchedInjectionInputs.set(key, input);
1218
1508
  }
@@ -1229,6 +1519,7 @@ var InputResolver = class extends GraphResolver {
1229
1519
  kind: "instance",
1230
1520
  instance: node.instance,
1231
1521
  component: node.component,
1522
+ entities: node.entities,
1232
1523
  resolvedInputs,
1233
1524
  resolvedOutputs: node.instance.resolvedOutputs,
1234
1525
  resolvedInjectionInputs: Array.from(injectionInputs.values()),
@@ -1386,6 +1677,43 @@ async function waitAll(promises) {
1386
1677
  );
1387
1678
  }
1388
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
+
1389
1717
  // src/shared/resolvers/input-hash.ts
1390
1718
  var InputHashResolver = class extends GraphResolver {
1391
1719
  getNodeDependencies({ resolvedInputs }) {
@@ -1424,11 +1752,11 @@ var InputHashResolver = class extends GraphResolver {
1424
1752
  const inputHashSink = [...selfHashSink];
1425
1753
  const sortedInputs = Object.entries(resolvedInputs).sort(([a], [b]) => a.localeCompare(b));
1426
1754
  const dependencyInstanceIds = /* @__PURE__ */ new Set();
1427
- for (const [inputKey, inputs] of sortedInputs) {
1755
+ for (const [inputKey2, inputs] of sortedInputs) {
1428
1756
  if (Object.keys(inputs).length === 0) {
1429
1757
  continue;
1430
1758
  }
1431
- inputHashSink.push(Buffer.from(inputKey));
1759
+ inputHashSink.push(Buffer.from(inputKey2));
1432
1760
  const instanceIds = inputs.map((input) => input.input.instanceId).sort();
1433
1761
  for (const instanceId of instanceIds) {
1434
1762
  const dependency = this.outputs.get(instanceId);
@@ -1557,6 +1885,6 @@ var resolverFactories = {
1557
1885
  ValidationResolver
1558
1886
  };
1559
1887
 
1560
- 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 };
1561
- //# sourceMappingURL=chunk-V2NILDHS.js.map
1562
- //# sourceMappingURL=chunk-V2NILDHS.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