@swell/cli 2.4.1 → 2.5.1
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/dist/commands/app/dev.d.ts +1 -0
- package/dist/commands/app/dev.js +5 -0
- package/dist/commands/app/frontend/deploy.d.ts +1 -0
- package/dist/commands/app/frontend/deploy.js +4 -0
- package/dist/commands/app/frontend/dev.d.ts +2 -1
- package/dist/commands/app/frontend/dev.js +45 -11
- package/dist/commands/app/push.d.ts +1 -3
- package/dist/commands/theme/dev.d.ts +1 -0
- package/dist/commands/theme/dev.js +4 -0
- package/dist/commands/theme/push.d.ts +2 -0
- package/dist/commands/theme/push.js +7 -1
- package/dist/create-app-command.js +1 -1
- package/dist/lib/apps/index.d.ts +6 -0
- package/dist/lib/apps/index.js +21 -1
- package/dist/lib/config.js +3 -2
- package/dist/push-app-command.d.ts +2 -1
- package/dist/push-app-command.js +84 -40
- package/oclif.manifest.json +38 -6
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ export default class AppDev extends PushAppCommand {
|
|
|
8
8
|
'frontend-port': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
9
|
'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
10
10
|
'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
|
+
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
13
|
static orientation: {
|
|
13
14
|
env: string;
|
package/dist/commands/app/dev.js
CHANGED
|
@@ -37,6 +37,11 @@ export default class AppDev extends PushAppCommand {
|
|
|
37
37
|
default: false,
|
|
38
38
|
description: 'for storefront apps, prompt to select a storefront to preview',
|
|
39
39
|
}),
|
|
40
|
+
// Declared here so oclif accepts -y; passed through to app:frontend:dev via this.argv
|
|
41
|
+
yes: Flags.boolean({
|
|
42
|
+
char: 'y',
|
|
43
|
+
description: 'skip prompts (non-interactive mode)',
|
|
44
|
+
}),
|
|
40
45
|
};
|
|
41
46
|
static orientation = {
|
|
42
47
|
env: 'test',
|
|
@@ -6,6 +6,7 @@ export default class AppFrontendDeploy extends PushAppCommand {
|
|
|
6
6
|
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
7
|
'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
8
|
'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
|
+
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
10
|
};
|
|
10
11
|
static orientation: {
|
|
11
12
|
env: string;
|
|
@@ -22,6 +22,10 @@ the app's deployment URL and push the updated frontend files.`;
|
|
|
22
22
|
default: false,
|
|
23
23
|
description: 'prompt to select a storefront to preview deployment with',
|
|
24
24
|
}),
|
|
25
|
+
yes: Flags.boolean({
|
|
26
|
+
char: 'y',
|
|
27
|
+
description: 'skip prompts (non-interactive mode)',
|
|
28
|
+
}),
|
|
25
29
|
};
|
|
26
30
|
static orientation = {
|
|
27
31
|
env: 'test',
|
|
@@ -2,10 +2,11 @@ import { PushAppCommand } from '../../../push-app-command.js';
|
|
|
2
2
|
export default class AppFrontendDev extends PushAppCommand {
|
|
3
3
|
static examples: string[];
|
|
4
4
|
static flags: {
|
|
5
|
-
'proxy-port': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
5
|
+
'proxy-port': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
6
6
|
'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
7
|
'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
8
|
'app-dev': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
|
+
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
10
|
'no-push': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
11
|
port: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
12
|
'frontend-port': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import { getProjectCommands, } from '../../../lib/apps/index.js';
|
|
2
|
+
import { CUSTOM_FRAMEWORK_SLUG, getManualDevHint, getProjectCommands, } from '../../../lib/apps/index.js';
|
|
3
3
|
import { default as localConfig } from '../../../lib/config.js';
|
|
4
4
|
import style from '../../../lib/style.js';
|
|
5
5
|
import { PushAppCommand } from '../../../push-app-command.js';
|
|
@@ -15,8 +15,7 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
15
15
|
static flags = {
|
|
16
16
|
...AppDev.flags,
|
|
17
17
|
'proxy-port': Flags.integer({
|
|
18
|
-
description: 'specify the port for
|
|
19
|
-
default: 3001,
|
|
18
|
+
description: 'specify the port for the frontend proxy',
|
|
20
19
|
}),
|
|
21
20
|
'storefront-id': Flags.string({
|
|
22
21
|
description: 'identify a storefront to preview with and push theme files to',
|
|
@@ -29,6 +28,10 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
29
28
|
description: 'indicates frontend app is running in app dev mode',
|
|
30
29
|
default: false,
|
|
31
30
|
}),
|
|
31
|
+
yes: Flags.boolean({
|
|
32
|
+
char: 'y',
|
|
33
|
+
description: 'skip prompts (non-interactive mode)',
|
|
34
|
+
}),
|
|
32
35
|
};
|
|
33
36
|
static orientation = {
|
|
34
37
|
env: 'test',
|
|
@@ -70,11 +73,32 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
70
73
|
if (!projectType) {
|
|
71
74
|
return;
|
|
72
75
|
}
|
|
76
|
+
// Manual mode for unrecognized frameworks
|
|
77
|
+
if (projectType.slug === CUSTOM_FRAMEWORK_SLUG) {
|
|
78
|
+
const hintCommand = getManualDevHint(this.appPath, serverPort);
|
|
79
|
+
const currentStore = localConfig.getDefaultStore();
|
|
80
|
+
const sessionId = localConfig.getSessionId(currentStore);
|
|
81
|
+
this.log(`Detected a frontend project but could not identify the framework.`);
|
|
82
|
+
this.log(`Start your dev server manually on port ${serverPort}:\n`);
|
|
83
|
+
this.log(` cd frontend && ${hintCommand}\n`);
|
|
84
|
+
this.log(`The Swell tunnel is ready and will route traffic once your server is running.\n`);
|
|
85
|
+
this.logAppLocalUrl(currentStore, sessionId);
|
|
86
|
+
if (!isAppDev) {
|
|
87
|
+
this.watchForChanges();
|
|
88
|
+
}
|
|
89
|
+
// Keep the process alive so the tunnel remains open
|
|
90
|
+
await new Promise(() => { });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
73
93
|
// Get commands transformed for the detected package manager
|
|
74
94
|
const { devCommand } = getProjectCommands(this.appPath, projectType);
|
|
75
95
|
const currentStore = localConfig.getDefaultStore();
|
|
76
96
|
let serverReadyDetected = false;
|
|
77
97
|
await this.execFrontend(devCommand.replace('${PORT}', String(serverPort)), (string) => {
|
|
98
|
+
// Shared: Hide Vite noise output common across frameworks
|
|
99
|
+
if (/press h \+ enter to show help/i.test(string)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
78
102
|
// Framework-specific output handling and ready detection
|
|
79
103
|
switch (projectType.slug) {
|
|
80
104
|
case 'nextjs': {
|
|
@@ -120,10 +144,6 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
120
144
|
break;
|
|
121
145
|
}
|
|
122
146
|
case 'angular': {
|
|
123
|
-
// 1. NOISE FILTER: Hide unwanted output
|
|
124
|
-
if (string.includes('press h + enter to show help')) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
147
|
// 2. URL FILTER: Hide localhost/network URLs (confusing - users should use Swell tunnel)
|
|
128
148
|
if (/➜\s+local:\s+http:\/\//i.test(string)) {
|
|
129
149
|
return false;
|
|
@@ -143,9 +163,23 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
143
163
|
break;
|
|
144
164
|
}
|
|
145
165
|
case 'hono': {
|
|
146
|
-
// 2. URL FILTER: Hide localhost URLs (confusing - users should use Swell tunnel)
|
|
147
|
-
//
|
|
148
|
-
|
|
166
|
+
// 2. URL FILTER: Hide localhost/network/debug URLs (confusing - users should use Swell tunnel)
|
|
167
|
+
// Vite-based Hono apps output "➜ Local: http://localhost:PORT/"
|
|
168
|
+
if (/➜\s+local:\s+http:\/\//i.test(string) ||
|
|
169
|
+
/➜\s+network:/i.test(string) ||
|
|
170
|
+
/➜\s+debug:\s+http:\/\//i.test(string)) {
|
|
171
|
+
if (!serverReadyDetected) {
|
|
172
|
+
serverReadyDetected = true;
|
|
173
|
+
this.log(`Started ${projectType.name} dev server on port ${serverPort}.\n`);
|
|
174
|
+
const sessionId = localConfig.getSessionId(currentStore);
|
|
175
|
+
setTimeout(() => this.logAppLocalUrl(currentStore, sessionId), 100);
|
|
176
|
+
if (!isAppDev) {
|
|
177
|
+
this.watchForChanges();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
// 3. READY DETECTION: Native Hono dev server outputs "ready on http://localhost:PORT"
|
|
149
183
|
if (!serverReadyDetected &&
|
|
150
184
|
/ready on http:\/\/localhost:\d+/i.test(string)) {
|
|
151
185
|
serverReadyDetected = true;
|
|
@@ -155,7 +189,7 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
155
189
|
if (!isAppDev) {
|
|
156
190
|
this.watchForChanges();
|
|
157
191
|
}
|
|
158
|
-
return false;
|
|
192
|
+
return false;
|
|
159
193
|
}
|
|
160
194
|
break;
|
|
161
195
|
}
|
|
@@ -7,9 +7,7 @@ export default class AppPush extends PushAppCommand {
|
|
|
7
7
|
static description: string;
|
|
8
8
|
static examples: string[];
|
|
9
9
|
static flags: any;
|
|
10
|
-
static orientation:
|
|
11
|
-
env: string;
|
|
12
|
-
};
|
|
10
|
+
static orientation: AppCommandOrientation;
|
|
13
11
|
static summary: string;
|
|
14
12
|
resolvePushPaths(file: string, appPathFlag?: string): {
|
|
15
13
|
filePath: string;
|
|
@@ -9,6 +9,7 @@ export default class AppThemeDev extends PushAppCommand {
|
|
|
9
9
|
'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
10
10
|
'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
11
|
env: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
|
+
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
12
13
|
};
|
|
13
14
|
static summary: string;
|
|
14
15
|
appType: string;
|
|
@@ -41,6 +41,10 @@ export default class AppThemeDev extends PushAppCommand {
|
|
|
41
41
|
char: 'e',
|
|
42
42
|
description: 'target environment to push to, defaults to live',
|
|
43
43
|
}),
|
|
44
|
+
yes: Flags.boolean({
|
|
45
|
+
char: 'y',
|
|
46
|
+
description: 'skip prompts (non-interactive mode)',
|
|
47
|
+
}),
|
|
44
48
|
};
|
|
45
49
|
static summary = `Run a theme in dev mode from your local machine.`;
|
|
46
50
|
appType = 'theme';
|
|
@@ -11,7 +11,9 @@ export default class AppThemePush extends AppPush {
|
|
|
11
11
|
'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
12
12
|
env: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
13
13
|
'sync-app': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
|
+
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
15
|
};
|
|
16
|
+
static orientation: AppCommandOrientation;
|
|
15
17
|
static summary: string;
|
|
16
18
|
appType: string;
|
|
17
19
|
run(): Promise<void>;
|
|
@@ -53,7 +53,13 @@ ${Object.values(ThemeConfigPaths)
|
|
|
53
53
|
default: false,
|
|
54
54
|
description: 'push app files in addition to theme files',
|
|
55
55
|
}),
|
|
56
|
+
yes: Flags.boolean({
|
|
57
|
+
char: 'y',
|
|
58
|
+
description: 'skip prompts (non-interactive mode)',
|
|
59
|
+
}),
|
|
56
60
|
};
|
|
61
|
+
// No fixed env — respect saved storefront env (test or live)
|
|
62
|
+
static orientation = {};
|
|
57
63
|
static summary = 'Push local files to your Swell theme.';
|
|
58
64
|
appType = 'theme';
|
|
59
65
|
async run() {
|
|
@@ -77,7 +83,7 @@ ${Object.values(ThemeConfigPaths)
|
|
|
77
83
|
this.themeSyncApp = true;
|
|
78
84
|
}
|
|
79
85
|
await this.getStorefrontToPush(flags);
|
|
80
|
-
await this.logOrientation();
|
|
86
|
+
await this.logOrientation({ env: this.api.envId || 'live' });
|
|
81
87
|
if (file) {
|
|
82
88
|
const { filePath, relativePath } = this.resolvePushPaths(file);
|
|
83
89
|
// Push individual files if not referring to the whole app path
|
|
@@ -429,7 +429,7 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
429
429
|
// Required for yarn workspaces, good practice for all package managers
|
|
430
430
|
private: true,
|
|
431
431
|
scripts: {
|
|
432
|
-
typecheck: '([ -z "$(find functions -name \'*.ts\' 2>/dev/null | head -1)" ] || tsc --noEmit) && ([ ! -f test/tsconfig.json ] || tsc --noEmit
|
|
432
|
+
typecheck: '([ -z "$(find functions -name \'*.ts\' 2>/dev/null | head -1)" ] || tsc --noEmit) && ([ ! -f test/tsconfig.json ] || tsc --build --noEmit test) && ([ ! -f frontend/tsconfig.json ] || tsc --build --noEmit frontend)',
|
|
433
433
|
},
|
|
434
434
|
version: config.get('version'),
|
|
435
435
|
};
|
package/dist/lib/apps/index.d.ts
CHANGED
|
@@ -126,6 +126,7 @@ export interface FrontendProjectType {
|
|
|
126
126
|
name: string;
|
|
127
127
|
slug: string;
|
|
128
128
|
}
|
|
129
|
+
export declare const CUSTOM_FRAMEWORK_SLUG = "custom";
|
|
129
130
|
export declare const FrontendProjectTypes: FrontendProjectType[];
|
|
130
131
|
export declare function getFrontendProjectSlugs(withNone?: boolean, withLegacy?: boolean): string[];
|
|
131
132
|
export declare function getFrontendProjectValidValues(withNone?: boolean, withLegacy?: boolean): string;
|
|
@@ -140,6 +141,11 @@ export declare function getProjectCommands(appPath: string, projectType: Fronten
|
|
|
140
141
|
buildCommand?: string;
|
|
141
142
|
devCommand: string;
|
|
142
143
|
};
|
|
144
|
+
/**
|
|
145
|
+
* Get a suggested dev command for an unrecognized frontend project,
|
|
146
|
+
* translated for the detected package manager.
|
|
147
|
+
*/
|
|
148
|
+
export declare function getManualDevHint(appPath: string, port: number): string;
|
|
143
149
|
export declare function getConfigTypeFromPath(path: string): ConfigType | undefined;
|
|
144
150
|
export declare function getConfigTypeKeyFromValue(value: string): string | undefined;
|
|
145
151
|
export declare function filePathExists(filePath: string): boolean;
|
package/dist/lib/apps/index.js
CHANGED
|
@@ -114,6 +114,8 @@ export var ConfigInputFields;
|
|
|
114
114
|
ConfigInputFields["VALUES"] = "values";
|
|
115
115
|
ConfigInputFields["VERSION"] = "version";
|
|
116
116
|
})(ConfigInputFields || (ConfigInputFields = {}));
|
|
117
|
+
// Slug for unrecognized frontend frameworks (manual dev server mode)
|
|
118
|
+
export const CUSTOM_FRAMEWORK_SLUG = 'custom';
|
|
117
119
|
// Frontend project types - all use direct commands run from frontend/ directory
|
|
118
120
|
export const FrontendProjectTypes = [
|
|
119
121
|
{
|
|
@@ -133,7 +135,7 @@ export const FrontendProjectTypes = [
|
|
|
133
135
|
slug: 'angular',
|
|
134
136
|
},
|
|
135
137
|
{
|
|
136
|
-
devCommand: '
|
|
138
|
+
devCommand: 'npm run dev -- --port ${PORT}',
|
|
137
139
|
installCommand: 'npm create cloudflare@latest -- frontend --framework=hono --deploy=false --git=false',
|
|
138
140
|
mainPackage: 'hono',
|
|
139
141
|
name: 'Hono',
|
|
@@ -198,6 +200,16 @@ export function getFrontendProjectType(appPath) {
|
|
|
198
200
|
return detectedType;
|
|
199
201
|
}
|
|
200
202
|
}
|
|
203
|
+
// Fallback: if package.json has a dev script, treat as unrecognized framework
|
|
204
|
+
if (pkg.scripts?.dev) {
|
|
205
|
+
return {
|
|
206
|
+
buildCommand: pkg.scripts?.build ? 'npm run build' : '',
|
|
207
|
+
devCommand: '',
|
|
208
|
+
mainPackage: '',
|
|
209
|
+
name: 'Custom',
|
|
210
|
+
slug: CUSTOM_FRAMEWORK_SLUG,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
201
213
|
}
|
|
202
214
|
catch {
|
|
203
215
|
// Ignore JSON parse errors, try next path
|
|
@@ -220,6 +232,14 @@ export function getProjectCommands(appPath, projectType) {
|
|
|
220
232
|
devCommand: transformCommand(projectType.devCommand, pm),
|
|
221
233
|
};
|
|
222
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Get a suggested dev command for an unrecognized frontend project,
|
|
237
|
+
* translated for the detected package manager.
|
|
238
|
+
*/
|
|
239
|
+
export function getManualDevHint(appPath, port) {
|
|
240
|
+
const pm = detectPackageManager(appPath);
|
|
241
|
+
return transformCommand(`npm run dev -- --port ${port}`, pm);
|
|
242
|
+
}
|
|
223
243
|
export function getConfigTypeFromPath(path) {
|
|
224
244
|
for (const type in AllConfigPaths) {
|
|
225
245
|
if (AllConfigPaths[type] === path) {
|
package/dist/lib/config.js
CHANGED
|
@@ -7,12 +7,13 @@ import prodEnv from '../env/production.js';
|
|
|
7
7
|
import reviewEnv from '../env/review.js';
|
|
8
8
|
import stagingEnv from '../env/staging.js';
|
|
9
9
|
import style from './style.js';
|
|
10
|
+
const swellHome = process.env.SWELL_CONFIG_HOME || homedir();
|
|
10
11
|
const configPath = process.env.NODE_ENV === 'test'
|
|
11
12
|
? path.resolve(process.cwd(), 'test', '.swell', 'config.json')
|
|
12
|
-
: path.resolve(
|
|
13
|
+
: path.resolve(swellHome, '.swell', 'config.json');
|
|
13
14
|
const configDir = process.env.NODE_ENV === 'test'
|
|
14
15
|
? path.resolve(process.cwd(), 'test', 'fixtures')
|
|
15
|
-
:
|
|
16
|
+
: swellHome;
|
|
16
17
|
const configStore = new Configstore('swell', {
|
|
17
18
|
// user: {...},
|
|
18
19
|
// defaultStore: '<store_id>',
|
|
@@ -21,7 +21,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
21
21
|
protected showFrontendMigrationError(): never;
|
|
22
22
|
buildFrontend(projectType?: FrontendProjectType): Promise<void>;
|
|
23
23
|
chooseAppToPull(query?: any): Promise<App>;
|
|
24
|
-
createAppStorefront(hasOtherStorefronts?: boolean): Promise<any>;
|
|
24
|
+
createAppStorefront(hasOtherStorefronts?: boolean, nonInteractive?: boolean): Promise<any>;
|
|
25
25
|
deployAppFrontend(force?: boolean, log?: boolean): Promise<void>;
|
|
26
26
|
deployFrontend(projectType: FrontendProjectType): Promise<string>;
|
|
27
27
|
ensureAppExists(file?: string, shouldCreate?: boolean): Promise<boolean>;
|
|
@@ -59,6 +59,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
59
59
|
env?: string;
|
|
60
60
|
'storefront-id'?: string;
|
|
61
61
|
'storefront-select'?: boolean;
|
|
62
|
+
yes?: boolean;
|
|
62
63
|
}): Promise<any>;
|
|
63
64
|
setStorefrontEnv(flags: {
|
|
64
65
|
env?: string;
|
package/dist/push-app-command.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as path from 'node:path';
|
|
|
6
6
|
import Stream from 'node:stream';
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import { default as swellConfig } from './lib/app-config.js';
|
|
9
|
-
import { ConfigType, getFrontendProjectValidValues, allConfigFilesInDir, appConfigFromFile, filePathExists, filePathExistsAsync, findAppConfig, getAppSlugId, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, getProjectCommands, globAllFilesByPath, hashString, isPathDirectory, } from './lib/apps/index.js';
|
|
9
|
+
import { ConfigType, getFrontendProjectValidValues, allConfigFilesInDir, CUSTOM_FRAMEWORK_SLUG, appConfigFromFile, filePathExists, filePathExistsAsync, findAppConfig, getAppSlugId, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, getProjectCommands, globAllFilesByPath, hashString, isPathDirectory, } from './lib/apps/index.js';
|
|
10
10
|
import { getGlobIgnorePathsChecker } from './lib/apps/paths.js';
|
|
11
11
|
import { default as localConfig } from './lib/config.js';
|
|
12
12
|
import { toAppId } from './lib/create/index.js';
|
|
@@ -110,6 +110,14 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
110
110
|
this.showFrontendMigrationError();
|
|
111
111
|
return; // unreachable but helps TypeScript narrow the type
|
|
112
112
|
}
|
|
113
|
+
// Skip automatic build for unrecognized frameworks
|
|
114
|
+
if (projectType.slug === CUSTOM_FRAMEWORK_SLUG) {
|
|
115
|
+
if (projectType.buildCommand) {
|
|
116
|
+
this.log(`Skipping automatic frontend build for unrecognized framework.\n` +
|
|
117
|
+
`Run your build command manually before deploying.\n`);
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
113
121
|
// Get commands transformed for the detected package manager
|
|
114
122
|
const { buildCommand } = getProjectCommands(this.appPath, projectType);
|
|
115
123
|
if (!buildCommand) {
|
|
@@ -140,7 +148,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
140
148
|
this.log();
|
|
141
149
|
return app;
|
|
142
150
|
}
|
|
143
|
-
async createAppStorefront(hasOtherStorefronts = true) {
|
|
151
|
+
async createAppStorefront(hasOtherStorefronts = true, nonInteractive = false) {
|
|
144
152
|
let appId;
|
|
145
153
|
let themeAppId;
|
|
146
154
|
if (this.app.type === 'theme') {
|
|
@@ -155,6 +163,12 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
155
163
|
if (compatibleStorefrontApps.length === 0) {
|
|
156
164
|
this.error('No compatible storefront apps found for this theme. Install a new storefront app first.');
|
|
157
165
|
}
|
|
166
|
+
if (compatibleStorefrontApps.length > 1 && nonInteractive) {
|
|
167
|
+
const appList = compatibleStorefrontApps
|
|
168
|
+
.map((app) => ` ${app.id} (${app.name})`)
|
|
169
|
+
.join('\n');
|
|
170
|
+
this.error(`Multiple compatible storefront apps found. Run without -y to select one interactively:\n${appList}`);
|
|
171
|
+
}
|
|
158
172
|
const targetApp = compatibleStorefrontApps.length === 1
|
|
159
173
|
? compatibleStorefrontApps[0]
|
|
160
174
|
: await select({
|
|
@@ -169,37 +183,49 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
169
183
|
}
|
|
170
184
|
else if (this.app.type === 'storefront') {
|
|
171
185
|
appId = this.app.id;
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
targetApp
|
|
186
|
+
const requiresTheme = this.app.storefront?.theme?.provider === 'app';
|
|
187
|
+
if (requiresTheme) {
|
|
188
|
+
const themeApps = await this.handleRequestErrors(async () => this.api.get({
|
|
189
|
+
adminPath: `/apps?type=theme`,
|
|
190
|
+
}));
|
|
191
|
+
const compatibleThemeApps = themeApps.results.filter((app) => app.installed &&
|
|
192
|
+
Object.keys(app.compatibilities || {}).includes(this.app.private_id));
|
|
193
|
+
if (compatibleThemeApps.length === 0) {
|
|
194
|
+
this.error('No compatible theme apps found for this storefront. Install a new theme app first.');
|
|
195
|
+
}
|
|
196
|
+
let targetApp;
|
|
197
|
+
if (compatibleThemeApps.length === 1) {
|
|
198
|
+
targetApp = compatibleThemeApps[0];
|
|
199
|
+
}
|
|
200
|
+
else if (nonInteractive) {
|
|
201
|
+
const appList = compatibleThemeApps
|
|
202
|
+
.map((app) => ` ${app.id} (${app.name})`)
|
|
203
|
+
.join('\n');
|
|
204
|
+
this.error(`Multiple compatible theme apps found. Run without -y to select one interactively:\n${appList}`);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
targetApp = await select({
|
|
208
|
+
choices: compatibleThemeApps.map((app) => ({
|
|
209
|
+
name: `${style.appConfigValue(app.name)} v${app.version}`,
|
|
210
|
+
value: app,
|
|
211
|
+
})),
|
|
212
|
+
message: 'Choose a theme app',
|
|
213
|
+
});
|
|
214
|
+
this.log();
|
|
215
|
+
}
|
|
216
|
+
themeAppId = targetApp.id;
|
|
217
|
+
this.log(`${style.success('✔')} Using ${style.appConfigValue(targetApp.name)} v${targetApp.version}\n`);
|
|
183
218
|
}
|
|
184
219
|
else {
|
|
185
|
-
|
|
186
|
-
choices: compatibleThemeApps.map((app) => ({
|
|
187
|
-
name: `${style.appConfigValue(app.name)} v${app.version}`,
|
|
188
|
-
value: app,
|
|
189
|
-
})),
|
|
190
|
-
message: 'Choose a theme app',
|
|
191
|
-
});
|
|
192
|
-
this.log();
|
|
220
|
+
this.log(`${style.success('✔')} Creating storefront without theme app\n`);
|
|
193
221
|
}
|
|
194
|
-
themeAppId = targetApp.id;
|
|
195
|
-
this.log(`${style.success('✔')} Using ${style.appConfigValue(targetApp.name)} v${targetApp.version}\n`);
|
|
196
222
|
}
|
|
197
223
|
else {
|
|
198
224
|
this.error('App type not supported for storefront creation');
|
|
199
225
|
}
|
|
200
226
|
let name;
|
|
201
227
|
// Leave name blank when syncing theme app to avoid blocking push
|
|
202
|
-
if (hasOtherStorefronts && !this.themeSyncApp) {
|
|
228
|
+
if (hasOtherStorefronts && !this.themeSyncApp && !nonInteractive) {
|
|
203
229
|
name = await input({
|
|
204
230
|
default: this.app.name,
|
|
205
231
|
message: 'Name your storefront',
|
|
@@ -504,6 +530,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
504
530
|
return this.storefront;
|
|
505
531
|
}
|
|
506
532
|
async getStorefrontToPush(flags = {}) {
|
|
533
|
+
const nonInteractive = flags.yes || false;
|
|
507
534
|
const targetStorefront = flags['storefront-id'];
|
|
508
535
|
const defaultStorefront = localConfig.getDefaultStorefront(this.appPath);
|
|
509
536
|
let storefrontId = targetStorefront || defaultStorefront?.id;
|
|
@@ -518,22 +545,37 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
518
545
|
// Choose storefront if multiple storefronts exist
|
|
519
546
|
// Except if we are syncing a theme app, then force create new storefront if not found
|
|
520
547
|
if (storefronts.count > 0 && !this.themeSyncApp) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
}
|
|
548
|
+
if (nonInteractive) {
|
|
549
|
+
if (storefronts.count === 1) {
|
|
550
|
+
const sf = storefronts.results[0];
|
|
551
|
+
storefrontId = sf.id;
|
|
552
|
+
this.log(`${style.success('✔')} Using storefront ${style.appConfigValue(sf.name)} (${sf.id})\n`);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
const sfList = storefronts.results
|
|
556
|
+
.map((sf) => ` ${sf.id} (${sf.name})${sf.primary ? ' [primary]' : ''}`)
|
|
557
|
+
.join('\n');
|
|
558
|
+
this.error(`Multiple storefronts found. Specify one with --storefront-id:\n${sfList}`);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
storefrontId = await select({
|
|
563
|
+
choices: [
|
|
564
|
+
...storefronts.results.map((storefront) => ({
|
|
565
|
+
name: `${style.appConfigValue(storefront.name)} (${storefront.id}) ${storefront.primary ? '[primary]' : ''}`,
|
|
566
|
+
value: storefront.id,
|
|
567
|
+
})),
|
|
568
|
+
{
|
|
569
|
+
name: 'Create new storefront',
|
|
570
|
+
value: null,
|
|
571
|
+
},
|
|
572
|
+
],
|
|
573
|
+
message: 'Choose a storefront',
|
|
574
|
+
});
|
|
575
|
+
}
|
|
534
576
|
}
|
|
535
577
|
if (!storefrontId) {
|
|
536
|
-
this.storefront = await this.createAppStorefront(storefronts.count > 0);
|
|
578
|
+
this.storefront = await this.createAppStorefront(storefronts.count > 0, nonInteractive);
|
|
537
579
|
}
|
|
538
580
|
}
|
|
539
581
|
if (storefrontId) {
|
|
@@ -547,7 +589,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
547
589
|
}
|
|
548
590
|
this.log(`Storefront ${style.appConfigValue(storefrontId)} not found.\n`);
|
|
549
591
|
localConfig.setDefaultStorefront(this.appPath, '');
|
|
550
|
-
return this.getStorefrontToPush();
|
|
592
|
+
return this.getStorefrontToPush({ yes: nonInteractive });
|
|
551
593
|
}
|
|
552
594
|
}
|
|
553
595
|
this.app = await this.getApp(this.app.id);
|
|
@@ -758,7 +800,9 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
758
800
|
$environment_id: 'test',
|
|
759
801
|
frontend: {
|
|
760
802
|
deployment_hash: deploymentHash,
|
|
761
|
-
|
|
803
|
+
...(projectType.slug !== CUSTOM_FRAMEWORK_SLUG && {
|
|
804
|
+
framework: projectType.slug,
|
|
805
|
+
}),
|
|
762
806
|
service: 'cloudflare',
|
|
763
807
|
url: deploymentUrl,
|
|
764
808
|
},
|
package/oclif.manifest.json
CHANGED
|
@@ -727,6 +727,13 @@
|
|
|
727
727
|
"name": "storefront-select",
|
|
728
728
|
"allowNo": false,
|
|
729
729
|
"type": "boolean"
|
|
730
|
+
},
|
|
731
|
+
"yes": {
|
|
732
|
+
"char": "y",
|
|
733
|
+
"description": "skip prompts (non-interactive mode)",
|
|
734
|
+
"name": "yes",
|
|
735
|
+
"allowNo": false,
|
|
736
|
+
"type": "boolean"
|
|
730
737
|
}
|
|
731
738
|
},
|
|
732
739
|
"hasDynamicHelp": false,
|
|
@@ -2483,6 +2490,13 @@
|
|
|
2483
2490
|
"hasDynamicHelp": false,
|
|
2484
2491
|
"multiple": false,
|
|
2485
2492
|
"type": "option"
|
|
2493
|
+
},
|
|
2494
|
+
"yes": {
|
|
2495
|
+
"char": "y",
|
|
2496
|
+
"description": "skip prompts (non-interactive mode)",
|
|
2497
|
+
"name": "yes",
|
|
2498
|
+
"allowNo": false,
|
|
2499
|
+
"type": "boolean"
|
|
2486
2500
|
}
|
|
2487
2501
|
},
|
|
2488
2502
|
"hasDynamicHelp": false,
|
|
@@ -2770,6 +2784,13 @@
|
|
|
2770
2784
|
"name": "sync-app",
|
|
2771
2785
|
"allowNo": false,
|
|
2772
2786
|
"type": "boolean"
|
|
2787
|
+
},
|
|
2788
|
+
"yes": {
|
|
2789
|
+
"char": "y",
|
|
2790
|
+
"description": "skip prompts (non-interactive mode)",
|
|
2791
|
+
"name": "yes",
|
|
2792
|
+
"allowNo": false,
|
|
2793
|
+
"type": "boolean"
|
|
2773
2794
|
}
|
|
2774
2795
|
},
|
|
2775
2796
|
"hasDynamicHelp": false,
|
|
@@ -2780,9 +2801,7 @@
|
|
|
2780
2801
|
"pluginType": "core",
|
|
2781
2802
|
"summary": "Push local files to your Swell theme.",
|
|
2782
2803
|
"delayOrientation": true,
|
|
2783
|
-
"orientation": {
|
|
2784
|
-
"env": "test"
|
|
2785
|
-
},
|
|
2804
|
+
"orientation": {},
|
|
2786
2805
|
"isESM": true,
|
|
2787
2806
|
"relativePath": [
|
|
2788
2807
|
"dist",
|
|
@@ -2827,6 +2846,13 @@
|
|
|
2827
2846
|
"name": "storefront-select",
|
|
2828
2847
|
"allowNo": false,
|
|
2829
2848
|
"type": "boolean"
|
|
2849
|
+
},
|
|
2850
|
+
"yes": {
|
|
2851
|
+
"char": "y",
|
|
2852
|
+
"description": "skip prompts (non-interactive mode)",
|
|
2853
|
+
"name": "yes",
|
|
2854
|
+
"allowNo": false,
|
|
2855
|
+
"type": "boolean"
|
|
2830
2856
|
}
|
|
2831
2857
|
},
|
|
2832
2858
|
"hasDynamicHelp": false,
|
|
@@ -2901,10 +2927,16 @@
|
|
|
2901
2927
|
"allowNo": false,
|
|
2902
2928
|
"type": "boolean"
|
|
2903
2929
|
},
|
|
2930
|
+
"yes": {
|
|
2931
|
+
"char": "y",
|
|
2932
|
+
"description": "skip prompts (non-interactive mode)",
|
|
2933
|
+
"name": "yes",
|
|
2934
|
+
"allowNo": false,
|
|
2935
|
+
"type": "boolean"
|
|
2936
|
+
},
|
|
2904
2937
|
"proxy-port": {
|
|
2905
|
-
"description": "specify the port for
|
|
2938
|
+
"description": "specify the port for the frontend proxy",
|
|
2906
2939
|
"name": "proxy-port",
|
|
2907
|
-
"default": 3001,
|
|
2908
2940
|
"hasDynamicHelp": false,
|
|
2909
2941
|
"multiple": false,
|
|
2910
2942
|
"type": "option"
|
|
@@ -2937,5 +2969,5 @@
|
|
|
2937
2969
|
]
|
|
2938
2970
|
}
|
|
2939
2971
|
},
|
|
2940
|
-
"version": "2.
|
|
2972
|
+
"version": "2.5.1"
|
|
2941
2973
|
}
|