@swell/cli 2.0.1-alpha.9 → 2.0.2

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 (102) hide show
  1. package/dist/app-command.d.ts +1 -1
  2. package/dist/app-command.js +9 -9
  3. package/dist/commands/app/dev.d.ts +16 -0
  4. package/dist/commands/app/dev.js +28 -0
  5. package/dist/commands/app/frontend/deploy.d.ts +15 -0
  6. package/dist/commands/app/frontend/deploy.js +41 -0
  7. package/dist/commands/app/frontend/dev.d.ts +19 -0
  8. package/dist/commands/app/frontend/dev.js +108 -0
  9. package/dist/commands/app/info.js +14 -9
  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 +4 -4
  13. package/dist/commands/app/install.js +36 -42
  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 +11 -14
  17. package/dist/commands/app/push.js +64 -138
  18. package/dist/commands/app/release.d.ts +13 -0
  19. package/dist/commands/app/release.js +148 -0
  20. package/dist/commands/app/version.d.ts +5 -4
  21. package/dist/commands/app/version.js +63 -42
  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 +143 -137
  26. package/dist/commands/create/content.d.ts +2 -2
  27. package/dist/commands/create/content.js +10 -10
  28. package/dist/commands/create/frontend.d.ts +12 -0
  29. package/dist/commands/create/frontend.js +38 -0
  30. package/dist/commands/create/function.d.ts +3 -3
  31. package/dist/commands/create/function.js +22 -22
  32. package/dist/commands/create/model.d.ts +2 -2
  33. package/dist/commands/create/model.js +11 -11
  34. package/dist/commands/create/notification.d.ts +4 -4
  35. package/dist/commands/create/notification.js +38 -40
  36. package/dist/commands/env.d.ts +12 -0
  37. package/dist/commands/env.js +31 -0
  38. package/dist/commands/login.d.ts +1 -1
  39. package/dist/commands/login.js +18 -24
  40. package/dist/commands/logs.js +0 -1
  41. package/dist/commands/theme/dev.d.ts +21 -0
  42. package/dist/commands/theme/dev.js +164 -0
  43. package/dist/commands/theme/init.d.ts +9 -0
  44. package/dist/commands/theme/init.js +15 -0
  45. package/dist/commands/theme/pull.d.ts +20 -0
  46. package/dist/commands/theme/pull.js +65 -0
  47. package/dist/commands/theme/push.d.ts +19 -0
  48. package/dist/commands/theme/push.js +89 -0
  49. package/dist/create-app-command.d.ts +20 -0
  50. package/dist/create-app-command.js +253 -0
  51. package/dist/create-collection-command.d.ts +9 -9
  52. package/dist/create-collection-command.js +23 -23
  53. package/dist/{create-command.d.ts → create-config-command.d.ts} +1 -1
  54. package/dist/{create-command.js → create-config-command.js} +7 -7
  55. package/dist/env/local.d.ts +8 -0
  56. package/dist/env/local.js +7 -0
  57. package/dist/env/production.d.ts +8 -0
  58. package/dist/env/production.js +7 -0
  59. package/dist/env/review.d.ts +8 -0
  60. package/dist/env/review.js +7 -0
  61. package/dist/env/staging.d.ts +8 -0
  62. package/dist/env/staging.js +7 -0
  63. package/dist/lib/api.d.ts +4 -2
  64. package/dist/lib/api.js +50 -21
  65. package/dist/lib/app-config.d.ts +13 -5
  66. package/dist/lib/app-config.js +62 -24
  67. package/dist/lib/apps/app-config.d.ts +17 -3
  68. package/dist/lib/apps/app-config.js +194 -66
  69. package/dist/lib/apps/index.d.ts +93 -12
  70. package/dist/lib/apps/index.js +155 -50
  71. package/dist/lib/apps/paths.d.ts +14 -7
  72. package/dist/lib/apps/paths.js +73 -28
  73. package/dist/lib/bundle.js +15 -3
  74. package/dist/lib/config.d.ts +9 -2
  75. package/dist/lib/config.js +49 -1
  76. package/dist/lib/constants.d.ts +5 -0
  77. package/dist/lib/constants.js +24 -6
  78. package/dist/lib/create/content.d.ts +2 -2
  79. package/dist/lib/create/content.js +1 -1
  80. package/dist/lib/create/function.d.ts +2 -2
  81. package/dist/lib/create/function.js +2 -2
  82. package/dist/lib/create/index.d.ts +1 -1
  83. package/dist/lib/create/index.js +11 -7
  84. package/dist/lib/create/model.d.ts +2 -2
  85. package/dist/lib/create/notification.d.ts +2 -2
  86. package/dist/lib/info.js +2 -2
  87. package/dist/lib/logs/index.js +1 -1
  88. package/dist/lib/sessions.js +2 -2
  89. package/dist/lib/stores.d.ts +9 -4
  90. package/dist/lib/stores.js +13 -8
  91. package/dist/lib/style.d.ts +2 -0
  92. package/dist/lib/style.js +2 -0
  93. package/dist/lib/swell-function-wrapper.d.ts +40 -1
  94. package/dist/lib/swell-function-wrapper.js +107 -22
  95. package/dist/push-app-command.d.ts +73 -0
  96. package/dist/push-app-command.js +743 -0
  97. package/dist/remote-app-command.d.ts +37 -11
  98. package/dist/remote-app-command.js +432 -169
  99. package/oclif.manifest.json +872 -123
  100. package/package.json +14 -1
  101. package/dist/commands/app/_pull.d.ts +0 -8
  102. package/dist/commands/app/_pull.js +0 -45
