@swell/cli 2.0.1-alpha.16 → 2.0.1-alpha.17

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.
Files changed (76) hide show
  1. package/dist/app-command.d.ts +1 -1
  2. package/dist/app-command.js +8 -8
  3. package/dist/commands/app/dev.d.ts +18 -0
  4. package/dist/commands/app/dev.js +31 -0
  5. package/dist/commands/app/frontend/deploy.d.ts +17 -0
  6. package/dist/commands/app/frontend/deploy.js +44 -0
  7. package/dist/commands/app/frontend/dev.d.ts +21 -0
  8. package/dist/commands/app/frontend/dev.js +111 -0
  9. package/dist/commands/app/info.js +15 -8
  10. package/dist/commands/app/init.d.ts +12 -0
  11. package/dist/commands/app/init.js +34 -0
  12. package/dist/commands/app/install.d.ts +0 -3
  13. package/dist/commands/app/install.js +12 -20
  14. package/dist/commands/app/pull.d.ts +15 -0
  15. package/dist/commands/app/pull.js +50 -0
  16. package/dist/commands/app/push.d.ts +10 -13
  17. package/dist/commands/app/push.js +64 -135
  18. package/dist/commands/app/release.d.ts +13 -0
  19. package/dist/commands/app/release.js +150 -0
  20. package/dist/commands/app/version.d.ts +7 -6
  21. package/dist/commands/app/version.js +61 -40
  22. package/dist/commands/app/watch.d.ts +2 -4
  23. package/dist/commands/app/watch.js +3 -83
  24. package/dist/commands/create/app.d.ts +35 -11
  25. package/dist/commands/create/app.js +141 -138
  26. package/dist/commands/create/frontend.d.ts +12 -0
  27. package/dist/commands/create/frontend.js +41 -0
  28. package/dist/commands/create/function.d.ts +2 -2
  29. package/dist/commands/create/function.js +2 -2
  30. package/dist/commands/create/notification.d.ts +2 -2
  31. package/dist/commands/create/notification.js +2 -2
  32. package/dist/commands/login.js +6 -4
  33. package/dist/commands/logs.js +0 -1
  34. package/dist/commands/theme/dev.d.ts +23 -0
  35. package/dist/commands/theme/dev.js +167 -0
  36. package/dist/commands/theme/init.d.ts +9 -0
  37. package/dist/commands/theme/init.js +15 -0
  38. package/dist/commands/theme/pull.d.ts +20 -0
  39. package/dist/commands/theme/pull.js +65 -0
  40. package/dist/commands/theme/push.d.ts +19 -0
  41. package/dist/commands/theme/push.js +92 -0
  42. package/dist/create-app-command.d.ts +20 -0
  43. package/dist/create-app-command.js +254 -0
  44. package/dist/create-collection-command.d.ts +3 -3
  45. package/dist/create-collection-command.js +4 -4
  46. package/dist/{create-command.d.ts → create-config-command.d.ts} +1 -1
  47. package/dist/{create-command.js → create-config-command.js} +3 -3
  48. package/dist/lib/api.d.ts +3 -2
  49. package/dist/lib/api.js +47 -21
  50. package/dist/lib/app-config.d.ts +12 -5
  51. package/dist/lib/app-config.js +59 -24
  52. package/dist/lib/apps/app-config.d.ts +22 -8
  53. package/dist/lib/apps/app-config.js +202 -68
  54. package/dist/lib/apps/index.d.ts +93 -13
  55. package/dist/lib/apps/index.js +150 -50
  56. package/dist/lib/apps/paths.d.ts +14 -7
  57. package/dist/lib/apps/paths.js +73 -28
  58. package/dist/lib/config.d.ts +5 -1
  59. package/dist/lib/config.js +14 -0
  60. package/dist/lib/constants.d.ts +5 -0
  61. package/dist/lib/constants.js +20 -0
  62. package/dist/lib/create/content.d.ts +1 -1
  63. package/dist/lib/create/index.js +5 -1
  64. package/dist/lib/info.js +2 -2
  65. package/dist/lib/stores.d.ts +1 -1
  66. package/dist/lib/stores.js +3 -3
  67. package/dist/lib/style.d.ts +2 -0
  68. package/dist/lib/style.js +2 -0
  69. package/dist/push-app-command.d.ts +73 -0
  70. package/dist/push-app-command.js +765 -0
  71. package/dist/remote-app-command.d.ts +33 -7
  72. package/dist/remote-app-command.js +423 -151
  73. package/oclif.manifest.json +794 -81
  74. package/package.json +13 -2
  75. package/dist/commands/app/_pull.d.ts +0 -8
  76. package/dist/commands/app/_pull.js +0 -45
