@highstate/cli 0.20.0 → 0.26.0
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/assets/template/package.tpl.json +1 -8
- package/assets/template/packages/units/package.tpl.json +1 -3
- package/assets/tsconfig.base.json +1 -0
- package/dist/{chunk-KA6ZC6BV.js → chunk-2s546hay.js} +569 -619
- package/dist/{library-loader-PZWYMBAE.js → chunk-sxh2gdkm.js} +21 -17
- package/dist/{chunk-CMECLVT7.js → chunk-vcev74he.js} +4 -3
- package/dist/commands/index.js +30 -4
- package/dist/highstate.manifest.json +2 -2
- package/dist/main.js +19 -7
- package/package.json +13 -14
- package/src/commands/build.ts +64 -20
- package/src/commands/designer.ts +51 -41
- package/src/commands/init.ts +6 -66
- package/src/commands/update.ts +101 -51
- package/src/shared/bin-transformer.ts +2 -3
- package/src/shared/index.ts +0 -1
- package/src/shared/overrides.ts +5 -41
- package/src/shared/project-versions.ts +6 -31
- package/src/shared/pulumi-cli.ts +5 -2
- package/src/shared/schema-transformer.ts +1 -2
- package/src/shared/source-hash-calculator.ts +55 -2
- package/LICENSE +0 -21
- package/assets/template/pnpm-workspace.tpl.yaml +0 -4
- package/dist/chunk-CMECLVT7.js.map +0 -1
- package/dist/chunk-KA6ZC6BV.js.map +0 -1
- package/dist/commands/index.js.map +0 -1
- package/dist/library-loader-PZWYMBAE.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/src/shared/pnpm-workspace.ts +0 -32
|
@@ -1,49 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { writeFile, mkdir, access, readdir, rm, readFile, stat } from 'node:fs/promises';
|
|
7
|
-
import { PassThrough } from 'node:stream';
|
|
8
|
-
import { LogLevels, consola } from 'consola';
|
|
9
|
-
import pino, { levels } from 'pino';
|
|
10
|
-
import { resolve, relative, dirname, join } from 'node:path';
|
|
11
|
-
import Handlebars from 'handlebars';
|
|
12
|
-
import { readPackageJSON, resolvePackageJSON } from 'pkg-types';
|
|
13
|
-
import { parse, stringify } from 'yaml';
|
|
14
|
-
import { execFile } from 'node:child_process';
|
|
15
|
-
import { promisify } from 'node:util';
|
|
16
|
-
import MagicString from 'magic-string';
|
|
17
|
-
import { parseAsync } from 'oxc-parser';
|
|
18
|
-
import { walk } from 'oxc-walker';
|
|
19
|
-
import { z } from 'zod';
|
|
20
|
-
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
21
|
-
import { crc32 } from '@aws-crypto/crc32';
|
|
22
|
-
import { resolve as resolve$1 } from 'import-meta-resolve';
|
|
23
|
-
import { existsSync } from 'node:fs';
|
|
24
|
-
import { input, confirm, select } from '@inquirer/prompts';
|
|
25
|
-
import { Table } from 'console-table-printer';
|
|
26
|
-
import { encode } from '@msgpack/msgpack';
|
|
27
|
-
import { mapValues } from 'remeda';
|
|
28
|
-
import { build } from 'tsup';
|
|
29
|
-
import { colorize } from 'consola/utils';
|
|
30
|
-
import { getPort } from 'get-port-please';
|
|
31
|
-
import { addDevDependency, detectPackageManager, installDependencies } from 'nypm';
|
|
32
|
-
import semver from 'semver';
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
int32ToBytes
|
|
5
|
+
} from "./chunk-vcev74he.js";
|
|
33
6
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
7
|
+
// src/commands/backend/identity.ts
|
|
8
|
+
import { hostname } from "os";
|
|
9
|
+
import { loadConfig } from "@highstate/backend";
|
|
10
|
+
import { identityToRecipient } from "age-encryption";
|
|
11
|
+
import { Command } from "clipanion";
|
|
12
|
+
|
|
13
|
+
// src/shared/bin-transformer.ts
|
|
14
|
+
import { readFile } from "fs/promises";
|
|
15
|
+
|
|
16
|
+
// src/shared/logger.ts
|
|
17
|
+
import { PassThrough } from "stream";
|
|
18
|
+
import { consola, LogLevels } from "consola";
|
|
19
|
+
import pino, { levels } from "pino";
|
|
20
|
+
var logger = pino({
|
|
21
|
+
name: "highstate-cli",
|
|
22
|
+
level: process.env.LOG_LEVEL ?? "info",
|
|
23
|
+
serializers: {
|
|
24
|
+
error: (value) => serializeError(value)
|
|
25
|
+
}
|
|
26
|
+
}, createConsolaStream());
|
|
44
27
|
consola.level = LogLevels[process.env.LOG_LEVEL ?? "info"];
|
|
45
28
|
function createConsolaStream() {
|
|
46
|
-
const stream = new PassThrough
|
|
29
|
+
const stream = new PassThrough;
|
|
47
30
|
stream.on("data", (data) => {
|
|
48
31
|
const { level, msg, error } = JSON.parse(String(data));
|
|
49
32
|
const levelLabel = levels.labels[level];
|
|
@@ -74,7 +57,7 @@ function createConsolaStream() {
|
|
|
74
57
|
});
|
|
75
58
|
return stream;
|
|
76
59
|
}
|
|
77
|
-
function serializeError(value, seen =
|
|
60
|
+
function serializeError(value, seen = new WeakSet) {
|
|
78
61
|
if (value instanceof Error) {
|
|
79
62
|
const base = {
|
|
80
63
|
name: value.name,
|
|
@@ -82,14 +65,12 @@ function serializeError(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
|
82
65
|
stack: value.stack
|
|
83
66
|
};
|
|
84
67
|
const cause = value.cause;
|
|
85
|
-
if (cause !==
|
|
68
|
+
if (cause !== undefined) {
|
|
86
69
|
base.cause = serializeError(cause, seen);
|
|
87
70
|
}
|
|
88
71
|
const extraEntries = Object.entries(value);
|
|
89
72
|
if (extraEntries.length > 0) {
|
|
90
|
-
base.details = Object.fromEntries(
|
|
91
|
-
extraEntries.map(([key, entryValue]) => [key, serializeError(entryValue, seen)])
|
|
92
|
-
);
|
|
73
|
+
base.details = Object.fromEntries(extraEntries.map(([key, entryValue]) => [key, serializeError(entryValue, seen)]));
|
|
93
74
|
}
|
|
94
75
|
return base;
|
|
95
76
|
}
|
|
@@ -108,9 +89,7 @@ function serializeError(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
|
108
89
|
message: String(value)
|
|
109
90
|
};
|
|
110
91
|
}
|
|
111
|
-
return Object.fromEntries(
|
|
112
|
-
entries.map(([key, entryValue]) => [key, serializeError(entryValue, seen)])
|
|
113
|
-
);
|
|
92
|
+
return Object.fromEntries(entries.map(([key, entryValue]) => [key, serializeError(entryValue, seen)]));
|
|
114
93
|
}
|
|
115
94
|
return {
|
|
116
95
|
type: typeof value,
|
|
@@ -124,11 +103,11 @@ function createBinTransformerPlugin(sourceFilePaths) {
|
|
|
124
103
|
logger.debug("created bin transformer plugin with filter: %s", filter);
|
|
125
104
|
return {
|
|
126
105
|
name: "bin-transformer",
|
|
127
|
-
setup(
|
|
128
|
-
|
|
106
|
+
setup(build) {
|
|
107
|
+
build.onLoad({ filter }, async (args) => {
|
|
129
108
|
const content = await readFile(args.path, "utf-8");
|
|
130
109
|
return {
|
|
131
|
-
contents: `#!/usr/bin/env
|
|
110
|
+
contents: `#!/usr/bin/env bun
|
|
132
111
|
|
|
133
112
|
${content}`,
|
|
134
113
|
loader: "ts"
|
|
@@ -137,27 +116,26 @@ ${content}`,
|
|
|
137
116
|
}
|
|
138
117
|
};
|
|
139
118
|
}
|
|
140
|
-
|
|
141
119
|
// src/shared/entry-points.ts
|
|
142
120
|
function extractEntryPoints(packageJson) {
|
|
143
|
-
const exports
|
|
121
|
+
const exports = packageJson.exports;
|
|
144
122
|
let bin = packageJson.bin;
|
|
145
|
-
if (!exports
|
|
123
|
+
if (!exports && !bin) {
|
|
146
124
|
logger.warn("no exports or bin found in package.json");
|
|
147
125
|
return {};
|
|
148
126
|
}
|
|
149
|
-
if (exports
|
|
127
|
+
if (exports !== undefined && (typeof exports !== "object" || Array.isArray(exports))) {
|
|
150
128
|
throw new Error("Exports field in package.json must be an object");
|
|
151
129
|
}
|
|
152
|
-
if (bin !==
|
|
130
|
+
if (bin !== undefined && typeof bin !== "object") {
|
|
153
131
|
if (!packageJson.name) {
|
|
154
132
|
throw new Error("Package name is required when bin is a string");
|
|
155
133
|
}
|
|
156
134
|
bin = { [packageJson.name]: bin };
|
|
157
135
|
}
|
|
158
136
|
const result = {};
|
|
159
|
-
if (exports
|
|
160
|
-
for (const [key, value] of Object.entries(exports
|
|
137
|
+
if (exports) {
|
|
138
|
+
for (const [key, value] of Object.entries(exports)) {
|
|
161
139
|
let distPath;
|
|
162
140
|
if (typeof value === "string") {
|
|
163
141
|
distPath = value;
|
|
@@ -175,14 +153,10 @@ function extractEntryPoints(packageJson) {
|
|
|
175
153
|
const isJsonExport = distPath.endsWith(".json");
|
|
176
154
|
const isJsExport = distPath.endsWith(".js");
|
|
177
155
|
if (!isJsonExport && !isJsExport) {
|
|
178
|
-
throw new Error(
|
|
179
|
-
`The default value of export "${key}" must end with ".js" or ".json" in package.json, got "${distPath}"`
|
|
180
|
-
);
|
|
156
|
+
throw new Error(`The default value of export "${key}" must end with ".js" or ".json" in package.json, got "${distPath}"`);
|
|
181
157
|
}
|
|
182
158
|
if (isJsExport && !distPath.startsWith("./dist/")) {
|
|
183
|
-
throw new Error(
|
|
184
|
-
`The default value of export "${key}" must start with "./dist/" when exporting ".js" in package.json, got "${distPath}"`
|
|
185
|
-
);
|
|
159
|
+
throw new Error(`The default value of export "${key}" must start with "./dist/" when exporting ".js" in package.json, got "${distPath}"`);
|
|
186
160
|
}
|
|
187
161
|
if (isJsonExport) {
|
|
188
162
|
continue;
|
|
@@ -204,14 +178,10 @@ function extractEntryPoints(packageJson) {
|
|
|
204
178
|
}
|
|
205
179
|
const distPath = value;
|
|
206
180
|
if (!distPath.startsWith("./dist/")) {
|
|
207
|
-
throw new Error(
|
|
208
|
-
`The value of bin entry "${key}" must start with "./dist/" in package.json, got "${distPath}"`
|
|
209
|
-
);
|
|
181
|
+
throw new Error(`The value of bin entry "${key}" must start with "./dist/" in package.json, got "${distPath}"`);
|
|
210
182
|
}
|
|
211
183
|
if (!distPath.endsWith(".js")) {
|
|
212
|
-
throw new Error(
|
|
213
|
-
`The value of bin entry "${key}" must end with ".js" in package.json, got "${distPath}"`
|
|
214
|
-
);
|
|
184
|
+
throw new Error(`The value of bin entry "${key}" must end with ".js" in package.json, got "${distPath}"`);
|
|
215
185
|
}
|
|
216
186
|
const targetName = distPath.slice(7).slice(0, -3);
|
|
217
187
|
result[targetName] = {
|
|
@@ -225,6 +195,10 @@ function extractEntryPoints(packageJson) {
|
|
|
225
195
|
}
|
|
226
196
|
return result;
|
|
227
197
|
}
|
|
198
|
+
// src/shared/generator.ts
|
|
199
|
+
import { mkdir, readdir, readFile as readFile2, stat, writeFile } from "fs/promises";
|
|
200
|
+
import { dirname, join, relative, resolve } from "path";
|
|
201
|
+
import Handlebars from "handlebars";
|
|
228
202
|
async function generateFromTemplate(templatePath, destinationPath, variables) {
|
|
229
203
|
const resolvedTemplatePath = resolve(templatePath);
|
|
230
204
|
const resolvedDestinationPath = resolve(destinationPath);
|
|
@@ -259,7 +233,7 @@ async function generateFromTemplate(templatePath, destinationPath, variables) {
|
|
|
259
233
|
const destinationRelativePath = relativeFilePath.replaceAll(".tpl", "");
|
|
260
234
|
const destinationFilePath = join(resolvedDestinationPath, destinationRelativePath);
|
|
261
235
|
await mkdir(dirname(destinationFilePath), { recursive: true });
|
|
262
|
-
const contents = await
|
|
236
|
+
const contents = await readFile2(absoluteSourcePath, "utf8");
|
|
263
237
|
const rendered = renderTemplate(contents);
|
|
264
238
|
if (rendered.trim().length === 0) {
|
|
265
239
|
return;
|
|
@@ -268,16 +242,13 @@ async function generateFromTemplate(templatePath, destinationPath, variables) {
|
|
|
268
242
|
};
|
|
269
243
|
await visit(resolvedTemplatePath);
|
|
270
244
|
}
|
|
271
|
-
|
|
272
245
|
// src/shared/npm-registry.ts
|
|
273
246
|
async function fetchNpmPackument(packageName) {
|
|
274
247
|
const encoded = encodeURIComponent(packageName);
|
|
275
248
|
const url = `https://registry.npmjs.org/${encoded}`;
|
|
276
249
|
const response = await fetch(url);
|
|
277
250
|
if (!response.ok) {
|
|
278
|
-
throw new Error(
|
|
279
|
-
`Failed to fetch package "${packageName}" from NPM registry (HTTP ${response.status})`
|
|
280
|
-
);
|
|
251
|
+
throw new Error(`Failed to fetch package "${packageName}" from NPM registry (HTTP ${response.status})`);
|
|
281
252
|
}
|
|
282
253
|
return await response.json();
|
|
283
254
|
}
|
|
@@ -285,9 +256,7 @@ async function fetchLatestVersion(packageName) {
|
|
|
285
256
|
const packument = await fetchNpmPackument(packageName);
|
|
286
257
|
const latest = packument["dist-tags"]?.latest;
|
|
287
258
|
if (!latest) {
|
|
288
|
-
throw new Error(
|
|
289
|
-
`NPM registry response for package "${packageName}" does not include "dist-tags.latest"`
|
|
290
|
-
);
|
|
259
|
+
throw new Error(`NPM registry response for package "${packageName}" does not include "dist-tags.latest"`);
|
|
291
260
|
}
|
|
292
261
|
return latest;
|
|
293
262
|
}
|
|
@@ -295,34 +264,22 @@ async function fetchManifest(packageName, version) {
|
|
|
295
264
|
const packument = await fetchNpmPackument(packageName);
|
|
296
265
|
const manifest = packument.versions?.[version];
|
|
297
266
|
if (!manifest) {
|
|
298
|
-
throw new Error(
|
|
299
|
-
`NPM registry response for package "${packageName}" does not include version "${version}"`
|
|
300
|
-
);
|
|
267
|
+
throw new Error(`NPM registry response for package "${packageName}" does not include version "${version}"`);
|
|
301
268
|
}
|
|
302
269
|
return manifest;
|
|
303
270
|
}
|
|
304
271
|
function getDependencyRange(manifest, dependencyName) {
|
|
305
272
|
return manifest.peerDependencies?.[dependencyName] ?? manifest.dependencies?.[dependencyName] ?? manifest.optionalDependencies?.[dependencyName] ?? null;
|
|
306
273
|
}
|
|
274
|
+
// src/shared/overrides.ts
|
|
275
|
+
import { readPackageJSON, resolvePackageJSON } from "pkg-types";
|
|
276
|
+
|
|
277
|
+
// src/shared/package-json.ts
|
|
278
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
307
279
|
async function writeJsonFile(filePath, value) {
|
|
308
280
|
const contents = `${JSON.stringify(value, null, 2)}
|
|
309
281
|
`;
|
|
310
|
-
await
|
|
311
|
-
}
|
|
312
|
-
function resolvePnpmWorkspacePath(projectRoot) {
|
|
313
|
-
return resolve(projectRoot, "pnpm-workspace.yaml");
|
|
314
|
-
}
|
|
315
|
-
async function readPnpmWorkspace(filePath) {
|
|
316
|
-
const raw = await readFile(filePath, "utf8");
|
|
317
|
-
const parsed = parse(raw);
|
|
318
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
319
|
-
return {};
|
|
320
|
-
}
|
|
321
|
-
return parsed;
|
|
322
|
-
}
|
|
323
|
-
async function writePnpmWorkspace(filePath, workspace) {
|
|
324
|
-
const raw = stringify(workspace);
|
|
325
|
-
await writeFile(filePath, raw, "utf8");
|
|
282
|
+
await writeFile2(filePath, contents, "utf8");
|
|
326
283
|
}
|
|
327
284
|
|
|
328
285
|
// src/shared/version-sets.ts
|
|
@@ -373,92 +330,46 @@ function buildOverrides(bundle) {
|
|
|
373
330
|
return merged;
|
|
374
331
|
}
|
|
375
332
|
async function applyOverrides(args) {
|
|
376
|
-
const {
|
|
377
|
-
if (packageManager === "pnpm") {
|
|
378
|
-
const pnpmWorkspacePath = resolvePnpmWorkspacePath(projectRoot);
|
|
379
|
-
try {
|
|
380
|
-
await access(pnpmWorkspacePath);
|
|
381
|
-
} catch {
|
|
382
|
-
throw new Error(`PNPM workspace file is missing: "${pnpmWorkspacePath}"`);
|
|
383
|
-
}
|
|
384
|
-
const workspace = await readPnpmWorkspace(pnpmWorkspacePath);
|
|
385
|
-
const nextWorkspace = {
|
|
386
|
-
...workspace,
|
|
387
|
-
overrides
|
|
388
|
-
};
|
|
389
|
-
await writePnpmWorkspace(pnpmWorkspacePath, nextWorkspace);
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
333
|
+
const { overrides, projectRoot } = args;
|
|
392
334
|
const packageJsonPath = await resolvePackageJSON(projectRoot);
|
|
393
335
|
const packageJson = await readPackageJSON(projectRoot);
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
});
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
if (packageManager === "yarn") {
|
|
402
|
-
await writeJsonFile(packageJsonPath, {
|
|
403
|
-
...packageJson,
|
|
404
|
-
resolutions: overrides
|
|
405
|
-
});
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
await writeJsonFile(packageJsonPath, packageJson);
|
|
336
|
+
await writeJsonFile(packageJsonPath, {
|
|
337
|
+
...packageJson,
|
|
338
|
+
overrides
|
|
339
|
+
});
|
|
409
340
|
}
|
|
341
|
+
// src/shared/project-versions.ts
|
|
342
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
343
|
+
import { resolvePackageJSON as resolvePackageJSON2 } from "pkg-types";
|
|
410
344
|
async function getProjectOverrideVersion(projectRoot, args) {
|
|
411
|
-
const {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const workspace = await readPnpmWorkspace(path);
|
|
415
|
-
return workspace.overrides?.[packageName] ?? null;
|
|
416
|
-
}
|
|
417
|
-
const packageJsonPath = await resolvePackageJSON(projectRoot);
|
|
418
|
-
const rawPackageJson = await readFile(packageJsonPath, "utf8");
|
|
345
|
+
const { packageName } = args;
|
|
346
|
+
const packageJsonPath = await resolvePackageJSON2(projectRoot);
|
|
347
|
+
const rawPackageJson = await readFile3(packageJsonPath, "utf8");
|
|
419
348
|
const packageJson = JSON.parse(rawPackageJson);
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return overrides?.[packageName] ?? null;
|
|
423
|
-
}
|
|
424
|
-
if (packageManager === "yarn") {
|
|
425
|
-
const resolutions = packageJson.resolutions;
|
|
426
|
-
return resolutions?.[packageName] ?? null;
|
|
427
|
-
}
|
|
428
|
-
return null;
|
|
349
|
+
const overrides = packageJson.overrides;
|
|
350
|
+
return overrides?.[packageName] ?? null;
|
|
429
351
|
}
|
|
430
|
-
async function getProjectPlatformVersion(projectRoot
|
|
352
|
+
async function getProjectPlatformVersion(projectRoot) {
|
|
431
353
|
return await getProjectOverrideVersion(projectRoot, {
|
|
432
|
-
packageManager: args.packageManager,
|
|
433
354
|
packageName: "@highstate/pulumi"
|
|
434
355
|
});
|
|
435
356
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
packageName: "@pulumi/pulumi"
|
|
440
|
-
});
|
|
441
|
-
}
|
|
357
|
+
// src/shared/pulumi-cli.ts
|
|
358
|
+
import { execFile } from "child_process";
|
|
359
|
+
import { promisify } from "util";
|
|
442
360
|
var execFileAsync = promisify(execFile);
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return null;
|
|
451
|
-
}
|
|
452
|
-
return raw.startsWith("v") ? raw.slice(1) : raw;
|
|
453
|
-
} catch {
|
|
454
|
-
return null;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
361
|
+
// src/shared/schema-transformer.ts
|
|
362
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
363
|
+
import MagicString from "magic-string";
|
|
364
|
+
import {
|
|
365
|
+
parseAsync
|
|
366
|
+
} from "oxc-parser";
|
|
367
|
+
import { walk } from "oxc-walker";
|
|
457
368
|
var schemaTransformerPlugin = {
|
|
458
369
|
name: "schema-transformer",
|
|
459
|
-
setup(
|
|
460
|
-
|
|
461
|
-
const content = await
|
|
370
|
+
setup(build) {
|
|
371
|
+
build.onLoad({ filter: /src\/.*\.ts$/ }, async (args) => {
|
|
372
|
+
const content = await readFile4(args.path, "utf-8");
|
|
462
373
|
return {
|
|
463
374
|
contents: await applySchemaTransformations(content),
|
|
464
375
|
loader: "ts"
|
|
@@ -518,7 +429,8 @@ async function applyZodMetaTransformations(content) {
|
|
|
518
429
|
});
|
|
519
430
|
let finalResult = result.toString();
|
|
520
431
|
if (hasTransformations && !content.includes("__camelCaseToHumanReadable")) {
|
|
521
|
-
finalResult =
|
|
432
|
+
finalResult = `import { camelCaseToHumanReadable as __camelCaseToHumanReadable } from "@highstate/contract"
|
|
433
|
+
` + finalResult;
|
|
522
434
|
}
|
|
523
435
|
return finalResult;
|
|
524
436
|
}
|
|
@@ -542,10 +454,7 @@ async function applyHelperFunctionTransformations(content) {
|
|
|
542
454
|
if (!returnArgument) {
|
|
543
455
|
return;
|
|
544
456
|
}
|
|
545
|
-
const originalReturnValue = content.substring(
|
|
546
|
-
returnArgument.start,
|
|
547
|
-
returnArgument.end
|
|
548
|
-
);
|
|
457
|
+
const originalReturnValue = content.substring(returnArgument.start, returnArgument.end);
|
|
549
458
|
if (originalReturnValue.trimStart().startsWith(`${helperFunction}(`)) {
|
|
550
459
|
return;
|
|
551
460
|
}
|
|
@@ -557,10 +466,7 @@ async function applyHelperFunctionTransformations(content) {
|
|
|
557
466
|
if (!hasValue(propertyNode) || !hasSourceRange(propertyNode.value)) {
|
|
558
467
|
return;
|
|
559
468
|
}
|
|
560
|
-
const originalValue = content.substring(
|
|
561
|
-
propertyNode.value.start,
|
|
562
|
-
propertyNode.value.end
|
|
563
|
-
);
|
|
469
|
+
const originalValue = content.substring(propertyNode.value.start, propertyNode.value.end);
|
|
564
470
|
const newValue = `${helperFunction}(${originalValue}, \`${description}\`)`;
|
|
565
471
|
result.update(propertyNode.value.start, propertyNode.value.end, newValue);
|
|
566
472
|
hasTransformations = true;
|
|
@@ -574,7 +480,8 @@ async function applyHelperFunctionTransformations(content) {
|
|
|
574
480
|
});
|
|
575
481
|
let finalResult = result.toString();
|
|
576
482
|
if (hasTransformations && !content.includes("$addArgumentDescription")) {
|
|
577
|
-
finalResult =
|
|
483
|
+
finalResult = `import { $addArgumentDescription, $addInputDescription } from "@highstate/contract"
|
|
484
|
+
` + finalResult;
|
|
578
485
|
}
|
|
579
486
|
return finalResult;
|
|
580
487
|
}
|
|
@@ -588,7 +495,7 @@ async function applyDefineFunctionMetaTransformations(content) {
|
|
|
588
495
|
if (node.type === "CallExpression" && "callee" in node && node.callee.type === "Identifier") {
|
|
589
496
|
const callNode = node;
|
|
590
497
|
const callee = callNode.callee;
|
|
591
|
-
const functionName = "name" in callee && typeof callee.name === "string" ? callee.name :
|
|
498
|
+
const functionName = "name" in callee && typeof callee.name === "string" ? callee.name : undefined;
|
|
592
499
|
if (functionName && ["defineUnit", "defineEntity", "defineComponent"].includes(functionName)) {
|
|
593
500
|
const jsdoc = findJsdocForDefineFunction(content, parentStack, comments);
|
|
594
501
|
if (jsdoc && callNode.arguments && callNode.arguments.length > 0) {
|
|
@@ -596,14 +503,9 @@ async function applyDefineFunctionMetaTransformations(content) {
|
|
|
596
503
|
const firstArg = callNode.arguments[0];
|
|
597
504
|
if (firstArg.type === "ObjectExpression" && "properties" in firstArg) {
|
|
598
505
|
const properties = firstArg.properties;
|
|
599
|
-
const metaProperty = properties?.find(
|
|
600
|
-
(prop) => prop.type === "Property" && "key" in prop && prop.key?.type === "Identifier" && prop.key?.name === "meta"
|
|
601
|
-
);
|
|
506
|
+
const metaProperty = properties?.find((prop) => prop.type === "Property" && ("key" in prop) && prop.key?.type === "Identifier" && prop.key?.name === "meta");
|
|
602
507
|
if (metaProperty && "value" in metaProperty) {
|
|
603
|
-
const originalMetaValue = content.substring(
|
|
604
|
-
metaProperty.value.start,
|
|
605
|
-
metaProperty.value.end
|
|
606
|
-
);
|
|
508
|
+
const originalMetaValue = content.substring(metaProperty.value.start, metaProperty.value.end);
|
|
607
509
|
const newMetaValue = injectDescriptionIntoMetaObject(originalMetaValue, description);
|
|
608
510
|
result.update(metaProperty.value.start, metaProperty.value.end, newMetaValue);
|
|
609
511
|
} else if (properties && properties.length > 0) {
|
|
@@ -630,19 +532,22 @@ async function applyDefineFunctionMetaTransformations(content) {
|
|
|
630
532
|
return result.toString();
|
|
631
533
|
}
|
|
632
534
|
function findJsdocForDefineFunction(content, parentStack, comments) {
|
|
633
|
-
for (let i = parentStack.length - 1;
|
|
535
|
+
for (let i = parentStack.length - 1;i >= 0; i--) {
|
|
634
536
|
const node = parentStack[i];
|
|
635
537
|
if (node.type === "VariableDeclarator" && "id" in node && node.id?.type === "Identifier") {
|
|
636
538
|
const jsdoc = findLeadingComment(content, node, comments);
|
|
637
|
-
if (jsdoc)
|
|
539
|
+
if (jsdoc)
|
|
540
|
+
return jsdoc;
|
|
638
541
|
}
|
|
639
542
|
if (node.type === "VariableDeclaration") {
|
|
640
543
|
const jsdoc = findLeadingComment(content, node, comments);
|
|
641
|
-
if (jsdoc)
|
|
544
|
+
if (jsdoc)
|
|
545
|
+
return jsdoc;
|
|
642
546
|
}
|
|
643
547
|
if (node.type === "ExportNamedDeclaration" && "declaration" in node && node.declaration) {
|
|
644
548
|
const jsdoc = findLeadingComment(content, node, comments);
|
|
645
|
-
if (jsdoc)
|
|
549
|
+
if (jsdoc)
|
|
550
|
+
return jsdoc;
|
|
646
551
|
}
|
|
647
552
|
}
|
|
648
553
|
return null;
|
|
@@ -714,7 +619,7 @@ function injectDescriptionIntoMetaObject(objectString, description) {
|
|
|
714
619
|
}
|
|
715
620
|
}
|
|
716
621
|
function isInsideZodObject(parentStack) {
|
|
717
|
-
for (let i = parentStack.length - 1;
|
|
622
|
+
for (let i = parentStack.length - 1;i >= 0; i--) {
|
|
718
623
|
const node = parentStack[i];
|
|
719
624
|
if (node.type === "CallExpression" && "callee" in node && node.callee.type === "MemberExpression" && isZodObjectCall(node.callee)) {
|
|
720
625
|
return true;
|
|
@@ -759,7 +664,7 @@ function getHelperFunctionForProperty(parentStack) {
|
|
|
759
664
|
return null;
|
|
760
665
|
}
|
|
761
666
|
function isDefinitionLikeContext(parentStack) {
|
|
762
|
-
for (let i = parentStack.length - 1;
|
|
667
|
+
for (let i = parentStack.length - 1;i >= 0; i--) {
|
|
763
668
|
const node = parentStack[i];
|
|
764
669
|
if (node.type !== "CallExpression") {
|
|
765
670
|
continue;
|
|
@@ -807,6 +712,8 @@ function startsWithZodCall(callExpression) {
|
|
|
807
712
|
}
|
|
808
713
|
return false;
|
|
809
714
|
}
|
|
715
|
+
// src/shared/schemas.ts
|
|
716
|
+
import { z } from "zod";
|
|
810
717
|
var sourceHashConfigSchema = z.discriminatedUnion("mode", [
|
|
811
718
|
z.object({
|
|
812
719
|
mode: z.literal("manual"),
|
|
@@ -829,7 +736,6 @@ var highstateConfigSchema = z.object({
|
|
|
829
736
|
var highstateManifestSchema = z.object({
|
|
830
737
|
sourceHashes: z.record(z.string(), z.number()).optional()
|
|
831
738
|
});
|
|
832
|
-
|
|
833
739
|
// src/shared/services.ts
|
|
834
740
|
var services;
|
|
835
741
|
var disposePromise;
|
|
@@ -837,7 +743,7 @@ function getBackendServices() {
|
|
|
837
743
|
if (services) {
|
|
838
744
|
return services;
|
|
839
745
|
}
|
|
840
|
-
services = import(
|
|
746
|
+
services = import("@highstate/backend").then(({ getSharedServices }) => {
|
|
841
747
|
return getSharedServices({
|
|
842
748
|
services: {
|
|
843
749
|
logger: logger.child({}, { msgPrefix: "[backend] " })
|
|
@@ -853,9 +759,18 @@ function disposeServices() {
|
|
|
853
759
|
if (disposePromise) {
|
|
854
760
|
return disposePromise;
|
|
855
761
|
}
|
|
856
|
-
disposePromise = import(
|
|
762
|
+
disposePromise = import("@highstate/backend").then(({ disposeServices: disposeServices2 }) => services.then((s) => disposeServices2(s)));
|
|
857
763
|
return disposePromise;
|
|
858
764
|
}
|
|
765
|
+
// src/shared/source-hash-calculator.ts
|
|
766
|
+
import { readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
767
|
+
import { builtinModules } from "module";
|
|
768
|
+
import { dirname as dirname2, isAbsolute, relative as relative2, resolve as resolve2 } from "path";
|
|
769
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
770
|
+
import { crc32 } from "@aws-crypto/crc32";
|
|
771
|
+
import { resolve as importMetaResolve } from "import-meta-resolve";
|
|
772
|
+
import { readPackageJSON as readPackageJSON2, resolvePackageJSON as resolvePackageJSON3 } from "pkg-types";
|
|
773
|
+
import { z as z2 } from "zod";
|
|
859
774
|
function parseFileDependencies(filePath, content) {
|
|
860
775
|
const dependencyRegex = /^[ \t]*import\b[\s\S]*?\bfrom\s*["']((?<relativePath>\.\.?\/[^"']+)|(?<nodeBuiltin>node:[^"']+)|(?<npmPackage>[^"']+))["']/gm;
|
|
861
776
|
const matches = content.matchAll(dependencyRegex);
|
|
@@ -863,39 +778,42 @@ function parseFileDependencies(filePath, content) {
|
|
|
863
778
|
for (const match of matches) {
|
|
864
779
|
const { nodeBuiltin, npmPackage, relativePath } = match.groups;
|
|
865
780
|
if (relativePath) {
|
|
866
|
-
const fullPath =
|
|
781
|
+
const fullPath = resolve2(dirname2(filePath), relativePath);
|
|
867
782
|
dependencies.push({
|
|
868
783
|
type: "relative",
|
|
869
784
|
id: `relative:${fullPath}`,
|
|
870
785
|
fullPath
|
|
871
786
|
});
|
|
872
787
|
} else if (npmPackage) {
|
|
788
|
+
const normalizedPackageName = npmPackage.startsWith("node:") ? npmPackage.slice("node:".length) : npmPackage;
|
|
789
|
+
const builtinName = normalizedPackageName.split("/")[0];
|
|
790
|
+
if (builtinModules.includes(normalizedPackageName) || builtinModules.includes(builtinName) || builtinModules.includes(`node:${normalizedPackageName}`) || builtinModules.includes(`node:${builtinName}`)) {
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
873
793
|
dependencies.push({
|
|
874
794
|
type: "npm",
|
|
875
795
|
id: `npm:${npmPackage}`,
|
|
876
796
|
package: npmPackage
|
|
877
797
|
});
|
|
878
|
-
} else
|
|
798
|
+
} else if (nodeBuiltin) {}
|
|
879
799
|
}
|
|
880
800
|
return dependencies;
|
|
881
801
|
}
|
|
882
|
-
|
|
802
|
+
|
|
803
|
+
class SourceHashCalculator {
|
|
804
|
+
packageJsonPath;
|
|
805
|
+
packageJson;
|
|
806
|
+
logger;
|
|
807
|
+
dependencyHashes = new Map;
|
|
808
|
+
fileHashes = new Map;
|
|
883
809
|
constructor(packageJsonPath, packageJson, logger2) {
|
|
884
810
|
this.packageJsonPath = packageJsonPath;
|
|
885
811
|
this.packageJson = packageJson;
|
|
886
812
|
this.logger = logger2;
|
|
887
813
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
* Calculates CRC32 hash of a string.
|
|
892
|
-
*/
|
|
893
|
-
hashString(input3) {
|
|
894
|
-
return crc32(Buffer.from(input3));
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* Gets the highstate configuration from package.json with defaults.
|
|
898
|
-
*/
|
|
814
|
+
hashString(input) {
|
|
815
|
+
return crc32(Buffer.from(input));
|
|
816
|
+
}
|
|
899
817
|
getHighstateConfig(packageJson) {
|
|
900
818
|
const rawConfig = packageJson.highstate;
|
|
901
819
|
if (!rawConfig) {
|
|
@@ -904,23 +822,17 @@ var SourceHashCalculator = class {
|
|
|
904
822
|
try {
|
|
905
823
|
return highstateConfigSchema.parse(rawConfig);
|
|
906
824
|
} catch (error) {
|
|
907
|
-
this.logger.warn(
|
|
908
|
-
{ error, packageName: packageJson.name },
|
|
909
|
-
"invalid highstate configuration, using defaults"
|
|
910
|
-
);
|
|
825
|
+
this.logger.warn({ error, packageName: packageJson.name }, "invalid highstate configuration, using defaults");
|
|
911
826
|
return { type: "source" };
|
|
912
827
|
}
|
|
913
828
|
}
|
|
914
|
-
/**
|
|
915
|
-
* Gets the effective source hash configuration with defaults for a specific output.
|
|
916
|
-
*/
|
|
917
829
|
getSourceHashConfig(highstateConfig, exportKey) {
|
|
918
830
|
if (highstateConfig.sourceHash) {
|
|
919
831
|
const singleConfigResult = sourceHashConfigSchema.safeParse(highstateConfig.sourceHash);
|
|
920
832
|
if (singleConfigResult.success) {
|
|
921
833
|
return singleConfigResult.data;
|
|
922
834
|
}
|
|
923
|
-
const recordConfigResult =
|
|
835
|
+
const recordConfigResult = z2.record(z2.string(), sourceHashConfigSchema).safeParse(highstateConfig.sourceHash);
|
|
924
836
|
if (recordConfigResult.success && exportKey) {
|
|
925
837
|
const perOutputConfig = recordConfigResult.data[exportKey];
|
|
926
838
|
if (perOutputConfig) {
|
|
@@ -937,40 +849,32 @@ var SourceHashCalculator = class {
|
|
|
937
849
|
const highstateConfig = this.getHighstateConfig(this.packageJson);
|
|
938
850
|
const promises = [];
|
|
939
851
|
for (const [distPath, exportKey] of distPathToExportKey) {
|
|
940
|
-
const fullPath =
|
|
852
|
+
const fullPath = resolve2(distPath);
|
|
941
853
|
const sourceHashConfig = this.getSourceHashConfig(highstateConfig, exportKey);
|
|
942
854
|
switch (sourceHashConfig.mode) {
|
|
943
855
|
case "manual":
|
|
944
|
-
promises.push(
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
})
|
|
949
|
-
);
|
|
856
|
+
promises.push(Promise.resolve({
|
|
857
|
+
distPath,
|
|
858
|
+
hash: this.hashString(sourceHashConfig.version)
|
|
859
|
+
}));
|
|
950
860
|
break;
|
|
951
861
|
case "version":
|
|
952
|
-
promises.push(
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
})
|
|
957
|
-
);
|
|
862
|
+
promises.push(Promise.resolve({
|
|
863
|
+
distPath,
|
|
864
|
+
hash: this.hashString(this.packageJson.version ?? "")
|
|
865
|
+
}));
|
|
958
866
|
break;
|
|
959
867
|
case "none":
|
|
960
|
-
promises.push(
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
})
|
|
965
|
-
);
|
|
868
|
+
promises.push(Promise.resolve({
|
|
869
|
+
distPath,
|
|
870
|
+
hash: 0
|
|
871
|
+
}));
|
|
966
872
|
break;
|
|
967
873
|
default:
|
|
968
|
-
promises.push(
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
}))
|
|
973
|
-
);
|
|
874
|
+
promises.push(this.getFileHash(fullPath).then((hash) => ({
|
|
875
|
+
distPath,
|
|
876
|
+
hash
|
|
877
|
+
})));
|
|
974
878
|
break;
|
|
975
879
|
}
|
|
976
880
|
}
|
|
@@ -981,8 +885,8 @@ var SourceHashCalculator = class {
|
|
|
981
885
|
for (const { distPath, hash } of hashes) {
|
|
982
886
|
manifest.sourceHashes[distPath] = hash;
|
|
983
887
|
}
|
|
984
|
-
const manifestPath =
|
|
985
|
-
await
|
|
888
|
+
const manifestPath = resolve2(distBasePath, "highstate.manifest.json");
|
|
889
|
+
await writeFile3(manifestPath, JSON.stringify(manifest, null, 2), "utf8");
|
|
986
890
|
}
|
|
987
891
|
async getFileHash(fullPath) {
|
|
988
892
|
const existingHash = this.fileHashes.get(fullPath);
|
|
@@ -994,7 +898,7 @@ var SourceHashCalculator = class {
|
|
|
994
898
|
return hash;
|
|
995
899
|
}
|
|
996
900
|
async calculateFileHash(fullPath) {
|
|
997
|
-
const content = await
|
|
901
|
+
const content = await readFile5(fullPath, "utf8");
|
|
998
902
|
const fileDeps = parseFileDependencies(fullPath, content);
|
|
999
903
|
const hashes = await Promise.all([
|
|
1000
904
|
this.hashString(content),
|
|
@@ -1020,39 +924,32 @@ var SourceHashCalculator = class {
|
|
|
1020
924
|
let resolvedUrl;
|
|
1021
925
|
try {
|
|
1022
926
|
const baseUrl = pathToFileURL(this.packageJsonPath);
|
|
1023
|
-
resolvedUrl =
|
|
927
|
+
resolvedUrl = importMetaResolve(dependency.package, baseUrl.toString());
|
|
1024
928
|
} catch (error) {
|
|
1025
929
|
this.logger.error(`failed to resolve package "%s"`, dependency.package);
|
|
1026
930
|
throw error;
|
|
1027
931
|
}
|
|
1028
|
-
const resolvedPath =
|
|
932
|
+
const resolvedPath = this.resolveDependencyPath(dependency.package, resolvedUrl);
|
|
933
|
+
if (!resolvedPath) {
|
|
934
|
+
this.logger.debug(`using package version as a fallback hash for "%s" due to unsupported resolver output "%s"`, dependency.package, resolvedUrl);
|
|
935
|
+
const [, depPackageJson2] = await this.getPackageJsonFromPackageName(dependency.package);
|
|
936
|
+
return this.hashString(depPackageJson2.version ?? "0.0.0");
|
|
937
|
+
}
|
|
1029
938
|
const [depPackageJsonPath, depPackageJson] = await this.getPackageJson(resolvedPath);
|
|
1030
939
|
const packageName = depPackageJson.name;
|
|
1031
|
-
this.logger.debug(
|
|
1032
|
-
`resolved package.json for "%s": "%s"`,
|
|
1033
|
-
dependency.package,
|
|
1034
|
-
depPackageJsonPath
|
|
1035
|
-
);
|
|
940
|
+
this.logger.debug(`resolved package.json for "%s": "%s"`, dependency.package, depPackageJsonPath);
|
|
1036
941
|
if (!this.packageJson.dependencies?.[packageName] && !this.packageJson.peerDependencies?.[packageName]) {
|
|
1037
942
|
this.logger.warn(`package "%s" is not listed in package.json dependencies`, packageName);
|
|
1038
943
|
}
|
|
1039
|
-
let relativePath =
|
|
944
|
+
let relativePath = relative2(dirname2(depPackageJsonPath), resolvedPath);
|
|
1040
945
|
relativePath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
1041
|
-
const highstateManifestPath =
|
|
1042
|
-
dirname(depPackageJsonPath),
|
|
1043
|
-
"dist",
|
|
1044
|
-
"highstate.manifest.json"
|
|
1045
|
-
);
|
|
946
|
+
const highstateManifestPath = resolve2(dirname2(depPackageJsonPath), "dist", "highstate.manifest.json");
|
|
1046
947
|
let manifest;
|
|
1047
948
|
try {
|
|
1048
|
-
const manifestContent = await
|
|
949
|
+
const manifestContent = await readFile5(highstateManifestPath, "utf8");
|
|
1049
950
|
manifest = highstateManifestSchema.parse(JSON.parse(manifestContent));
|
|
1050
951
|
} catch (error) {
|
|
1051
|
-
this.logger.debug(
|
|
1052
|
-
{ error },
|
|
1053
|
-
`failed to read highstate manifest for package "%s"`,
|
|
1054
|
-
packageName
|
|
1055
|
-
);
|
|
952
|
+
this.logger.debug({ error }, `failed to read highstate manifest for package "%s"`, packageName);
|
|
1056
953
|
}
|
|
1057
954
|
const sourceHash = manifest?.sourceHashes?.[relativePath];
|
|
1058
955
|
if (sourceHash) {
|
|
@@ -1064,18 +961,38 @@ var SourceHashCalculator = class {
|
|
|
1064
961
|
}
|
|
1065
962
|
}
|
|
1066
963
|
}
|
|
964
|
+
resolveDependencyPath(packageName, resolvedUrl) {
|
|
965
|
+
if (resolvedUrl.startsWith("file:")) {
|
|
966
|
+
return fileURLToPath(resolvedUrl);
|
|
967
|
+
}
|
|
968
|
+
if (isAbsolute(resolvedUrl)) {
|
|
969
|
+
return resolvedUrl;
|
|
970
|
+
}
|
|
971
|
+
if (resolvedUrl.startsWith("node:")) {
|
|
972
|
+
return null;
|
|
973
|
+
}
|
|
974
|
+
if (resolvedUrl.includes(":")) {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
const baseDir = dirname2(this.packageJsonPath);
|
|
978
|
+
return resolve2(baseDir, "node_modules", packageName);
|
|
979
|
+
}
|
|
980
|
+
async getPackageJsonFromPackageName(packageName) {
|
|
981
|
+
const baseDir = dirname2(this.packageJsonPath);
|
|
982
|
+
const packagePath = resolve2(baseDir, "node_modules", packageName);
|
|
983
|
+
return await this.getPackageJson(packagePath);
|
|
984
|
+
}
|
|
1067
985
|
async getPackageJson(basePath) {
|
|
1068
986
|
while (true) {
|
|
1069
|
-
const packageJson = await
|
|
987
|
+
const packageJson = await readPackageJSON2(basePath);
|
|
1070
988
|
if (packageJson.name) {
|
|
1071
|
-
const packageJsonPath = await
|
|
989
|
+
const packageJsonPath = await resolvePackageJSON3(basePath);
|
|
1072
990
|
return [packageJsonPath, packageJson];
|
|
1073
991
|
}
|
|
1074
|
-
basePath =
|
|
992
|
+
basePath = resolve2(dirname2(basePath), "..");
|
|
1075
993
|
}
|
|
1076
994
|
}
|
|
1077
|
-
}
|
|
1078
|
-
|
|
995
|
+
}
|
|
1079
996
|
// src/shared/version-bundle.ts
|
|
1080
997
|
var platformSourcePackage = "@highstate/pulumi";
|
|
1081
998
|
var stdlibSourcePackage = "@highstate/library";
|
|
@@ -1087,9 +1004,7 @@ async function resolveVersionBundle(args) {
|
|
|
1087
1004
|
const platformManifest = await fetchManifest(platformSourcePackage, resolvedPlatformVersion);
|
|
1088
1005
|
const inferredPulumi = getDependencyRange(platformManifest, "@pulumi/pulumi");
|
|
1089
1006
|
if (!inferredPulumi) {
|
|
1090
|
-
throw new Error(
|
|
1091
|
-
`Unable to infer "@pulumi/pulumi" version from "${platformSourcePackage}@${resolvedPlatformVersion}"`
|
|
1092
|
-
);
|
|
1007
|
+
throw new Error(`Unable to infer "@pulumi/pulumi" version from "${platformSourcePackage}@${resolvedPlatformVersion}"`);
|
|
1093
1008
|
}
|
|
1094
1009
|
return {
|
|
1095
1010
|
platformVersion: resolvedPlatformVersion,
|
|
@@ -1098,8 +1013,8 @@ async function resolveVersionBundle(args) {
|
|
|
1098
1013
|
};
|
|
1099
1014
|
}
|
|
1100
1015
|
function normalizeProvidedVersion(value, label) {
|
|
1101
|
-
if (value ===
|
|
1102
|
-
return
|
|
1016
|
+
if (value === undefined) {
|
|
1017
|
+
return;
|
|
1103
1018
|
}
|
|
1104
1019
|
const trimmed = value.trim();
|
|
1105
1020
|
if (trimmed.length === 0) {
|
|
@@ -1107,12 +1022,17 @@ function normalizeProvidedVersion(value, label) {
|
|
|
1107
1022
|
}
|
|
1108
1023
|
return trimmed;
|
|
1109
1024
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1025
|
+
// src/shared/workspace.ts
|
|
1026
|
+
import { existsSync } from "fs";
|
|
1027
|
+
import { mkdir as mkdir2, readdir as readdir2, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
|
|
1028
|
+
import { join as join2, relative as relative3, resolve as resolve3 } from "path";
|
|
1029
|
+
import { z as z3 } from "zod";
|
|
1030
|
+
var packageJsonSchema = z3.object({
|
|
1031
|
+
name: z3.string(),
|
|
1112
1032
|
highstate: highstateConfigSchema.optional()
|
|
1113
1033
|
});
|
|
1114
1034
|
function generateTsconfigContent(workspaceRoot, packagePath) {
|
|
1115
|
-
const relativePath =
|
|
1035
|
+
const relativePath = relative3(workspaceRoot, packagePath);
|
|
1116
1036
|
const depth = relativePath.split("/").length;
|
|
1117
1037
|
const relativeNodeModules = `${"../".repeat(depth)}node_modules/@highstate/cli/assets/tsconfig.base.json`;
|
|
1118
1038
|
return {
|
|
@@ -1121,49 +1041,50 @@ function generateTsconfigContent(workspaceRoot, packagePath) {
|
|
|
1121
1041
|
};
|
|
1122
1042
|
}
|
|
1123
1043
|
async function findWorkspaceRoot(startPath = process.cwd()) {
|
|
1124
|
-
let currentPath =
|
|
1044
|
+
let currentPath = resolve3(startPath);
|
|
1125
1045
|
while (currentPath !== "/") {
|
|
1126
|
-
const packageJsonPath =
|
|
1046
|
+
const packageJsonPath = join2(currentPath, "package.json");
|
|
1127
1047
|
if (existsSync(packageJsonPath)) {
|
|
1128
1048
|
try {
|
|
1129
|
-
const content = await
|
|
1049
|
+
const content = await readFile6(packageJsonPath, "utf-8");
|
|
1130
1050
|
const packageJson = JSON.parse(content);
|
|
1131
1051
|
if (packageJson.workspaces) {
|
|
1132
1052
|
return currentPath;
|
|
1133
1053
|
}
|
|
1134
|
-
} catch {
|
|
1135
|
-
}
|
|
1054
|
+
} catch {}
|
|
1136
1055
|
}
|
|
1137
|
-
const parentPath =
|
|
1138
|
-
if (parentPath === currentPath)
|
|
1056
|
+
const parentPath = resolve3(currentPath, "..");
|
|
1057
|
+
if (parentPath === currentPath)
|
|
1058
|
+
break;
|
|
1139
1059
|
currentPath = parentPath;
|
|
1140
1060
|
}
|
|
1141
1061
|
throw new Error("Could not find workspace root (no package.json with workspaces found)");
|
|
1142
1062
|
}
|
|
1143
1063
|
async function scanWorkspacePackages(workspaceRoot) {
|
|
1144
1064
|
const packages = [];
|
|
1145
|
-
const packagesDir =
|
|
1065
|
+
const packagesDir = join2(workspaceRoot, "packages");
|
|
1146
1066
|
if (!existsSync(packagesDir)) {
|
|
1147
1067
|
return packages;
|
|
1148
1068
|
}
|
|
1149
1069
|
async function scanDirectory(dirPath, depth = 0) {
|
|
1150
|
-
const dirName =
|
|
1070
|
+
const dirName = relative3(packagesDir, dirPath).split("/").pop();
|
|
1151
1071
|
if (dirName?.startsWith(".") || dirName === "node_modules") {
|
|
1152
1072
|
return;
|
|
1153
1073
|
}
|
|
1154
|
-
const entries = await
|
|
1074
|
+
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
1155
1075
|
for (const entry of entries) {
|
|
1156
|
-
if (!entry.isDirectory())
|
|
1157
|
-
|
|
1076
|
+
if (!entry.isDirectory())
|
|
1077
|
+
continue;
|
|
1078
|
+
const entryPath = join2(dirPath, entry.name);
|
|
1158
1079
|
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
1159
1080
|
continue;
|
|
1160
1081
|
}
|
|
1161
|
-
const packageJsonPath =
|
|
1082
|
+
const packageJsonPath = join2(entryPath, "package.json");
|
|
1162
1083
|
if (existsSync(packageJsonPath)) {
|
|
1163
1084
|
try {
|
|
1164
|
-
const content = await
|
|
1085
|
+
const content = await readFile6(packageJsonPath, "utf-8");
|
|
1165
1086
|
const packageJson = packageJsonSchema.parse(JSON.parse(content));
|
|
1166
|
-
const relativePath =
|
|
1087
|
+
const relativePath = relative3(workspaceRoot, entryPath);
|
|
1167
1088
|
const type = packageJson.highstate?.type ?? "source";
|
|
1168
1089
|
packages.push({
|
|
1169
1090
|
path: entryPath,
|
|
@@ -1171,8 +1092,7 @@ async function scanWorkspacePackages(workspaceRoot) {
|
|
|
1171
1092
|
name: packageJson.name,
|
|
1172
1093
|
type
|
|
1173
1094
|
});
|
|
1174
|
-
} catch {
|
|
1175
|
-
}
|
|
1095
|
+
} catch {}
|
|
1176
1096
|
}
|
|
1177
1097
|
if (depth < 3) {
|
|
1178
1098
|
await scanDirectory(entryPath, depth + 1);
|
|
@@ -1183,13 +1103,9 @@ async function scanWorkspacePackages(workspaceRoot) {
|
|
|
1183
1103
|
return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
1184
1104
|
}
|
|
1185
1105
|
async function updateTsconfigReferences(workspaceRoot, packages, ensureTsconfigs = false) {
|
|
1186
|
-
const tsconfigPath =
|
|
1106
|
+
const tsconfigPath = join2(workspaceRoot, "tsconfig.json");
|
|
1187
1107
|
if (ensureTsconfigs) {
|
|
1188
|
-
await ensurePackageTsconfigs(
|
|
1189
|
-
workspaceRoot,
|
|
1190
|
-
// only udate for Highstate-managed packages
|
|
1191
|
-
packages.filter((pkg) => pkg.type !== void 0)
|
|
1192
|
-
);
|
|
1108
|
+
await ensurePackageTsconfigs(workspaceRoot, packages.filter((pkg) => pkg.type !== undefined));
|
|
1193
1109
|
}
|
|
1194
1110
|
const references = packages.map((pkg) => ({
|
|
1195
1111
|
path: `./${pkg.relativePath}/tsconfig.json`
|
|
@@ -1198,22 +1114,22 @@ async function updateTsconfigReferences(workspaceRoot, packages, ensureTsconfigs
|
|
|
1198
1114
|
files: [],
|
|
1199
1115
|
references
|
|
1200
1116
|
};
|
|
1201
|
-
await
|
|
1117
|
+
await writeFile4(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
|
|
1202
1118
|
`, "utf-8");
|
|
1203
1119
|
}
|
|
1204
1120
|
async function ensurePackageTsconfigs(workspaceRoot, packages) {
|
|
1205
1121
|
for (const pkg of packages) {
|
|
1206
|
-
const tsconfigPath =
|
|
1122
|
+
const tsconfigPath = join2(pkg.path, "tsconfig.json");
|
|
1207
1123
|
const tsconfigContent = generateTsconfigContent(workspaceRoot, pkg.path);
|
|
1208
|
-
await
|
|
1124
|
+
await writeFile4(tsconfigPath, `${JSON.stringify(tsconfigContent, null, 2)}
|
|
1209
1125
|
`, "utf-8");
|
|
1210
1126
|
}
|
|
1211
1127
|
}
|
|
1212
1128
|
async function createPackage(workspaceRoot, name, type) {
|
|
1213
|
-
const packagePath =
|
|
1214
|
-
const srcPath =
|
|
1215
|
-
await
|
|
1216
|
-
await
|
|
1129
|
+
const packagePath = join2(workspaceRoot, "packages", name);
|
|
1130
|
+
const srcPath = join2(packagePath, "src");
|
|
1131
|
+
await mkdir2(packagePath, { recursive: true });
|
|
1132
|
+
await mkdir2(srcPath, { recursive: true });
|
|
1217
1133
|
const packageJson = {
|
|
1218
1134
|
name: `@highstate/${name}`,
|
|
1219
1135
|
version: "0.0.1",
|
|
@@ -1222,20 +1138,12 @@ async function createPackage(workspaceRoot, name, type) {
|
|
|
1222
1138
|
type
|
|
1223
1139
|
}
|
|
1224
1140
|
};
|
|
1225
|
-
await
|
|
1226
|
-
|
|
1227
|
-
`${JSON.stringify(packageJson, null, 2)}
|
|
1228
|
-
`,
|
|
1229
|
-
"utf-8"
|
|
1230
|
-
);
|
|
1141
|
+
await writeFile4(join2(packagePath, "package.json"), `${JSON.stringify(packageJson, null, 2)}
|
|
1142
|
+
`, "utf-8");
|
|
1231
1143
|
const tsconfigContent = generateTsconfigContent(workspaceRoot, packagePath);
|
|
1232
|
-
await
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
`,
|
|
1236
|
-
"utf-8"
|
|
1237
|
-
);
|
|
1238
|
-
await writeFile(join(srcPath, "index.ts"), `// ${name} package
|
|
1144
|
+
await writeFile4(join2(packagePath, "tsconfig.json"), `${JSON.stringify(tsconfigContent, null, 2)}
|
|
1145
|
+
`, "utf-8");
|
|
1146
|
+
await writeFile4(join2(srcPath, "index.ts"), `// ${name} package
|
|
1239
1147
|
`, "utf-8");
|
|
1240
1148
|
return {
|
|
1241
1149
|
path: packagePath,
|
|
@@ -1244,16 +1152,15 @@ async function createPackage(workspaceRoot, name, type) {
|
|
|
1244
1152
|
type
|
|
1245
1153
|
};
|
|
1246
1154
|
}
|
|
1247
|
-
|
|
1248
1155
|
// src/commands/backend/identity.ts
|
|
1249
|
-
|
|
1156
|
+
class BackendIdentityCommand extends Command {
|
|
1250
1157
|
static paths = [["backend", "identity"]];
|
|
1251
1158
|
static usage = Command.Usage({
|
|
1252
1159
|
category: "Backend",
|
|
1253
1160
|
description: "Ensures the backend identity is set up and returns the recipient."
|
|
1254
1161
|
});
|
|
1255
1162
|
async execute() {
|
|
1256
|
-
const { getOrCreateBackendIdentity } = await import(
|
|
1163
|
+
const { getOrCreateBackendIdentity } = await import("@highstate/backend");
|
|
1257
1164
|
const config = await loadConfig();
|
|
1258
1165
|
const backendIdentity = await getOrCreateBackendIdentity(config, logger);
|
|
1259
1166
|
const recipient = await identityToRecipient(backendIdentity);
|
|
@@ -1263,16 +1170,15 @@ var BackendIdentityCommand = class extends Command {
|
|
|
1263
1170
|
logger.info(`run "highstate backend unlock-method add %s" on a trusted device`, recipient);
|
|
1264
1171
|
return;
|
|
1265
1172
|
}
|
|
1266
|
-
logger.info(
|
|
1267
|
-
`run "highstate backend unlock-method add %s --title %s" on a trusted device`,
|
|
1268
|
-
recipient,
|
|
1269
|
-
suggestedTitle
|
|
1270
|
-
);
|
|
1173
|
+
logger.info(`run "highstate backend unlock-method add %s --title %s" on a trusted device`, recipient, suggestedTitle);
|
|
1271
1174
|
}
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1175
|
+
}
|
|
1176
|
+
// src/commands/backend/unlock-method/add.ts
|
|
1177
|
+
import { input } from "@inquirer/prompts";
|
|
1178
|
+
import { Command as Command2, Option } from "clipanion";
|
|
1179
|
+
class BackendUnlockMethodAddCommand extends Command2 {
|
|
1274
1180
|
static paths = [["backend", "unlock-method", "add"]];
|
|
1275
|
-
static usage =
|
|
1181
|
+
static usage = Command2.Usage({
|
|
1276
1182
|
category: "Backend",
|
|
1277
1183
|
description: "Adds a new backend unlock method for the current workspace.",
|
|
1278
1184
|
examples: [["Add recipient", "highstate backend unlock-method add age1example --title Laptop"]]
|
|
@@ -1290,15 +1196,15 @@ var BackendUnlockMethodAddCommand = class extends Command {
|
|
|
1290
1196
|
});
|
|
1291
1197
|
}
|
|
1292
1198
|
let description = this.description;
|
|
1293
|
-
if (description ===
|
|
1199
|
+
if (description === undefined) {
|
|
1294
1200
|
description = await input({
|
|
1295
1201
|
message: "Description (optional)",
|
|
1296
1202
|
default: ""
|
|
1297
1203
|
});
|
|
1298
1204
|
}
|
|
1299
|
-
const
|
|
1205
|
+
const services3 = await getBackendServices();
|
|
1300
1206
|
try {
|
|
1301
|
-
const result = await
|
|
1207
|
+
const result = await services3.backendUnlockService.addUnlockMethod({
|
|
1302
1208
|
recipient: this.recipient,
|
|
1303
1209
|
meta: description ? { title: title.trim(), description: description.trim() } : { title: title.trim() }
|
|
1304
1210
|
});
|
|
@@ -1308,15 +1214,18 @@ var BackendUnlockMethodAddCommand = class extends Command {
|
|
|
1308
1214
|
}
|
|
1309
1215
|
process.exit(0);
|
|
1310
1216
|
}
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1217
|
+
}
|
|
1218
|
+
// src/commands/backend/unlock-method/delete.ts
|
|
1219
|
+
import { confirm } from "@inquirer/prompts";
|
|
1220
|
+
import { Command as Command3, Option as Option2 } from "clipanion";
|
|
1221
|
+
class BackendUnlockMethodDeleteCommand extends Command3 {
|
|
1313
1222
|
static paths = [["backend", "unlock-method", "delete"]];
|
|
1314
|
-
static usage =
|
|
1223
|
+
static usage = Command3.Usage({
|
|
1315
1224
|
category: "Backend",
|
|
1316
1225
|
description: "Removes a backend unlock method by its identifier."
|
|
1317
1226
|
});
|
|
1318
|
-
id =
|
|
1319
|
-
force =
|
|
1227
|
+
id = Option2.String();
|
|
1228
|
+
force = Option2.Boolean("--force", false);
|
|
1320
1229
|
async execute() {
|
|
1321
1230
|
if (!this.force) {
|
|
1322
1231
|
const answer = await confirm({
|
|
@@ -1328,26 +1237,29 @@ var BackendUnlockMethodDeleteCommand = class extends Command {
|
|
|
1328
1237
|
return;
|
|
1329
1238
|
}
|
|
1330
1239
|
}
|
|
1331
|
-
const
|
|
1240
|
+
const services3 = await getBackendServices();
|
|
1332
1241
|
try {
|
|
1333
|
-
await
|
|
1242
|
+
await services3.backendUnlockService.deleteUnlockMethod(this.id);
|
|
1334
1243
|
logger.info(`deleted backend unlock method "%s"`, this.id);
|
|
1335
1244
|
} finally {
|
|
1336
1245
|
await disposeServices();
|
|
1337
1246
|
}
|
|
1338
1247
|
process.exit(0);
|
|
1339
1248
|
}
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1249
|
+
}
|
|
1250
|
+
// src/commands/backend/unlock-method/list.ts
|
|
1251
|
+
import { Command as Command4 } from "clipanion";
|
|
1252
|
+
import { Table } from "console-table-printer";
|
|
1253
|
+
class BackendUnlockMethodListCommand extends Command4 {
|
|
1342
1254
|
static paths = [["backend", "unlock-method", "list"]];
|
|
1343
|
-
static usage =
|
|
1255
|
+
static usage = Command4.Usage({
|
|
1344
1256
|
category: "Backend",
|
|
1345
1257
|
description: "Lists backend unlock methods registered for the current workspace."
|
|
1346
1258
|
});
|
|
1347
1259
|
async execute() {
|
|
1348
|
-
const
|
|
1260
|
+
const services3 = await getBackendServices();
|
|
1349
1261
|
try {
|
|
1350
|
-
const methods = await
|
|
1262
|
+
const methods = await services3.backendUnlockService.listUnlockMethods();
|
|
1351
1263
|
if (methods.length === 0) {
|
|
1352
1264
|
logger.warn("no backend unlock methods configured");
|
|
1353
1265
|
return;
|
|
@@ -1363,33 +1275,60 @@ var BackendUnlockMethodListCommand = class extends Command {
|
|
|
1363
1275
|
alignment: "left"
|
|
1364
1276
|
}
|
|
1365
1277
|
});
|
|
1366
|
-
table.addRows(
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
}))
|
|
1373
|
-
);
|
|
1278
|
+
table.addRows(methods.map((method) => ({
|
|
1279
|
+
title: method.meta.title,
|
|
1280
|
+
id: method.id,
|
|
1281
|
+
recipient: method.recipient,
|
|
1282
|
+
description: method.meta.description ?? ""
|
|
1283
|
+
})));
|
|
1374
1284
|
table.printTable();
|
|
1375
1285
|
} finally {
|
|
1376
1286
|
await disposeServices();
|
|
1377
1287
|
}
|
|
1378
1288
|
process.exit(0);
|
|
1379
1289
|
}
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1290
|
+
}
|
|
1291
|
+
// src/commands/build.ts
|
|
1292
|
+
import { chmod, readFile as readFile7, rm, writeFile as writeFile5 } from "fs/promises";
|
|
1293
|
+
import { resolve as resolve4 } from "path";
|
|
1294
|
+
import { encode } from "@msgpack/msgpack";
|
|
1295
|
+
import { Command as Command5, Option as Option3 } from "clipanion";
|
|
1296
|
+
import { readPackageJSON as readPackageJSON3, resolvePackageJSON as resolvePackageJSON4 } from "pkg-types";
|
|
1297
|
+
function formatUnknownError(error) {
|
|
1298
|
+
if (error instanceof Error) {
|
|
1299
|
+
return error.stack ?? error.message;
|
|
1300
|
+
}
|
|
1301
|
+
if (typeof error === "string") {
|
|
1302
|
+
return error;
|
|
1303
|
+
}
|
|
1304
|
+
try {
|
|
1305
|
+
return JSON.stringify(error);
|
|
1306
|
+
} catch {
|
|
1307
|
+
return String(error);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
class BuildCommand extends Command5 {
|
|
1382
1312
|
static paths = [["build"]];
|
|
1383
|
-
static usage =
|
|
1313
|
+
static usage = Command5.Usage({
|
|
1384
1314
|
category: "Builder",
|
|
1385
1315
|
description: "Builds the Highstate library or unit package."
|
|
1386
1316
|
});
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
noSourceHash = Option.Boolean("--no-source-hash", false);
|
|
1317
|
+
library = Option3.Boolean("--library", false);
|
|
1318
|
+
silent = Option3.Boolean("--silent", true);
|
|
1319
|
+
noSourceHash = Option3.Boolean("--no-source-hash", false);
|
|
1391
1320
|
async execute() {
|
|
1392
|
-
|
|
1321
|
+
try {
|
|
1322
|
+
await this.build();
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
if (error instanceof Error) {
|
|
1325
|
+
throw error;
|
|
1326
|
+
}
|
|
1327
|
+
throw new Error(`Build failed with non-error rejection: ${formatUnknownError(error)}`);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
async build() {
|
|
1331
|
+
const packageJson = await readPackageJSON3();
|
|
1393
1332
|
const highstateConfig = highstateConfigSchema.parse(packageJson.highstate ?? {});
|
|
1394
1333
|
if (highstateConfig.type === "library") {
|
|
1395
1334
|
this.library = true;
|
|
@@ -1404,168 +1343,194 @@ var BuildCommand = class extends Command {
|
|
|
1404
1343
|
if (Object.keys(entryPoints).length === 0) {
|
|
1405
1344
|
return;
|
|
1406
1345
|
}
|
|
1407
|
-
const
|
|
1346
|
+
const bunPlugins = [];
|
|
1408
1347
|
const binSourceFilePaths = Object.values(entryPoints).filter((value) => value.isBin).map((value) => value.entryPoint.slice(2));
|
|
1409
1348
|
if (this.library) {
|
|
1410
|
-
|
|
1349
|
+
bunPlugins.push(schemaTransformerPlugin);
|
|
1411
1350
|
}
|
|
1412
1351
|
if (binSourceFilePaths.length > 0) {
|
|
1413
|
-
|
|
1414
|
-
}
|
|
1415
|
-
await
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1352
|
+
bunPlugins.push(createBinTransformerPlugin(binSourceFilePaths));
|
|
1353
|
+
}
|
|
1354
|
+
await rm("dist", { recursive: true, force: true });
|
|
1355
|
+
const bunEntryPoints = Object.values(entryPoints).map((value) => value.entryPoint);
|
|
1356
|
+
const result = await Bun.build({
|
|
1357
|
+
entrypoints: bunEntryPoints,
|
|
1358
|
+
outdir: "dist",
|
|
1359
|
+
root: "./src",
|
|
1421
1360
|
format: "esm",
|
|
1422
|
-
target: "
|
|
1423
|
-
platform: "node",
|
|
1361
|
+
target: "bun",
|
|
1424
1362
|
external: ["@pulumi/pulumi"],
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
silent: this.silent || ["warn", "error", "fatal"].includes(logger.level)
|
|
1363
|
+
packages: "external",
|
|
1364
|
+
splitting: true,
|
|
1365
|
+
plugins: bunPlugins
|
|
1429
1366
|
});
|
|
1430
|
-
|
|
1431
|
-
|
|
1367
|
+
if (!result.success) {
|
|
1368
|
+
for (const log of result.logs) {
|
|
1369
|
+
logger.error(log.message);
|
|
1370
|
+
}
|
|
1371
|
+
throw new Error("build failed");
|
|
1372
|
+
}
|
|
1373
|
+
const binEntryPoints = Object.values(entryPoints).filter((value) => value.isBin);
|
|
1374
|
+
for (const binEntryPoint of binEntryPoints) {
|
|
1375
|
+
const binPath = resolve4(binEntryPoint.distPath);
|
|
1376
|
+
const binContent = await readFile7(binPath, "utf8");
|
|
1377
|
+
if (!binContent.startsWith(`#!/usr/bin/env bun
|
|
1378
|
+
`)) {
|
|
1379
|
+
await writeFile5(binPath, `#!/usr/bin/env bun
|
|
1380
|
+
${binContent}`, "utf8");
|
|
1381
|
+
}
|
|
1382
|
+
await chmod(binPath, 493);
|
|
1383
|
+
}
|
|
1384
|
+
const packageJsonPath = await resolvePackageJSON4();
|
|
1385
|
+
const upToDatePackageJson = await readPackageJSON3();
|
|
1432
1386
|
if (!this.noSourceHash) {
|
|
1433
|
-
const sourceHashCalculator = new SourceHashCalculator(
|
|
1434
|
-
|
|
1435
|
-
upToDatePackageJson,
|
|
1436
|
-
logger
|
|
1437
|
-
);
|
|
1438
|
-
const distPathToExportKey = /* @__PURE__ */ new Map();
|
|
1387
|
+
const sourceHashCalculator = new SourceHashCalculator(packageJsonPath, upToDatePackageJson, logger);
|
|
1388
|
+
const distPathToExportKey = new Map;
|
|
1439
1389
|
for (const value of Object.values(entryPoints)) {
|
|
1440
1390
|
distPathToExportKey.set(value.distPath, value.key);
|
|
1441
1391
|
}
|
|
1442
1392
|
await sourceHashCalculator.writeHighstateManifest("./dist", distPathToExportKey);
|
|
1443
1393
|
}
|
|
1444
1394
|
if (this.library) {
|
|
1445
|
-
const { loadLibrary } = await import(
|
|
1446
|
-
const fullModulePaths = Object.values(entryPoints).map((value) =>
|
|
1395
|
+
const { loadLibrary } = await import("./chunk-sxh2gdkm.js");
|
|
1396
|
+
const fullModulePaths = Object.values(entryPoints).map((value) => resolve4(value.distPath));
|
|
1447
1397
|
logger.info("evaluating library components from modules: %s", fullModulePaths.join(", "));
|
|
1448
1398
|
const library = await loadLibrary(logger, fullModulePaths);
|
|
1449
|
-
const libraryPath =
|
|
1450
|
-
await
|
|
1399
|
+
const libraryPath = resolve4("./dist", "highstate.library.msgpack");
|
|
1400
|
+
await writeFile5(libraryPath, encode(library), "utf8");
|
|
1451
1401
|
}
|
|
1452
1402
|
logger.info("build completed successfully");
|
|
1453
1403
|
}
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1404
|
+
}
|
|
1405
|
+
// src/commands/designer.ts
|
|
1406
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1407
|
+
import { Command as Command6, UsageError } from "clipanion";
|
|
1408
|
+
import { consola as consola2 } from "consola";
|
|
1409
|
+
import { colorize } from "consola/utils";
|
|
1410
|
+
import { checkPort, getPort } from "get-port-please";
|
|
1411
|
+
import { resolve as importMetaResolve2 } from "import-meta-resolve";
|
|
1412
|
+
import { addDevDependency } from "nypm";
|
|
1413
|
+
import { readPackageJSON as readPackageJSON4, resolvePackageJSON as resolvePackageJSON5 } from "pkg-types";
|
|
1414
|
+
var shuttingDown = false;
|
|
1415
|
+
|
|
1416
|
+
class DesignerCommand extends Command6 {
|
|
1456
1417
|
static paths = [["designer"]];
|
|
1457
|
-
static usage =
|
|
1418
|
+
static usage = Command6.Usage({
|
|
1458
1419
|
category: "Designer",
|
|
1459
1420
|
description: "Starts the Highstate designer in the current project."
|
|
1460
1421
|
});
|
|
1461
1422
|
async execute() {
|
|
1462
|
-
const packageJsonPath = await
|
|
1463
|
-
const packageJsonUrl =
|
|
1464
|
-
const packageJson = await
|
|
1423
|
+
const packageJsonPath = await resolvePackageJSON5();
|
|
1424
|
+
const packageJsonUrl = pathToFileURL2(packageJsonPath).toString();
|
|
1425
|
+
const packageJson = await readPackageJSON4(packageJsonPath);
|
|
1465
1426
|
if (!packageJson.devDependencies?.["@highstate/cli"]) {
|
|
1466
|
-
throw new UsageError(
|
|
1467
|
-
|
|
1468
|
-
);
|
|
1427
|
+
throw new UsageError(`This project is not a Highstate project.
|
|
1428
|
+
@highstate/cli must be installed as a devDependency.`);
|
|
1469
1429
|
}
|
|
1470
1430
|
if (!packageJson.devDependencies?.["@highstate/designer"]) {
|
|
1471
1431
|
logger.info("Installing @highstate/designer...");
|
|
1472
1432
|
await addDevDependency(["@highstate/designer", "classic-level"]);
|
|
1473
1433
|
}
|
|
1474
|
-
const projectRoot = process.cwd();
|
|
1475
|
-
const detected = await detectPackageManager(projectRoot);
|
|
1476
|
-
const packageManager = detected?.name;
|
|
1477
|
-
if (packageManager === "npm" || packageManager === "pnpm" || packageManager === "yarn") {
|
|
1478
|
-
const expectedPulumiSdk = await getProjectPulumiSdkVersion(projectRoot, { packageManager });
|
|
1479
|
-
const actualPulumiCli = await getPulumiCliVersion(projectRoot);
|
|
1480
|
-
if (expectedPulumiSdk && actualPulumiCli && expectedPulumiSdk !== actualPulumiCli) {
|
|
1481
|
-
logger.warn(
|
|
1482
|
-
`pulumi version mismatch detected, this may cause incompatibilities
|
|
1483
|
-
expected "%s" (from overrides for "@pulumi/pulumi"), got "%s" (from "pulumi version")
|
|
1484
|
-
recommended: run "highstate update" or downgrade your Pulumi CLI to "%s"`,
|
|
1485
|
-
expectedPulumiSdk,
|
|
1486
|
-
actualPulumiCli,
|
|
1487
|
-
expectedPulumiSdk
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
1434
|
logger.info("starting highstate designer...");
|
|
1492
1435
|
await getBackendServices();
|
|
1493
1436
|
const oldConsoleLog = console.log;
|
|
1494
|
-
const
|
|
1495
|
-
const
|
|
1496
|
-
const
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1437
|
+
const host = "127.0.0.1";
|
|
1438
|
+
const configuredPort = process.env.HIGHSTATE_DESIGNER_PORT;
|
|
1439
|
+
const port = configuredPort === undefined ? 7283 : Number(configuredPort);
|
|
1440
|
+
if (!/^\d+$/.test(configuredPort ?? port.toString()) || port < 1 || port > 65535) {
|
|
1441
|
+
throw new UsageError(`HIGHSTATE_DESIGNER_PORT must be an integer between "1" and "65535"`);
|
|
1442
|
+
}
|
|
1443
|
+
if (configuredPort !== undefined) {
|
|
1444
|
+
logger.warn(`using custom designer port "%s"; changing the port changes the WebAuthn origin and may require registering security keys again`, port);
|
|
1445
|
+
}
|
|
1446
|
+
const availablePort = await checkPort(port, host);
|
|
1447
|
+
if (!availablePort) {
|
|
1448
|
+
throw new UsageError(`Port "${port}" is already in use`);
|
|
1449
|
+
}
|
|
1450
|
+
const eventsPort = await getPort({ random: true, host });
|
|
1451
|
+
const designerPackageJsonPath = importMetaResolve2("@highstate/designer/package.json", packageJsonUrl);
|
|
1452
|
+
const designerPackageJson = await readPackageJSON4(designerPackageJsonPath);
|
|
1501
1453
|
process.env.NITRO_PORT = port.toString();
|
|
1502
|
-
process.env.NITRO_HOST =
|
|
1454
|
+
process.env.NITRO_HOST = host;
|
|
1455
|
+
process.env.NITRO_BUN_IDLE_TIMEOUT ??= "255";
|
|
1503
1456
|
process.env.NUXT_PUBLIC_VERSION = designerPackageJson.version;
|
|
1504
1457
|
process.env.NUXT_PUBLIC_EVENTS_PORT = eventsPort.toString();
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1458
|
+
try {
|
|
1459
|
+
await new Promise((resolve5, reject) => {
|
|
1460
|
+
console.log = (message) => {
|
|
1461
|
+
if (message.startsWith("Listening on")) {
|
|
1462
|
+
if (!message.includes(`http://${host}:${port}`)) {
|
|
1463
|
+
reject(new Error(`Designer started on an unexpected endpoint: ${message}`));
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
resolve5();
|
|
1467
|
+
}
|
|
1468
|
+
};
|
|
1469
|
+
const serverPath = importMetaResolve2("@highstate/designer/server", packageJsonUrl);
|
|
1470
|
+
import(serverPath).catch(reject);
|
|
1471
|
+
});
|
|
1472
|
+
} finally {
|
|
1473
|
+
console.log = oldConsoleLog;
|
|
1474
|
+
}
|
|
1475
|
+
consola2.log([
|
|
1476
|
+
`
|
|
1477
|
+
`,
|
|
1478
|
+
colorize("bold", colorize("cyanBright", "Highstate Designer")),
|
|
1479
|
+
`
|
|
1480
|
+
`,
|
|
1481
|
+
colorize("greenBright", "\u279C Local: "),
|
|
1482
|
+
colorize("underline", colorize("cyanBright", `http://highstate.localhost:${port}`)),
|
|
1483
|
+
`
|
|
1484
|
+
`
|
|
1485
|
+
].join(""));
|
|
1486
|
+
process.once("SIGINT", () => {
|
|
1487
|
+
if (shuttingDown) {
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
shuttingDown = true;
|
|
1526
1491
|
process.stdout.write("\r");
|
|
1527
|
-
|
|
1528
|
-
setTimeout(() => process.exit(0),
|
|
1492
|
+
consola2.info("shutting down highstate designer...");
|
|
1493
|
+
setTimeout(() => process.exit(0), 1000);
|
|
1529
1494
|
});
|
|
1530
1495
|
}
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1496
|
+
}
|
|
1497
|
+
// src/commands/init.ts
|
|
1498
|
+
import { access, mkdir as mkdir3, readdir as readdir3 } from "fs/promises";
|
|
1499
|
+
import { resolve as resolve5 } from "path";
|
|
1500
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1501
|
+
import { input as input2 } from "@inquirer/prompts";
|
|
1502
|
+
import { Command as Command7, Option as Option4 } from "clipanion";
|
|
1503
|
+
import { installDependencies } from "nypm";
|
|
1504
|
+
class InitCommand extends Command7 {
|
|
1533
1505
|
static paths = [["init"]];
|
|
1534
|
-
static usage =
|
|
1506
|
+
static usage = Command7.Usage({
|
|
1535
1507
|
description: "Initializes a new Highstate project."
|
|
1536
1508
|
});
|
|
1537
|
-
pathOption =
|
|
1509
|
+
pathOption = Option4.String("--path,-p", {
|
|
1538
1510
|
description: "The path where the project should be initialized."
|
|
1539
1511
|
});
|
|
1540
|
-
|
|
1541
|
-
description: "The package manager to use (npm, yarn, pnpm)."
|
|
1542
|
-
});
|
|
1543
|
-
name = Option.String("--name", {
|
|
1512
|
+
name = Option4.String("--name", {
|
|
1544
1513
|
description: "The project name."
|
|
1545
1514
|
});
|
|
1546
|
-
platformVersion =
|
|
1515
|
+
platformVersion = Option4.String("--platform-version", {
|
|
1547
1516
|
description: "The Highstate platform version to use."
|
|
1548
1517
|
});
|
|
1549
|
-
stdlibVersion =
|
|
1518
|
+
stdlibVersion = Option4.String("--stdlib-version", {
|
|
1550
1519
|
description: "The Highstate standard library version to use."
|
|
1551
1520
|
});
|
|
1552
1521
|
async execute() {
|
|
1553
|
-
const
|
|
1554
|
-
if (
|
|
1555
|
-
throw new Error('
|
|
1522
|
+
const isBunAvailable = await isExecutableInPath("bun");
|
|
1523
|
+
if (!isBunAvailable) {
|
|
1524
|
+
throw new Error('Required package manager "bun" was not found in PATH');
|
|
1556
1525
|
}
|
|
1557
1526
|
const projectName = await resolveProjectName(this.name);
|
|
1558
1527
|
const destinationPath = await resolveDestinationPath(this.pathOption, projectName);
|
|
1559
|
-
const selectedPackageManager = await resolvePackageManager(
|
|
1560
|
-
this.packageManager,
|
|
1561
|
-
availablePackageManagers
|
|
1562
|
-
);
|
|
1563
1528
|
const templatePath = resolveTemplatePath();
|
|
1564
1529
|
const versionBundle = await resolveVersionBundle({
|
|
1565
1530
|
platformVersion: this.platformVersion,
|
|
1566
1531
|
stdlibVersion: this.stdlibVersion
|
|
1567
1532
|
});
|
|
1568
|
-
await
|
|
1533
|
+
await mkdir3(destinationPath, { recursive: true });
|
|
1569
1534
|
const isEmptyOrMissing = await isEmptyDirectory(destinationPath);
|
|
1570
1535
|
if (!isEmptyOrMissing) {
|
|
1571
1536
|
throw new Error(`Destination path is not empty: "${destinationPath}"`);
|
|
@@ -1575,85 +1540,49 @@ var InitCommand = class extends Command {
|
|
|
1575
1540
|
projectName,
|
|
1576
1541
|
packageName: projectName,
|
|
1577
1542
|
platformVersion: versionBundle.platformVersion,
|
|
1578
|
-
libraryVersion: versionBundle.stdlibVersion
|
|
1579
|
-
isPnpm: selectedPackageManager === "pnpm" ? "true" : "",
|
|
1580
|
-
isYarn: selectedPackageManager === "yarn" ? "true" : "",
|
|
1581
|
-
isNpm: selectedPackageManager === "npm" ? "true" : ""
|
|
1543
|
+
libraryVersion: versionBundle.stdlibVersion
|
|
1582
1544
|
});
|
|
1583
|
-
const
|
|
1545
|
+
const overrides2 = buildOverrides(versionBundle);
|
|
1584
1546
|
await applyOverrides({
|
|
1585
1547
|
projectRoot: destinationPath,
|
|
1586
|
-
|
|
1587
|
-
overrides
|
|
1548
|
+
overrides: overrides2
|
|
1588
1549
|
});
|
|
1589
|
-
logger.info("installing dependencies using
|
|
1550
|
+
logger.info("installing dependencies using bun...");
|
|
1590
1551
|
await installDependencies({
|
|
1591
1552
|
cwd: destinationPath,
|
|
1592
|
-
packageManager:
|
|
1553
|
+
packageManager: "bun",
|
|
1593
1554
|
silent: false
|
|
1594
1555
|
});
|
|
1595
1556
|
logger.info("project initialized successfully");
|
|
1596
1557
|
}
|
|
1597
|
-
}
|
|
1558
|
+
}
|
|
1598
1559
|
async function resolveDestinationPath(pathOption, projectName) {
|
|
1599
1560
|
if (pathOption) {
|
|
1600
|
-
return
|
|
1561
|
+
return resolve5(pathOption);
|
|
1601
1562
|
}
|
|
1602
|
-
const defaultPath =
|
|
1603
|
-
const pathValue = await
|
|
1563
|
+
const defaultPath = resolve5(process.cwd(), projectName);
|
|
1564
|
+
const pathValue = await input2({
|
|
1604
1565
|
message: "Project path",
|
|
1605
1566
|
default: defaultPath,
|
|
1606
1567
|
validate: (value) => value.trim().length > 0 ? true : "Path is required"
|
|
1607
1568
|
});
|
|
1608
|
-
return
|
|
1569
|
+
return resolve5(pathValue);
|
|
1609
1570
|
}
|
|
1610
1571
|
async function resolveProjectName(nameOption) {
|
|
1611
|
-
if (nameOption !==
|
|
1572
|
+
if (nameOption !== undefined) {
|
|
1612
1573
|
const trimmed = nameOption.trim();
|
|
1613
1574
|
if (trimmed.length === 0) {
|
|
1614
1575
|
throw new Error('Flag "--name" must not be empty');
|
|
1615
1576
|
}
|
|
1616
1577
|
return trimmed;
|
|
1617
1578
|
}
|
|
1618
|
-
const value = await
|
|
1579
|
+
const value = await input2({
|
|
1619
1580
|
message: "Project name",
|
|
1620
1581
|
default: "my-project",
|
|
1621
1582
|
validate: (inputValue) => inputValue.trim().length > 0 ? true : "Name is required"
|
|
1622
1583
|
});
|
|
1623
1584
|
return value.trim();
|
|
1624
1585
|
}
|
|
1625
|
-
async function resolvePackageManager(packageManagerOption, available) {
|
|
1626
|
-
if (packageManagerOption) {
|
|
1627
|
-
if (!isSupportedPackageManagerName(packageManagerOption)) {
|
|
1628
|
-
throw new Error(`Unsupported package manager: "${packageManagerOption}"`);
|
|
1629
|
-
}
|
|
1630
|
-
const name = packageManagerOption;
|
|
1631
|
-
if (!available.includes(name)) {
|
|
1632
|
-
throw new Error(`Package manager not found in PATH: "${name}"`);
|
|
1633
|
-
}
|
|
1634
|
-
return name;
|
|
1635
|
-
}
|
|
1636
|
-
const preferredOrder = ["pnpm", "yarn", "npm"];
|
|
1637
|
-
const defaultValue = preferredOrder.find((value) => available.includes(value)) ?? available[0];
|
|
1638
|
-
return await select({
|
|
1639
|
-
message: "Package manager",
|
|
1640
|
-
default: defaultValue,
|
|
1641
|
-
choices: available.map((value) => ({ name: value, value }))
|
|
1642
|
-
});
|
|
1643
|
-
}
|
|
1644
|
-
function isSupportedPackageManagerName(value) {
|
|
1645
|
-
return value === "npm" || value === "pnpm" || value === "yarn";
|
|
1646
|
-
}
|
|
1647
|
-
async function detectAvailablePackageManagers(candidates) {
|
|
1648
|
-
const results = [];
|
|
1649
|
-
for (const candidate of candidates) {
|
|
1650
|
-
const exists = await isExecutableInPath(candidate);
|
|
1651
|
-
if (exists) {
|
|
1652
|
-
results.push(candidate);
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
return results;
|
|
1656
|
-
}
|
|
1657
1586
|
async function isExecutableInPath(command) {
|
|
1658
1587
|
const pathValue = process.env.PATH;
|
|
1659
1588
|
if (!pathValue) {
|
|
@@ -1661,35 +1590,36 @@ async function isExecutableInPath(command) {
|
|
|
1661
1590
|
}
|
|
1662
1591
|
const parts = pathValue.split(":").filter(Boolean);
|
|
1663
1592
|
for (const part of parts) {
|
|
1664
|
-
const candidate =
|
|
1593
|
+
const candidate = resolve5(part, command);
|
|
1665
1594
|
try {
|
|
1666
1595
|
await access(candidate);
|
|
1667
1596
|
return true;
|
|
1668
|
-
} catch {
|
|
1669
|
-
}
|
|
1597
|
+
} catch {}
|
|
1670
1598
|
}
|
|
1671
1599
|
return false;
|
|
1672
1600
|
}
|
|
1673
1601
|
async function isEmptyDirectory(path) {
|
|
1674
1602
|
try {
|
|
1675
|
-
const entries = await
|
|
1603
|
+
const entries = await readdir3(path);
|
|
1676
1604
|
return entries.length === 0;
|
|
1677
1605
|
} catch {
|
|
1678
1606
|
return true;
|
|
1679
1607
|
}
|
|
1680
1608
|
}
|
|
1681
1609
|
function resolveTemplatePath() {
|
|
1682
|
-
const here =
|
|
1683
|
-
return
|
|
1610
|
+
const here = fileURLToPath2(new URL(import.meta.url));
|
|
1611
|
+
return resolve5(here, "..", "..", "assets", "template");
|
|
1684
1612
|
}
|
|
1685
|
-
|
|
1613
|
+
// src/commands/package/create.ts
|
|
1614
|
+
import { Command as Command8, Option as Option5 } from "clipanion";
|
|
1615
|
+
class PackageCreateCommand extends Command8 {
|
|
1686
1616
|
static paths = [["package", "create"]];
|
|
1687
|
-
static usage =
|
|
1617
|
+
static usage = Command8.Usage({
|
|
1688
1618
|
category: "Package",
|
|
1689
1619
|
description: "Creates a new package in the workspace."
|
|
1690
1620
|
});
|
|
1691
|
-
name =
|
|
1692
|
-
type =
|
|
1621
|
+
name = Option5.String({ required: true });
|
|
1622
|
+
type = Option5.String("--type,-t", {
|
|
1693
1623
|
description: "Package type (source, library, worker)"
|
|
1694
1624
|
});
|
|
1695
1625
|
async execute() {
|
|
@@ -1700,10 +1630,13 @@ var PackageCreateCommand = class extends Command {
|
|
|
1700
1630
|
await updateTsconfigReferences(workspaceRoot, packages);
|
|
1701
1631
|
logger.info(`created package: @highstate/${this.name} (${packageType})`);
|
|
1702
1632
|
}
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1633
|
+
}
|
|
1634
|
+
// src/commands/package/list.ts
|
|
1635
|
+
import { Command as Command9 } from "clipanion";
|
|
1636
|
+
import { Table as Table2 } from "console-table-printer";
|
|
1637
|
+
class PackageListCommand extends Command9 {
|
|
1705
1638
|
static paths = [["package", "list"]];
|
|
1706
|
-
static usage =
|
|
1639
|
+
static usage = Command9.Usage({
|
|
1707
1640
|
category: "Package",
|
|
1708
1641
|
description: "Lists all packages in the workspace with their types."
|
|
1709
1642
|
});
|
|
@@ -1714,49 +1647,50 @@ var PackageListCommand = class extends Command {
|
|
|
1714
1647
|
logger.info("no packages found in workspace");
|
|
1715
1648
|
return;
|
|
1716
1649
|
}
|
|
1717
|
-
const table = new
|
|
1650
|
+
const table = new Table2({
|
|
1718
1651
|
columns: [
|
|
1719
1652
|
{ name: "name", title: "Name" },
|
|
1720
1653
|
{ name: "type", title: "Type" },
|
|
1721
1654
|
{ name: "path", title: "Path" }
|
|
1722
1655
|
]
|
|
1723
1656
|
});
|
|
1724
|
-
table.addRows(
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
}))
|
|
1730
|
-
);
|
|
1657
|
+
table.addRows(packages.map((pkg) => ({
|
|
1658
|
+
name: pkg.name,
|
|
1659
|
+
type: pkg.type ?? "unknown",
|
|
1660
|
+
path: pkg.relativePath
|
|
1661
|
+
})));
|
|
1731
1662
|
table.printTable();
|
|
1732
1663
|
}
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1664
|
+
}
|
|
1665
|
+
// src/commands/package/remove.ts
|
|
1666
|
+
import { rm as rm2 } from "fs/promises";
|
|
1667
|
+
import { Command as Command10, Option as Option6 } from "clipanion";
|
|
1668
|
+
class PackageRemoveCommand extends Command10 {
|
|
1735
1669
|
static paths = [["package", "remove"]];
|
|
1736
|
-
static usage =
|
|
1670
|
+
static usage = Command10.Usage({
|
|
1737
1671
|
category: "Package",
|
|
1738
1672
|
description: "Removes a package from the workspace."
|
|
1739
1673
|
});
|
|
1740
|
-
name =
|
|
1674
|
+
name = Option6.String({ required: true });
|
|
1741
1675
|
async execute() {
|
|
1742
1676
|
const workspaceRoot = await findWorkspaceRoot();
|
|
1743
1677
|
const packages = await scanWorkspacePackages(workspaceRoot);
|
|
1744
|
-
const targetPackage = packages.find(
|
|
1745
|
-
(pkg) => pkg.name === this.name || pkg.name === `@highstate/${this.name}` || pkg.relativePath.endsWith(this.name)
|
|
1746
|
-
);
|
|
1678
|
+
const targetPackage = packages.find((pkg) => pkg.name === this.name || pkg.name === `@highstate/${this.name}` || pkg.relativePath.endsWith(this.name));
|
|
1747
1679
|
if (!targetPackage) {
|
|
1748
1680
|
logger.error(`package not found: ${this.name}`);
|
|
1749
1681
|
process.exit(1);
|
|
1750
1682
|
}
|
|
1751
|
-
await
|
|
1683
|
+
await rm2(targetPackage.path, { recursive: true, force: true });
|
|
1752
1684
|
const remainingPackages = await scanWorkspacePackages(workspaceRoot);
|
|
1753
1685
|
await updateTsconfigReferences(workspaceRoot, remainingPackages);
|
|
1754
1686
|
logger.info(`removed package: ${targetPackage.name}`);
|
|
1755
1687
|
}
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1688
|
+
}
|
|
1689
|
+
// src/commands/package/update-references.ts
|
|
1690
|
+
import { Command as Command11 } from "clipanion";
|
|
1691
|
+
class PackageUpdateReferencesCommand extends Command11 {
|
|
1758
1692
|
static paths = [["package", "update-references"]];
|
|
1759
|
-
static usage =
|
|
1693
|
+
static usage = Command11.Usage({
|
|
1760
1694
|
category: "Package",
|
|
1761
1695
|
description: "Updates the root tsconfig.json with references to all packages in the workspace."
|
|
1762
1696
|
});
|
|
@@ -1765,121 +1699,137 @@ var PackageUpdateReferencesCommand = class extends Command {
|
|
|
1765
1699
|
const packages = await scanWorkspacePackages(workspaceRoot);
|
|
1766
1700
|
await updateTsconfigReferences(workspaceRoot, packages, true);
|
|
1767
1701
|
}
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1702
|
+
}
|
|
1703
|
+
// src/commands/update.ts
|
|
1704
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
1705
|
+
import { Command as Command12, Option as Option7 } from "clipanion";
|
|
1706
|
+
import { readPackageJSON as readPackageJSON5, resolvePackageJSON as resolvePackageJSON6 } from "pkg-types";
|
|
1707
|
+
import semver from "semver";
|
|
1708
|
+
class UpdateCommand extends Command12 {
|
|
1770
1709
|
static paths = [["update"]];
|
|
1771
|
-
static usage =
|
|
1710
|
+
static usage = Command12.Usage({
|
|
1772
1711
|
description: "Updates version overrides in an existing Highstate project."
|
|
1773
1712
|
});
|
|
1774
|
-
platformVersion =
|
|
1713
|
+
platformVersion = Option7.String("--platform-version", {
|
|
1775
1714
|
description: "The Highstate platform version to set."
|
|
1776
1715
|
});
|
|
1777
|
-
stdlibVersion =
|
|
1716
|
+
stdlibVersion = Option7.String("--stdlib-version", {
|
|
1778
1717
|
description: "The Highstate standard library version to set."
|
|
1779
1718
|
});
|
|
1780
|
-
platformOnly =
|
|
1719
|
+
platformOnly = Option7.Boolean("--platform", false, {
|
|
1781
1720
|
description: "Update only platform versions."
|
|
1782
1721
|
});
|
|
1783
|
-
stdlibOnly =
|
|
1722
|
+
stdlibOnly = Option7.Boolean("--stdlib", false, {
|
|
1784
1723
|
description: "Update only standard library versions."
|
|
1785
1724
|
});
|
|
1786
|
-
install =
|
|
1725
|
+
install = Option7.Boolean("--install", true, {
|
|
1787
1726
|
description: "Install dependencies after updating overrides."
|
|
1788
1727
|
});
|
|
1789
1728
|
async execute() {
|
|
1790
1729
|
const projectRoot = process.cwd();
|
|
1791
|
-
|
|
1730
|
+
await assertPackageJsonExists(projectRoot);
|
|
1792
1731
|
if (this.platformOnly && this.stdlibOnly) {
|
|
1793
1732
|
throw new Error('Flags "--platform" and "--stdlib" cannot be used together');
|
|
1794
1733
|
}
|
|
1795
1734
|
const updatePlatform = this.platformOnly || !this.stdlibOnly;
|
|
1796
1735
|
const updateStdlib = this.stdlibOnly || !this.platformOnly;
|
|
1736
|
+
let currentPlatformVersion;
|
|
1737
|
+
let resolvedStdlibVersion = this.stdlibVersion;
|
|
1797
1738
|
if (this.stdlibOnly) {
|
|
1798
|
-
const
|
|
1799
|
-
|
|
1800
|
-
});
|
|
1801
|
-
if (!currentPlatformVersion) {
|
|
1739
|
+
const projectPlatformVersion = await getProjectPlatformVersion(projectRoot);
|
|
1740
|
+
if (!projectPlatformVersion) {
|
|
1802
1741
|
throw new Error('Current platform version is not set in overrides for "@highstate/pulumi"');
|
|
1803
1742
|
}
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
const stdlibManifest = await fetchManifest("@highstate/library", targetStdlibVersion);
|
|
1809
|
-
const supportedPlatformRange = getDependencyRange(stdlibManifest, "@highstate/pulumi");
|
|
1810
|
-
if (!supportedPlatformRange) {
|
|
1811
|
-
throw new Error(
|
|
1812
|
-
`Unable to infer "@highstate/pulumi" version from "@highstate/library@${targetStdlibVersion}"`
|
|
1813
|
-
);
|
|
1814
|
-
}
|
|
1815
|
-
const validPlatform = semver.valid(currentPlatformVersion);
|
|
1816
|
-
if (!validPlatform) {
|
|
1817
|
-
throw new Error(
|
|
1818
|
-
`Current platform version is not a valid semver "${currentPlatformVersion}"`
|
|
1819
|
-
);
|
|
1820
|
-
}
|
|
1821
|
-
const ok = semver.satisfies(validPlatform, supportedPlatformRange, {
|
|
1822
|
-
includePrerelease: true
|
|
1743
|
+
currentPlatformVersion = projectPlatformVersion;
|
|
1744
|
+
resolvedStdlibVersion = await resolveCompatibleStdlibVersion({
|
|
1745
|
+
currentPlatformVersion: projectPlatformVersion,
|
|
1746
|
+
stdlibVersion: this.stdlibVersion
|
|
1823
1747
|
});
|
|
1824
|
-
if (!ok) {
|
|
1825
|
-
throw new Error(
|
|
1826
|
-
`Current platform version "${currentPlatformVersion}" does not satisfy requirement "${supportedPlatformRange}"`
|
|
1827
|
-
);
|
|
1828
|
-
}
|
|
1829
1748
|
}
|
|
1830
1749
|
const bundle = await resolveVersionBundle({
|
|
1831
|
-
platformVersion: updatePlatform ? this.platformVersion :
|
|
1832
|
-
stdlibVersion: updateStdlib ?
|
|
1750
|
+
platformVersion: updatePlatform ? this.platformVersion : currentPlatformVersion,
|
|
1751
|
+
stdlibVersion: updateStdlib ? resolvedStdlibVersion : undefined
|
|
1833
1752
|
});
|
|
1834
|
-
const
|
|
1753
|
+
const overrides2 = buildOverrides(bundle);
|
|
1835
1754
|
await applyOverrides({
|
|
1836
1755
|
projectRoot,
|
|
1837
|
-
|
|
1838
|
-
|
|
1756
|
+
overrides: overrides2
|
|
1757
|
+
});
|
|
1758
|
+
await syncRootPulumiDependency({
|
|
1759
|
+
projectRoot,
|
|
1760
|
+
pulumiVersion: bundle.pulumiVersion
|
|
1839
1761
|
});
|
|
1840
|
-
logger.info(
|
|
1841
|
-
"updated overrides: platform=%s stdlib=%s pulumi=%s",
|
|
1842
|
-
bundle.platformVersion,
|
|
1843
|
-
bundle.stdlibVersion,
|
|
1844
|
-
bundle.pulumiVersion
|
|
1845
|
-
);
|
|
1762
|
+
logger.info("updated overrides: platform=%s stdlib=%s pulumi=%s", bundle.platformVersion, bundle.stdlibVersion, bundle.pulumiVersion);
|
|
1846
1763
|
if (this.install) {
|
|
1847
|
-
const { installDependencies: installDependencies2 } = await import(
|
|
1848
|
-
logger.info("installing dependencies using
|
|
1764
|
+
const { installDependencies: installDependencies2 } = await import("nypm");
|
|
1765
|
+
logger.info("installing dependencies using bun...");
|
|
1849
1766
|
await installDependencies2({
|
|
1850
1767
|
cwd: projectRoot,
|
|
1851
|
-
packageManager,
|
|
1768
|
+
packageManager: "bun",
|
|
1852
1769
|
silent: false
|
|
1853
1770
|
});
|
|
1854
1771
|
}
|
|
1855
1772
|
logger.info("update completed successfully");
|
|
1856
1773
|
}
|
|
1857
|
-
}
|
|
1858
|
-
async function
|
|
1859
|
-
const
|
|
1860
|
-
if (!
|
|
1861
|
-
throw new Error(
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1774
|
+
}
|
|
1775
|
+
async function resolveCompatibleStdlibVersion(args) {
|
|
1776
|
+
const validPlatform = semver.valid(args.currentPlatformVersion);
|
|
1777
|
+
if (!validPlatform) {
|
|
1778
|
+
throw new Error(`Current platform version is not a valid semver "${args.currentPlatformVersion}"`);
|
|
1779
|
+
}
|
|
1780
|
+
const targetStdlibVersion = args.stdlibVersion?.trim();
|
|
1781
|
+
if (targetStdlibVersion) {
|
|
1782
|
+
await assertStdlibSupportsPlatform({
|
|
1783
|
+
currentPlatformVersion: validPlatform,
|
|
1784
|
+
stdlibVersion: targetStdlibVersion
|
|
1785
|
+
});
|
|
1786
|
+
return targetStdlibVersion;
|
|
1865
1787
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1788
|
+
const packument = await fetchNpmPackument("@highstate/library");
|
|
1789
|
+
const sortedVersions = Object.entries(packument.versions ?? {}).filter(([version]) => semver.valid(version)).sort(([a], [b]) => semver.rcompare(a, b));
|
|
1790
|
+
for (const [stdlibVersion, stdlibManifest] of sortedVersions) {
|
|
1791
|
+
const supportedPlatformRange = getDependencyRange(stdlibManifest, "@highstate/pulumi");
|
|
1792
|
+
if (!supportedPlatformRange) {
|
|
1793
|
+
continue;
|
|
1794
|
+
}
|
|
1795
|
+
const ok = semver.satisfies(validPlatform, supportedPlatformRange, {
|
|
1796
|
+
includePrerelease: true
|
|
1797
|
+
});
|
|
1798
|
+
if (ok) {
|
|
1799
|
+
return stdlibVersion;
|
|
1800
|
+
}
|
|
1868
1801
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1802
|
+
throw new Error(`Unable to find "@highstate/library" version compatible with platform "${validPlatform}"`);
|
|
1803
|
+
}
|
|
1804
|
+
async function assertStdlibSupportsPlatform(args) {
|
|
1805
|
+
const stdlibManifest = await fetchManifest("@highstate/library", args.stdlibVersion);
|
|
1806
|
+
const supportedPlatformRange = getDependencyRange(stdlibManifest, "@highstate/pulumi");
|
|
1807
|
+
if (!supportedPlatformRange) {
|
|
1808
|
+
throw new Error(`Unable to infer "@highstate/pulumi" version from "@highstate/library@${args.stdlibVersion}"`);
|
|
1809
|
+
}
|
|
1810
|
+
const ok = semver.satisfies(args.currentPlatformVersion, supportedPlatformRange, {
|
|
1811
|
+
includePrerelease: true
|
|
1812
|
+
});
|
|
1813
|
+
if (!ok) {
|
|
1814
|
+
throw new Error(`Current platform version "${args.currentPlatformVersion}" does not satisfy requirement "${supportedPlatformRange}"`);
|
|
1871
1815
|
}
|
|
1872
|
-
await assertPackageJsonExists(projectRoot);
|
|
1873
|
-
return detected.name;
|
|
1874
1816
|
}
|
|
1875
1817
|
async function assertPackageJsonExists(projectRoot) {
|
|
1876
1818
|
try {
|
|
1877
|
-
await
|
|
1819
|
+
await readFile8(`${projectRoot}/package.json`, "utf8");
|
|
1878
1820
|
} catch {
|
|
1879
1821
|
throw new Error(`File "package.json" not found in "${projectRoot}"`);
|
|
1880
1822
|
}
|
|
1881
1823
|
}
|
|
1882
|
-
|
|
1824
|
+
async function syncRootPulumiDependency(args) {
|
|
1825
|
+
const packageJsonPath = await resolvePackageJSON6(args.projectRoot);
|
|
1826
|
+
const packageJson = await readPackageJSON5(packageJsonPath);
|
|
1827
|
+
await writeJsonFile(packageJsonPath, {
|
|
1828
|
+
...packageJson,
|
|
1829
|
+
dependencies: {
|
|
1830
|
+
...packageJson.dependencies ?? {},
|
|
1831
|
+
"@pulumi/pulumi": args.pulumiVersion
|
|
1832
|
+
}
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1883
1835
|
export { BackendIdentityCommand, BackendUnlockMethodAddCommand, BackendUnlockMethodDeleteCommand, BackendUnlockMethodListCommand, BuildCommand, DesignerCommand, InitCommand, PackageCreateCommand, PackageListCommand, PackageRemoveCommand, PackageUpdateReferencesCommand, UpdateCommand };
|
|
1884
|
-
//# sourceMappingURL=chunk-KA6ZC6BV.js.map
|
|
1885
|
-
//# sourceMappingURL=chunk-KA6ZC6BV.js.map
|