@@ -1,26 +1,26 @@
1
- import { CreateCommand } from './create-command.js';
1
+ import { CreateConfigCommand } from './create-config-command.js';
2
2
  /**
3
3
  * A base class for Swell CLI Create [content|models] command input.
4
4
  *
5
- * This class extends the `CreateCommand` class and adds:
5
+ * This class extends the `CreateConfigCommand` class and adds:
6
6
  *
7
7
  * - promptCollection: Get collection name and description
8
8
  */
9
- export declare abstract class CreateCollectionCommand extends CreateCommand {
10
- static baseFlags: {
11
- 'app-path': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
- };
9
+ export declare abstract class CreateCollectionCommand extends CreateConfigCommand {
13
10
  static args: {
14
11
  collection: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
15
12
  };
13
+ static baseFlags: {
14
+ 'app-path': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
15
+ };
16
16
  static flags: {
17
- label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
17
  description: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
+ label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
19
19
  overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
20
20
  };
21
21
  promptCollection(): Promise<{
22
- label: string;
23
- description: string;
24
22
  collection: string;
23
+ description: string;
24
+ label: string;
25
25
  }>;
26
26
  }
@@ -1,39 +1,39 @@
1
- import { input, select, Separator } from '@inquirer/prompts';
1
+ import { Separator, input, select } from '@inquirer/prompts';
2
2
  import { Args, Flags } from '@oclif/core';
3
- import { CreateCommand } from './create-command.js';
4
- import { toCollectionName, toCollectionLabel } from './lib/create/index.js';
3
+ import { CreateConfigCommand } from './create-config-command.js';
4
+ import { toCollectionLabel, toCollectionName } from './lib/create/index.js';
5
5
  /**
6
6
  * A base class for Swell CLI Create [content|models] command input.
7
7
  *
8
- * This class extends the `CreateCommand` class and adds:
8
+ * This class extends the `CreateConfigCommand` class and adds:
9
9
  *
10
10
  * - promptCollection: Get collection name and description
11
11
  */
12
- export class CreateCollectionCommand extends CreateCommand {
12
+ export class CreateCollectionCommand extends CreateConfigCommand {
13
13
  // base flags for all AppCommands
14
- // needs to be in a ES2021 format: https://github.com/oclif/oclif/issues/1100
15
- static baseFlags = {
16
- 'app-path': Flags.string({
17
- description: 'path to the app directory',
18
- }),
19
- };
20
14
  static args = {
21
15
  collection: Args.string({
22
16
  default: '',
23
17
  description: 'collection to create or apply to, i.e. products',
24
18
  }),
25
19
  };
26
- static flags = {
27
- label: Flags.string({
28
- char: 'l',
29
- default: '',
30
- description: 'the collection label',
20
+ // needs to be in a ES2021 format: https://github.com/oclif/oclif/issues/1100
21
+ static baseFlags = {
22
+ 'app-path': Flags.string({
23
+ description: 'path to your app directory',
31
24
  }),
25
+ };
26
+ static flags = {
32
27
  description: Flags.string({
33
28
  char: 'd',
34
29
  default: '',
35
30
  description: 'the collection description',
36
31
  }),
32
+ label: Flags.string({
33
+ char: 'l',
34
+ default: '',
35
+ description: 'the collection label',
36
+ }),
37
37
  overwrite: Flags.boolean({
38
38
  char: 'o',
39
39
  default: false,
@@ -42,14 +42,13 @@ export class CreateCollectionCommand extends CreateCommand {
42
42
  };
43
43
  async promptCollection() {
44
44
  const { args, flags } = await this.parse(CreateCollectionCommand);
45
- let { label, description } = flags;
45
+ let { description, label } = flags;
46
46
  let { collection } = args;
47
47
  let isStandardCollection = false;
48
48
  let collectionInput = collection;
49
49
  if (!collection) {
50
50
  const collections = await this.getCollectionOptions();
51
51
  collectionInput = await select({
52
- message: 'Where will content be stored?',
53
52
  choices: [
54
53
  { name: 'Create a new collection', value: '' },
55
54
  new Separator(),
@@ -58,6 +57,7 @@ export class CreateCollectionCommand extends CreateCommand {
58
57
  value: collectionName,
59
58
  })),
60
59
  ],
60
+ message: 'Where will content be stored?',
61
61
  pageSize: 25,
62
62
  });
63
63
  if (collectionInput) {
@@ -65,8 +65,8 @@ export class CreateCollectionCommand extends CreateCommand {
65
65
  }
66
66
  else {
67
67
  collectionInput = await input({
68
- message: 'Collection name',
69
68
  default: 'special-things',
69
+ message: 'Collection name',
70
70
  });
71
71
  }
72
72
  // we replace unwanted characters with underscores to make things easier
@@ -75,23 +75,23 @@ export class CreateCollectionCommand extends CreateCommand {
75
75
  }
76
76
  if (!label && !isStandardCollection) {
77
77
  label = await input({
78
- message: 'Collection label',
79
78
  default: toCollectionLabel(collection),
79
+ message: 'Collection label',
80
80
  });
81
81
  label = toCollectionLabel(label);
82
82
  }
83
83
  description =
84
84
  description ||
85
85
  (await input({
86
+ default: 'Special things for special people',
86
87
  message: isStandardCollection
87
88
  ? `Describe the purpose of fields being added to ${collection}`
88
89
  : 'Describe what this collection is for',
89
- default: 'Special things for special people',
90
90
  }));
91
91
  return {
92
- label,
93
- description,
94
92
  collection,
93
+ description,
94
+ label,
95
95
  };
96
96
  }
97
97
  }
@@ -9,7 +9,7 @@ import { CreateFileParams } from './lib/create/index.js';
9
9
  * - createType: Type of Config to generate file path
10
10
  * - createFile: File creation, including general prompts
11
11
  */
12
- export declare abstract class CreateCommand extends AppCommand {
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
15
  protected getCollectionOptions(): Promise<any>;
@@ -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 { ConfigPaths, fileExists, writeFile, writeJsonFile, } from './lib/apps/index.js';
4
+ import { ConfigPaths, filePathExists, 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
  *
@@ -10,7 +10,7 @@ import { ConfigPaths, fileExists, writeFile, writeJsonFile, } from './lib/apps/i
10
10
  * - createType: Type of Config to generate file path
11
11
  * - createFile: File creation, including general prompts
12
12
  */
13
- export class CreateCommand extends AppCommand {
13
+ export class CreateConfigCommand extends AppCommand {
14
14
  createType = '';
15
15
  async createFile({ extension = 'json', fileBody, fileName }, overwrite, shouldConfirm = true) {
16
16
  const isJson = extension === 'json';
@@ -18,7 +18,7 @@ export class CreateCommand 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 (fileExists(filePath) && !overwrite) {
21
+ if (filePathExists(filePath) && !overwrite) {
22
22
  const continueWrite = await confirm({
23
23
  message: `This will overwrite an existing ${this.createType} file. Ok to continue?`,
24
24
  });
@@ -44,14 +44,14 @@ export class CreateCommand extends AppCommand {
44
44
  async getCollectionOptions() {
45
45
  const models = await this.api.post({ adminPath: `/data/$get/:models` }, {
46
46
  body: {
47
- limit: 1000,
48
- client_id: null,
49
- app_id: null,
50
47
  abstract: { $ne: true },
48
+ app_id: null,
49
+ client_id: null,
51
50
  deprecated: { $ne: true },
51
+ fields: 'name, namespace',
52
+ limit: 1000,
52
53
  name: { $nin: ['events', 'notifications', 'settings'] },
53
54
  sort: 'namespace asc, name asc',
54
- fields: 'name, namespace',
55
55
  },
56
56
  });
57
57
  return (models?.results?.map((model) => model.namespace ? `${model.namespace}/${model.name}` : model.name) || []);
@@ -0,0 +1,8 @@
1
+ declare namespace _default {
2
+ let API_BASE_URL: string;
3
+ let ADMIN_API_BASE_URL: string;
4
+ let LOGIN_HOST: string;
5
+ let APP_PAGES_HOST: string;
6
+ let STOREFRONT_FRONTEND_HOST: string;
7
+ }
8
+ export default _default;
@@ -0,0 +1,7 @@
1
+ export default {
2
+ API_BASE_URL: 'https://localapi.schema.io:4443',
3
+ ADMIN_API_BASE_URL: 'http://${STORE_ID}.swell.test:4001/admin/api',
4
+ LOGIN_HOST: 'http://${STORE_ID}.swell.test:3000',
5
+ APP_PAGES_HOST: 'http://${STORE_ID}--${APP_ID}--${ENV}.swell.test:4001',
6
+ STOREFRONT_FRONTEND_HOST: 'http://${BRANCH_PREFIX}${STOREFRONT_SLUG}.swell.test:4001',
7
+ };
@@ -0,0 +1,8 @@
1
+ declare namespace _default {
2
+ let API_BASE_URL: string;
3
+ let ADMIN_API_BASE_URL: string;
4
+ let LOGIN_HOST: string;
5
+ let APP_PAGES_HOST: string;
6
+ let STOREFRONT_FRONTEND_HOST: string;
7
+ }
8
+ export default _default;
@@ -0,0 +1,7 @@
1
+ export default {
2
+ API_BASE_URL: 'https://api.swell.store',
3
+ ADMIN_API_BASE_URL: 'https://${STORE_ID}.swell.store/admin/api',
4
+ LOGIN_HOST: 'https://${STORE_ID}.swell.store',
5
+ APP_PAGES_HOST: 'https://${STORE_ID}--${APP_ID}--${ENV}.swell.store',
6
+ STOREFRONT_FRONTEND_HOST: 'https://${BRANCH_PREFIX}${STOREFRONT_SLUG}.swell.store',
7
+ };
@@ -0,0 +1,8 @@
1
+ declare namespace _default {
2
+ let API_BASE_URL: string;
3
+ let ADMIN_API_BASE_URL: string;
4
+ let LOGIN_HOST: string;
5
+ let APP_PAGES_HOST: string;
6
+ let STOREFRONT_FRONTEND_HOST: string;
7
+ }
8
+ export default _default;
@@ -0,0 +1,7 @@
1
+ export default {
2
+ API_BASE_URL: 'https://${REVIEW_DOMAIN}.rav2.swell.store',
3
+ ADMIN_API_BASE_URL: 'https://${STORE_ID}.${REVIEW_DOMAIN}.rav2.swell.store/admin/api',
4
+ LOGIN_HOST: 'https://${REVIEW_DOMAIN}.rav2.swell.store',
5
+ APP_PAGES_HOST: 'https://${STORE_ID}--${APP_ID}--${ENV}.${REVIEW_DOMAIN}.rav2.swell.store',
6
+ STOREFRONT_FRONTEND_HOST: 'https://${BRANCH_PREFIX}${STOREFRONT_SLUG}.${REVIEW_DOMAIN}.rav2.swell.store',
7
+ };
@@ -0,0 +1,8 @@
1
+ declare namespace _default {
2
+ let API_BASE_URL: string;
3
+ let ADMIN_API_BASE_URL: string;
4
+ let LOGIN_HOST: string;
5
+ let APP_PAGES_HOST: string;
6
+ let STOREFRONT_FRONTEND_HOST: string;
7
+ }
8
+ export default _default;
@@ -0,0 +1,7 @@
1
+ export default {
2
+ API_BASE_URL: 'https://staging.swell.store',
3
+ ADMIN_API_BASE_URL: 'https://${STORE_ID}.staging.swell.store/admin/api',
4
+ LOGIN_HOST: 'https://staging.swell.store',
5
+ APP_PAGES_HOST: 'https://${STORE_ID}--${APP_ID}--${ENV}.staging.swell.store',
6
+ STOREFRONT_FRONTEND_HOST: 'https://${BRANCH_PREFIX}${STOREFRONT_SLUG}.staging.swell.store',
7
+ };
package/dist/lib/api.d.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  export default class Api {
2
+ private envId;
2
3
  private secretKey;
3
4
  private storeId;
4
- private envId;
5
5
  constructor(storeId?: string, envId?: string, secretKey?: string);
6
- setStoreEnv(storeId: string, envId?: string): void;
7
6
  api(pathOpts: Api.Paths, options: Api.RequestOptions): Promise<any>;
8
7
  delete(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
9
8
  get(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
10
9
  isAdmin(): boolean;
11
10
  post(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
12
11
  put(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
12
+ setStoreEnv(storeId: string, envId?: string): void;
13
+ truncatePath(path: string | undefined): string | undefined;
14
+ waitForAsyncResponse(response: any, pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
13
15
  }
package/dist/lib/api.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import fetch from 'node-fetch';
2
+ import { stringify } from 'qs';
2
3
  import config from './config.js';
3
- import { getAdminApiBaseUrl, API_BASE_URL } from './constants.js';
4
+ import { API_BASE_URL, getAdminApiBaseUrl } from './constants.js';
4
5
  const defaultHeaders = (opts) => ({
5
6
  'Content-Type': 'application/json',
6
7
  ...opts,
@@ -23,18 +24,14 @@ const authenticatedHeaders = (storeId, opts = {}) => {
23
24
  return defaultHeaders(moreOpts);
24
25
  };
25
26
  export default class Api {
27
+ envId;
26
28
  secretKey;
27
29
  storeId;
28
- envId;
29
30
  constructor(storeId, envId, secretKey) {
30
31
  this.storeId = storeId;
31
32
  this.envId = envId;
32
33
  this.secretKey = secretKey;
33
34
  }
34
- setStoreEnv(storeId, envId) {
35
- this.storeId = storeId;
36
- this.envId = envId;
37
- }
38
35
  async api(pathOpts, options) {
39
36
  const storeId = this.storeId || config.getDefaultStore();
40
37
  let path;
@@ -51,38 +48,38 @@ export default class Api {
51
48
  },
52
49
  };
53
50
  path = this.isAdmin()
54
- ? `${getAdminApiBaseUrl(storeId)}/${pathOpts.adminPath}`
55
- : `${API_BASE_URL}/${pathOpts.backendPath}`;
51
+ ? `${getAdminApiBaseUrl(storeId)}/${this.truncatePath(pathOpts.adminPath)}`
52
+ : `${API_BASE_URL}/${this.truncatePath(pathOpts.backendPath)}`;
56
53
  if (options.query) {
57
- const query = new URLSearchParams(options.query);
58
- path += `?${query.toString()}`;
54
+ path += `?${stringify(options.query)}`;
59
55
  }
60
56
  path = path
61
- // eslint-disable-next-line no-template-curly-in-string
62
57
  .replace('${STORE_ID}', storeId) // replace store id in template string
63
58
  .replaceAll(/([^:]\/)\/+/g, '$1'); // remove duplicate slashes
64
59
  if (!path)
65
60
  throw new Error('Operation not supported.');
66
- const resp = await fetch(path, fetchOptions);
67
- const respData = await resp.text();
68
- if (!resp.ok) {
61
+ const res = await fetch(path, fetchOptions);
62
+ const resData = await res.text();
63
+ if (!res.ok) {
69
64
  // Try to parse error message
70
65
  let errorJson;
71
66
  try {
72
- errorJson = JSON.parse(respData);
67
+ errorJson = JSON.parse(resData);
73
68
  }
74
69
  catch {
75
70
  // ignore
76
71
  }
77
- throw new Error(errorJson?.error?.message || errorJson?.error || respData);
72
+ const error = new Error(errorJson?.error?.message || errorJson?.error || resData);
73
+ error.status = res.status;
74
+ throw error;
78
75
  }
79
76
  try {
80
- return JSON.parse(respData);
77
+ return JSON.parse(resData);
81
78
  }
82
79
  catch (error) {
83
80
  // respData could be "{}" (length: >=2) but it shouldn't be "{", " " (whitespace - length: 1) or
84
81
  // "" (empty response - length: 0) while logging the error.
85
- if (respData.length >= 2)
82
+ if (resData.length >= 2)
86
83
  console.log(error);
87
84
  return null;
88
85
  }
@@ -91,10 +88,11 @@ export default class Api {
91
88
  // ensure post body is stringified
92
89
  if (options.body)
93
90
  options.body = JSON.stringify(options.body);
94
- return this.api(pathOpts, {
91
+ const response = await this.api(pathOpts, {
95
92
  method: 'DELETE',
96
93
  ...options,
97
94
  });
95
+ return this.waitForAsyncResponse(response, pathOpts, options);
98
96
  }
99
97
  async get(pathOpts, options = {}) {
100
98
  return this.api(pathOpts, {
@@ -109,18 +107,49 @@ export default class Api {
109
107
  // ensure post body is stringified
110
108
  if (options.body)
111
109
  options.body = JSON.stringify(options.body);
112
- return this.api(pathOpts, {
110
+ const response = await this.api(pathOpts, {
113
111
  method: 'POST',
114
112
  ...options,
115
113
  });
114
+ return this.waitForAsyncResponse(response, pathOpts, options);
116
115
  }
117
116
  async put(pathOpts, options = {}) {
118
117
  // ensure post body is stringified
119
118
  if (options.body)
120
119
  options.body = JSON.stringify(options.body);
121
- return this.api(pathOpts, {
120
+ const response = await this.api(pathOpts, {
122
121
  method: 'PUT',
123
122
  ...options,
124
123
  });
124
+ return this.waitForAsyncResponse(response, pathOpts, options);
125
+ }
126
+ setStoreEnv(storeId, envId) {
127
+ this.storeId = storeId;
128
+ this.envId = envId;
129
+ }
130
+ truncatePath(path) {
131
+ return path?.startsWith('/') ? path.slice(1) : path;
132
+ }
133
+ async waitForAsyncResponse(response, pathOpts, options = {}) {
134
+ const { onAsyncGetPath, spinner } = options;
135
+ if (!response?.async_progressing || !onAsyncGetPath) {
136
+ return response;
137
+ }
138
+ /* eslint-disable-next-line no-promise-executor-return */
139
+ await new Promise((resolve) => setTimeout(resolve, 1000));
140
+ const asyncResponse = await this.api(onAsyncGetPath(response), {
141
+ method: 'GET',
142
+ onAsyncGetPath,
143
+ });
144
+ if (asyncResponse?.async_error) {
145
+ throw new Error(asyncResponse.async_error);
146
+ }
147
+ if (!asyncResponse?.async_progressing && spinner) {
148
+ spinner.suffixText = '';
149
+ }
150
+ else if (asyncResponse?.async_progress > 0 && spinner) {
151
+ spinner.suffixText = `${asyncResponse.async_progress}%`;
152
+ }
153
+ return this.waitForAsyncResponse(asyncResponse, pathOpts, options);
125
154
  }
126
155
  }
@@ -1,29 +1,37 @@
1
1
  import { App } from './apps';
2
2
  /**
3
- * Checks if the app config file exists.
3
+ * Checks if the swell config file exists at the given path, default to cwd.
4
4
  *
5
5
  * @param configFilePath - the path to the app config file
6
6
  * @returns boolean
7
7
  * @throws Error
8
8
  */
9
- declare function appConfigFileExists(configFilePath?: string): boolean;
9
+ declare function swellConfigFileExists(configFilePath?: string): boolean;
10
10
  declare function writeRcFile(path: string, data: any): Promise<void>;
11
11
  declare function readRcFile(path: string): App;
12
12
  /**
13
13
  * Returns a new configuration instance in the current working directory or
14
14
  * a parent directory.
15
15
  *
16
- * @param configDirPath - the path to the app config directory. If not provided,
16
+ * @param configDir - the path to the app config directory. If not provided,
17
17
  * the config file will be searched for in the current working directory or
18
18
  * a parent directory.
19
19
  *
20
20
  * @returns Conf
21
21
  */
22
- declare function config(configDirPath?: string): LocalApp;
22
+ declare function config(configDir?: string): LocalApp;
23
23
  /**
24
24
  * Returns a new configuration instance in the current working directory only.
25
25
  *
26
+ * @param path Path of the current working directory
26
27
  * @returns Conf
27
28
  */
28
29
  declare function newConfig(path?: string): any;
29
- export { appConfigFileExists, config as default, newConfig, readRcFile, writeRcFile, };
30
+ /**
31
+ * Returns a new configuration instance at the specified path.
32
+ *
33
+ * @param appPath Path of the current working directory
34
+ * @returns Conf
35
+ */
36
+ declare function newConfigAtPath(appPath?: string): any;
37
+ export { config as default, newConfig, newConfigAtPath, readRcFile, swellConfigFileExists, writeRcFile, };
@@ -5,12 +5,16 @@ import Conf from 'conf';
5
5
  import * as fs from 'node:fs';
6
6
  import * as path from 'node:path';
7
7
  const schema = {
8
+ compatibilities: { type: 'object' },
9
+ description: { type: 'string' },
8
10
  id: { type: 'string' },
9
- version: { type: 'string' },
11
+ integrations: { type: 'array' },
10
12
  name: { type: 'string' },
11
- description: { type: 'string' },
12
- type: { type: 'string' },
13
13
  permissions: { type: 'array' },
14
+ storefront: { type: 'object' },
15
+ theme: { type: 'object' },
16
+ type: { type: 'string' },
17
+ version: { type: 'string' },
14
18
  };
15
19
  const APP_FILE_NAME = 'swell';
16
20
  const APP_FILE_EXT = 'json';
@@ -21,23 +25,23 @@ const APP_FILE_EXT = 'json';
21
25
  * @param dir - the directory to use for the config file path
22
26
  * @returns string
23
27
  */
24
- function appConfigFile(dir = '') {
28
+ function swellConfigFile(dir = '') {
25
29
  if (!dir) {
26
30
  dir = process.cwd();
27
31
  }
28
32
  return path.join(dir, [APP_FILE_NAME, '.', APP_FILE_EXT].join(''));
29
33
  }
30
34
  /**
31
- * Checks if the app config file exists.
35
+ * Checks if the swell config file exists at the given path, default to cwd.
32
36
  *
33
37
  * @param configFilePath - the path to the app config file
34
38
  * @returns boolean
35
39
  * @throws Error
36
40
  */
37
- function appConfigFileExists(configFilePath = '') {
41
+ function swellConfigFileExists(configFilePath = '') {
38
42
  // if the config file path is not provided, try to find it as the default
39
43
  if (!configFilePath) {
40
- configFilePath = appConfigFile();
44
+ configFilePath = swellConfigFile();
41
45
  }
42
46
  try {
43
47
  // eslint-disable-next-line no-bitwise
@@ -59,9 +63,9 @@ function appConfigFileExists(configFilePath = '') {
59
63
  * @returns string
60
64
  * @throws Error
61
65
  */
62
- function appConfigFilePath(dir = '') {
63
- const configFilePath = appConfigFile(dir);
64
- if (appConfigFileExists(configFilePath)) {
66
+ function swellConfigFilePath(dir = '') {
67
+ const configFilePath = swellConfigFile(dir);
68
+ if (swellConfigFileExists(configFilePath)) {
65
69
  return configFilePath;
66
70
  }
67
71
  // if the file doesn't exist, try to find it in the parent directory
@@ -69,10 +73,10 @@ function appConfigFilePath(dir = '') {
69
73
  if (dir && dir === path.parse(dir).root) {
70
74
  return '';
71
75
  }
72
- return appConfigFilePath(path.resolve(dir, '..'));
76
+ return swellConfigFilePath(path.resolve(dir, '..'));
73
77
  }
74
78
  async function writeRcFile(path, data) {
75
- let dataToWrite = '';
79
+ let dataToWrite = '# This file is automatically generated by the Swell CLI\n';
76
80
  for (const [key, value] of Object.entries(data)) {
77
81
  dataToWrite += `${key}=${value}\n`;
78
82
  }
@@ -83,9 +87,15 @@ function readRcFile(path) {
83
87
  const dataFromFile = fs.readFileSync(path, 'utf8');
84
88
  const lines = dataFromFile.split('\n');
85
89
  for (const line of lines) {
86
- const [key, value] = line.split('=');
87
- if (key && value) {
88
- data[key] = value;
90
+ const cleanLine = line.trim();
91
+ if (cleanLine.startsWith('#')) {
92
+ // Ignore comments
93
+ continue;
94
+ }
95
+ const [key, value] = cleanLine.trim().split('=');
96
+ const cleanValue = value && value.trim();
97
+ if (key && cleanValue) {
98
+ data[key] = cleanValue;
89
99
  }
90
100
  }
91
101
  return data;
@@ -94,19 +104,26 @@ function readRcFile(path) {
94
104
  * Returns a new configuration instance in the current working directory or
95
105
  * a parent directory.
96
106
  *
97
- * @param configDirPath - the path to the app config directory. If not provided,
107
+ * @param configDir - the path to the app config directory. If not provided,
98
108
  * the config file will be searched for in the current working directory or
99
109
  * a parent directory.
100
110
  *
101
111
  * @returns Conf
102
112
  */
103
- function config(configDirPath = '') {
104
- const dirPath = configDirPath || path.dirname(appConfigFilePath());
105
- const config = new Conf({
106
- configName: APP_FILE_NAME,
107
- cwd: dirPath,
108
- schema,
109
- });
113
+ function config(configDir = '') {
114
+ const dirPath = configDir || path.dirname(swellConfigFilePath());
115
+ let config;
116
+ try {
117
+ config = new Conf({
118
+ clearInvalidConfig: true,
119
+ configName: APP_FILE_NAME,
120
+ cwd: dirPath,
121
+ schema,
122
+ });
123
+ }
124
+ catch (error) {
125
+ throw new Error(`Error parsing swell.json: ${error.toString()}`);
126
+ }
110
127
  // for convenience, we add custom properties to the Conf object
111
128
  // we prefix them with "sw" to avoid conflicts with Conf's properties
112
129
  config.swDirPath = dirPath;
@@ -115,13 +132,34 @@ function config(configDirPath = '') {
115
132
  /**
116
133
  * Returns a new configuration instance in the current working directory only.
117
134
  *
135
+ * @param path Path of the current working directory
118
136
  * @returns Conf
119
137
  */
120
138
  function newConfig(path) {
121
139
  return new Conf({
140
+ clearInvalidConfig: true,
122
141
  configName: APP_FILE_NAME,
123
142
  cwd: `${process.cwd()}${path ? `/${path}` : ''}`,
124
143
  schema,
144
+ serialize,
125
145
  });
126
146
  }
127
- export { appConfigFileExists, config as default, newConfig, readRcFile, writeRcFile, };
147
+ /**
148
+ * Returns a new configuration instance at the specified path.
149
+ *
150
+ * @param appPath Path of the current working directory
151
+ * @returns Conf
152
+ */
153
+ function newConfigAtPath(appPath) {
154
+ const dirPath = appPath || path.dirname(swellConfigFilePath());
155
+ return new Conf({
156
+ configName: APP_FILE_NAME,
157
+ cwd: dirPath,
158
+ schema,
159
+ serialize,
160
+ });
161
+ }
162
+ function serialize(value) {
163
+ return JSON.stringify(value, null, 2);
164
+ }
165
+ export { config as default, newConfig, newConfigAtPath, readRcFile, swellConfigFileExists, writeRcFile, };