@highstate/backend 0.9.21 → 0.9.23

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 (49) hide show
  1. package/dist/{chunk-JNUJ4LTX.js → chunk-5LYHHLFW.js} +6 -9
  2. package/dist/chunk-5LYHHLFW.js.map +1 -0
  3. package/dist/index.js +42 -52
  4. package/dist/index.js.map +1 -1
  5. package/dist/library/package-resolution-worker.js +1 -1
  6. package/dist/library/package-resolution-worker.js.map +1 -1
  7. package/dist/shared/index.js +1 -1
  8. package/package.json +3 -3
  9. package/prisma/backend/postgresql/main.prisma +1 -1
  10. package/prisma/backend/sqlite/main.prisma +2 -2
  11. package/prisma/project/instance.prisma +5 -5
  12. package/prisma/project/main.prisma +2 -2
  13. package/prisma/project/migrations/20250921092621_b/migration.sql +33 -0
  14. package/prisma/project/migrations/20250921093911_b/migration.sql +1 -0
  15. package/prisma/project/operation.prisma +3 -0
  16. package/src/business/instance-state.ts +0 -3
  17. package/src/database/_generated/project/client.ts +89 -0
  18. package/src/database/_generated/project/internal/class.ts +3 -3
  19. package/src/database/_generated/project/internal/prismaNamespace.ts +3 -4
  20. package/src/database/_generated/project/models/ApiKey.ts +4 -0
  21. package/src/database/_generated/project/models/InstanceEvaluationState.ts +9 -0
  22. package/src/database/_generated/project/models/InstanceState.ts +175 -266
  23. package/src/database/_generated/project/models/Page.ts +8 -1
  24. package/src/database/_generated/project/models/Secret.ts +11 -0
  25. package/src/database/_generated/project/models/ServiceAccount.ts +5 -0
  26. package/src/database/_generated/project/models/Terminal.ts +10 -1
  27. package/src/database/_generated/project/models/TerminalSession.ts +2 -0
  28. package/src/database/_generated/project/models/TerminalSessionLog.ts +2 -0
  29. package/src/database/_generated/project/models/Trigger.ts +6 -1
  30. package/src/database/_generated/project/models/UnlockMethod.ts +12 -0
  31. package/src/database/_generated/project/models/Worker.ts +10 -1
  32. package/src/database/_generated/project/models/WorkerUnitRegistration.ts +8 -1
  33. package/src/database/_generated/project/models/WorkerVersion.ts +8 -0
  34. package/src/database/_generated/project/models/WorkerVersionLog.ts +3 -0
  35. package/src/library/local.ts +1 -5
  36. package/src/library/package-resolution-worker.ts +1 -1
  37. package/src/orchestrator/manager.ts +1 -2
  38. package/src/orchestrator/operation-context.ts +11 -10
  39. package/src/orchestrator/operation.ts +16 -6
  40. package/src/orchestrator/plan-test-builder.ts +0 -1
  41. package/src/project-model/backends/codebase.ts +1 -1
  42. package/src/project-model/backends/database.ts +1 -1
  43. package/src/runner/abstractions.ts +0 -5
  44. package/src/runner/local.ts +7 -21
  45. package/src/runner/pulumi.ts +0 -11
  46. package/src/shared/models/project/operation.ts +7 -5
  47. package/src/shared/models/project/terminal.ts +2 -1
  48. package/src/shared/resolvers/state.ts +1 -5
  49. package/dist/chunk-JNUJ4LTX.js.map +0 -1
@@ -15,7 +15,12 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model Page
18
+ * The page provides custom UI content for instances and service accounts.
18
19
  *
20
+ * Pages can be created by units to display instance-specific information or by service accounts.
21
+ * The content consists of blocks that support markdown text, QR codes with optional content display,
22
+ * and file attachments (inline or artifact references). Instance pages are explicitly deleted
23
+ * when instances are destroyed.
19
24
  */
20
25
  export type PageModel = runtime.Types.Result.DefaultSelection<Prisma.$PagePayload>
21
26
 
@@ -917,7 +922,9 @@ export type $PagePayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
917
922
  */
918
923
  serviceAccountId: string | null
