@shopify/cli-kit 3.94.3 → 4.1.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/README.md +2 -2
- package/dist/private/node/api/headers.js +2 -2
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/conf-store.d.ts +3 -2
- package/dist/private/node/conf-store.js +3 -2
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/private/node/constants.d.ts +1 -1
- package/dist/private/node/constants.js +1 -1
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/ui/components/Alert.test.js +29 -0
- package/dist/private/node/ui/components/Alert.test.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.d.ts +8 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js +3 -2
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +16 -0
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.js +6 -1
- package/dist/private/node/ui/components/FatalError.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.test.js +28 -0
- package/dist/private/node/ui/components/FatalError.test.js.map +1 -1
- package/dist/private/node/ui/components/Link.js +8 -4
- package/dist/private/node/ui/components/Link.js.map +1 -1
- package/dist/private/node/ui/components/Link.test.js +45 -0
- package/dist/private/node/ui/components/Link.test.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.js +61 -2
- package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.test.js +109 -2
- package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
- package/dist/public/common/string.js +22 -25
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/base-command.js +23 -14
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli-launcher.d.ts +2 -0
- package/dist/public/node/cli-launcher.js +7 -3
- package/dist/public/node/cli-launcher.js.map +1 -1
- package/dist/public/node/cli.d.ts +5 -1
- package/dist/public/node/cli.js +3 -3
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/context/local.d.ts +1 -8
- package/dist/public/node/context/local.js +34 -15
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/custom-oclif-loader.d.ts +31 -0
- package/dist/public/node/custom-oclif-loader.js +45 -0
- package/dist/public/node/custom-oclif-loader.js.map +1 -0
- package/dist/public/node/error.d.ts +1 -1
- package/dist/public/node/error.js +1 -1
- package/dist/public/node/error.js.map +1 -1
- package/dist/public/node/fs.js +12 -16
- package/dist/public/node/fs.js.map +1 -1
- package/dist/public/node/git.js +9 -3
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/hooks/postrun.d.ts +15 -0
- package/dist/public/node/hooks/postrun.js +75 -14
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/hooks/prerun.d.ts +1 -1
- package/dist/public/node/hooks/prerun.js +17 -10
- package/dist/public/node/hooks/prerun.js.map +1 -1
- package/dist/public/node/import-extractor.js +4 -3
- package/dist/public/node/import-extractor.js.map +1 -1
- package/dist/public/node/is-global.d.ts +1 -1
- package/dist/public/node/is-global.js +27 -11
- package/dist/public/node/is-global.js.map +1 -1
- package/dist/public/node/monorail.d.ts +2 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +2 -2
- package/dist/public/node/node-package-manager.js +10 -10
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/notifications-system.d.ts +6 -6
- package/dist/public/node/output.js +2 -0
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/path.js +0 -2
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/session.d.ts +6 -0
- package/dist/public/node/session.js +8 -0
- package/dist/public/node/session.js.map +1 -1
- package/dist/public/node/system.js +19 -42
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/tree-kill.js +17 -5
- package/dist/public/node/tree-kill.js.map +1 -1
- package/dist/public/node/ui.js +6 -0
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/upgrade.d.ts +27 -8
- package/dist/public/node/upgrade.js +50 -21
- package/dist/public/node/upgrade.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import * as metadata from '../metadata.js';
|
|
7
|
-
import { runAtMinimumInterval } from '../../../private/node/conf-store.js';
|
|
8
|
-
import { CLI_KIT_VERSION } from '../../common/version.js';
|
|
9
|
-
import { isMajorVersionChange } from '../version.js';
|
|
1
|
+
/**
|
|
2
|
+
* Postrun hook — uses dynamic imports to avoid loading heavy modules (base-command, analytics)
|
|
3
|
+
* at module evaluation time. These are only needed after the command has already finished.
|
|
4
|
+
*/
|
|
5
|
+
import { treeKill } from '../tree-kill.js';
|
|
10
6
|
let postRunHookCompleted = false;
|
|
11
7
|
/**
|
|
12
8
|
* Check if post run hook has completed.
|
|
@@ -16,16 +12,54 @@ let postRunHookCompleted = false;
|
|
|
16
12
|
export function postRunHookHasCompleted() {
|
|
17
13
|
return postRunHookCompleted;
|
|
18
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Wait for the postrun hook to finish (so auto-upgrade has a chance to run) and then
|
|
17
|
+
* tree-kill the current process tree before exiting.
|
|
18
|
+
*
|
|
19
|
+
* Long-running interactive commands like `app dev` need this when the user terminates
|
|
20
|
+
* the command via `q` or Ctrl+C. The dev sub-processes such as servers and watchers keep
|
|
21
|
+
* the event loop alive, so even after oclif's postrun hook completes the node process
|
|
22
|
+
* won't exit on its own and we have to `treeKill` the process tree. We must not do that
|
|
23
|
+
* before the postrun hook has actually finished running auto-upgrade, otherwise we would
|
|
24
|
+
* kill the upgrade mid-way while `npm install` is still running.
|
|
25
|
+
*
|
|
26
|
+
* The flag `postRunHookCompleted` is flipped at the very end of the hook after
|
|
27
|
+
* `autoUpgradeIfNeeded` resolves, so polling it here is safe.
|
|
28
|
+
*/
|
|
29
|
+
export function waitForPostRunHookAndExit() {
|
|
30
|
+
const pollIntervalMs = 100;
|
|
31
|
+
// Auto-upgrade can take a while (npm/pnpm/yarn install). Cap the wait generously so
|
|
32
|
+
// a stuck upgrade still terminates the process eventually.
|
|
33
|
+
const maxWaitMs = 120000;
|
|
34
|
+
let elapsed = 0;
|
|
35
|
+
let terminating = false;
|
|
36
|
+
const handle = setInterval(() => {
|
|
37
|
+
if (terminating)
|
|
38
|
+
return;
|
|
39
|
+
if (postRunHookHasCompleted() || elapsed >= maxWaitMs) {
|
|
40
|
+
terminating = true;
|
|
41
|
+
clearInterval(handle);
|
|
42
|
+
treeKill(process.pid, 'SIGINT', false, () => {
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
elapsed += pollIntervalMs;
|
|
48
|
+
}, pollIntervalMs);
|
|
49
|
+
}
|
|
19
50
|
// This hook is called after each successful command run. More info: https://oclif.io/docs/hooks
|
|
20
51
|
export const hook = async ({ config, Command }) => {
|
|
21
52
|
await detectStopCommand(Command);
|
|
53
|
+
const { reportAnalyticsEvent } = await import('../analytics.js');
|
|
22
54
|
await reportAnalyticsEvent({ config, exitMode: 'ok' });
|
|
55
|
+
const { postrun: deprecationsHook } = await import('./deprecations.js');
|
|
23
56
|
deprecationsHook(Command);
|
|
57
|
+
const { outputDebug } = await import('../output.js');
|
|
24
58
|
const command = Command.id.replace(/:/g, ' ');
|
|
25
59
|
outputDebug(`Completed command ${command}`);
|
|
26
|
-
postRunHookCompleted = true;
|
|
27
60
|
if (!command.includes('notifications') && !command.includes('upgrade'))
|
|
28
61
|
await autoUpgradeIfNeeded();
|
|
62
|
+
postRunHookCompleted = true;
|
|
29
63
|
};
|
|
30
64
|
/**
|
|
31
65
|
* Auto-upgrades the CLI after a command completes, if a newer version is available.
|
|
@@ -34,6 +68,7 @@ export const hook = async ({ config, Command }) => {
|
|
|
34
68
|
* @returns Resolves when the upgrade attempt (or fallback warning) is complete.
|
|
35
69
|
*/
|
|
36
70
|
export async function autoUpgradeIfNeeded() {
|
|
71
|
+
const { versionToAutoUpgrade, warnIfUpgradeAvailable } = await import('../upgrade.js');
|
|
37
72
|
const newerVersion = versionToAutoUpgrade();
|
|
38
73
|
if (!newerVersion) {
|
|
39
74
|
await warnIfUpgradeAvailable();
|
|
@@ -45,6 +80,7 @@ export async function autoUpgradeIfNeeded() {
|
|
|
45
80
|
await performAutoUpgrade(newerVersion);
|
|
46
81
|
}
|
|
47
82
|
else {
|
|
83
|
+
const { runAtMinimumInterval } = await import('../../../private/node/conf-store.js');
|
|
48
84
|
// Rate-limit the entire upgrade flow to once per day to avoid repeated attempts and major-version warnings.
|
|
49
85
|
await runAtMinimumInterval('auto-upgrade', { days: 1 }, async () => {
|
|
50
86
|
await performAutoUpgrade(newerVersion);
|
|
@@ -52,6 +88,13 @@ export async function autoUpgradeIfNeeded() {
|
|
|
52
88
|
}
|
|
53
89
|
}
|
|
54
90
|
async function performAutoUpgrade(newerVersion) {
|
|
91
|
+
const [{ CLI_KIT_VERSION }, { isMajorVersionChange }, { outputWarn, outputDebug }, { getOutputUpdateCLIReminder, runCLIUpgrade, hasBlockingAutoUpgradeNotification }, metadata,] = await Promise.all([
|
|
92
|
+
import('../../common/version.js'),
|
|
93
|
+
import('../version.js'),
|
|
94
|
+
import('../output.js'),
|
|
95
|
+
import('../upgrade.js'),
|
|
96
|
+
import('../metadata.js'),
|
|
97
|
+
]);
|
|
55
98
|
if (isMajorVersionChange(CLI_KIT_VERSION, newerVersion)) {
|
|
56
99
|
outputWarn(getOutputUpdateCLIReminder(newerVersion, true));
|
|
57
100
|
await metadata.addPublicMetadata(() => ({
|
|
@@ -59,8 +102,18 @@ async function performAutoUpgrade(newerVersion) {
|
|
|
59
102
|
}));
|
|
60
103
|
return;
|
|
61
104
|
}
|
|
105
|
+
// Notification kill switch: an `error`-type notification on the `autoupgrade` surface
|
|
106
|
+
// silently disables auto-upgrade. Checked last — after every other gate, including the
|
|
107
|
+
// daily rate limit and the major-version check — so the network fetch only happens when
|
|
108
|
+
// we're about to actually run the upgrade.
|
|
109
|
+
if (await hasBlockingAutoUpgradeNotification()) {
|
|
110
|
+
await metadata.addPublicMetadata(() => ({
|
|
111
|
+
env_auto_upgrade_skipped_reason: 'blocked_by_notification',
|
|
112
|
+
}));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
62
115
|
try {
|
|
63
|
-
await runCLIUpgrade();
|
|
116
|
+
await runCLIUpgrade({ autoupgrade: true });
|
|
64
117
|
await metadata.addPublicMetadata(() => ({ env_auto_upgrade_success: true }));
|
|
65
118
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
66
119
|
}
|
|
@@ -70,7 +123,10 @@ async function performAutoUpgrade(newerVersion) {
|
|
|
70
123
|
outputWarn(getOutputUpdateCLIReminder(newerVersion));
|
|
71
124
|
await metadata.addPublicMetadata(() => ({ env_auto_upgrade_success: false }));
|
|
72
125
|
// Report to Observe as a handled error without showing anything extra to the user
|
|
73
|
-
const { sendErrorToBugsnag } = await
|
|
126
|
+
const [{ sendErrorToBugsnag }, { inferPackageManagerForGlobalCLI }] = await Promise.all([
|
|
127
|
+
import('../error-handler.js'),
|
|
128
|
+
import('../is-global.js'),
|
|
129
|
+
]);
|
|
74
130
|
const enrichedError = Object.assign(new Error(errorMessage), {
|
|
75
131
|
packageManager: inferPackageManagerForGlobalCLI(),
|
|
76
132
|
platform: process.platform,
|
|
@@ -82,13 +138,18 @@ async function performAutoUpgrade(newerVersion) {
|
|
|
82
138
|
/**
|
|
83
139
|
* Override the command name with the stop one for analytics purposes.
|
|
84
140
|
*
|
|
85
|
-
* @param commandClass -
|
|
141
|
+
* @param commandClass - Command.Class.
|
|
86
142
|
*/
|
|
87
143
|
async function detectStopCommand(commandClass) {
|
|
88
144
|
const currentTime = new Date().getTime();
|
|
89
|
-
|
|
145
|
+
// Check for analyticsStopCommand without importing BaseCommand
|
|
146
|
+
if (commandClass &&
|
|
147
|
+
'analyticsStopCommand' in commandClass &&
|
|
148
|
+
typeof commandClass.analyticsStopCommand === 'function') {
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
150
|
const stopCommand = commandClass.analyticsStopCommand();
|
|
91
151
|
if (stopCommand) {
|
|
152
|
+
const metadata = await import('../metadata.js');
|
|
92
153
|
const { commandStartOptions } = metadata.getAllSensitiveMetadata();
|
|
93
154
|
if (!commandStartOptions)
|
|
94
155
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postrun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/postrun.ts"],"names":[],"mappings":"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","sourcesContent":["import {postrun as deprecationsHook} from './deprecations.js'\nimport {reportAnalyticsEvent} from '../analytics.js'\nimport {outputDebug, outputWarn} from '../output.js'\nimport {getOutputUpdateCLIReminder, runCLIUpgrade, versionToAutoUpgrade, warnIfUpgradeAvailable} from '../upgrade.js'\nimport {inferPackageManagerForGlobalCLI} from '../is-global.js'\nimport BaseCommand from '../base-command.js'\nimport * as metadata from '../metadata.js'\nimport {runAtMinimumInterval} from '../../../private/node/conf-store.js'\nimport {CLI_KIT_VERSION} from '../../common/version.js'\nimport {isMajorVersionChange} from '../version.js'\nimport {Command, Hook} from '@oclif/core'\n\nlet postRunHookCompleted = false\n\n/**\n * Check if post run hook has completed.\n *\n * @returns Whether post run hook has completed.\n */\nexport function postRunHookHasCompleted(): boolean {\n return postRunHookCompleted\n}\n\n// This hook is called after each successful command run. More info: https://oclif.io/docs/hooks\nexport const hook: Hook.Postrun = async ({config, Command}) => {\n await detectStopCommand(Command as unknown as typeof Command)\n await reportAnalyticsEvent({config, exitMode: 'ok'})\n deprecationsHook(Command)\n\n const command = Command.id.replace(/:/g, ' ')\n outputDebug(`Completed command ${command}`)\n postRunHookCompleted = true\n\n if (!command.includes('notifications') && !command.includes('upgrade')) await autoUpgradeIfNeeded()\n}\n\n/**\n * Auto-upgrades the CLI after a command completes, if a newer version is available.\n * The entire flow is rate-limited to once per day unless forced via SHOPIFY_CLI_FORCE_AUTO_UPGRADE.\n *\n * @returns Resolves when the upgrade attempt (or fallback warning) is complete.\n */\nexport async function autoUpgradeIfNeeded(): Promise<void> {\n const newerVersion = versionToAutoUpgrade()\n if (!newerVersion) {\n await warnIfUpgradeAvailable()\n return\n }\n\n const forced = process.env.SHOPIFY_CLI_FORCE_AUTO_UPGRADE === '1'\n\n // SHOPIFY_CLI_FORCE_AUTO_UPGRADE bypasses the daily rate limit so tests and intentional upgrades always run.\n if (forced) {\n await performAutoUpgrade(newerVersion)\n } else {\n // Rate-limit the entire upgrade flow to once per day to avoid repeated attempts and major-version warnings.\n await runAtMinimumInterval('auto-upgrade', {days: 1}, async () => {\n await performAutoUpgrade(newerVersion)\n })\n }\n}\n\nasync function performAutoUpgrade(newerVersion: string): Promise<void> {\n if (isMajorVersionChange(CLI_KIT_VERSION, newerVersion)) {\n outputWarn(getOutputUpdateCLIReminder(newerVersion, true))\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'major_version',\n }))\n return\n }\n\n try {\n await runCLIUpgrade()\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: true}))\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n const errorMessage = `Auto-upgrade failed: ${error}`\n outputDebug(errorMessage)\n outputWarn(getOutputUpdateCLIReminder(newerVersion))\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: false}))\n // Report to Observe as a handled error without showing anything extra to the user\n const {sendErrorToBugsnag} = await import('../error-handler.js')\n const enrichedError = Object.assign(new Error(errorMessage), {\n packageManager: inferPackageManagerForGlobalCLI(),\n platform: process.platform,\n cliVersion: CLI_KIT_VERSION,\n })\n await sendErrorToBugsnag(enrichedError, 'expected_error')\n }\n}\n\n/**\n * Override the command name with the stop one for analytics purposes.\n *\n * @param commandClass - Oclif command class.\n */\nasync function detectStopCommand(commandClass: Command.Class | typeof BaseCommand): Promise<void> {\n const currentTime = new Date().getTime()\n if (commandClass && Object.prototype.hasOwnProperty.call(commandClass, 'analyticsStopCommand')) {\n const stopCommand = (commandClass as typeof BaseCommand).analyticsStopCommand()\n if (stopCommand) {\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n if (!commandStartOptions) return\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n ...commandStartOptions,\n startTime: currentTime,\n startCommand: stopCommand,\n },\n }))\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"postrun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/postrun.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Postrun hook — uses dynamic imports to avoid loading heavy modules (base-command, analytics)\n * at module evaluation time. These are only needed after the command has already finished.\n */\nimport {treeKill} from '../tree-kill.js'\nimport {Command, Hook} from '@oclif/core'\n\nlet postRunHookCompleted = false\n\n/**\n * Check if post run hook has completed.\n *\n * @returns Whether post run hook has completed.\n */\nexport function postRunHookHasCompleted(): boolean {\n return postRunHookCompleted\n}\n\n/**\n * Wait for the postrun hook to finish (so auto-upgrade has a chance to run) and then\n * tree-kill the current process tree before exiting.\n *\n * Long-running interactive commands like `app dev` need this when the user terminates\n * the command via `q` or Ctrl+C. The dev sub-processes such as servers and watchers keep\n * the event loop alive, so even after oclif's postrun hook completes the node process\n * won't exit on its own and we have to `treeKill` the process tree. We must not do that\n * before the postrun hook has actually finished running auto-upgrade, otherwise we would\n * kill the upgrade mid-way while `npm install` is still running.\n *\n * The flag `postRunHookCompleted` is flipped at the very end of the hook after\n * `autoUpgradeIfNeeded` resolves, so polling it here is safe.\n */\nexport function waitForPostRunHookAndExit(): void {\n const pollIntervalMs = 100\n // Auto-upgrade can take a while (npm/pnpm/yarn install). Cap the wait generously so\n // a stuck upgrade still terminates the process eventually.\n const maxWaitMs = 120000\n\n let elapsed = 0\n let terminating = false\n const handle = setInterval(() => {\n if (terminating) return\n if (postRunHookHasCompleted() || elapsed >= maxWaitMs) {\n terminating = true\n clearInterval(handle)\n treeKill(process.pid, 'SIGINT', false, () => {\n process.exit(0)\n })\n return\n }\n elapsed += pollIntervalMs\n }, pollIntervalMs)\n}\n\n// This hook is called after each successful command run. More info: https://oclif.io/docs/hooks\nexport const hook: Hook.Postrun = async ({config, Command}) => {\n await detectStopCommand(Command as unknown as typeof Command)\n\n const {reportAnalyticsEvent} = await import('../analytics.js')\n await reportAnalyticsEvent({config, exitMode: 'ok'})\n\n const {postrun: deprecationsHook} = await import('./deprecations.js')\n deprecationsHook(Command)\n\n const {outputDebug} = await import('../output.js')\n const command = Command.id.replace(/:/g, ' ')\n outputDebug(`Completed command ${command}`)\n\n if (!command.includes('notifications') && !command.includes('upgrade')) await autoUpgradeIfNeeded()\n postRunHookCompleted = true\n}\n\n/**\n * Auto-upgrades the CLI after a command completes, if a newer version is available.\n * The entire flow is rate-limited to once per day unless forced via SHOPIFY_CLI_FORCE_AUTO_UPGRADE.\n *\n * @returns Resolves when the upgrade attempt (or fallback warning) is complete.\n */\nexport async function autoUpgradeIfNeeded(): Promise<void> {\n const {versionToAutoUpgrade, warnIfUpgradeAvailable} = await import('../upgrade.js')\n const newerVersion = versionToAutoUpgrade()\n if (!newerVersion) {\n await warnIfUpgradeAvailable()\n return\n }\n\n const forced = process.env.SHOPIFY_CLI_FORCE_AUTO_UPGRADE === '1'\n\n // SHOPIFY_CLI_FORCE_AUTO_UPGRADE bypasses the daily rate limit so tests and intentional upgrades always run.\n if (forced) {\n await performAutoUpgrade(newerVersion)\n } else {\n const {runAtMinimumInterval} = await import('../../../private/node/conf-store.js')\n // Rate-limit the entire upgrade flow to once per day to avoid repeated attempts and major-version warnings.\n await runAtMinimumInterval('auto-upgrade', {days: 1}, async () => {\n await performAutoUpgrade(newerVersion)\n })\n }\n}\n\nasync function performAutoUpgrade(newerVersion: string): Promise<void> {\n const [\n {CLI_KIT_VERSION},\n {isMajorVersionChange},\n {outputWarn, outputDebug},\n {getOutputUpdateCLIReminder, runCLIUpgrade, hasBlockingAutoUpgradeNotification},\n metadata,\n ] = await Promise.all([\n import('../../common/version.js'),\n import('../version.js'),\n import('../output.js'),\n import('../upgrade.js'),\n import('../metadata.js'),\n ])\n\n if (isMajorVersionChange(CLI_KIT_VERSION, newerVersion)) {\n outputWarn(getOutputUpdateCLIReminder(newerVersion, true))\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'major_version',\n }))\n return\n }\n\n // Notification kill switch: an `error`-type notification on the `autoupgrade` surface\n // silently disables auto-upgrade. Checked last — after every other gate, including the\n // daily rate limit and the major-version check — so the network fetch only happens when\n // we're about to actually run the upgrade.\n if (await hasBlockingAutoUpgradeNotification()) {\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'blocked_by_notification',\n }))\n return\n }\n\n try {\n await runCLIUpgrade({autoupgrade: true})\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: true}))\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n const errorMessage = `Auto-upgrade failed: ${error}`\n outputDebug(errorMessage)\n outputWarn(getOutputUpdateCLIReminder(newerVersion))\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: false}))\n // Report to Observe as a handled error without showing anything extra to the user\n const [{sendErrorToBugsnag}, {inferPackageManagerForGlobalCLI}] = await Promise.all([\n import('../error-handler.js'),\n import('../is-global.js'),\n ])\n const enrichedError = Object.assign(new Error(errorMessage), {\n packageManager: inferPackageManagerForGlobalCLI(),\n platform: process.platform,\n cliVersion: CLI_KIT_VERSION,\n })\n await sendErrorToBugsnag(enrichedError, 'expected_error')\n }\n}\n\n/**\n * Override the command name with the stop one for analytics purposes.\n *\n * @param commandClass - Command.Class.\n */\nasync function detectStopCommand(commandClass: Command.Class): Promise<void> {\n const currentTime = new Date().getTime()\n // Check for analyticsStopCommand without importing BaseCommand\n if (\n commandClass &&\n 'analyticsStopCommand' in commandClass &&\n typeof commandClass.analyticsStopCommand === 'function'\n ) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stopCommand = (commandClass as any).analyticsStopCommand()\n if (stopCommand) {\n const metadata = await import('../metadata.js')\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n if (!commandStartOptions) return\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n ...commandStartOptions,\n startTime: currentTime,\n startCommand: stopCommand,\n },\n }))\n }\n }\n}\n"]}
|
|
@@ -14,4 +14,4 @@ export declare function parseCommandContent(cmdInfo: {
|
|
|
14
14
|
* Triggers a background check for a newer CLI version (non-blocking).
|
|
15
15
|
* The result is cached and consumed by the postrun hook for auto-upgrade.
|
|
16
16
|
*/
|
|
17
|
-
export declare function checkForNewVersionInBackground(): void
|
|
17
|
+
export declare function checkForNewVersionInBackground(): Promise<void>;
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { CLI_KIT_VERSION } from '../../common/version.js';
|
|
2
|
-
import { isPreReleaseVersion } from '../version.js';
|
|
3
|
-
import { checkForNewVersion } from '../node-package-manager.js';
|
|
4
|
-
import { startAnalytics } from '../../../private/node/analytics.js';
|
|
5
|
-
import { outputDebug } from '../output.js';
|
|
6
|
-
import { fetchNotificationsInBackground } from '../notifications-system.js';
|
|
7
1
|
// This hook is called before each command run. More info: https://oclif.io/docs/hooks
|
|
8
2
|
export const hook = async (options) => {
|
|
9
3
|
const commandContent = parseCommandContent({
|
|
@@ -12,10 +6,18 @@ export const hook = async (options) => {
|
|
|
12
6
|
pluginAlias: options.Command.plugin?.alias,
|
|
13
7
|
});
|
|
14
8
|
const args = options.argv;
|
|
15
|
-
|
|
9
|
+
// Load heavy modules in parallel
|
|
10
|
+
const [{ outputDebug }, analyticsMod, notificationsMod] = await Promise.all([
|
|
11
|
+
import('../output.js'),
|
|
12
|
+
import('../../../private/node/analytics.js'),
|
|
13
|
+
import('../notifications-system.js'),
|
|
14
|
+
]);
|
|
15
|
+
// Fire upgrade check in background (non-blocking)
|
|
16
|
+
// eslint-disable-next-line no-void
|
|
17
|
+
void checkForNewVersionInBackground();
|
|
16
18
|
outputDebug(`Running command ${commandContent.command}`);
|
|
17
|
-
await startAnalytics({ commandContent, args, commandClass: options.Command });
|
|
18
|
-
fetchNotificationsInBackground(options.Command.id);
|
|
19
|
+
await analyticsMod.startAnalytics({ commandContent, args, commandClass: options.Command });
|
|
20
|
+
notificationsMod.fetchNotificationsInBackground(options.Command.id);
|
|
19
21
|
};
|
|
20
22
|
export function parseCommandContent(cmdInfo) {
|
|
21
23
|
let commandContent = parseCreateCommand(cmdInfo.pluginAlias);
|
|
@@ -71,7 +73,12 @@ function findAlias(aliases) {
|
|
|
71
73
|
* Triggers a background check for a newer CLI version (non-blocking).
|
|
72
74
|
* The result is cached and consumed by the postrun hook for auto-upgrade.
|
|
73
75
|
*/
|
|
74
|
-
export function checkForNewVersionInBackground() {
|
|
76
|
+
export async function checkForNewVersionInBackground() {
|
|
77
|
+
const [{ CLI_KIT_VERSION }, { isPreReleaseVersion }, { checkForNewVersion }] = await Promise.all([
|
|
78
|
+
import('../../common/version.js'),
|
|
79
|
+
import('../version.js'),
|
|
80
|
+
import('../node-package-manager.js'),
|
|
81
|
+
]);
|
|
75
82
|
const currentVersion = CLI_KIT_VERSION;
|
|
76
83
|
if (isPreReleaseVersion(currentVersion)) {
|
|
77
84
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/prerun.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prerun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/prerun.ts"],"names":[],"mappings":"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","sourcesContent":["import {Hook} from '@oclif/core'\n\nexport declare interface CommandContent {\n command: string\n topic?: string\n alias?: string\n}\n\n// This hook is called before each command run. More info: https://oclif.io/docs/hooks\nexport const hook: Hook.Prerun = async (options) => {\n const commandContent = parseCommandContent({\n id: options.Command.id,\n aliases: options.Command.aliases,\n pluginAlias: options.Command.plugin?.alias,\n })\n const args = options.argv\n\n // Load heavy modules in parallel\n const [{outputDebug}, analyticsMod, notificationsMod] = await Promise.all([\n import('../output.js'),\n import('../../../private/node/analytics.js'),\n import('../notifications-system.js'),\n ])\n\n // Fire upgrade check in background (non-blocking)\n // eslint-disable-next-line no-void\n void checkForNewVersionInBackground()\n\n outputDebug(`Running command ${commandContent.command}`)\n await analyticsMod.startAnalytics({commandContent, args, commandClass: options.Command})\n notificationsMod.fetchNotificationsInBackground(options.Command.id)\n}\n\nexport function parseCommandContent(cmdInfo: {id: string; aliases: string[]; pluginAlias?: string}): CommandContent {\n let commandContent = parseCreateCommand(cmdInfo.pluginAlias)\n commandContent ??= parseNormalCommand(cmdInfo.id, cmdInfo.aliases)\n return commandContent\n}\n\nfunction parseNormalCommand(id: string, aliases: string[]): CommandContent {\n return {\n command: id.replace(/:/g, ' '),\n topic: parseTopic(id),\n alias: findAlias(aliases),\n }\n}\n\n/**\n * Create commands implement Init by default, so the name of the command must be extracted from\n * the plugin/module name. Neither alias or topic are supported\n *\n * @param commandClass - Oclif command configuration\n * @returns Command content with the name of the command or undefined otherwise\n */\nfunction parseCreateCommand(pluginAlias?: string): CommandContent | undefined {\n if (!pluginAlias?.startsWith('@shopify/create-')) {\n return undefined\n }\n\n return {command: pluginAlias.substring(pluginAlias.indexOf('/') + 1)}\n}\n\n/**\n * Commands use this pattern topic:subtopic1:...:subtopicN:command. This method extract the topic and subtopic\n * information replacing the ':' separator with one space\n *\n * @param cmd - Complete command string to extract the topic information\n * @returns The topic name or undefined otherwise\n */\nfunction parseTopic(cmd: string) {\n if (cmd.lastIndexOf(':') === -1) {\n return\n }\n return cmd.slice(0, cmd.lastIndexOf(':')).replace(/:/g, ' ')\n}\n\n/**\n * Identifies if the command was launched using an alias instead of the oficial command name\n *\n * @param aliases - List of possible alias a command has\n * @returns The alias used or undefined otherwise\n */\nfunction findAlias(aliases: string[]) {\n const existingAlias = aliases.find((alias) =>\n alias.split(':').every((aliasToken) => process.argv.includes(aliasToken)),\n )\n if (existingAlias) {\n return existingAlias.replace(/:/g, ' ')\n }\n}\n\n/**\n * Triggers a background check for a newer CLI version (non-blocking).\n * The result is cached and consumed by the postrun hook for auto-upgrade.\n */\nexport async function checkForNewVersionInBackground(): Promise<void> {\n const [{CLI_KIT_VERSION}, {isPreReleaseVersion}, {checkForNewVersion}] = await Promise.all([\n import('../../common/version.js'),\n import('../version.js'),\n import('../node-package-manager.js'),\n ])\n const currentVersion = CLI_KIT_VERSION\n if (isPreReleaseVersion(currentVersion)) {\n return\n }\n // eslint-disable-next-line no-void\n void checkForNewVersion('@shopify/cli', currentVersion, {cacheExpiryInHours: 24})\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fileExistsSync, isDirectorySync } from './fs.js';
|
|
2
2
|
import { dirname, joinPath } from './path.js';
|
|
3
|
+
import { uniq } from '../common/array.js';
|
|
3
4
|
import { openSync, readSync, closeSync } from 'fs';
|
|
4
5
|
// Only read the first 128KB of each file for import scanning. This covers
|
|
5
6
|
// ~3,000+ lines which is more than enough to capture all static imports.
|
|
@@ -114,7 +115,7 @@ export function extractImportPathsRecursively(filePath, visited = new Set()) {
|
|
|
114
115
|
throw error;
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
|
-
return
|
|
118
|
+
return uniq(allImports);
|
|
118
119
|
}
|
|
119
120
|
/**
|
|
120
121
|
* Returns diagnostic information about the import scanning caches.
|
|
@@ -166,7 +167,7 @@ function extractJSLikeImports(content, filePath) {
|
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
|
-
return
|
|
170
|
+
return uniq(imports);
|
|
170
171
|
}
|
|
171
172
|
function extractRustImports(content, filePath) {
|
|
172
173
|
const imports = [];
|
|
@@ -193,7 +194,7 @@ function extractRustImports(content, filePath) {
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
|
-
return
|
|
197
|
+
return uniq(imports);
|
|
197
198
|
}
|
|
198
199
|
function resolveJSImport(importPath, fromFile) {
|
|
199
200
|
const basePath = cachedFileExists(fromFile) && cachedIsDir(fromFile) ? fromFile : dirname(fromFile);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-extractor.js","sourceRoot":"","sources":["../../../src/public/node/import-extractor.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExistsSync, isDirectorySync} from './fs.js'\nimport {dirname, joinPath} from './path.js'\nimport {openSync, readSync, closeSync} from 'fs'\n\n// Only read the first 128KB of each file for import scanning. This covers\n// ~3,000+ lines which is more than enough to capture all static imports.\n// Generated type files (e.g. graphql-codegen) can be tens of megabytes and\n// reading them fully takes several seconds on some machines.\nconst MAX_READ_SIZE = 128 * 1024\n\n// Caches direct import results per file path to avoid redundant file reads and parsing\n// when multiple extensions import the same shared code.\nconst directImportsCache = new Map<string, string[]>()\n\n// Caches filesystem stat results to avoid redundant synchronous I/O.\n// Each stat call also triggers outputDebug overhead, so caching here\n// avoids both the kernel round-trip and the debug string construction.\nconst fileExistsCache = new Map<string, boolean>()\nconst isDirCache = new Map<string, boolean>()\n\nfunction cachedFileExists(path: string): boolean {\n const cached = fileExistsCache.get(path)\n if (cached !== undefined) return cached\n const result = fileExistsSync(path)\n fileExistsCache.set(path, result)\n return result\n}\n\nfunction cachedIsDir(path: string): boolean {\n const cached = isDirCache.get(path)\n if (cached !== undefined) return cached\n const result = isDirectorySync(path)\n isDirCache.set(path, result)\n return result\n}\n\nfunction readFileContent(filePath: string): string {\n const fd = openSync(filePath, 'r')\n try {\n const buffer = Buffer.alloc(MAX_READ_SIZE)\n const bytesRead = readSync(fd, buffer, 0, MAX_READ_SIZE, 0)\n return buffer.subarray(0, bytesRead).toString()\n } finally {\n closeSync(fd)\n }\n}\n\n/**\n * Clears all import-scanning caches (direct imports, recursive results, and filesystem stats).\n * Should be called when watched files change so that rescanning picks up updated imports.\n */\nexport function clearImportPathsCache(): void {\n directImportsCache.clear()\n fileExistsCache.clear()\n isDirCache.clear()\n}\n\n/**\n * Extracts import paths from a source file.\n * Supports JavaScript, TypeScript, and Rust files.\n * Results are cached per file path to avoid redundant I/O.\n *\n * @param filePath - Path to the file to analyze.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractImportPaths(filePath: string): string[] {\n const cached = directImportsCache.get(filePath)\n if (cached) return cached\n\n const content = readFileContent(filePath)\n const ext = filePath.substring(filePath.lastIndexOf('.'))\n\n let result: string[]\n switch (ext) {\n case '.js':\n case '.mjs':\n case '.cjs':\n case '.ts':\n case '.tsx':\n case '.jsx':\n result = extractJSLikeImports(content, filePath)\n break\n case '.rs':\n result = extractRustImports(content, filePath)\n break\n default:\n result = []\n }\n\n directImportsCache.set(filePath, result)\n return result\n}\n\n/**\n * Recursively extracts import paths from a source file and all its dependencies.\n * Supports JavaScript, TypeScript, and Rust files.\n * Handles circular dependencies by tracking visited files.\n *\n * @param filePath - Path to the file to analyze.\n * @param visited - Set of already visited files to prevent infinite recursion.\n * @returns Array of absolute paths to the provided file and all imported files there (including nested imports).\n * @throws If an unexpected error occurs while processing files (not including ENOENT file not found errors).\n */\nexport function extractImportPathsRecursively(filePath: string, visited: Set<string> = new Set<string>()): string[] {\n if (visited.has(filePath)) {\n return []\n }\n\n visited.add(filePath)\n\n const directImports = extractImportPaths(filePath)\n const allImports = [filePath, ...directImports]\n\n for (const importedFile of directImports) {\n try {\n if (cachedFileExists(importedFile) && !cachedIsDir(importedFile)) {\n const nestedImports = extractImportPathsRecursively(importedFile, visited)\n allImports.push(...nestedImports)\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n continue\n }\n throw error\n }\n }\n\n return [...new Set(allImports)]\n}\n\n/**\n * Returns diagnostic information about the import scanning caches.\n * Useful for debugging performance issues with --verbose.\n *\n * @returns Cache size stats for directImports, fileExists, and isDir.\n */\nexport function getImportScanningCacheStats(): {directImports: number; fileExists: number; isDir: number} {\n return {\n directImports: directImportsCache.size,\n fileExists: fileExistsCache.size,\n isDir: isDirCache.size,\n }\n}\n\n/**\n * Extracts import paths from a JavaScript content.\n *\n * @param content - The content to extract imports from.\n * @param filePath - The path to the file to extract imports from.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractJSImports(content: string, filePath: string): string[] {\n return extractJSLikeImports(content, filePath)\n}\n\nfunction extractJSLikeImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Regular expressions for different import types\n const patterns = [\n // ES6 imports: import ... from './path'\n /import\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // ES6 side-effect imports: import './path'\n /import\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/g,\n // ES6 exports: export ... from './path'\n /export\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // Dynamic imports: import('./path')\n /import\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n // CommonJS requires: require('./path')\n /require\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n ]\n\n for (const pattern of patterns) {\n let match\n while ((match = pattern.exec(content)) !== null) {\n const importPath = match[1]\n if (importPath && importPath.startsWith('.')) {\n const resolvedPath = resolveJSImport(importPath, filePath)\n if (resolvedPath) {\n imports.push(resolvedPath)\n }\n }\n }\n }\n\n return [...new Set(imports)]\n}\n\nfunction extractRustImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Basic Rust mod declarations: mod module_name;\n const modPattern = /^\\s*(?:pub\\s+)?mod\\s+([a-z_][a-z0-9_]*)\\s*;/gm\n\n let match\n while ((match = modPattern.exec(content)) !== null) {\n const modName = match[1]\n if (modName) {\n const modPath = resolveRustModule(modName, filePath)\n if (modPath) {\n imports.push(modPath)\n }\n }\n }\n\n // Handle #[path = \"...\"] attributes\n const pathPattern = /#\\[path\\s*=\\s*\"([^\"]+)\"\\]/g\n while ((match = pathPattern.exec(content)) !== null) {\n const pathValue = match[1]\n if (pathValue) {\n const resolvedPath = joinPath(dirname(filePath), pathValue)\n if (cachedFileExists(resolvedPath)) {\n imports.push(resolvedPath)\n }\n }\n }\n\n return [...new Set(imports)]\n}\n\nfunction resolveJSImport(importPath: string, fromFile: string): string | null {\n const basePath = cachedFileExists(fromFile) && cachedIsDir(fromFile) ? fromFile : dirname(fromFile)\n const resolvedPath = joinPath(basePath, importPath)\n\n if (cachedFileExists(resolvedPath) && cachedIsDir(resolvedPath)) {\n const indexPaths = [\n joinPath(resolvedPath, 'index.js'),\n joinPath(resolvedPath, 'index.ts'),\n joinPath(resolvedPath, 'index.tsx'),\n joinPath(resolvedPath, 'index.jsx'),\n ]\n\n for (const indexPath of indexPaths) {\n if (cachedFileExists(indexPath) && !cachedIsDir(indexPath)) {\n return indexPath\n }\n }\n return null\n }\n\n const possiblePaths = [\n resolvedPath,\n `${resolvedPath}.js`,\n `${resolvedPath}.ts`,\n `${resolvedPath}.tsx`,\n `${resolvedPath}.jsx`,\n ]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path) && !cachedIsDir(path)) {\n return path\n }\n }\n\n return null\n}\n\nfunction resolveRustModule(modName: string, fromFile: string): string | null {\n const basePath = dirname(fromFile)\n const possiblePaths = [joinPath(basePath, `${modName}.rs`), joinPath(basePath, modName, 'mod.rs')]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path)) {\n return path\n }\n }\n\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"file":"import-extractor.js","sourceRoot":"","sources":["../../../src/public/node/import-extractor.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExistsSync, isDirectorySync} from './fs.js'\nimport {dirname, joinPath} from './path.js'\nimport {uniq} from '../common/array.js'\nimport {openSync, readSync, closeSync} from 'fs'\n\n// Only read the first 128KB of each file for import scanning. This covers\n// ~3,000+ lines which is more than enough to capture all static imports.\n// Generated type files (e.g. graphql-codegen) can be tens of megabytes and\n// reading them fully takes several seconds on some machines.\nconst MAX_READ_SIZE = 128 * 1024\n\n// Caches direct import results per file path to avoid redundant file reads and parsing\n// when multiple extensions import the same shared code.\nconst directImportsCache = new Map<string, string[]>()\n\n// Caches filesystem stat results to avoid redundant synchronous I/O.\n// Each stat call also triggers outputDebug overhead, so caching here\n// avoids both the kernel round-trip and the debug string construction.\nconst fileExistsCache = new Map<string, boolean>()\nconst isDirCache = new Map<string, boolean>()\n\nfunction cachedFileExists(path: string): boolean {\n const cached = fileExistsCache.get(path)\n if (cached !== undefined) return cached\n const result = fileExistsSync(path)\n fileExistsCache.set(path, result)\n return result\n}\n\nfunction cachedIsDir(path: string): boolean {\n const cached = isDirCache.get(path)\n if (cached !== undefined) return cached\n const result = isDirectorySync(path)\n isDirCache.set(path, result)\n return result\n}\n\nfunction readFileContent(filePath: string): string {\n const fd = openSync(filePath, 'r')\n try {\n const buffer = Buffer.alloc(MAX_READ_SIZE)\n const bytesRead = readSync(fd, buffer, 0, MAX_READ_SIZE, 0)\n return buffer.subarray(0, bytesRead).toString()\n } finally {\n closeSync(fd)\n }\n}\n\n/**\n * Clears all import-scanning caches (direct imports, recursive results, and filesystem stats).\n * Should be called when watched files change so that rescanning picks up updated imports.\n */\nexport function clearImportPathsCache(): void {\n directImportsCache.clear()\n fileExistsCache.clear()\n isDirCache.clear()\n}\n\n/**\n * Extracts import paths from a source file.\n * Supports JavaScript, TypeScript, and Rust files.\n * Results are cached per file path to avoid redundant I/O.\n *\n * @param filePath - Path to the file to analyze.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractImportPaths(filePath: string): string[] {\n const cached = directImportsCache.get(filePath)\n if (cached) return cached\n\n const content = readFileContent(filePath)\n const ext = filePath.substring(filePath.lastIndexOf('.'))\n\n let result: string[]\n switch (ext) {\n case '.js':\n case '.mjs':\n case '.cjs':\n case '.ts':\n case '.tsx':\n case '.jsx':\n result = extractJSLikeImports(content, filePath)\n break\n case '.rs':\n result = extractRustImports(content, filePath)\n break\n default:\n result = []\n }\n\n directImportsCache.set(filePath, result)\n return result\n}\n\n/**\n * Recursively extracts import paths from a source file and all its dependencies.\n * Supports JavaScript, TypeScript, and Rust files.\n * Handles circular dependencies by tracking visited files.\n *\n * @param filePath - Path to the file to analyze.\n * @param visited - Set of already visited files to prevent infinite recursion.\n * @returns Array of absolute paths to the provided file and all imported files there (including nested imports).\n * @throws If an unexpected error occurs while processing files (not including ENOENT file not found errors).\n */\nexport function extractImportPathsRecursively(filePath: string, visited: Set<string> = new Set<string>()): string[] {\n if (visited.has(filePath)) {\n return []\n }\n\n visited.add(filePath)\n\n const directImports = extractImportPaths(filePath)\n const allImports = [filePath, ...directImports]\n\n for (const importedFile of directImports) {\n try {\n if (cachedFileExists(importedFile) && !cachedIsDir(importedFile)) {\n const nestedImports = extractImportPathsRecursively(importedFile, visited)\n allImports.push(...nestedImports)\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n continue\n }\n throw error\n }\n }\n\n return uniq(allImports)\n}\n\n/**\n * Returns diagnostic information about the import scanning caches.\n * Useful for debugging performance issues with --verbose.\n *\n * @returns Cache size stats for directImports, fileExists, and isDir.\n */\nexport function getImportScanningCacheStats(): {directImports: number; fileExists: number; isDir: number} {\n return {\n directImports: directImportsCache.size,\n fileExists: fileExistsCache.size,\n isDir: isDirCache.size,\n }\n}\n\n/**\n * Extracts import paths from a JavaScript content.\n *\n * @param content - The content to extract imports from.\n * @param filePath - The path to the file to extract imports from.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractJSImports(content: string, filePath: string): string[] {\n return extractJSLikeImports(content, filePath)\n}\n\nfunction extractJSLikeImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Regular expressions for different import types\n const patterns = [\n // ES6 imports: import ... from './path'\n /import\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // ES6 side-effect imports: import './path'\n /import\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/g,\n // ES6 exports: export ... from './path'\n /export\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // Dynamic imports: import('./path')\n /import\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n // CommonJS requires: require('./path')\n /require\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n ]\n\n for (const pattern of patterns) {\n let match\n while ((match = pattern.exec(content)) !== null) {\n const importPath = match[1]\n if (importPath && importPath.startsWith('.')) {\n const resolvedPath = resolveJSImport(importPath, filePath)\n if (resolvedPath) {\n imports.push(resolvedPath)\n }\n }\n }\n }\n\n return uniq(imports)\n}\n\nfunction extractRustImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Basic Rust mod declarations: mod module_name;\n const modPattern = /^\\s*(?:pub\\s+)?mod\\s+([a-z_][a-z0-9_]*)\\s*;/gm\n\n let match\n while ((match = modPattern.exec(content)) !== null) {\n const modName = match[1]\n if (modName) {\n const modPath = resolveRustModule(modName, filePath)\n if (modPath) {\n imports.push(modPath)\n }\n }\n }\n\n // Handle #[path = \"...\"] attributes\n const pathPattern = /#\\[path\\s*=\\s*\"([^\"]+)\"\\]/g\n while ((match = pathPattern.exec(content)) !== null) {\n const pathValue = match[1]\n if (pathValue) {\n const resolvedPath = joinPath(dirname(filePath), pathValue)\n if (cachedFileExists(resolvedPath)) {\n imports.push(resolvedPath)\n }\n }\n }\n\n return uniq(imports)\n}\n\nfunction resolveJSImport(importPath: string, fromFile: string): string | null {\n const basePath = cachedFileExists(fromFile) && cachedIsDir(fromFile) ? fromFile : dirname(fromFile)\n const resolvedPath = joinPath(basePath, importPath)\n\n if (cachedFileExists(resolvedPath) && cachedIsDir(resolvedPath)) {\n const indexPaths = [\n joinPath(resolvedPath, 'index.js'),\n joinPath(resolvedPath, 'index.ts'),\n joinPath(resolvedPath, 'index.tsx'),\n joinPath(resolvedPath, 'index.jsx'),\n ]\n\n for (const indexPath of indexPaths) {\n if (cachedFileExists(indexPath) && !cachedIsDir(indexPath)) {\n return indexPath\n }\n }\n return null\n }\n\n const possiblePaths = [\n resolvedPath,\n `${resolvedPath}.js`,\n `${resolvedPath}.ts`,\n `${resolvedPath}.tsx`,\n `${resolvedPath}.jsx`,\n ]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path) && !cachedIsDir(path)) {\n return path\n }\n }\n\n return null\n}\n\nfunction resolveRustModule(modName: string, fromFile: string): string | null {\n const basePath = dirname(fromFile)\n const possiblePaths = [joinPath(basePath, `${modName}.rs`), joinPath(basePath, modName, 'mod.rs')]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path)) {\n return path\n }\n }\n\n return null\n}\n"]}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cwd, dirname, joinPath, sniffForPath } from './path.js';
|
|
3
|
-
import { exec, terminalSupportsPrompting } from './system.js';
|
|
4
|
-
import { renderSelectPrompt } from './ui.js';
|
|
5
|
-
import { globalCLIVersion } from './version.js';
|
|
1
|
+
import { cwd, dirname, isSubpath, joinPath, sniffForPath } from './path.js';
|
|
6
2
|
import { isUnitTest } from './context/local.js';
|
|
7
3
|
import { findPathUpSync, globSync } from './fs.js';
|
|
8
4
|
import { realpathSync } from 'fs';
|
|
@@ -26,8 +22,16 @@ export function currentProcessIsGlobal(argv = process.argv) {
|
|
|
26
22
|
}
|
|
27
23
|
// From node docs: "The second element [of the array] will be the path to the JavaScript file being executed"
|
|
28
24
|
const binDir = argv[1] ?? '';
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
if (!binDir) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
// If binDir lives inside projectDir, we are running a local CLI.
|
|
29
|
+
// Use isSubpath (pathe.relative under the hood) instead of a raw
|
|
30
|
+
// string startsWith: projectDir flows through normalizePath and is
|
|
31
|
+
// forward-slash on every platform, while argv[1] is OS-native, so on
|
|
32
|
+
// Windows it arrives backslash-separated and a naive startsWith would
|
|
33
|
+
// misclassify a local install as global.
|
|
34
|
+
const isLocal = isSubpath(projectDir.trim(), binDir);
|
|
31
35
|
_isGlobal = !isLocal;
|
|
32
36
|
return _isGlobal;
|
|
33
37
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
@@ -42,6 +46,8 @@ export function currentProcessIsGlobal(argv = process.argv) {
|
|
|
42
46
|
* @param packageManager - The package manager to use.
|
|
43
47
|
*/
|
|
44
48
|
export async function installGlobalShopifyCLI(packageManager) {
|
|
49
|
+
const { outputInfo } = await import('./output.js');
|
|
50
|
+
const { exec } = await import('./system.js');
|
|
45
51
|
const args = packageManager === 'yarn' ? ['global', 'add', '@shopify/cli@latest'] : ['install', '-g', '@shopify/cli@latest'];
|
|
46
52
|
outputInfo(`Running ${packageManager} ${args.join(' ')}...`);
|
|
47
53
|
await exec(packageManager, args, { stdio: 'inherit' });
|
|
@@ -52,11 +58,14 @@ export async function installGlobalShopifyCLI(packageManager) {
|
|
|
52
58
|
* @returns `true` if the user has installed the global CLI.
|
|
53
59
|
*/
|
|
54
60
|
export async function installGlobalCLIPrompt() {
|
|
61
|
+
const { terminalSupportsPrompting } = await import('./system.js');
|
|
55
62
|
if (!terminalSupportsPrompting())
|
|
56
63
|
return { install: false, alreadyInstalled: false };
|
|
64
|
+
const { globalCLIVersion } = await import('./version.js');
|
|
57
65
|
if (await globalCLIVersion()) {
|
|
58
66
|
return { install: false, alreadyInstalled: true };
|
|
59
67
|
}
|
|
68
|
+
const { renderSelectPrompt } = await import('./ui.js');
|
|
60
69
|
const result = await renderSelectPrompt({
|
|
61
70
|
message: 'We recommend installing Shopify CLI globally in your system. Would you like to install it now?',
|
|
62
71
|
choices: [
|
|
@@ -81,8 +90,9 @@ export function inferPackageManagerForGlobalCLI(argv = process.argv, env = proce
|
|
|
81
90
|
return 'homebrew';
|
|
82
91
|
}
|
|
83
92
|
const processArgv = argv[1] ?? '';
|
|
93
|
+
const symlinkPath = processArgv.toLowerCase();
|
|
84
94
|
// Resolve symlinks to get the real path of the binary.
|
|
85
|
-
let realPath =
|
|
95
|
+
let realPath = symlinkPath;
|
|
86
96
|
try {
|
|
87
97
|
realPath = realpathSync(processArgv).toLowerCase();
|
|
88
98
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
@@ -90,11 +100,17 @@ export function inferPackageManagerForGlobalCLI(argv = process.argv, env = proce
|
|
|
90
100
|
catch (error) {
|
|
91
101
|
// fall back to using the original path for detection
|
|
92
102
|
}
|
|
93
|
-
|
|
103
|
+
// Inspect both the (unresolved) symlink path and the resolved real path. Some
|
|
104
|
+
// package managers — notably bun (`~/.bun/bin/<name>`) — install global binaries
|
|
105
|
+
// as symlinks pointing into a generic `node_modules` directory whose real path
|
|
106
|
+
// no longer contains the package manager name. The original symlink under the
|
|
107
|
+
// PM's bin dir is the most reliable signal in that case.
|
|
108
|
+
const matches = (needle) => realPath.includes(needle) || symlinkPath.includes(needle);
|
|
109
|
+
if (matches('yarn'))
|
|
94
110
|
return 'yarn';
|
|
95
|
-
if (
|
|
111
|
+
if (matches('pnpm'))
|
|
96
112
|
return 'pnpm';
|
|
97
|
-
if (
|
|
113
|
+
if (matches('bun'))
|
|
98
114
|
return 'bun';
|
|
99
115
|
// Check for Homebrew via Cellar path (resolved symlink)
|
|
100
116
|
if (realPath.includes('/cellar/'))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-global.js","sourceRoot":"","sources":["../../../src/public/node/is-global.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"is-global.js","sourceRoot":"","sources":["../../../src/public/node/is-global.ts"],"names":[],"mappings":"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","sourcesContent":["import {cwd, dirname, isSubpath, joinPath, sniffForPath} from './path.js'\nimport {isUnitTest} from './context/local.js'\nimport {findPathUpSync, globSync} from './fs.js'\nimport {realpathSync} from 'fs'\nimport type {PackageManager} from './node-package-manager.js'\n\nlet _isGlobal: boolean | undefined\n\n/**\n * Returns true if the current process is running in a global context.\n *\n * @param argv - The arguments passed to the process.\n * @returns `true` if the current process is running in a global context.\n */\nexport function currentProcessIsGlobal(argv = process.argv): boolean {\n // If we are running tests, we need to disable the cache\n try {\n if (_isGlobal !== undefined && !isUnitTest()) return _isGlobal\n\n // Path where the current project is (app/hydrogen)\n const path = sniffForPath() ?? cwd()\n\n const projectDir = getProjectDir(path)\n if (!projectDir) {\n return true\n }\n\n // From node docs: \"The second element [of the array] will be the path to the JavaScript file being executed\"\n const binDir = argv[1] ?? ''\n if (!binDir) {\n return true\n }\n\n // If binDir lives inside projectDir, we are running a local CLI.\n // Use isSubpath (pathe.relative under the hood) instead of a raw\n // string startsWith: projectDir flows through normalizePath and is\n // forward-slash on every platform, while argv[1] is OS-native, so on\n // Windows it arrives backslash-separated and a naive startsWith would\n // misclassify a local install as global.\n const isLocal = isSubpath(projectDir.trim(), binDir)\n\n _isGlobal = !isLocal\n return _isGlobal\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n return false\n }\n}\n\n/**\n * Installs the global Shopify CLI, using the provided package manager.\n *\n * @param packageManager - The package manager to use.\n */\nexport async function installGlobalShopifyCLI(packageManager: PackageManager): Promise<void> {\n const {outputInfo} = await import('./output.js')\n const {exec} = await import('./system.js')\n const args =\n packageManager === 'yarn' ? ['global', 'add', '@shopify/cli@latest'] : ['install', '-g', '@shopify/cli@latest']\n outputInfo(`Running ${packageManager} ${args.join(' ')}...`)\n await exec(packageManager, args, {stdio: 'inherit'})\n}\n\nexport interface InstallGlobalCLIPromptResult {\n install: boolean\n alreadyInstalled: boolean\n}\n/**\n * Prompts the user to install the global CLI.\n *\n * @returns `true` if the user has installed the global CLI.\n */\nexport async function installGlobalCLIPrompt(): Promise<InstallGlobalCLIPromptResult> {\n const {terminalSupportsPrompting} = await import('./system.js')\n if (!terminalSupportsPrompting()) return {install: false, alreadyInstalled: false}\n const {globalCLIVersion} = await import('./version.js')\n if (await globalCLIVersion()) {\n return {install: false, alreadyInstalled: true}\n }\n const {renderSelectPrompt} = await import('./ui.js')\n const result = await renderSelectPrompt({\n message: 'We recommend installing Shopify CLI globally in your system. Would you like to install it now?',\n choices: [\n {value: 'yes', label: 'Yes'},\n {value: 'no', label: 'No, just for this project'},\n ],\n })\n\n return {install: result === 'yes', alreadyInstalled: false}\n}\n\n/**\n * Infers the package manager used by the global CLI.\n *\n * @param argv - The arguments passed to the process.\n * @param env - The environment variables of the process.\n * @returns The package manager used by the global CLI.\n */\nexport function inferPackageManagerForGlobalCLI(argv = process.argv, env = process.env): PackageManager {\n if (!currentProcessIsGlobal(argv)) return 'unknown'\n\n // Check for Homebrew first (most reliable via environment variable)\n if (env.SHOPIFY_HOMEBREW_FORMULA) {\n return 'homebrew'\n }\n\n const processArgv = argv[1] ?? ''\n const symlinkPath = processArgv.toLowerCase()\n\n // Resolve symlinks to get the real path of the binary.\n let realPath = symlinkPath\n try {\n realPath = realpathSync(processArgv).toLowerCase()\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n // fall back to using the original path for detection\n }\n\n // Inspect both the (unresolved) symlink path and the resolved real path. Some\n // package managers — notably bun (`~/.bun/bin/<name>`) — install global binaries\n // as symlinks pointing into a generic `node_modules` directory whose real path\n // no longer contains the package manager name. The original symlink under the\n // PM's bin dir is the most reliable signal in that case.\n const matches = (needle: string) => realPath.includes(needle) || symlinkPath.includes(needle)\n\n if (matches('yarn')) return 'yarn'\n if (matches('pnpm')) return 'pnpm'\n if (matches('bun')) return 'bun'\n\n // Check for Homebrew via Cellar path (resolved symlink)\n if (realPath.includes('/cellar/')) return 'homebrew'\n\n return 'npm'\n}\n\n/**\n * Returns the project directory for the given path.\n *\n * @param directory - The path to search upward from.\n * @returns The project root directory, or undefined if not found.\n */\nexport function getProjectDir(directory: string): string | undefined {\n const configFiles = ['shopify.app{,.*}.toml', 'hydrogen.config.js', 'hydrogen.config.ts']\n const existsConfigFile = (directory: string) => {\n const configPaths = globSync(configFiles.map((file) => joinPath(directory, file)))\n return configPaths.length > 0 ? configPaths[0] : undefined\n }\n try {\n const configFile = findPathUpSync(existsConfigFile, {\n cwd: directory,\n type: 'file',\n })\n if (configFile) return dirname(configFile)\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n return undefined\n }\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import { JsonMap } from '../../private/common/json.js';
|
|
|
2
2
|
import { DeepRequired } from '../common/ts/deep-required.js';
|
|
3
3
|
export { DeepRequired };
|
|
4
4
|
type Optional<T> = T | null;
|
|
5
|
-
export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.
|
|
5
|
+
export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.24";
|
|
6
6
|
export interface Schemas {
|
|
7
7
|
[MONORAIL_COMMAND_TOPIC]: {
|
|
8
8
|
sensitive: {
|
|
@@ -32,6 +32,7 @@ export interface Schemas {
|
|
|
32
32
|
node_version: string;
|
|
33
33
|
is_employee: boolean;
|
|
34
34
|
store_fqdn_hash?: Optional<string>;
|
|
35
|
+
store_fqdn_validated?: Optional<boolean>;
|
|
35
36
|
user_id: string;
|
|
36
37
|
cmd_all_alias_used?: Optional<string>;
|
|
37
38
|
cmd_all_launcher?: Optional<string>;
|
|
@@ -2,7 +2,7 @@ import { fetch } from './http.js';
|
|
|
2
2
|
import { outputDebug, outputContent, outputToken } from './output.js';
|
|
3
3
|
const url = 'https://monorail-edge.shopifysvc.com/v1/produce';
|
|
4
4
|
// This is the topic name of the main event we log to Monorail, the command tracker
|
|
5
|
-
export const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.
|
|
5
|
+
export const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.24';
|
|
6
6
|
const publishedCommandNames = new Set();
|
|
7
7
|
/**
|
|
8
8
|
* Publishes an event to Monorail.
|