@highstate/backend 0.9.16 → 0.9.19

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 (302) hide show
  1. package/dist/chunk-5WVU2AK4.js +1535 -0
  2. package/dist/chunk-5WVU2AK4.js.map +1 -0
  3. package/dist/chunk-I7BWSAN6.js +49 -0
  4. package/dist/chunk-I7BWSAN6.js.map +1 -0
  5. package/dist/{chunk-RCB4AFGD.js → chunk-VB4YL327.js} +51 -71
  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 +5 -4
  10. package/dist/index.js +7676 -6634
  11. package/dist/index.js.map +1 -1
  12. package/dist/library/package-resolution-worker.js +8 -6
  13. package/dist/library/package-resolution-worker.js.map +1 -1
  14. package/dist/library/worker/main.js +63 -58
  15. package/dist/library/worker/main.js.map +1 -1
  16. package/dist/shared/index.js +3 -216
  17. package/dist/shared/index.js.map +1 -1
  18. package/package.json +23 -11
  19. package/prisma/backend/_schema/layout.prisma +7 -0
  20. package/prisma/backend/_schema/library.prisma +17 -0
  21. package/prisma/backend/_schema/project.prisma +101 -0
  22. package/prisma/backend/_schema/pulumi.prisma +17 -0
  23. package/prisma/backend/postgresql/main.prisma +17 -0
  24. package/prisma/backend/sqlite/main.prisma +17 -0
  25. package/prisma/backend/sqlite/migrations/20250817070609_initiial/migration.sql +34 -0
  26. package/prisma/backend/sqlite/migrations/20250817104948_add_fields/migration.sql +59 -0
  27. package/prisma/backend/sqlite/migrations/20250818082732_add_models/migration.sql +41 -0
  28. package/prisma/backend/sqlite/migrations/20250818083106_a/migration.sql +19 -0
  29. package/prisma/backend/sqlite/migrations/20250818101945_hi/migration.sql +1 -0
  30. package/prisma/backend/sqlite/migrations/20250819082315_a/migration.sql +5 -0
  31. package/prisma/backend/sqlite/migrations/migration_lock.toml +3 -0
  32. package/prisma/project/api-key.prisma +27 -0
  33. package/prisma/project/artifact.prisma +52 -0
  34. package/prisma/project/custom-status.prisma +46 -0
  35. package/prisma/project/evaluation.prisma +35 -0
  36. package/prisma/project/instance.prisma +160 -0
  37. package/prisma/project/layout.prisma +23 -0
  38. package/prisma/project/lock.prisma +18 -0
  39. package/prisma/project/main.prisma +17 -0
  40. package/prisma/project/migrations/20250816081310_initial/migration.sql +300 -0
  41. package/prisma/project/migrations/20250816082523_test/migration.sql +72 -0
  42. package/prisma/project/migrations/20250818065643_update/migration.sql +42 -0
  43. package/prisma/project/migrations/20250818070758_a/migration.sql +8 -0
  44. package/prisma/project/migrations/20250818070913_a/migration.sql +8 -0
  45. package/prisma/project/migrations/20250818082720_add_motels/migration.sql +11 -0
  46. package/prisma/project/migrations/20250818112523_hello/migration.sql +35 -0
  47. package/prisma/project/migrations/20250819082305_a/migration.sql +14 -0
  48. package/prisma/project/migrations/20250819165004_add_missing_fields/migration.sql +216 -0
  49. package/prisma/project/migrations/20250819171309_a/migration.sql +22 -0
  50. package/prisma/project/migrations/20250820113949_a/migration.sql +66 -0
  51. package/prisma/project/migrations/20250820144256_b/migration.sql +31 -0
  52. package/prisma/project/migrations/20250820145547_a/migration.sql +24 -0
  53. package/prisma/project/migrations/20250820182517_b/migration.sql +2 -0
  54. package/prisma/project/migrations/20250821172324_a/migration.sql +2 -0
  55. package/prisma/project/migrations/20250822081339_a/migration.sql +219 -0
  56. package/prisma/project/migrations/20250822083742_b/migration.sql +1 -0
  57. package/prisma/project/migrations/20250822105134_boom/migration.sql +1 -0
  58. package/prisma/project/migrations/20250822141028_b/migration.sql +1 -0
  59. package/prisma/project/migrations/20250822142342_b/migration.sql +16 -0
  60. package/prisma/project/migrations/20250824072720_a/migration.sql +1 -0
  61. package/prisma/project/migrations/20250824093656_b/migration.sql +21 -0
  62. package/prisma/project/migrations/20250825082518_a/migration.sql +1 -0
  63. package/prisma/project/migrations/20250825085343_b/migration.sql +1 -0
  64. package/prisma/project/migrations/20250825091312_a/migration.sql +1 -0
  65. package/prisma/project/migrations/20250903095431_hi/migration.sql +44 -0
  66. package/prisma/project/migrations/20250903174255_a/migration.sql +24 -0
  67. package/prisma/project/migrations/20250908095205_hi/migration.sql +18 -0
  68. package/prisma/project/migrations/20250909155857_hi/migration.sql +15 -0
  69. package/prisma/project/migrations/migration_lock.toml +3 -0
  70. package/prisma/project/model.prisma +37 -0
  71. package/prisma/project/operation.prisma +148 -0
  72. package/prisma/project/page.prisma +41 -0
  73. package/prisma/project/secret.prisma +42 -0
  74. package/prisma/project/service-account.prisma +36 -0
  75. package/prisma/project/terminal.prisma +90 -0
  76. package/prisma/project/trigger.prisma +31 -0
  77. package/prisma/project/unlock-method.prisma +32 -0
  78. package/prisma/project/worker.prisma +138 -0
  79. package/src/artifact/abstractions.ts +13 -13
  80. package/src/artifact/encryption.ts +31 -15
  81. package/src/artifact/factory.ts +7 -10
  82. package/src/artifact/local.ts +33 -50
  83. package/src/business/api-key.ts +24 -36
  84. package/src/business/artifact.test.ts +978 -0
  85. package/src/business/artifact.ts +136 -215
  86. package/src/business/evaluation.ts +328 -0
  87. package/src/business/index.ts +5 -1
  88. package/src/business/instance-lock.test.ts +1060 -0
  89. package/src/business/instance-lock.ts +387 -77
  90. package/src/business/instance-state.test.ts +735 -0
  91. package/src/business/instance-state.ts +604 -217
  92. package/src/business/operation.test.ts +439 -0
  93. package/src/business/operation.ts +174 -208
  94. package/src/business/project-model.ts +258 -0
  95. package/src/business/project-unlock.ts +172 -112
  96. package/src/business/project.ts +407 -0
  97. package/src/business/secret.test.ts +513 -0
  98. package/src/business/secret.ts +194 -131
  99. package/src/business/settings.test.ts +695 -0
  100. package/src/business/settings.ts +855 -0
  101. package/src/business/terminal-session.ts +90 -0
  102. package/src/business/unit-extra.test.ts +539 -0
  103. package/src/business/unit-extra.ts +160 -0
  104. package/src/business/worker.test.ts +391 -0
  105. package/src/business/worker.ts +250 -114
  106. package/src/common/codebase.ts +65 -0
  107. package/src/common/index.ts +3 -2
  108. package/src/common/logger.ts +5 -0
  109. package/src/common/utils.ts +4 -3
  110. package/src/config.ts +15 -12
  111. package/src/database/_generated/backend/postgresql/client.ts +72 -0
  112. package/src/database/_generated/backend/postgresql/commonInputTypes.ts +350 -0
  113. package/src/database/_generated/backend/postgresql/enums.ts +13 -0
  114. package/src/database/_generated/backend/postgresql/internal/class.ts +320 -0
  115. package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +1238 -0
  116. package/src/database/_generated/backend/postgresql/models/Library.ts +1263 -0
  117. package/src/database/_generated/backend/postgresql/models/Project.ts +2175 -0
  118. package/src/database/_generated/backend/postgresql/models/ProjectModelStorage.ts +1263 -0
  119. package/src/database/_generated/backend/postgresql/models/ProjectSpace.ts +1602 -0
  120. package/src/database/_generated/backend/postgresql/models/PulumiBackend.ts +1263 -0
  121. package/src/database/_generated/backend/postgresql/models/UserWorkspaseLayout.ts +1065 -0
  122. package/src/database/_generated/backend/postgresql/models.ts +16 -0
  123. package/src/database/_generated/backend/postgresql/pjtg.ts +182 -0
  124. package/src/database/_generated/backend/sqlite/client.ts +72 -0
  125. package/src/database/_generated/backend/sqlite/commonInputTypes.ts +331 -0
  126. package/src/database/_generated/backend/sqlite/enums.ts +13 -0
  127. package/src/database/_generated/backend/sqlite/internal/class.ts +318 -0
  128. package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +1207 -0
  129. package/src/database/_generated/backend/sqlite/models/Library.ts +1261 -0
  130. package/src/database/_generated/backend/sqlite/models/Project.ts +2169 -0
  131. package/src/database/_generated/backend/sqlite/models/ProjectModelStorage.ts +1261 -0
  132. package/src/database/_generated/backend/sqlite/models/ProjectSpace.ts +1599 -0
  133. package/src/database/_generated/backend/sqlite/models/PulumiBackend.ts +1261 -0
  134. package/src/database/_generated/backend/sqlite/models/UserWorkspaseLayout.ts +1063 -0
  135. package/src/database/_generated/backend/sqlite/models.ts +16 -0
  136. package/src/database/_generated/backend/sqlite/pjtg.ts +182 -0
  137. package/src/database/_generated/project/client.ts +204 -0
  138. package/src/database/_generated/project/commonInputTypes.ts +827 -0
  139. package/src/database/_generated/project/enums.ts +104 -0
  140. package/src/database/_generated/project/internal/class.ts +479 -0
  141. package/src/database/_generated/project/internal/prismaNamespace.ts +2974 -0
  142. package/src/database/_generated/project/models/ApiKey.ts +1506 -0
  143. package/src/database/_generated/project/models/Artifact.ts +2051 -0
  144. package/src/database/_generated/project/models/HubModel.ts +1125 -0
  145. package/src/database/_generated/project/models/InstanceCustomStatus.ts +1713 -0
  146. package/src/database/_generated/project/models/InstanceEvaluationState.ts +1312 -0
  147. package/src/database/_generated/project/models/InstanceLock.ts +1268 -0
  148. package/src/database/_generated/project/models/InstanceModel.ts +1125 -0
  149. package/src/database/_generated/project/models/InstanceOperationState.ts +1707 -0
  150. package/src/database/_generated/project/models/InstanceState.ts +4613 -0
  151. package/src/database/_generated/project/models/Operation.ts +1647 -0
  152. package/src/database/_generated/project/models/OperationLog.ts +1455 -0
  153. package/src/database/_generated/project/models/Page.ts +1838 -0
  154. package/src/database/_generated/project/models/Secret.ts +1692 -0
  155. package/src/database/_generated/project/models/ServiceAccount.ts +2165 -0
  156. package/src/database/_generated/project/models/Terminal.ts +2038 -0
  157. package/src/database/_generated/project/models/TerminalSession.ts +1454 -0
  158. package/src/database/_generated/project/models/TerminalSessionLog.ts +1280 -0
  159. package/src/database/_generated/project/models/Trigger.ts +1430 -0
  160. package/src/database/_generated/project/models/UnlockMethod.ts +1220 -0
  161. package/src/database/_generated/project/models/UserCompositeViewport.ts +1280 -0
  162. package/src/database/_generated/project/models/UserProjectViewport.ts +1059 -0
  163. package/src/database/_generated/project/models/Worker.ts +1459 -0
  164. package/src/database/_generated/project/models/WorkerUnitRegistration.ts +1524 -0
  165. package/src/database/_generated/project/models/WorkerVersion.ts +1974 -0
  166. package/src/database/_generated/project/models/WorkerVersionLog.ts +1318 -0
  167. package/src/database/_generated/project/models.ts +35 -0
  168. package/src/database/_generated/project/pjtg.ts +182 -0
  169. package/src/database/abstractions.ts +19 -0
  170. package/src/database/factory.ts +37 -0
  171. package/src/database/index.ts +6 -0
  172. package/src/database/local/backend.ts +134 -0
  173. package/src/database/local/index.ts +3 -0
  174. package/src/database/local/meta.ts +46 -0
  175. package/src/database/local/prisma.config.ts +25 -0
  176. package/src/database/local/project.ts +39 -0
  177. package/src/database/manager.ts +181 -0
  178. package/src/database/migrate.ts +35 -0
  179. package/src/database/prisma.ts +56 -0
  180. package/src/database/well-known.ts +38 -0
  181. package/src/index.ts +4 -4
  182. package/src/library/abstractions.ts +21 -14
  183. package/src/library/factory.ts +1 -1
  184. package/src/library/local.ts +86 -38
  185. package/src/library/package-resolution-worker.ts +1 -1
  186. package/src/library/worker/evaluator.ts +61 -48
  187. package/src/library/worker/loader.lite.ts +14 -1
  188. package/src/library/worker/main.ts +9 -16
  189. package/src/library/worker/protocol.ts +0 -12
  190. package/src/lock/manager.ts +12 -7
  191. package/src/orchestrator/manager.ts +198 -131
  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 +235 -583
  203. package/src/orchestrator/operation.ts +446 -904
  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 +49 -25
  217. package/src/pubsub/memory.ts +31 -0
  218. package/src/runner/abstractions.ts +38 -26
  219. package/src/runner/artifact-env.ts +17 -6
  220. package/src/runner/factory.ts +6 -6
  221. package/src/runner/force-abort.ts +3 -6
  222. package/src/runner/local.ts +79 -72
  223. package/src/runner/pulumi.ts +26 -63
  224. package/src/services.ts +214 -103
  225. package/src/shared/models/backend/index.ts +3 -1
  226. package/src/shared/models/backend/library.ts +12 -4
  227. package/src/shared/models/backend/project.ts +43 -23
  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 -109
  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 -56
  236. package/src/shared/models/project/artifact.ts +15 -105
  237. package/src/shared/models/project/custom-status.ts +12 -0
  238. package/src/shared/models/project/index.ts +9 -9
  239. package/src/shared/models/project/lock.ts +10 -78
  240. package/src/shared/models/project/model.ts +32 -0
  241. package/src/shared/models/project/operation.ts +222 -99
  242. package/src/shared/models/project/page.ts +37 -48
  243. package/src/shared/models/project/secret.ts +29 -103
  244. package/src/shared/models/project/service-account.ts +12 -17
  245. package/src/shared/models/project/state.ts +100 -390
  246. package/src/shared/models/project/terminal.ts +75 -89
  247. package/src/shared/models/project/trigger.ts +13 -49
  248. package/src/shared/models/project/unlock-method.ts +21 -20
  249. package/src/shared/models/project/worker.ts +89 -88
  250. package/src/shared/resolvers/graph-resolver.ts +62 -26
  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 +48 -6
  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 +29 -9
  257. package/src/shared/utils/index.ts +1 -1
  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 +31 -0
  266. package/src/unlock/index.ts +2 -0
  267. package/src/unlock/memory.ts +27 -0
  268. package/src/worker/abstractions.ts +7 -4
  269. package/src/worker/docker.ts +14 -19
  270. package/src/worker/manager.ts +376 -79
  271. package/dist/chunk-RCB4AFGD.js.map +0 -1
  272. package/dist/chunk-WHALQHEZ.js +0 -2017
  273. package/dist/chunk-WHALQHEZ.js.map +0 -1
  274. package/src/business/backend-unlock.ts +0 -10
  275. package/src/common/performance.ts +0 -44
  276. package/src/hotstate/abstractions.ts +0 -48
  277. package/src/hotstate/factory.ts +0 -17
  278. package/src/hotstate/index.ts +0 -3
  279. package/src/hotstate/manager.ts +0 -192
  280. package/src/hotstate/memory.ts +0 -100
  281. package/src/hotstate/validation.ts +0 -101
  282. package/src/project/abstractions.ts +0 -102
  283. package/src/project/factory.ts +0 -11
  284. package/src/project/index.ts +0 -3
  285. package/src/project/local.ts +0 -469
  286. package/src/project/manager.ts +0 -574
  287. package/src/pubsub/local.ts +0 -36
  288. package/src/pubsub/validation.ts +0 -33
  289. package/src/shared/models/project/component.ts +0 -45
  290. package/src/shared/models/project/instance.ts +0 -74
  291. package/src/state/abstractions.ts +0 -450
  292. package/src/state/encryption.ts +0 -59
  293. package/src/state/factory.ts +0 -20
  294. package/src/state/index.ts +0 -6
  295. package/src/state/local/backend.ts +0 -299
  296. package/src/state/local/collection.ts +0 -342
  297. package/src/state/local/index.ts +0 -2
  298. package/src/state/manager.ts +0 -819
  299. package/src/state/repository/index.ts +0 -2
  300. package/src/state/repository/repository.index.ts +0 -193
  301. package/src/state/repository/repository.ts +0 -458
  302. /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
+ }