919
924
  /**
920
- * The content of the page managed by the backend.
925
+ * The content of the page as an array of blocks.
926
+ *
927
+ * Supports markdown, QR codes, and file blocks.
921
928
  *
922
929
  * [PageContent]
923
930
  */
@@ -15,7 +15,18 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model Secret
18
+ * The secret stores sensitive configuration values for instances, service accounts, and system components.
18
19
  *
20
+ * Secrets can be instance-owned (for unit configuration), service account-owned, or system-level
21
+ * (like Pulumi passwords).
22
+ *
23
+ * Secrets persist through normal destroy (recreate) operations
24
+ * and are only deleted when explicitly forgetting instance state with the deleteSecrets flag or when manually deleted.
25
+ *
26
+ * Secret updates invalidate instance input hashes via inputHashNonce, triggering re-execution
27
+ * during operations. But the content of the secrets itself do not contribute to the input hash.
28
+ *
29
+ * System secrets like Pulumi passwords are created on-demand and persist for the whole project lifetime.
19
30
  */
20
31
  export type SecretModel = runtime.Types.Result.DefaultSelection<Prisma.$SecretPayload>
21
32
 
@@ -15,7 +15,12 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model ServiceAccount
18
+ * The service account represents an identity for non-human actors in the system.
18
19
  *
20
+ * Service accounts are automatically created for workers and can be manually created
21
+ * for external integrations. They define the access scope for resources like artifacts,
22
+ * secrets, terminals, and pages. Multiple API keys can impersonate the same service account,
23
+ * allowing different authentication tokens to share the same permissions.
19
24
  */
20
25
  export type ServiceAccountModel = runtime.Types.Result.DefaultSelection<Prisma.$ServiceAccountPayload>
21
26
 
@@ -15,7 +15,14 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model Terminal
18
+ * The terminal provides interactive shell access to infrastructure resources.
18
19
  *
20
+ * Terminals can be created by units (owned by instances) or by service accounts.
21
+ * Each terminal maintains a specification for creating containers that power the terminal,
22
+ * including image, command, environment, and mounted files.
23
+ *
24
+ * Instance-owned terminals are marked unavailable when the instance is destroyed, preserving session history.
25
+ * Service account terminals persist independently.
19
26
  */
20
27
  export type TerminalModel = runtime.Types.Result.DefaultSelection<Prisma.$TerminalPayload>
21
28
 
@@ -1077,7 +1084,9 @@ export type $TerminalPayload<ExtArgs extends runtime.Types.Extensions.InternalAr
1077
1084
  */
1078
1085
  status: $Enums.TerminalStatus
1079
1086
  /**
1080
- * The specification of the terminal managed by the backend.
1087
+ * The specification for creating the container that powers this terminal.
1088
+ *
1089
+ * Includes image, command, working directory, environment variables, and files.
1081
1090
  *
1082
1091
  * [TerminalSpec]
1083
1092
  */
@@ -15,7 +15,9 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model TerminalSession
18
+ * The terminal session represents a single interactive connection to a terminal.
18
19
  *
20
+ * Each session tracks when it started and finished. All session output is preserved in logs.
19
21
  */
20
22
  export type TerminalSessionModel = runtime.Types.Result.DefaultSelection<Prisma.$TerminalSessionPayload>
21
23
 
@@ -15,7 +15,9 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model TerminalSessionLog
18
+ * The terminal session log captures all input and output from a terminal session.
18
19
  *
20
+ * Logs are stored with ULID identifiers for timestamp ordering.
19
21
  */
20
22
  export type TerminalSessionLogModel = runtime.Types.Result.DefaultSelection<Prisma.$TerminalSessionLogPayload>
21
23
 
@@ -15,7 +15,12 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model Trigger
18
+ * The trigger defines automated actions that execute in response to specific events.
18
19
  *
20
+ * Triggers are created by units to perform actions at defined points in the instance lifecycle
21
+ * or on schedule. The spec field determines the trigger type and behavior - currently supporting
22
+ * before-destroy triggers, with planned support for additional types like cron scheduling.
23
+ * Triggers are deleted along with their instance.
19
24
  */
20
25
  export type TriggerModel = runtime.Types.Result.DefaultSelection<Prisma.$TriggerPayload>
