@highstate/backend 0.9.18 → 0.9.20

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 (331) hide show
  1. package/dist/{chunk-OU5OQBLB.js → chunk-I7BWSAN6.js} +3 -28
  2. package/dist/{chunk-OU5OQBLB.js.map → chunk-I7BWSAN6.js.map} +1 -1
  3. package/dist/chunk-RC6Q3XQQ.js +1547 -0
  4. package/dist/chunk-RC6Q3XQQ.js.map +1 -0
  5. package/dist/chunk-VB4YL327.js +139 -0
  6. package/dist/chunk-VB4YL327.js.map +1 -0
  7. package/dist/database/local/prisma.config.js +26 -0
  8. package/dist/database/local/prisma.config.js.map +1 -0
  9. package/dist/highstate.manifest.json +2 -1
  10. package/dist/index.js +7590 -7289
  11. package/dist/index.js.map +1 -1
  12. package/dist/library/package-resolution-worker.js +1 -1
  13. package/dist/library/package-resolution-worker.js.map +1 -1
  14. package/dist/library/worker/main.js +35 -29
  15. package/dist/library/worker/main.js.map +1 -1
  16. package/dist/shared/index.js +2 -2
  17. package/package.json +18 -9
  18. package/prisma/backend/_schema/layout.prisma +7 -0
  19. package/prisma/backend/_schema/library.prisma +17 -0
  20. package/prisma/backend/_schema/project.prisma +101 -0
  21. package/prisma/backend/_schema/pulumi.prisma +17 -0
  22. package/prisma/backend/postgresql/main.prisma +17 -0
  23. package/prisma/backend/sqlite/main.prisma +17 -0
  24. package/prisma/backend/sqlite/migrations/20250817070609_initiial/migration.sql +34 -0
  25. package/prisma/backend/sqlite/migrations/20250817104948_add_fields/migration.sql +59 -0
  26. package/prisma/backend/sqlite/migrations/20250818082732_add_models/migration.sql +41 -0
  27. package/prisma/backend/sqlite/migrations/20250818083106_a/migration.sql +19 -0
  28. package/prisma/backend/sqlite/migrations/20250818101945_hi/migration.sql +1 -0
  29. package/prisma/backend/sqlite/migrations/20250819082315_a/migration.sql +5 -0
  30. package/prisma/backend/sqlite/migrations/migration_lock.toml +3 -0
  31. package/prisma/project/api-key.prisma +32 -0
  32. package/prisma/project/artifact.prisma +52 -0
  33. package/prisma/project/custom-status.prisma +46 -0
  34. package/prisma/project/evaluation.prisma +45 -0
  35. package/prisma/project/instance.prisma +157 -0
  36. package/prisma/project/layout.prisma +23 -0
  37. package/prisma/project/lock.prisma +18 -0
  38. package/prisma/project/main.prisma +17 -0
  39. package/prisma/project/migrations/20250816081310_initial/migration.sql +300 -0
  40. package/prisma/project/migrations/20250816082523_test/migration.sql +72 -0
  41. package/prisma/project/migrations/20250818065643_update/migration.sql +42 -0
  42. package/prisma/project/migrations/20250818070758_a/migration.sql +8 -0
  43. package/prisma/project/migrations/20250818070913_a/migration.sql +8 -0
  44. package/prisma/project/migrations/20250818082720_add_motels/migration.sql +11 -0
  45. package/prisma/project/migrations/20250818112523_hello/migration.sql +35 -0
  46. package/prisma/project/migrations/20250819082305_a/migration.sql +14 -0
  47. package/prisma/project/migrations/20250819165004_add_missing_fields/migration.sql +216 -0
  48. package/prisma/project/migrations/20250819171309_a/migration.sql +22 -0
  49. package/prisma/project/migrations/20250820113949_a/migration.sql +66 -0
  50. package/prisma/project/migrations/20250820144256_b/migration.sql +31 -0
  51. package/prisma/project/migrations/20250820145547_a/migration.sql +24 -0
  52. package/prisma/project/migrations/20250820182517_b/migration.sql +2 -0
  53. package/prisma/project/migrations/20250821172324_a/migration.sql +2 -0
  54. package/prisma/project/migrations/20250822081339_a/migration.sql +219 -0
  55. package/prisma/project/migrations/20250822083742_b/migration.sql +1 -0
  56. package/prisma/project/migrations/20250822105134_boom/migration.sql +1 -0
  57. package/prisma/project/migrations/20250822141028_b/migration.sql +1 -0
  58. package/prisma/project/migrations/20250822142342_b/migration.sql +16 -0
  59. package/prisma/project/migrations/20250824072720_a/migration.sql +1 -0
  60. package/prisma/project/migrations/20250824093656_b/migration.sql +21 -0
  61. package/prisma/project/migrations/20250825082518_a/migration.sql +1 -0
  62. package/prisma/project/migrations/20250825085343_b/migration.sql +1 -0
  63. package/prisma/project/migrations/20250825091312_a/migration.sql +1 -0
  64. package/prisma/project/migrations/20250903095431_hi/migration.sql +44 -0
  65. package/prisma/project/migrations/20250903174255_a/migration.sql +24 -0
  66. package/prisma/project/migrations/20250908095205_hi/migration.sql +18 -0
  67. package/prisma/project/migrations/20250909155857_hi/migration.sql +15 -0
  68. package/prisma/project/migrations/migration_lock.toml +3 -0
  69. package/prisma/project/model.prisma +37 -0
  70. package/prisma/project/operation.prisma +148 -0
  71. package/prisma/project/page.prisma +49 -0
  72. package/prisma/project/secret.prisma +54 -0
  73. package/prisma/project/service-account.prisma +42 -0
  74. package/prisma/project/terminal.prisma +107 -0
  75. package/prisma/project/trigger.prisma +37 -0
  76. package/prisma/project/unlock-method.prisma +46 -0
  77. package/prisma/project/worker.prisma +169 -0
  78. package/src/artifact/abstractions.ts +13 -13
  79. package/src/artifact/encryption.ts +30 -54
  80. package/src/artifact/factory.ts +6 -9
  81. package/src/artifact/local.ts +33 -46
  82. package/src/business/api-key.ts +24 -36
  83. package/src/business/artifact.test.ts +978 -0
  84. package/src/business/artifact.ts +136 -216
  85. package/src/business/evaluation.ts +328 -0
  86. package/src/business/index.ts +5 -2
  87. package/src/business/instance-lock.test.ts +1060 -0
  88. package/src/business/instance-lock.ts +387 -78
  89. package/src/business/instance-state.test.ts +735 -0
  90. package/src/business/instance-state.ts +582 -337
  91. package/src/business/operation.test.ts +439 -0
  92. package/src/business/operation.ts +174 -208
  93. package/src/business/project-model.ts +258 -0
  94. package/src/business/project-unlock.ts +168 -126
  95. package/src/business/project.ts +287 -179
  96. package/src/business/secret.test.ts +469 -130
  97. package/src/business/secret.ts +177 -217
  98. package/src/business/settings.test.ts +695 -0
  99. package/src/business/settings.ts +855 -0
  100. package/src/business/terminal-session.ts +90 -0
  101. package/src/business/unit-extra.test.ts +539 -0
  102. package/src/business/unit-extra.ts +160 -0
  103. package/src/business/worker.test.ts +356 -579
  104. package/src/business/worker.ts +238 -339
  105. package/src/common/codebase.ts +65 -0
  106. package/src/common/index.ts +3 -5
  107. package/src/common/logger.ts +5 -0
  108. package/src/common/utils.ts +4 -3
  109. package/src/config.ts +10 -11
  110. package/src/database/_generated/backend/postgresql/client.ts +72 -0
  111. package/src/database/_generated/backend/postgresql/commonInputTypes.ts +350 -0
  112. package/src/database/_generated/backend/postgresql/enums.ts +13 -0
  113. package/src/database/_generated/backend/postgresql/internal/class.ts +320 -0
  114. package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +1238 -0
  115. package/src/database/_generated/backend/postgresql/models/Library.ts +1263 -0
  116. package/src/database/_generated/backend/postgresql/models/Project.ts +2175 -0
  117. package/src/database/_generated/backend/postgresql/models/ProjectModelStorage.ts +1263 -0
  118. package/src/database/_generated/backend/postgresql/models/ProjectSpace.ts +1602 -0
  119. package/src/database/_generated/backend/postgresql/models/PulumiBackend.ts +1263 -0
  120. package/src/database/_generated/backend/postgresql/models/UserWorkspaseLayout.ts +1065 -0
  121. package/src/database/_generated/backend/postgresql/models.ts +16 -0
  122. package/src/database/_generated/backend/postgresql/pjtg.ts +182 -0
  123. package/src/database/_generated/backend/sqlite/client.ts +72 -0
  124. package/src/database/_generated/backend/sqlite/commonInputTypes.ts +331 -0
  125. package/src/database/_generated/backend/sqlite/enums.ts +13 -0
  126. package/src/database/_generated/backend/sqlite/internal/class.ts +318 -0
  127. package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +1207 -0
  128. package/src/database/_generated/backend/sqlite/models/Library.ts +1261 -0
  129. package/src/database/_generated/backend/sqlite/models/Project.ts +2169 -0
  130. package/src/database/_generated/backend/sqlite/models/ProjectModelStorage.ts +1261 -0
  131. package/src/database/_generated/backend/sqlite/models/ProjectSpace.ts +1599 -0
  132. package/src/database/_generated/backend/sqlite/models/PulumiBackend.ts +1261 -0
  133. package/src/database/_generated/backend/sqlite/models/UserWorkspaseLayout.ts +1063 -0
  134. package/src/database/_generated/backend/sqlite/models.ts +16 -0
  135. package/src/database/_generated/backend/sqlite/pjtg.ts +182 -0
  136. package/src/database/_generated/project/client.ts +204 -0
  137. package/src/database/_generated/project/commonInputTypes.ts +827 -0
  138. package/src/database/_generated/project/enums.ts +104 -0
  139. package/src/database/_generated/project/internal/class.ts +479 -0
  140. package/src/database/_generated/project/internal/prismaNamespace.ts +2974 -0
  141. package/src/database/_generated/project/models/ApiKey.ts +1506 -0
  142. package/src/database/_generated/project/models/Artifact.ts +2051 -0
  143. package/src/database/_generated/project/models/HubModel.ts +1125 -0
  144. package/src/database/_generated/project/models/InstanceCustomStatus.ts +1713 -0
  145. package/src/database/_generated/project/models/InstanceEvaluationState.ts +1312 -0
  146. package/src/database/_generated/project/models/InstanceLock.ts +1268 -0
  147. package/src/database/_generated/project/models/InstanceModel.ts +1125 -0
  148. package/src/database/_generated/project/models/InstanceOperationState.ts +1707 -0
  149. package/src/database/_generated/project/models/InstanceState.ts +4613 -0
  150. package/src/database/_generated/project/models/Operation.ts +1647 -0
  151. package/src/database/_generated/project/models/OperationLog.ts +1455 -0
  152. package/src/database/_generated/project/models/Page.ts +1838 -0
  153. package/src/database/_generated/project/models/Secret.ts +1692 -0
  154. package/src/database/_generated/project/models/ServiceAccount.ts +2165 -0
  155. package/src/database/_generated/project/models/Terminal.ts +2038 -0
  156. package/src/database/_generated/project/models/TerminalSession.ts +1454 -0
  157. package/src/database/_generated/project/models/TerminalSessionLog.ts +1280 -0
  158. package/src/database/_generated/project/models/Trigger.ts +1430 -0
  159. package/src/database/_generated/project/models/UnlockMethod.ts +1220 -0
  160. package/src/database/_generated/project/models/UserCompositeViewport.ts +1280 -0
  161. package/src/database/_generated/project/models/UserProjectViewport.ts +1059 -0
  162. package/src/database/_generated/project/models/Worker.ts +1459 -0
  163. package/src/database/_generated/project/models/WorkerUnitRegistration.ts +1524 -0
  164. package/src/database/_generated/project/models/WorkerVersion.ts +1974 -0
  165. package/src/database/_generated/project/models/WorkerVersionLog.ts +1318 -0
  166. package/src/database/_generated/project/models.ts +35 -0
  167. package/src/database/_generated/project/pjtg.ts +182 -0
  168. package/src/database/abstractions.ts +19 -0
  169. package/src/database/factory.ts +37 -0
  170. package/src/database/index.ts +6 -0
  171. package/src/database/local/backend.ts +134 -0
  172. package/src/database/local/index.ts +3 -0
  173. package/src/database/local/meta.ts +46 -0
  174. package/src/database/local/prisma.config.ts +25 -0
  175. package/src/database/local/project.ts +39 -0
  176. package/src/database/manager.ts +181 -0
  177. package/src/database/migrate.ts +35 -0
  178. package/src/database/prisma.ts +56 -0
  179. package/src/database/well-known.ts +38 -0
  180. package/src/index.ts +4 -4
  181. package/src/library/abstractions.ts +3 -5
  182. package/src/library/factory.ts +1 -1
  183. package/src/library/local.ts +81 -26
  184. package/src/library/package-resolution-worker.ts +1 -1
  185. package/src/library/worker/evaluator.ts +40 -23
  186. package/src/library/worker/loader.lite.ts +1 -1
  187. package/src/library/worker/main.ts +3 -10
  188. package/src/library/worker/protocol.ts +0 -1
  189. package/src/lock/index.ts +0 -1
  190. package/src/lock/manager.ts +0 -10
  191. package/src/orchestrator/manager.ts +190 -104
  192. package/src/orchestrator/operation-context.ts +357 -0
  193. package/src/orchestrator/operation-plan.destroy.test.md +357 -0
  194. package/src/orchestrator/operation-plan.destroy.test.ts +775 -0
  195. package/src/orchestrator/operation-plan.fixtures.ts +213 -0
  196. package/src/orchestrator/operation-plan.md +198 -0
  197. package/src/orchestrator/operation-plan.refresh.test.md +199 -0
  198. package/src/orchestrator/operation-plan.refresh.test.ts +367 -0
  199. package/src/orchestrator/operation-plan.ts +709 -0
  200. package/src/orchestrator/operation-plan.update.test.md +485 -0
  201. package/src/orchestrator/operation-plan.update.test.ts +1066 -0
  202. package/src/orchestrator/operation-workset.ts +233 -578
  203. package/src/orchestrator/operation.ts +440 -948
  204. package/src/orchestrator/plan-test-builder.ts +267 -0
  205. package/src/project-model/abstractions.ts +118 -0
  206. package/src/project-model/backends/codebase.ts +365 -0
  207. package/src/project-model/backends/database.ts +440 -0
  208. package/src/project-model/errors.ts +81 -0
  209. package/src/project-model/factory.ts +24 -0
  210. package/src/project-model/index.ts +4 -0
  211. package/src/project-model/utils.test.ts +544 -0
  212. package/src/project-model/utils.ts +242 -0
  213. package/src/pubsub/abstractions.ts +10 -1
  214. package/src/pubsub/factory.ts +4 -4
  215. package/src/pubsub/index.ts +1 -0
  216. package/src/pubsub/manager.ts +29 -13
  217. package/src/pubsub/memory.ts +31 -0
  218. package/src/runner/abstractions.ts +40 -41
  219. package/src/runner/artifact-env.ts +19 -8
  220. package/src/runner/factory.ts +6 -6
  221. package/src/runner/force-abort.ts +3 -6
  222. package/src/runner/local.ts +74 -67
  223. package/src/runner/pulumi.ts +23 -63
  224. package/src/services.ts +181 -123
  225. package/src/shared/models/backend/index.ts +3 -1
  226. package/src/shared/models/backend/library.ts +9 -1
  227. package/src/shared/models/backend/project.ts +43 -42
  228. package/src/shared/models/backend/pulumi.ts +14 -0
  229. package/src/shared/models/backend/unlock-method.ts +1 -1
  230. package/src/shared/models/backend/well-known.ts +58 -0
  231. package/src/shared/models/base.ts +40 -26
  232. package/src/shared/models/errors.ts +82 -1
  233. package/src/shared/models/index.ts +3 -2
  234. package/src/shared/models/prisma.ts +36 -0
  235. package/src/shared/models/project/api-key.ts +37 -59
  236. package/src/shared/models/project/artifact.ts +16 -76
  237. package/src/shared/models/project/custom-status.ts +12 -0
  238. package/src/shared/models/project/index.ts +8 -7
  239. package/src/shared/models/project/lock.ts +10 -78
  240. package/src/shared/models/project/model.ts +19 -1
  241. package/src/shared/models/project/operation.ts +235 -99
  242. package/src/shared/models/project/page.ts +37 -48
  243. package/src/shared/models/project/secret.ts +29 -89
  244. package/src/shared/models/project/service-account.ts +12 -17
  245. package/src/shared/models/project/state.ts +100 -407
  246. package/src/shared/models/project/terminal.ts +75 -88
  247. package/src/shared/models/project/trigger.ts +13 -49
  248. package/src/shared/models/project/unlock-method.ts +20 -26
  249. package/src/shared/models/project/worker.ts +89 -90
  250. package/src/shared/resolvers/graph-resolver.ts +21 -0
  251. package/src/shared/resolvers/index.ts +1 -1
  252. package/src/shared/resolvers/input-hash.ts +24 -14
  253. package/src/shared/resolvers/input.ts +9 -2
  254. package/src/shared/resolvers/registry.ts +5 -4
  255. package/src/shared/resolvers/state.ts +12 -1
  256. package/src/shared/resolvers/validation.ts +7 -3
  257. package/src/shared/utils/index.ts +1 -2
  258. package/src/shared/utils/promise-tracker.ts +30 -3
  259. package/src/terminal/abstractions.ts +1 -1
  260. package/src/terminal/docker.ts +3 -3
  261. package/src/terminal/manager.ts +102 -118
  262. package/src/test-utils/database.ts +119 -0
  263. package/src/test-utils/index.ts +2 -0
  264. package/src/test-utils/services.ts +134 -0
  265. package/src/unlock/abstractions.ts +5 -23
  266. package/src/unlock/memory.ts +9 -14
  267. package/src/worker/abstractions.ts +7 -4
  268. package/src/worker/docker.ts +14 -19
  269. package/src/worker/manager.ts +366 -97
  270. package/dist/chunk-NAAIDR4U.js +0 -8499
  271. package/dist/chunk-NAAIDR4U.js.map +0 -1
  272. package/dist/chunk-Y7DXREVO.js +0 -1745
  273. package/dist/chunk-Y7DXREVO.js.map +0 -1
  274. package/dist/magic-string.es-5ABAC4JN.js +0 -1292
  275. package/dist/magic-string.es-5ABAC4JN.js.map +0 -1
  276. package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +0 -356
  277. package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +0 -274
  278. package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +0 -223
  279. package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +0 -147
  280. package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +0 -280
  281. package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +0 -360
  282. package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +0 -215
  283. package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +0 -427
  284. package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +0 -217
  285. package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +0 -132
  286. package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +0 -454
  287. package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +0 -426
  288. package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +0 -372
  289. package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +0 -383
  290. package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +0 -245
  291. package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +0 -174
  292. package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +0 -432
  293. package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +0 -220
  294. package/src/business/backend-unlock.ts +0 -10
  295. package/src/common/clock.ts +0 -18
  296. package/src/common/performance.ts +0 -44
  297. package/src/common/random.ts +0 -68
  298. package/src/common/test/index.ts +0 -2
  299. package/src/common/test/render.ts +0 -98
  300. package/src/common/test/tracer.ts +0 -359
  301. package/src/hotstate/abstractions.ts +0 -48
  302. package/src/hotstate/factory.ts +0 -17
  303. package/src/hotstate/index.ts +0 -3
  304. package/src/hotstate/manager.ts +0 -192
  305. package/src/hotstate/memory.ts +0 -100
  306. package/src/hotstate/validation.ts +0 -100
  307. package/src/lock/test.ts +0 -108
  308. package/src/project/abstractions.ts +0 -78
  309. package/src/project/evaluation.ts +0 -248
  310. package/src/project/factory.ts +0 -11
  311. package/src/project/index.ts +0 -3
  312. package/src/project/local.ts +0 -417
  313. package/src/pubsub/local.ts +0 -36
  314. package/src/pubsub/validation.ts +0 -33
  315. package/src/shared/utils/args.ts +0 -25
  316. package/src/state/abstractions.ts +0 -289
  317. package/src/state/encryption.ts +0 -98
  318. package/src/state/factory.ts +0 -20
  319. package/src/state/index.ts +0 -7
  320. package/src/state/local/backend.ts +0 -106
  321. package/src/state/local/collection.ts +0 -361
  322. package/src/state/local/index.ts +0 -2
  323. package/src/state/manager.ts +0 -890
  324. package/src/state/memory/backend.ts +0 -70
  325. package/src/state/memory/collection.ts +0 -270
  326. package/src/state/memory/index.ts +0 -2
  327. package/src/state/repository/index.ts +0 -2
  328. package/src/state/repository/repository.index.ts +0 -193
  329. package/src/state/repository/repository.ts +0 -507
  330. package/src/state/test.ts +0 -457
  331. /package/src/{state → database/local}/keyring.ts +0 -0
