@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.
- package/dist/{chunk-JNUJ4LTX.js → chunk-5LYHHLFW.js} +6 -9
- package/dist/chunk-5LYHHLFW.js.map +1 -0
- package/dist/index.js +42 -52
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +1 -1
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/shared/index.js +1 -1
- package/package.json +3 -3
- package/prisma/backend/postgresql/main.prisma +1 -1
- package/prisma/backend/sqlite/main.prisma +2 -2
- package/prisma/project/instance.prisma +5 -5
- package/prisma/project/main.prisma +2 -2
- package/prisma/project/migrations/20250921092621_b/migration.sql +33 -0
- package/prisma/project/migrations/20250921093911_b/migration.sql +1 -0
- package/prisma/project/operation.prisma +3 -0
- package/src/business/instance-state.ts +0 -3
- package/src/database/_generated/project/client.ts +89 -0
- package/src/database/_generated/project/internal/class.ts +3 -3
- package/src/database/_generated/project/internal/prismaNamespace.ts +3 -4
- package/src/database/_generated/project/models/ApiKey.ts +4 -0
- package/src/database/_generated/project/models/InstanceEvaluationState.ts +9 -0
- package/src/database/_generated/project/models/InstanceState.ts +175 -266
- package/src/database/_generated/project/models/Page.ts +8 -1
- package/src/database/_generated/project/models/Secret.ts +11 -0
- package/src/database/_generated/project/models/ServiceAccount.ts +5 -0
- package/src/database/_generated/project/models/Terminal.ts +10 -1
- package/src/database/_generated/project/models/TerminalSession.ts +2 -0
- package/src/database/_generated/project/models/TerminalSessionLog.ts +2 -0
- package/src/database/_generated/project/models/Trigger.ts +6 -1
- package/src/database/_generated/project/models/UnlockMethod.ts +12 -0
- package/src/database/_generated/project/models/Worker.ts +10 -1
- package/src/database/_generated/project/models/WorkerUnitRegistration.ts +8 -1
- package/src/database/_generated/project/models/WorkerVersion.ts +8 -0
- package/src/database/_generated/project/models/WorkerVersionLog.ts +3 -0
- package/src/library/local.ts +1 -5
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/orchestrator/manager.ts +1 -2
- package/src/orchestrator/operation-context.ts +11 -10
- package/src/orchestrator/operation.ts +16 -6
- package/src/orchestrator/plan-test-builder.ts +0 -1
- package/src/project-model/backends/codebase.ts +1 -1
- package/src/project-model/backends/database.ts +1 -1
- package/src/runner/abstractions.ts +0 -5
- package/src/runner/local.ts +7 -21
- package/src/runner/pulumi.ts +0 -11
- package/src/shared/models/project/operation.ts +7 -5
- package/src/shared/models/project/terminal.ts +2 -1
- package/src/shared/resolvers/state.ts +1 -5
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
package/src/library/local.ts
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
@@ -272,7 +272,7 @@ export class CodebaseProjectModelBackend implements ProjectModelBackend {
|
|
|
272
272
|
return {}
|
|
273
273
|
})
|
|
274
274
|
|
|
275
|
-
this.logger.
|
|
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.
|
|
418
|
+
this.logger.debug(
|
|
419
419
|
{ projectId: project.id, instanceCount: instances.length, hubCount: hubs.length },
|
|
420
420
|
"created nodes in project model",
|
|
421
421
|
)
|
package/src/runner/local.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
527
|
+
const update = this.createCompletionStateUpdate(opType, unitId, output)
|
|
542
528
|
|
|
543
529
|
return this.emitStateUpdate(update)
|
|
544
530
|
}
|
package/src/runner/pulumi.ts
CHANGED
|
@@ -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
|
|
210
|
-
|
|
211
|
-
|
|
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
|
|
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:
|
|
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.
|
|
7
|
+
for (const inputs of Object.values(node.resolvedInputs ?? {})) {
|
|
12
8
|
for (const input of inputs) {
|
|
13
9
|
dependencies.add(input.instanceId)
|
|
14
10
|
}
|