@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.
- package/dist/chunk-5WVU2AK4.js +1535 -0
- package/dist/chunk-5WVU2AK4.js.map +1 -0
- package/dist/chunk-I7BWSAN6.js +49 -0
- package/dist/chunk-I7BWSAN6.js.map +1 -0
- package/dist/{chunk-RCB4AFGD.js → chunk-VB4YL327.js} +51 -71
- package/dist/chunk-VB4YL327.js.map +1 -0
- package/dist/database/local/prisma.config.js +26 -0
- package/dist/database/local/prisma.config.js.map +1 -0
- package/dist/highstate.manifest.json +5 -4
- package/dist/index.js +7676 -6634
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +8 -6
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +63 -58
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +3 -216
- package/dist/shared/index.js.map +1 -1
- package/package.json +23 -11
- package/prisma/backend/_schema/layout.prisma +7 -0
- package/prisma/backend/_schema/library.prisma +17 -0
- package/prisma/backend/_schema/project.prisma +101 -0
- package/prisma/backend/_schema/pulumi.prisma +17 -0
- package/prisma/backend/postgresql/main.prisma +17 -0
- package/prisma/backend/sqlite/main.prisma +17 -0
- package/prisma/backend/sqlite/migrations/20250817070609_initiial/migration.sql +34 -0
- package/prisma/backend/sqlite/migrations/20250817104948_add_fields/migration.sql +59 -0
- package/prisma/backend/sqlite/migrations/20250818082732_add_models/migration.sql +41 -0
- package/prisma/backend/sqlite/migrations/20250818083106_a/migration.sql +19 -0
- package/prisma/backend/sqlite/migrations/20250818101945_hi/migration.sql +1 -0
- package/prisma/backend/sqlite/migrations/20250819082315_a/migration.sql +5 -0
- package/prisma/backend/sqlite/migrations/migration_lock.toml +3 -0
- package/prisma/project/api-key.prisma +27 -0
- package/prisma/project/artifact.prisma +52 -0
- package/prisma/project/custom-status.prisma +46 -0
- package/prisma/project/evaluation.prisma +35 -0
- package/prisma/project/instance.prisma +160 -0
- package/prisma/project/layout.prisma +23 -0
- package/prisma/project/lock.prisma +18 -0
- package/prisma/project/main.prisma +17 -0
- package/prisma/project/migrations/20250816081310_initial/migration.sql +300 -0
- package/prisma/project/migrations/20250816082523_test/migration.sql +72 -0
- package/prisma/project/migrations/20250818065643_update/migration.sql +42 -0
- package/prisma/project/migrations/20250818070758_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818070913_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818082720_add_motels/migration.sql +11 -0
- package/prisma/project/migrations/20250818112523_hello/migration.sql +35 -0
- package/prisma/project/migrations/20250819082305_a/migration.sql +14 -0
- package/prisma/project/migrations/20250819165004_add_missing_fields/migration.sql +216 -0
- package/prisma/project/migrations/20250819171309_a/migration.sql +22 -0
- package/prisma/project/migrations/20250820113949_a/migration.sql +66 -0
- package/prisma/project/migrations/20250820144256_b/migration.sql +31 -0
- package/prisma/project/migrations/20250820145547_a/migration.sql +24 -0
- package/prisma/project/migrations/20250820182517_b/migration.sql +2 -0
- package/prisma/project/migrations/20250821172324_a/migration.sql +2 -0
- package/prisma/project/migrations/20250822081339_a/migration.sql +219 -0
- package/prisma/project/migrations/20250822083742_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822105134_boom/migration.sql +1 -0
- package/prisma/project/migrations/20250822141028_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822142342_b/migration.sql +16 -0
- package/prisma/project/migrations/20250824072720_a/migration.sql +1 -0
- package/prisma/project/migrations/20250824093656_b/migration.sql +21 -0
- package/prisma/project/migrations/20250825082518_a/migration.sql +1 -0
- package/prisma/project/migrations/20250825085343_b/migration.sql +1 -0
- package/prisma/project/migrations/20250825091312_a/migration.sql +1 -0
- package/prisma/project/migrations/20250903095431_hi/migration.sql +44 -0
- package/prisma/project/migrations/20250903174255_a/migration.sql +24 -0
- package/prisma/project/migrations/20250908095205_hi/migration.sql +18 -0
- package/prisma/project/migrations/20250909155857_hi/migration.sql +15 -0
- package/prisma/project/migrations/migration_lock.toml +3 -0
- package/prisma/project/model.prisma +37 -0
- package/prisma/project/operation.prisma +148 -0
- package/prisma/project/page.prisma +41 -0
- package/prisma/project/secret.prisma +42 -0
- package/prisma/project/service-account.prisma +36 -0
- package/prisma/project/terminal.prisma +90 -0
- package/prisma/project/trigger.prisma +31 -0
- package/prisma/project/unlock-method.prisma +32 -0
- package/prisma/project/worker.prisma +138 -0
- package/src/artifact/abstractions.ts +13 -13
- package/src/artifact/encryption.ts +31 -15
- package/src/artifact/factory.ts +7 -10
- package/src/artifact/local.ts +33 -50
- package/src/business/api-key.ts +24 -36
- package/src/business/artifact.test.ts +978 -0
- package/src/business/artifact.ts +136 -215
- package/src/business/evaluation.ts +328 -0
- package/src/business/index.ts +5 -1
- package/src/business/instance-lock.test.ts +1060 -0
- package/src/business/instance-lock.ts +387 -77
- package/src/business/instance-state.test.ts +735 -0
- package/src/business/instance-state.ts +604 -217
- package/src/business/operation.test.ts +439 -0
- package/src/business/operation.ts +174 -208
- package/src/business/project-model.ts +258 -0
- package/src/business/project-unlock.ts +172 -112
- package/src/business/project.ts +407 -0
- package/src/business/secret.test.ts +513 -0
- package/src/business/secret.ts +194 -131
- package/src/business/settings.test.ts +695 -0
- package/src/business/settings.ts +855 -0
- package/src/business/terminal-session.ts +90 -0
- package/src/business/unit-extra.test.ts +539 -0
- package/src/business/unit-extra.ts +160 -0
- package/src/business/worker.test.ts +391 -0
- package/src/business/worker.ts +250 -114
- package/src/common/codebase.ts +65 -0
- package/src/common/index.ts +3 -2
- package/src/common/logger.ts +5 -0
- package/src/common/utils.ts +4 -3
- package/src/config.ts +15 -12
- package/src/database/_generated/backend/postgresql/client.ts +72 -0
- package/src/database/_generated/backend/postgresql/commonInputTypes.ts +350 -0
- package/src/database/_generated/backend/postgresql/enums.ts +13 -0
- package/src/database/_generated/backend/postgresql/internal/class.ts +320 -0
- package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +1238 -0
- package/src/database/_generated/backend/postgresql/models/Library.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/Project.ts +2175 -0
- package/src/database/_generated/backend/postgresql/models/ProjectModelStorage.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/ProjectSpace.ts +1602 -0
- package/src/database/_generated/backend/postgresql/models/PulumiBackend.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/UserWorkspaseLayout.ts +1065 -0
- package/src/database/_generated/backend/postgresql/models.ts +16 -0
- package/src/database/_generated/backend/postgresql/pjtg.ts +182 -0
- package/src/database/_generated/backend/sqlite/client.ts +72 -0
- package/src/database/_generated/backend/sqlite/commonInputTypes.ts +331 -0
- package/src/database/_generated/backend/sqlite/enums.ts +13 -0
- package/src/database/_generated/backend/sqlite/internal/class.ts +318 -0
- package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +1207 -0
- package/src/database/_generated/backend/sqlite/models/Library.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/Project.ts +2169 -0
- package/src/database/_generated/backend/sqlite/models/ProjectModelStorage.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/ProjectSpace.ts +1599 -0
- package/src/database/_generated/backend/sqlite/models/PulumiBackend.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/UserWorkspaseLayout.ts +1063 -0
- package/src/database/_generated/backend/sqlite/models.ts +16 -0
- package/src/database/_generated/backend/sqlite/pjtg.ts +182 -0
- package/src/database/_generated/project/client.ts +204 -0
- package/src/database/_generated/project/commonInputTypes.ts +827 -0
- package/src/database/_generated/project/enums.ts +104 -0
- package/src/database/_generated/project/internal/class.ts +479 -0
- package/src/database/_generated/project/internal/prismaNamespace.ts +2974 -0
- package/src/database/_generated/project/models/ApiKey.ts +1506 -0
- package/src/database/_generated/project/models/Artifact.ts +2051 -0
- package/src/database/_generated/project/models/HubModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceCustomStatus.ts +1713 -0
- package/src/database/_generated/project/models/InstanceEvaluationState.ts +1312 -0
- package/src/database/_generated/project/models/InstanceLock.ts +1268 -0
- package/src/database/_generated/project/models/InstanceModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceOperationState.ts +1707 -0
- package/src/database/_generated/project/models/InstanceState.ts +4613 -0
- package/src/database/_generated/project/models/Operation.ts +1647 -0
- package/src/database/_generated/project/models/OperationLog.ts +1455 -0
- package/src/database/_generated/project/models/Page.ts +1838 -0
- package/src/database/_generated/project/models/Secret.ts +1692 -0
- package/src/database/_generated/project/models/ServiceAccount.ts +2165 -0
- package/src/database/_generated/project/models/Terminal.ts +2038 -0
- package/src/database/_generated/project/models/TerminalSession.ts +1454 -0
- package/src/database/_generated/project/models/TerminalSessionLog.ts +1280 -0
- package/src/database/_generated/project/models/Trigger.ts +1430 -0
- package/src/database/_generated/project/models/UnlockMethod.ts +1220 -0
- package/src/database/_generated/project/models/UserCompositeViewport.ts +1280 -0
- package/src/database/_generated/project/models/UserProjectViewport.ts +1059 -0
- package/src/database/_generated/project/models/Worker.ts +1459 -0
- package/src/database/_generated/project/models/WorkerUnitRegistration.ts +1524 -0
- package/src/database/_generated/project/models/WorkerVersion.ts +1974 -0
- package/src/database/_generated/project/models/WorkerVersionLog.ts +1318 -0
- package/src/database/_generated/project/models.ts +35 -0
- package/src/database/_generated/project/pjtg.ts +182 -0
- package/src/database/abstractions.ts +19 -0
- package/src/database/factory.ts +37 -0
- package/src/database/index.ts +6 -0
- package/src/database/local/backend.ts +134 -0
- package/src/database/local/index.ts +3 -0
- package/src/database/local/meta.ts +46 -0
- package/src/database/local/prisma.config.ts +25 -0
- package/src/database/local/project.ts +39 -0
- package/src/database/manager.ts +181 -0
- package/src/database/migrate.ts +35 -0
- package/src/database/prisma.ts +56 -0
- package/src/database/well-known.ts +38 -0
- package/src/index.ts +4 -4
- package/src/library/abstractions.ts +21 -14
- package/src/library/factory.ts +1 -1
- package/src/library/local.ts +86 -38
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/library/worker/evaluator.ts +61 -48
- package/src/library/worker/loader.lite.ts +14 -1
- package/src/library/worker/main.ts +9 -16
- package/src/library/worker/protocol.ts +0 -12
- package/src/lock/manager.ts +12 -7
- package/src/orchestrator/manager.ts +198 -131
- package/src/orchestrator/operation-context.ts +357 -0
- package/src/orchestrator/operation-plan.destroy.test.md +357 -0
- package/src/orchestrator/operation-plan.destroy.test.ts +775 -0
- package/src/orchestrator/operation-plan.fixtures.ts +213 -0
- package/src/orchestrator/operation-plan.md +198 -0
- package/src/orchestrator/operation-plan.refresh.test.md +199 -0
- package/src/orchestrator/operation-plan.refresh.test.ts +367 -0
- package/src/orchestrator/operation-plan.ts +709 -0
- package/src/orchestrator/operation-plan.update.test.md +485 -0
- package/src/orchestrator/operation-plan.update.test.ts +1066 -0
- package/src/orchestrator/operation-workset.ts +235 -583
- package/src/orchestrator/operation.ts +446 -904
- package/src/orchestrator/plan-test-builder.ts +267 -0
- package/src/project-model/abstractions.ts +118 -0
- package/src/project-model/backends/codebase.ts +365 -0
- package/src/project-model/backends/database.ts +440 -0
- package/src/project-model/errors.ts +81 -0
- package/src/project-model/factory.ts +24 -0
- package/src/project-model/index.ts +4 -0
- package/src/project-model/utils.test.ts +544 -0
- package/src/project-model/utils.ts +242 -0
- package/src/pubsub/abstractions.ts +10 -1
- package/src/pubsub/factory.ts +4 -4
- package/src/pubsub/index.ts +1 -0
- package/src/pubsub/manager.ts +49 -25
- package/src/pubsub/memory.ts +31 -0
- package/src/runner/abstractions.ts +38 -26
- package/src/runner/artifact-env.ts +17 -6
- package/src/runner/factory.ts +6 -6
- package/src/runner/force-abort.ts +3 -6
- package/src/runner/local.ts +79 -72
- package/src/runner/pulumi.ts +26 -63
- package/src/services.ts +214 -103
- package/src/shared/models/backend/index.ts +3 -1
- package/src/shared/models/backend/library.ts +12 -4
- package/src/shared/models/backend/project.ts +43 -23
- package/src/shared/models/backend/pulumi.ts +14 -0
- package/src/shared/models/backend/unlock-method.ts +1 -1
- package/src/shared/models/backend/well-known.ts +58 -0
- package/src/shared/models/base.ts +40 -109
- package/src/shared/models/errors.ts +82 -1
- package/src/shared/models/index.ts +3 -2
- package/src/shared/models/prisma.ts +36 -0
- package/src/shared/models/project/api-key.ts +37 -56
- package/src/shared/models/project/artifact.ts +15 -105
- package/src/shared/models/project/custom-status.ts +12 -0
- package/src/shared/models/project/index.ts +9 -9
- package/src/shared/models/project/lock.ts +10 -78
- package/src/shared/models/project/model.ts +32 -0
- package/src/shared/models/project/operation.ts +222 -99
- package/src/shared/models/project/page.ts +37 -48
- package/src/shared/models/project/secret.ts +29 -103
- package/src/shared/models/project/service-account.ts +12 -17
- package/src/shared/models/project/state.ts +100 -390
- package/src/shared/models/project/terminal.ts +75 -89
- package/src/shared/models/project/trigger.ts +13 -49
- package/src/shared/models/project/unlock-method.ts +21 -20
- package/src/shared/models/project/worker.ts +89 -88
- package/src/shared/resolvers/graph-resolver.ts +62 -26
- package/src/shared/resolvers/index.ts +1 -1
- package/src/shared/resolvers/input-hash.ts +24 -14
- package/src/shared/resolvers/input.ts +48 -6
- package/src/shared/resolvers/registry.ts +5 -4
- package/src/shared/resolvers/state.ts +12 -1
- package/src/shared/resolvers/validation.ts +29 -9
- package/src/shared/utils/index.ts +1 -1
- package/src/shared/utils/promise-tracker.ts +30 -3
- package/src/terminal/abstractions.ts +1 -1
- package/src/terminal/docker.ts +3 -3
- package/src/terminal/manager.ts +102 -118
- package/src/test-utils/database.ts +119 -0
- package/src/test-utils/index.ts +2 -0
- package/src/test-utils/services.ts +134 -0
- package/src/unlock/abstractions.ts +31 -0
- package/src/unlock/index.ts +2 -0
- package/src/unlock/memory.ts +27 -0
- package/src/worker/abstractions.ts +7 -4
- package/src/worker/docker.ts +14 -19
- package/src/worker/manager.ts +376 -79
- package/dist/chunk-RCB4AFGD.js.map +0 -1
- package/dist/chunk-WHALQHEZ.js +0 -2017
- package/dist/chunk-WHALQHEZ.js.map +0 -1
- package/src/business/backend-unlock.ts +0 -10
- package/src/common/performance.ts +0 -44
- package/src/hotstate/abstractions.ts +0 -48
- package/src/hotstate/factory.ts +0 -17
- package/src/hotstate/index.ts +0 -3
- package/src/hotstate/manager.ts +0 -192
- package/src/hotstate/memory.ts +0 -100
- package/src/hotstate/validation.ts +0 -101
- package/src/project/abstractions.ts +0 -102
- package/src/project/factory.ts +0 -11
- package/src/project/index.ts +0 -3
- package/src/project/local.ts +0 -469
- package/src/project/manager.ts +0 -574
- package/src/pubsub/local.ts +0 -36
- package/src/pubsub/validation.ts +0 -33
- package/src/shared/models/project/component.ts +0 -45
- package/src/shared/models/project/instance.ts +0 -74
- package/src/state/abstractions.ts +0 -450
- package/src/state/encryption.ts +0 -59
- package/src/state/factory.ts +0 -20
- package/src/state/index.ts +0 -6
- package/src/state/local/backend.ts +0 -299
- package/src/state/local/collection.ts +0 -342
- package/src/state/local/index.ts +0 -2
- package/src/state/manager.ts +0 -819
- package/src/state/repository/index.ts +0 -2
- package/src/state/repository/repository.index.ts +0 -193
- package/src/state/repository/repository.ts +0 -458
- /package/src/{state → database/local}/keyring.ts +0 -0
|
@@ -1,292 +1,679 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type {
|
|
2
|
+
ComponentKind,
|
|
3
|
+
UnitPage,
|
|
4
|
+
UnitTerminal,
|
|
5
|
+
UnitTrigger,
|
|
6
|
+
UnitWorker,
|
|
7
|
+
} from "@highstate/contract"
|
|
5
8
|
import type { Logger } from "pino"
|
|
6
|
-
import type { RunnerBackend } from "../runner"
|
|
7
9
|
import type { ArtifactService } from "../artifact"
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import type { SecretService, UnitExtraService, WorkerService } from "../business"
|
|
11
|
+
import type { PubSubManager } from "../pubsub"
|
|
12
|
+
import type { RunnerBackend } from "../runner"
|
|
13
|
+
import { type InstanceId, parseInstanceId } from "@highstate/contract"
|
|
14
|
+
import { isNonNullish, omit } from "remeda"
|
|
15
|
+
import {
|
|
16
|
+
type DatabaseManager,
|
|
17
|
+
DbNull,
|
|
18
|
+
type InstanceOperationStateCreateManyInput,
|
|
19
|
+
type InstanceOperationStateUpdateInput,
|
|
20
|
+
type InstanceStateInclude,
|
|
21
|
+
type InstanceStateUpdateInput,
|
|
22
|
+
type ProjectTransaction,
|
|
23
|
+
} from "../database"
|
|
11
24
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type
|
|
25
|
+
forSchema,
|
|
26
|
+
type InstanceCustomStatusInput,
|
|
27
|
+
InstanceLockedError,
|
|
28
|
+
type InstanceOperationState,
|
|
16
29
|
type InstanceState,
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
InstanceStateNotFoundError,
|
|
31
|
+
ProjectNotFoundError,
|
|
32
|
+
projectOutputSchema,
|
|
33
|
+
waitAll,
|
|
19
34
|
} from "../shared"
|
|
20
35
|
|
|
21
|
-
export
|
|
22
|
-
constructor(
|
|
23
|
-
private readonly stateManager: StateManager,
|
|
24
|
-
private readonly hotStateManager: HotStateManager,
|
|
25
|
-
private readonly pubsubManager: PubSubManager,
|
|
26
|
-
private readonly lockManager: LockManager,
|
|
27
|
-
private readonly runnerBackend: RunnerBackend,
|
|
28
|
-
private readonly artifactManager: ArtifactService,
|
|
29
|
-
private readonly logger: Logger,
|
|
30
|
-
) {}
|
|
31
|
-
|
|
36
|
+
export type GetProjectInstancesOptions = {
|
|
32
37
|
/**
|
|
33
|
-
*
|
|
38
|
+
* Whether to include evaluation states in the result.
|
|
34
39
|
*
|
|
35
|
-
*
|
|
40
|
+
* By default, this is false.
|
|
36
41
|
*/
|
|
37
|
-
|
|
38
|
-
const entries = await this.hotStateManager.hgetall(["instance-states", projectId])
|
|
42
|
+
includeEvaluationState?: boolean
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Include last operation state in the result.
|
|
46
|
+
*
|
|
47
|
+
* By default, this is false.
|
|
48
|
+
*/
|
|
49
|
+
includeLastOperationState?: boolean
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Include the instance ID of the parent instance in the result.
|
|
53
|
+
*
|
|
54
|
+
* By default, this is false.
|
|
55
|
+
*/
|
|
56
|
+
includeParentInstanceId?: boolean
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const promises: Promise<void>[] = []
|
|
58
|
+
/**
|
|
59
|
+
* Whether to include `terminalIds` and `pageIds` in the result.
|
|
60
|
+
*
|
|
61
|
+
* By default, this is false.
|
|
62
|
+
*/
|
|
63
|
+
includeExtra?: boolean
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Whether to load custom statuses for each instance.
|
|
67
|
+
*
|
|
68
|
+
* By default, this is false.
|
|
69
|
+
*/
|
|
70
|
+
loadCustomStatuses?: boolean
|
|
71
|
+
}
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
export type ForgetInstanceStateOptions = {
|
|
74
|
+
/**
|
|
75
|
+
* Whether to delete terminals and their sessions associated with the instance.
|
|
76
|
+
*
|
|
77
|
+
* If `false`, the terminals will be marked as deleted and no new sessions will be allowed to be created,
|
|
78
|
+
* but existing sessions will remain to provide history and logs.
|
|
79
|
+
*
|
|
80
|
+
* By default, this is false.
|
|
81
|
+
*/
|
|
82
|
+
clearTerminalData?: boolean
|
|
61
83
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Whether to delete the secrets associated with the instance.
|
|
86
|
+
*
|
|
87
|
+
* By default, this is false.
|
|
88
|
+
*/
|
|
89
|
+
deleteSecrets?: boolean
|
|
90
|
+
}
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
|
|
92
|
+
export type InstanceStatePatch = Pick<
|
|
93
|
+
Partial<InstanceState>,
|
|
94
|
+
| "status"
|
|
95
|
+
| "message"
|
|
96
|
+
| "statusFields"
|
|
97
|
+
| "parentId"
|
|
98
|
+
| "lastOperationState"
|
|
99
|
+
| "inputHash"
|
|
100
|
+
| "outputHash"
|
|
101
|
+
| "dependencyOutputHash"
|
|
102
|
+
| "model"
|
|
103
|
+
| "resolvedInputs"
|
|
104
|
+
| "currentResourceCount"
|
|
105
|
+
>
|
|
106
|
+
|
|
107
|
+
export type UpdateOperationStateOptions = {
|
|
108
|
+
/**
|
|
109
|
+
* The operation state to update.
|
|
110
|
+
*/
|
|
111
|
+
operationState: InstanceOperationStateUpdateInput
|
|
69
112
|
|
|
70
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Instance state patch to update or function to compute patch from current state.
|
|
115
|
+
*/
|
|
116
|
+
instanceState?: InstanceStatePatch
|
|
71
117
|
|
|
72
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Unit-specific extra data to update.
|
|
120
|
+
*/
|
|
121
|
+
unitExtra?: {
|
|
122
|
+
/**
|
|
123
|
+
* Unit pages to update.
|
|
124
|
+
*/
|
|
125
|
+
pages: UnitPage[]
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Unit terminals to update.
|
|
129
|
+
*/
|
|
130
|
+
terminals: UnitTerminal[]
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Unit triggers to update.
|
|
134
|
+
*/
|
|
135
|
+
triggers: UnitTrigger[]
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Unit workers to update.
|
|
139
|
+
*/
|
|
140
|
+
workers: UnitWorker[]
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Unit secrets to update.
|
|
144
|
+
*/
|
|
145
|
+
secrets: Record<string, unknown>
|
|
73
146
|
}
|
|
147
|
+
}
|
|
74
148
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
149
|
+
export function includeForInstanceState(
|
|
150
|
+
options: GetProjectInstancesOptions = {},
|
|
151
|
+
): InstanceStateInclude {
|
|
152
|
+
return {
|
|
153
|
+
secrets: {
|
|
154
|
+
select: { name: true },
|
|
155
|
+
},
|
|
78
156
|
|
|
79
|
-
|
|
80
|
-
throw new Error(`Instance state with ID "${patch.id}" not found in project "${projectId}"`)
|
|
81
|
-
}
|
|
157
|
+
parent: options.includeParentInstanceId ? { select: { instanceId: true } } : undefined,
|
|
82
158
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
patch,
|
|
87
|
-
patch.operationStatus !== undefined,
|
|
88
|
-
)
|
|
159
|
+
operationStates: options.includeLastOperationState
|
|
160
|
+
? { take: 1, orderBy: { startedAt: "desc" } }
|
|
161
|
+
: undefined,
|
|
89
162
|
|
|
90
|
-
|
|
91
|
-
{ projectId, instanceId: patch.id, patch },
|
|
92
|
-
`instance state updated for instance "%s" in project "%s"`,
|
|
93
|
-
patch.id,
|
|
94
|
-
projectId,
|
|
95
|
-
)
|
|
163
|
+
evaluationState: options.includeEvaluationState,
|
|
96
164
|
|
|
97
|
-
|
|
98
|
-
}
|
|
165
|
+
terminals: options.includeExtra ? { select: { id: true } } : undefined,
|
|
166
|
+
pages: options.includeExtra ? { select: { id: true } } : undefined,
|
|
167
|
+
|
|
168
|
+
customStatuses: options.loadCustomStatuses
|
|
169
|
+
? {
|
|
170
|
+
orderBy: [{ order: "asc" }, { createdAt: "asc" }],
|
|
171
|
+
}
|
|
172
|
+
: undefined,
|
|
99
173
|
}
|
|
174
|
+
}
|
|
100
175
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
176
|
+
export function mapInstanceStateResult(
|
|
177
|
+
instance: InstanceState & {
|
|
178
|
+
secrets: { name: string | null }[]
|
|
179
|
+
parent?: { instanceId: InstanceId } | null
|
|
180
|
+
operationStates?: InstanceOperationState[]
|
|
181
|
+
terminals?: { id: string }[]
|
|
182
|
+
pages?: { id: string }[]
|
|
183
|
+
customStatuses: InstanceState["customStatuses"]
|
|
184
|
+
},
|
|
185
|
+
): InstanceState {
|
|
186
|
+
return {
|
|
187
|
+
...omit(instance, [
|
|
188
|
+
"secrets",
|
|
189
|
+
"parent",
|
|
190
|
+
"operationStates",
|
|
191
|
+
"terminals",
|
|
192
|
+
"pages",
|
|
193
|
+
"customStatuses",
|
|
194
|
+
]),
|
|
195
|
+
|
|
196
|
+
secretNames: instance.secrets.map(secret => secret.name).filter(isNonNullish),
|
|
197
|
+
parentInstanceId: instance.parent ? (instance.parent?.instanceId ?? null) : undefined,
|
|
198
|
+
lastOperationState: instance.operationStates?.[0],
|
|
199
|
+
evaluationState: instance.evaluationState ?? undefined,
|
|
200
|
+
terminalIds: instance.terminals ? instance.terminals.map(terminal => terminal.id) : undefined,
|
|
201
|
+
pageIds: instance.pages ? instance.pages.map(page => page.id) : undefined,
|
|
202
|
+
customStatuses: instance.customStatuses ?? undefined,
|
|
203
|
+
}
|
|
204
|
+
}
|
|
108
205
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
206
|
+
export class InstanceStateService {
|
|
207
|
+
constructor(
|
|
208
|
+
private readonly database: DatabaseManager,
|
|
209
|
+
private readonly pubsubManager: PubSubManager,
|
|
210
|
+
private readonly runnerBackend: RunnerBackend,
|
|
211
|
+
private readonly workerService: WorkerService,
|
|
212
|
+
private readonly artifactService: ArtifactService,
|
|
213
|
+
private readonly unitExtraService: UnitExtraService,
|
|
214
|
+
private readonly secretService: SecretService,
|
|
215
|
+
private readonly logger: Logger,
|
|
216
|
+
) {}
|
|
115
217
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
218
|
+
/**
|
|
219
|
+
* Gets the aggregates of all instances in the project.
|
|
220
|
+
*
|
|
221
|
+
* @param projectId The ID of the project for which to retrieve instances.
|
|
222
|
+
* @param options Options to customize the retrieval of instances.
|
|
223
|
+
*/
|
|
224
|
+
async getInstanceStates(
|
|
225
|
+
projectId: string,
|
|
226
|
+
options: GetProjectInstancesOptions = {},
|
|
227
|
+
): Promise<InstanceState[]> {
|
|
228
|
+
const database = await this.database.forProject(projectId)
|
|
122
229
|
|
|
123
|
-
|
|
230
|
+
// load instance states from the database
|
|
231
|
+
const queryResult = await database.instanceState.findMany({
|
|
232
|
+
include: includeForInstanceState(options),
|
|
124
233
|
})
|
|
234
|
+
|
|
235
|
+
// aggregate the results from the database
|
|
236
|
+
return queryResult.map(mapInstanceStateResult)
|
|
125
237
|
}
|
|
126
238
|
|
|
127
|
-
|
|
239
|
+
/**
|
|
240
|
+
* Marks an instance state as deleted and cleans up associated resources.
|
|
241
|
+
*
|
|
242
|
+
* This operation:
|
|
243
|
+
* - only allows deletion of instances with operation state null or "destroyed";
|
|
244
|
+
* - prevents deletion of instances that have active locks;
|
|
245
|
+
* - marks the instance state as "deleted" (never actually removes the record);
|
|
246
|
+
* - handles terminals: deletes data if requested, otherwise marks as "unavailable";
|
|
247
|
+
* - handles secrets: deletes if requested, otherwise ignores them;
|
|
248
|
+
* - deletes artifact references for the instance;
|
|
249
|
+
* - recursively handles child instances using parentId relationship;
|
|
250
|
+
* - performs worker cleanup and synchronization;
|
|
251
|
+
* - performs artifact garbage collection.
|
|
252
|
+
*
|
|
253
|
+
* @param projectId The ID of the project containing the instance.
|
|
254
|
+
* @param instanceId The ID of the instance whose state is to be marked as deleted.
|
|
255
|
+
* @param options Configuration options for terminal and secret handling.
|
|
256
|
+
*/
|
|
257
|
+
async forgetInstanceState(
|
|
128
258
|
projectId: string,
|
|
129
|
-
instanceId:
|
|
130
|
-
|
|
131
|
-
secretNamesToRemove: string[],
|
|
132
|
-
invalidateState = true,
|
|
259
|
+
instanceId: InstanceId,
|
|
260
|
+
{ deleteSecrets = false, clearTerminalData = false }: ForgetInstanceStateOptions = {},
|
|
133
261
|
): Promise<void> {
|
|
134
|
-
await this.
|
|
135
|
-
|
|
262
|
+
const database = await this.database.forProject(projectId)
|
|
263
|
+
const project = await this.database.backend.project.findUnique({
|
|
264
|
+
where: { id: projectId },
|
|
265
|
+
select: forSchema(projectOutputSchema),
|
|
266
|
+
})
|
|
136
267
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
268
|
+
if (!project) {
|
|
269
|
+
throw new ProjectNotFoundError(projectId)
|
|
270
|
+
}
|
|
141
271
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
272
|
+
// collect instances to process cleanup after transaction
|
|
273
|
+
const unitInstancesToCleanup: { id: string; instanceId: InstanceId }[] = []
|
|
274
|
+
const updatedStateIds: string[] = []
|
|
145
275
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
276
|
+
await database.$transaction(async tx => {
|
|
277
|
+
const state = await tx.instanceState.findUnique({
|
|
278
|
+
where: { instanceId },
|
|
279
|
+
select: { id: true, kind: true, instanceId: true, lock: { select: { stateId: true } } },
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
if (!state) {
|
|
283
|
+
throw new InstanceStateNotFoundError(projectId, instanceId)
|
|
149
284
|
}
|
|
150
285
|
|
|
151
|
-
if (state
|
|
152
|
-
|
|
153
|
-
// if not, the invalidation makes no sense
|
|
154
|
-
patch.operationStatus = {
|
|
155
|
-
inputHashNonce: randomBytes(4).readInt32LE(),
|
|
156
|
-
}
|
|
286
|
+
if (state.lock) {
|
|
287
|
+
throw new InstanceLockedError(projectId, instanceId)
|
|
157
288
|
}
|
|
158
289
|
|
|
159
|
-
await this.
|
|
290
|
+
await this.processInstanceDeletion(
|
|
291
|
+
tx,
|
|
292
|
+
projectId,
|
|
293
|
+
state,
|
|
294
|
+
{ deleteSecrets, clearTerminalData },
|
|
295
|
+
unitInstancesToCleanup,
|
|
296
|
+
updatedStateIds,
|
|
297
|
+
)
|
|
160
298
|
})
|
|
299
|
+
|
|
300
|
+
// publish state events for all updated instances
|
|
301
|
+
for (const updatedStateId of updatedStateIds) {
|
|
302
|
+
void this.pubsubManager.publish(["instance-state", projectId], {
|
|
303
|
+
type: "patched",
|
|
304
|
+
stateId: updatedStateId,
|
|
305
|
+
patch: {
|
|
306
|
+
status: "undeployed",
|
|
307
|
+
statusFields: null,
|
|
308
|
+
inputHash: null,
|
|
309
|
+
outputHash: null,
|
|
310
|
+
dependencyOutputHash: null,
|
|
311
|
+
message: null,
|
|
312
|
+
currentResourceCount: null,
|
|
313
|
+
model: null,
|
|
314
|
+
resolvedInputs: null,
|
|
315
|
+
secretNames: deleteSecrets ? [] : undefined,
|
|
316
|
+
terminalIds: clearTerminalData ? [] : undefined,
|
|
317
|
+
pageIds: [],
|
|
318
|
+
customStatuses: [],
|
|
319
|
+
triggerIds: [],
|
|
320
|
+
evaluationState: null,
|
|
321
|
+
},
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// process side effects
|
|
326
|
+
try {
|
|
327
|
+
await waitAll([
|
|
328
|
+
this.workerService.cleanupWorkerUsageAndSync(projectId),
|
|
329
|
+
this.artifactService.collectGarbage(projectId),
|
|
330
|
+
...unitInstancesToCleanup.map(async ({ id, instanceId }) => {
|
|
331
|
+
const [instanceType, instanceName] = parseInstanceId(instanceId)
|
|
332
|
+
|
|
333
|
+
await this.runnerBackend.deleteState({
|
|
334
|
+
projectId: project.id,
|
|
335
|
+
stateId: id,
|
|
336
|
+
libraryId: project.libraryId,
|
|
337
|
+
instanceName,
|
|
338
|
+
instanceType,
|
|
339
|
+
})
|
|
340
|
+
}),
|
|
341
|
+
])
|
|
342
|
+
} catch (error) {
|
|
343
|
+
this.logger.warn(
|
|
344
|
+
{ error, projectId, instanceId },
|
|
345
|
+
"failed to perform side effects after forgetting instance state",
|
|
346
|
+
)
|
|
347
|
+
}
|
|
161
348
|
}
|
|
162
349
|
|
|
163
350
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* @param projectId The ID of the project from which to delete the instance state.
|
|
167
|
-
* @param instanceId The ID of the instance whose state is to be deleted.
|
|
351
|
+
* Processes the deletion of an instance within a transaction.
|
|
352
|
+
* Handles validation, deletion logic, and recursive child deletion.
|
|
168
353
|
*/
|
|
169
|
-
async
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
354
|
+
private async processInstanceDeletion(
|
|
355
|
+
tx: ProjectTransaction,
|
|
356
|
+
projectId: string,
|
|
357
|
+
state: { id: string; kind: ComponentKind; instanceId: InstanceId },
|
|
358
|
+
options: ForgetInstanceStateOptions,
|
|
359
|
+
unitInstancesToCleanup: { id: string; instanceId: InstanceId }[],
|
|
360
|
+
updatedStateIds: string[],
|
|
361
|
+
): Promise<void> {
|
|
362
|
+
const { deleteSecrets = false, clearTerminalData = false } = options
|
|
363
|
+
|
|
364
|
+
// always mark instance state as undeployed (never actually delete the record)
|
|
365
|
+
await tx.instanceState.update({
|
|
366
|
+
where: { id: state.id },
|
|
367
|
+
data: {
|
|
368
|
+
status: "undeployed",
|
|
369
|
+
statusFields: DbNull,
|
|
370
|
+
inputHash: null,
|
|
371
|
+
outputHash: null,
|
|
372
|
+
dependencyOutputHash: null,
|
|
373
|
+
message: null,
|
|
374
|
+
currentResourceCount: null,
|
|
375
|
+
model: DbNull,
|
|
376
|
+
resolvedInputs: DbNull,
|
|
377
|
+
},
|
|
378
|
+
})
|
|
186
379
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
380
|
+
// handle terminals
|
|
381
|
+
if (clearTerminalData) {
|
|
382
|
+
await tx.terminal.deleteMany({ where: { stateId: state.id } })
|
|
383
|
+
} else {
|
|
384
|
+
await tx.terminal.updateMany({
|
|
385
|
+
where: { stateId: state.id },
|
|
386
|
+
data: { status: "unavailable" },
|
|
387
|
+
})
|
|
388
|
+
}
|
|
190
389
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
390
|
+
// handle secrets
|
|
391
|
+
if (deleteSecrets) {
|
|
392
|
+
await tx.secret.deleteMany({
|
|
393
|
+
where: { stateId: state.id },
|
|
394
|
+
})
|
|
395
|
+
}
|
|
195
396
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
397
|
+
// delete custom statuses for this instance
|
|
398
|
+
await tx.instanceCustomStatus.deleteMany({
|
|
399
|
+
where: { stateId: state.id },
|
|
400
|
+
})
|
|
199
401
|
|
|
200
|
-
|
|
201
|
-
|
|
402
|
+
// delete other related resources
|
|
403
|
+
await tx.page.deleteMany({ where: { stateId: state.id } })
|
|
404
|
+
await tx.trigger.deleteMany({ where: { stateId: state.id } })
|
|
405
|
+
|
|
406
|
+
// remove artifact references for this instance
|
|
407
|
+
await tx.instanceState.update({
|
|
408
|
+
where: { id: state.id },
|
|
409
|
+
data: {
|
|
410
|
+
artifacts: {
|
|
411
|
+
set: [],
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
})
|
|
202
415
|
|
|
203
|
-
|
|
204
|
-
|
|
416
|
+
// collect unit instances for Pulumi cleanup (to be done outside transaction)
|
|
417
|
+
if (state.kind === "unit") {
|
|
418
|
+
unitInstancesToCleanup.push({ id: state.id, instanceId: state.instanceId })
|
|
419
|
+
}
|
|
205
420
|
|
|
206
|
-
|
|
207
|
-
|
|
421
|
+
// track this instance as updated
|
|
422
|
+
updatedStateIds.push(state.id)
|
|
423
|
+
|
|
424
|
+
this.logger.info({ projectId }, `marked state "%s" as deleted`, state.id)
|
|
425
|
+
|
|
426
|
+
// recursively handle child instances using parentId
|
|
427
|
+
if (state.kind === "composite") {
|
|
428
|
+
const childStates = await tx.instanceState.findMany({
|
|
429
|
+
where: {
|
|
430
|
+
parentId: state.id,
|
|
431
|
+
status: { not: "undeployed" }, // don't process undeployed children
|
|
432
|
+
},
|
|
433
|
+
select: { id: true, kind: true, instanceId: true },
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
// recursively delete child states (within the same transaction)
|
|
437
|
+
for (const child of childStates) {
|
|
438
|
+
await this.processInstanceDeletion(
|
|
439
|
+
tx,
|
|
208
440
|
projectId,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// clear pulumi state
|
|
217
|
-
this.runnerBackend.deleteState({ projectId, instanceName, instanceType }),
|
|
218
|
-
])
|
|
219
|
-
})
|
|
441
|
+
child,
|
|
442
|
+
options,
|
|
443
|
+
unitInstancesToCleanup,
|
|
444
|
+
updatedStateIds,
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
220
448
|
}
|
|
221
449
|
|
|
450
|
+
/**
|
|
451
|
+
* Replaces or adds a custom status for an instance in a project.
|
|
452
|
+
*
|
|
453
|
+
* @param projectId The ID of the project containing the instance.
|
|
454
|
+
* @param serviceAccoundtId The ID of the service account owning the instance.
|
|
455
|
+
* @param stateId The ID of the instance state to update.
|
|
456
|
+
* @param status The custom status to replace or add.
|
|
457
|
+
*/
|
|
222
458
|
async updateCustomStatus(
|
|
223
459
|
projectId: string,
|
|
224
|
-
|
|
225
|
-
|
|
460
|
+
stateId: string,
|
|
461
|
+
serviceAccountId: string,
|
|
462
|
+
status: InstanceCustomStatusInput,
|
|
226
463
|
): Promise<void> {
|
|
227
|
-
await this.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
464
|
+
const database = await this.database.forProject(projectId)
|
|
465
|
+
|
|
466
|
+
const customStatuses = await database.$transaction(async tx => {
|
|
467
|
+
await tx.instanceCustomStatus.upsert({
|
|
468
|
+
where: {
|
|
469
|
+
stateId_serviceAccountId_name: {
|
|
470
|
+
stateId,
|
|
471
|
+
serviceAccountId,
|
|
472
|
+
name: status.name,
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
create: {
|
|
476
|
+
stateId: stateId,
|
|
477
|
+
serviceAccountId,
|
|
478
|
+
name: status.name,
|
|
479
|
+
meta: status.meta,
|
|
480
|
+
value: status.value,
|
|
481
|
+
message: status.message ?? null,
|
|
482
|
+
order: status.order ?? 50,
|
|
483
|
+
},
|
|
484
|
+
update: {
|
|
485
|
+
meta: status.meta,
|
|
486
|
+
value: status.value,
|
|
487
|
+
message: status.message ?? null,
|
|
488
|
+
order: status.order ?? 50,
|
|
489
|
+
},
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
return await tx.instanceCustomStatus.findMany({
|
|
493
|
+
where: { stateId, serviceAccountId },
|
|
494
|
+
orderBy: [{ order: "asc" }, { createdAt: "asc" }],
|
|
495
|
+
})
|
|
496
|
+
})
|
|
234
497
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
498
|
+
void this.pubsubManager.publish(["instance-state", projectId], {
|
|
499
|
+
type: "patched",
|
|
500
|
+
stateId,
|
|
501
|
+
patch: { customStatuses },
|
|
502
|
+
})
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Removes a custom status from an instance in a project.
|
|
507
|
+
*
|
|
508
|
+
* @param projectId The ID of the project containing the instance.
|
|
509
|
+
* @param stateId The ID of the instance state to update.
|
|
510
|
+
* @param serviceAccountId The ID of the service account owning the instance.
|
|
511
|
+
* @param statusName The name of the custom status to remove.
|
|
512
|
+
*/
|
|
513
|
+
async removeCustomStatus(
|
|
514
|
+
projectId: string,
|
|
515
|
+
stateId: string,
|
|
516
|
+
serviceAccountId: string,
|
|
517
|
+
statusName: string,
|
|
518
|
+
): Promise<void> {
|
|
519
|
+
const database = await this.database.forProject(projectId)
|
|
520
|
+
|
|
521
|
+
const customStatuses = await database.$transaction(async tx => {
|
|
522
|
+
await tx.instanceCustomStatus.deleteMany({
|
|
523
|
+
where: {
|
|
524
|
+
stateId,
|
|
525
|
+
serviceAccountId,
|
|
526
|
+
name: statusName,
|
|
527
|
+
},
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
return await tx.instanceCustomStatus.findMany({
|
|
531
|
+
where: { stateId, serviceAccountId },
|
|
532
|
+
orderBy: [{ order: "asc" }, { createdAt: "asc" }],
|
|
533
|
+
})
|
|
534
|
+
})
|
|
243
535
|
|
|
244
|
-
|
|
536
|
+
void this.pubsubManager.publish(["instance-state", projectId], {
|
|
537
|
+
type: "patched",
|
|
538
|
+
stateId,
|
|
539
|
+
patch: { customStatuses },
|
|
245
540
|
})
|
|
246
541
|
}
|
|
247
542
|
|
|
248
|
-
|
|
543
|
+
/**
|
|
544
|
+
* Creates the provided operation states.
|
|
545
|
+
* Also updates the instance state if provided.
|
|
546
|
+
*
|
|
547
|
+
* @param projectId The ID of the project containing the instances.
|
|
548
|
+
* @param operationStates The tuples of operation state data to create and instance state patch to apply.
|
|
549
|
+
*/
|
|
550
|
+
async createOperationStates(
|
|
249
551
|
projectId: string,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
type: "deleted",
|
|
271
|
-
instanceId: patchedState.id,
|
|
552
|
+
operationStates: [
|
|
553
|
+
opState: InstanceOperationStateCreateManyInput,
|
|
554
|
+
instanceState: InstanceStatePatch,
|
|
555
|
+
][],
|
|
556
|
+
): Promise<Partial<InstanceState>[]> {
|
|
557
|
+
const database = await this.database.forProject(projectId)
|
|
558
|
+
|
|
559
|
+
const patches = await database.$transaction(async tx => {
|
|
560
|
+
return await Promise.all(
|
|
561
|
+
operationStates.map(async ([opState, instanceState]) => {
|
|
562
|
+
const operationState = await tx.instanceOperationState.create({
|
|
563
|
+
data: opState,
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
const state = await tx.instanceState.update({
|
|
567
|
+
where: { id: opState.stateId },
|
|
568
|
+
data: instanceState as InstanceStateUpdateInput,
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
return { ...state, lastOperationState: operationState }
|
|
272
572
|
}),
|
|
273
573
|
)
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
// publish patches after transaction
|
|
577
|
+
for (const patch of patches) {
|
|
578
|
+
void this.pubsubManager.publish(["instance-state", projectId], {
|
|
579
|
+
type: "patched",
|
|
580
|
+
stateId: patch.id,
|
|
581
|
+
patch,
|
|
582
|
+
})
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return patches
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Updates the operation state and instance state for a specific instance.
|
|
590
|
+
*
|
|
591
|
+
* @param projectId The ID of the project containing the instance.
|
|
592
|
+
* @param stateId The ID of the instance state to update.
|
|
593
|
+
* @param operationId The ID of the operation (required if operationState is provided).
|
|
594
|
+
* @param options Update options containing operation state, instance state, and unit-specific data.
|
|
595
|
+
* @return The instance state patch containing the updated operation state and instance state fields.
|
|
596
|
+
*/
|
|
597
|
+
async updateOperationState(
|
|
598
|
+
projectId: string,
|
|
599
|
+
stateId: string,
|
|
600
|
+
operationId: string,
|
|
601
|
+
options: UpdateOperationStateOptions,
|
|
602
|
+
): Promise<Partial<InstanceState>> {
|
|
603
|
+
const { operationState, instanceState, unitExtra } = options
|
|
604
|
+
const database = await this.database.forProject(projectId)
|
|
605
|
+
|
|
606
|
+
const result = await database.$transaction(async tx => {
|
|
607
|
+
let unitExtraData = null
|
|
608
|
+
|
|
609
|
+
// update operation state
|
|
610
|
+
const updatedOperationState = await tx.instanceOperationState.update({
|
|
611
|
+
where: {
|
|
612
|
+
operationId_stateId: {
|
|
613
|
+
operationId,
|
|
614
|
+
stateId,
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
data: operationState,
|
|
618
|
+
})
|
|
619
|
+
|
|
620
|
+
const project = await this.database.backend.project.findUnique({
|
|
621
|
+
where: { id: projectId },
|
|
622
|
+
select: { libraryId: true },
|
|
623
|
+
})
|
|
624
|
+
|
|
625
|
+
if (!project) {
|
|
626
|
+
throw new ProjectNotFoundError(projectId)
|
|
627
|
+
}
|
|
274
628
|
|
|
275
|
-
if
|
|
276
|
-
|
|
629
|
+
// update unit-specific data if provided
|
|
630
|
+
if (unitExtra) {
|
|
631
|
+
const [pageIds, terminalIds, triggerIds, secretNames] = await Promise.all([
|
|
632
|
+
this.unitExtraService.processUnitPages(tx, stateId, unitExtra.pages),
|
|
633
|
+
this.unitExtraService.processUnitTerminals(tx, stateId, unitExtra.terminals),
|
|
634
|
+
this.unitExtraService.processUnitTriggers(tx, stateId, unitExtra.triggers),
|
|
635
|
+
this.secretService.updateInstanceSecretsCore(
|
|
636
|
+
tx,
|
|
637
|
+
project.libraryId,
|
|
638
|
+
stateId,
|
|
639
|
+
unitExtra.secrets,
|
|
640
|
+
),
|
|
641
|
+
this.workerService.updateUnitRegistrations(tx, projectId, stateId, unitExtra.workers),
|
|
642
|
+
])
|
|
643
|
+
|
|
644
|
+
unitExtraData = { pageIds, terminalIds, triggerIds, secretNames }
|
|
277
645
|
}
|
|
278
|
-
} else {
|
|
279
|
-
promises.push(
|
|
280
|
-
this.pubsubManager.publish(["instance-state", projectId], { type: "patched", patch }),
|
|
281
|
-
)
|
|
282
646
|
|
|
283
|
-
if
|
|
284
|
-
|
|
647
|
+
// update instance state if provided
|
|
648
|
+
if (instanceState) {
|
|
649
|
+
await tx.instanceState.update({
|
|
650
|
+
where: { id: stateId },
|
|
651
|
+
data: instanceState as InstanceStateUpdateInput,
|
|
652
|
+
})
|
|
285
653
|
}
|
|
654
|
+
|
|
655
|
+
return { updatedOperationState, unitExtraData }
|
|
656
|
+
})
|
|
657
|
+
|
|
658
|
+
// build patch combining operation state, instance state, and unit extra data
|
|
659
|
+
const patch: Partial<InstanceState> = {
|
|
660
|
+
...instanceState,
|
|
661
|
+
...result.unitExtraData,
|
|
662
|
+
lastOperationState: result.updatedOperationState,
|
|
286
663
|
}
|
|
287
664
|
|
|
288
|
-
|
|
665
|
+
// emit the patch after transaction
|
|
666
|
+
void this.pubsubManager.publish(["instance-state", projectId], {
|
|
667
|
+
type: "patched",
|
|
668
|
+
stateId,
|
|
669
|
+
patch,
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
this.logger.debug(
|
|
673
|
+
{ projectId, stateId, operationId, options },
|
|
674
|
+
"updated operation state for instance",
|
|
675
|
+
)
|
|
289
676
|
|
|
290
|
-
return
|
|
677
|
+
return patch
|
|
291
678
|
}
|
|
292
679
|
}
|