@highstate/backend 0.9.15 → 0.9.18
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-NAAIDR4U.js +8499 -0
- package/dist/chunk-NAAIDR4U.js.map +1 -0
- package/dist/chunk-OU5OQBLB.js +74 -0
- package/dist/chunk-OU5OQBLB.js.map +1 -0
- package/dist/chunk-Y7DXREVO.js +1745 -0
- package/dist/chunk-Y7DXREVO.js.map +1 -0
- package/dist/highstate.manifest.json +4 -4
- package/dist/index.js +7227 -2501
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +7 -5
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +76 -185
- package/dist/library/worker/main.js.map +1 -1
- package/dist/magic-string.es-5ABAC4JN.js +1292 -0
- package/dist/magic-string.es-5ABAC4JN.js.map +1 -0
- package/dist/shared/index.js +3 -98
- package/dist/shared/index.js.map +1 -1
- package/package.json +31 -10
- package/src/artifact/abstractions.ts +46 -0
- package/src/artifact/encryption.ts +109 -0
- package/src/artifact/factory.ts +36 -0
- package/src/artifact/index.ts +3 -0
- package/src/artifact/local.ts +138 -0
- package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +356 -0
- package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +274 -0
- package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +223 -0
- package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +147 -0
- package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +280 -0
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +360 -0
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +215 -0
- package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +427 -0
- package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +217 -0
- package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +132 -0
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +454 -0
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +426 -0
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +372 -0
- package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +383 -0
- package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +245 -0
- package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +174 -0
- package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +432 -0
- package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +220 -0
- package/src/business/api-key.ts +65 -0
- package/src/business/artifact.ts +289 -0
- package/src/business/backend-unlock.ts +10 -0
- package/src/business/index.ts +10 -0
- package/src/business/instance-lock.ts +125 -0
- package/src/business/instance-state.ts +434 -0
- package/src/business/operation.ts +251 -0
- package/src/business/project-unlock.ts +260 -0
- package/src/business/project.ts +299 -0
- package/src/business/secret.test.ts +178 -0
- package/src/business/secret.ts +281 -0
- package/src/business/worker.test.ts +614 -0
- package/src/business/worker.ts +398 -0
- package/src/common/clock.ts +18 -0
- package/src/common/index.ts +5 -1
- package/src/common/performance.ts +44 -0
- package/src/common/random.ts +68 -0
- package/src/common/test/index.ts +2 -0
- package/src/common/test/render.ts +98 -0
- package/src/common/test/tracer.ts +359 -0
- package/src/common/tree.ts +33 -0
- package/src/common/utils.ts +40 -1
- package/src/config.ts +19 -11
- package/src/hotstate/abstractions.ts +48 -0
- package/src/hotstate/factory.ts +17 -0
- package/src/{secret → hotstate}/index.ts +1 -0
- package/src/hotstate/manager.ts +192 -0
- package/src/hotstate/memory.ts +100 -0
- package/src/hotstate/validation.ts +100 -0
- package/src/index.ts +2 -1
- package/src/library/abstractions.ts +24 -28
- package/src/library/factory.ts +2 -2
- package/src/library/local.ts +91 -111
- package/src/library/worker/evaluator.ts +36 -73
- package/src/library/worker/loader.lite.ts +54 -0
- package/src/library/worker/main.ts +15 -66
- package/src/library/worker/protocol.ts +6 -33
- package/src/lock/abstractions.ts +6 -0
- package/src/lock/factory.ts +15 -0
- package/src/lock/index.ts +4 -0
- package/src/lock/manager.ts +97 -0
- package/src/lock/memory.ts +19 -0
- package/src/lock/test.ts +108 -0
- package/src/orchestrator/manager.ts +118 -90
- package/src/orchestrator/operation-workset.ts +181 -93
- package/src/orchestrator/operation.ts +1021 -283
- package/src/project/abstractions.ts +27 -38
- package/src/project/evaluation.ts +248 -0
- package/src/project/factory.ts +1 -1
- package/src/project/index.ts +1 -2
- package/src/project/local.ts +107 -103
- package/src/pubsub/abstractions.ts +13 -0
- package/src/pubsub/factory.ts +19 -0
- package/src/{workspace → pubsub}/index.ts +1 -0
- package/src/pubsub/local.ts +36 -0
- package/src/pubsub/manager.ts +108 -0
- package/src/pubsub/validation.ts +33 -0
- package/src/runner/abstractions.ts +155 -68
- package/src/runner/artifact-env.ts +160 -0
- package/src/runner/factory.ts +20 -5
- package/src/runner/force-abort.ts +117 -0
- package/src/runner/local.ts +292 -372
- package/src/{common → runner}/pulumi.ts +89 -37
- package/src/services.ts +251 -40
- package/src/shared/index.ts +3 -11
- package/src/shared/models/backend/index.ts +3 -0
- package/src/shared/{library.ts → models/backend/library.ts} +4 -4
- package/src/shared/models/backend/project.ts +82 -0
- package/src/shared/models/backend/unlock-method.ts +20 -0
- package/src/shared/models/base.ts +68 -0
- package/src/shared/models/errors.ts +5 -0
- package/src/shared/models/index.ts +4 -0
- package/src/shared/models/project/api-key.ts +65 -0
- package/src/shared/models/project/artifact.ts +83 -0
- package/src/shared/models/project/index.ts +13 -0
- package/src/shared/models/project/lock.ts +91 -0
- package/src/shared/models/project/model.ts +14 -0
- package/src/shared/{operation.ts → models/project/operation.ts} +29 -8
- package/src/shared/models/project/page.ts +57 -0
- package/src/shared/models/project/secret.ts +98 -0
- package/src/shared/models/project/service-account.ts +22 -0
- package/src/shared/models/project/state.ts +449 -0
- package/src/shared/models/project/terminal.ts +98 -0
- package/src/shared/models/project/trigger.ts +56 -0
- package/src/shared/models/project/unlock-method.ts +38 -0
- package/src/shared/models/project/worker.ts +107 -0
- package/src/shared/resolvers/graph-resolver.ts +61 -18
- package/src/shared/resolvers/index.ts +5 -0
- package/src/shared/resolvers/input-hash.ts +53 -15
- package/src/shared/resolvers/input.ts +47 -13
- package/src/shared/resolvers/registry.ts +3 -2
- package/src/shared/resolvers/state.ts +2 -2
- package/src/shared/resolvers/validation.ts +82 -25
- package/src/shared/utils/args.ts +25 -0
- package/src/shared/{async-batcher.ts → utils/async-batcher.ts} +13 -1
- package/src/shared/utils/hash.ts +6 -0
- package/src/shared/utils/index.ts +4 -0
- package/src/shared/utils/promise-tracker.ts +23 -0
- package/src/state/abstractions.ts +199 -131
- package/src/state/encryption.ts +98 -0
- package/src/state/factory.ts +3 -5
- package/src/state/index.ts +4 -0
- package/src/state/keyring.ts +22 -0
- package/src/state/local/backend.ts +106 -0
- package/src/state/local/collection.ts +361 -0
- package/src/state/local/index.ts +2 -0
- package/src/state/manager.ts +875 -18
- package/src/state/memory/backend.ts +70 -0
- package/src/state/memory/collection.ts +270 -0
- package/src/state/memory/index.ts +2 -0
- package/src/state/repository/index.ts +2 -0
- package/src/state/repository/repository.index.ts +193 -0
- package/src/state/repository/repository.ts +507 -0
- package/src/state/test.ts +457 -0
- package/src/terminal/{shared.ts → abstractions.ts} +3 -3
- package/src/terminal/docker.ts +18 -14
- package/src/terminal/factory.ts +3 -3
- package/src/terminal/index.ts +1 -1
- package/src/terminal/manager.ts +131 -79
- package/src/terminal/run.sh.ts +21 -11
- package/src/unlock/abstractions.ts +49 -0
- package/src/unlock/index.ts +2 -0
- package/src/unlock/memory.ts +32 -0
- package/src/worker/abstractions.ts +42 -0
- package/src/worker/docker.ts +83 -0
- package/src/worker/factory.ts +20 -0
- package/src/worker/index.ts +3 -0
- package/src/worker/manager.ts +167 -0
- package/dist/chunk-KTGKNSKM.js +0 -979
- package/dist/chunk-KTGKNSKM.js.map +0 -1
- package/dist/chunk-WXDYCRTT.js +0 -234
- package/dist/chunk-WXDYCRTT.js.map +0 -1
- package/src/library/worker/loader.ts +0 -114
- package/src/preferences/shared.ts +0 -1
- package/src/project/lock.ts +0 -39
- package/src/project/manager.ts +0 -433
- package/src/secret/abstractions.ts +0 -59
- package/src/secret/factory.ts +0 -22
- package/src/secret/local.ts +0 -152
- package/src/shared/project.ts +0 -62
- package/src/shared/state.ts +0 -247
- package/src/shared/terminal.ts +0 -14
- package/src/state/local.ts +0 -612
- package/src/workspace/abstractions.ts +0 -41
- package/src/workspace/factory.ts +0 -14
- package/src/workspace/local.ts +0 -54
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import type { ConfigMap, OpMap, OpType, Stack, WhoAmIResult } from "@pulumi/pulumi/automation"
|
|
2
1
|
import type { Logger } from "pino"
|
|
2
|
+
import type { StateManager } from "../state"
|
|
3
|
+
import {
|
|
4
|
+
type ConfigMap,
|
|
5
|
+
type OpMap,
|
|
6
|
+
type OpType,
|
|
7
|
+
type Stack,
|
|
8
|
+
type WhoAmIResult,
|
|
9
|
+
} from "@pulumi/pulumi/automation/index.js"
|
|
3
10
|
import { BetterLock } from "better-lock"
|
|
4
|
-
import {
|
|
11
|
+
import { v4 as uuidv4, v7 as uuidv7 } from "uuid"
|
|
12
|
+
import { formatSecretDescriptor, WellKnownSecretDescriptors, type Secret } from "../shared"
|
|
13
|
+
import { AbortError, errorToString, runWithRetryOnError } from "../common/utils"
|
|
14
|
+
import { createForceAbortableCommand } from "./force-abort"
|
|
5
15
|
|
|
6
16
|
export type RunOptions = {
|
|
7
17
|
projectId: string
|
|
@@ -18,7 +28,10 @@ export type RunLocalOptions = RunOptions & {
|
|
|
18
28
|
export class LocalPulumiHost {
|
|
19
29
|
private lock = new BetterLock()
|
|
20
30
|
|
|
21
|
-
private constructor(
|
|
31
|
+
private constructor(
|
|
32
|
+
private readonly stateManager: StateManager,
|
|
33
|
+
private readonly logger: Logger,
|
|
34
|
+
) {}
|
|
22
35
|
|
|
23
36
|
async getCurrentUser(): Promise<WhoAmIResult | null> {
|
|
24
37
|
const { LocalWorkspace } = await import("@pulumi/pulumi/automation/index.js")
|
|
@@ -55,10 +68,11 @@ export class LocalPulumiHost {
|
|
|
55
68
|
runtime: "nodejs",
|
|
56
69
|
},
|
|
57
70
|
envVars: {
|
|
58
|
-
PULUMI_CONFIG_PASSPHRASE: this.getPassword(projectId),
|
|
71
|
+
PULUMI_CONFIG_PASSPHRASE: await this.getPassword(projectId),
|
|
59
72
|
PULUMI_K8S_AWAIT_ALL: "true",
|
|
60
73
|
...envVars,
|
|
61
74
|
},
|
|
75
|
+
pulumiCommand: await createForceAbortableCommand(),
|
|
62
76
|
},
|
|
63
77
|
)
|
|
64
78
|
|
|
@@ -90,6 +104,8 @@ export class LocalPulumiHost {
|
|
|
90
104
|
return await this.lock.acquire(`${pulumiProjectName}.${pulumiStackName}`, async () => {
|
|
91
105
|
const { LocalWorkspace } = await import("@pulumi/pulumi/automation/index.js")
|
|
92
106
|
|
|
107
|
+
console.log({ projectPath })
|
|
108
|
+
|
|
93
109
|
const stack = await LocalWorkspace.createOrSelectStack(
|
|
94
110
|
{
|
|
95
111
|
stackName: pulumiStackName,
|
|
@@ -99,6 +115,7 @@ export class LocalPulumiHost {
|
|
|
99
115
|
projectSettings: {
|
|
100
116
|
name: pulumiProjectName,
|
|
101
117
|
runtime: "nodejs",
|
|
118
|
+
main: "index.js",
|
|
102
119
|
},
|
|
103
120
|
stackSettings: stackConfig
|
|
104
121
|
? {
|
|
@@ -108,10 +125,11 @@ export class LocalPulumiHost {
|
|
|
108
125
|
}
|
|
109
126
|
: undefined,
|
|
110
127
|
envVars: {
|
|
111
|
-
PULUMI_CONFIG_PASSPHRASE: this.getPassword(projectId),
|
|
128
|
+
PULUMI_CONFIG_PASSPHRASE: await this.getPassword(projectId),
|
|
112
129
|
PULUMI_K8S_AWAIT_ALL: "true",
|
|
113
130
|
...envVars,
|
|
114
131
|
},
|
|
132
|
+
pulumiCommand: await createForceAbortableCommand(),
|
|
115
133
|
},
|
|
116
134
|
)
|
|
117
135
|
|
|
@@ -132,30 +150,50 @@ export class LocalPulumiHost {
|
|
|
132
150
|
})
|
|
133
151
|
}
|
|
134
152
|
|
|
135
|
-
private
|
|
136
|
-
|
|
153
|
+
private async getPassword(projectId: string): Promise<string> {
|
|
154
|
+
return await this.lock.acquire(`pulumi-password.${projectId}`, async () => {
|
|
155
|
+
const secretRepo = this.stateManager.getSecretRepository(projectId)
|
|
156
|
+
const secretContentRepo = this.stateManager.getSecretContentRepository(projectId)
|
|
157
|
+
const indexRepo = this.stateManager.getSecretIndexRepository(projectId)
|
|
137
158
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
159
|
+
const contentKey = formatSecretDescriptor(WellKnownSecretDescriptors.PulumiPassword)
|
|
160
|
+
const pulumiPasswordContent = await secretContentRepo.get(contentKey)
|
|
161
|
+
if (typeof pulumiPasswordContent === "string") {
|
|
162
|
+
return pulumiPasswordContent
|
|
163
|
+
}
|
|
141
164
|
|
|
142
|
-
|
|
143
|
-
this.passwords.set(projectId, password)
|
|
144
|
-
}
|
|
165
|
+
this.logger.info({ projectId }, "generating new Pulumi password")
|
|
145
166
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
const pulumiPassword = uuidv4()
|
|
168
|
+
const batch = this.stateManager.batch()
|
|
169
|
+
|
|
170
|
+
const pulumiPasswordSecret: Secret = {
|
|
171
|
+
id: uuidv7(),
|
|
172
|
+
descriptor: WellKnownSecretDescriptors.PulumiPassword,
|
|
173
|
+
meta: {
|
|
174
|
+
title: "Pulumi Password",
|
|
175
|
+
description: "The password used to encrypt the Pulumi state.",
|
|
176
|
+
icon: "devicon:pulumi",
|
|
177
|
+
},
|
|
178
|
+
}
|
|
149
179
|
|
|
150
|
-
|
|
151
|
-
|
|
180
|
+
await Promise.all([
|
|
181
|
+
secretRepo.putItem(pulumiPasswordSecret, batch),
|
|
182
|
+
secretContentRepo.put(contentKey, pulumiPassword, batch),
|
|
183
|
+
indexRepo.indexRepository.put(contentKey, pulumiPasswordSecret.id, batch),
|
|
184
|
+
])
|
|
185
|
+
|
|
186
|
+
await batch.write()
|
|
187
|
+
|
|
188
|
+
return pulumiPassword
|
|
189
|
+
})
|
|
152
190
|
}
|
|
153
191
|
|
|
154
192
|
async tryUnlockStack(stack: Stack, error: unknown) {
|
|
155
193
|
if (error instanceof Error && error.message.includes("the stack is currently locked")) {
|
|
156
194
|
// TODO: kill the process if the hostname matches the current hostname
|
|
157
195
|
|
|
158
|
-
this.logger.warn({ stackName: stack.name }, "
|
|
196
|
+
this.logger.warn({ stackName: stack.name }, "unlocking stack")
|
|
159
197
|
await stack.cancel()
|
|
160
198
|
return true
|
|
161
199
|
}
|
|
@@ -163,24 +201,8 @@ export class LocalPulumiHost {
|
|
|
163
201
|
return false
|
|
164
202
|
}
|
|
165
203
|
|
|
166
|
-
static create(logger: Logger) {
|
|
167
|
-
return new LocalPulumiHost(logger.child({ service: "LocalPulumiHost" }))
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function valueToString(value: unknown): string {
|
|
172
|
-
if (typeof value === "string") {
|
|
173
|
-
return value
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return JSON.stringify(value)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export function stringToValue(value: string): unknown {
|
|
180
|
-
try {
|
|
181
|
-
return JSON.parse(value)
|
|
182
|
-
} catch {
|
|
183
|
-
return value
|
|
204
|
+
static create(stateManager: StateManager, logger: Logger) {
|
|
205
|
+
return new LocalPulumiHost(stateManager, logger.child({ service: "LocalPulumiHost" }))
|
|
184
206
|
}
|
|
185
207
|
}
|
|
186
208
|
|
|
@@ -228,3 +250,33 @@ export function calculateTotalResources(opMap: OpMap | undefined): number {
|
|
|
228
250
|
|
|
229
251
|
return total
|
|
230
252
|
}
|
|
253
|
+
|
|
254
|
+
export async function pulumiErrorToString(error: unknown): Promise<string> {
|
|
255
|
+
const { CommandError } = await import("@pulumi/pulumi/automation/index.js")
|
|
256
|
+
|
|
257
|
+
if (error instanceof CommandError) {
|
|
258
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
259
|
+
const stderr = error["commandResult"].stderr as string
|
|
260
|
+
let diagnosticsStart = stderr.indexOf("\u001b[38;5;13m\u001b[1mDiagnostics:")
|
|
261
|
+
|
|
262
|
+
if (diagnosticsStart === -1) {
|
|
263
|
+
diagnosticsStart = stderr.indexOf("Diagnostics:")
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (diagnosticsStart !== -1) {
|
|
267
|
+
return stderr.slice(diagnosticsStart)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return errorToString(error)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function getOperationSummary(stdout: string): string | null {
|
|
275
|
+
const summaryStart = stdout.indexOf("\u001b[38;5;13m\u001b[1mOutputs:")
|
|
276
|
+
|
|
277
|
+
if (summaryStart !== -1) {
|
|
278
|
+
return stdout.slice(summaryStart)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return null
|
|
282
|
+
}
|
package/src/services.ts
CHANGED
|
@@ -1,34 +1,77 @@
|
|
|
1
1
|
import type { RunnerBackend } from "./runner"
|
|
2
2
|
import { pino, type Logger } from "pino"
|
|
3
|
-
import {
|
|
3
|
+
import { MemoryProjectUnlockBackend, type ProjectUnlockBackend } from "./unlock"
|
|
4
|
+
import { createWorkerBackend, WorkerManager, type WorkerBackend } from "./worker"
|
|
5
|
+
import { createHotStateBackend, HotStateManager, type HotStateBackend } from "./hotstate"
|
|
6
|
+
import { createPubSubBackend, PubSubManager, type PubSubBackend } from "./pubsub"
|
|
7
|
+
import { createLockBackend, type LockBackend, LockManager } from "./lock"
|
|
4
8
|
import { createStateBackend, StateManager, type StateBackend } from "./state"
|
|
5
9
|
import { type Config, loadConfig } from "./config"
|
|
6
10
|
import { type LibraryBackend, createLibraryBackend } from "./library"
|
|
7
11
|
import { OperationManager } from "./orchestrator"
|
|
8
|
-
import {
|
|
9
|
-
type ProjectBackend,
|
|
10
|
-
ProjectLockManager,
|
|
11
|
-
ProjectManager,
|
|
12
|
-
createProjectBackend,
|
|
13
|
-
} from "./project"
|
|
12
|
+
import { type ProjectBackend, ProjectEvaluationSubsystem, createProjectBackend } from "./project"
|
|
14
13
|
import { createRunnerBackend } from "./runner"
|
|
15
|
-
import { type SecretBackend, createSecretBackend } from "./secret"
|
|
16
14
|
import { type TerminalBackend, TerminalManager, createTerminalBackend } from "./terminal"
|
|
17
|
-
import {
|
|
15
|
+
import { type ArtifactBackend, createArtifactBackend, ArtifactService } from "./artifact"
|
|
16
|
+
import {
|
|
17
|
+
InstanceLockService,
|
|
18
|
+
OperationService,
|
|
19
|
+
SecretService,
|
|
20
|
+
ProjectUnlockService,
|
|
21
|
+
InstanceStateService,
|
|
22
|
+
ApiKeyService,
|
|
23
|
+
WorkerService,
|
|
24
|
+
ProjectService,
|
|
25
|
+
} from "./business"
|
|
26
|
+
import {
|
|
27
|
+
CryptoRandomProvider,
|
|
28
|
+
SystemClockProvider,
|
|
29
|
+
type ClockProvider,
|
|
30
|
+
type RandomProvider,
|
|
31
|
+
} from "./common"
|
|
18
32
|
|
|
19
33
|
export type Services = {
|
|
34
|
+
readonly clock: ClockProvider
|
|
35
|
+
readonly random: RandomProvider
|
|
20
36
|
readonly logger: Logger
|
|
37
|
+
|
|
38
|
+
readonly projectUnlockBackend: ProjectUnlockBackend
|
|
39
|
+
|
|
40
|
+
readonly hotStateBackend: HotStateBackend
|
|
41
|
+
readonly hotStateManager: HotStateManager
|
|
42
|
+
|
|
43
|
+
readonly pubsubBackend: PubSubBackend
|
|
44
|
+
readonly pubsubManager: PubSubManager
|
|
45
|
+
|
|
46
|
+
readonly lockBackend: LockBackend
|
|
47
|
+
readonly lockManager: LockManager
|
|
48
|
+
|
|
21
49
|
readonly libraryBackend: LibraryBackend
|
|
22
|
-
readonly secretBackend: SecretBackend
|
|
23
50
|
readonly runnerBackend: RunnerBackend
|
|
24
51
|
readonly projectBackend: ProjectBackend
|
|
25
|
-
readonly
|
|
52
|
+
readonly projectEvaluationSubsystem: ProjectEvaluationSubsystem
|
|
26
53
|
readonly stateBackend: StateBackend
|
|
27
54
|
readonly stateManager: StateManager
|
|
28
55
|
readonly operationManager: OperationManager
|
|
56
|
+
|
|
29
57
|
readonly terminalBackend: TerminalBackend
|
|
30
58
|
readonly terminalManager: TerminalManager
|
|
31
|
-
|
|
59
|
+
|
|
60
|
+
readonly workerBackend: WorkerBackend
|
|
61
|
+
readonly workerManager: WorkerManager
|
|
62
|
+
|
|
63
|
+
readonly artifactBackend: ArtifactBackend
|
|
64
|
+
readonly artifactManager: ArtifactService
|
|
65
|
+
|
|
66
|
+
// business services
|
|
67
|
+
readonly instanceLockService: InstanceLockService
|
|
68
|
+
readonly projectUnlockService: ProjectUnlockService
|
|
69
|
+
readonly operationService: OperationService
|
|
70
|
+
readonly instanceStateService: InstanceStateService
|
|
71
|
+
readonly secretService: SecretService
|
|
72
|
+
readonly apiKeyService: ApiKeyService
|
|
73
|
+
readonly workerService: WorkerService
|
|
74
|
+
readonly projectService: ProjectService
|
|
32
75
|
}
|
|
33
76
|
|
|
34
77
|
export interface CreateServicesOptions {
|
|
@@ -46,79 +89,247 @@ export interface CreateServicesOptions {
|
|
|
46
89
|
export async function createServices({
|
|
47
90
|
config,
|
|
48
91
|
services: {
|
|
92
|
+
clock,
|
|
93
|
+
random,
|
|
49
94
|
logger,
|
|
95
|
+
|
|
96
|
+
projectUnlockBackend,
|
|
97
|
+
|
|
98
|
+
hotStateBackend,
|
|
99
|
+
hotStateManager,
|
|
100
|
+
|
|
101
|
+
pubsubBackend,
|
|
102
|
+
pubsubManager,
|
|
103
|
+
|
|
104
|
+
lockBackend,
|
|
105
|
+
lockManager,
|
|
106
|
+
|
|
50
107
|
libraryBackend,
|
|
51
|
-
secretBackend,
|
|
52
108
|
runnerBackend,
|
|
53
109
|
projectBackend,
|
|
54
|
-
|
|
110
|
+
projectEvaluationSubsystem,
|
|
55
111
|
stateBackend,
|
|
56
112
|
stateManager,
|
|
57
113
|
operationManager,
|
|
114
|
+
|
|
58
115
|
terminalBackend,
|
|
59
116
|
terminalManager,
|
|
60
|
-
|
|
117
|
+
|
|
118
|
+
workerBackend,
|
|
119
|
+
workerManager,
|
|
120
|
+
|
|
121
|
+
artifactBackend,
|
|
122
|
+
artifactManager,
|
|
123
|
+
|
|
124
|
+
// business services
|
|
125
|
+
instanceLockService,
|
|
126
|
+
projectUnlockService,
|
|
127
|
+
operationService,
|
|
128
|
+
secretService,
|
|
129
|
+
instanceStateService,
|
|
130
|
+
apiKeyService,
|
|
131
|
+
workerService,
|
|
132
|
+
projectService,
|
|
61
133
|
} = {},
|
|
62
134
|
}: CreateServicesOptions = {}): Promise<Services> {
|
|
63
135
|
config ??= await loadConfig()
|
|
64
136
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
errorKey: "error",
|
|
69
|
-
})
|
|
137
|
+
clock ??= new SystemClockProvider()
|
|
138
|
+
random ??= new CryptoRandomProvider()
|
|
139
|
+
logger ??= pino({ level: config.HIGHSTATE_LOG_LEVEL, errorKey: "error" })
|
|
70
140
|
|
|
71
|
-
|
|
72
|
-
const projectLockManager = new ProjectLockManager()
|
|
141
|
+
projectUnlockBackend ??= new MemoryProjectUnlockBackend()
|
|
73
142
|
|
|
74
|
-
|
|
143
|
+
pubsubBackend ??= createPubSubBackend(config, logger)
|
|
144
|
+
pubsubManager ??= new PubSubManager(pubsubBackend, logger)
|
|
145
|
+
|
|
146
|
+
lockBackend ??= createLockBackend(config)
|
|
147
|
+
lockManager ??= new LockManager(lockBackend)
|
|
148
|
+
|
|
149
|
+
hotStateBackend ??= createHotStateBackend(config)
|
|
150
|
+
hotStateManager ??= new HotStateManager(hotStateBackend)
|
|
151
|
+
|
|
152
|
+
stateBackend ??= await createStateBackend(config, logger)
|
|
153
|
+
stateManager ??= await StateManager.create(
|
|
154
|
+
config,
|
|
155
|
+
stateBackend,
|
|
156
|
+
projectUnlockBackend,
|
|
157
|
+
clock,
|
|
158
|
+
random,
|
|
159
|
+
logger,
|
|
160
|
+
)
|
|
75
161
|
|
|
76
162
|
libraryBackend ??= await createLibraryBackend(config, logger)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
163
|
+
|
|
164
|
+
artifactBackend ??= await createArtifactBackend(config, stateManager, logger)
|
|
165
|
+
artifactManager ??= new ArtifactService(stateManager, artifactBackend, lockManager, logger)
|
|
166
|
+
|
|
167
|
+
runnerBackend ??= createRunnerBackend(
|
|
168
|
+
config,
|
|
169
|
+
libraryBackend,
|
|
170
|
+
artifactManager,
|
|
171
|
+
artifactBackend,
|
|
172
|
+
stateManager,
|
|
173
|
+
logger,
|
|
174
|
+
)
|
|
175
|
+
|
|
80
176
|
projectBackend ??= await createProjectBackend(config)
|
|
81
177
|
|
|
82
|
-
|
|
83
|
-
|
|
178
|
+
instanceLockService ??= new InstanceLockService(
|
|
179
|
+
stateManager,
|
|
180
|
+
lockManager,
|
|
181
|
+
pubsubManager,
|
|
182
|
+
logger.child({ service: "InstanceLockService" }),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
projectUnlockService ??= new ProjectUnlockService(
|
|
186
|
+
stateManager,
|
|
187
|
+
hotStateManager,
|
|
188
|
+
pubsubManager,
|
|
189
|
+
projectUnlockBackend,
|
|
190
|
+
random,
|
|
191
|
+
logger.child({ service: "StateUnlockService" }),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
operationService ??= new OperationService(
|
|
195
|
+
stateManager,
|
|
196
|
+
hotStateManager,
|
|
197
|
+
pubsubManager,
|
|
198
|
+
logger.child({ service: "OperationService" }),
|
|
199
|
+
)
|
|
84
200
|
|
|
85
|
-
|
|
201
|
+
instanceStateService ??= new InstanceStateService(
|
|
202
|
+
stateManager,
|
|
203
|
+
hotStateManager,
|
|
204
|
+
pubsubManager,
|
|
205
|
+
lockManager,
|
|
86
206
|
runnerBackend,
|
|
87
|
-
|
|
207
|
+
artifactManager,
|
|
208
|
+
logger.child({ service: "InstanceService" }),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
secretService ??= new SecretService(
|
|
212
|
+
stateManager,
|
|
88
213
|
libraryBackend,
|
|
214
|
+
instanceStateService,
|
|
215
|
+
random,
|
|
216
|
+
logger.child({ service: "SecretService" }),
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
apiKeyService ??= new ApiKeyService(stateManager, lockManager)
|
|
220
|
+
|
|
221
|
+
projectEvaluationSubsystem ??= new ProjectEvaluationSubsystem(
|
|
89
222
|
projectBackend,
|
|
90
|
-
|
|
91
|
-
|
|
223
|
+
libraryBackend,
|
|
224
|
+
stateManager,
|
|
225
|
+
instanceLockService,
|
|
226
|
+
instanceStateService,
|
|
227
|
+
pubsubManager,
|
|
228
|
+
lockManager,
|
|
229
|
+
random,
|
|
230
|
+
logger,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
terminalBackend ??= createTerminalBackend(config, logger)
|
|
234
|
+
terminalManager ??= TerminalManager.create(
|
|
235
|
+
terminalBackend,
|
|
236
|
+
stateManager,
|
|
237
|
+
pubsubManager,
|
|
238
|
+
projectUnlockService,
|
|
239
|
+
logger,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
workerBackend ??= createWorkerBackend(config, logger)
|
|
243
|
+
workerManager ??= new WorkerManager(
|
|
244
|
+
config,
|
|
245
|
+
workerBackend,
|
|
92
246
|
stateManager,
|
|
247
|
+
projectUnlockService,
|
|
248
|
+
lockManager,
|
|
249
|
+
apiKeyService,
|
|
93
250
|
logger,
|
|
94
251
|
)
|
|
95
252
|
|
|
96
|
-
|
|
253
|
+
workerService ??= new WorkerService(
|
|
254
|
+
stateManager,
|
|
255
|
+
workerManager,
|
|
256
|
+
lockManager,
|
|
257
|
+
random,
|
|
258
|
+
logger.child({ service: "WorkerService" }),
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
projectService ??= new ProjectService(
|
|
262
|
+
stateManager,
|
|
263
|
+
projectUnlockService,
|
|
264
|
+
projectEvaluationSubsystem,
|
|
97
265
|
projectBackend,
|
|
98
|
-
stateBackend,
|
|
99
266
|
libraryBackend,
|
|
100
|
-
|
|
267
|
+
lockManager,
|
|
268
|
+
pubsubManager,
|
|
269
|
+
random,
|
|
270
|
+
logger.child({ service: "ProjectService" }),
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
operationManager ??= new OperationManager(
|
|
274
|
+
runnerBackend,
|
|
275
|
+
libraryBackend,
|
|
276
|
+
projectBackend,
|
|
277
|
+
artifactManager,
|
|
101
278
|
stateManager,
|
|
279
|
+
instanceLockService,
|
|
280
|
+
projectUnlockService,
|
|
281
|
+
operationService,
|
|
282
|
+
secretService,
|
|
283
|
+
instanceStateService,
|
|
284
|
+
pubsubManager,
|
|
285
|
+
workerService,
|
|
102
286
|
logger,
|
|
103
287
|
)
|
|
104
288
|
|
|
105
|
-
workspaceBackend ??= await createWorkspaceBackend(config)
|
|
106
|
-
|
|
107
289
|
logger.info("services created")
|
|
108
290
|
|
|
109
291
|
return {
|
|
292
|
+
clock,
|
|
293
|
+
random,
|
|
110
294
|
logger,
|
|
295
|
+
|
|
296
|
+
projectUnlockBackend,
|
|
297
|
+
|
|
298
|
+
hotStateBackend,
|
|
299
|
+
hotStateManager,
|
|
300
|
+
|
|
301
|
+
pubsubBackend,
|
|
302
|
+
pubsubManager,
|
|
303
|
+
|
|
304
|
+
lockBackend,
|
|
305
|
+
lockManager,
|
|
306
|
+
|
|
111
307
|
libraryBackend,
|
|
112
|
-
secretBackend,
|
|
113
308
|
runnerBackend,
|
|
114
309
|
projectBackend,
|
|
115
|
-
|
|
310
|
+
projectEvaluationSubsystem,
|
|
116
311
|
stateBackend,
|
|
117
312
|
stateManager,
|
|
118
313
|
operationManager,
|
|
314
|
+
|
|
119
315
|
terminalBackend,
|
|
120
316
|
terminalManager,
|
|
121
|
-
|
|
317
|
+
|
|
318
|
+
workerBackend,
|
|
319
|
+
workerManager,
|
|
320
|
+
|
|
321
|
+
artifactBackend,
|
|
322
|
+
artifactManager,
|
|
323
|
+
|
|
324
|
+
// business services
|
|
325
|
+
instanceLockService,
|
|
326
|
+
projectUnlockService,
|
|
327
|
+
operationService,
|
|
328
|
+
instanceStateService,
|
|
329
|
+
secretService,
|
|
330
|
+
apiKeyService,
|
|
331
|
+
workerService,
|
|
332
|
+
projectService,
|
|
122
333
|
}
|
|
123
334
|
}
|
|
124
335
|
|
package/src/shared/index.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./resolvers/graph-resolver"
|
|
5
|
-
export * from "./resolvers/registry"
|
|
6
|
-
export * from "./resolvers/input"
|
|
7
|
-
export * from "./resolvers/input-hash"
|
|
8
|
-
export * from "./resolvers/validation"
|
|
9
|
-
export * from "./terminal"
|
|
10
|
-
export * from "./library"
|
|
11
|
-
export * from "./async-batcher"
|
|
1
|
+
export * from "./models"
|
|
2
|
+
export * from "./resolvers"
|
|
3
|
+
export * from "./utils"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ComponentModel,
|
|
1
|
+
import type { ComponentModel, EntityModel } from "@highstate/contract"
|
|
2
2
|
|
|
3
3
|
export type LibraryModel = {
|
|
4
4
|
components: Record<string, ComponentModel>
|
|
5
|
-
entities: Record<string,
|
|
5
|
+
entities: Record<string, EntityModel>
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export type LibraryUpdate =
|
|
@@ -15,7 +15,7 @@ export type LibraryUpdate =
|
|
|
15
15
|
}
|
|
16
16
|
| {
|
|
17
17
|
type: "entity-updated"
|
|
18
|
-
entity:
|
|
18
|
+
entity: EntityModel
|
|
19
19
|
}
|
|
20
20
|
| {
|
|
21
21
|
type: "component-removed"
|
|
@@ -60,7 +60,7 @@ export function diffLibraries(oldLibrary: LibraryModel, newLibrary: LibraryModel
|
|
|
60
60
|
|
|
61
61
|
export function applyLibraryUpdate(
|
|
62
62
|
components: Record<string, ComponentModel>,
|
|
63
|
-
entities: Record<string,
|
|
63
|
+
entities: Record<string, EntityModel>,
|
|
64
64
|
update: LibraryUpdate,
|
|
65
65
|
): void {
|
|
66
66
|
switch (update.type) {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
import { hubModelSchema, instanceModelSchema, objectMetaSchema } from "@highstate/contract"
|
|
3
|
+
|
|
4
|
+
export const projectSchema = z.object({
|
|
5
|
+
/**
|
|
6
|
+
* The identifier of the project unique across the world.
|
|
7
|
+
*/
|
|
8
|
+
id: z.uuidv7(),
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The metadata of the project.
|
|
12
|
+
*/
|
|
13
|
+
meta: objectMetaSchema
|
|
14
|
+
.required({ title: true })
|
|
15
|
+
.pick({ title: true, description: true, icon: true, iconColor: true }),
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The user-provided name of the project unique across its scope.
|
|
19
|
+
*/
|
|
20
|
+
name: z
|
|
21
|
+
.string()
|
|
22
|
+
.min(1)
|
|
23
|
+
.max(64)
|
|
24
|
+
.regex(/^[a-z][a-z0-9-.]*$/),
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The ID of the project scope (e.g., organization or user or something else not decided yet).
|
|
28
|
+
*
|
|
29
|
+
* For local deployments, this is `undefined`.
|
|
30
|
+
*/
|
|
31
|
+
scopeId: z.uuidv7().optional(),
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The identifier of the library used by the project.
|
|
35
|
+
*
|
|
36
|
+
* For local deployment is `undefined`, for cloud deployment will be the library ID.
|
|
37
|
+
*/
|
|
38
|
+
libraryId: z.uuidv7().optional(),
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
export type Project = z.infer<typeof projectSchema>
|
|
42
|
+
|
|
43
|
+
export const projectModelSchema = z.object({
|
|
44
|
+
instances: z.array(instanceModelSchema),
|
|
45
|
+
hubs: z.array(hubModelSchema),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export type ProjectModel = z.infer<typeof projectModelSchema>
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The project unlock suite is something that the frontend
|
|
52
|
+
* needs to unlock the project and provide the backend
|
|
53
|
+
* with the necessary information to decrypt the master key.
|
|
54
|
+
*/
|
|
55
|
+
export const projectUnlockSuiteSchema = z.object({
|
|
56
|
+
/**
|
|
57
|
+
* The list of encrypted AGE identities that can be used to decrypt the master key of the project.
|
|
58
|
+
*
|
|
59
|
+
* The frontend should try to decrypt at least one of these identities
|
|
60
|
+
* using the password or passkey.
|
|
61
|
+
*/
|
|
62
|
+
encryptedIdentities: z.array(z.string()),
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether one of the identities is a passkey and user should be asked to use it.
|
|
66
|
+
*/
|
|
67
|
+
hasPasskey: z.boolean(),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
export type ProjectUnlockSuite = z.infer<typeof projectUnlockSuiteSchema>
|
|
71
|
+
|
|
72
|
+
export const projectUnlockStateSchema = z.discriminatedUnion("type", [
|
|
73
|
+
z.object({
|
|
74
|
+
type: z.literal("locked"),
|
|
75
|
+
unlockSuite: projectUnlockSuiteSchema.optional(),
|
|
76
|
+
}),
|
|
77
|
+
z.object({
|
|
78
|
+
type: z.literal("unlocked"),
|
|
79
|
+
}),
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
export type ProjectUnlockState = z.infer<typeof projectUnlockStateSchema>
|