@highstate/backend 0.9.18 → 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-OU5OQBLB.js → chunk-I7BWSAN6.js} +3 -28
- package/dist/{chunk-OU5OQBLB.js.map → chunk-I7BWSAN6.js.map} +1 -1
- package/dist/chunk-VB4YL327.js +139 -0
- 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 +2 -1
- package/dist/index.js +7587 -7291
- 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/library/worker/main.js +35 -29
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +2 -2
- package/package.json +18 -9
- 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 +30 -54
- package/src/artifact/factory.ts +6 -9
- package/src/artifact/local.ts +33 -46
- package/src/business/api-key.ts +24 -36
- package/src/business/artifact.test.ts +978 -0
- package/src/business/artifact.ts +136 -216
- package/src/business/evaluation.ts +328 -0
- package/src/business/index.ts +5 -2
- package/src/business/instance-lock.test.ts +1060 -0
- package/src/business/instance-lock.ts +387 -78
- package/src/business/instance-state.test.ts +735 -0
- package/src/business/instance-state.ts +582 -337
- 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 +168 -126
- package/src/business/project.ts +287 -179
- package/src/business/secret.test.ts +465 -130
- package/src/business/secret.ts +186 -217
- 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 +356 -579
- package/src/business/worker.ts +238 -339
- package/src/common/codebase.ts +65 -0
- package/src/common/index.ts +3 -5
- package/src/common/logger.ts +5 -0
- package/src/common/utils.ts +4 -3
- package/src/config.ts +10 -11
- 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 +3 -5
- package/src/library/factory.ts +1 -1
- package/src/library/local.ts +81 -26
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/library/worker/evaluator.ts +40 -23
- package/src/library/worker/loader.lite.ts +1 -1
- package/src/library/worker/main.ts +3 -10
- package/src/library/worker/protocol.ts +0 -1
- package/src/lock/index.ts +0 -1
- package/src/lock/manager.ts +0 -10
- package/src/orchestrator/manager.ts +190 -104
- 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 +233 -578
- package/src/orchestrator/operation.ts +435 -948
- 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 +29 -13
- package/src/pubsub/memory.ts +31 -0
- package/src/runner/abstractions.ts +33 -41
- package/src/runner/artifact-env.ts +19 -8
- package/src/runner/factory.ts +6 -6
- package/src/runner/force-abort.ts +3 -6
- package/src/runner/local.ts +64 -67
- package/src/runner/pulumi.ts +23 -63
- package/src/services.ts +181 -123
- package/src/shared/models/backend/index.ts +3 -1
- package/src/shared/models/backend/library.ts +9 -1
- package/src/shared/models/backend/project.ts +43 -42
- 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 -26
- 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 -59
- package/src/shared/models/project/artifact.ts +16 -76
- package/src/shared/models/project/custom-status.ts +12 -0
- package/src/shared/models/project/index.ts +8 -7
- package/src/shared/models/project/lock.ts +10 -78
- package/src/shared/models/project/model.ts +19 -1
- 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 -89
- package/src/shared/models/project/service-account.ts +12 -17
- package/src/shared/models/project/state.ts +100 -407
- package/src/shared/models/project/terminal.ts +75 -88
- package/src/shared/models/project/trigger.ts +13 -49
- package/src/shared/models/project/unlock-method.ts +20 -26
- package/src/shared/models/project/worker.ts +89 -90
- package/src/shared/resolvers/graph-resolver.ts +21 -0
- package/src/shared/resolvers/index.ts +1 -1
- package/src/shared/resolvers/input-hash.ts +24 -14
- package/src/shared/resolvers/input.ts +1 -1
- package/src/shared/resolvers/registry.ts +5 -4
- package/src/shared/resolvers/state.ts +12 -1
- package/src/shared/resolvers/validation.ts +7 -3
- package/src/shared/utils/index.ts +1 -2
- 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 +5 -23
- package/src/unlock/memory.ts +9 -14
- package/src/worker/abstractions.ts +7 -4
- package/src/worker/docker.ts +14 -19
- package/src/worker/manager.ts +366 -97
- package/dist/chunk-NAAIDR4U.js +0 -8499
- package/dist/chunk-NAAIDR4U.js.map +0 -1
- package/dist/chunk-Y7DXREVO.js +0 -1745
- package/dist/chunk-Y7DXREVO.js.map +0 -1
- package/dist/magic-string.es-5ABAC4JN.js +0 -1292
- package/dist/magic-string.es-5ABAC4JN.js.map +0 -1
- package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +0 -356
- package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +0 -274
- package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +0 -223
- package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +0 -147
- package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +0 -280
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +0 -360
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +0 -215
- package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +0 -427
- package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +0 -217
- package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +0 -132
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +0 -454
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +0 -426
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +0 -372
- package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +0 -383
- package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +0 -245
- package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +0 -174
- package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +0 -432
- package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +0 -220
- package/src/business/backend-unlock.ts +0 -10
- package/src/common/clock.ts +0 -18
- package/src/common/performance.ts +0 -44
- package/src/common/random.ts +0 -68
- package/src/common/test/index.ts +0 -2
- package/src/common/test/render.ts +0 -98
- package/src/common/test/tracer.ts +0 -359
- 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 -100
- package/src/lock/test.ts +0 -108
- package/src/project/abstractions.ts +0 -78
- package/src/project/evaluation.ts +0 -248
- package/src/project/factory.ts +0 -11
- package/src/project/index.ts +0 -3
- package/src/project/local.ts +0 -417
- package/src/pubsub/local.ts +0 -36
- package/src/pubsub/validation.ts +0 -33
- package/src/shared/utils/args.ts +0 -25
- package/src/state/abstractions.ts +0 -289
- package/src/state/encryption.ts +0 -98
- package/src/state/factory.ts +0 -20
- package/src/state/index.ts +0 -7
- package/src/state/local/backend.ts +0 -106
- package/src/state/local/collection.ts +0 -361
- package/src/state/local/index.ts +0 -2
- package/src/state/manager.ts +0 -890
- package/src/state/memory/backend.ts +0 -70
- package/src/state/memory/collection.ts +0 -270
- package/src/state/memory/index.ts +0 -2
- package/src/state/repository/index.ts +0 -2
- package/src/state/repository/repository.index.ts +0 -193
- package/src/state/repository/repository.ts +0 -507
- package/src/state/test.ts +0 -457
- /package/src/{state → database/local}/keyring.ts +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { Logger } from "pino"
|
|
2
|
+
import type { ProjectUnlockBackend } from "../unlock"
|
|
3
|
+
import type { BackendDatabase, ProjectDatabase } from "./prisma"
|
|
4
|
+
import { LRUCache } from "lru-cache"
|
|
5
|
+
import z from "zod"
|
|
6
|
+
import { createProjectLogger } from "../common"
|
|
7
|
+
import { BackendError, ProjectLockedError, ProjectNotFoundError } from "../shared"
|
|
8
|
+
import { type ProjectDatabaseBackend, projectDatabaseVersion } from "./abstractions"
|
|
9
|
+
import { migrateDatabase } from "./migrate"
|
|
10
|
+
|
|
11
|
+
export const databaseManagerConfig = z.object({
|
|
12
|
+
HIGHSTATE_ENCRYPTION_ENABLED: z.stringbool().default(true),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export interface DatabaseManager {
|
|
16
|
+
/**
|
|
17
|
+
* The backend database instance.
|
|
18
|
+
*/
|
|
19
|
+
readonly backend: BackendDatabase
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether the encryption is enabled for the backend and project databases.
|
|
23
|
+
*/
|
|
24
|
+
readonly isEncryptionEnabled: boolean
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the master key of the project with the given ID.
|
|
28
|
+
*
|
|
29
|
+
* If the project does not exist or is not unlocked, this will throw an error.
|
|
30
|
+
*
|
|
31
|
+
* Returns `undefined` if the encryption is not enabled.
|
|
32
|
+
*
|
|
33
|
+
* @param projectId The ID of the project to get the master key for.
|
|
34
|
+
* @returns A Promise that resolves to the master key of the project as a Uint8Array.
|
|
35
|
+
*/
|
|
36
|
+
getProjectMasterKey(projectId: string): Promise<Buffer | undefined>
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Sets up the database for the project with the given ID.
|
|
40
|
+
*
|
|
41
|
+
* Assumes that no database exists yet.
|
|
42
|
+
*
|
|
43
|
+
* The project must be unlocked before calling this method.
|
|
44
|
+
*
|
|
45
|
+
* @param projectId The ID of the project to set up the database for.
|
|
46
|
+
*/
|
|
47
|
+
setupDatabase(projectId: string): Promise<ProjectDatabase>
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the database client for the project with the given ID.
|
|
51
|
+
*
|
|
52
|
+
* Automatically migrates the project database if necessary.
|
|
53
|
+
*
|
|
54
|
+
* If the project does not exist or not unlocked, this will throw an error.
|
|
55
|
+
*
|
|
56
|
+
* @param projectId The ID of the project to get the database client for.
|
|
57
|
+
*/
|
|
58
|
+
forProject(projectId: string): Promise<ProjectDatabase>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class DatabaseManagerImpl implements DatabaseManager {
|
|
62
|
+
constructor(
|
|
63
|
+
readonly backend: BackendDatabase,
|
|
64
|
+
private readonly projectUnlockBackend: ProjectUnlockBackend,
|
|
65
|
+
private readonly projectDatabaseBackend: ProjectDatabaseBackend,
|
|
66
|
+
private readonly config: z.infer<typeof databaseManagerConfig>,
|
|
67
|
+
private readonly logger: Logger,
|
|
68
|
+
) {}
|
|
69
|
+
|
|
70
|
+
// store the master keys in memory cache for 30 seconds
|
|
71
|
+
private readonly projectMasterKeys = new LRUCache<string, Buffer>({
|
|
72
|
+
ttl: 30_000,
|
|
73
|
+
ttlAutopurge: true,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// TODO: auto unload project databases after some time
|
|
77
|
+
private readonly projectDatabases = new Map<string, ProjectDatabase>()
|
|
78
|
+
|
|
79
|
+
get isEncryptionEnabled(): boolean {
|
|
80
|
+
return this.config.HIGHSTATE_ENCRYPTION_ENABLED
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async getProjectMasterKey(projectId: string): Promise<Buffer | undefined> {
|
|
84
|
+
if (!this.isEncryptionEnabled) {
|
|
85
|
+
return undefined
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const cachedInfo = this.projectMasterKeys.get(projectId)
|
|
89
|
+
if (cachedInfo) {
|
|
90
|
+
return cachedInfo
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const masterKey = await this.projectUnlockBackend.getProjectMasterKey(projectId)
|
|
94
|
+
if (!masterKey) {
|
|
95
|
+
throw new ProjectLockedError(projectId)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.projectMasterKeys.set(projectId, masterKey)
|
|
99
|
+
return masterKey
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async setupDatabase(projectId: string): Promise<ProjectDatabase> {
|
|
103
|
+
const logger = createProjectLogger(this.logger, projectId)
|
|
104
|
+
const masterKey = await this.getProjectMasterKey(projectId)
|
|
105
|
+
const hexMasterKey = masterKey?.toString("hex")
|
|
106
|
+
|
|
107
|
+
const [database, databaseUrl] = await this.projectDatabaseBackend.openProjectDatabase(
|
|
108
|
+
projectId,
|
|
109
|
+
hexMasterKey,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
// can safely apply migrations here, because no one knows about the database yet
|
|
113
|
+
await migrateDatabase(databaseUrl, "project", hexMasterKey, logger)
|
|
114
|
+
|
|
115
|
+
this.projectDatabases.set(projectId, database)
|
|
116
|
+
|
|
117
|
+
return database
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async forProject(projectId: string): Promise<ProjectDatabase> {
|
|
121
|
+
const cachedDatabase = this.projectDatabases.get(projectId)
|
|
122
|
+
if (cachedDatabase) {
|
|
123
|
+
return cachedDatabase
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const masterKey = await this.getProjectMasterKey(projectId)
|
|
127
|
+
const hexMasterKey = masterKey?.toString("hex")
|
|
128
|
+
|
|
129
|
+
// TODO: is it really necessary to migrate the database inside the transaction?
|
|
130
|
+
let database = await this.backend.$transaction(async tx => {
|
|
131
|
+
const databaseEntity = await tx.project.findUnique({
|
|
132
|
+
where: { id: projectId },
|
|
133
|
+
select: { databaseVersion: true },
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
if (!databaseEntity) {
|
|
137
|
+
throw new ProjectNotFoundError(projectId)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (databaseEntity.databaseVersion > projectDatabaseVersion) {
|
|
141
|
+
throw new BackendError(
|
|
142
|
+
`Project database version (${databaseEntity.databaseVersion}) is newer than expected (${projectDatabaseVersion}).`,
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (databaseEntity.databaseVersion === projectDatabaseVersion) {
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const [database, databaseUrl] = await this.projectDatabaseBackend.openProjectDatabase(
|
|
151
|
+
projectId,
|
|
152
|
+
hexMasterKey,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
if (databaseEntity.databaseVersion < projectDatabaseVersion) {
|
|
156
|
+
await migrateDatabase(databaseUrl, "project", hexMasterKey, this.logger)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await tx.project.update({
|
|
160
|
+
where: { id: projectId },
|
|
161
|
+
data: { databaseVersion: projectDatabaseVersion },
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return database
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
if (!database) {
|
|
168
|
+
// open database if was not migrated in the transaction
|
|
169
|
+
const [_database] = await this.projectDatabaseBackend.openProjectDatabase(
|
|
170
|
+
projectId,
|
|
171
|
+
hexMasterKey,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
database = _database
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.projectDatabases.set(projectId, database)
|
|
178
|
+
|
|
179
|
+
return database
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Logger } from "pino"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
import { execa } from "execa"
|
|
5
|
+
import { resolve } from "import-meta-resolve"
|
|
6
|
+
import { detectPackageManager } from "nypm"
|
|
7
|
+
|
|
8
|
+
export async function migrateDatabase(
|
|
9
|
+
databaseUrl: string,
|
|
10
|
+
schemaPath: "backend/sqlite" | "project",
|
|
11
|
+
masterKey: string | undefined,
|
|
12
|
+
logger: Logger,
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
logger.info("applying database migrations")
|
|
15
|
+
|
|
16
|
+
const backendIndexPath = resolve("@highstate/backend", import.meta.url)
|
|
17
|
+
const backendRootPath = join(fileURLToPath(backendIndexPath), "..")
|
|
18
|
+
|
|
19
|
+
const packageManager = await detectPackageManager(backendRootPath)
|
|
20
|
+
if (!packageManager) {
|
|
21
|
+
throw new Error("Could not detect package manager to run migrations")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const hasCorepack = await execa`"corepack" --version`.then(() => true).catch(() => false)
|
|
25
|
+
const command = hasCorepack ? `corepack ${packageManager.command}` : packageManager.command
|
|
26
|
+
|
|
27
|
+
await execa({
|
|
28
|
+
cwd: backendRootPath,
|
|
29
|
+
env: {
|
|
30
|
+
HIGHSTATE_MIGRATION_DATABASE_SCHEMA_PATH: schemaPath,
|
|
31
|
+
HIGHSTATE_MIGRATION_DATABASE_URL: databaseUrl,
|
|
32
|
+
HIGHSTATE_MIGRATION_DATABASE_ENCRYPTION_KEY: masterKey ?? "",
|
|
33
|
+
},
|
|
34
|
+
})`${command} migrate`
|
|
35
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type * as runtime from "@prisma/client/runtime/client"
|
|
2
|
+
import { PrismaClient as BackendDatabase } from "./_generated/backend/postgresql/client"
|
|
3
|
+
import { PrismaClient as ProjectDatabase } from "./_generated/project/client"
|
|
4
|
+
|
|
5
|
+
export type BackendTransaction = Omit<BackendDatabase, runtime.ITXClientDenyList>
|
|
6
|
+
export type ProjectTransaction = Omit<ProjectDatabase, runtime.ITXClientDenyList>
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
Library,
|
|
10
|
+
Project,
|
|
11
|
+
ProjectSpace,
|
|
12
|
+
PulumiBackend,
|
|
13
|
+
} from "./_generated/backend/postgresql/client"
|
|
14
|
+
export type {
|
|
15
|
+
ApiKey,
|
|
16
|
+
Artifact,
|
|
17
|
+
InstanceCustomStatus,
|
|
18
|
+
InstanceEvaluationState,
|
|
19
|
+
InstanceEvaluationStatus,
|
|
20
|
+
InstanceLock,
|
|
21
|
+
InstanceOperationState,
|
|
22
|
+
InstanceOperationStatus,
|
|
23
|
+
InstanceSource,
|
|
24
|
+
InstanceState,
|
|
25
|
+
InstanceStatus,
|
|
26
|
+
Operation,
|
|
27
|
+
OperationLog,
|
|
28
|
+
OperationStatus,
|
|
29
|
+
OperationType,
|
|
30
|
+
Page,
|
|
31
|
+
Secret,
|
|
32
|
+
ServiceAccount,
|
|
33
|
+
Terminal,
|
|
34
|
+
TerminalSession,
|
|
35
|
+
TerminalSessionLog,
|
|
36
|
+
TerminalStatus,
|
|
37
|
+
Trigger,
|
|
38
|
+
UnlockMethod,
|
|
39
|
+
Worker,
|
|
40
|
+
WorkerUnitRegistration,
|
|
41
|
+
WorkerVersion,
|
|
42
|
+
WorkerVersionLog,
|
|
43
|
+
} from "./_generated/project/client"
|
|
44
|
+
export type {
|
|
45
|
+
InstanceEvaluationStateUncheckedCreateInput,
|
|
46
|
+
InstanceEvaluationStateUpdateInput,
|
|
47
|
+
InstanceOperationStateCreateInput,
|
|
48
|
+
InstanceOperationStateCreateManyInput,
|
|
49
|
+
InstanceOperationStateUpdateInput,
|
|
50
|
+
InstanceStateInclude,
|
|
51
|
+
InstanceStateUpdateInput,
|
|
52
|
+
OperationUpdateInput,
|
|
53
|
+
} from "./_generated/project/models"
|
|
54
|
+
export { DbNull } from "./_generated/project/internal/prismaNamespace"
|
|
55
|
+
|
|
56
|
+
export { BackendDatabase, ProjectDatabase }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BackendDatabase } from "./prisma"
|
|
2
|
+
import {
|
|
3
|
+
codebaseLibrary,
|
|
4
|
+
codebaseProjectModelStorage,
|
|
5
|
+
databaseProjectModelStorage,
|
|
6
|
+
globalProjectSpace,
|
|
7
|
+
hostPulumiBackend,
|
|
8
|
+
} from "../shared/models/backend/well-known"
|
|
9
|
+
|
|
10
|
+
export async function ensureWellKnownEntitiesCreated(database: BackendDatabase): Promise<void> {
|
|
11
|
+
await database.$transaction([
|
|
12
|
+
database.projectSpace.upsert({
|
|
13
|
+
where: { id: globalProjectSpace.id },
|
|
14
|
+
create: globalProjectSpace,
|
|
15
|
+
update: globalProjectSpace,
|
|
16
|
+
}),
|
|
17
|
+
database.library.upsert({
|
|
18
|
+
where: { id: codebaseLibrary.id },
|
|
19
|
+
create: codebaseLibrary,
|
|
20
|
+
update: codebaseLibrary,
|
|
21
|
+
}),
|
|
22
|
+
database.pulumiBackend.upsert({
|
|
23
|
+
where: { id: hostPulumiBackend.id },
|
|
24
|
+
create: hostPulumiBackend,
|
|
25
|
+
update: hostPulumiBackend,
|
|
26
|
+
}),
|
|
27
|
+
database.projectModelStorage.upsert({
|
|
28
|
+
where: { id: codebaseProjectModelStorage.id },
|
|
29
|
+
create: codebaseProjectModelStorage,
|
|
30
|
+
update: codebaseProjectModelStorage,
|
|
31
|
+
}),
|
|
32
|
+
database.projectModelStorage.upsert({
|
|
33
|
+
where: { id: databaseProjectModelStorage.id },
|
|
34
|
+
create: databaseProjectModelStorage,
|
|
35
|
+
update: databaseProjectModelStorage,
|
|
36
|
+
}),
|
|
37
|
+
])
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from "./
|
|
1
|
+
export * from "./business"
|
|
2
2
|
export * from "./config"
|
|
3
|
+
export * from "./database"
|
|
4
|
+
export * from "./library"
|
|
3
5
|
export * from "./orchestrator"
|
|
4
|
-
export * from "./terminal"
|
|
5
6
|
export * from "./services"
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./business"
|
|
7
|
+
export * from "./terminal"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InstanceModel } from "@highstate/contract"
|
|
1
|
+
import type { InstanceId, InstanceModel } from "@highstate/contract"
|
|
2
2
|
import type { LibraryModel, LibraryUpdate, ResolvedInstanceInput } from "../shared"
|
|
3
3
|
|
|
4
4
|
export type ResolvedUnitSource = {
|
|
@@ -16,7 +16,7 @@ export type ProjectEvaluationResult =
|
|
|
16
16
|
/**
|
|
17
17
|
* The mapping of top-level composite instance IDs to error messages if any.
|
|
18
18
|
*/
|
|
19
|
-
topLevelErrors: Record<
|
|
19
|
+
topLevelErrors: Record<InstanceId, string>
|
|
20
20
|
}
|
|
21
21
|
| {
|
|
22
22
|
success: false
|
|
@@ -58,17 +58,15 @@ export interface LibraryBackend {
|
|
|
58
58
|
): AsyncIterable<ResolvedUnitSource>
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* Evaluates the instances and returns
|
|
61
|
+
* Evaluates the composite instances of the project and returns evaluated virtual instances.
|
|
62
62
|
*
|
|
63
63
|
* @param libraryId The library ID to use for evaluation.
|
|
64
64
|
* @param allInstances The all instances of the project.
|
|
65
65
|
* @param resolvedInputs The resolved inputs of the instances.
|
|
66
|
-
* @param instanceIds The instance ids to evaluate.
|
|
67
66
|
*/
|
|
68
67
|
evaluateCompositeInstances(
|
|
69
68
|
libraryId: string | undefined,
|
|
70
69
|
allInstances: InstanceModel[],
|
|
71
70
|
resolvedInputs: Record<string, Record<string, ResolvedInstanceInput[]>>,
|
|
72
|
-
instanceIds: string[],
|
|
73
71
|
): Promise<ProjectEvaluationResult>
|
|
74
72
|
}
|
package/src/library/factory.ts
CHANGED
package/src/library/local.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import type { LibraryBackend, ProjectEvaluationResult, ResolvedUnitSource } from "./abstractions"
|
|
2
1
|
import type { Logger } from "pino"
|
|
2
|
+
import type { LibraryBackend, ProjectEvaluationResult, ResolvedUnitSource } from "./abstractions"
|
|
3
3
|
import type {
|
|
4
4
|
PackageResolutionResponse,
|
|
5
5
|
PackageResolutionWorkerData,
|
|
6
6
|
} from "./package-resolution-worker"
|
|
7
7
|
import type { WorkerData } from "./worker/protocol"
|
|
8
|
-
import { fileURLToPath } from "node:url"
|
|
9
8
|
import { EventEmitter, on } from "node:events"
|
|
10
|
-
import { Worker } from "node:worker_threads"
|
|
11
|
-
import { resolve } from "node:path"
|
|
12
9
|
import { readFile } from "node:fs/promises"
|
|
10
|
+
import { resolve } from "node:path"
|
|
11
|
+
import { fileURLToPath } from "node:url"
|
|
12
|
+
import { Worker } from "node:worker_threads"
|
|
13
13
|
import { type InstanceModel, isUnitModel } from "@highstate/contract"
|
|
14
|
-
import
|
|
14
|
+
import { decode } from "@msgpack/msgpack"
|
|
15
15
|
import { BetterLock } from "better-lock"
|
|
16
16
|
import { resolve as importMetaResolve } from "import-meta-resolve"
|
|
17
|
-
import {
|
|
17
|
+
import { addDependency, installDependencies, runScript } from "nypm"
|
|
18
18
|
import { readPackageJSON } from "pkg-types"
|
|
19
|
-
import { runScript, installDependencies, addDependency } from "nypm"
|
|
20
19
|
import { flatMap, groupBy, map, pipe, unique } from "remeda"
|
|
21
|
-
import
|
|
20
|
+
import Watcher from "watcher"
|
|
21
|
+
import { z } from "zod"
|
|
22
22
|
import { resolveMainLocalProject, stringArrayType } from "../common"
|
|
23
23
|
import {
|
|
24
24
|
diffLibraries,
|
|
@@ -48,6 +48,11 @@ type LibraryPackage = {
|
|
|
48
48
|
dependents: Set<string>
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
type RebuildState = {
|
|
52
|
+
inProgress: boolean
|
|
53
|
+
pending: boolean
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
export class LocalLibraryBackend implements LibraryBackend {
|
|
52
57
|
private readonly watcher: Watcher
|
|
53
58
|
|
|
@@ -58,6 +63,7 @@ export class LocalLibraryBackend implements LibraryBackend {
|
|
|
58
63
|
|
|
59
64
|
private readonly packages = new Map<string, LibraryPackage>()
|
|
60
65
|
private readonly resolvedUnitSources = new Map<string, ResolvedUnitSource>()
|
|
66
|
+
private readonly rebuildStates = new Map<string, RebuildState>()
|
|
61
67
|
|
|
62
68
|
private constructor(
|
|
63
69
|
private readonly libraryPackages: string[],
|
|
@@ -67,7 +73,7 @@ export class LocalLibraryBackend implements LibraryBackend {
|
|
|
67
73
|
this.watcher = new Watcher(watchPaths, {
|
|
68
74
|
recursive: true,
|
|
69
75
|
ignoreInitial: true,
|
|
70
|
-
ignore: /\.git|node_modules|dist/,
|
|
76
|
+
ignore: /\.git|node_modules|dist|\.highstate/,
|
|
71
77
|
})
|
|
72
78
|
|
|
73
79
|
this.watcher.on("all", (event: string, path: string) => {
|
|
@@ -148,15 +154,11 @@ export class LocalLibraryBackend implements LibraryBackend {
|
|
|
148
154
|
_libraryId: string,
|
|
149
155
|
allInstances: InstanceModel[],
|
|
150
156
|
resolvedInputs: Record<string, Record<string, ResolvedInstanceInput[]>>,
|
|
151
|
-
instanceIds: string[],
|
|
152
157
|
): Promise<ProjectEvaluationResult> {
|
|
153
|
-
this.logger.info("evaluating %d composite instances", instanceIds.length)
|
|
154
|
-
|
|
155
158
|
const worker = this.createLibraryWorker({
|
|
156
159
|
libraryModulePaths: this.libraryPackages,
|
|
157
160
|
allInstances,
|
|
158
161
|
resolvedInputs,
|
|
159
|
-
instanceIds,
|
|
160
162
|
})
|
|
161
163
|
|
|
162
164
|
for await (const [event] of on(worker, "message", { signal: AbortSignal.timeout(10_000) })) {
|
|
@@ -260,7 +262,7 @@ export class LocalLibraryBackend implements LibraryBackend {
|
|
|
260
262
|
|
|
261
263
|
this.resolvedUnitSources.set(unit.type, newResolvedSource)
|
|
262
264
|
this.eventEmitter.emit("resolvedUnitSource", newResolvedSource)
|
|
263
|
-
this.logger.
|
|
265
|
+
this.logger.trace(`updated source for unit: "%s"`, unit.type)
|
|
264
266
|
}
|
|
265
267
|
}
|
|
266
268
|
|
|
@@ -468,22 +470,75 @@ export class LocalLibraryBackend implements LibraryBackend {
|
|
|
468
470
|
}
|
|
469
471
|
}
|
|
470
472
|
|
|
471
|
-
private
|
|
472
|
-
|
|
473
|
-
const libraryPackage = this.packages.values().find(pkg => path.startsWith(pkg.rootPath))
|
|
473
|
+
private handleFileEvent(path: string): void {
|
|
474
|
+
const libraryPackage = this.packages.values().find(pkg => path.startsWith(pkg.rootPath))
|
|
474
475
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
if (!libraryPackage) {
|
|
477
|
+
return
|
|
478
|
+
}
|
|
478
479
|
|
|
479
|
-
|
|
480
|
-
|
|
480
|
+
void this.schedulePackageRebuild(libraryPackage.name)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
private async schedulePackageRebuild(packageName: string): Promise<void> {
|
|
484
|
+
const state = this.rebuildStates.get(packageName) ?? { inProgress: false, pending: false }
|
|
485
|
+
|
|
486
|
+
// if both in progress and pending, discard this request
|
|
487
|
+
if (state.inProgress && state.pending) {
|
|
488
|
+
this.logger.debug(`rebuild in progress and already pending for "%s", discarding`, packageName)
|
|
489
|
+
return
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// if in progress but no pending, mark as pending
|
|
493
|
+
if (state.inProgress && !state.pending) {
|
|
494
|
+
state.pending = true
|
|
495
|
+
this.rebuildStates.set(packageName, state)
|
|
496
|
+
this.logger.debug(`rebuild in progress, scheduling pending rebuild for "%s"`, packageName)
|
|
497
|
+
return
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// not in progress, start immediately
|
|
501
|
+
await this.executePackageRebuild(packageName)
|
|
502
|
+
}
|
|
481
503
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
504
|
+
private async executePackageRebuild(packageName: string): Promise<void> {
|
|
505
|
+
const state = this.rebuildStates.get(packageName) ?? { inProgress: false, pending: false }
|
|
506
|
+
|
|
507
|
+
do {
|
|
508
|
+
// mark as in progress, clear pending
|
|
509
|
+
state.inProgress = true
|
|
510
|
+
state.pending = false
|
|
511
|
+
this.rebuildStates.set(packageName, state)
|
|
512
|
+
|
|
513
|
+
try {
|
|
514
|
+
await this.lock.acquire(async () => {
|
|
515
|
+
const libraryPackage = this.packages.get(packageName)
|
|
516
|
+
|
|
517
|
+
if (!libraryPackage) {
|
|
518
|
+
this.logger.warn(`package not found for rebuild: "%s"`, packageName)
|
|
519
|
+
return
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const builtPackages = new Set<string>()
|
|
523
|
+
await this.rebuildLibraryPackage(libraryPackage, false, false, builtPackages)
|
|
524
|
+
|
|
525
|
+
if (this.libraryPackages.some(pkg => builtPackages.has(pkg))) {
|
|
526
|
+
this.logger.info(
|
|
527
|
+
"reloading library due to file change in package: %s",
|
|
528
|
+
libraryPackage.name,
|
|
529
|
+
)
|
|
530
|
+
await this.reloadLibrary()
|
|
531
|
+
}
|
|
532
|
+
})
|
|
533
|
+
} finally {
|
|
534
|
+
state.inProgress = false
|
|
485
535
|
}
|
|
486
|
-
|
|
536
|
+
|
|
537
|
+
// continue if another rebuild was requested while we were working
|
|
538
|
+
} while (state.pending)
|
|
539
|
+
|
|
540
|
+
// clean up if no longer needed
|
|
541
|
+
this.rebuildStates.delete(packageName)
|
|
487
542
|
}
|
|
488
543
|
|
|
489
544
|
private createLibraryWorker(workerData: WorkerData): Worker {
|
|
@@ -14,20 +14,18 @@ export function evaluateProject(
|
|
|
14
14
|
components: Readonly<Record<string, Component>>,
|
|
15
15
|
allInstances: InstanceModel[],
|
|
16
16
|
resolvedInputs: Record<string, Record<string, ResolvedInstanceInput[]>>,
|
|
17
|
-
instanceIds: string[],
|
|
18
17
|
): ProjectEvaluationResult {
|
|
19
|
-
const errors: Record<string, string> = {}
|
|
20
18
|
const allInstancesMap = new Map(allInstances.map(instance => [instance.id, instance]))
|
|
19
|
+
|
|
20
|
+
const instanceErrors: Record<string, unknown> = {}
|
|
21
|
+
const topLevelErrors: Record<string, string> = {}
|
|
22
|
+
|
|
21
23
|
const instanceOutputs = new Map<string, Record<string, unknown>>()
|
|
22
24
|
|
|
23
|
-
for (const
|
|
25
|
+
for (const instance of allInstances) {
|
|
24
26
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
evaluateInstance(instanceId as InstanceModel["id"])
|
|
27
|
+
evaluateInstance(instance.id)
|
|
28
28
|
} catch (error) {
|
|
29
|
-
errors[instanceId] = errorToString(error)
|
|
30
|
-
|
|
31
29
|
if (error instanceof InstanceNameConflictError) {
|
|
32
30
|
// fail the whole evaluation if there's a name conflict
|
|
33
31
|
return {
|
|
@@ -40,35 +38,54 @@ export function evaluateProject(
|
|
|
40
38
|
|
|
41
39
|
return {
|
|
42
40
|
success: true,
|
|
41
|
+
|
|
43
42
|
virtualInstances: getRuntimeInstances()
|
|
44
43
|
.map(instance => instance.instance)
|
|
45
44
|
// only include top-level composite instances and their children
|
|
46
|
-
.filter(instance =>
|
|
47
|
-
|
|
45
|
+
.filter(instance => instance.kind === "composite" || !allInstancesMap.has(instance.id)),
|
|
46
|
+
|
|
47
|
+
topLevelErrors,
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function evaluateInstance(instanceId: InstanceModel["id"]): Record<string, unknown> {
|
|
51
51
|
let outputs = instanceOutputs.get(instanceId)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
outputs = _evaluateInstance(instanceId)
|
|
55
|
-
instanceOutputs.set(instanceId, outputs)
|
|
52
|
+
if (outputs) {
|
|
53
|
+
return outputs
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
// do not evaluate instance if it has an error, just rethrow it
|
|
57
|
+
const error = instanceErrors[instanceId]
|
|
58
|
+
if (error) {
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
|
60
|
+
throw error
|
|
61
|
+
}
|
|
60
62
|
|
|
61
|
-
function _evaluateInstance(instanceId: InstanceModel["id"]): Record<string, unknown> {
|
|
62
|
-
const inputs: Record<string, unknown> = {}
|
|
63
63
|
const instance = allInstancesMap.get(instanceId)
|
|
64
|
-
|
|
65
|
-
logger.debug("evaluating instance", { instanceId })
|
|
66
|
-
|
|
67
64
|
if (!instance) {
|
|
68
65
|
throw new Error(`Instance not found: ${instanceId}`)
|
|
69
66
|
}
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
try {
|
|
69
|
+
outputs = _evaluateInstance(instance)
|
|
70
|
+
|
|
71
|
+
instanceOutputs.set(instanceId, outputs)
|
|
72
|
+
return outputs
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (instance.kind === "composite" || !allInstancesMap.has(instance.id)) {
|
|
75
|
+
topLevelErrors[instance.id] = errorToString(error)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
instanceErrors[instanceId] = error
|
|
79
|
+
throw error
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _evaluateInstance(instance: InstanceModel): Record<string, unknown> {
|
|
84
|
+
const inputs: Record<string, unknown> = {}
|
|
85
|
+
|
|
86
|
+
logger.debug("evaluating instance", { instanceId: instance.id })
|
|
87
|
+
|
|
88
|
+
for (const [inputName, input] of Object.entries(resolvedInputs[instance.id] ?? {})) {
|
|
72
89
|
inputs[inputName] = input.map(input => {
|
|
73
90
|
const evaluated = evaluateInstance(input.input.instanceId)
|
|
74
91
|
|
|
@@ -78,7 +95,7 @@ export function evaluateProject(
|
|
|
78
95
|
|
|
79
96
|
const component = components[instance.type]
|
|
80
97
|
if (!component) {
|
|
81
|
-
throw new Error(`Component not found: ${instance.type}, required by instance: ${
|
|
98
|
+
throw new Error(`Component not found: ${instance.type}, required by instance: ${instance.id}`)
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
return component({
|
|
@@ -11,20 +11,13 @@ const logger = pino({ name: "library-worker" })
|
|
|
11
11
|
|
|
12
12
|
try {
|
|
13
13
|
const library = await loadComponents(logger, data.libraryModulePaths)
|
|
14
|
+
const result = evaluateProject(logger, library, data.allInstances, data.resolvedInputs)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
logger,
|
|
17
|
-
library,
|
|
18
|
-
data.allInstances,
|
|
19
|
-
data.resolvedInputs,
|
|
20
|
-
data.instanceIds,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
parentPort!.postMessage(result)
|
|
16
|
+
parentPort?.postMessage(result)
|
|
24
17
|
} catch (error) {
|
|
25
18
|
logger.error({ error }, "failed to evaluate project")
|
|
26
19
|
|
|
27
|
-
parentPort
|
|
20
|
+
parentPort?.postMessage({
|
|
28
21
|
success: false,
|
|
29
22
|
error: errorToString(error),
|
|
30
23
|
})
|