@swell/cli 2.9.4 → 2.9.6

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 (82) 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/templates/mock-request.js +30 -0
  49. package/dist/lib/create/tests/templates/setup-globals.js +35 -0
  50. package/dist/lib/create/tests/types.d.ts +3 -4
  51. package/dist/lib/create/tests.d.ts +1 -2
  52. package/dist/lib/create/tests.js +12 -13
  53. package/dist/lib/create/webhook.d.ts +6 -6
  54. package/dist/lib/create/webhook.js +15 -10
  55. package/dist/lib/function-source-analysis.js +3 -3
  56. package/dist/lib/info.d.ts +1 -1
  57. package/dist/lib/logs/index.d.ts +1 -0
  58. package/dist/lib/logs/line-output.d.ts +1 -0
  59. package/dist/lib/logs/line-output.js +12 -4
  60. package/dist/lib/logs/output.d.ts +1 -0
  61. package/dist/lib/logs/table-output.d.ts +1 -0
  62. package/dist/lib/logs/table-output.js +8 -5
  63. package/dist/lib/package-manager.d.ts +5 -5
  64. package/dist/lib/package-manager.js +9 -7
  65. package/dist/lib/proxy.js +4 -3
  66. package/dist/lib/sessions.d.ts +1 -2
  67. package/dist/lib/sessions.js +1 -2
  68. package/dist/lib/stores.d.ts +6 -6
  69. package/dist/lib/stores.js +5 -6
  70. package/dist/lib/swell-function-wrapper.d.ts +1 -193
  71. package/dist/lib/swell-function-wrapper.js +24 -1
  72. package/dist/lib/theme-sync.js +0 -5
  73. package/dist/push-app-command.d.ts +7 -6
  74. package/dist/push-app-command.js +35 -37
  75. package/dist/remote-app-command.d.ts +6 -4
  76. package/dist/remote-app-command.js +39 -25
  77. package/dist/swell-api-command.d.ts +1 -0
  78. package/dist/swell-api-command.js +3 -3
  79. package/dist/types/index.d.ts +94 -0
  80. package/dist/types/index.js +4 -0
  81. package/oclif.manifest.json +1 -1
  82. package/package.json +3 -3
@@ -1,4 +1,9 @@
1
- import { App } from './apps';
1
+ /**
2
+ * App configuration for local development of Swell Apps.
3
+ */
4
+ import Conf from 'conf';
5
+ import type { LocalApp } from '../types/index.js';
6
+ import type { App } from './apps/index.js';
2
7
  /**
3
8
  * Checks if the swell config file exists at the given path, default to cwd.
4
9
  *
@@ -6,9 +11,9 @@ import { App } from './apps';
6
11
  * @returns boolean
7
12
  * @throws Error
8
13
  */
9
- declare function swellConfigFileExists(configFilePath?: string): boolean;
10
- declare function writeRcFile(path: string, data: any): Promise<void>;
11
- declare function readRcFile(path: string): App;
14
+ export declare function swellConfigFileExists(configFilePath?: string): Promise<boolean>;
15
+ export declare function writeRcFile(path: string, data: any): Promise<void>;
16
+ export declare function readRcFile(path: string): Promise<App>;
12
17
  /**
13
18
  * Returns a new configuration instance in the current working directory or
14
19
  * a parent directory.
@@ -19,19 +24,19 @@ declare function readRcFile(path: string): App;
19
24
  *
20
25
  * @returns Conf
21
26
  */
22
- declare function config(configDir?: string): LocalApp;
27
+ declare function config(configDir?: string): Promise<LocalApp>;
23
28
  /**
24
29
  * Returns a new configuration instance in the current working directory only.
25
30
  *
26
31
  * @param path Path of the current working directory
27
32
  * @returns Conf
28
33
  */
29
- declare function newConfig(path?: string): any;
34
+ export declare function newConfig(path?: string): Conf;
30
35
  /**
31
36
  * Returns a new configuration instance at the specified path.
32
37
  *
33
38
  * @param appPath Path of the current working directory
34
39
  * @returns Conf
35
40
  */