@@ -1,11 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as fs from 'node:fs';
3
- import * as path from 'node:path';
4
- import { appConfigFileExists } from '../../lib/app-config.js';
5
- import { appConfigFromFile, findAppConfig, getConfigTypeFromPath, hasAllowedFileExtension, } from '../../lib/apps/index.js';
6
- import style from '../../lib/style.js';
7
- import { RemoteAppCommand } from '../../remote-app-command.js';
8
- export default class AppWatch extends RemoteAppCommand {
2
+ import { PushAppCommand } from '../../push-app-command.js';
3
+ export default class AppWatch extends PushAppCommand {
9
4
  static description = `Watches configuration files including functions, and automatically pushes
10
5
  to the remote store.
11
6
 
@@ -26,85 +21,10 @@ Optionally synchronize all configs on change.`;
26
21
  env: 'test',
27
22
  };
28
23
  static summary = 'Watch for changes and push app configurations.';
29
- watchListener = async (eventType, filename) => {
30
- const configFile = filename;
31
- const pathParsed = path.parse(configFile);
32
- const fileDirs = pathParsed.dir.split(path.sep);
33
- // only the first directory is relevant for us
34
- const configDir = fileDirs[0];
35
- // we only want to watch files in the root of the app directory
36
- // and with the allowed extensions
37
- if (!configDir ||
38
- fileDirs.length > 1 ||
39
- !hasAllowedFileExtension(configFile)) {
40
- return;
41
- }
42
- const configType = getConfigTypeFromPath(configDir);
43
- if (!configType) {
44
- this.debug(`watchListener: ${filename} is not a valid config type`);
45
- return;
46
- }
47
- let watchFileEvent;
48
- // per node docs:
49
- //
50
- // On most platforms, 'rename' is emitted whenever a filename appears
51
- // or disappears in the directory.
52
- //
53
- // we want however to identify delete file events so we can send the
54
- // correct API request
55
- if (eventType === 'rename') {
56
- watchFileEvent = 'new';
57
- if (!appConfigFileExists(path.join(this.appPath, configFile))) {
58
- watchFileEvent = 'deleted';
59
- }
60
- }
61
- else {
62
- watchFileEvent = 'change';
63
- }
64
- try {
65
- await this.handleFileChange(configFile, configType, watchFileEvent);
66
- }
67
- catch (error) {
68
- // we don't want to break the watcher if an error is thrown while
69
- // handling a file change
70
- this.debug(error);
71
- // for tests though, we want to break the watcher
72
- if (process.env.NODE_ENV === 'test') {
73
- // throwing does not break the test so we need to hard exit and log
74
- // the error
75
- console.error(style.error(error));
76
- // eslint-disable-next-line no-process-exit, unicorn/no-process-exit
77
- process.exit(1);
78
- }
79
- }
80
- // refetch app to get updated configs
81
- this.app = await this.getAppWithConfig(this.app.id);
82
- };
83
24
  async run() {
84
25
  const { flags } = await this.parse(AppWatch);
85
26
  this.app = await this.getAppWithConfig();
86
27
  this.log('Watching for changes...');
87
- if (flags['sync-all']) {
88
- await this.syncAppConfigs();
89
- fs.watch(this.appPath, { recursive: true }, async (eventType, filename) => {
90
- if (filename && hasAllowedFileExtension(filename)) {
91
- await this.syncAppConfigs();
92
- }
93
- });
94
- return;
95
- }
96
- fs.watch(this.appPath, { recursive: true }, this.watchListener);
97
- }
98
- async handleFileChange(configFile, configType, event) {
99
- if (event === 'deleted') {
100
- const appConfig = findAppConfig(this.app, configFile, configType);
101
- if (!appConfig) {
102
- return;
103
- }
104
- return this.removeConfig(appConfig);
105
- }
106
- const appConfig = appConfigFromFile(path.join(this.appPath, configFile), configType);
107
- const result = await this.pushConfigFile(appConfig);
108
- this.debug(`handleFileChange: ${configFile} pushed`, result);
28
+ await this.watchForChanges({ syncAll: flags['sync-all'] });
109
29
  }
110
30
  }
