@swell/cli 2.9.3 → 2.9.5

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 (80) hide show
  1. package/dist/app-command.d.ts +2 -3
  2. package/dist/app-command.js +3 -6
  3. package/dist/commands/app/dev.d.ts +2 -2
  4. package/dist/commands/app/dev.js +49 -33
  5. package/dist/commands/app/frontend/dev.js +12 -6
  6. package/dist/commands/app/push.d.ts +1 -0
  7. package/dist/commands/app/push.js +3 -3
  8. package/dist/commands/app/release.js +2 -2
  9. package/dist/commands/create/app.d.ts +1 -1
  10. package/dist/commands/create/app.js +1 -1
  11. package/dist/commands/create/frontend.js +3 -3
  12. package/dist/commands/create/tests.js +10 -8
  13. package/dist/commands/inspect/extensions.js +4 -4
  14. package/dist/commands/schema.js +21 -18
  15. package/dist/commands/theme/dev.js +5 -5
  16. package/dist/commands/theme/push.d.ts +1 -0
  17. package/dist/commands/theme/push.js +3 -3
  18. package/dist/create-app-command.js +2 -2
  19. package/dist/create-config-command.d.ts +1 -1
  20. package/dist/create-config-command.js +3 -3
  21. package/dist/help/custom-help.d.ts +1 -1
  22. package/dist/help/types.d.ts +1 -1
  23. package/dist/lib/api.d.ts +1 -0
  24. package/dist/lib/api.js +1 -1
  25. package/dist/lib/app-config.d.ts +13 -8
  26. package/dist/lib/app-config.js +25 -23
  27. package/dist/lib/apps/app-config.d.ts +5 -5
  28. package/dist/lib/apps/app-config.js +53 -37
  29. package/dist/lib/apps/index.d.ts +15 -14
  30. package/dist/lib/apps/index.js +40 -23
  31. package/dist/lib/apps/paths.d.ts +1 -1
  32. package/dist/lib/apps/paths.js +3 -3
  33. package/dist/lib/bundle.js +26 -17
  34. package/dist/lib/config.d.ts +8 -8
  35. package/dist/lib/config.js +8 -10
  36. package/dist/lib/constants.d.ts +9 -9
  37. package/dist/lib/create/content.d.ts +6 -6
  38. package/dist/lib/create/content.js +7 -8
  39. package/dist/lib/create/function.d.ts +5 -6
  40. package/dist/lib/create/function.js +7 -8
  41. package/dist/lib/create/index.d.ts +8 -9
  42. package/dist/lib/create/index.js +7 -8
  43. package/dist/lib/create/model.d.ts +4 -4
  44. package/dist/lib/create/model.js +4 -5
  45. package/dist/lib/create/notification.d.ts +2 -3
  46. package/dist/lib/create/setting.d.ts +4 -4
  47. package/dist/lib/create/setting.js +3 -4
  48. package/dist/lib/create/tests/types.d.ts +3 -4
  49. package/dist/lib/create/tests.d.ts +1 -2
  50. package/dist/lib/create/tests.js +12 -13
  51. package/dist/lib/create/webhook.d.ts +6 -6
  52. package/dist/lib/create/webhook.js +15 -10
  53. package/dist/lib/function-source-analysis.js +3 -3
  54. package/dist/lib/info.d.ts +1 -1
  55. package/dist/lib/logs/index.d.ts +1 -0
  56. package/dist/lib/logs/line-output.d.ts +1 -0
  57. package/dist/lib/logs/line-output.js +12 -4
  58. package/dist/lib/logs/output.d.ts +1 -0
  59. package/dist/lib/logs/table-output.d.ts +1 -0
  60. package/dist/lib/logs/table-output.js +8 -5
  61. package/dist/lib/package-manager.d.ts +5 -5
  62. package/dist/lib/package-manager.js +9 -7
  63. package/dist/lib/proxy.js +4 -3
  64. package/dist/lib/sessions.d.ts +1 -2
  65. package/dist/lib/sessions.js +1 -2
  66. package/dist/lib/stores.d.ts +6 -6
  67. package/dist/lib/stores.js +5 -6
  68. package/dist/lib/swell-function-wrapper.d.ts +1 -193
  69. package/dist/lib/swell-function-wrapper.js +1 -1
  70. package/dist/lib/theme-sync.js +0 -5
  71. package/dist/push-app-command.d.ts +8 -6
  72. package/dist/push-app-command.js +45 -51
  73. package/dist/remote-app-command.d.ts +6 -4
  74. package/dist/remote-app-command.js +39 -25
  75. package/dist/swell-api-command.d.ts +1 -0
  76. package/dist/swell-api-command.js +3 -3
  77. package/dist/types/index.d.ts +94 -0
  78. package/dist/types/index.js +4 -0
  79. package/oclif.manifest.json +1 -1
  80. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import { Config } from '@oclif/core';
