@swell/cli 2.9.24 → 2.9.26

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.
@@ -14,6 +14,8 @@ import { analyzeFunctionSource, hasKindDiagnostic, } from '../../lib/function-so
14
14
  import { detectPackageManager, getExecSpawnArgs, } from '../../lib/package-manager.js';
15
15
  import style from '../../lib/style.js';
16
16
  import { PushAppCommand } from '../../push-app-command.js';
17
+ // How long shutdown waits for the tunnel address to be cleared on the platform
18
+ const UNREGISTER_TIMEOUT_MS = 5000;
17
19
  /**
18
20
  * Headers that show the frontend dev server the public host and scheme, as
19
21
  * managed hosting does. The tunnel replaces both with its own, so without them
@@ -118,7 +120,8 @@ export default class AppDev extends PushAppCommand {
118
120
  // Register cleanup handlers to clear local proxy on exit
119
121
  process.on('SIGINT', this.cleanupOnExit.bind(this));
120
122
  process.on('SIGTERM', this.cleanupOnExit.bind(this));
121
- const serverPort = await this.startProxyServer(port);
123
+ // The handlers above must finish unregistering before the process exits.
124
+ const serverPort = await this.startProxyServer(port, false);
122
125
  await this.startAppFunctionServer(spinner, serverPort);
123
126
  this.emitLifecycleEvent('preview:proxy-ready', {
124
127
  proxyPort: serverPort,
@@ -135,7 +138,14 @@ export default class AppDev extends PushAppCommand {
135
138
  proc.kill();
136
139
  }
137
140
  try {
138
- await this.updateLocalProxy(null, this.storefront?.id);
141
+ // The address can't be cleared while the admin API is unreachable, so
142
+ // don't hold the exit on the request; the platform falls back on its own.
143
+ await Promise.race([
144
+ this.updateLocalProxy(null, this.storefront?.id),
145
+ new Promise((resolve) => {
146
+ setTimeout(resolve, UNREGISTER_TIMEOUT_MS);
147
+ }),
148
+ ]);
139
149
  }
140
150
  catch {
141
151
  // Ignore errors during cleanup
@@ -2,6 +2,7 @@ export interface ProxyContext {
2
2
  appId?: string;
3
3
  storeId?: string;
4
4
  storefrontId?: string;
5
+ handleSignals?: boolean;
5
6
  }
6
7
  /**
7
8
  * Stop the active tunnel (if any) so the process can exit on its own.
package/dist/lib/proxy.js CHANGED
@@ -19,7 +19,7 @@ export function stopProxy() {
19
19
  activeLocaltunnel?.close();
20
20
  activeLocaltunnel = null;
21
21
  }
22
- async function startCloudflaredTunnel(port) {
22
+ async function startCloudflaredTunnel(port, handleSignals = true) {
23
23
  // Stop existing tunnel if called again
24
24
  if (activeTunnel) {
25
25
  activeTunnel.stop();
@@ -56,16 +56,18 @@ async function startCloudflaredTunnel(port) {
56
56
  if (!cleanupRegistered) {
57
57
  cleanupRegistered = true;
58
58
  process.on('exit', () => activeTunnel?.stop());
59
- process.on('SIGINT', () => {
60
- activeTunnel?.stop();
61
- // eslint-disable-next-line no-process-exit
62
- process.exit();
63
- });
64
- process.on('SIGTERM', () => {
65
- activeTunnel?.stop();
66
- // eslint-disable-next-line no-process-exit
67
- process.exit();
68
- });
59
+ if (handleSignals) {
60
+ process.on('SIGINT', () => {
61
+ activeTunnel?.stop();
62
+ // eslint-disable-next-line no-process-exit
63
+ process.exit();
64
+ });
65
+ process.on('SIGTERM', () => {
66
+ activeTunnel?.stop();
67
+ // eslint-disable-next-line no-process-exit
68
+ process.exit();
69
+ });
70
+ }
69
71
  }
70
72
  return url;
71
73
  }
@@ -92,7 +94,7 @@ export async function getProxyUrl(port, context) {
92
94
  // eslint-disable-next-line unicorn/no-useless-switch-case
93
95
  case 'cloudflared':
94
96
  default: {
95
- return await startCloudflaredTunnel(port);
97
+ return await startCloudflaredTunnel(port, context?.handleSignals);
96
98
  }
97
99
  }
98
100
  }
@@ -82,6 +82,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
82
82
  logDashboardUrl(flags: {
83
83
  [flag: string]: any;
84
84
  }): void;
85
+ logDeployedStorefrontUrl(): Promise<void>;
85
86
  logStorefrontConnected(): void;
86
87
  logStorefrontFrontendUrl(storefront?: any, branchId?: string): void;
87
88
  logReleaseDetailsHint(error: any): void;
@@ -93,7 +94,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
93
94
  logLocalPreviewUrl(): void;
94
95
  setStoreUser(storeUser: boolean): void;
95
96
  setWatchingFiles(): Promise<void>;
96
- startProxyServer(port?: number): Promise<number>;
97
+ startProxyServer(port?: number, handleSignals?: boolean): Promise<number>;
97
98
  updateFrontendDeployment(currentStore: string, projectType: FrontendProjectType, deploymentUrl: string, deploymentHash: string): Promise<void>;
98
99
  updateLocalProxy(proxyUrl: string | null, storefrontId?: string): Promise<void>;
99
100
  watchForChanges({ logChanges, onChange, syncAll, }?: {
@@ -286,6 +286,9 @@ export class PushAppCommand extends RemoteAppCommand {
286
286
  }
287
287
  await this.handleRequestErrors(async () => this.api.post({ adminPath: `/apps/${this.app.id}/frontend-package` }, { body: { package: serialized } }));
288
288
  this.log(`Deployed managed frontend package ${pkg.digest}.`);
289
+ if (log !== false) {
290
+ await this.logDeployedStorefrontUrl();
291
+ }
289
292
  return;
290
293
  }
291
294
  if (this.app.frontend?.hosting === 'managed' &&
@@ -306,10 +309,10 @@ export class PushAppCommand extends RemoteAppCommand {
306
309
  await this.updateFrontendDeployment(currentStore, projectType, deploymentUrl, deploymentHash);
307
310
  }
308
311
  if (log !== false) {
309
- if (this.app.type === 'storefront' && this.storefront) {
310
- this.logStorefrontFrontendUrl(this.storefront);
312
+ if (this.app.type === 'storefront') {
313
+ await this.logDeployedStorefrontUrl();
311
314
  }
312
- else if (this.app.type !== 'storefront') {
315
+ else {
313
316
  // Get updated app with `installed` property
314
317
  this.app = await this.getApp(this.app.id);
315
318
  this.logAppFrontendUrl();
@@ -737,6 +740,21 @@ export class PushAppCommand extends RemoteAppCommand {
737
740
  const currentStore = localConfig.getDefaultStore();
738
741
  this.log(`View the ${style.appConfigValue(this.app.name)} app in your dashboard at ${style.link(this.dashboardUrl(flags, currentStore))}.`);
739
742
  }
743
+ // `swell app push` deploys without choosing a storefront, so fall back to
744
+ // the app's latest one in this environment
745
+ async logDeployedStorefrontUrl() {
746
+ if (this.app.type !== 'storefront') {
747
+ return;
748
+ }
749
+ // The frontend is already deployed, so a failed lookup only skips the link
750
+ const storefront = this.storefront ||
751
+ (await this.api
752
+ .get({ adminPath: `/apps/${this.app.id}/storefront` })
753
+ .catch(() => null));
754
+ if (storefront) {
755
+ this.logStorefrontFrontendUrl(storefront);
756
+ }
757
+ }
740
758
  logStorefrontConnected() {
741
759
  if (!this.storefront) {
742
760
  this.error('Storefront not connected');
@@ -885,7 +903,7 @@ export class PushAppCommand extends RemoteAppCommand {
885
903
  async setWatchingFiles() {
886
904
  this.watchingFiles = new Set(await globAllFilesByPath(this.appPath));
887
905
  }
888
- async startProxyServer(port) {
906
+ async startProxyServer(port, handleSignals = true) {
889
907
  // Find an open port starting at 3000
890
908
  const freePort = port ||
891
909
  (await getPort({ port: portNumbers(3000, 3100) })) ||
@@ -895,6 +913,7 @@ export class PushAppCommand extends RemoteAppCommand {
895
913
  appId: this.app.id,
896
914
  storeId: localConfig.getDefaultStore(),
897
915
  storefrontId: this.storefront?.id,
916
+ handleSignals,
898
917
  });
899
918
  await this.updateLocalProxy(proxyUrl, this.storefront?.id);
900
919
  return freePort;
@@ -3606,5 +3606,5 @@
3606
3606
  ]
3607
3607
  }
3608
3608
  },
3609
- "version": "2.9.24"
3609
+ "version": "2.9.26"
3610
3610
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swell/cli",
3
- "version": "2.9.24",
3
+ "version": "2.9.26",
4
4
  "type": "module",
5
5
  "description": "Swell's command line interface/utility",
6
6
  "keywords": [