@highstate/backend 0.7.8 → 0.7.10
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 +267 -155
- 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 -5
- package/src/library/abstractions.ts +7 -7
- package/src/library/local.ts +296 -171
- 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/local.ts +5 -4
- 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
@@ -1,8 +1,8 @@
|
|
1
1
|
{
|
2
2
|
"sourceHashes": {
|
3
|
-
"./dist/index.js": "
|
4
|
-
"./dist/shared/index.js": "
|
5
|
-
"./dist/library/worker/main.js": "
|
6
|
-
"./dist/library/
|
3
|
+
"./dist/index.js": "e5fc1ecef50b0c434ff63c631362ecbc196b32f1b7c0d92a16b1511df017ad6c",
|
4
|
+
"./dist/shared/index.js": "ce531a480a772514e20f94ec9116c98580dba419c8f5507bb85b6cef40a5c1ae",
|
5
|
+
"./dist/library/worker/main.js": "11bbed95f67a1756408bcbea93b87af1ed913ebbf7dbd35978027b0b3e219c05",
|
6
|
+
"./dist/library/package-resolution-worker.js": "4bfa368ad35a64c109df9e5a468c057791164760fe166c4eb5d9a889dee4d7bc"
|
7
7
|
}
|
8
8
|
}
|
package/dist/index.js
CHANGED
@@ -32,7 +32,6 @@ import {
|
|
32
32
|
updateResourceCount,
|
33
33
|
valueToString
|
34
34
|
} from "./chunk-EQ4LMS7B.js";
|
35
|
-
import "./chunk-DGUM43GV.js";
|
36
35
|
|
37
36
|
// src/secret/abstractions.ts
|
38
37
|
var SecretAccessDeniedError = class extends Error {
|
@@ -173,49 +172,43 @@ import { z as z4 } from "zod";
|
|
173
172
|
import { fileURLToPath } from "node:url";
|
174
173
|
import { EventEmitter, on } from "node:events";
|
175
174
|
import { Worker } from "node:worker_threads";
|
176
|
-
import {
|
175
|
+
import { resolve } from "node:path";
|
177
176
|
import { readFile } from "node:fs/promises";
|
178
177
|
import { isUnitModel } from "@highstate/contract";
|
179
178
|
import Watcher from "watcher";
|
180
179
|
import { BetterLock } from "better-lock";
|
181
180
|
import { resolve as importMetaResolve } from "import-meta-resolve";
|
182
181
|
import { z as z3 } from "zod";
|
183
|
-
import { readPackageJSON
|
182
|
+
import { readPackageJSON } from "pkg-types";
|
183
|
+
import { runScript, installDependencies, addDependency } from "nypm";
|
184
|
+
import { flatMap, groupBy, map, pipe, unique } from "remeda";
|
184
185
|
var localLibraryBackendConfig = z3.object({
|
185
|
-
|
186
|
-
|
187
|
-
HIGHSTATE_BACKEND_LIBRARY_LOCAL_EXTRA_SOURCE_WATCH_PATHS: stringArrayType.default("")
|
186
|
+
HIGHSTATE_BACKEND_LIBRARY_LOCAL_PACKAGES: stringArrayType.default("@highstate/library"),
|
187
|
+
HIGHSTATE_BACKEND_LIBRARY_LOCAL_WATCH_PATHS: stringArrayType.optional()
|
188
188
|
});
|
189
189
|
var LocalLibraryBackend = class _LocalLibraryBackend {
|
190
|
-
constructor(
|
191
|
-
this.
|
192
|
-
this.sourceBasePath = sourceBasePath;
|
190
|
+
constructor(libraryPackages, watchPaths, logger) {
|
191
|
+
this.libraryPackages = libraryPackages;
|
193
192
|
this.logger = logger;
|
194
|
-
this.
|
195
|
-
this.libraryWatcher.on("all", (event, path) => {
|
196
|
-
const prefixPath = modulePaths.find((modulePath) => path.startsWith(modulePath));
|
197
|
-
this.logger.info({ msg: "library event", event, path: relative(prefixPath, path) });
|
198
|
-
void this.lock.acquire(() => this.updateLibrary());
|
199
|
-
});
|
200
|
-
this.sourceWatcher = new Watcher([sourceBasePath, ...extraSourceWatchPaths], {
|
193
|
+
this.watcher = new Watcher(watchPaths, {
|
201
194
|
recursive: true,
|
202
195
|
ignoreInitial: true,
|
203
|
-
ignore: /\.git|node_modules/
|
196
|
+
ignore: /\.git|node_modules|dist/
|
204
197
|
});
|
205
|
-
this.
|
206
|
-
|
198
|
+
this.watcher.on("all", (event, path) => {
|
199
|
+
this.logger.debug({ event, path }, "library event");
|
200
|
+
if (!path.endsWith(".json") && !path.endsWith(".ts")) {
|
207
201
|
return;
|
208
202
|
}
|
209
|
-
void this.
|
203
|
+
void this.handleFileEvent(path);
|
210
204
|
});
|
211
|
-
this.logger.debug({ msg: "initialized", modulePaths });
|
212
205
|
}
|
213
|
-
|
214
|
-
sourceWatcher;
|
206
|
+
watcher;
|
215
207
|
lock = new BetterLock();
|
216
208
|
eventEmitter = new EventEmitter();
|
217
209
|
library = null;
|
218
210
|
worker = null;
|
211
|
+
packages = /* @__PURE__ */ new Map();
|
219
212
|
resolvedUnitSources = /* @__PURE__ */ new Map();
|
220
213
|
async loadLibrary() {
|
221
214
|
return await this.lock.acquire(async () => {
|
@@ -228,22 +221,27 @@ var LocalLibraryBackend = class _LocalLibraryBackend {
|
|
228
221
|
yield library;
|
229
222
|
}
|
230
223
|
}
|
231
|
-
|
232
|
-
return
|
233
|
-
const [library] = await this.getLibrary();
|
234
|
-
if (!this.resolvedUnitSources.size) {
|
235
|
-
await this.syncUnitSources(library);
|
236
|
-
}
|
224
|
+
getLoadedResolvedUnitSources() {
|
225
|
+
return this.lock.acquire(() => {
|
237
226
|
return Array.from(this.resolvedUnitSources.values());
|
238
227
|
});
|
239
228
|
}
|
240
|
-
async
|
229
|
+
async getResolvedUnitSources(unitTypes) {
|
241
230
|
return await this.lock.acquire(async () => {
|
242
231
|
const [library] = await this.getLibrary();
|
243
|
-
|
244
|
-
|
232
|
+
const units = unitTypes.map((type) => library.components[type]).filter(isUnitModel);
|
233
|
+
const packageNames = Object.keys(groupBy(units, (unit) => unit.source.package));
|
234
|
+
await this.ensureLibraryPackagesLoaded(packageNames, true);
|
235
|
+
const result = [];
|
236
|
+
for (const unitType of unitTypes) {
|
237
|
+
const resolvedUnitSource = this.resolvedUnitSources.get(unitType);
|
238
|
+
if (resolvedUnitSource) {
|
239
|
+
result.push(resolvedUnitSource);
|
240
|
+
} else {
|
241
|
+
this.logger.warn(`resolved unit source not found for unit: "%s"`, unitType);
|
242
|
+
}
|
245
243
|
}
|
246
|
-
return
|
244
|
+
return result;
|
247
245
|
});
|
248
246
|
}
|
249
247
|
async *watchResolvedUnitSources(signal) {
|
@@ -253,63 +251,6 @@ var LocalLibraryBackend = class _LocalLibraryBackend {
|
|
253
251
|
yield resolvedUnitSource;
|
254
252
|
}
|
255
253
|
}
|
256
|
-
async syncUnitSources(library) {
|
257
|
-
const unitsToResolve = /* @__PURE__ */ new Map();
|
258
|
-
for (const component of Object.values(library.components)) {
|
259
|
-
if (!isUnitModel(component)) {
|
260
|
-
continue;
|
261
|
-
}
|
262
|
-
const existingResolvedSource = this.resolvedUnitSources.get(component.type);
|
263
|
-
const expectedSource = JSON.stringify(component.source);
|
264
|
-
if (existingResolvedSource?.serializedSource !== expectedSource) {
|
265
|
-
unitsToResolve.set(component.type, component);
|
266
|
-
}
|
267
|
-
}
|
268
|
-
await this.runSourceResolution(unitsToResolve);
|
269
|
-
}
|
270
|
-
async runSourceResolution(units) {
|
271
|
-
const workerPathUrl = importMetaResolve(
|
272
|
-
`@highstate/backend/source-resolution-worker`,
|
273
|
-
import.meta.url
|
274
|
-
);
|
275
|
-
const workerPath = fileURLToPath(workerPathUrl);
|
276
|
-
const worker = new Worker(workerPath, {
|
277
|
-
workerData: {
|
278
|
-
requests: Array.from(units.values()).map((unit) => ({
|
279
|
-
unitType: unit.type,
|
280
|
-
source: unit.source
|
281
|
-
})),
|
282
|
-
sourceBasePath: this.sourceBasePath,
|
283
|
-
logLevel: "error"
|
284
|
-
}
|
285
|
-
});
|
286
|
-
for await (const [event] of on(worker, "message")) {
|
287
|
-
const eventData = event;
|
288
|
-
if (eventData.type !== "result") {
|
289
|
-
throw new Error(`Unexpected message type '${eventData.type}', expected 'result'`);
|
290
|
-
}
|
291
|
-
for (const result of eventData.results) {
|
292
|
-
const unit = units.get(result.unitType);
|
293
|
-
if (!unit) {
|
294
|
-
this.logger.warn("unit not found for resolved source", { unitType: result.unitType });
|
295
|
-
continue;
|
296
|
-
}
|
297
|
-
const resolvedSource = {
|
298
|
-
unitType: result.unitType,
|
299
|
-
serializedSource: JSON.stringify(unit.source),
|
300
|
-
projectPath: result.projectPath,
|
301
|
-
packageJsonPath: result.packageJsonPath,
|
302
|
-
allowedDependencies: result.allowedDependencies,
|
303
|
-
sourceHash: result.sourceHash
|
304
|
-
};
|
305
|
-
this.resolvedUnitSources.set(result.unitType, resolvedSource);
|
306
|
-
this.eventEmitter.emit("resolvedUnitSource", resolvedSource);
|
307
|
-
}
|
308
|
-
this.logger.info("unit sources synced");
|
309
|
-
return;
|
310
|
-
}
|
311
|
-
throw new Error("Worker ended without sending the result");
|
312
|
-
}
|
313
254
|
async evaluateCompositeInstances(allInstances, resolvedInputs, instanceIds) {
|
314
255
|
return await this.lock.acquire(async () => {
|
315
256
|
this.logger.info("evaluating %d composite instances", instanceIds.length);
|
@@ -357,11 +298,14 @@ var LocalLibraryBackend = class _LocalLibraryBackend {
|
|
357
298
|
if (this.library && this.worker) {
|
358
299
|
return [this.library, this.worker];
|
359
300
|
}
|
360
|
-
return await this.
|
301
|
+
return await this.reloadLibrary();
|
361
302
|
}
|
362
|
-
async
|
363
|
-
this.logger.info("
|
364
|
-
this.worker = this.
|
303
|
+
async reloadLibrary() {
|
304
|
+
this.logger.info("reloading library");
|
305
|
+
this.worker = this.createLibraryWorker({
|
306
|
+
modulePaths: this.libraryPackages,
|
307
|
+
logLevel: "silent"
|
308
|
+
});
|
365
309
|
for await (const [event] of on(this.worker, "message")) {
|
366
310
|
const eventData = event;
|
367
311
|
if (eventData.type === "error") {
|
@@ -377,79 +321,213 @@ var LocalLibraryBackend = class _LocalLibraryBackend {
|
|
377
321
|
this.eventEmitter.emit("library", updates);
|
378
322
|
this.library = eventData.library;
|
379
323
|
this.logger.info("library reloaded");
|
380
|
-
await this.syncUnitSources(eventData.library);
|
381
324
|
return [this.library, this.worker];
|
382
325
|
}
|
383
326
|
throw new Error("Worker ended without sending library model");
|
384
327
|
}
|
385
|
-
|
386
|
-
const
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
const packageJsonPath = await resolvePackageJSON(path);
|
392
|
-
const packageJson = await readPackageJSON(path);
|
393
|
-
const library = await this.loadLibrary();
|
394
|
-
const manifestPath = resolve(dirname(packageJsonPath), "dist", "highstate.manifest.json");
|
395
|
-
let manifest;
|
396
|
-
try {
|
397
|
-
manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
398
|
-
} catch (error) {
|
399
|
-
this.logger.debug(
|
400
|
-
{ error },
|
401
|
-
`failed to read highstate manifest for package "%s"`,
|
402
|
-
packageJson.name
|
328
|
+
async reloadUnitManifest(libraryPackage) {
|
329
|
+
const library = this.library;
|
330
|
+
if (!library) {
|
331
|
+
this.logger.warn(
|
332
|
+
`library not loaded, cannot reload unit manifest for package: "%s"`,
|
333
|
+
libraryPackage.name
|
403
334
|
);
|
335
|
+
return;
|
404
336
|
}
|
337
|
+
const manifest = await this.readLibraryPackageManifest(libraryPackage);
|
338
|
+
const packageJson = await readPackageJSON(libraryPackage.rootPath);
|
405
339
|
for (const unit of Object.values(library.components)) {
|
406
340
|
if (!isUnitModel(unit)) {
|
407
341
|
continue;
|
408
342
|
}
|
409
|
-
if (unit.source.package !==
|
343
|
+
if (unit.source.package !== libraryPackage.name) {
|
410
344
|
continue;
|
411
345
|
}
|
412
|
-
const relativePath = unit.source.path ? `./dist/${unit.source.path}
|
413
|
-
const sourceHash = manifest?.sourceHashes?.[relativePath];
|
346
|
+
const relativePath = unit.source.path ? `./dist/${unit.source.path}` : `./dist`;
|
347
|
+
const sourceHash = manifest?.sourceHashes?.[`${relativePath}/index.js`];
|
414
348
|
if (!sourceHash) {
|
415
349
|
this.logger.warn(`source hash not found for unit: "%s"`, unit.type);
|
416
350
|
continue;
|
417
351
|
}
|
418
352
|
const resolvedSource = this.resolvedUnitSources.get(unit.type);
|
419
|
-
if (!resolvedSource) {
|
420
|
-
this.logger.warn(`resolved source not found for unit: "%s"`, unit.type);
|
421
|
-
continue;
|
422
|
-
}
|
423
353
|
const newResolvedSource = {
|
424
|
-
|
425
|
-
sourceHash
|
354
|
+
unitType: unit.type,
|
355
|
+
sourceHash,
|
356
|
+
projectPath: resolve(libraryPackage.rootPath, relativePath),
|
357
|
+
allowedDependencies: Object.keys(packageJson.peerDependencies ?? {})
|
426
358
|
};
|
359
|
+
if (resolvedSource?.sourceHash === newResolvedSource.sourceHash && resolvedSource?.projectPath === newResolvedSource.projectPath) {
|
360
|
+
continue;
|
361
|
+
}
|
427
362
|
this.resolvedUnitSources.set(unit.type, newResolvedSource);
|
428
363
|
this.eventEmitter.emit("resolvedUnitSource", newResolvedSource);
|
429
|
-
this.logger.
|
364
|
+
this.logger.debug(`updated source for unit: "%s"`, unit.type);
|
430
365
|
}
|
431
366
|
}
|
367
|
+
async ensureLibraryPackagesLoaded(names, installIfNotFound = false) {
|
368
|
+
const packagesToLoad = names.filter((name) => !this.packages.has(name));
|
369
|
+
if (packagesToLoad.length > 0) {
|
370
|
+
await this.loadLibraryPackages(packagesToLoad, installIfNotFound);
|
371
|
+
}
|
372
|
+
}
|
373
|
+
async rebuildLibraryPackage(libraryPackage, installDeps = false, updateDeps = false, rebuiltPackages = /* @__PURE__ */ new Set()) {
|
374
|
+
if (rebuiltPackages.has(libraryPackage.name)) {
|
375
|
+
return;
|
376
|
+
}
|
377
|
+
rebuiltPackages.add(libraryPackage.name);
|
378
|
+
if (installDeps) {
|
379
|
+
this.logger.info(`installing dependencies for package "${libraryPackage.name}"`);
|
380
|
+
await installDependencies({ cwd: libraryPackage.rootPath });
|
381
|
+
}
|
382
|
+
if (updateDeps) {
|
383
|
+
await this.updateLibraryPackageDependencies(libraryPackage);
|
384
|
+
}
|
385
|
+
this.logger.info(`rebuilding library package "${libraryPackage.name}" via build script`);
|
386
|
+
await runScript("build", { cwd: libraryPackage.rootPath });
|
387
|
+
if (this.libraryPackages.includes(libraryPackage.name)) {
|
388
|
+
await this.reloadLibrary();
|
389
|
+
} else {
|
390
|
+
await this.reloadUnitManifest(libraryPackage);
|
391
|
+
}
|
392
|
+
await this.rebuildLibraryPackageDependents(libraryPackage, rebuiltPackages);
|
393
|
+
}
|
394
|
+
async updateLibraryPackageDependencies(libraryPackage) {
|
395
|
+
const packageJson = await readPackageJSON(libraryPackage.rootPath);
|
396
|
+
const parsedName = _LocalLibraryBackend.parseDependencyName(libraryPackage.name);
|
397
|
+
const dependencyPackageNames = pipe(
|
398
|
+
[packageJson.dependencies, packageJson.devDependencies, packageJson.peerDependencies],
|
399
|
+
flatMap((deps) => Object.keys(deps ?? {})),
|
400
|
+
unique(),
|
401
|
+
map(_LocalLibraryBackend.parseDependencyName)
|
402
|
+
);
|
403
|
+
const sameScopeDependencies = dependencyPackageNames.filter(
|
404
|
+
(dep) => dep.scope === parsedName.scope && dep.name !== parsedName.name
|
405
|
+
);
|
406
|
+
await this.ensureLibraryPackagesLoaded(sameScopeDependencies.map((dep) => dep.name));
|
407
|
+
for (const dependency of sameScopeDependencies) {
|
408
|
+
const dependencyPackage = this.packages.get(dependency.name);
|
409
|
+
if (!dependencyPackage) {
|
410
|
+
this.logger.warn(`dependency package not found for graph update: "%s"`, dependency.name);
|
411
|
+
continue;
|
412
|
+
}
|
413
|
+
libraryPackage.dependencies.add(dependency.name);
|
414
|
+
dependencyPackage.dependents.add(libraryPackage.name);
|
415
|
+
}
|
416
|
+
}
|
417
|
+
async rebuildLibraryPackageDependents(libraryPackage, rebuiltPackages = /* @__PURE__ */ new Set()) {
|
418
|
+
const promises = [];
|
419
|
+
for (const dependent of libraryPackage.dependents) {
|
420
|
+
const dependentPackage = this.packages.get(dependent);
|
421
|
+
if (!dependentPackage) {
|
422
|
+
this.logger.warn(`dependent package not found for rebuild: "%s"`, dependent);
|
423
|
+
continue;
|
424
|
+
}
|
425
|
+
promises.push(this.rebuildLibraryPackage(dependentPackage, false, false, rebuiltPackages));
|
426
|
+
}
|
427
|
+
await Promise.all(promises);
|
428
|
+
}
|
429
|
+
static parseDependencyName(dependency) {
|
430
|
+
if (dependency.startsWith("@")) {
|
431
|
+
const parts = dependency.split("/");
|
432
|
+
return {
|
433
|
+
name: dependency,
|
434
|
+
scope: parts[0]
|
435
|
+
};
|
436
|
+
}
|
437
|
+
return {
|
438
|
+
name: dependency,
|
439
|
+
scope: null
|
440
|
+
};
|
441
|
+
}
|
442
|
+
async readLibraryPackageManifest(libraryPackage) {
|
443
|
+
const manifestPath = resolve(libraryPackage.rootPath, "dist", "highstate.manifest.json");
|
444
|
+
try {
|
445
|
+
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
446
|
+
return manifest;
|
447
|
+
} catch (error) {
|
448
|
+
this.logger.debug(
|
449
|
+
{ error },
|
450
|
+
`failed to read highstate manifest of package: "%s"`,
|
451
|
+
libraryPackage.name
|
452
|
+
);
|
453
|
+
return void 0;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
async loadLibraryPackages(names, installIfNotFound = false) {
|
457
|
+
this.logger.info("loading library packages: %s", names.join(", "));
|
458
|
+
const missingPackages = [];
|
459
|
+
const packagesToUpdate = [];
|
460
|
+
const worker = this.createPackageResolutionWorker({ packageNames: names });
|
461
|
+
for await (const [event] of on(worker, "message")) {
|
462
|
+
const eventData = event;
|
463
|
+
if (eventData.type !== "result") {
|
464
|
+
continue;
|
465
|
+
}
|
466
|
+
for (const result of eventData.results) {
|
467
|
+
if (result.type === "success") {
|
468
|
+
const libraryPackage = {
|
469
|
+
name: result.packageName,
|
470
|
+
rootPath: result.packageRootPath,
|
471
|
+
dependencies: /* @__PURE__ */ new Set(),
|
472
|
+
dependents: /* @__PURE__ */ new Set()
|
473
|
+
};
|
474
|
+
this.packages.set(result.packageName, libraryPackage);
|
475
|
+
packagesToUpdate.push(libraryPackage);
|
476
|
+
this.logger.info(`loaded library package: "%s"`, result.packageName);
|
477
|
+
} else if (result.type === "not-found") {
|
478
|
+
missingPackages.push(result.packageName);
|
479
|
+
} else {
|
480
|
+
this.logger.error(
|
481
|
+
`failed to load library package "%s": %s`,
|
482
|
+
result.packageName,
|
483
|
+
result.error
|
484
|
+
);
|
485
|
+
}
|
486
|
+
}
|
487
|
+
break;
|
488
|
+
}
|
489
|
+
for (const libraryPackage of packagesToUpdate) {
|
490
|
+
await this.updateLibraryPackageDependencies(libraryPackage);
|
491
|
+
if (!this.libraryPackages.includes(libraryPackage.name)) {
|
492
|
+
await this.reloadUnitManifest(libraryPackage);
|
493
|
+
}
|
494
|
+
}
|
495
|
+
if (installIfNotFound && missingPackages.length > 0) {
|
496
|
+
this.logger.info("installing missing library packages: %s", missingPackages.join(", "));
|
497
|
+
await addDependency(missingPackages);
|
498
|
+
await this.loadLibraryPackages(missingPackages);
|
499
|
+
}
|
500
|
+
}
|
501
|
+
async handleFileEvent(path) {
|
502
|
+
await this.lock.acquire(async () => {
|
503
|
+
const libraryPackage = this.packages.values().find((pkg) => path.startsWith(pkg.rootPath));
|
504
|
+
if (libraryPackage) {
|
505
|
+
await this.rebuildLibraryPackage(libraryPackage);
|
506
|
+
}
|
507
|
+
});
|
508
|
+
}
|
509
|
+
createLibraryWorker(workerData) {
|
510
|
+
const workerPathUrl = importMetaResolve(`@highstate/backend/library-worker`, import.meta.url);
|
511
|
+
const workerPath = fileURLToPath(workerPathUrl);
|
512
|
+
return new Worker(workerPath, { workerData });
|
513
|
+
}
|
514
|
+
createPackageResolutionWorker(workerData) {
|
515
|
+
const workerPathUrl = importMetaResolve(
|
516
|
+
`@highstate/backend/package-resolution-worker`,
|
517
|
+
import.meta.url
|
518
|
+
);
|
519
|
+
const workerPath = fileURLToPath(workerPathUrl);
|
520
|
+
return new Worker(workerPath, { workerData });
|
521
|
+
}
|
432
522
|
static async create(config, logger) {
|
433
|
-
|
434
|
-
|
435
|
-
const url = importMetaResolve(module, import.meta.url);
|
436
|
-
let path = fileURLToPath(url);
|
437
|
-
if (basename(path).includes(".")) {
|
438
|
-
path = dirname(path);
|
439
|
-
}
|
440
|
-
modulePaths.push(path);
|
441
|
-
}
|
442
|
-
let sourceBasePath = config.HIGHSTATE_BACKEND_LIBRARY_LOCAL_SOURCE_BASE_PATH;
|
443
|
-
const extraSourceWatchPaths = config.HIGHSTATE_BACKEND_LIBRARY_LOCAL_EXTRA_SOURCE_WATCH_PATHS;
|
444
|
-
if (!sourceBasePath) {
|
523
|
+
let watchPaths = config.HIGHSTATE_BACKEND_LIBRARY_LOCAL_WATCH_PATHS;
|
524
|
+
if (!watchPaths) {
|
445
525
|
const [projectPath] = await resolveMainLocalProject();
|
446
|
-
|
447
|
-
extraSourceWatchPaths.push(projectPath);
|
526
|
+
watchPaths = [resolve(projectPath, "packages")];
|
448
527
|
}
|
449
528
|
return new _LocalLibraryBackend(
|
450
|
-
|
451
|
-
|
452
|
-
extraSourceWatchPaths,
|
529
|
+
config.HIGHSTATE_BACKEND_LIBRARY_LOCAL_PACKAGES,
|
530
|
+
watchPaths,
|
453
531
|
logger.child({ backend: "LibraryBackend", service: "LocalLibraryBackend" })
|
454
532
|
);
|
455
533
|
}
|
@@ -481,6 +559,7 @@ import { z as z5 } from "zod";
|
|
481
559
|
import {
|
482
560
|
getInstanceId
|
483
561
|
} from "@highstate/contract";
|
562
|
+
import { stringify, parse } from "yaml";
|
484
563
|
var localProjectBackendConfig = z5.object({
|
485
564
|
HIGHSTATE_BACKEND_PROJECT_PROJECTS_DIR: z5.string().optional()
|
486
565
|
});
|
@@ -495,7 +574,7 @@ var LocalProjectBackend = class _LocalProjectBackend {
|
|
495
574
|
async getProjectIds() {
|
496
575
|
try {
|
497
576
|
const files = await readdir(this.projectsDir);
|
498
|
-
return files.filter((file) => file.endsWith(".
|
577
|
+
return files.filter((file) => file.endsWith(".yaml")).map((file) => file.replace(/\.yaml$/, ""));
|
499
578
|
} catch (error) {
|
500
579
|
throw new Error("Failed to get project names", { cause: error });
|
501
580
|
}
|
@@ -732,13 +811,13 @@ var LocalProjectBackend = class _LocalProjectBackend {
|
|
732
811
|
}
|
733
812
|
}
|
734
813
|
getProjectPath(projectId) {
|
735
|
-
return `${this.projectsDir}/${projectId}.
|
814
|
+
return `${this.projectsDir}/${projectId}.yaml`;
|
736
815
|
}
|
737
816
|
async loadProject(projectId) {
|
738
817
|
const projectPath = this.getProjectPath(projectId);
|
739
818
|
try {
|
740
819
|
const content = await readFile2(projectPath, "utf-8");
|
741
|
-
return projectModelSchema.parse(
|
820
|
+
return projectModelSchema.parse(parse(content));
|
742
821
|
} catch (error) {
|
743
822
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
744
823
|
return { instances: {}, hubs: {} };
|
@@ -748,7 +827,7 @@ var LocalProjectBackend = class _LocalProjectBackend {
|
|
748
827
|
}
|
749
828
|
async writeProject(projectId, project) {
|
750
829
|
const projectPath = this.getProjectPath(projectId);
|
751
|
-
const content =
|
830
|
+
const content = stringify(project, void 0, 2);
|
752
831
|
await writeFile(projectPath, content);
|
753
832
|
}
|
754
833
|
async withInstance(projectId, instanceId, callback) {
|
@@ -842,6 +921,30 @@ var ProjectManager = class _ProjectManager {
|
|
842
921
|
yield children;
|
843
922
|
}
|
844
923
|
}
|
924
|
+
/**
|
925
|
+
* Loads the full info of a project, including instances, hubs, and composite instances.
|
926
|
+
*
|
927
|
+
* Also filters out instances that are not in the library.
|
928
|
+
*
|
929
|
+
* @param projectId The ID of the project to load.
|
930
|
+
*/
|
931
|
+
async getProject(projectId) {
|
932
|
+
const [{ instances, hubs }, compositeInstances, library] = await Promise.all([
|
933
|
+
this.projectBackend.getProject(projectId),
|
934
|
+
this.stateBackend.getCompositeInstances(projectId),
|
935
|
+
this.libraryBackend.loadLibrary()
|
936
|
+
]);
|
937
|
+
const filteredInstances = instances.filter((instance) => instance.type in library.components);
|
938
|
+
const filteredCompositeInstances = compositeInstances.filter((instance) => instance.instance.type in library.components).map((instance) => ({
|
939
|
+
...instance,
|
940
|
+
children: instance.children.filter((child) => child.type in library.components)
|
941
|
+
}));
|
942
|
+
return {
|
943
|
+
instances: filteredInstances,
|
944
|
+
hubs,
|
945
|
+
compositeInstances: filteredCompositeInstances
|
946
|
+
};
|
947
|
+
}
|
845
948
|
async createInstance(projectId, instance) {
|
846
949
|
const createdInstance = await this.projectBackend.createInstance(projectId, instance);
|
847
950
|
await this.updateCompositeInstance(projectId, createdInstance);
|
@@ -986,9 +1089,10 @@ var ProjectManager = class _ProjectManager {
|
|
986
1089
|
}
|
987
1090
|
let sourceHash;
|
988
1091
|
if (isUnitModel2(library.components[instance.type])) {
|
989
|
-
const
|
1092
|
+
const resolvedUnits = await this.libraryBackend.getResolvedUnitSources([instance.type]);
|
1093
|
+
const resolvedUnit = resolvedUnits.find((unit) => unit.unitType === instance.type);
|
990
1094
|
if (!resolvedUnit) {
|
991
|
-
throw new Error(`Resolved unit not found
|
1095
|
+
throw new Error(`Resolved unit not found for type "${instance.type}"`);
|
992
1096
|
}
|
993
1097
|
sourceHash = resolvedUnit.sourceHash;
|
994
1098
|
}
|
@@ -1088,7 +1192,7 @@ import { z as z7 } from "zod";
|
|
1088
1192
|
import spawn from "nano-spawn";
|
1089
1193
|
|
1090
1194
|
// src/terminal/run.sh.ts
|
1091
|
-
var
|
1195
|
+
var runScript2 = `set -e -o pipefail
|
1092
1196
|
read -r data
|
1093
1197
|
|
1094
1198
|
# Extract env and files as key-value pairs, and command as an array
|
@@ -1143,7 +1247,7 @@ var DockerTerminalBackend = class _DockerTerminalBackend {
|
|
1143
1247
|
const hsTempDir = resolve3(tmpdir(), "highstate");
|
1144
1248
|
await mkdir2(hsTempDir, { recursive: true });
|
1145
1249
|
const runScriptPath = resolve3(hsTempDir, "run.sh");
|
1146
|
-
await writeFile2(runScriptPath,
|
1250
|
+
await writeFile2(runScriptPath, runScript2, { mode: 493 });
|
1147
1251
|
const args = [
|
1148
1252
|
"run",
|
1149
1253
|
"-i",
|
@@ -1630,10 +1734,7 @@ var LocalRunnerBackend = class _LocalRunnerBackend {
|
|
1630
1734
|
async updateWorker(options, configMap, preview) {
|
1631
1735
|
const instanceId = _LocalRunnerBackend.getInstanceId(options);
|
1632
1736
|
try {
|
1633
|
-
const resolvedSource = await this.
|
1634
|
-
if (!resolvedSource) {
|
1635
|
-
throw new Error(`Resolved unit source not found for ${options.instanceType}`);
|
1636
|
-
}
|
1737
|
+
const resolvedSource = await this.getResolvedUnitSource(options.instanceType);
|
1637
1738
|
await this.pulumiProjectHost.runLocal(
|
1638
1739
|
{
|
1639
1740
|
projectId: options.projectId,
|
@@ -1737,7 +1838,7 @@ var LocalRunnerBackend = class _LocalRunnerBackend {
|
|
1737
1838
|
async destroyWorker(options) {
|
1738
1839
|
const instanceId = _LocalRunnerBackend.getInstanceId(options);
|
1739
1840
|
try {
|
1740
|
-
const resolvedSource = await this.
|
1841
|
+
const resolvedSource = await this.getResolvedUnitSource(options.instanceType);
|
1741
1842
|
if (!resolvedSource) {
|
1742
1843
|
throw new Error(`Resolved unit source not found for ${options.instanceType}`);
|
1743
1844
|
}
|
@@ -1980,6 +2081,14 @@ var LocalRunnerBackend = class _LocalRunnerBackend {
|
|
1980
2081
|
await ensureDependencyInstalled(packageName);
|
1981
2082
|
return true;
|
1982
2083
|
}
|
2084
|
+
async getResolvedUnitSource(instanceType) {
|
2085
|
+
const sources = await this.libraryBackend.getResolvedUnitSources([instanceType]);
|
2086
|
+
const source = sources.find((source2) => source2.unitType === instanceType);
|
2087
|
+
if (!source) {
|
2088
|
+
throw new Error(`Resolved unit source not found for ${instanceType}`);
|
2089
|
+
}
|
2090
|
+
return source;
|
2091
|
+
}
|
1983
2092
|
static getStackName(options) {
|
1984
2093
|
return `${options.projectId}_${options.instanceName}`;
|
1985
2094
|
}
|
@@ -2538,6 +2647,7 @@ import { mapValues as mapValues3 } from "remeda";
|
|
2538
2647
|
|
2539
2648
|
// src/orchestrator/operation-workset.ts
|
2540
2649
|
import { isUnitModel as isUnitModel3 } from "@highstate/contract";
|
2650
|
+
import { unique as unique2 } from "remeda";
|
2541
2651
|
var OperationWorkset = class _OperationWorkset {
|
2542
2652
|
constructor(operation, library, stateManager, logger) {
|
2543
2653
|
this.operation = operation;
|
@@ -2788,13 +2898,15 @@ var OperationWorkset = class _OperationWorkset {
|
|
2788
2898
|
return Array.from(instanceIds);
|
2789
2899
|
}
|
2790
2900
|
static async load(operation, projectBackend, libraryBackend, stateBackend, stateManager, logger, signal) {
|
2791
|
-
const [library,
|
2901
|
+
const [library, project, compositeInstances, states] = await Promise.all([
|
2792
2902
|
libraryBackend.loadLibrary(signal),
|
2793
|
-
libraryBackend.getResolvedUnitSources(),
|
2794
2903
|
projectBackend.getProject(operation.projectId, signal),
|
2795
2904
|
stateBackend.getCompositeInstances(operation.projectId, signal),
|
2796
2905
|
stateBackend.getAllInstanceStates(operation.projectId, signal)
|
2797
2906
|
]);
|
2907
|
+
const unitSources = await libraryBackend.getResolvedUnitSources(
|
2908
|
+
unique2(project.instances.map((i) => i.type))
|
2909
|
+
);
|
2798
2910
|
const workset = new _OperationWorkset(
|
2799
2911
|
operation,
|
2800
2912
|
library,
|