@@ -0,0 +1,267 @@
1
+ import type { InstanceId, InstanceModel, VersionedName } from "@highstate/contract"
2
+ import type { Operation } from "../database"
3
+ import type { InstanceState, OperationOptions } from "../shared"
4
+ import type { OperationContext } from "./operation-context"
5
+ import { getInstanceId } from "@highstate/contract"
6
+
7
+ type StateType = "upToDate" | "changed" | "error" | "undeployed" | "ghost"
8
+
9
+ export class PlanTestBuilder {
10
+ private instances = new Map<string, InstanceModel>()
11
+ private dependencies: Array<{ dependent: string; dependency: string }> = []
12
+ private stateMap = new Map<string, InstanceState>()
13
+ private requestedInstanceNames: string[] = []
14
+ private operationType: "update" | "destroy" | "recreate" | "preview" | "refresh" = "update"
15
+ private operationOptions: Partial<OperationOptions> = {}
16
+
17
+ constructor(
18
+ private readonly createContext: (
19
+ instances: InstanceModel[],
20
+ states?: InstanceState[],
21
+ ) => Promise<OperationContext>,
22
+ private readonly createTestOperation: (
23
+ type?: "update" | "destroy" | "recreate" | "preview" | "refresh",
24
+ instanceIds?: InstanceId[],
25
+ options?: Partial<OperationOptions>,
26
+ ) => Operation,
27
+ ) {}
28
+
29
+ unit(name: string, type: VersionedName = "component.v1") {
30
+ this.instances.set(name, {
31
+ id: getInstanceId(type, name),
32
+ name,
33
+ type,
34
+ kind: "unit",
35
+ parentId: undefined,
36
+ inputs: {},
37
+ args: {},
38
+ outputs: {},
39
+ resolvedInputs: {},
40
+ resolvedOutputs: {},
41
+ })
42
+ return this
43
+ }
44
+
45
+ composite(name: string, type: VersionedName = "composite.v1") {
46
+ this.instances.set(name, {
47
+ id: getInstanceId(type, name),
48
+ name,
49
+ type,
50
+ kind: "composite",
51
+ parentId: undefined,
52
+ inputs: {},
53
+ args: {},
54
+ outputs: {},
55
+ resolvedInputs: {},
56
+ resolvedOutputs: {},
57
+ })
58
+ return this
59
+ }
60
+
61
+ children(parentName: string, ...childNames: string[]) {
62
+ const parent = this.instances.get(parentName)
63
+ if (!parent) throw new Error(`Parent instance '${parentName}' not found`)
64
+
65
+ childNames.forEach(childName => {
66
+ const child = this.instances.get(childName)
67
+ if (!child) throw new Error(`Child instance '${childName}' not found`)
68
+ child.parentId = parent.id
69
+ })
70
+ return this
71
+ }
72
+
73
+ depends(dependentName: string, dependencyName: string) {
74
+ this.dependencies.push({ dependent: dependentName, dependency: dependencyName })
75
+ return this
76
+ }
77
+
78
+ // set operation type and requested instances
79
+ request(
80
+ operationType: "update" | "destroy" | "recreate" | "preview" | "refresh",
81
+ ...instanceNames: string[]
82
+ ) {
83
+ this.operationType = operationType
84
+ this.requestedInstanceNames = instanceNames
85
+ return this
86
+ }
87
+
88
+ // set operation options
89
+ options(options: Partial<OperationOptions>) {
90
+ this.operationOptions = options
91
+ return this
92
+ }
93
+
94
+ state(instanceName: string, stateType: StateType) {
95
+ const instance = this.instances.get(instanceName)
96
+ if (!instance) throw new Error(`Instance '${instanceName}' not found`)
97
+
98
+ const baseState: InstanceState = {
99
+ id: instance.id,
100
+ instanceId: instance.id,
101
+ status: "undeployed",
102
+ source: stateType === "ghost" ? "virtual" : "resident",
103
+ kind: instance.kind,
104
+ parentId: null,
105
+ parentInstanceId: instance.parentId ?? null,
106
+ inputHash: null,
107
+ outputHash: null,
108
+ dependencyOutputHash: null,
109
+ statusFields: null,
110
+ exportedArtifactIds: null,
111
+ inputHashNonce: null,
112
+ message: null,
113
+ currentResourceCount: null,
114
+ model: null,
115
+ resolvedInputs: null,
116
+ lastOperationState: undefined,
117
+ evaluationState: {} as InstanceState["evaluationState"],
118
+ }
119
+
120
+ switch (stateType) {
121
+ case "upToDate": {
122
+ baseState.status = "deployed"
123
+ baseState.inputHash = 12345 // will be updated with actual hash after workset creation
124
+ baseState.lastOperationState = {
125
+ operationId: "test-op",
126
+ stateId: instance.id,
127
+ status: "updated",
128
+ currentResourceCount: null,
129
+ totalResourceCount: null,
130
+ model: instance,
131
+ resolvedInputs: {},
132
+ startedAt: null,
133
+ finishedAt: null,
134
+ }
135
+ break
136
+ }
137
+ case "changed":
138
+ baseState.status = "deployed"
139
+ baseState.inputHash = 99999 // different hash indicates changed state
140
+ baseState.lastOperationState = {
141
+ operationId: "test-op",
142
+ stateId: instance.id,
143
+ status: "updated",
144
+ currentResourceCount: null,
145
+ totalResourceCount: null,
146
+ model: instance,
147
+ resolvedInputs: {},
148
+ startedAt: null,
149
+ finishedAt: null,
150
+ }
151
+ break
152
+ case "error":
153
+ baseState.status = "failed"
154
+ baseState.inputHash = 12345
155
+ baseState.lastOperationState = {
156
+ operationId: "test-op",
157
+ stateId: instance.id,
158
+ status: "updated",
159
+ currentResourceCount: null,
160
+ totalResourceCount: null,
161
+ model: instance,
162
+ resolvedInputs: {},
163
+ startedAt: null,
164
+ finishedAt: null,
165
+ }
166
+ break
167
+ case "undeployed":
168
+ // keep defaults
169
+ break
170
+ case "ghost":
171
+ baseState.status = "deployed"
172
+ baseState.source = "virtual"
173
+ baseState.inputHash = 12345
174
+ baseState.evaluationState = null
175
+ break
176
+ }
177
+
178
+ this.stateMap.set(instanceName, baseState)
179
+ return this
180
+ }
181
+
182
+ states(stateMap: Record<string, StateType>) {
183
+ Object.entries(stateMap).forEach(([name, type]) => {
184
+ this.state(name, type)
185
+ })
186
+ return this
187
+ }
188
+
189
+ async build(): Promise<{
190
+ context: OperationContext
191
+ operation: Operation
192
+ }> {
193
+ // apply dependencies to instance inputs
194
+ this.dependencies.forEach(({ dependent, dependency }) => {
195
+ const depInstance = this.instances.get(dependent)
196
+ const depTarget = this.instances.get(dependency)
197
+
198
+ if (!depInstance) throw new Error(`Dependent instance '${dependent}' not found`)
199
+ if (!depTarget) throw new Error(`Dependency instance '${dependency}' not found`)
200
+
201
+ // accumulate dependencies instead of overwriting
202
+ const existingDeps = depInstance.inputs?.dependency || []
203
+ depInstance.inputs = {
204
+ ...depInstance.inputs,
205
+ dependency: [...existingDeps, { instanceId: depTarget.id, output: "default" }],
206
+ }
207
+ depInstance.resolvedInputs = depInstance.inputs
208
+ })
209
+
210
+ const instances = Array.from(this.instances.values())
211
+ const states = Array.from(this.stateMap.values())
212
+
213
+ // Copy resolvedInputs from instances to states for dependency tracking
214
+ states.forEach(state => {
215
+ const instance = instances.find(i => i.id === state.instanceId)
216
+ if (instance?.resolvedInputs) {
217
+ state.resolvedInputs = instance.resolvedInputs
218
+ }
219
+ })
220
+
221
+ // get requested instance IDs
222
+ const requestedInstanceIds = this.requestedInstanceNames.map(name => {
223
+ const instance = this.instances.get(name)
224
+ if (!instance) throw new Error(`Requested instance '${name}' not found`)
225
+ return instance.id
226
+ })
227
+
228
+ // create operation
229
+ const operation = this.createTestOperation(
230
+ this.operationType,
231
+ requestedInstanceIds,
232
+ this.operationOptions,
233
+ )
234
+
235
+ // create context with instances and initial states
236
+ const context = await this.createContext(instances, states)
237
+
238
+ // update "upToDate" states with correct input hashes from context
239
+ const updatedStates = states.map(state => {
240
+ const stateEntry = Array.from(this.stateMap.entries()).find(
241
+ ([, s]) => s.instanceId === state.instanceId,
242
+ )
243
+ if (stateEntry && stateEntry[1] === state) {
244
+ const [instanceName] = stateEntry
245
+ // biome-ignore lint/style/noNonNullAssertion: hello
246
+ const instance = this.instances.get(instanceName)!
247
+
248
+ // if this was marked as upToDate, get the actual input hash from context
249
+ if (state.status === "deployed" && state.inputHash === 12345) {
250
+ try {
251
+ const { inputHash } = context.inputHashResolver.requireOutput(instance.id)
252
+ return { ...state, inputHash }
253
+ } catch {
254
+ // if can't resolve, keep original
255
+ return state
256
+ }
257
+ }
258
+ }
259
+ return state
260
+ })
261
+
262
+ // set the corrected states
263
+ context.setStates(updatedStates)
264
+
265
+ return { context, operation }
266
+ }
267
+ }
@@ -0,0 +1,118 @@
1
+ import type {
2
+ HubModel,
3
+ HubModelPatch,
4
+ InstanceModel,
5
+ InstanceModelPatch,
6
+ } from "@highstate/contract"
7
+ import type { ProjectModel, ProjectModelStorageSpec, ProjectOutput } from "../shared"
8
+
9
+ /**
10
+ * Interface for project model backends that handle storage-specific operations.
11
+ */
12
+ export interface ProjectModelBackend {
13
+ /**
14
+ * Get the instances and hubs of the project.
15
+ *
16
+ * @param project The project to get the model for.
17
+ * @param spec The project model storage specification.
18
+ * @param signal Optional abort signal.
19
+ */
20
+ getProjectModel(
21
+ project: ProjectOutput,
22
+ spec: ProjectModelStorageSpec,
23
+ signal?: AbortSignal,
24
+ ): Promise<ProjectModel>
25
+
26
+ /**
27
+ * Create an empty project model.
28
+ *
29
+ * @param project The project to create the model for.
30
+ * @param spec The project model storage specification.
31
+ */
32
+ createProjectModel(project: ProjectOutput, spec: ProjectModelStorageSpec): Promise<void>
33
+
34
+ /**
35
+ * Creates a set of instances and hubs from the blueprint.
36
+ * All changes are atomic.
37
+ *
38
+ * @param project The project to create the nodes in.
39
+ * @param spec The project model storage specification.
40
+ * @param instances The instances to apply from the blueprint.
41
+ * @param hubs The hubs to apply from the blueprint.
42
+ */
43
+ createNodes(
44
+ project: ProjectOutput,
45
+ spec: ProjectModelStorageSpec,
46
+ instances: InstanceModel[],
47
+ hubs: HubModel[],
48
+ ): Promise<void>
49
+
50
+ /**
51
+ * Rename the instance of the project.
52
+ * Changes its id and updates all references to the instance.
53
+ * Potentially dangerous, but safe when the instance is not yet created.
54
+ *
55
+ * @param project The project containing the instance.
56
+ * @param spec The project model storage specification.
57
+ * @param instanceId The ID of the instance to rename.
58
+ * @param newName The new name for the instance.
59
+ */
60
+ renameInstance(
61
+ project: ProjectOutput,
62
+ spec: ProjectModelStorageSpec,
63
+ instanceId: string,
64
+ newName: string,
65
+ ): Promise<InstanceModel>
66
+
67
+ /**
68
+ * Patches the instance of the project.
69
+ *
70
+ * @param project The project containing the instance.
71
+ * @param spec The project model storage specification.
72
+ * @param instanceId The ID of the instance to update.
73
+ * @param patch The patch to apply to the instance.
74
+ */
75
+ updateInstance(
76
+ project: ProjectOutput,
77
+ spec: ProjectModelStorageSpec,
78
+ instanceId: string,
79
+ patch: InstanceModelPatch,
80
+ ): Promise<InstanceModel>
81
+
82
+ /**
83
+ * Delete the instance of the project.
84
+ *
85
+ * @param project The project containing the instance.
86
+ * @param spec The project model storage specification.
87
+ * @param instanceId The ID of the instance to delete.
88
+ */
89
+ deleteInstance(
90
+ project: ProjectOutput,
91
+ spec: ProjectModelStorageSpec,
92
+ instanceId: string,
93
+ ): Promise<void>
94
+
95
+ /**
96
+ * Patches the hub of the project.
97
+ *
98
+ * @param project The project containing the hub.
99
+ * @param spec The project model storage specification.
100
+ * @param hubId The ID of the hub to update.
101
+ * @param patch The patch to apply to the hub.
102
+ */
103
+ updateHub(
104
+ project: ProjectOutput,
105
+ spec: ProjectModelStorageSpec,
106
+ hubId: string,
107
+ patch: HubModelPatch,
108
+ ): Promise<HubModel>
109
+
110
+ /**
111
+ * Delete the hub of the project.
112
+ *
113
+ * @param project The project containing the hub.
114
+ * @param spec The project model storage specification.
115
+ * @param hubId The ID of the hub to delete.
116
+ */
117
+ deleteHub(project: ProjectOutput, spec: ProjectModelStorageSpec, hubId: string): Promise<void>
118
+ }