21
26
 
@@ -574,7 +579,7 @@ export type $TriggerPayload<ExtArgs extends runtime.Types.Extensions.InternalArg
574
579
  */
575
580
  name: string
576
581
  /**
577
- * The specification of the trigger describing its behavior and configuration.
582
+ * The specification of the trigger describing its type and behavior.
578
583
  *
579
584
  * [TriggerSpec]
580
585
  */
@@ -15,7 +15,19 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model UnlockMethod
18
+ * The unlock method enables decryption of project databases through user authentication.
18
19
  *
20
+ * Each project database is encrypted with a master key, which is then encrypted for each
21
+ * unlock method's recipient using AGE encryption. Users authenticate (password or passkey)
22
+ * to decrypt their specific AGE identity, which then decrypts the master key.
23
+ *
24
+ * Multiple unlock methods can exist per project, allowing different authentication paths
25
+ * to the same encrypted database. When unlock methods are added/removed, the master key
26
+ * is re-encrypted for the new set of recipients.
27
+ *
28
+ * The encryptedIdentity contains the AGE identity encrypted with the user's authentication
29
+ * method (password-derived key or WebAuthn), while the recipient is the public key
30
+ * corresponding to that identity.
19
31
  */
20
32
  export type UnlockMethodModel = runtime.Types.Result.DefaultSelection<Prisma.$UnlockMethodPayload>
21
33
 
@@ -15,7 +15,16 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model Worker
18
+ * The worker represents a containerized application that extends unit capabilities beyond Pulumi execution.
18
19
  *
20
+ * Workers enable units to perform runtime operations after Pulumi program completion,
21
+ * such as attaching custom statuses, monitoring resources, or triggering unit reconfigurations.
22
+ * Since Pulumi programs cannot affect instances after execution, workers bypass this limitation
23
+ * by providing persistent runtime behavior.
24
+ *
25
+ * The worker identity (fully qualified image name) indicates the same publisher/party and services as natural authentication mechanism.
26
+ * All versions of a worker share the same service account, meaning they operate over
27
+ * the same resources and have the same access scope within the platform.
19
28
  */
20
29
  export type WorkerModel = runtime.Types.Result.DefaultSelection<Prisma.$WorkerPayload>
21
30
 
@@ -578,7 +587,7 @@ export type $WorkerPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs
578
587
  */
579
588
  id: string
580
589
  /**
581
- * The ID of the worker.
590
+ * The identity of the worker derived from the container image.
582
591
  *
583
592
  * This is the fully qualified image name without the tag or digest.
584
593
  * The format is `{<registry>/}[<namespace>/]<name>`.
@@ -15,7 +15,14 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model WorkerUnitRegistration
18
+ * The worker unit registration tracks which unit instances require specific worker versions.
18
19
  *
20
+ * Units declare worker dependencies through their outputs, creating registrations that
21
+ * trigger the runtime to start corresponding worker containers. Each registration
22
+ * includes parameters passed to the worker for unit-specific configuration.
23
+ *
24
+ * Registrations are managed during operation execution - created when units declare workers
25
+ * and removed when units are destroyed. Worker versions without registrations are garbage collected.
19
26
  */
20
27
  export type WorkerUnitRegistrationModel = runtime.Types.Result.DefaultSelection<Prisma.$WorkerUnitRegistrationPayload>
21
28
 
@@ -660,7 +667,7 @@ export type $WorkerUnitRegistrationPayload<ExtArgs extends runtime.Types.Extensi
660
667
  */
661
668
  stateId: string
662
669
  /**
663
- * The name of the workor within the instance.
670
+ * The name of the worker within the instance.
664
671
  */
665
672
  name: string
666
673
  /**
@@ -15,7 +15,15 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model WorkerVersion
18
+ * The worker version represents a specific container image digest of a worker.
18
19
  *
20
+ * Each version corresponds to an immutable container image identified by its SHA256 digest.
21
+ * Versions are automatically created when units reference new image digests and deleted
22
+ * when no longer referenced by any unit registrations.
23
+ *
24
+ * Each version has its own API key for isolation, but all versions of a worker
25
+ * share the same service account and thus the same access scope within the platform.
26
+ * The runtime starts containers when registrations exist and stops them when removed.
19
27
  */
