@swell/cli 2.3.4 → 2.4.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.
Files changed (40) hide show
  1. package/dist/commands/api/delete.d.ts +1 -0
  2. package/dist/commands/api/delete.js +8 -1
  3. package/dist/commands/api/get.d.ts +1 -0
  4. package/dist/commands/api/get.js +9 -2
  5. package/dist/commands/api/index.js +4 -2
  6. package/dist/commands/api/post.d.ts +1 -0
  7. package/dist/commands/api/post.js +9 -2
  8. package/dist/commands/api/put.d.ts +1 -0
  9. package/dist/commands/api/put.js +9 -2
  10. package/dist/commands/app/dev.js +6 -2
  11. package/dist/commands/app/frontend/dev.js +6 -3
  12. package/dist/commands/create/app.js +2 -2
  13. package/dist/commands/create/frontend.js +2 -2
  14. package/dist/commands/create/tests.js +5 -2
  15. package/dist/commands/inspect/models.d.ts +0 -1
  16. package/dist/commands/inspect/models.js +2 -15
  17. package/dist/commands/theme/dev.js +10 -7
  18. package/dist/create-app-command.d.ts +8 -2
  19. package/dist/create-app-command.js +137 -79
  20. package/dist/env/local.d.ts +1 -0
  21. package/dist/env/local.js +1 -0
  22. package/dist/env/production.d.ts +1 -0
  23. package/dist/env/production.js +1 -0
  24. package/dist/env/review.d.ts +1 -0
  25. package/dist/env/review.js +1 -0
  26. package/dist/env/staging.d.ts +1 -0
  27. package/dist/env/staging.js +1 -0
  28. package/dist/lib/api.d.ts +5 -2
  29. package/dist/lib/api.js +60 -9
  30. package/dist/lib/apps/index.d.ts +11 -0
  31. package/dist/lib/apps/index.js +45 -46
  32. package/dist/lib/constants.d.ts +1 -0
  33. package/dist/lib/constants.js +5 -0
  34. package/dist/lib/create/tests.js +1 -1
  35. package/dist/lib/package-manager.d.ts +86 -0
  36. package/dist/lib/package-manager.js +186 -0
  37. package/dist/push-app-command.js +13 -6
  38. package/dist/swell-api-command.js +8 -2
  39. package/oclif.manifest.json +76 -15
  40. package/package.json +1 -1
@@ -8,6 +8,7 @@ export default class ApiDelete extends SwellApiCommand {
8
8
  };
9
9
  static flags: {
10
10
  live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
11
+ api: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
12
  };
12
13
  static examples: string[];
13
14
  get method(): HttpMethod;
@@ -3,7 +3,8 @@ import { HttpMethod } from '../../lib/api.js';
3
3
  import { SwellApiCommand } from '../../swell-api-command.js';