36
- declare function newConfigAtPath(appPath?: string): any;
37
- export { config as default, newConfig, newConfigAtPath, readRcFile, swellConfigFileExists, writeRcFile, };
41
+ export declare function newConfigAtPath(appPath?: string): Promise<Conf>;
42
+ export default config;
@@ -2,7 +2,7 @@
2
2
  * App configuration for local development of Swell Apps.
3
3
  */
4
4
  import Conf from 'conf';
5
- import * as fs from 'node:fs';
5
+ import * as fs from 'node:fs/promises';
6
6
  import * as path from 'node:path';
7
7
  const schema = {
8
8
  compatibilities: { type: 'object' },
@@ -30,7 +30,7 @@ function swellConfigFile(dir = '') {
30
30
  if (!dir) {
31
31
  dir = process.cwd();
32
32
  }
33
- return path.join(dir, [APP_FILE_NAME, '.', APP_FILE_EXT].join(''));
33
+ return path.join(dir, `${APP_FILE_NAME}.${APP_FILE_EXT}`);
34
34
  }
35
35
  /**
36
36
  * Checks if the swell config file exists at the given path, default to cwd.
@@ -39,14 +39,14 @@ function swellConfigFile(dir = '') {
39
39
  * @returns boolean
40
40
  * @throws Error
41
41
  */
42
- function swellConfigFileExists(configFilePath = '') {
42
+ export async function swellConfigFileExists(configFilePath = '') {
43
43
  // if the config file path is not provided, try to find it as the default
44
44
  if (!configFilePath) {
45
45
  configFilePath = swellConfigFile();
46
46
  }
47
47
  try {
48
48
  // eslint-disable-next-line no-bitwise
49
- fs.accessSync(configFilePath, fs.constants.R_OK | fs.constants.W_OK);
49
+ await fs.access(configFilePath, fs.constants.R_OK | fs.constants.W_OK);
50
50
  return true;
51
51
  }
52
52
  catch (error) {
@@ -64,9 +64,9 @@ function swellConfigFileExists(configFilePath = '') {
64
64
  * @returns string
65
65
  * @throws Error
66
66
  */
67
- function swellConfigFilePath(dir = '') {
67
+ async function swellConfigFilePath(dir = '') {
68
68
  const configFilePath = swellConfigFile(dir);
69
- if (swellConfigFileExists(configFilePath)) {
69
+ if (await swellConfigFileExists(configFilePath)) {
70
70
  return configFilePath;
71
71
  }
72
72
  // if the file doesn't exist, try to find it in the parent directory
@@ -76,16 +76,16 @@ function swellConfigFilePath(dir = '') {
76
76
  }
77
77
  return swellConfigFilePath(path.resolve(dir, '..'));
78
78
  }
79
- async function writeRcFile(path, data) {
79
+ export async function writeRcFile(path, data) {
80
80
  let dataToWrite = '# This file is automatically generated by the Swell CLI\n';
81
81
  for (const [key, value] of Object.entries(data)) {
82
82
  dataToWrite += `${key}=${value}\n`;
83
83
  }
84
- fs.writeFileSync(path, dataToWrite);
84
+ return fs.writeFile(path, dataToWrite, { encoding: 'utf8' });
85
85
  }
86
- function readRcFile(path) {
86
+ export async function readRcFile(path) {
87
87
  const data = {};
88
- const dataFromFile = fs.readFileSync(path, 'utf8');
88
+ const dataFromFile = await fs.readFile(path, 'utf8');
89
89
  const lines = dataFromFile.split('\n');
90
90
  for (const line of lines) {
91
91
  const cleanLine = line.trim();
@@ -111,24 +111,26 @@ function readRcFile(path) {
111
111
  *
112
112
  * @returns Conf
113
113
  */
114
- function config(configDir = '') {
115
- const dirPath = configDir || path.dirname(swellConfigFilePath());
116
- let config;
114
+ async function config(configDir = '') {
115
+ const dirPath = configDir || path.dirname(await swellConfigFilePath());
117
116
  try {
118
- config = new Conf({
117
+ const config = new Conf({
119
118
  clearInvalidConfig: true,
120
119
  configName: APP_FILE_NAME,
121
120
  cwd: dirPath,
122
121
  schema,
123
122
  });
123
+ return Object.assign(config, {
124
+ // for convenience, we add custom properties to the Conf object
125
+ // we prefix them with "sw" to avoid conflicts with Conf's properties
126
+ swDirPath: dirPath,
127
+ });
124
128
  }
125
129
  catch (error) {
126
- throw new Error(`Error parsing swell.json: ${error.toString()}`);
130
+ throw new Error(`Error parsing swell.json: ${error.message}`, {
131
+ cause: error,
132
+ });
127
133
  }
128
- // for convenience, we add custom properties to the Conf object
129
- // we prefix them with "sw" to avoid conflicts with Conf's properties
130
- config.swDirPath = dirPath;
131
- return config;
132
134
  }
133
135
  /**
134
136
  * Returns a new configuration instance in the current working directory only.
@@ -136,7 +138,7 @@ function config(configDir = '') {
136
138
  * @param path Path of the current working directory
137
139
  * @returns Conf
138
140
  */
139
- function newConfig(path) {
141
+ export function newConfig(path) {
140
142
  return new Conf({
141
143
  clearInvalidConfig: true,
142
144
  configName: APP_FILE_NAME,
@@ -151,8 +153,8 @@ function newConfig(path) {
151
153
  * @param appPath Path of the current working directory
152
154
  * @returns Conf
153
155
  */
154
- function newConfigAtPath(appPath) {
155
- const dirPath = appPath || path.dirname(swellConfigFilePath());
156
+ export async function newConfigAtPath(appPath) {
157
+ const dirPath = appPath || path.dirname(await swellConfigFilePath());
156
158
  return new Conf({
157
159
  configName: APP_FILE_NAME,
158
160
  cwd: dirPath,
@@ -163,4 +165,4 @@ function newConfigAtPath(appPath) {
163
165
  function serialize(value) {
164
166
  return JSON.stringify(value, null, 2);
165
167
  }
166
- export { config as default, newConfig, newConfigAtPath, readRcFile, swellConfigFileExists, writeRcFile, };
168
+ export default config;
@@ -1,11 +1,11 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
3
  import { ConfigType } from './index.js';
4
4
  export declare class IgnoringFileError extends Error {
5
5
  constructor(message: string);
6
6
  }
7
7
  export declare class FunctionProcessingError extends Error {
8
- originalError: Error;
8
+ cause: Error;
9
9
  constructor(message: string, error: Error);
10
10
  }
11
11
  interface AppConfigFile {
@@ -30,7 +30,6 @@ export declare abstract class AppConfig {
30
30
  date_updated?: string;
31
31
  file?: AppConfigFile;
32
32
  file_path?: string;
33
- fileContent?: string;
34
33
  fileData?: Buffer;
35
34
  fileHash?: string;
36
35
  filePath: string;
@@ -45,7 +44,8 @@ export declare abstract class AppConfig {
45
44
  };
46
45
  version?: string;
47
46
  constructor(attrs?: Partial<AppConfig>);
48
- static create(attrs?: Partial<AppConfig>): AppConfig;
47
+ load(): Promise<void>;
48
+ static create(attrs?: Partial<AppConfig>): Promise<AppConfig>;
49
49
  isRootConfig(configDir: string): boolean;
50
50
  postData(): Promise<any>;
51
51
  prepareFileData(): any;
@@ -1,11 +1,11 @@
1
1
  import { getEncoding } from 'istextorbinary';
2
2
  import isEmpty from 'lodash/isEmpty.js';
3
3
  import { detectFilenameMime } from 'mime-detect';
4
- import * as fs from 'node:fs';
4
+ import * as fs from 'node:fs/promises';
5
5
  import * as path from 'node:path';
6
6
  import { bundleFunction, bundleComponent, bundleWorkflow } from '../bundle.js';
7
7
  import { analyzeFunctionSource, hasKindDiagnostic, workflowStaticConfigError, } from '../function-source-analysis.js';
8
- import { AllConfigPaths, ConfigType, filePathExists, hashFile, } from './index.js';
8
+ import { AllConfigPaths, ConfigType, filePathExistsAsync, hashFile, } from './index.js';
9
9
  export class IgnoringFileError extends Error {
10
10
  constructor(message) {
11
11
  super(message);
@@ -13,11 +13,11 @@ export class IgnoringFileError extends Error {
13
13
  }
14
14
  }
15
15
  export class FunctionProcessingError extends Error {
16
- originalError;
16
+ cause;
17
17
  constructor(message, error) {
18
18
  super(message);
19
+ this.cause = error;
19
20
  this.name = 'FunctionProcessingError';
20
- this.originalError = error;
21
21
  }
22
22
  }
23
23
  /**
@@ -35,8 +35,6 @@ export class AppConfig {
35
35
  date_updated;
36
36
  file;
37
37
  file_path;
38
- // UTF8 content of local file
39
- fileContent;
40
38
  // Buffer of local file data
41
39
  fileData;
42
40
  fileHash;
@@ -80,67 +78,83 @@ export class AppConfig {
80
78
  if (!appPath.endsWith(filePath)) {
81
79
  this.appPath = path.join(appPath, filePath);
82
80
  }
83
- if (filePathExists(this.appPath)) {
84
- this.fileHash = hashFile(this.appPath, undefined, filePath);
81
+ }
82
+ async load() {
83
+ if (await filePathExistsAsync(this.appPath)) {
84
+ this.fileData = await fs.readFile(this.appPath);
85
+ this.fileHash = hashFile(this.appPath, this.fileData, this.filePath);
85
86
  this.hash = this.hash || this.fileHash;
86
- this.fileData = fs.readFileSync(this.appPath);
87
- this.fileContent = this.fileData.toString('utf8');
88
- this.byteSize = Buffer.byteLength(this.fileContent);
87
+ this.byteSize = this.fileData.length;
89
88
  this.mbSize = this.byteSize / 1024 / 1024;
90
89
  }
91
90
  }
92
- static create(attrs = {}) {
91
+ static async create(attrs = {}) {
92
+ let instance;
93
93
  switch (attrs.type) {
94
94
  case ConfigType.ASSET: {
95
- return new AppConfigAsset(attrs);
95
+ instance = new AppConfigAsset(attrs);
96
+ break;
96
97
  }
97
98
  case ConfigType.FUNCTION: {
98
- return new AppConfigFunction(attrs);
99
+ instance = new AppConfigFunction(attrs);
100
+ break;
99
101
  }
100
102
  case ConfigType.MODEL: {
101
- return new AppConfigModel(attrs);
103
+ instance = new AppConfigModel(attrs);
104
+ break;
102
105
  }
103
106
  case ConfigType.CONTENT: {
104
- return new AppConfigContent(attrs);
107
+ instance = new AppConfigContent(attrs);
108
+ break;
105
109
  }
106
110
  case ConfigType.NOTIFICATION: {
107
- return new AppConfigNotification(attrs);
111
+ instance = new AppConfigNotification(attrs);
112
+ break;
108
113
  }
109
114
  case ConfigType.SETTING: {
110
- return new AppConfigSetting(attrs);
115
+ instance = new AppConfigSetting(attrs);
116
+ break;
111
117
  }
112
118
  case ConfigType.WEBHOOK: {
113
- return new AppConfigWebhook(attrs);
119
+ instance = new AppConfigWebhook(attrs);
120
+ break;
114
121
  }
115
122
  case ConfigType.FRONTEND: {
116
- return new AppConfigFrontend(attrs);
123
+ instance = new AppConfigFrontend(attrs);
124
+ break;
117
125
  }
118
126
  case ConfigType.THEME: {
119
- return new AppConfigTheme(attrs);
127
+ instance = new AppConfigTheme(attrs);
128
+ break;
120
129
  }
121
130
  case ConfigType.COMPONENT: {
122
- return new AppConfigComponent(attrs);
131
+ instance = new AppConfigComponent(attrs);
132
+ break;
123
133
  }
124
134
  default: {
125
135
  // the default type is file
126
136
  const defaultConfig = new AppConfigDefault(attrs);
127
137
  defaultConfig.type = attrs.type;
128
- return defaultConfig;
138
+ instance = defaultConfig;
139
+ break;
129
140
  }
130
141
  }
142
+ await instance.load();
143
+ return instance;
131
144
  }
132
145
  isRootConfig(configDir) {
133
- return !this.filePath
134
- ?.replace(new RegExp(`^${configDir}/`), '')
135
- .includes('/');
146
+ const pos = this.filePath.startsWith(configDir + '/')
147
+ ? configDir.length + 1
148
+ : 0;
149
+ return !this.filePath.includes('/', pos);
136
150
  }
137
151
  async postData() {
138
- if (this.fileContent === undefined) {
152
+ if (this.fileData === undefined) {
139
153
  return;
140
154
  }
141
155
  if (this.hasValues && this.filePath.endsWith('.json')) {
142
156
  try {
143
- this.values = JSON.parse(this.fileContent);
157
+ this.values = JSON.parse(this.fileData.toString('utf8'));
144
158
  }
145
159
  catch {
146
160
  throw new IgnoringFileError('Invalid JSON');
@@ -205,17 +219,16 @@ export class AppConfigContent extends AppConfig {
205
219
  export class AppConfigNotification extends AppConfig {
206
220
  hasValues = true;
207
221
  type = ConfigType.NOTIFICATION;
208
- preparePostData(postData) {
222
+ async preparePostData(postData) {
209
223
  const isTemplate = this.isRootConfig('notifications') &&
210
224
  (this.filePath.endsWith('.tpl') || this.filePath.endsWith('.liquid'));
211
225
  if (isTemplate) {
212
226
  // Get json config to match collection/model name
213
- let jsonData;
214
227
  try {
215
228
  const jsonPath = this.filePath
216
229
  .replace('.tpl', '.json')
217
230
  .replace('.liquid', '.json');
218
- jsonData = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
231
+ const jsonData = JSON.parse(await fs.readFile(jsonPath, 'utf8'));
219
232
  postData.values.collection = jsonData?.collection || jsonData?.model;
220
233
  }
221
234
  catch {
@@ -223,7 +236,7 @@ export class AppConfigNotification extends AppConfig {
223
236
  }
224
237
  postData.file = {
225
238
  content_type: 'text/plain',
226
- data: this.fileContent?.replaceAll('\r\n', '\n'),
239
+ data: this.fileData?.toString('utf8')?.replaceAll('\r\n', '\n'),
227
240
  };
228
241
  }
229
242
  return postData;
@@ -350,16 +363,19 @@ export class AppConfigFrontend extends AppConfigDefault {
350
363
  export class AppConfigTheme extends AppConfigDefault {
351
364
  hasValues = false;
352
365
  type = ConfigType.THEME;
353
- preparePostData(postData) {
354
- const isConfigJson = this.filePath?.match(/^theme\/config\/[^./]+\.json$/);
366
+ async preparePostData(postData) {
367
+ const isConfigJson = this.filePath && /^theme\/config\/[^./]+\.json$/.test(this.filePath);
355
368
  // Files in theme/config/*.json are treated as settings with values
356
369
  if (isConfigJson) {
357
370
  try {
358
- const jsonData = JSON.parse(fs.readFileSync(this.filePath, 'utf8'));
371
+ const jsonData = JSON.parse(await fs.readFile(this.filePath, 'utf8'));
359
372
  postData.values = jsonData;
360
373
  }
361
- catch {
362
- // noop
374
+ catch (error) {
375
+ // If the file is not valid JSON, ignore it silently.
376
+ if (!(error instanceof SyntaxError)) {
377
+ throw error;
378
+ }
363
379
  }
364
380
  }
365
381
  return postData;
@@ -1,5 +1,5 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
3
  import { AppConfig } from './app-config.js';
4
4
  export { AppConfig, FunctionProcessingError, IgnoringFileError, } from './app-config.js';
5
5
  export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, } from './paths.js';
@@ -9,7 +9,7 @@ export declare const PUSH_CONCURRENCY = 3;
9
9
  * configuration that developers define.
10
10
  */
11
11
  export interface App {
12
- categories?: Array<string>;
12
+ categories?: string[];
13
13
  client?: any;
14
14
  client_id?: string;
15
15
  compatibilities?: {
@@ -19,8 +19,8 @@ export interface App {
19
19
  date_created?: string;
20
20
  date_updated?: string;
21
21
  description?: string;
22
- extensions?: Array<any>;
23
- features?: Array<string>;
22
+ extensions?: any[];
23
+ features?: string[];
24
24
  frontend?: {
25
25
  deployment?: null | object;
26
26
  deployment_hash?: string;
@@ -42,12 +42,13 @@ export interface App {
42
42
  kind?: string;
43
43
  logo_icon?: unknown;
44
44
  name?: string;
45
+ owned?: boolean;
45
46
  preview_image?: unknown;
46
47
  preview_mobile_image?: unknown;
47
48
  private_id?: string;
48
49
  public_id?: string;
49
50
  published?: boolean;
50
- purchase_options?: Array<string>;
51
+ purchase_options?: string[];
51
52
  storefront?: {
52
53
  [key: string]: any;
53
54
  };
@@ -63,7 +64,7 @@ export interface App {
63
64
  [key: string]: any;
64
65
  };
65
66
  type?: string;
66
- use_cases?: Array<string>;
67
+ use_cases?: string[];
67
68
  version?: string;
68
69
  }
69
70
  export declare enum SwellJsonFields {
@@ -133,21 +134,21 @@ export declare const CUSTOM_FRAMEWORK_SLUG = "custom";
133
134
  export declare const FrontendProjectTypes: FrontendProjectType[];
134
135
  export declare function getFrontendProjectSlugs(withNone?: boolean, withLegacy?: boolean): string[];
135
136
  export declare function getFrontendProjectValidValues(withNone?: boolean, withLegacy?: boolean): string;
136
- export declare function getFrontendProjectType(appPath: string): FrontendProjectType | undefined;
137
+ export declare function getFrontendProjectType(appPath: string): Promise<FrontendProjectType | undefined>;
137
138
  /**
138
139
  * Get project commands transformed for the detected package manager.
139
140
  * Detects the package manager from lock files in appPath and transforms
140
141
  * npm-style commands to the equivalent for that package manager.
141
142
  */
142
- export declare function getProjectCommands(appPath: string, projectType: FrontendProjectType): {
143
+ export declare function getProjectCommands(appPath: string, projectType: FrontendProjectType): Promise<{
143
144
  buildCommand?: string;
144
145
  devCommand: string;
145
- };
146
+ }>;
146
147
  /**
147
148
  * Get a suggested dev command for an unrecognized frontend project,
148
149
  * translated for the detected package manager.
149
150
  */
150
- export declare function getManualDevHint(appPath: string, port: number): string;
151
+ export declare function getManualDevHint(appPath: string, port: number): Promise<string>;
151
152
  export declare function getConfigTypeFromPath(path: string): ConfigType | undefined;
152
153
  export declare function getConfigTypeKeyFromValue(value: string): string | undefined;
153
154
  export declare function filePathExists(filePath: string): boolean;
@@ -157,8 +158,8 @@ export declare function deleteFile(file: string): Promise<void>;
157
158
  export declare function writeJsonFile(file: string, data?: any): Promise<void>;
158
159
  export declare function hashFile(filePath: string, fileContents?: Buffer, relativePath?: string): string;
159
160
  export declare function hashString(...contents: (Buffer | string)[]): string;
160
- export declare function appAssetImage(appPath: string, fileName: string): string | undefined;
161
- export declare function appConfigFromFile(filePath: string, configType: ConfigType, appPath: string): AppConfig;
161
+ export declare function appAssetImage(appPath: string, fileName: string): Promise<string | undefined>;
162
+ export declare function appConfigFromFile(filePath: string, configType: ConfigType, appPath: string): Promise<AppConfig>;
162
163
  export declare function findAppConfig(app: App, filePath: string, configType: ConfigType): AppConfig | undefined;
163
164
  interface BatchAppFiles {
164
165
  configs: AppConfig[];
@@ -173,5 +174,5 @@ interface BatchAppFiles {
173
174
  * @returns {BatchAppFiles[]} Batches of files to push
174
175
  */
175
176
  export declare function batchAppFilesByType(configs: AppConfig[]): BatchAppFiles[];
176
- export declare function hasAppContext(): boolean;
177
+ export declare function hasAppContext(): Promise<boolean>;
177
178
  export declare function getCurrentAppSlugId(): Promise<string | undefined>;
@@ -205,18 +205,20 @@ export function getFrontendProjectSlugs(withNone = true, withLegacy = true) {
205
205
  export function getFrontendProjectValidValues(withNone = true, withLegacy = true) {
206
206
  return getFrontendProjectSlugs(withNone, withLegacy).join(', ');
207
207
  }
208
- export function getFrontendProjectType(appPath) {
208
+ export async function getFrontendProjectType(appPath) {
209
209
  // Try frontend/package.json first (workspace structure), then root package.json (legacy)
210
210
  const pkgPaths = [
211
211
  path.join(appPath, 'frontend', 'package.json'),
212
212
  path.join(appPath, 'package.json'),
213
213
  ];
214
214
  for (const pkgPath of pkgPaths) {
215
- if (!filePathExists(pkgPath)) {
215
+ // eslint-disable-next-line no-await-in-loop
216
+ if (!(await filePathExistsAsync(pkgPath))) {
216
217
  continue;
217
218
  }
218
219
  try {
219
- const content = fs.readFileSync(pkgPath, 'utf8');
220
+ // eslint-disable-next-line no-await-in-loop
221
+ const content = await fs.promises.readFile(pkgPath, 'utf8');
220
222
  const pkg = JSON.parse(content);
221
223
  for (const projectType of FrontendProjectTypes) {
222
224
  if (pkg.dependencies?.[projectType.mainPackage] ||
@@ -242,9 +244,16 @@ export function getFrontendProjectType(appPath) {
242
244
  };
243
245
  }
244
246
  }
245
- catch {
247
+ catch (error) {
246
248
  // Ignore JSON parse errors, try next path
247
- continue;
249
+ if (error instanceof SyntaxError) {
250
+ continue;
251
+ }
252
+ // Ignore file not found errors, try next path
253
+ if (error.code === 'ENOENT') {
254
+ continue;
255
+ }
256
+ throw error;
248
257
  }
249
258
  }
250
259
  return undefined;
@@ -254,8 +263,8 @@ export function getFrontendProjectType(appPath) {
254
263
  * Detects the package manager from lock files in appPath and transforms
255
264
  * npm-style commands to the equivalent for that package manager.
256
265
  */
257
- export function getProjectCommands(appPath, projectType) {
258
- const pm = detectPackageManager(appPath);
266
+ export async function getProjectCommands(appPath, projectType) {
267
+ const pm = await detectPackageManager(appPath);
259
268
  return {
260
269
  buildCommand: projectType.buildCommand
261
270
  ? transformCommand(projectType.buildCommand, pm)
@@ -267,12 +276,12 @@ export function getProjectCommands(appPath, projectType) {
267
276
  * Get a suggested dev command for an unrecognized frontend project,
268
277
  * translated for the detected package manager.
269
278
  */
270
- export function getManualDevHint(appPath, port) {
271
- const pm = detectPackageManager(appPath);
279
+ export async function getManualDevHint(appPath, port) {
280
+ const pm = await detectPackageManager(appPath);
272
281
  return transformCommand(`npm run dev -- --port ${port}`, pm);
273
282
  }
274
283
  export function getConfigTypeFromPath(path) {
275
- for (const type in AllConfigPaths) {
284
+ for (const type of Object.keys(AllConfigPaths)) {
276
285
  if (AllConfigPaths[type] === path) {
277
286
  const configType = ConfigType[type];
278
287
  return configType;
@@ -343,12 +352,12 @@ export function hashString(...contents) {
343
352
  }
344
353
  return hash.digest('hex', { length: 16 });
345
354
  }
346
- export function appAssetImage(appPath, fileName) {
355
+ export async function appAssetImage(appPath, fileName) {
347
356
  const assetsDirPath = path.join(appPath, AllConfigPaths['ASSET']);
348
- if (!filePathExists(assetsDirPath)) {
357
+ if (!(await filePathExistsAsync(assetsDirPath))) {
349
358
  return;
350
359
  }
351
- for (const configFile of fs.readdirSync(assetsDirPath)) {
360
+ for (const configFile of await fs.promises.readdir(assetsDirPath)) {
352
361
  if (path.parse(configFile).name === fileName) {
353
362
  return path.join(assetsDirPath, configFile);
354
363
  }
@@ -357,7 +366,7 @@ export function appAssetImage(appPath, fileName) {
357
366
  function getNameFromFilePath(filePath) {
358
367
  return path.parse(filePath).name.replaceAll('_', '-');
359
368
  }
360
- export function appConfigFromFile(filePath, configType, appPath) {
369
+ export async function appConfigFromFile(filePath, configType, appPath) {
361
370
  const name = getNameFromFilePath(filePath);
362
371
  // Notification basenames must not contain dots: the inspect identifier
363
372
  // grammar (app.<slug>.<model>.<name>) splits on '.', so a dotted name
@@ -365,7 +374,7 @@ export function appConfigFromFile(filePath, configType, appPath) {
365
374
  if (configType === ConfigType.NOTIFICATION && name.includes('.')) {
366
375
  throw new Error(`Notification file '${filePath}': basename cannot contain '.'. Rename the file.`);
367
376
  }
368
- const config = AppConfig.create({
377
+ const config = await AppConfig.create({
369
378
  name,
370
379
  filePath,
371
380
  appPath,
@@ -390,10 +399,10 @@ export function findAppConfig(app, filePath, configType) {
390
399
  * @returns {BatchAppFiles[]} Batches of files to push
391
400
  */
392
401
  export function batchAppFilesByType(configs) {
393
- const modelsWithExtends = configs.filter((config) => config.type === 'model' && config.values.extends);
394
- const modelsWithoutExtends = configs.filter((config) => config.type === 'model' && !config.values.extends);
395
- const contentTypesWithCollection = configs.filter((config) => config.type === 'content' && config.values.collection);
396
- const contentTypesWithoutCollection = configs.filter((config) => config.type === 'content' && !config.values.collection);
402
+ const modelsWithExtends = configs.filter((config) => config.type === ConfigType.MODEL && config.values.extends);
403
+ const modelsWithoutExtends = configs.filter((config) => config.type === ConfigType.MODEL && !config.values.extends);
404
+ const contentTypesWithCollection = configs.filter((config) => config.type === ConfigType.CONTENT && config.values.collection);
405
+ const contentTypesWithoutCollection = configs.filter((config) => config.type === ConfigType.CONTENT && !config.values.collection);
397
406
  const prioritized = new Set([
398
407
  ...modelsWithExtends,
399
408
  ...modelsWithoutExtends,
@@ -424,17 +433,25 @@ export function batchAppFilesByType(configs) {
424
433
  return batches;
425
434
  }
426
435
  export function hasAppContext() {
427
- return fs.existsSync('swell.json');
436
+ return filePathExistsAsync('swell.json');
428
437
  }
429
438
  export async function getCurrentAppSlugId() {
430
- if (!hasAppContext()) {
439
+ if (!(await hasAppContext())) {
431
440
  return;
432
441
  }
433
442
  try {
434
443
  const appConfig = JSON.parse(await fs.promises.readFile('swell.json', 'utf8'));
435
444
  return appConfig.id;
436
445
  }
437
- catch {
438
- // noop
446
+ catch (error) {
447
+ // Ignore JSON parse error
448
+ if (error instanceof SyntaxError) {
449
+ return;
450
+ }
451
+ // Ignore error when swell.json does not exists
452
+ if (error.code === 'ENOENT') {
453
+ return;
454
+ }
455
+ throw error;
439
456
  }
440
457
  }
@@ -23,4 +23,4 @@ export declare function allConfigFilesInDir(appPath: string, dirPath: string, co
23
23
  }, void, unknown>;
24
24
  export declare function allBaseFilesInDir(appPath: string): Generator<string, void, unknown>;
25
25
  export declare function getAllConfigPaths(appType: string): string[];
26
- export declare function isPathDirectory(path: string): boolean;
26
+ export declare function isPathDirectory(path: string): Promise<boolean>;
@@ -1,5 +1,5 @@
1
1
  import { globby, globbySync, isGitIgnored, } from 'globby';
2
- import * as fs from 'node:fs';
2
+ import * as fs from 'node:fs/promises';
3
3
  import * as path from 'node:path';
4
4
  import { AllConfigPaths, ConfigType, StandardConfigPaths, StorefrontConfigPaths, ThemeConfigPaths, filePathExists, } from './index.js';
5
5
  function globOptions(appPath, options) {
@@ -99,9 +99,9 @@ export function getAllConfigPaths(appType) {
99
99
  }
100
100
  return configPaths;
101
101
  }
102
- export function isPathDirectory(path) {
102
+ export async function isPathDirectory(path) {
103
103
  try {
104
- const stat = fs.statSync(path);
104
+ const stat = await fs.stat(path);
105
105
  return stat.isDirectory();
106
106
  }
107
107
  catch {