Add resilliency to errors on concurrent build asset writes
WHY are these changes introduced?
Fixes an issue where the extension bundling process would fail completely if any single file couldn't be copied, preventing developers from continuing their work.
WHAT is this pull request doing?
Improves error handling during extension bundling by:
- Using
Promise.allSettled()instead ofPromise.all()to prevent the entire process from failing if a single file copy fails - Adding detailed error reporting for failed file copies
- Outputting debug warnings when files can't be copied instead of crashing
- Continuing the bundling process even when some files fail to copy
How to test your changes?
- Create a theme or UI extension with a file that can't be copied (e.g., a file with special permissions or a locked file)
- Run
shopify app dev - Verify that the build process completes successfully despite the problematic file
- Check the debug output for warnings about files that couldn't be copied
Measuring impact
How do we know this change was effective? Please choose one:
- [x] n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
Checklist
- [x] I've considered possible cross-platform impacts (Mac, Linux, Windows)
- [x] I've considered possible documentation changes
- #6559
π (View in Graphite) - #6558

- #6553

main
This stack of pull requests is managed by Graphite. Learn more about stacking.
Coverage report
St.:grey_question: |
Category | Percentage | Covered / Total |
|---|---|---|---|
| π‘ | Statements | 79.25% (+0.03% πΌ) |
13609/17172 |
| π‘ | Branches | 73.14% (+0.09% πΌ) |
6654/9097 |
| π‘ | Functions | 79.35% (+0.07% πΌ) |
3508/4421 |
| π‘ | Lines | 79.61% (+0.02% πΌ) |
12854/16146 |
Show new covered files π£
St.:grey_question: |
File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| π΄ | ... / info.ts |
0% | 0% | 0% | 0% |
| π’ | ... / info.ts |
100% | 87.5% | 100% | 100% |
Show files with reduced coverage π»
St.:grey_question: |
File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| π’ | ... / loader.ts |
93.86% (+0.74% πΌ) |
86.7% (+1.06% πΌ) |
97.06% (-0.03% π») |
94.67% (+0.53% πΌ) |
| π’ | ... / ui_extension.ts |
94.83% (+0.04% πΌ) |
81.25% (-1.64% π») |
100% | 96.46% (+0.03% πΌ) |
| π’ | ... / Dev.tsx |
90.59% (-2.35% π») |
75% (-1.79% π») |
86.36% (-4.55% π») |
92.5% (-1.25% π») |
| π’ | ... / bundle.ts |
83.82% (-9.4% π») |
65.71% (-0.95% π») |
84.21% (-4.02% π») |
85.71% (-10.58% π») |
| π’ | ... / git.ts |
93.16% (+0.78% πΌ) |
87.93% (-1.35% π») |
90.91% (+0.43% πΌ) |
94.34% (+1.2% πΌ) |
| π‘ | ... / admin.ts |
72.22% (-2.78% π») |
40% (-5.16% π») |
90.91% | 73.58% (-2.89% π») |
| π΄ | ... / dev.ts |
13.04% (-0.29% π») |
2.94% | 57.14% | 13.04% (-0.29% π») |
| π’ | ... / theme-uploader.ts |
91.84% (+0.12% πΌ) |
78.21% (-0.83% π») |
86.36% (-1.14% π») |
93.18% (+0.59% πΌ) |
| π‘ | ... / theme-environment.ts |
70.45% (-0.97% π») |
50% | 57.89% (-0.93% π») |
70.45% (-0.97% π») |
Test suite run success
3358 tests passing in 1372 suites.
Report generated by π§ͺjest coverage report action from b49c429baa4b68bebbc01bb1822ff342ecd17ad2
We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run pnpm changeset add to track your changes and include them in the next release CHANGELOG.
[!CAUTION] DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release.
/snapit
π«°β¨ Thanks @isaacroldan! Your snapshot has been published to npm.
Test the snapshot by installing your package globally:
npm i -g --@shopify:registry=https://registry.npmjs.org @shopify/[email protected]
[!CAUTION] After installing, validate the version by running just
shopifyin your terminal. If the versions don't match, you might have multiple global instances installed. Usewhich shopifyto find out which one you are running and uninstall it.
when you have automatic build from an external vite running in parallel with dev which is, with every change that you do, deleting the assets folder and rewriting it, it may happend that you delete something that is listed in glob to be copied
Differences in type declarations
We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
- Some seemingly private modules might be re-exported through public modules.
- If the branch is behind
mainyou might see odd diffs, rebasemaininto this branch.
New type declarations
We found no new type declarations in this PR
Existing type declarations
packages/cli-kit/dist/private/node/analytics.d.ts
@@ -27,6 +27,5 @@ interface EnvironmentData {
export declare function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData>;
export declare function getSensitiveEnvironmentData(config: Interfaces.Config): Promise<{
env_plugin_installed_all: string;
- env_shopify_variables: string;
}>;
export {};
\ No newline at end of file
packages/cli-kit/dist/private/node/api.d.ts
@@ -11,30 +11,6 @@ type RequestOptions<T> = {
request: () => Promise<T>;
url: string;
} & NetworkRetryBehaviour;
-/**
- * Checks if an error is a transient network error that is likely to recover with retries.
- *
- * Use this function for retry logic. Use isNetworkError for error classification.
- *
- * Examples of transient errors (worth retrying):
- * - Connection timeouts, resets, and aborts
- * - DNS failures (enotfound, getaddrinfo, eai_again) - can be temporary
- * - Socket disconnects and hang ups
- * - Premature connection closes
- */
-export declare function isTransientNetworkError(error: unknown): boolean;
-/**
- * Checks if an error is any kind of network-related error (connection issues, timeouts, DNS failures,
- * TLS/certificate errors, etc.) rather than an application logic error.
- *
- * These errors should be reported as user-facing errors (AbortError) rather than bugs (BugError),
- * regardless of whether they are transient or permanent.
- *
- * Examples include:
- * - Transient: connection timeouts, socket hang ups, temporary DNS failures
- * - Permanent: certificate validation failures, misconfigured SSL
- */
-export declare function isNetworkError(error: unknown): boolean;
export declare function simpleRequestWithDebugLog<T extends {
headers: Headers;
status: number;
packages/cli-kit/dist/public/node/metadata.d.ts
@@ -55,7 +55,6 @@ declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
cmd_all_environment_flags?: string | null;
cmd_dev_tunnel_custom?: string | null;
env_plugin_installed_all?: string | null;
- env_shopify_variables?: string | null;
}, "store_", never>>;
export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>, getAllSensitiveMetadata: () => Partial<{
commandStartOptions: {
@@ -75,7 +74,6 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
cmd_all_environment_flags?: string | null;
cmd_dev_tunnel_custom?: string | null;
env_plugin_installed_all?: string | null;
- env_shopify_variables?: string | null;
}, "store_", never>>, addPublicMetadata: (getData: ProvideMetadata<CmdFieldsFromMonorail>, onError?: MetadataErrorHandling) => Promise<void>, addSensitiveMetadata: (getData: ProvideMetadata<{
commandStartOptions: {
startTime: number;
@@ -94,7 +92,6 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
cmd_all_environment_flags?: string | null;
cmd_dev_tunnel_custom?: string | null;
env_plugin_installed_all?: string | null;
- env_shopify_variables?: string | null;
}, "store_", never>>, onError?: MetadataErrorHandling) => Promise<void>, runWithTimer: (field: NumericKeyOf<CmdFieldsFromMonorail>) => <T>(fn: () => Promise<T>) => Promise<T>;
export type Public = PublicSchema<typeof coreData>;
export type Sensitive = SensitiveSchema<typeof coreData>;
packages/cli-kit/dist/public/node/monorail.d.ts
@@ -2,7 +2,7 @@ import { JsonMap } from '../../private/common/json.js';
import { DeepRequired } from '../common/ts/deep-required.js';
export { DeepRequired };
type Optional<T> = T | null;
-export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.20";
+export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.19";
export interface Schemas {
[MONORAIL_COMMAND_TOPIC]: {
sensitive: {
@@ -14,7 +14,6 @@ export interface Schemas {
cmd_all_environment_flags?: Optional<string>;
cmd_dev_tunnel_custom?: Optional<string>;
env_plugin_installed_all?: Optional<string>;
- env_shopify_variables?: Optional<string>;
};
public: {
business_platform_id?: Optional<number>;
packages/cli-kit/dist/cli/api/graphql/admin/generated/theme_files_upsert.d.ts
@@ -8,7 +8,6 @@ export type ThemeFilesUpsertMutation = {
themeFilesUpsert?: {
upsertedThemeFiles?: {
filename: string;
- checksumMd5?: string | null;
}[] | null;
userErrors: {
filename?: string | null;
@alfonso-noriega I think @gonzaloriestra is right, because this method is also used during deploy so we need to handle errors better