@highstate/backend 0.7.6 → 0.7.9
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/highstate.manifest.json +4 -4
- package/dist/index.js +260 -149
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +41 -0
- package/dist/library/package-resolution-worker.js.map +1 -0
- package/dist/library/worker/main.js +1 -4
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +0 -1
- package/package.json +6 -6
- package/src/library/abstractions.ts +7 -7
- package/src/library/local.ts +294 -166
- package/src/library/package-resolution-worker.ts +70 -0
- package/src/library/worker/loader.ts +8 -7
- package/src/orchestrator/operation-workset.ts +6 -2
- package/src/project/manager.ts +40 -2
- package/src/runner/local.ts +14 -6
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/library/source-resolution-worker.js +0 -56
- package/dist/library/source-resolution-worker.js.map +0 -1
- package/src/library/source-resolution-worker.ts +0 -96
@@ -3,6 +3,7 @@ import type { ProjectBackend } from "../project"
|
|
3
3
|
import type { StateBackend, StateManager } from "../state"
|
4
4
|
import type { Logger } from "pino"
|
5
5
|
import { isUnitModel, type ComponentModel, type InstanceModel } from "@highstate/contract"
|
6
|
+
import { unique } from "remeda"
|
6
7
|
import {
|
7
8
|
applyPartialInstanceState,
|
8
9
|
createInputHashResolver,
|
@@ -366,14 +367,17 @@ export class OperationWorkset {
|
|
366
367
|
logger: Logger,
|
367
368
|
signal: AbortSignal,
|
368
369
|
): Promise<OperationWorkset> {
|
369
|
-
const [library,
|
370
|
+
const [library, project, compositeInstances, states] = await Promise.all([
|
370
371
|
libraryBackend.loadLibrary(signal),
|
371
|
-
libraryBackend.getResolvedUnitSources(),
|
372
372
|
projectBackend.getProject(operation.projectId, signal),
|
373
373
|
stateBackend.getCompositeInstances(operation.projectId, signal),
|
374
374
|
stateBackend.getAllInstanceStates(operation.projectId, signal),
|
375
375
|
])
|
376
376
|
|
377
|
+
const unitSources = await libraryBackend.getResolvedUnitSources(
|
378
|
+
unique(project.instances.map(i => i.type)),
|
379
|
+
)
|
380
|
+
|
377
381
|
const workset = new OperationWorkset(
|
378
382
|
operation,
|
379
383
|
library,
|
package/src/project/manager.ts
CHANGED
@@ -15,6 +15,7 @@ import {
|
|
15
15
|
createInstanceState,
|
16
16
|
type CompositeInstance,
|
17
17
|
type ResolvedInstanceInput,
|
18
|
+
type HubModel,
|
18
19
|
} from "../shared"
|
19
20
|
|
20
21
|
type CompositeInstanceEvent =
|
@@ -31,6 +32,12 @@ type CompositeInstanceEvents = {
|
|
31
32
|
[K in string]: [CompositeInstanceEvent]
|
32
33
|
}
|
33
34
|
|
35
|
+
export type FullProjectModel = {
|
36
|
+
instances: InstanceModel[]
|
37
|
+
hubs: HubModel[]
|
38
|
+
compositeInstances: CompositeInstance[]
|
39
|
+
}
|
40
|
+
|
34
41
|
export class ProjectManager {
|
35
42
|
private constructor(
|
36
43
|
private readonly projectBackend: ProjectBackend,
|
@@ -56,6 +63,35 @@ export class ProjectManager {
|
|
56
63
|
}
|
57
64
|
}
|
58
65
|
|
66
|
+
/**
|
67
|
+
* Loads the full info of a project, including instances, hubs, and composite instances.
|
68
|
+
*
|
69
|
+
* Also filters out instances that are not in the library.
|
70
|
+
*
|
71
|
+
* @param projectId The ID of the project to load.
|
72
|
+
*/
|
73
|
+
async getProject(projectId: string): Promise<FullProjectModel> {
|
74
|
+
const [{ instances, hubs }, compositeInstances, library] = await Promise.all([
|
75
|
+
this.projectBackend.getProject(projectId),
|
76
|
+
this.stateBackend.getCompositeInstances(projectId),
|
77
|
+
this.libraryBackend.loadLibrary(),
|
78
|
+
])
|
79
|
+
|
80
|
+
const filteredInstances = instances.filter(instance => instance.type in library.components)
|
81
|
+
const filteredCompositeInstances = compositeInstances
|
82
|
+
.filter(instance => instance.instance.type in library.components)
|
83
|
+
.map(instance => ({
|
84
|
+
...instance,
|
85
|
+
children: instance.children.filter(child => child.type in library.components),
|
86
|
+
}))
|
87
|
+
|
88
|
+
return {
|
89
|
+
instances: filteredInstances,
|
90
|
+
hubs,
|
91
|
+
compositeInstances: filteredCompositeInstances,
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
59
95
|
async createInstance(projectId: string, instance: InstanceModel): Promise<InstanceModel> {
|
60
96
|
const createdInstance = await this.projectBackend.createInstance(projectId, instance)
|
61
97
|
await this.updateCompositeInstance(projectId, createdInstance)
|
@@ -255,9 +291,11 @@ export class ProjectManager {
|
|
255
291
|
|
256
292
|
let sourceHash: string | undefined
|
257
293
|
if (isUnitModel(library.components[instance.type])) {
|
258
|
-
const
|
294
|
+
const resolvedUnits = await this.libraryBackend.getResolvedUnitSources([instance.type])
|
295
|
+
const resolvedUnit = resolvedUnits.find(unit => unit.unitType === instance.type)
|
296
|
+
|
259
297
|
if (!resolvedUnit) {
|
260
|
-
throw new Error(`Resolved unit not found
|
298
|
+
throw new Error(`Resolved unit not found for type "${instance.type}"`)
|
261
299
|
}
|
262
300
|
|
263
301
|
sourceHash = resolvedUnit.sourceHash
|
package/src/runner/local.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import type { ConfigMap, Stack } from "@pulumi/pulumi/automation"
|
2
|
-
import type { LibraryBackend } from "../library"
|
2
|
+
import type { LibraryBackend, ResolvedUnitSource } from "../library"
|
3
3
|
import { EventEmitter, on } from "node:events"
|
4
4
|
import { resolve } from "node:path"
|
5
5
|
import { getInstanceId } from "@highstate/contract"
|
@@ -238,10 +238,7 @@ export class LocalRunnerBackend implements RunnerBackend {
|
|
238
238
|
const instanceId = LocalRunnerBackend.getInstanceId(options)
|
239
239
|
|
240
240
|
try {
|
241
|
-
const resolvedSource = await this.
|
242
|
-
if (!resolvedSource) {
|
243
|
-
throw new Error(`Resolved unit source not found for ${options.instanceType}`)
|
244
|
-
}
|
241
|
+
const resolvedSource = await this.getResolvedUnitSource(options.instanceType)
|
245
242
|
|
246
243
|
await this.pulumiProjectHost.runLocal(
|
247
244
|
{
|
@@ -366,7 +363,7 @@ export class LocalRunnerBackend implements RunnerBackend {
|
|
366
363
|
const instanceId = LocalRunnerBackend.getInstanceId(options)
|
367
364
|
|
368
365
|
try {
|
369
|
-
const resolvedSource = await this.
|
366
|
+
const resolvedSource = await this.getResolvedUnitSource(options.instanceType)
|
370
367
|
if (!resolvedSource) {
|
371
368
|
throw new Error(`Resolved unit source not found for ${options.instanceType}`)
|
372
369
|
}
|
@@ -666,6 +663,17 @@ export class LocalRunnerBackend implements RunnerBackend {
|
|
666
663
|
return true
|
667
664
|
}
|
668
665
|
|
666
|
+
private async getResolvedUnitSource(instanceType: string): Promise<ResolvedUnitSource> {
|
667
|
+
const sources = await this.libraryBackend.getResolvedUnitSources([instanceType])
|
668
|
+
const source = sources.find(source => source.unitType === instanceType)
|
669
|
+
|
670
|
+
if (!source) {
|
671
|
+
throw new Error(`Resolved unit source not found for ${instanceType}`)
|
672
|
+
}
|
673
|
+
|
674
|
+
return source
|
675
|
+
}
|
676
|
+
|
669
677
|
private static getStackName(options: RunnerBaseOptions) {
|
670
678
|
return `${options.projectId}_${options.instanceName}`
|
671
679
|
}
|
package/dist/chunk-DGUM43GV.js
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
3
|
-
}) : x)(function(x) {
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
6
|
-
});
|
7
|
-
|
8
|
-
export {
|
9
|
-
__require
|
10
|
-
};
|
11
|
-
//# sourceMappingURL=chunk-DGUM43GV.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
@@ -1,56 +0,0 @@
|
|
1
|
-
// src/library/source-resolution-worker.ts
|
2
|
-
import { parentPort, workerData } from "node:worker_threads";
|
3
|
-
import { fileURLToPath } from "node:url";
|
4
|
-
import { dirname, relative, resolve } from "node:path";
|
5
|
-
import { readFile } from "node:fs/promises";
|
6
|
-
import pino from "pino";
|
7
|
-
import { resolve as importMetaResolve } from "import-meta-resolve";
|
8
|
-
import { readPackageJSON, resolvePackageJSON } from "pkg-types";
|
9
|
-
var { requests, logLevel } = workerData;
|
10
|
-
var logger = pino({ name: "source-resolution-worker", level: logLevel ?? "silent" });
|
11
|
-
var results = await Promise.all(
|
12
|
-
requests.map((request) => resolveUnitSourceSafe(request.source, request.unitType))
|
13
|
-
);
|
14
|
-
parentPort.postMessage({
|
15
|
-
type: "result",
|
16
|
-
results: results.filter((result) => result !== null)
|
17
|
-
});
|
18
|
-
async function resolveUnitSourceSafe(source, unitType) {
|
19
|
-
try {
|
20
|
-
return await resolveUnitSource(source, unitType);
|
21
|
-
} catch (error) {
|
22
|
-
logger.error({ source, unitType, err: error }, "failed to resolve unit source");
|
23
|
-
return null;
|
24
|
-
}
|
25
|
-
}
|
26
|
-
async function resolveUnitSource(source, unitType) {
|
27
|
-
const fullPath = source.path ? `${source.package}/${source.path}` : source.package;
|
28
|
-
const url = importMetaResolve(fullPath, import.meta.url);
|
29
|
-
const path = fileURLToPath(url);
|
30
|
-
const projectPath = dirname(path);
|
31
|
-
const packageJsonPath = await resolvePackageJSON(projectPath);
|
32
|
-
const packageJson = await readPackageJSON(projectPath);
|
33
|
-
const manifestPath = resolve(dirname(packageJsonPath), "dist", "highstate.manifest.json");
|
34
|
-
let manifest;
|
35
|
-
try {
|
36
|
-
manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
37
|
-
} catch (error) {
|
38
|
-
logger.debug({ error }, "failed to read highstate manifest");
|
39
|
-
}
|
40
|
-
let relativePath = relative(dirname(packageJsonPath), path);
|
41
|
-
relativePath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
42
|
-
const sourceHash = manifest?.sourceHashes?.[relativePath];
|
43
|
-
if (!sourceHash) {
|
44
|
-
logger.warn({ unitType, relativePath, packageName: packageJson.name }, "source hash not found");
|
45
|
-
}
|
46
|
-
const allowedDependencies = Object.keys(packageJson.peerDependencies ?? {});
|
47
|
-
logger.debug({ packageJson }, "package.json read");
|
48
|
-
return {
|
49
|
-
unitType,
|
50
|
-
projectPath,
|
51
|
-
packageJsonPath,
|
52
|
-
sourceHash: sourceHash ?? "",
|
53
|
-
allowedDependencies
|
54
|
-
};
|
55
|
-
}
|
56
|
-
//# sourceMappingURL=source-resolution-worker.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"sources":["../../src/library/source-resolution-worker.ts"],"sourcesContent":["import type { UnitSource } from \"@highstate/contract\"\nimport { parentPort, workerData } from \"node:worker_threads\"\nimport { fileURLToPath } from \"node:url\"\nimport { dirname, relative, resolve } from \"node:path\"\nimport { readFile } from \"node:fs/promises\"\nimport pino, { type Level } from \"pino\"\nimport { resolve as importMetaResolve } from \"import-meta-resolve\"\nimport { readPackageJSON, resolvePackageJSON } from \"pkg-types\"\n\nexport type SourceResolutionRequest = {\n unitType: string\n source: UnitSource\n}\n\nexport type SourceResolutionResult = {\n unitType: string\n projectPath: string\n packageJsonPath: string\n sourceHash: string\n allowedDependencies: string[]\n}\n\nexport type HighstateManifestJson = {\n sourceHashes?: Record<string, string>\n}\n\nconst { requests, logLevel } = workerData as {\n requests: SourceResolutionRequest[]\n logLevel?: Level\n}\n\nconst logger = pino({ name: \"source-resolution-worker\", level: logLevel ?? \"silent\" })\n\nconst results = await Promise.all(\n requests.map(request => resolveUnitSourceSafe(request.source, request.unitType)),\n)\n\nparentPort!.postMessage({\n type: \"result\",\n results: results.filter((result): result is SourceResolutionResult => result !== null),\n})\n\nasync function resolveUnitSourceSafe(\n source: UnitSource,\n unitType: string,\n): Promise<SourceResolutionResult | null> {\n try {\n return await resolveUnitSource(source, unitType)\n } catch (error) {\n logger.error({ source, unitType, err: error }, \"failed to resolve unit source\")\n return null\n }\n}\n\nasync function resolveUnitSource(\n source: UnitSource,\n unitType: string,\n): Promise<SourceResolutionResult> {\n const fullPath = source.path ? `${source.package}/${source.path}` : source.package\n\n const url = importMetaResolve(fullPath, import.meta.url)\n const path = fileURLToPath(url)\n const projectPath = dirname(path)\n\n const packageJsonPath = await resolvePackageJSON(projectPath)\n const packageJson = await readPackageJSON(projectPath)\n\n const manifestPath = resolve(dirname(packageJsonPath), \"dist\", \"highstate.manifest.json\")\n let manifest: HighstateManifestJson | undefined\n try {\n manifest = JSON.parse(await readFile(manifestPath, \"utf8\")) as HighstateManifestJson\n } catch (error) {\n logger.debug({ error }, \"failed to read highstate manifest\")\n }\n\n let relativePath = relative(dirname(packageJsonPath), path)\n relativePath = relativePath.startsWith(\".\") ? relativePath : `./${relativePath}`\n\n const sourceHash = manifest?.sourceHashes?.[relativePath]\n if (!sourceHash) {\n logger.warn({ unitType, relativePath, packageName: packageJson.name }, \"source hash not found\")\n }\n\n // only the peer dependencies of the package are allowed to auto-install when they are missing\n const allowedDependencies = Object.keys(packageJson.peerDependencies ?? {})\n\n logger.debug({ packageJson }, \"package.json read\")\n\n return {\n unitType,\n projectPath,\n packageJsonPath,\n sourceHash: sourceHash ?? \"\",\n allowedDependencies,\n }\n}\n"],"mappings":";AACA,SAAS,YAAY,kBAAkB;AACvC,SAAS,qBAAqB;AAC9B,SAAS,SAAS,UAAU,eAAe;AAC3C,SAAS,gBAAgB;AACzB,OAAO,UAA0B;AACjC,SAAS,WAAW,yBAAyB;AAC7C,SAAS,iBAAiB,0BAA0B;AAmBpD,IAAM,EAAE,UAAU,SAAS,IAAI;AAK/B,IAAM,SAAS,KAAK,EAAE,MAAM,4BAA4B,OAAO,YAAY,SAAS,CAAC;AAErF,IAAM,UAAU,MAAM,QAAQ;AAAA,EAC5B,SAAS,IAAI,aAAW,sBAAsB,QAAQ,QAAQ,QAAQ,QAAQ,CAAC;AACjF;AAEA,WAAY,YAAY;AAAA,EACtB,MAAM;AAAA,EACN,SAAS,QAAQ,OAAO,CAAC,WAA6C,WAAW,IAAI;AACvF,CAAC;AAED,eAAe,sBACb,QACA,UACwC;AACxC,MAAI;AACF,WAAO,MAAM,kBAAkB,QAAQ,QAAQ;AAAA,EACjD,SAAS,OAAO;AACd,WAAO,MAAM,EAAE,QAAQ,UAAU,KAAK,MAAM,GAAG,+BAA+B;AAC9E,WAAO;AAAA,EACT;AACF;AAEA,eAAe,kBACb,QACA,UACiC;AACjC,QAAM,WAAW,OAAO,OAAO,GAAG,OAAO,OAAO,IAAI,OAAO,IAAI,KAAK,OAAO;AAE3E,QAAM,MAAM,kBAAkB,UAAU,YAAY,GAAG;AACvD,QAAM,OAAO,cAAc,GAAG;AAC9B,QAAM,cAAc,QAAQ,IAAI;AAEhC,QAAM,kBAAkB,MAAM,mBAAmB,WAAW;AAC5D,QAAM,cAAc,MAAM,gBAAgB,WAAW;AAErD,QAAM,eAAe,QAAQ,QAAQ,eAAe,GAAG,QAAQ,yBAAyB;AACxF,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,MAAM,MAAM,SAAS,cAAc,MAAM,CAAC;AAAA,EAC5D,SAAS,OAAO;AACd,WAAO,MAAM,EAAE,MAAM,GAAG,mCAAmC;AAAA,EAC7D;AAEA,MAAI,eAAe,SAAS,QAAQ,eAAe,GAAG,IAAI;AAC1D,iBAAe,aAAa,WAAW,GAAG,IAAI,eAAe,KAAK,YAAY;AAE9E,QAAM,aAAa,UAAU,eAAe,YAAY;AACxD,MAAI,CAAC,YAAY;AACf,WAAO,KAAK,EAAE,UAAU,cAAc,aAAa,YAAY,KAAK,GAAG,uBAAuB;AAAA,EAChG;AAGA,QAAM,sBAAsB,OAAO,KAAK,YAAY,oBAAoB,CAAC,CAAC;AAE1E,SAAO,MAAM,EAAE,YAAY,GAAG,mBAAmB;AAEjD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,cAAc;AAAA,IAC1B;AAAA,EACF;AACF;","names":[]}
|
@@ -1,96 +0,0 @@
|
|
1
|
-
import type { UnitSource } from "@highstate/contract"
|
2
|
-
import { parentPort, workerData } from "node:worker_threads"
|
3
|
-
import { fileURLToPath } from "node:url"
|
4
|
-
import { dirname, relative, resolve } from "node:path"
|
5
|
-
import { readFile } from "node:fs/promises"
|
6
|
-
import pino, { type Level } from "pino"
|
7
|
-
import { resolve as importMetaResolve } from "import-meta-resolve"
|
8
|
-
import { readPackageJSON, resolvePackageJSON } from "pkg-types"
|
9
|
-
|
10
|
-
export type SourceResolutionRequest = {
|
11
|
-
unitType: string
|
12
|
-
source: UnitSource
|
13
|
-
}
|
14
|
-
|
15
|
-
export type SourceResolutionResult = {
|
16
|
-
unitType: string
|
17
|
-
projectPath: string
|
18
|
-
packageJsonPath: string
|
19
|
-
sourceHash: string
|
20
|
-
allowedDependencies: string[]
|
21
|
-
}
|
22
|
-
|
23
|
-
export type HighstateManifestJson = {
|
24
|
-
sourceHashes?: Record<string, string>
|
25
|
-
}
|
26
|
-
|
27
|
-
const { requests, logLevel } = workerData as {
|
28
|
-
requests: SourceResolutionRequest[]
|
29
|
-
logLevel?: Level
|
30
|
-
}
|
31
|
-
|
32
|
-
const logger = pino({ name: "source-resolution-worker", level: logLevel ?? "silent" })
|
33
|
-
|
34
|
-
const results = await Promise.all(
|
35
|
-
requests.map(request => resolveUnitSourceSafe(request.source, request.unitType)),
|
36
|
-
)
|
37
|
-
|
38
|
-
parentPort!.postMessage({
|
39
|
-
type: "result",
|
40
|
-
results: results.filter((result): result is SourceResolutionResult => result !== null),
|
41
|
-
})
|
42
|
-
|
43
|
-
async function resolveUnitSourceSafe(
|
44
|
-
source: UnitSource,
|
45
|
-
unitType: string,
|
46
|
-
): Promise<SourceResolutionResult | null> {
|
47
|
-
try {
|
48
|
-
return await resolveUnitSource(source, unitType)
|
49
|
-
} catch (error) {
|
50
|
-
logger.error({ source, unitType, err: error }, "failed to resolve unit source")
|
51
|
-
return null
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
async function resolveUnitSource(
|
56
|
-
source: UnitSource,
|
57
|
-
unitType: string,
|
58
|
-
): Promise<SourceResolutionResult> {
|
59
|
-
const fullPath = source.path ? `${source.package}/${source.path}` : source.package
|
60
|
-
|
61
|
-
const url = importMetaResolve(fullPath, import.meta.url)
|
62
|
-
const path = fileURLToPath(url)
|
63
|
-
const projectPath = dirname(path)
|
64
|
-
|
65
|
-
const packageJsonPath = await resolvePackageJSON(projectPath)
|
66
|
-
const packageJson = await readPackageJSON(projectPath)
|
67
|
-
|
68
|
-
const manifestPath = resolve(dirname(packageJsonPath), "dist", "highstate.manifest.json")
|
69
|
-
let manifest: HighstateManifestJson | undefined
|
70
|
-
try {
|
71
|
-
manifest = JSON.parse(await readFile(manifestPath, "utf8")) as HighstateManifestJson
|
72
|
-
} catch (error) {
|
73
|
-
logger.debug({ error }, "failed to read highstate manifest")
|
74
|
-
}
|
75
|
-
|
76
|
-
let relativePath = relative(dirname(packageJsonPath), path)
|
77
|
-
relativePath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`
|
78
|
-
|
79
|
-
const sourceHash = manifest?.sourceHashes?.[relativePath]
|
80
|
-
if (!sourceHash) {
|
81
|
-
logger.warn({ unitType, relativePath, packageName: packageJson.name }, "source hash not found")
|
82
|
-
}
|
83
|
-
|
84
|
-
// only the peer dependencies of the package are allowed to auto-install when they are missing
|
85
|
-
const allowedDependencies = Object.keys(packageJson.peerDependencies ?? {})
|
86
|
-
|
87
|
-
logger.debug({ packageJson }, "package.json read")
|
88
|
-
|
89
|
-
return {
|
90
|
-
unitType,
|
91
|
-
projectPath,
|
92
|
-
packageJsonPath,
|
93
|
-
sourceHash: sourceHash ?? "",
|
94
|
-
allowedDependencies,
|
95
|
-
}
|
96
|
-
}
|