1
+ import type { LocalApp } from './types/index.js';
2
2
  import { SwellCommand } from './swell-command.js';
3
3
  /**
4
4
  * A base class for Swell CLI commands that do not require an app to be saved
@@ -15,8 +15,7 @@ export declare abstract class AppCommand extends SwellCommand {
15
15
  'app-path': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
16
16
  };
17
17
  appPath: string;
18
- swellConfig: any;
19
- constructor(argv: string[], config: Config);
18
+ swellConfig: LocalApp;
20
19
  init(): Promise<void>;
21
20
  protected initBaseFlags(): Promise<void>;
22
21
  }
@@ -24,12 +24,9 @@ export class AppCommand extends SwellCommand {
24
24
  appPath = '';
25
25
  // local app configuration, what developers define
26
26
  swellConfig;
27
- constructor(argv, config) {
28
- super(argv, config);
29
- this.swellConfig = swellConfig();
30
- this.appPath = path.resolve(this.swellConfig.swDirPath);
31
- }
32
27
  async init() {
28
+ this.swellConfig = await swellConfig();
29
+ this.appPath = path.resolve(this.swellConfig.swDirPath);
33
30
  await super.init();
34
31
  await this.initBaseFlags();
35
32
  }
@@ -39,7 +36,7 @@ export class AppCommand extends SwellCommand {
39
36
  klass.flags = { ...klass.flags, ...AppCommand.baseFlags };
40
37
  const { flags } = await this.parse(klass);
41
38
  // if the user passed an app path, use it: reload the app config
42
- this.swellConfig = swellConfig(flags['app-path']);
39
+ this.swellConfig = await swellConfig(flags['app-path']);
43
40
  this.appPath = path.resolve(this.swellConfig.swDirPath);
44
41
  }
45
42
  }
@@ -1,4 +1,4 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import { ChildProcess } from 'node:child_process';
3
3
  import { PushAppCommand } from '../../push-app-command.js';
4
4
  export default class AppDev extends PushAppCommand {
@@ -26,7 +26,7 @@ export default class AppDev extends PushAppCommand {
26
26
  isCleaningUp: boolean;
27
27
  run(): Promise<void>;
28
28
  private cleanupOnExit;
29
- runAppFrontendDevIfApplicable(frontendPort?: number): Promise<number | void>;
29
+ runAppFrontendDevIfApplicable(frontendPort?: number): Promise<number | undefined>;
30
30
  private createFunctionRouter;
31
31
  private createTmpDirectory;
32
32
  private generateWranglerConfig;
@@ -1,7 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import getPort, { portNumbers } from 'get-port';
3
3
  import { spawn } from 'node:child_process';
4
- import * as fs from 'node:fs';
4
+ import * as fs from 'node:fs/promises';
5
5
  import * as http from 'node:http';
6
6
  import * as os from 'node:os';
7
7
  import * as path from 'node:path';
@@ -108,7 +108,7 @@ export default class AppDev extends PushAppCommand {
108
108
  process.exit();
109
109
  }
110
110
  async runAppFrontendDevIfApplicable(frontendPort) {
111
- const projectType = this.getFrontendProjectType(false);
111
+ const projectType = await this.getFrontendProjectType(false);
112
112
  if (projectType) {
113
113
  // add app-dev flag to avoid watching for changes
114
114
  this.argv.push('--app-dev');
@@ -121,9 +121,15 @@ export default class AppDev extends PushAppCommand {
121
121
  .runCommand('app:frontend:dev', this.argv)
122
122
  .catch((error) => {
123
123
  // SIGTERM/SIGINT during dev server shutdown is expected
124
- if (error?.signal === 'SIGTERM' || error?.signal === 'SIGINT')
125
- return;
126
- this.error(error);
124
+ switch (error?.signal) {
125
+ case 'SIGTERM':
126
+ case 'SIGINT': {
127
+ return;
128
+ }
129
+ default: {
130
+ this.error(error);
131
+ }
132
+ }
127
133
  });
128
134
  return proxyPort;
129
135
  }
@@ -199,7 +205,7 @@ export default class AppDev extends PushAppCommand {
199
205
  const tmpBase = path.join(os.tmpdir(), 'swell-cli');
200
206
  const appTmpDir = path.join(tmpBase, this.app.id || 'unknown-app', 'functions');
201
207
  // Create the directory structure
202
- await fs.promises.mkdir(appTmpDir, { recursive: true });
208
+ await fs.mkdir(appTmpDir, { recursive: true });
203
209
  this.tmpDir = appTmpDir;
204
210
  }
205
211
  generateWranglerConfig(functionName, bundledPath) {
@@ -216,31 +222,41 @@ ENVIRONMENT = "development"
216
222
  const functions = [];
217
223
  // Get all function files from the functions directory
218
224
  try {
225
+ const promises = [];
219
226
  for (const { configFile } of allConfigFilesInDir(this.appPath, 'functions', ConfigType.FUNCTION)) {
220
- const config = appConfigFromFile(configFile, ConfigType.FUNCTION, this.appPath);
221
- if (!config.isRootFunction()) {
222
- continue; // Skip if not a root function config
223
- }
224
- if (this.functionFilter && config.name !== this.functionFilter) {
225
- continue;
226
- }
227
- const fullPath = path.join(this.appPath, config.filePath);
228
- // eslint-disable-next-line no-await-in-loop
229
- const analysis = await analyzeFunctionSource(fullPath);
230
- if (analysis.kind === 'workflow') {
231
- if (this.functionFilter) {
232
- this.log(`Workflow ${style.appConfigValue(config.name)} deploys through ${style.command('swell app push')} and cannot run in local dev.`);
227
+ promises.push(appConfigFromFile(configFile, ConfigType.FUNCTION, this.appPath).then(async (config) => {
228
+ if (!config.isRootFunction()) {
229
+ return null; // Skip if not a root function config
233
230
  }
234
- continue;
235
- }
236
- if (hasKindDiagnostic(analysis)) {
237
- this.functionErrors.set(config.name, analysis.diagnostics.join('\n'));
231
+ if (this.functionFilter && config.name !== this.functionFilter) {
232
+ return null;
233
+ }
234
+ const fullPath = path.join(this.appPath, config.filePath);
235
+ const analysis = await analyzeFunctionSource(fullPath);
236
+ if (analysis.kind === 'workflow') {
237
+ if (this.functionFilter) {
238
+ this.log(`Workflow ${style.appConfigValue(config.name)} deploys through ${style.command('swell app push')} and cannot run in local dev.`);
239
+ }
240
+ return null;
241
+ }
242
+ if (hasKindDiagnostic(analysis)) {
243
+ this.functionErrors.set(config.name, analysis.diagnostics.join('\n'));
244
+ }
245
+ return config;
246
+ }));
247
+ }
248
+ const configs = await Promise.all(promises);
249
+ for (const config of configs) {
250
+ if (config !== null) {
251
+ functions.push(config);
238
252
  }
239
- functions.push(config);
240
253
  }
241
254
  }
242
- catch {
243
- // functions directory doesn't exist
255
+ catch (error) {
256
+ // Skip error if functions directory doesn't exist
257
+ if (error.code !== 'ENOENT') {
258
+ throw error;
259
+ }
244
260
  }
245
261
  if (this.functionFilter && functions.length === 0) {
246
262
  this.error(`Function '${this.functionFilter}' not found in ${style.path('functions/')}.`);
@@ -348,9 +364,9 @@ ENVIRONMENT = "development"
348
364
  const { code } = await bundleFunction(fullPath);
349
365
  // Update the bundled file (wrangler dev will auto-reload)
350
366
  const functionDir = path.join(this.tmpDir, `${appConfig.name}`);
351
- await fs.promises.mkdir(functionDir, { recursive: true });
367
+ await fs.mkdir(functionDir, { recursive: true });
352
368
  const bundledPath = path.join(functionDir, `${appConfig.name}.js`);
353
- await fs.promises.writeFile(bundledPath, code);
369
+ await fs.writeFile(bundledPath, code);
354
370
  if (this.functionPorts.has(appConfig.name)) {
355
371
  this.log(`\nUpdating function ${appConfig.name}...`);
356
372
  }
@@ -368,7 +384,7 @@ ENVIRONMENT = "development"
368
384
  async startAppFunctionServer(spinner, serverPort) {
369
385
  // Get all functions in this app
370
386
  const functions = await this.getAppFunctions();
371
- const projectType = this.getFrontendProjectType(false);
387
+ const projectType = await this.getFrontendProjectType(false);
372
388
  const shouldLogPreviewUrl = this.app.type === 'storefront' && !projectType;
373
389
  if (functions.length === 0) {
374
390
  if (!projectType && this.app.type !== 'storefront') {
@@ -448,17 +464,17 @@ ENVIRONMENT = "development"
448
464
  const { code } = await bundleFunction(fullPath);
449
465
  // Each function gets its own directory to avoid wrangler state conflicts
450
466
  const functionDir = path.join(this.tmpDir, functionName);
451
- await fs.promises.mkdir(functionDir, { recursive: true });
467
+ await fs.mkdir(functionDir, { recursive: true });
452
468
  // Write bundled function to its directory
453
469
  const bundledPath = path.join(functionDir, `${functionName}.js`);
454
- await fs.promises.writeFile(bundledPath, code);
470
+ await fs.writeFile(bundledPath, code);
455
471
  // Generate wrangler config
456
472
  const wranglerConfig = this.generateWranglerConfig(functionName, bundledPath);
457
473
  const configPath = path.join(functionDir, `${functionName}.toml`);
458
- await fs.promises.writeFile(configPath, wranglerConfig);
474
+ await fs.writeFile(configPath, wranglerConfig);
459
475
  functionStatus.set(functionName, 'starting');
460
476
  // Start wrangler process in background using detected package manager
461
- const pm = detectPackageManager(this.appPath);
477
+ const pm = await detectPackageManager(this.appPath);
462
478
  const { program, prefixArgs } = getExecSpawnArgs(pm);
463
479
  const wranglerProcess = spawn(program, [
464
480
  ...prefixArgs,
@@ -60,19 +60,25 @@ export default class AppFrontendDev extends PushAppCommand {
60
60
  : await this.startProxyServer(proxyPort || port);
61
61
  await this.execFrontendProject(serverPort, isAppDev).catch((error) => {
62
62
  // SIGTERM/SIGINT during dev server shutdown is expected
63
- if (error?.signal === 'SIGTERM' || error?.signal === 'SIGINT')
64
- return;
65
- throw error;
63
+ switch (error?.signal) {
64
+ case 'SIGTERM':
65
+ case 'SIGINT': {
66
+ return;
67
+ }
68
+ default: {
69
+ throw error;
70
+ }
71
+ }
66
72
  });
67
73
  }
68
74
  async execFrontendProject(serverPort, isAppDev) {
69
- const projectType = this.getFrontendProjectType(!isAppDev);
75
+ const projectType = await this.getFrontendProjectType(!isAppDev);
70
76
  if (!projectType) {
71
77
  return;
72
78
  }
73
79
  // Manual mode for unrecognized frameworks
74
80
  if (projectType.slug === CUSTOM_FRAMEWORK_SLUG) {
75
- const hintCommand = getManualDevHint(this.appPath, serverPort);
81
+ const hintCommand = await getManualDevHint(this.appPath, serverPort);
76
82
  this.log(`Detected a frontend project but could not identify the framework.`);
77
83
  this.log(`Start your dev server manually on port ${serverPort}:\n`);
78
84
  this.log(` cd frontend && ${hintCommand}\n`);
@@ -86,7 +92,7 @@ export default class AppFrontendDev extends PushAppCommand {
86
92
  return;
87
93
  }
88
94
  // Get commands transformed for the detected package manager
89
- const { devCommand } = getProjectCommands(this.appPath, projectType);
95
+ const { devCommand } = await getProjectCommands(this.appPath, projectType);
90
96
  let serverReadyDetected = false;
91
97
  await this.execFrontend(devCommand.replace('${PORT}', String(serverPort)), (string) => {
92
98
  // Shared: Hide Vite noise output common across frameworks
@@ -1,3 +1,4 @@
1
+ import type { AppCommandOrientation } from '../../types/index.js';
1
2
  import { PushAppCommand } from '../../push-app-command.js';
2
3
  export default class AppPush extends PushAppCommand {
3
4
  static args: {
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as path from 'node:path';
3
- import { AllConfigPaths, filePathExists, isPathDirectory, } from '../../lib/apps/index.js';
3
+ import { AllConfigPaths, filePathExistsAsync, isPathDirectory, } from '../../lib/apps/index.js';
4
4
  import style from '../../lib/style.js';
5
5
  import { PushAppCommand } from '../../push-app-command.js';
6
6
  export default class AppPush extends PushAppCommand {
@@ -76,11 +76,11 @@ ${Object.values(AllConfigPaths)
76
76
  const { filePath, relativePath } = this.resolvePushPaths(file, flags['app-path']);
77
77
  // Push individual files if not referring to the whole app path
78
78
  if (filePath !== this.appPath) {
79
- if (!filePathExists(filePath)) {
79
+ if (!(await filePathExistsAsync(filePath))) {
80
80
  this.error(`Path ${style.path(file)} does not exist.`);
81
81
  }
82
82
  // Targeting a directory
83
- await (isPathDirectory(filePath)
83
+ await ((await isPathDirectory(filePath))
84
84
  ? this.pushFilePath(relativePath, force)
85
85
  : this.pushFile(relativePath));
86
86
  this.log();
@@ -1,7 +1,7 @@
1
1
  import { confirm } from '@inquirer/prompts';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { CLIError } from '@oclif/errors';
4
- import * as fs from 'node:fs';
4
+ import * as fs from 'node:fs/promises';
5
5
  import ora from 'ora';
6
6
  import * as semver from 'semver';
7
7
  import style from '../../lib/style.js';
@@ -69,7 +69,7 @@ The app must be connected to a partner account with access to publish.`;
69
69
  let releaseNotes;
70
70
  if (releaseNotesFile) {
71
71
  try {
72
- releaseNotes = fs.readFileSync(releaseNotesFile, 'utf8');
72
+ releaseNotes = await fs.readFile(releaseNotesFile, 'utf8');
73
73
  }
74
74
  catch {
75
75
  this.error(`Release notes could not be loaded from \`${releaseNotesFile}\``);
@@ -29,7 +29,7 @@ export default class CreateApp extends CreateAppCommand {
29
29
  nestedPath?: boolean;
30
30
  }): Promise<{
31
31
  appId: string;
32
- config: any;
32
+ config: import("conf").default<Record<string, unknown>>;
33
33
  installedStorefrontApp: any;
34
34
  swellConfigJson: {
35
35
  extensions?: any[] | undefined;
@@ -317,7 +317,7 @@ export default class CreateApp extends CreateAppCommand {
317
317
  ? path.join(process.cwd(), inputId || appId)
318
318
  : process.cwd();
319
319
  const swellConfigPath = path.join(appPath, 'swell.json');
320
- if (swellConfigFileExists(swellConfigPath)) {
320
+ if (await swellConfigFileExists(swellConfigPath)) {
321
321
  if (allowOverwrite) {
322
322
  if (!confirmYes) {
323
323
  const continueCreateApp = await confirm({
@@ -18,17 +18,17 @@ export default class CreateFrontend extends CreateAppCommand {
18
18
  pkg: Flags.string({
19
19
  char: 'p',
20
20
  default: 'npm',
21
- description: `Package manager: npm | yarn | pnpm | bun | none`,
21
+ description: 'Package manager: npm | yarn | pnpm | bun | none',
22
22
  options: ['npm', 'yarn', 'pnpm', 'bun', 'none'],
23
23
  }),
24
24
  };
25
25
  async run() {
26
26
  const { flags } = await this.parse(CreateFrontend);
27
- const newSwellConfig = swellConfig();
27
+ const newSwellConfig = await swellConfig();
28
28
  const appType = newSwellConfig?.get('type');
29
29
  const spinner = ora();
30
30
  if (appType === 'theme') {
31
- spinner.fail(`You can't create app frontend in a theme.`);
31
+ spinner.fail("You can't create app frontend in a theme.");
32
32
  return;
33
33
  }
34
34
  await (appType === 'storefront'
@@ -32,14 +32,17 @@ export default class CreateTests extends AppCommand {
32
32
  const appId = appIdFromConfig ||
33
33
  toAppId(this.swellConfig.get('name')) ||
34
34
  'app';
35
- const result = await createTestsScaffold({
36
- appPath: this.appPath,
37
- appId,
38
- overwrite: Boolean(flags.overwrite),
39
- });
40
- this.logScaffoldResult(result);
35
+ const [result, pm] = await Promise.all([
36
+ createTestsScaffold({
37
+ appPath: this.appPath,
38
+ appId,
39
+ overwrite: Boolean(flags.overwrite),
40
+ }),
41
+ detectPackageManager(this.appPath),
42
+ ]);
43
+ this.logScaffoldResult(result, pm);
41
44
  }
42
- logScaffoldResult(result) {
45
+ logScaffoldResult(result, pm) {
43
46
  const hasChanges = result.createdFiles.length > 0 || result.packageJsonUpdated;
44
47
  if (hasChanges) {
45
48
  this.log('');
@@ -67,7 +70,6 @@ export default class CreateTests extends AppCommand {
67
70
  this.warn(warning);
68
71
  }
69
72
  if (hasChanges) {
70
- const pm = detectPackageManager(this.appPath);
71
73
  const commands = getPackageManagerCommands(pm);
72
74
  this.log('');
73
75
  this.log('Next steps:');
@@ -1,4 +1,4 @@
1
- import { promises as fs } from 'node:fs';
1
+ import * as fs from 'node:fs/promises';
2
2
  import { FetchError } from 'node-fetch';
3
3
  import { inspectResourceBaseArgs, inspectResourceBaseFlags, } from '../../inspect-resource-command.js';
4
4
  import { getCurrentAppSlugId, hasAppContext } from '../../lib/apps/index.js';
@@ -306,7 +306,7 @@ Identifier forms:
306
306
  const fnsForExtension = allFunctions.filter((f) => functionMatchesExtension(f, extId));
307
307
  const compsForExtension = allComponents.filter((c) => componentMatchesExtension(c, extId));
308
308
  let localDiff = null;
309
- if (flags.app === '.' && hasAppContext()) {
309
+ if (flags.app === '.' && (await hasAppContext())) {
310
310
  const local = await readLocalManifest();
311
311
  const localEntry = local?.extensions?.find((e) => e.id === extId);
312
312
  if (localEntry) {
@@ -339,7 +339,7 @@ Identifier forms:
339
339
  // Local-not-deployed: under --app=. with a local manifest entry that
340
340
  // hasn't been deployed yet, surface `not deployed` rather than orphan.
341
341
  let localEntry = null;
342
- if (flags.app === '.' && hasAppContext()) {
342
+ if (flags.app === '.' && (await hasAppContext())) {
343
343
  const local = await readLocalManifest();
344
344
  localEntry = local?.extensions?.find((e) => e.id === extId) ?? null;
345
345
  }
@@ -412,7 +412,7 @@ function slugFromInstalled(a) {
412
412
  return a.app_private_id?.replace(/^_/, '') || a.app_public_id;
413
413
  }
414
414
  async function readLocalManifest() {
415
- if (!hasAppContext())
415
+ if (!(await hasAppContext()))
416
416
  return null;
417
417
  try {
418
418
  const raw = await fs.readFile('swell.json', 'utf8');
@@ -1,9 +1,8 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- // eslint-disable-next-line import/no-named-as-default
3
- import Ajv2020 from 'ajv/dist/2020.js';
2
+ import { Ajv } from 'ajv';
4
3
  import ajvErrors from 'ajv-errors';
5
4
  import addFormats from 'ajv-formats';
6
- import * as fs from 'node:fs';
5
+ import * as fs from 'node:fs/promises';
7
6
  import parseJson from 'parse-json';
8
7
  import { bundleFunction } from '../lib/bundle.js';
9
8
  import { SCHEMAS_BASE_URL } from '../lib/constants.js';
@@ -96,7 +95,7 @@ export default class Schema extends SwellCommand {
96
95
  return;
97
96
  }
98
97
  // Validate type
99
- if (!(type in SCHEMA_DEFINITIONS)) {
98
+ if (!Object.hasOwn(SCHEMA_DEFINITIONS, type)) {
100
99
  throw new Error(`Unknown schema type '${type}'. Use 'swell schema' to list available types`);
101
100
  }
102
101
  // Validate file
@@ -181,9 +180,9 @@ export default class Schema extends SwellCommand {
181
180
  }
182
181
  async validate(type, file) {
183
182
  const isStdin = file === '-';
184
- const input = isStdin
185
- ? await this.readFromStdin()
186
- : await this.getFileInput(file);
183
+ const input = await (isStdin
184
+ ? this.readFromStdin()
185
+ : this.getFileInput(file));
187
186
  let json;
188
187
  try {
189
188
  json = parseJson(input);
@@ -201,12 +200,12 @@ export default class Schema extends SwellCommand {
201
200
  throw new Error(`Failed to fetch bundled schema: ${response.statusText}`);
202
201
  }
203
202
  const schema = await response.json();
204
- const ajv = new Ajv2020({
203
+ const ajv = new Ajv({
205
204
  allErrors: true,
206
205
  strict: false,
207
206
  });
208
- addFormats(ajv);
209
- ajvErrors(ajv);
207
+ addFormats.default(ajv);
208
+ ajvErrors.default(ajv);
210
209
  const validate = ajv.compile(schema);
211
210
  const valid = validate(json);
212
211
  if (!valid) {
@@ -226,10 +225,11 @@ export default class Schema extends SwellCommand {
226
225
  this.log('Valid model definition');
227
226
  }
228
227
  async validateFunction(file) {
229
- if (!fs.existsSync(file)) {
230
- throw new Error(`File not found: ${file}`);
228
+ const accessError = await fs.access(file, fs.constants.F_OK).then(() => null, (error) => error);
229
+ if (accessError) {
230
+ throw new Error(`File not found: ${file}`, { cause: accessError });
231
231
  }
232
- const filePath = fs.realpathSync(file);
232
+ const filePath = await fs.realpath(file);
233
233
  const analysis = await analyzeFunctionSource(filePath);
234
234
  if (analysis.kind === 'workflow') {
235
235
  if (analysis.diagnostics.length > 0) {
@@ -247,7 +247,9 @@ export default class Schema extends SwellCommand {
247
247
  bundleResult = await bundleFunction(filePath);
248
248
  }
249
249
  catch (error) {
250
- throw new Error(`Function compilation failed:\n• ${error.message}`);
250
+ throw new Error(`Function compilation failed:\n• ${error.message}`, {
251
+ cause: error,
252
+ });
251
253
  }
252
254
  const { config } = bundleResult;
253
255
  if (config?.kind === 'workflow') {
@@ -267,11 +269,12 @@ export default class Schema extends SwellCommand {
267
269
  }
268
270
  this.log('Valid function definition');
269
271
  }
270
- getFileInput(file) {
271
- if (!fs.existsSync(file)) {
272
- throw new Error(`File not found: ${file}`);
272
+ async getFileInput(file) {
273
+ const accessError = await fs.access(file, fs.constants.F_OK).then(() => null, (error) => error);
274
+ if (accessError) {
275
+ throw new Error(`File not found: ${file}`, { cause: accessError });
273
276
  }
274
- return fs.promises.readFile(file, 'utf8');
277
+ return fs.readFile(file, 'utf8');
275
278
  }
276
279
  readFromStdin() {
277
280
  return new Promise((resolve, reject) => {
@@ -1,7 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { findUp } from 'find-up';
3
3
  import { execSync, spawn } from 'node:child_process';
4
- import fs from 'node:fs';
4
+ import * as fs from 'node:fs/promises';
5
5
  import ora from 'ora';
6
6
  import { default as localConfig } from '../../lib/config.js';
7
7
  import { findLockFile, getPackageManager } from '../../lib/package-manager.js';
@@ -79,7 +79,7 @@ export default class AppThemeDev extends PushAppCommand {
79
79
  const spinner = ora('Locating package.json...').start();
80
80
  try {
81
81
  // Check for any package manager lock file
82
- const lockFile = findLockFile(process.cwd());
82
+ const lockFile = await findLockFile(process.cwd());
83
83
  if (lockFile) {
84
84
  spinner.succeed(`${lockFile.name} found. Skipping dependency install.`);
85
85
  return null;
@@ -91,7 +91,7 @@ export default class AppThemeDev extends PushAppCommand {
91
91
  }
92
92
  spinner.succeed(`Found package.json at ${packageJsonPath}`);
93
93
  spinner.start('Installing dependencies...');
94
- const { commands } = getPackageManager(process.cwd());
94
+ const { commands } = await getPackageManager(process.cwd());
95
95
  execSync(commands.install, { stdio: 'inherit' });
96
96
  spinner.succeed('Dependencies installed');
97
97
  return packageJsonPath;
@@ -103,7 +103,7 @@ export default class AppThemeDev extends PushAppCommand {
103
103
  }
104
104
  async findAndTryScriptCommands() {
105
105
  try {
106
- const data = await fs.promises.readFile('package.json', 'utf8');
106
+ const data = await fs.readFile('package.json', 'utf8');
107
107
  const packageJson = JSON.parse(data);
108
108
  if (!packageJson.scripts) {
109
109
  console.error('No scripts found in package.json. Try adding scripts to your package file.');
@@ -113,7 +113,7 @@ export default class AppThemeDev extends PushAppCommand {
113
113
  console.warn('"bundle" script not found in package.json');
114
114
  return;
115
115
  }
116
- const { commands } = getPackageManager(process.cwd());
116
+ const { commands } = await getPackageManager(process.cwd());
117
117
  const runCommand = commands.run('bundle').split(' ');
118
118
  const childProcess = spawn(runCommand[0], runCommand.slice(1), {
119
119
  env: { ...process.env, BROWSERSLIST_IGNORE_OLD_DATA: 'true' },
@@ -1,3 +1,4 @@
1
+ import type { AppCommandOrientation } from '../../types/index.js';
1
2
  import AppPush from '../app/push.js';
2
3
  export default class AppThemePush extends AppPush {
3
4
  static args: {
@@ -1,5 +1,5 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import { ThemeConfigPaths, filePathExists, isPathDirectory, } from '../../lib/apps/index.js';
2
+ import { ThemeConfigPaths, filePathExistsAsync, isPathDirectory, } 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 AppPush from '../app/push.js';
@@ -88,11 +88,11 @@ ${Object.values(ThemeConfigPaths)
88
88
  const { filePath, relativePath } = this.resolvePushPaths(file);
89
89
  // Push individual files if not referring to the whole app path
90
90
  if (filePath !== this.appPath) {
91
- if (!filePathExists(filePath)) {
91
+ if (!(await filePathExistsAsync(filePath))) {
92
92
  this.error(`Path ${style.path(file)} does not exist.`);
93
93
  }
94
94
  // Targeting a directory
95
- const pushPromise = isPathDirectory(filePath)
95
+ const pushPromise = (await isPathDirectory(filePath))
96
96
  ? this.pushFilePath(relativePath, force)
97
97
  : this.pushFile(relativePath);
98
98
  await pushPromise;
@@ -2,8 +2,8 @@ import { confirm, select } from '@inquirer/prompts';
2
2
  import { Flags } from '@oclif/core';
3
3
  import { $ } from 'execa';
4
4
  import { exec } from 'node:child_process';
5
- import fs from 'node:fs/promises';
6
- import path from 'node:path';
5
+ import * as fs from 'node:fs/promises';
6
+ import * as path from 'node:path';
7
7
  import Stream from 'node:stream';
8
8
  import { promisify } from 'node:util';
9
9
  import ora from 'ora';
@@ -12,5 +12,5 @@ import { CreateFileParams } from './lib/create/index.js';
12
12
  export declare abstract class CreateConfigCommand extends AppCommand {
13
13
  protected createType: '' | ConfigType;
14
14
  protected createFile({ extension, fileBody, fileName }: CreateFileParams, overwrite: boolean, shouldConfirm?: boolean): Promise<boolean | undefined>;
15
- protected getCollectionOptions(): Promise<any>;
15
+ protected getCollectionOptions(): Promise<string[]>;
16
16
  }
@@ -1,7 +1,7 @@
1
1
  import { confirm } from '@inquirer/prompts';
2
2
  import * as path from 'node:path';
3
3
  import { AppCommand } from './app-command.js';
4
- import { AllConfigPaths, filePathExists, writeFile, writeJsonFile, } from './lib/apps/index.js';
4
+ import { AllConfigPaths, filePathExistsAsync, writeFile, writeJsonFile, } from './lib/apps/index.js';
5
5
  /**
6
6
  * A base class for Swell CLI Create commands for file and input handling.
7
7
  *
@@ -18,7 +18,7 @@ export class CreateConfigCommand extends AppCommand {
18
18
  if (shouldConfirm) {
19
19
  this.log(`\nCreating app ${this.createType} in ${filePath}`);
20
20
  this.log(`\n${isJson ? JSON.stringify(fileBody, null, 4) : fileBody}\n`);
21
- if (filePathExists(filePath) && !overwrite) {
21
+ if ((await filePathExistsAsync(filePath)) && !overwrite) {
22
22
  const continueWrite = await confirm({
23
23
  message: `This will overwrite an existing ${this.createType} file. Ok to continue?`,
24
24
  });
@@ -35,7 +35,7 @@ export class CreateConfigCommand extends AppCommand {
35
35
  }
36
36
  }
37
37
  }
38
- else if (filePathExists(filePath) && !overwrite) {
38
+ else if ((await filePathExistsAsync(filePath)) && !overwrite) {
39
39
  // Non-interactive mode: never prompt; fail fast on potential overwrite
40
40
  this.error(`A ${this.createType} file already exists at ${filePath}.\n\nUse --overwrite to replace the existing file in non-interactive mode.`, { exit: 1 });
41
41
  }
@@ -1,4 +1,4 @@
1
- import { Command, Help } from '@oclif/core';
1
+ import { type Command, Help } from '@oclif/core';
2
2
  /**
3
3
  * Custom Help class for Swell CLI
4
4
  *
@@ -1,4 +1,4 @@
1
- import { Command } from '@oclif/core';
1
+ import type { Command } from '@oclif/core';
2
2
  /**
3
3
  * Represents a type variant with conditional flag requirements.
4
4
  * Used for complex commands like `create app` where different types
package/dist/lib/api.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type Api from '../types/index.js';
1
2
  export declare enum HttpMethod {
2
3
  GET = "get",
3
4
  POST = "post",
package/dist/lib/api.js CHANGED
@@ -235,7 +235,7 @@ export default class Api {
235
235
  if (!this.publicKey) {
236
236
  throw new Error('No API public key available. Run inside a deployed app or create a user-scoped public key.');
237
237
  }
238
- else if (hasAppContext() && !installedApp?.public_key) {
238
+ else if ((await hasAppContext()) && !installedApp?.public_key) {
239
239
  console.warn(style.funcWarn('⚠ No app context found. Running in user scope.'));
240
240
  }
241
241
  }