@getmagical/cli 0.1.7 → 0.1.8
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/README.md +4 -0
- package/dist/index.js +271 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,6 +68,10 @@ Once installed, users can update from the same channel with:
|
|
|
68
68
|
mgcl --update
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
Installed CLIs also check the configured npm dist-tag before running
|
|
72
|
+
subcommands. If the local version is behind, `mgcl` blocks the command and
|
|
73
|
+
asks the user to run `mgcl update` before rerunning it.
|
|
74
|
+
|
|
71
75
|
To remove the managed install:
|
|
72
76
|
|
|
73
77
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -2546,6 +2546,9 @@ function isAppErrorCategory(category) {
|
|
|
2546
2546
|
return typeof category === "string" && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2547
2547
|
ORDERED_APP_ERROR_CATEGORIES.includes(category);
|
|
2548
2548
|
}
|
|
2549
|
+
function isNonEmptyAppErrorCategoryArray(categories) {
|
|
2550
|
+
return Array.isArray(categories) && categories.length > 0 && categories.every(isAppErrorCategory);
|
|
2551
|
+
}
|
|
2549
2552
|
var APP_ERROR_SEVERITIES = ["warn", "error", "fatal"];
|
|
2550
2553
|
function isAppErrorCode(code) {
|
|
2551
2554
|
return typeof code === "number" && Number.isInteger(code) && code >= 400 && code <= 599;
|
|
@@ -2583,42 +2586,55 @@ var AppError = class _AppError extends Error {
|
|
|
2583
2586
|
}
|
|
2584
2587
|
return type;
|
|
2585
2588
|
}
|
|
2586
|
-
static
|
|
2587
|
-
if (!cause || typeof cause !== "object" ||
|
|
2588
|
-
return
|
|
2589
|
+
static getInheritedCauseField(cause, extractor, seen = /* @__PURE__ */ new Set()) {
|
|
2590
|
+
if (!cause || typeof cause !== "object" || seen.has(cause)) {
|
|
2591
|
+
return void 0;
|
|
2589
2592
|
}
|
|
2590
|
-
|
|
2591
|
-
|
|
2593
|
+
const causeRecord = cause;
|
|
2594
|
+
const extractedValue = extractor(causeRecord);
|
|
2595
|
+
if (extractedValue !== void 0) {
|
|
2596
|
+
return extractedValue;
|
|
2592
2597
|
}
|
|
2593
|
-
return ["
|
|
2598
|
+
return _AppError.getInheritedCauseField(causeRecord["cause"], extractor, new Set(seen).add(cause));
|
|
2599
|
+
}
|
|
2600
|
+
static extractCategoriesFromCause(cause) {
|
|
2601
|
+
return _AppError.getInheritedCauseField(cause, (causeRecord) => {
|
|
2602
|
+
const { categories } = causeRecord;
|
|
2603
|
+
if (isNonEmptyAppErrorCategoryArray(categories)) {
|
|
2604
|
+
return categories;
|
|
2605
|
+
}
|
|
2606
|
+
return void 0;
|
|
2607
|
+
}) ?? ["internal_platform"];
|
|
2594
2608
|
}
|
|
2595
2609
|
static extractSeverityFromCause(cause) {
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2610
|
+
return _AppError.getInheritedCauseField(cause, (causeRecord) => {
|
|
2611
|
+
const { severity } = causeRecord;
|
|
2612
|
+
return isAppErrorSeverity(severity) ? severity : void 0;
|
|
2613
|
+
}) ?? "error";
|
|
2600
2614
|
}
|
|
2601
2615
|
static extractStatusCodeFromCause(cause) {
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2616
|
+
return _AppError.getInheritedCauseField(cause, (causeRecord) => {
|
|
2617
|
+
const { statusCode } = causeRecord;
|
|
2618
|
+
if (isAppErrorCode(statusCode)) {
|
|
2619
|
+
return statusCode;
|
|
2620
|
+
}
|
|
2621
|
+
const { code: legacyCode } = causeRecord;
|
|
2622
|
+
return isAppErrorCode(legacyCode) ? legacyCode : void 0;
|
|
2623
|
+
});
|
|
2609
2624
|
}
|
|
2610
2625
|
/** @deprecated Use statusCode instead. */
|
|
2611
2626
|
get code() {
|
|
2612
2627
|
return this.statusCode;
|
|
2613
2628
|
}
|
|
2614
2629
|
static extractSuggestedActionFromCause(cause) {
|
|
2615
|
-
|
|
2616
|
-
const
|
|
2617
|
-
if (
|
|
2618
|
-
return
|
|
2630
|
+
return _AppError.getInheritedCauseField(cause, (causeRecord) => {
|
|
2631
|
+
const { suggestedAction } = causeRecord;
|
|
2632
|
+
if (typeof suggestedAction !== "string") {
|
|
2633
|
+
return void 0;
|
|
2619
2634
|
}
|
|
2620
|
-
|
|
2621
|
-
|
|
2635
|
+
const trimmedSuggestedAction = suggestedAction.trim();
|
|
2636
|
+
return trimmedSuggestedAction.length > 0 ? trimmedSuggestedAction : void 0;
|
|
2637
|
+
});
|
|
2622
2638
|
}
|
|
2623
2639
|
static applyStack(error, stack, internalFrames) {
|
|
2624
2640
|
if (stack) {
|
|
@@ -3022,10 +3038,28 @@ import { spawn as spawn2 } from "child_process";
|
|
|
3022
3038
|
import fs from "fs";
|
|
3023
3039
|
import path3 from "path";
|
|
3024
3040
|
import { fileURLToPath } from "url";
|
|
3041
|
+
|
|
3042
|
+
// ../common/dist/src/stdlib/url.utils.js
|
|
3043
|
+
function safeUrlConstructor(url) {
|
|
3044
|
+
try {
|
|
3045
|
+
return Ok(new URL(url));
|
|
3046
|
+
} catch {
|
|
3047
|
+
return Err({
|
|
3048
|
+
type: "invalid-url",
|
|
3049
|
+
message: `Invalid URL`,
|
|
3050
|
+
url
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
// src/self-update.ts
|
|
3025
3056
|
var CLI_PACKAGE_NAME = "@getmagical/cli";
|
|
3026
3057
|
var DEFAULT_CLI_DIST_TAG2 = "latest";
|
|
3027
3058
|
var DEFAULT_NPM_REGISTRY_URL = "https://registry.npmjs.org/";
|
|
3028
3059
|
var MANAGED_NODE_SUBPATH = "runtime/node";
|
|
3060
|
+
function isRecord2(value) {
|
|
3061
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3062
|
+
}
|
|
3029
3063
|
function resolveInstalledPackageRoot({
|
|
3030
3064
|
entryFilePath,
|
|
3031
3065
|
packageName
|
|
@@ -3066,6 +3100,154 @@ function resolveInstallPrefixFromPackageRoot(packageRootPath) {
|
|
|
3066
3100
|
currentPath = parentPath;
|
|
3067
3101
|
}
|
|
3068
3102
|
}
|
|
3103
|
+
function readInstalledPackageVersion({
|
|
3104
|
+
packageName,
|
|
3105
|
+
packageRootPath
|
|
3106
|
+
}) {
|
|
3107
|
+
const packageManifestPath = path3.join(packageRootPath, "package.json");
|
|
3108
|
+
if (!fs.existsSync(packageManifestPath)) {
|
|
3109
|
+
throw new CliError(
|
|
3110
|
+
`Installed package metadata was not found at ${packageManifestPath}. Reinstall mgcl and try again.`
|
|
3111
|
+
);
|
|
3112
|
+
}
|
|
3113
|
+
const packageManifestResult = safeJsonParse(
|
|
3114
|
+
fs.readFileSync(packageManifestPath, "utf8")
|
|
3115
|
+
);
|
|
3116
|
+
if (isErr(packageManifestResult)) {
|
|
3117
|
+
throw new CliError(`Failed to parse ${packageManifestPath}.`, {
|
|
3118
|
+
cause: packageManifestResult.error.cause
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
const packageManifest = packageManifestResult.value;
|
|
3122
|
+
if (packageManifest.name !== packageName) {
|
|
3123
|
+
throw new CliError(
|
|
3124
|
+
`Expected installed package ${packageName} at ${packageManifestPath}. Reinstall mgcl and try again.`
|
|
3125
|
+
);
|
|
3126
|
+
}
|
|
3127
|
+
if (typeof packageManifest.version !== "string" || !packageManifest.version) {
|
|
3128
|
+
throw new CliError(
|
|
3129
|
+
`Installed package version is missing from ${packageManifestPath}. Reinstall mgcl and try again.`
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
return packageManifest.version;
|
|
3133
|
+
}
|
|
3134
|
+
function parseVersionSegment(segment, version) {
|
|
3135
|
+
if (!/^\d+$/u.test(segment)) {
|
|
3136
|
+
throw new CliError(`Invalid CLI version "${version}".`);
|
|
3137
|
+
}
|
|
3138
|
+
return Number(segment);
|
|
3139
|
+
}
|
|
3140
|
+
function parseSemanticVersion(version) {
|
|
3141
|
+
const normalizedVersion = version.trim().replace(/^v/u, "");
|
|
3142
|
+
const [versionWithoutBuildMetadata = ""] = normalizedVersion.split("+");
|
|
3143
|
+
if (!versionWithoutBuildMetadata) {
|
|
3144
|
+
throw new CliError(`Invalid CLI version "${version}".`);
|
|
3145
|
+
}
|
|
3146
|
+
const [releasePart, prereleasePart] = versionWithoutBuildMetadata.split("-");
|
|
3147
|
+
if (!releasePart) {
|
|
3148
|
+
throw new CliError(`Invalid CLI version "${version}".`);
|
|
3149
|
+
}
|
|
3150
|
+
return {
|
|
3151
|
+
prerelease: prereleasePart ? prereleasePart.split(".") : null,
|
|
3152
|
+
release: releasePart.split(".").map((segment) => parseVersionSegment(segment, version))
|
|
3153
|
+
};
|
|
3154
|
+
}
|
|
3155
|
+
function comparePrereleaseIdentifiers(left, right) {
|
|
3156
|
+
const leftIsNumeric = /^\d+$/u.test(left);
|
|
3157
|
+
const rightIsNumeric = /^\d+$/u.test(right);
|
|
3158
|
+
if (leftIsNumeric && rightIsNumeric) {
|
|
3159
|
+
return Number(left) - Number(right);
|
|
3160
|
+
}
|
|
3161
|
+
if (leftIsNumeric) {
|
|
3162
|
+
return -1;
|
|
3163
|
+
}
|
|
3164
|
+
if (rightIsNumeric) {
|
|
3165
|
+
return 1;
|
|
3166
|
+
}
|
|
3167
|
+
return left.localeCompare(right);
|
|
3168
|
+
}
|
|
3169
|
+
function compareSemanticVersions(leftVersion, rightVersion) {
|
|
3170
|
+
const left = parseSemanticVersion(leftVersion);
|
|
3171
|
+
const right = parseSemanticVersion(rightVersion);
|
|
3172
|
+
const releaseLength = Math.max(left.release.length, right.release.length);
|
|
3173
|
+
for (let index = 0; index < releaseLength; index += 1) {
|
|
3174
|
+
const difference = (left.release[index] ?? 0) - (right.release[index] ?? 0);
|
|
3175
|
+
if (difference !== 0) {
|
|
3176
|
+
return difference;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
if (!left.prerelease && !right.prerelease) {
|
|
3180
|
+
return 0;
|
|
3181
|
+
}
|
|
3182
|
+
if (!left.prerelease) {
|
|
3183
|
+
return 1;
|
|
3184
|
+
}
|
|
3185
|
+
if (!right.prerelease) {
|
|
3186
|
+
return -1;
|
|
3187
|
+
}
|
|
3188
|
+
const prereleaseLength = Math.max(
|
|
3189
|
+
left.prerelease.length,
|
|
3190
|
+
right.prerelease.length
|
|
3191
|
+
);
|
|
3192
|
+
for (let index = 0; index < prereleaseLength; index += 1) {
|
|
3193
|
+
const leftIdentifier = left.prerelease[index];
|
|
3194
|
+
const rightIdentifier = right.prerelease[index];
|
|
3195
|
+
if (leftIdentifier === void 0) {
|
|
3196
|
+
return -1;
|
|
3197
|
+
}
|
|
3198
|
+
if (rightIdentifier === void 0) {
|
|
3199
|
+
return 1;
|
|
3200
|
+
}
|
|
3201
|
+
const difference = comparePrereleaseIdentifiers(
|
|
3202
|
+
leftIdentifier,
|
|
3203
|
+
rightIdentifier
|
|
3204
|
+
);
|
|
3205
|
+
if (difference !== 0) {
|
|
3206
|
+
return difference;
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
return 0;
|
|
3210
|
+
}
|
|
3211
|
+
async function fetchPublishedPackageVersion({
|
|
3212
|
+
distTag,
|
|
3213
|
+
fetchFn = fetch,
|
|
3214
|
+
packageName,
|
|
3215
|
+
registryUrl
|
|
3216
|
+
}) {
|
|
3217
|
+
const distTagUrlResult = safeUrlConstructor(
|
|
3218
|
+
`${registryUrl.replace(/\/?$/u, "/")}-/package/${encodeURIComponent(packageName)}/dist-tags`
|
|
3219
|
+
);
|
|
3220
|
+
if (isErr(distTagUrlResult)) {
|
|
3221
|
+
throw new CliError(`Invalid npm registry URL "${registryUrl}".`);
|
|
3222
|
+
}
|
|
3223
|
+
const response = await fetchFn(distTagUrlResult.value, {
|
|
3224
|
+
headers: {
|
|
3225
|
+
accept: "application/json"
|
|
3226
|
+
}
|
|
3227
|
+
});
|
|
3228
|
+
if (!response.ok) {
|
|
3229
|
+
throw new CliError(
|
|
3230
|
+
`Could not check the latest published mgcl version (status ${response.status}).`
|
|
3231
|
+
);
|
|
3232
|
+
}
|
|
3233
|
+
const distTagsResult = safeJsonParse(await response.text());
|
|
3234
|
+
if (isErr(distTagsResult)) {
|
|
3235
|
+
throw new CliError("Could not parse the npm dist-tags response for mgcl.", {
|
|
3236
|
+
cause: distTagsResult.error.cause
|
|
3237
|
+
});
|
|
3238
|
+
}
|
|
3239
|
+
if (!isRecord2(distTagsResult.value)) {
|
|
3240
|
+
throw new CliError("Could not parse the npm dist-tags response for mgcl.");
|
|
3241
|
+
}
|
|
3242
|
+
const distTags = distTagsResult.value;
|
|
3243
|
+
const publishedVersion = distTags[distTag];
|
|
3244
|
+
if (typeof publishedVersion !== "string" || publishedVersion.length === 0) {
|
|
3245
|
+
throw new CliError(
|
|
3246
|
+
`Could not find npm dist-tag "${distTag}" for ${packageName}.`
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
return publishedVersion;
|
|
3250
|
+
}
|
|
3069
3251
|
function resolveNpmCommandFromPath() {
|
|
3070
3252
|
return {
|
|
3071
3253
|
argsPrefix: [],
|
|
@@ -3179,18 +3361,44 @@ async function selfUpdateInstalledCli({
|
|
|
3179
3361
|
registryUrl
|
|
3180
3362
|
});
|
|
3181
3363
|
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3364
|
+
async function getInstalledCliUpdateRequirement({
|
|
3365
|
+
distTag = DEFAULT_CLI_DIST_TAG2,
|
|
3366
|
+
entryFilePath = fileURLToPath(import.meta.url),
|
|
3367
|
+
fetchFn = fetch,
|
|
3368
|
+
packageName = CLI_PACKAGE_NAME,
|
|
3369
|
+
registryUrl = DEFAULT_NPM_REGISTRY_URL
|
|
3370
|
+
} = {}) {
|
|
3371
|
+
const packageRootPath = resolveInstalledPackageRoot({
|
|
3372
|
+
entryFilePath,
|
|
3373
|
+
packageName
|
|
3374
|
+
});
|
|
3375
|
+
if (!packageRootPath) {
|
|
3376
|
+
return null;
|
|
3377
|
+
}
|
|
3378
|
+
const installedVersion = readInstalledPackageVersion({
|
|
3379
|
+
packageName,
|
|
3380
|
+
packageRootPath
|
|
3381
|
+
});
|
|
3382
|
+
const publishedVersionResult = await fromThrowable(
|
|
3383
|
+
async () => fetchPublishedPackageVersion({
|
|
3384
|
+
distTag,
|
|
3385
|
+
fetchFn,
|
|
3386
|
+
packageName,
|
|
3387
|
+
registryUrl
|
|
3388
|
+
}),
|
|
3389
|
+
"cli-update-check-failed"
|
|
3390
|
+
);
|
|
3391
|
+
if (isErr(publishedVersionResult)) {
|
|
3392
|
+
return null;
|
|
3393
|
+
}
|
|
3394
|
+
const publishedVersion = publishedVersionResult.value;
|
|
3395
|
+
if (compareSemanticVersions(installedVersion, publishedVersion) >= 0) {
|
|
3396
|
+
return null;
|
|
3193
3397
|
}
|
|
3398
|
+
return {
|
|
3399
|
+
installedVersion,
|
|
3400
|
+
latestVersion: publishedVersion
|
|
3401
|
+
};
|
|
3194
3402
|
}
|
|
3195
3403
|
|
|
3196
3404
|
// src/settings-command.ts
|
|
@@ -3555,7 +3763,7 @@ function parseCommandOptionValue(rawValue, optionSpec) {
|
|
|
3555
3763
|
}
|
|
3556
3764
|
}
|
|
3557
3765
|
}
|
|
3558
|
-
function
|
|
3766
|
+
function isRecord3(value) {
|
|
3559
3767
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3560
3768
|
}
|
|
3561
3769
|
function resolveOrganizationBySelector({
|
|
@@ -3615,7 +3823,7 @@ function collectOperationVariables(operationSpec, options) {
|
|
|
3615
3823
|
parsedVariables.error.issues[0]?.message ?? "Invalid command input."
|
|
3616
3824
|
);
|
|
3617
3825
|
}
|
|
3618
|
-
if (!
|
|
3826
|
+
if (!isRecord3(parsedVariables.data)) {
|
|
3619
3827
|
throw new CliError("Invalid command input.");
|
|
3620
3828
|
}
|
|
3621
3829
|
return parsedVariables.data;
|
|
@@ -3718,6 +3926,25 @@ async function handleSelfUpdate(dependencies, options) {
|
|
|
3718
3926
|
`Updated mgcl via npm (${updateResult.packageSpecifier}) in ${updateResult.installPrefix}.`
|
|
3719
3927
|
);
|
|
3720
3928
|
}
|
|
3929
|
+
function isRootUpdateCommand(program2, actionCommand) {
|
|
3930
|
+
return actionCommand.parent === program2 && actionCommand.name() === "update";
|
|
3931
|
+
}
|
|
3932
|
+
async function enforceLatestCliVersionIfNeeded({
|
|
3933
|
+
dependencies,
|
|
3934
|
+
program: program2,
|
|
3935
|
+
actionCommand
|
|
3936
|
+
}) {
|
|
3937
|
+
if (actionCommand === program2 || isRootUpdateCommand(program2, actionCommand)) {
|
|
3938
|
+
return;
|
|
3939
|
+
}
|
|
3940
|
+
const updateRequirement = await dependencies.ensureLatestCliVersion?.();
|
|
3941
|
+
if (!updateRequirement) {
|
|
3942
|
+
return;
|
|
3943
|
+
}
|
|
3944
|
+
throw new CliError(
|
|
3945
|
+
`mgcl ${updateRequirement.installedVersion} is outdated. Upgrade to ${updateRequirement.latestVersion} with "mgcl update", then rerun your command.`
|
|
3946
|
+
);
|
|
3947
|
+
}
|
|
3721
3948
|
async function handleOperationCommand(dependencies, operationSpec, commandOptions) {
|
|
3722
3949
|
const state = requireLoggedInState(await dependencies.stateStore.load());
|
|
3723
3950
|
const organization = resolveSelectedOrganization({
|
|
@@ -3862,6 +4089,7 @@ function createDefaultDependencies() {
|
|
|
3862
4089
|
refreshTokenStore: createKeytarRefreshTokenStore(
|
|
3863
4090
|
runtimeConfig.keychainServiceName
|
|
3864
4091
|
),
|
|
4092
|
+
ensureLatestCliVersion: async () => getInstalledCliUpdateRequirement(selfUpdateOptions),
|
|
3865
4093
|
runtimeConfig,
|
|
3866
4094
|
settingsStore,
|
|
3867
4095
|
selfUpdateCli: async () => selfUpdateInstalledCli(selfUpdateOptions),
|
|
@@ -3897,6 +4125,13 @@ ${formatOutputModesNote()}`
|
|
|
3897
4125
|
}
|
|
3898
4126
|
this.outputHelp();
|
|
3899
4127
|
});
|
|
4128
|
+
program2.hook("preAction", async (_command, actionCommand) => {
|
|
4129
|
+
await enforceLatestCliVersionIfNeeded({
|
|
4130
|
+
actionCommand,
|
|
4131
|
+
dependencies,
|
|
4132
|
+
program: program2
|
|
4133
|
+
});
|
|
4134
|
+
});
|
|
3900
4135
|
const authCommand = configureCommandPresentation(
|
|
3901
4136
|
new Command2("auth").description("Manage CLI authentication.")
|
|
3902
4137
|
).helpGroup("Workspace:").addHelpText(
|