@@ -1,5 +1,6 @@
1
- import { SwellCommand } from '../../swell-command.js';
2
- export default class CreateApp extends SwellCommand {
1
+ import { CreateAppCommand } from '../../create-app-command.js';
2
+ export default class CreateApp extends CreateAppCommand {
3
+ appType: string;
3
4
  static args: {
4
5
  id: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
6
  };
@@ -8,14 +9,37 @@ export default class CreateApp extends SwellCommand {
8
9
  command: string;
9
10
  description: string;
10
11
  }[];
11
- static flags: {
12
- pkg: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
13
- yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
14
- };
12
+ static flags: any;
15
13
  run(): Promise<void>;
16
- private createAppConfigFolders;
17
- private doesPackageManagerExist;
18
- private findPackageManager;
19
- private setupPackage;
20
- private tryPackageSetup;
14
+ createSwellConfig({ inputId, inputYes, inputType, inputStorefrontApp, allowOverwrite, nestedPath, }: {
15
+ inputId: string;
16
+ inputYes?: boolean;
17
+ inputType?: string;
18
+ inputStorefrontApp?: string;
19
+ allowOverwrite?: boolean;
20
+ nestedPath?: boolean;
21
+ }): Promise<{
22
+ appId: string;
23
+ swellConfigJson: {
24
+ permissions: never[];
25
+ id: string;
26
+ name: string;
27
+ description: string;
28
+ type: string;
29
+ version: string;
30
+ } | {
31
+ theme: {
32
+ storefront: {
33
+ app: string;
34
+ };
35
+ };
36
+ id: string;
37
+ name: string;
38
+ description: string;
39
+ type: string;
40
+ version: string;
41
+ };
42
+ config: any;
43
+ installedStorefrontApp: any;
44
+ } | undefined>;
21
45
  }
@@ -1,23 +1,20 @@
1
1
  import { confirm, input, select } from '@inquirer/prompts';
2
2
  import { Args, Flags } from '@oclif/core';
3
- import { exec } from 'node:child_process';
4
3
  import path from 'node:path';
5
- import { promisify } from 'node:util';
6
4
  import ora from 'ora';
7
- import { appConfigFileExists, newConfig } from '../../lib/app-config.js';
8
- import { getAllConfigPaths, writeJsonFile } from '../../lib/apps/index.js';
5
+ import { swellConfigFileExists, newConfig } from '../../lib/app-config.js';
9
6
  import { toAppId, toAppName } from '../../lib/create/index.js';
10
7
  import style from '../../lib/style.js';
11
- import { SwellCommand } from '../../swell-command.js';
12
- const execAsync = promisify(exec);
13
- export default class CreateApp extends SwellCommand {
8
+ import { CreateAppCommand } from '../../create-app-command.js';
9
+ export default class CreateApp extends CreateAppCommand {
10
+ appType = '';
14
11
  static args = {
15
12
  id: Args.string({
16
13
  default: '',
17
14
  description: `id of the app to create`,
18
15
  }),
19
16
  };
20
- static description = 'Initialize an app with config file and folder structure.';
17
+ static description = 'Create an app.';
21
18
  static examples = [
22
19
  {
23
20
  command: 'swell create app',
@@ -37,75 +34,172 @@ export default class CreateApp extends SwellCommand {
37
34
  },
38
35
  ];
39
36
  static flags = {
37
+ type: Flags.string({
38
+ char: 't',
39
+ description: `create a specific app type`,
40
+ options: ['admin', 'integration', 'storefront', 'theme'],
41
+ }),
40
42
  pkg: Flags.string({
41
43
  char: 'p',
42
44
  default: 'npm',
43
45
  description: `use npm or yarn to install default dependencies, or none to disable`,
44
46
  options: ['npm', 'yarn', 'none'],
45
47
  }),
46
- yes: Flags.boolean({
47
- char: 'y',
48
- description: `accept all default values`,
49
- }),
50
48
  };
51
49
  async run() {
52
50
  const { args, flags } = await this.parse(CreateApp);
53
51
  const { id } = args;
54
52
  const { pkg, yes } = flags;
55
- let confirmYes = yes && id;
53
+ let confirmYes = Boolean(yes && id);
54
+ const createParams = await this.createSwellConfig({
55
+ inputId: id,
56
+ inputYes: confirmYes,
57
+ inputType: flags['type'],
58
+ inputStorefrontApp: flags['storefront-app'],
59
+ });
60
+ if (!createParams) {
61
+ return;
62
+ }
63
+ const { appId, config, installedStorefrontApp } = createParams;
64
+ !confirmYes && this.log();
65
+ const spinner = ora();
66
+ spinner.start('Creating app...');
67
+ if (pkg !== 'none') {
68
+ await this.tryPackageSetup(appId, config, pkg);
69
+ }
70
+ await this.createAppConfigFolders(config);
71
+ spinner.succeed(`${style.appConfigValue(config.get('name'))} app created.\n`);
72
+ let createdFrontend, createdTheme;
73
+ if (installedStorefrontApp) {
74
+ createdTheme = await this.createThemeApp(config, flags, installedStorefrontApp);
75
+ }
76
+ else if (config.get('type') === 'storefront') {
77
+ createdFrontend = await this.createStorefrontApp(config, flags);
78
+ }
79
+ else {
80
+ createdFrontend = await this.createFrontendApp(config, flags);
81
+ }
82
+ this.log('\nNext steps:');
83
+ this.log(`Run ${style.command('swell app push')} to push configurations to your test store.`);
84
+ this.log(`Run ${style.command('swell app install')} to install the app in another store or environment.`);
85
+ if (createdFrontend) {
86
+ this.log(`Run ${style.command('swell app frontend dev')} to start a local dev server for your frontend app.`);
87
+ }
88
+ else if (createdTheme) {
89
+ this.log(`Run ${style.command('swell app theme dev')} to start a local dev server for your theme.`);
90
+ }
91
+ }
92
+ async createSwellConfig({ inputId, inputYes, inputType, inputStorefrontApp, allowOverwrite = true, nestedPath = true, }) {
93
+ let confirmYes = inputYes;
94
+ const type = inputType ||
95
+ (confirmYes
96
+ ? 'admin'
97
+ : await select({
98
+ choices: [
99
+ { name: 'Admin', value: 'admin' },
100
+ { name: 'Integration', value: 'integration' },
101
+ { name: 'Storefront', value: 'storefront' },
102
+ { name: 'Theme', value: 'theme' },
103
+ ],
104
+ message: `What is the primary purpose of the app?`,
105
+ }));
106
+ const typeLabel = type === 'theme' ? 'theme' : 'app';
107
+ const typeLabelTitle = type === 'theme' ? 'Theme' : 'App';
56
108
  const name = confirmYes
57
- ? toAppName(id)
109
+ ? toAppName(inputId)
58
110
  : await input({
59
- default: id ? toAppName(id) : '',
60
- message: 'App name',
111
+ default: inputId ? toAppName(inputId) : '',
112
+ message: `${typeLabelTitle} name`,
61
113
  validate: (answer) => answer.length > 2,
62
114
  });
63
- let appId = toAppId(id || '');
115
+ let appId = toAppId(inputId || '');
64
116
  if (!appId) {
65
117
  appId = await input({
66
118
  default: toAppId(name),
67
- message: 'App ID',
119
+ message: `${typeLabelTitle} ID`,
68
120
  validate: (answer) => answer.length > 2,
69
121
  });
70
122
  appId = toAppId(appId);
71
- confirmYes = yes && appId;
123
+ confirmYes = Boolean(inputYes && appId);
72
124
  }
125
+ const version = confirmYes
126
+ ? '1.0.0'
127
+ : await input({
128
+ default: '1.0.0',
129
+ message: `${typeLabelTitle} version`,
130
+ });
73
131
  const description = confirmYes
74
132
  ? ''
75
133
  : await input({
76
134
  default: 'Something special',
77
- message: 'Describe what the app does',
78
- });
79
- const type = confirmYes
80
- ? 'admin'
81
- : await select({
82
- choices: [
83
- { name: 'Admin', value: 'admin' },
84
- { name: 'Integration', value: 'integration' },
85
- { name: 'Storefront', value: 'storefront' },
86
- ],
87
- message: 'What is the primary purpose of the app?',
135
+ message: `Describe your ${typeLabel}`,
88
136
  });
89
- const appConfigJson = {
90
- description,
137
+ let storefrontInstalledApps;
138
+ let storefrontAppId;
139
+ let installedStorefrontApp;
140
+ if (type === 'theme') {
141
+ storefrontInstalledApps = await this.getInstalledStorefrontApps();
142
+ if (storefrontInstalledApps === false) {
143
+ return;
144
+ }
145
+ storefrontAppId =
146
+ inputStorefrontApp || (storefrontInstalledApps.length > 1
147
+ ? (await select({
148
+ choices: [
149
+ ...storefrontInstalledApps.map(({ id, app }) => ({
150
+ name: app.name,
151
+ value: id,
152
+ })),
153
+ ],
154
+ message: `Which storefront app is your theme for?`,
155
+ }))
156
+ : storefrontInstalledApps[0].id);
157
+ installedStorefrontApp = storefrontInstalledApps.find((installedApp) => inputStorefrontApp
158
+ ? inputStorefrontApp === installedApp.app_private_id ||
159
+ inputStorefrontApp === installedApp.app_public_id ||
160
+ inputStorefrontApp === installedApp.app_id ||
161
+ inputStorefrontApp === toAppId(installedApp.app_private_id)
162
+ : installedApp.id === storefrontAppId);
163
+ if (!installedStorefrontApp) {
164
+ this.error(`Could not find an installed storefront app by id: ${storefrontAppId}`);
165
+ }
166
+ }
167
+ const swellConfigJson = {
91
168
  id: appId,
92
- integrations: [],
93
169
  name,
94
- permissions: [],
170
+ description,
95
171
  type,
96
- version: '1.0.0',
172
+ version,
173
+ ...(type !== 'theme'
174
+ ? {
175
+ permissions: [],
176
+ }
177
+ : {
178
+ theme: {
179
+ storefront: {
180
+ app: toAppId(installedStorefrontApp.app_private_id),
181
+ },
182
+ },
183
+ }),
97
184
  };
98
- const config = newConfig(appId);
99
- if (!confirmYes && appConfigFileExists(config.path)) {
100
- const continueCreateApp = await confirm({
101
- message: `An app already exists in the target folder ${appId}. Overwrite?`,
102
- });
103
- if (!continueCreateApp) {
104
- return;
185
+ const appPath = path.join(process.cwd(), appId);
186
+ if (swellConfigFileExists(appPath)) {
187
+ if (allowOverwrite) {
188
+ if (!confirmYes) {
189
+ const continueCreateApp = await confirm({
190
+ message: `An app already exists in the target path ${appPath}. Overwrite?`,
191
+ });
192
+ if (!continueCreateApp) {
193
+ return;
194
+ }
195
+ }
196
+ }
197
+ else {
198
+ this.error(`An app already exists in the target path ${appPath}.`);
105
199
  }
106
200
  }
107
- this.log(`\nCreating app ${style.appConfigValue(name)} in ${config.path}`);
108
- this.log(`\n${JSON.stringify(appConfigJson, null, 4)}\n`);
201
+ this.log(`\nCreating ${this.appType === 'theme' ? 'theme' : 'app'} ${style.appConfigValue(name)} in ${appPath}/swell.json`);
202
+ this.log(`\n${JSON.stringify(swellConfigJson, null, 2)}\n`);
109
203
  const confirmCreateApp = confirmYes
110
204
  ? true
111
205
  : await confirm({
@@ -114,100 +208,9 @@ export default class CreateApp extends SwellCommand {
114
208
  if (!confirmCreateApp) {
115
209
  return;
116
210
  }
117
- !confirmYes && this.log();
118
- const spinner = ora();
119
- spinner.start('Creating app...');
211
+ const config = newConfig(nestedPath ? appId : '');
120
212
  config.clear();
121
- config.set(appConfigJson);
122
- if (pkg !== 'none') {
123
- await this.tryPackageSetup(appId, config, pkg);
124
- }
125
- await this.createAppConfigFolders(config);
126
- spinner.succeed(`${style.appConfigValue(name)} app created.`);
127
- this.log('\nNext steps:');
128
- this.log(`Run ${style.command('swell app push')} to push configurations to your test store.`);
129
- this.log(`Run ${style.command('swell app install')} to install the app in another store or environment.`);
130
- }
131
- async createAppConfigFolders(config) {
132
- for (const type of getAllConfigPaths()) {
133
- // Create a config folder
134
- // eslint-disable-next-line no-await-in-loop
135
- await execAsync(`mkdir -p ${type}`, {
136
- cwd: path.dirname(config.path),
137
- });
138
- // Create gitkeep file
139
- // eslint-disable-next-line no-await-in-loop
140
- await execAsync(`touch ${path.join(type, '.gitkeep')}`, {
141
- cwd: path.dirname(config.path),
142
- });
143
- }
144
- }
145
- async doesPackageManagerExist(packageManager) {
146
- try {
147
- await execAsync(`${packageManager} --version`);
148
- return true;
149
- }
150
- catch {
151
- this.debug(`Could not find ${packageManager} on your system. Please install ${packageManager} and try again.`);
152
- return false;
153
- }
154
- }
155
- async findPackageManager(pkg = '') {
156
- const packageManager = pkg;
157
- // Determine if system has yarn or npm install
158
- if (packageManager) {
159
- if (await this.doesPackageManagerExist(packageManager)) {
160
- return packageManager;
161
- }
162
- }
163
- else {
164
- if (await this.doesPackageManagerExist('npm')) {
165
- return 'npm';
166
- }
167
- if (await this.doesPackageManagerExist('yarn')) {
168
- return 'yarn';
169
- }
170
- }
171
- }
172
- async setupPackage(name, config, pkg) {
173
- const execAsync = promisify(exec);
174
- const packageJson = {
175
- description: config.get('description'),
176
- devDependencies: {
177
- '@swell/app-types': '^1.0.5',
178
- },
179
- name,
180
- scripts: {},
181
- version: config.get('version'),
182
- };
183
- const tsConfig = {
184
- compilerOptions: {
185
- lib: ['esnext', 'webworker'],
186
- module: 'esnext',
187
- target: 'esnext',
188
- types: ['@swell/app-types'],
189
- },
190
- exclude: ['node_modules'],
191
- include: ['**/*.ts'],
192
- };
193
- await writeJsonFile(path.join(path.dirname(config.path), 'package.json'), packageJson);
194
- await writeJsonFile(path.join(path.dirname(config.path), 'tsconfig.json'), tsConfig);
195
- try {
196
- const packageManager = await this.findPackageManager(pkg);
197
- await execAsync(`${packageManager} install`, {
198
- cwd: path.dirname(config.path),
199
- });
200
- }
201
- catch (error) {
202
- this.error(error.message);
203
- }
204
- }
205
- async tryPackageSetup(name, config, pkg) {
206
- try {
207
- await this.setupPackage(name, config, pkg);
208
- }
209
- catch (error) {
210
- this.log(`There was an error setting up the package manager: ${error.message}`);
211
- }
213
+ config.set(swellConfigJson);
214
+ return { appId, swellConfigJson, config, installedStorefrontApp };
212
215
  }
213
216
  }
@@ -0,0 +1,12 @@
1
+ import { CreateAppCommand } from '../../create-app-command.js';
2
+ export default class CreateFrontend extends CreateAppCommand {
3
+ static description: string;
4
+ static examples: {
5
+ command: string;
6
+ description: string;
7
+ }[];
8
+ static flags: {
9
+ pkg: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,41 @@
1
+ import { Flags } from '@oclif/core';
2
+ import ora from 'ora';
3
+ import swellConfig from '../../lib/app-config.js';
4
+ import { CreateAppCommand } from '../../create-app-command.js';
5
+ export default class CreateFrontend extends CreateAppCommand {
6
+ static description = 'Initialize a frontend app framework and folder structure.';
7
+ static examples = [
8
+ {
9
+ command: 'swell create frontend',
10
+ description: 'Create frontend app following command prompts.',
11
+ },
12
+ {
13
+ command: 'swell create frontend -y',
14
+ description: 'Create frontend app and accept all default values.',
15
+ },
16
+ ];
17
+ static flags = {
18
+ pkg: Flags.string({
19
+ char: 'p',
20
+ default: 'npm',
21
+ description: `use npm or yarn to install default dependencies, or none to disable`,
22
+ options: ['npm', 'yarn', 'none'],
23
+ }),
24
+ };
25
+ async run() {
26
+ const { flags } = await this.parse(CreateFrontend);
27
+ const newSwellConfig = swellConfig();
28
+ const appType = newSwellConfig?.get('type');
29
+ const spinner = ora();
30
+ if (appType === 'theme') {
31
+ spinner.fail(`You can't create app frontend in a theme.`);
32
+ return;
33
+ }
34
+ if (appType === 'storefront') {
35
+ await this.createStorefrontApp(newSwellConfig, flags, true);
36
+ }
37
+ else {
38
+ await this.createFrontendApp(newSwellConfig, flags, true);
39
+ }
40
+ }
41
+ }
@@ -1,6 +1,6 @@
1
- import { CreateCommand } from '../../create-command.js';
1
+ import { CreateConfigCommand } from '../../create-config-command.js';
2
2
  import { ConfigType } from '../../lib/apps/index.js';
3
- export default class CreateFunction extends CreateCommand {
3
+ export default class CreateFunction extends CreateConfigCommand {
4
4
  static args: {
5
5
  functionName: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
6
6
  trigger: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
@@ -1,11 +1,11 @@
1
1
  import { input, select } from '@inquirer/prompts';
2
2
  import { Args, Flags } from '@oclif/core';
3
- import { CreateCommand } from '../../create-command.js';
3
+ import { CreateConfigCommand } from '../../create-config-command.js';
4
4
  import { ConfigType } from '../../lib/apps/index.js';
5
5
  import { getFunctionTemplate, } from '../../lib/create/function.js';
6
6
  import { toFunctionFileName } from '../../lib/create/index.js';
7
7
  const PERMITTED_TRIGGERS = ['cron', 'model', 'route'];
8
- export default class CreateFunction extends CreateCommand {
8
+ export default class CreateFunction extends CreateConfigCommand {
9
9
  static args = {
10
10
  functionName: Args.string({
11
11
  description: 'function name, used in an http route if applicable',
@@ -1,6 +1,6 @@
1
- import { CreateCommand } from '../../create-command.js';
1
+ import { CreateConfigCommand } from '../../create-config-command.js';
2
2
  import { ConfigType } from '../../lib/apps/index.js';
3
- export default class CreateNotification extends CreateCommand {
3
+ export default class CreateNotification extends CreateConfigCommand {
4
4
  static args: {
5
5
  model: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
6
6
  name: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
@@ -1,10 +1,10 @@
1
1
  import { input, select } from '@inquirer/prompts';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { capitalize, singularize } from 'inflection';
4
- import { CreateCommand } from '../../create-command.js';
4
+ import { CreateConfigCommand } from '../../create-config-command.js';
5
5
  import { ConfigType } from '../../lib/apps/index.js';
6
6
  import { toFileName, toNotificationLabel } from '../../lib/create/index.js';
7
- export default class CreateNotification extends CreateCommand {
7
+ export default class CreateNotification extends CreateConfigCommand {
8
8
  static args = {
9
9
  model: Args.string({
10
10
  description: 'data model to trigger the notification by',
@@ -34,6 +34,10 @@ have available for logging in to.
34
34
  try {
35
35
  user = await this.api.get({ adminPath: 'user' });
36
36
  config.setUser(user);
37
+ this.log(`You are already logged in to ${style.storeId(currentStoreId)} as ${style.currentUser(user.username)}. Use --force to login again, or \`swell switch\` to switch stores.`);
38
+ // eslint-disable-next-line no-process-exit, unicorn/no-process-exit
39
+ process.env.NODE_ENV !== 'test' && process.exit(0);
40
+ return;
37
41
  }
38
42
  catch {
39
43
  // noop
@@ -43,11 +47,9 @@ have available for logging in to.
43
47
  this.api.setStoreEnv(storeId);
44
48
  user = await this.api.get({ adminPath: 'user' }, { sessionId });
45
49
  await this.getAndSetStoreConfig({ sessionId, storeId });
46
- await modifyDefaultStore({ currentStoreId, storeId });
50
+ await modifyDefaultStore({ currentStoreId, storeId }, force);
47
51
  config.setUser(user);
48
- this.log(`You are now logged in to ${style.storeId(storeId)} as ${style.currentUser(user.username)}.`);
49
- // eslint-disable-next-line no-process-exit, unicorn/no-process-exit
50
- process.env.NODE_ENV !== 'test' && process.exit(0);
52
+ this.log(`\nYou are now logged in to ${style.storeId(storeId)} as ${style.currentUser(user.username)}.`);
51
53
  }
52
54
  /**
53
55
  * Use the /user/switch API request to either get the session id for the
@@ -191,7 +191,6 @@ export default class Logs extends SwellCommand {
191
191
  }
192
192
  async getLogs(flags) {
193
193
  const body = buildLogRequestBody(flags);
194
- this.debug('getLogs body', body);
195
194
  const response = await this.api.post({ adminPath: `/data/$get/:logs` }, { body });
196
195
  return response?.results?.reverse() || [];
197
196
  }
@@ -0,0 +1,23 @@
1
+ import { Config } from '@oclif/core';
2
+ import { PushAppCommand } from '../../push-app-command.js';
3
+ export default class AppThemeDev extends PushAppCommand {
4
+ appType: string;
5
+ static summary: string;
6
+ static examples: string[];
7
+ static flags: {
8
+ 'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
9
+ 'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
+ local: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
11
+ bundle: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
+ 'no-push': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
13
+ };
14
+ static orientation: {
15
+ env: string;
16
+ };
17
+ constructor(argv: string[], config: Config);
18
+ run(): Promise<void>;
19
+ private findAndInstallDependencies;
20
+ private findAndTryScriptCommands;
21
+ private startThemeDevServer;
22
+ logAppLocalUrl(storeId: string, sessionId: string): void;
23
+ }