4
4
  export default class ApiDelete extends SwellApiCommand {
5
5
  static summary = 'Send a DELETE request to the Swell API.';
6
- static description = 'Remove existing resources from the Swell Backend API.';
6
+ static description = `Remove existing resources from the Swell API.
7
+ Use --api frontend for public key authentication scoped to your app or user.`;
7
8
  static args = {
8
9
  path: Args.string({
9
10
  description: 'API endpoint path (must start with /)',
@@ -15,10 +16,16 @@ export default class ApiDelete extends SwellApiCommand {
15
16
  description: 'Use live environment instead of test',
16
17
  default: false,
17
18
  }),
19
+ api: Flags.string({
20
+ description: 'Use frontend or backend API (frontend uses public key auth).',
21
+ options: ['backend', 'frontend'],
22
+ default: 'backend',
23
+ }),
18
24
  };
19
25
  static examples = [
20
26
  'swell api delete /products/abc123',
21
27
  'swell api delete /functions/my-app/clear-cache',
28
+ 'swell api delete /products/abc123 --api frontend',
22
29
  ];
23
30
  get method() {
24
31
  return HttpMethod.DELETE;
@@ -8,6 +8,7 @@ export default class ApiGet extends SwellApiCommand {
8
8
  };
9
9
  static flags: {
10
10
  live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
11
+ api: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
12
  };
12
13
  static examples: string[];
13
14
  get method(): HttpMethod;
@@ -3,8 +3,9 @@ import { HttpMethod } from '../../lib/api.js';
3
3
  import { SwellApiCommand } from '../../swell-api-command.js';
4
4
  export default class ApiGet extends SwellApiCommand {
5
5
  static summary = 'Send a GET request to the Swell API.';
6
- static description = `Retrieve data from the Swell Backend API.
7
- The command performs a GET request to the specified endpoint path.`;
6
+ static description = `Retrieve data from the Swell API.
7
+ The command performs a GET request to the specified endpoint path.
8
+ Use --api frontend for public key authentication scoped to your app or user.`;
8
9
  static args = {
9
10
  path: Args.string({
10
11
  description: 'API endpoint path (must start with /)',
@@ -16,12 +17,18 @@ export default class ApiGet extends SwellApiCommand {
16
17
  description: 'Use live environment instead of test',
17
18
  default: false,
18
19
  }),
20
+ api: Flags.string({
21
+ description: 'Use frontend or backend API (frontend uses public key auth).',
22
+ options: ['backend', 'frontend'],
23
+ default: 'backend',
24
+ }),
19
25
  };
20
26
  static examples = [
21
27
  'swell api get /products',
22
28
  'swell api get "/products?limit=10&category=shoes"',
23
29
  'swell api get /products/abc123',
24
30
  'swell api get /functions/my-app/get-inventory',
31
+ 'swell api get /products --api frontend',
25
32
  ];
26
33
  get method() {
27
34
  return HttpMethod.GET;
@@ -2,8 +2,9 @@ import { Command } from '@oclif/core';
2
2
  export default class Api extends Command {
3
3
  static summary = 'Send requests directly to the Swell Backend API.';
4
4
  static description = `Run Swell API requests directly from the command line.
5
- Supports GET, POST, PUT, and DELETE methods with optional test/live environments.
6
- Call app functions via /functions/<app_id>/<function_name> paths.`;
5
+ Supports GET, POST, PUT, and DELETE methods with optional test/live environments.
6
+ Use --api frontend for public key authentication via the frontend API.
7
+ Call app functions via /functions/<app_id>/<function_name> paths.`;
7
8
  static examples = [
8
9
  'swell api get /products',
9
10
  'swell api post /products --body \'{"name":"New product"}\'',
@@ -11,6 +12,7 @@ export default class Api extends Command {
11
12
  'swell api delete /products/abc123',
12
13
  'swell api get /functions/my-app/get-inventory',
13
14
  'swell api post /functions/my-app/create-order --body \'{"items":["sku-1"]}\'',
15
+ 'swell api get /products --api frontend',
14
16
  ];
15
17
  async run() {
16
18
  this.log('Use "swell api get|post|put|delete" to interact with the Swell API.');
@@ -9,6 +9,7 @@ export default class ApiPost extends SwellApiCommand {
9
9
  static flags: {
10
10
  body: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
11
  live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
+ api: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
13
  };
13
14
  static examples: string[];
14
15
  get method(): HttpMethod;
@@ -3,8 +3,9 @@ import { HttpMethod } from '../../lib/api.js';
3
3
  import { SwellApiCommand } from '../../swell-api-command.js';
4
4
  export default class ApiPost extends SwellApiCommand {
5
5
  static summary = 'Send a POST request to the Swell API.';
6
- static description = `Create new resources in the Swell Backend API.
7
- You can provide a JSON body directly or specify a file path containing JSON data.`;
6
+ static description = `Create new resources in the Swell API.
7
+ You can provide a JSON body directly or specify a file path containing JSON data.
8
+ Use --api frontend for public key authentication scoped to your app or user.`;
8
9
  static args = {
9
10
  path: Args.string({
10
11
  description: 'API endpoint path (must start with /)',
@@ -19,11 +20,17 @@ export default class ApiPost extends SwellApiCommand {
19
20
  description: 'Use live environment instead of test',
20
21
  default: false,
21
22
  }),
23
+ api: Flags.string({
24
+ description: 'Use frontend or backend API (frontend uses public key auth).',
25
+ options: ['backend', 'frontend'],
26
+ default: 'backend',
27
+ }),
22
28
  };
23
29
  static examples = [
24
30
  'swell api post /products --body \'{"name": "Product", "price": 100}\'',
25
31
  'swell api post /products --body ./product.json',
26
32
  'swell api post /functions/my-app/create-order --body \'{"items":["sku-1"]}\'',
33
+ `swell api post /products --body '{"name": "Product"}' --api frontend`,
27
34
  ];
28
35
  get method() {
29
36
  return HttpMethod.POST;
@@ -9,6 +9,7 @@ export default class ApiPut extends SwellApiCommand {
9
9
  static flags: {
10
10
  body: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
11
  live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
+ api: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
13
  };
13
14
  static examples: string[];
14
15
  get method(): HttpMethod;
@@ -3,8 +3,9 @@ import { HttpMethod } from '../../lib/api.js';
3
3
  import { SwellApiCommand } from '../../swell-api-command.js';
4
4
  export default class ApiPut extends SwellApiCommand {
5
5
  static summary = 'Send a PUT request to the Swell API.';
6
- static description = `Update existing resources in the Swell Backend API.
7
- You can provide a JSON body directly or specify a file path containing JSON data.`;
6
+ static description = `Update existing resources in the Swell API.
7
+ You can provide a JSON body directly or specify a file path containing JSON data.
8
+ Use --api frontend for public key authentication scoped to your app or user.`;
8
9
  static args = {
9
10
  path: Args.string({
10
11
  description: 'API endpoint path (must start with /)',
@@ -19,11 +20,17 @@ export default class ApiPut extends SwellApiCommand {
19
20
  description: 'Use live environment instead of test',
20
21
  default: false,
21
22
  }),
23
+ api: Flags.string({
24
+ description: 'Use frontend or backend API (frontend uses public key auth).',
25
+ options: ['backend', 'frontend'],
26
+ default: 'backend',
27
+ }),
22
28
  };
23
29
  static examples = [
24
30
  'swell api put /products/{id} --body \'{"id": "abc123", "name": "Updated"}\'',
25
31
  'swell api put /products/abc123 --body ./product.json',
26
32
  'swell api put /functions/my-app/update-stock --body \'{"sku":"abc","qty":10}\'',
33
+ `swell api put /products/abc123 --body '{"name": "Updated"}' --api frontend`,
27
34
  ];
28
35
  get method() {
29
36
  return HttpMethod.PUT;
@@ -8,6 +8,7 @@ import * as path from 'node:path';
8
8
  import ora from 'ora';
9
9
  import { ConfigType, allConfigFilesInDir, appConfigFromFile, } from '../../lib/apps/index.js';
10
10
  import { bundleFunction } from '../../lib/bundle.js';
11
+ import { detectPackageManager, getExecSpawnArgs, } from '../../lib/package-manager.js';
11
12
  import style from '../../lib/style.js';
12
13
  import { PushAppCommand } from '../../push-app-command.js';
13
14
  export default class AppDev extends PushAppCommand {
@@ -345,8 +346,11 @@ ENVIRONMENT = "development"
345
346
  const configPath = path.join(this.tmpDir, `${functionName}.toml`);
346
347
  await fs.promises.writeFile(configPath, wranglerConfig);
347
348
  functionStatus.set(functionName, 'starting');
348
- // Start wrangler process in background
349
- const wranglerProcess = spawn('npx', [
349
+ // Start wrangler process in background using detected package manager
350
+ const pm = detectPackageManager(this.appPath);
351
+ const { program, prefixArgs } = getExecSpawnArgs(pm);
352
+ const wranglerProcess = spawn(program, [
353
+ ...prefixArgs,
350
354
  'wrangler',
351
355
  'dev',
352
356
  `--config=${configPath}`,
@@ -1,4 +1,5 @@
1
1
  import { Flags } from '@oclif/core';
2
+ import { getProjectCommands, } from '../../../lib/apps/index.js';
2
3
  import { default as localConfig } from '../../../lib/config.js';
3
4
  import style from '../../../lib/style.js';
4
5
  import { PushAppCommand } from '../../../push-app-command.js';
@@ -69,9 +70,11 @@ export default class AppFrontendDev extends PushAppCommand {
69
70
  if (!projectType) {
70
71
  return;
71
72
  }
73
+ // Get commands transformed for the detected package manager
74
+ const { devCommand } = getProjectCommands(this.appPath, projectType);
72
75
  const currentStore = localConfig.getDefaultStore();
73
76
  let serverReadyDetected = false;
74
- await this.execFrontend(projectType.devCommand.replace('${PORT}', String(serverPort)), (string) => {
77
+ await this.execFrontend(devCommand.replace('${PORT}', String(serverPort)), (string) => {
75
78
  // Framework-specific output handling and ready detection
76
79
  switch (projectType.slug) {
77
80
  case 'nextjs': {
@@ -127,8 +130,8 @@ export default class AppFrontendDev extends PushAppCommand {
127
130
  }
128
131
  // 3. READY DETECTION: Detect server ready, show our message
129
132
  if (!serverReadyDetected &&
130
- (/application bundle generation complete/.test(string) ||
131
- /watch mode enabled/.test(string))) {
133
+ (/application bundle generation complete/i.test(string) ||
134
+ /watch mode enabled/i.test(string))) {
132
135
  serverReadyDetected = true;
133
136
  this.log(`Started ${projectType.name} dev server on port ${serverPort}.\n`);
134
137
  const sessionId = localConfig.getSessionId(currentStore);
@@ -70,8 +70,8 @@ export default class CreateApp extends CreateAppCommand {
70
70
  pkg: Flags.string({
71
71
  char: 'p',
72
72
  default: 'npm',
73
- description: 'Package manager: npm | yarn | none',
74
- options: ['npm', 'yarn', 'none'],
73
+ description: 'Package manager: npm | yarn | pnpm | bun | none',
74
+ options: ['npm', 'yarn', 'pnpm', 'bun', 'none'],
75
75
  }),
76
76
  type: Flags.string({
77
77
  char: 't',
@@ -18,8 +18,8 @@ export default class CreateFrontend extends CreateAppCommand {
18
18
  pkg: Flags.string({
19
19
  char: 'p',
20
20
  default: 'npm',
21
- description: `use npm or yarn to install default dependencies, or none to disable`,
22
- options: ['npm', 'yarn', 'none'],
21
+ description: `Package manager: npm | yarn | pnpm | bun | none`,
22
+ options: ['npm', 'yarn', 'pnpm', 'bun', 'none'],
23
23
  }),
24
24
  };
25
25
  async run() {
@@ -2,6 +2,7 @@ import { Flags } from '@oclif/core';
2
2
  import { AppCommand } from '../../app-command.js';
3
3
  import { toAppId } from '../../lib/create/index.js';
4
4
  import { createTestsScaffold, } from '../../lib/create/tests.js';
5
+ import { detectPackageManager, getPackageManagerCommands, } from '../../lib/package-manager.js';
5
6
  export default class CreateTests extends AppCommand {
6
7
  static description = 'Initialize a vitest + Cloudflare Workers test setup that reuses swell-cli authentication.';
7
8
  static examples = [
@@ -66,10 +67,12 @@ export default class CreateTests extends AppCommand {
66
67
  this.warn(warning);
67
68
  }
68
69
  if (hasChanges) {
70
+ const pm = detectPackageManager(this.appPath);
71
+ const commands = getPackageManagerCommands(pm);
69
72
  this.log('');
70
73
  this.log('Next steps:');
71
- this.log(' 1. npm install');
72
- this.log(' 2. npm test');
74
+ this.log(` 1. ${commands.install}`);
75
+ this.log(` 2. ${commands.run('test')}`);
73
76
  }
74
77
  this.log('');
75
78
  }
@@ -17,7 +17,6 @@ export default class Models extends SwellCommand {
17
17
  private showAppModels;
18
18
  private showModels;
19
19
  private getModelPath;
20
- private getCurrentAppSlugId;
21
20
  private getAppSlugId;
22
21
  private showModelDetail;
23
22
  private resolveModelPath;
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import * as fs from 'node:fs';
3
2
  import { FetchError } from 'node-fetch';
3
+ import { getCurrentAppSlugId } from '../../lib/apps/index.js';
4
4
  import { default as localConfig } from '../../lib/config.js';
5
5
  import { SwellCommand } from '../../swell-command.js';
6
6
  export default class Models extends SwellCommand {
@@ -109,7 +109,7 @@ With a collection path, it retrieves the model for that specific collection in J
109
109
  this.showModels(models, 'Standard');
110
110
  }
111
111
  async showAppModels(appsById, modelsByAppId) {
112
- const currentAppSlugId = await this.getCurrentAppSlugId();
112
+ const currentAppSlugId = await getCurrentAppSlugId();
113
113
  for (const [appId, app] of Object.entries(appsById)) {
114
114
  const models = modelsByAppId[appId];
115
115
  if (models) {
@@ -153,19 +153,6 @@ With a collection path, it retrieves the model for that specific collection in J
153
153
  }
154
154
  return `/${model.name}`;
155
155
  }
156
- async getCurrentAppSlugId() {
157
- const hasAppContext = fs.existsSync('swell.json');
158
- if (!hasAppContext) {
159
- return;
160
- }
161
- try {
162
- const appConfig = JSON.parse(await fs.promises.readFile('swell.json', 'utf8'));
163
- return appConfig.id;
164
- }
165
- catch {
166
- // noop
167
- }
168
- }
169
156
  getAppSlugId(app) {
170
157
  return app.public_id || app.private_id.replace(/^_/, '');
171
158
  }
@@ -4,6 +4,7 @@ import { execSync, spawn } from 'node:child_process';
4
4
  import fs from 'node:fs';
5
5
  import ora from 'ora';
6
6
  import { default as localConfig } from '../../lib/config.js';
7
+ import { findLockFile, getPackageManager } from '../../lib/package-manager.js';
7
8
  import style from '../../lib/style.js';
8
9
  import { ThemeSync } from '../../lib/theme-sync.js';
9
10
  import { PushAppCommand } from '../../push-app-command.js';
@@ -74,11 +75,10 @@ export default class AppThemeDev extends PushAppCommand {
74
75
  async findAndInstallDependencies() {
75
76
  const spinner = ora('Locating package.json...').start();
76
77
  try {
77
- const packageJsonLockPath = await findUp('package-lock.json', {
78
- type: 'file',
79
- });
80
- if (packageJsonLockPath) {
81
- spinner.succeed('package-lock.json found. Skipping npm install.');
78
+ // Check for any package manager lock file
79
+ const lockFile = findLockFile(process.cwd());
80
+ if (lockFile) {
81
+ spinner.succeed(`${lockFile.name} found. Skipping dependency install.`);
82
82
  return null;
83
83
  }
84
84
  const packageJsonPath = await findUp('package.json', { type: 'file' });
@@ -88,7 +88,8 @@ export default class AppThemeDev extends PushAppCommand {
88
88
  }
89
89
  spinner.succeed(`Found package.json at ${packageJsonPath}`);
90
90
  spinner.start('Installing dependencies...');
91
- execSync('npm install', { stdio: 'inherit' });
91
+ const { commands } = getPackageManager(process.cwd());
92
+ execSync(commands.install, { stdio: 'inherit' });
92
93
  spinner.succeed('Dependencies installed');
93
94
  return packageJsonPath;
94
95
  }
@@ -109,7 +110,9 @@ export default class AppThemeDev extends PushAppCommand {
109
110
  console.warn('"bundle" script not found in package.json');
110
111
  return;
111
112
  }
112
- const childProcess = spawn('npm', ['run', 'bundle'], {
113
+ const { commands } = getPackageManager(process.cwd());
114
+ const runCommand = commands.run('bundle').split(' ');
115
+ const childProcess = spawn(runCommand[0], runCommand.slice(1), {
113
116
  env: { ...process.env, BROWSERSLIST_IGNORE_OLD_DATA: 'true' },
114
117
  shell: true,
115
118
  stdio: 'pipe',
@@ -1,3 +1,4 @@
1
+ import { PackageManager } from './lib/package-manager.js';
1
2
  import { SwellCommand } from './swell-command.js';
2
3
  export declare abstract class CreateAppCommand extends SwellCommand {
3
4
  protected commandExample: string;
@@ -13,6 +14,11 @@ export declare abstract class CreateAppCommand extends SwellCommand {
13
14
  addAllowedHostsToAngular(configPath: string): Promise<void>;
14
15
  addAllowedHostsToAstro(configPath: string): Promise<void>;
15
16
  addAllowedHostsToNuxt(configPath: string): Promise<void>;
17
+ /**
18
+ * Add vite allowedHosts configuration to a framework config file.
19
+ * Supports config files that use a defineX({}) pattern (Astro, Nuxt, etc.)
20
+ */
21
+ private addViteAllowedHosts;
16
22
  createAppConfigFolders(swellConfig: any): Promise<void>;
17
23
  createFrontendApp(swellConfig: any, flags: any, directCreate?: boolean, kind?: string): Promise<boolean>;
18
24
  createStorefrontApp(swellConfig: any, flags: any, directCreate?: boolean): Promise<boolean>;
@@ -29,7 +35,7 @@ export declare abstract class CreateAppCommand extends SwellCommand {
29
35
  name: string;
30
36
  slug: string;
31
37
  };
32
- setupPackage(name: string, config: any, pkg: string): Promise<void>;
33
- tryPackageSetup(name: string, config: any, pkg: string): Promise<void>;
38
+ setupPackage(name: string, config: any, pkg: PackageManager): Promise<void>;
39
+ tryPackageSetup(name: string, config: any, pkg: PackageManager): Promise<void>;
34
40
  private addFrontendAllowedHosts;
35
41
  }