20
28
  export type WorkerVersionModel = runtime.Types.Result.DefaultSelection<Prisma.$WorkerVersionPayload>
21
29
 
@@ -15,7 +15,10 @@ import type * as Prisma from "../internal/prismaNamespace.ts"
15
15
 
16
16
  /**
17
17
  * Model WorkerVersionLog
18
+ * The worker version log captures output from running worker containers.
18
19
  *
20
+ * Logs include both worker-generated output and system messages from the runtime.
21
+ * The ULID identifier provides timestamp ordering. Logs are deleted with the worker version.
19
22
  */
20
23
  export type WorkerVersionLogModel = runtime.Types.Result.DefaultSelection<Prisma.$WorkerVersionLogPayload>
21
24
 
@@ -88,13 +88,10 @@ export class LocalLibraryBackend implements LibraryBackend {
88
88
  }
89
89
 
90
90
  async loadLibrary(): Promise<LibraryModel> {
91
- return await this.lock.acquire(async () => {
92
- return await this.getLibrary()
93
- })
91
+ return await this.lock.acquire(async () => await this.getLibrary())
94
92
  }
95
93
 
96
94
  async *watchLibrary(_libraryId: string, signal?: AbortSignal): AsyncIterable<LibraryUpdate[]> {
97
- // For local backend, we ignore libraryId since there's only one library
98
95
  for await (const [library] of on(this.eventEmitter, "library", { signal })) {
99
96
  yield library
100
97
  }
@@ -142,7 +139,6 @@ export class LocalLibraryBackend implements LibraryBackend {
142
139
  _libraryId: string,
143
140
  signal?: AbortSignal,
144
141
  ): AsyncIterable<ResolvedUnitSource> {
145
- // For local backend, we ignore libraryId since there's only one library
146
142
  for await (const [resolvedUnitSource] of on(this.eventEmitter, "resolvedUnitSource", {
147
143
  signal,
148
144
  })) {
@@ -49,7 +49,7 @@ for (const packageName of packageNames) {
49
49
  } catch (error) {
50
50
  logger.error({ error }, `failed to resolve package "%s"`, packageName)
51
51
 
52
- if (error instanceof Error && error.message.includes("not found")) {
52
+ if (error instanceof Error && error.message.includes(`Cannot find package '${packageName}'`)) {
53
53
  results.push({
54
54
  type: "not-found",
55
55
  packageName,
@@ -88,7 +88,7 @@ export class OperationManager {
88
88
 
89
89
  const operation = await this.operationService.createOperation(
90
90
  request.projectId,
91
- {},
91
+ request.meta,
92
92
  request.type,
93
93
  request.instanceIds,
94
94
  options,
@@ -268,7 +268,6 @@ export class OperationManager {
268
268
  },
269
269
  data: {
270
270
  status: "failed",
271
- message: "Operation was interrupted",
272
271
  },
273
272
  })
274
273
 
@@ -44,8 +44,6 @@ export class OperationContext {
44
44
  Record<InstanceId, ResolvedInstanceInput[]>
45
45
  >()
46
46
 
47
- private instanceIdToStateIdMap: Record<InstanceId, string> | null = null
48
-
49
47
  private constructor(
50
48
  public readonly project: ProjectOutput,
51
49
  public readonly library: LibraryModel,
@@ -213,18 +211,21 @@ export class OperationContext {
213
211
  }
214
212
  }
215
213
 
216
- public getInstanceIdToStateIdMap(): Record<InstanceId, string> {
217
- if (this.instanceIdToStateIdMap) {
218
- return this.instanceIdToStateIdMap
219
- }
220
-
221
- // build map on first request and cache it
214
+ /**
215
+ * Gets a map of instance IDs to state IDs for dependencies of the given instance.
216
+ *
217
+ * @param instanceId The instance ID to get the state ID map for.
218
+ * @returns A map of instance IDs to state IDs.
219
+ */
220
+ public getInstanceIdToStateIdMap(instanceId: InstanceId): Record<InstanceId, string> {
222
221
  const map: Record<InstanceId, string> = {}
223
- for (const [instanceId, state] of this.stateMap.entries()) {
222
+ const dependencies = this.getDependencies(instanceId).map(i => i.id)
223
+
224
+ for (const dep of dependencies) {
225
+ const state = this.getState(dep)
224
226
  map[instanceId] = state.id
225
227
  }
226
228
 
227
- this.instanceIdToStateIdMap = map
228
229
  return map
229
230
  }
230
231
 
@@ -309,7 +309,6 @@ export class RuntimeOperation {
309
309
  },
310
310
  instanceState: {
311
311
  status: this.workset.getNextStableInstanceStatus(instance.id),
312
- message: null,
313
312
  },
314
313
  })
315
314
  }
@@ -327,6 +326,10 @@ export class RuntimeOperation {
327
326
 
328
327
  signal.throwIfAborted()
329
328
 
329
+ if (this.operation.status === "failing") {
330
+ throw new AbortError("The operation is failing, aborting current branch (still not failed)")
331
+ }
332
+
330
333
  logger.info("updating unit")
331
334
 
332
335
  await this.workset.updateState(instance.id, {
@@ -467,9 +470,19 @@ export class RuntimeOperation {
467
470
  dependentPromises.push(this.getInstancePromiseForOperation(instance, dependent))
468
471
  }
469
472
 
470
- await waitAll(dependentPromises)
473
+ await Promise.race([
474
+ waitAll(dependentPromises),
475
+
476
+ // to immediately abort the operation if requested
477
+ waitForAbort(signal),
478
+ ])
479
+
471
480
  signal.throwIfAborted()
472
481
 
482
+ if (this.operation.status === "failing") {
483
+ throw new AbortError("The operation is failing, aborting current branch (still not failed)")
484
+ }
485
+
473
486
  await this.processBeforeDestroyTriggers(instance, state, logger, signal, forceSignal)
474
487
  signal.throwIfAborted()
475
488
 
@@ -594,7 +607,7 @@ export class RuntimeOperation {
594
607
  inputs: mapValues(resolvedInputs ?? {}, input => input.map(value => value.input)),
595
608
  invokedTriggers,
596
609
  secretNames: Object.keys(secrets),
597
- stateIdMap: this.context.getInstanceIdToStateIdMap(),
610
+ stateIdMap: this.context.getInstanceIdToStateIdMap(instance.id),
598
611
  }
599
612
  }
600
613
 
@@ -655,7 +668,6 @@ export class RuntimeOperation {
655
668
  instanceState: {
656
669
  // keep "deployed" status for initially deployed instances even if the operation was failed or cancelled
657
670
  status: state.status === "deployed" ? "deployed" : "failed",
658
- message: update.message,
659
671
  },
660
672
  operationState: {
661
673
  status: isAbortErrorLike(update.message) ? "cancelled" : "failed",
@@ -672,7 +684,6 @@ export class RuntimeOperation {
672
684
 
673
685
  const data: InstanceStatePatch = {
674
686
  status: this.workset.getNextStableInstanceStatus(instance.id),
675
- message: update.message,
676
687
  statusFields: update.statusFields ?? null,
677
688
  }
678
689
 
@@ -697,7 +708,6 @@ export class RuntimeOperation {
697
708
  data.parentId = null
698
709
  }
699
710
  } else {
700
- data.message = null
701
711
  data.inputHash = null
702
712
  data.dependencyOutputHash = null
703
713
  data.outputHash = null
@@ -109,7 +109,6 @@ export class PlanTestBuilder {
109
109
  statusFields: null,
110
110
  exportedArtifactIds: null,
111
111
  inputHashNonce: null,
112
- message: null,
113
112
  currentResourceCount: null,
114
113
  model: null,
115
114
  resolvedInputs: null,
@@ -272,7 +272,7 @@ export class CodebaseProjectModelBackend implements ProjectModelBackend {
272
272
  return {}
273
273
  })
274
274
 
275
- this.logger.info(
275
+ this.logger.debug(
276
276
  { projectId: project.id, instanceCount: instances.length, hubCount: hubs.length },
277
277
  "created nodes in project model",
278
278
  )
@@ -415,7 +415,7 @@ export class DatabaseProjectModelBackend implements ProjectModelBackend {
415
415
  ])
416
416
  })
417
417
 
418
- this.logger.info(
418
+ this.logger.debug(
419
419
  { projectId: project.id, instanceCount: instances.length, hubCount: hubs.length },
420
420
  "created nodes in project model",
421
421
  )
@@ -56,11 +56,6 @@ export type UnitStateUpdate = {
56
56
  */
57
57
  operationType: OperationType
58
58
 
59
- /**
60
- * The summary message produced by the unit.
61
- */
62
- message?: string | null
63
-
64
59
  /**
65
60
  * The CRC32 hash of the output produced by the unit.
66
61
  */
@@ -41,12 +41,7 @@ import {
41
41
  collectAndStoreArtifacts,
42
42
  setupArtifactEnvironment,
43
43
  } from "./artifact-env"
44
- import {
45
- getOperationSummary,
46
- type LocalPulumiHost,
47
- pulumiErrorToString,
48
- updateResourceCount,
49
- } from "./pulumi"
44
+ import { type LocalPulumiHost, pulumiErrorToString, updateResourceCount } from "./pulumi"
50
45
 
51
46
  type Events = {
52
47
  [K in `update:${string}`]: [UnitStateUpdate]
@@ -172,7 +167,7 @@ export class LocalRunnerBackend implements RunnerBackend {
172
167
 
173
168
  await runWithRetryOnError(
174
169
  async () => {
175
- const { stdout } = await stack[preview ? "preview" : "up"]({
170
+ await stack[preview ? "preview" : "up"]({
176
171
  color: "always",
177
172
  refresh: options.refresh,
178
173
  signal,
@@ -211,12 +206,7 @@ export class LocalRunnerBackend implements RunnerBackend {
211
206
  })
212
207
 
213
208
  const outputs = await stack.outputs()
214
- const completionUpdate = this.createCompletionStateUpdate(
215
- "update",
216
- unitId,
217
- outputs,
218
- stdout,
219
- )
209
+ const completionUpdate = this.createCompletionStateUpdate("update", unitId, outputs)
220
210
 
221
211
  if (outputs["$artifacts"]) {
222
212
  const artifacts = z
@@ -333,7 +323,7 @@ export class LocalRunnerBackend implements RunnerBackend {
333
323
  try {
334
324
  await runWithRetryOnError(
335
325
  async () => {
336
- const { stdout } = await stack.destroy({
326
+ await stack.destroy({
337
327
  color: "always",
338
328
  refresh: options.refresh,
339
329
  remove: true,
@@ -361,7 +351,7 @@ export class LocalRunnerBackend implements RunnerBackend {
361
351
  },
362
352
  })
363
353
 
364
- await this.emitCompletionStateUpdate("destroy", unitId, stack, stdout)
354
+ await this.emitCompletionStateUpdate("destroy", unitId, stack)
365
355
  },
366
356
  error => this.pulumiProjectHost.tryUnlockStack(stack, error),
367
357
  )
@@ -431,7 +421,7 @@ export class LocalRunnerBackend implements RunnerBackend {
431
421
 
432
422
  await runWithRetryOnError(
433
423
  async () => {
434
- const { stdout } = await stack.refresh({
424
+ await stack.refresh({
435
425
  color: "always",
436
426
  debug: options.debug,
437
427
 
@@ -472,7 +462,6 @@ export class LocalRunnerBackend implements RunnerBackend {
472
462
  type: "completion",
473
463
  operationType: "refresh",
474
464
  unitId,
475
- message: getOperationSummary(stdout),
476
465
 
477
466
  // do not emit output-related fields on refresh since they will not change
478
467
  // some of them (like artifact files) are not even available on refresh
@@ -495,7 +484,6 @@ export class LocalRunnerBackend implements RunnerBackend {
495
484
  opType: "update" | "destroy" | "refresh",
496
485
  unitId: InstanceId,
497
486
  outputs: OutputMap,
498
- stdout: string,
499
487
  ): TypedUnitStateUpdate<"completion"> {
500
488
  const unitOutputs = omitBy(outputs, (_, key) => key.startsWith("$"))
501
489
 
@@ -503,7 +491,6 @@ export class LocalRunnerBackend implements RunnerBackend {
503
491
  unitId,
504
492
  type: "completion",
505
493
  operationType: opType,
506
- message: getOperationSummary(stdout),
507
494
 
508
495
  outputHash: crc32(sha256(encode(unitOutputs))),
509
496
 
@@ -535,10 +522,9 @@ export class LocalRunnerBackend implements RunnerBackend {
535
522
  opType: OperationType,
536
523
  unitId: InstanceId,
537
524
  stack: Stack,
538
- stdout: string,
539
525
  ): Promise<TypedUnitStateUpdate<"completion">> {
540
526
  const output = await stack.outputs()
541
- const update = this.createCompletionStateUpdate(opType, unitId, output, stdout)
527
+ const update = this.createCompletionStateUpdate(opType, unitId, output)
542
528
 
543
529
  return this.emitStateUpdate(update)
544
530
  }
@@ -204,7 +204,6 @@ export function calculateTotalResources(opMap: OpMap | undefined): number {
204
204
  for (const [op, count] of Object.entries(opMap)) {
205
205
  const opType = op as OpType
206
206
  const value = count ?? 0
207
-
208
207
  total = updateResourceCount(opType, value)
209
208
  }
210
209
 
@@ -230,13 +229,3 @@ export async function pulumiErrorToString(error: unknown): Promise<string> {
230
229
 
231
230
  return errorToString(error)
232
231
  }
233
-
234
- export function getOperationSummary(stdout: string): string | null {
235
- const summaryStart = stdout.indexOf("\u001b[38;5;13m\u001b[1mOutputs:")
236
-
237
- if (summaryStart !== -1) {
238
- return stdout.slice(summaryStart)
239
- }
240
-
241
- return null
242
- }
@@ -206,17 +206,19 @@ export const operationStatusSchema = z.enum([
206
206
  "cancelled",
207
207
  ]) satisfies z.ZodType<OperationStatus>
208
208
 
209
- export const operationMetaSchema = objectMetaSchema.pick({
210
- title: true,
211
- description: true,
212
- })
209
+ export const operationMetaSchema = objectMetaSchema
210
+ .pick({
211
+ title: true,
212
+ description: true,
213
+ })
214
+ .required({ title: true })
213
215
 
214
216
  export const operationInputSchema = z.object({
215
217
  projectId: z.string(),
216
218
  type: operationTypeSchema,
217
219
  instanceIds: z.array(instanceIdSchema).min(1),
218
220
  options: operationOptionsSchema.partial().optional(),
219
- meta: operationMetaSchema.optional(),
221
+ meta: operationMetaSchema,
220
222
  plan: operationPhaseSchema.array().optional(),
221
223
  })
222
224
 
@@ -1,6 +1,7 @@
1
1
  import type { ServiceAccount, Terminal, TerminalSession, TerminalStatus } from "../../../database"
2
2
  import {
3
3
  commonObjectMetaSchema,
4
+ globalCommonObjectMetaSchema,
4
5
  serviceAccountMetaSchema,
5
6
  terminalSpecSchema,
6
7
  } from "@highstate/contract"
@@ -15,7 +16,7 @@ export const terminalStatusSchema = z.enum([
15
16
  export const terminalSessionOutputSchema = z.object({
16
17
  id: z.cuid2(),
17
18
  terminalId: z.cuid2(),
18
- meta: commonObjectMetaSchema,
19
+ meta: globalCommonObjectMetaSchema,
19
20
  startedAt: z.date(),
20
21
  finishedAt: z.date().nullable(),
21
22
  })
@@ -3,12 +3,8 @@ import { GraphResolver } from "./graph-resolver"
3
3
 
4
4
  export class StateResolver extends GraphResolver<InstanceState, void> {
5
5
  protected getNodeDependencies(node: InstanceState): string[] {
6
- if (!node.lastOperationState) {
7
- return []
8
- }
9
-
10
6
  const dependencies = new Set<string>()
11
- for (const inputs of Object.values(node.lastOperationState.resolvedInputs)) {
7
+ for (const inputs of Object.values(node.resolvedInputs ?? {})) {
12
8
  for (const input of inputs) {
13
9
  dependencies.add(input.instanceId)
14
10
  }