@swell/cli 2.1.0 → 2.2.0

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 (87) hide show
  1. package/dist/commands/api/delete.d.ts +15 -0
  2. package/dist/commands/api/delete.js +26 -0
  3. package/dist/commands/api/get.d.ts +15 -0
  4. package/dist/commands/api/get.js +31 -0
  5. package/dist/commands/api/index.d.ts +7 -0
  6. package/dist/commands/api/index.js +16 -0
  7. package/dist/commands/api/post.d.ts +16 -0
  8. package/dist/commands/api/post.js +33 -0
  9. package/dist/commands/api/put.d.ts +16 -0
  10. package/dist/commands/api/put.js +33 -0
  11. package/dist/commands/app/dev.d.ts +9 -9
  12. package/dist/commands/app/dev.js +158 -136
  13. package/dist/commands/app/frontend/dev.d.ts +1 -1
  14. package/dist/commands/app/frontend/dev.js +84 -78
  15. package/dist/commands/app/install.js +3 -3
  16. package/dist/commands/app/pull.d.ts +1 -1
  17. package/dist/commands/app/pull.js +6 -6
  18. package/dist/commands/app/push.d.ts +3 -3
  19. package/dist/commands/app/push.js +8 -6
  20. package/dist/commands/app/release.d.ts +1 -1
  21. package/dist/commands/app/release.js +1 -1
  22. package/dist/commands/app/version.d.ts +1 -1
  23. package/dist/commands/app/version.js +5 -3
  24. package/dist/commands/create/app.d.ts +10 -2
  25. package/dist/commands/create/app.js +226 -57
  26. package/dist/commands/create/content.d.ts +4 -0
  27. package/dist/commands/create/content.js +83 -15
  28. package/dist/commands/create/function.js +27 -5
  29. package/dist/commands/create/model.d.ts +4 -0
  30. package/dist/commands/create/model.js +120 -25
  31. package/dist/commands/inspect/content.d.ts +25 -0
  32. package/dist/commands/inspect/content.js +159 -0
  33. package/dist/commands/inspect/index.d.ts +7 -0
  34. package/dist/commands/inspect/index.js +16 -0
  35. package/dist/commands/inspect/models.d.ts +27 -0
  36. package/dist/commands/inspect/models.js +197 -0
  37. package/dist/commands/schema.d.ts +27 -0
  38. package/dist/commands/schema.js +231 -0
  39. package/dist/commands/theme/dev.d.ts +1 -1
  40. package/dist/commands/theme/dev.js +2 -2
  41. package/dist/commands/theme/init.d.ts +1 -1
  42. package/dist/commands/theme/init.js +1 -1
  43. package/dist/commands/theme/pull.d.ts +2 -2
  44. package/dist/commands/theme/pull.js +2 -2
  45. package/dist/commands/theme/push.d.ts +1 -1
  46. package/dist/commands/theme/push.js +1 -1
  47. package/dist/create-app-command.d.ts +12 -2
  48. package/dist/create-app-command.js +103 -80
  49. package/dist/create-collection-command.js +4 -1
  50. package/dist/create-config-command.js +4 -0
  51. package/dist/env/local.d.ts +1 -0
  52. package/dist/env/local.js +1 -0
  53. package/dist/env/production.d.ts +1 -0
  54. package/dist/env/production.js +1 -0
  55. package/dist/env/review.d.ts +1 -0
  56. package/dist/env/review.js +1 -0
  57. package/dist/env/staging.d.ts +1 -0
  58. package/dist/env/staging.js +1 -0
  59. package/dist/lib/api.d.ts +16 -5
  60. package/dist/lib/api.js +67 -25
  61. package/dist/lib/app-config.js +1 -0
  62. package/dist/lib/apps/index.d.ts +2 -0
  63. package/dist/lib/apps/index.js +20 -15
  64. package/dist/lib/config.d.ts +1 -1
  65. package/dist/lib/constants.d.ts +1 -0
  66. package/dist/lib/constants.js +1 -0
  67. package/dist/lib/create/content.d.ts +5 -1
  68. package/dist/lib/create/content.js +8 -1
  69. package/dist/lib/create/function.d.ts +2 -1
  70. package/dist/lib/create/function.js +7 -3
  71. package/dist/lib/create/model.d.ts +1 -0
  72. package/dist/lib/create/schemas.d.ts +6 -0
  73. package/dist/lib/create/schemas.js +6 -0
  74. package/dist/lib/sessions.js +4 -3
  75. package/dist/lib/style.js +0 -1
  76. package/dist/lib/theme-sync.d.ts +6 -6
  77. package/dist/lib/theme-sync.js +49 -39
  78. package/dist/push-app-command.d.ts +7 -7
  79. package/dist/push-app-command.js +38 -36
  80. package/dist/remote-app-command.d.ts +1 -1
  81. package/dist/remote-app-command.js +4 -2
  82. package/dist/swell-api-command.d.ts +13 -0
  83. package/dist/swell-api-command.js +75 -0
  84. package/dist/swell-command.d.ts +1 -1
  85. package/dist/swell-command.js +9 -9
  86. package/package.json +8 -1
  87. package/oclif.manifest.json +0 -1936
@@ -2,28 +2,35 @@ 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';
5
6
  import path from 'node:path';
6
7
  import Stream from 'node:stream';
7
8
  import { promisify } from 'node:util';
8
9
  import ora from 'ora';
9
10
  import Api from './lib/api.js';
10
- import { FrontendProjectTypes, getAllConfigPaths, writeFile, writeJsonFile, } from './lib/apps/index.js';
11
+ import { FrontendProjectTypes, getFrontendProjectValidValues, getAllConfigPaths, getFrontendProjectSlugs, writeFile, writeJsonFile, } from './lib/apps/index.js';
11
12
  import style from './lib/style.js';
12
13
  import { SwellCommand } from './swell-command.js';
13
- import fs from 'node:fs/promises';
14
14
  const execAsync = promisify(exec);
15
15
  export class CreateAppCommand extends SwellCommand {
16
16
  static baseFlags = {
17
17
  frontend: Flags.string({
18
- description: `create a starter framework for a hosted frontend`,
19
- options: FrontendProjectTypes.map(({ slug }) => slug),
18
+ description: `create a starter framework for a hosted frontend (default in -y: none)`,
19
+ options: getFrontendProjectSlugs(true, false),
20
20
  }),
21
21
  'storefront-app': Flags.string({
22
22
  description: `id of an installed storefront app to create a theme for, if applicable`,
23
23
  }),
24
+ 'integration-type': Flags.string({
25
+ description: `integration type for integration app, if applicable`,
26
+ options: ['generic', 'payment', 'shipping', 'tax'],
27
+ }),
28
+ 'integration-id': Flags.string({
29
+ description: `unique identifier for the integration service (required for payment/shipping/tax; use 'card' for credit cards)`,
30
+ }),
24
31
  yes: Flags.boolean({
25
32
  char: 'y',
26
- description: `accept all default values`,
33
+ description: `accept all default values; non-interactive, never prompts; errors if required values are missing`,
27
34
  }),
28
35
  };
29
36
  devApi;
@@ -31,48 +38,11 @@ export class CreateAppCommand extends SwellCommand {
31
38
  super(argv, config);
32
39
  this.devApi = new Api(undefined, 'test');
33
40
  }
34
- async addAllowedHostsToAstro(configPath) {
35
- const astroConfigPath = path.join(configPath, 'frontend', 'astro.config.mjs');
36
- let content;
37
- try {
38
- content = await fs.readFile(astroConfigPath, 'utf-8');
39
- }
40
- catch {
41
- return;
42
- }
43
- if (content.includes('allowedHosts')) {
44
- return;
45
- }
46
- const lines = content.split('\n');
47
- let insertIndex = -1;
48
- for (let i = 0; i < lines.length; i++) {
49
- if (lines[i].includes('defineConfig({')) {
50
- insertIndex = i + 1;
51
- break;
52
- }
53
- }
54
- if (insertIndex === -1) {
55
- return;
56
- }
57
- // Detect indentation from next line or use default
58
- const nextLine = lines[insertIndex];
59
- const indentMatch = nextLine?.match(/^(\s+)/);
60
- const baseIndent = indentMatch ? indentMatch[1] : ' ';
61
- const viteConfig = [
62
- `${baseIndent}vite: {`,
63
- `${baseIndent} server: {`,
64
- `${baseIndent} allowedHosts: ['.ngrok.app', '.loca.lt'],`,
65
- `${baseIndent} },`,
66
- `${baseIndent}},`,
67
- ];
68
- lines.splice(insertIndex, 0, ...viteConfig);
69
- await fs.writeFile(astroConfigPath, lines.join('\n'), 'utf-8');
70
- }
71
41
  async addAllowedHostsToAngular(configPath) {
72
42
  const angularJsonPath = path.join(configPath, 'frontend', 'angular.json');
73
43
  let content;
74
44
  try {
75
- content = await fs.readFile(angularJsonPath, 'utf-8');
45
+ content = await fs.readFile(angularJsonPath, 'utf8');
76
46
  }
77
47
  catch {
78
48
  return;
@@ -84,7 +54,7 @@ export class CreateAppCommand extends SwellCommand {
84
54
  catch {
85
55
  return;
86
56
  }
87
- const projects = config.projects;
57
+ const { projects } = config;
88
58
  if (!projects || typeof projects !== 'object') {
89
59
  return;
90
60
  }
@@ -105,13 +75,13 @@ export class CreateAppCommand extends SwellCommand {
105
75
  return;
106
76
  }
107
77
  project.architect.serve.options.allowedHosts = ['.ngrok.app', '.loca.lt'];
108
- await fs.writeFile(angularJsonPath, JSON.stringify(config, null, 2), 'utf-8');
78
+ await fs.writeFile(angularJsonPath, JSON.stringify(config, null, 2), 'utf8');
109
79
  }
110
- async addAllowedHostsToNuxt(configPath) {
111
- const nuxtConfigPath = path.join(configPath, 'frontend', 'nuxt.config.ts');
80
+ async addAllowedHostsToAstro(configPath) {
81
+ const astroConfigPath = path.join(configPath, 'frontend', 'astro.config.mjs');
112
82
  let content;
113
83
  try {
114
- content = await fs.readFile(nuxtConfigPath, 'utf-8');
84
+ content = await fs.readFile(astroConfigPath, 'utf8');
115
85
  }
116
86
  catch {
117
87
  return;
@@ -121,8 +91,8 @@ export class CreateAppCommand extends SwellCommand {
121
91
  }
122
92
  const lines = content.split('\n');
123
93
  let insertIndex = -1;
124
- for (let i = 0; i < lines.length; i++) {
125
- if (lines[i].includes('defineNuxtConfig({')) {
94
+ for (const [i, line] of lines.entries()) {
95
+ if (line.includes('defineConfig({')) {
126
96
  insertIndex = i + 1;
127
97
  break;
128
98
  }
@@ -130,6 +100,7 @@ export class CreateAppCommand extends SwellCommand {
130
100
  if (insertIndex === -1) {
131
101
  return;
132
102
  }
103
+ // Detect indentation from next line or use default
133
104
  const nextLine = lines[insertIndex];
134
105
  const indentMatch = nextLine?.match(/^(\s+)/);
135
106
  const baseIndent = indentMatch ? indentMatch[1] : ' ';
@@ -141,23 +112,43 @@ export class CreateAppCommand extends SwellCommand {
141
112
  `${baseIndent}},`,
142
113
  ];
143
114
  lines.splice(insertIndex, 0, ...viteConfig);
144
- await fs.writeFile(nuxtConfigPath, lines.join('\n'), 'utf-8');
115
+ await fs.writeFile(astroConfigPath, lines.join('\n'), 'utf8');
145
116
  }
146
- async addFrontendAllowedHosts(projectType, configPath) {
147
- // Configure allowedHosts for frameworks using Vite dev server
148
- // This allows tunneling services (ngrok, localtunnel) to proxy requests to the local dev environment
149
- switch (projectType.slug) {
150
- case 'astro':
151
- await this.addAllowedHostsToAstro(configPath);
152
- break;
153
- case 'angular':
154
- await this.addAllowedHostsToAngular(configPath);
155
- break;
156
- case 'nuxt':
157
- await this.addAllowedHostsToNuxt(configPath);
117
+ async addAllowedHostsToNuxt(configPath) {
118
+ const nuxtConfigPath = path.join(configPath, 'frontend', 'nuxt.config.ts');
119
+ let content;
120
+ try {
121
+ content = await fs.readFile(nuxtConfigPath, 'utf8');
122
+ }
123
+ catch {
124
+ return;
125
+ }
126
+ if (content.includes('allowedHosts')) {
127
+ return;
128
+ }
129
+ const lines = content.split('\n');
130
+ let insertIndex = -1;
131
+ for (const [i, line] of lines.entries()) {
132
+ if (line.includes('defineNuxtConfig({')) {
133
+ insertIndex = i + 1;
158
134
  break;
159
- // Other frameworks don't require allowedHosts configuration
135
+ }
136
+ }
137
+ if (insertIndex === -1) {
138
+ return;
160
139
  }
140
+ const nextLine = lines[insertIndex];
141
+ const indentMatch = nextLine?.match(/^(\s+)/);
142
+ const baseIndent = indentMatch ? indentMatch[1] : ' ';
143
+ const viteConfig = [
144
+ `${baseIndent}vite: {`,
145
+ `${baseIndent} server: {`,
146
+ `${baseIndent} allowedHosts: ['.ngrok.app', '.loca.lt'],`,
147
+ `${baseIndent} },`,
148
+ `${baseIndent}},`,
149
+ ];
150
+ lines.splice(insertIndex, 0, ...viteConfig);
151
+ await fs.writeFile(nuxtConfigPath, lines.join('\n'), 'utf8');
161
152
  }
162
153
  async createAppConfigFolders(swellConfig) {
163
154
  for (const type of getAllConfigPaths(swellConfig.get('type'))) {
@@ -171,13 +162,11 @@ export class CreateAppCommand extends SwellCommand {
171
162
  async createFrontendApp(swellConfig, flags, directCreate, kind) {
172
163
  const spinner = ora();
173
164
  const configPath = path.dirname(swellConfig.path);
174
- const frameworkType = flags.frontend ||
165
+ // use 'none' by default for non-interactive mode
166
+ const inputFrontend = flags.yes ? flags.frontend || 'none' : flags.frontend;
167
+ const frameworkType = inputFrontend ||
175
168
  (await select({
176
169
  choices: [
177
- ...FrontendProjectTypes.map(({ name, slug }) => ({
178
- name,
179
- value: slug,
180
- })),
181
170
  ...(directCreate
182
171
  ? []
183
172
  : [
@@ -186,19 +175,17 @@ export class CreateAppCommand extends SwellCommand {
186
175
  value: null,
187
176
  },
188
177
  ]),
178
+ ...FrontendProjectTypes.map(({ name, slug }) => ({
179
+ name,
180
+ value: slug,
181
+ })),
189
182
  ],
190
183
  message: directCreate
191
184
  ? `Choose framework for your hosted${kind ? ` ${kind} ` : ' '}app frontend`
192
185
  : `Install framework for a hosted${kind ? ` ${kind} ` : ' '}app frontend?`,
193
186
  }));
194
- if (frameworkType) {
195
- const projectType = FrontendProjectTypes.find((type) => type.slug === frameworkType);
196
- if (!projectType) {
197
- this.error(`Could not find project type: ${frameworkType}`);
198
- }
199
- if (!projectType.installCommand) {
200
- this.error(`Project type ${projectType.name} cannot be installed (legacy type)`);
201
- }
187
+ if (frameworkType && frameworkType !== 'none') {
188
+ const projectType = this.getProjectType(frameworkType);
202
189
  this.log();
203
190
  spinner.start(`Creating ${projectType?.name} frontend app (this may take a while)...`);
204
191
  try {
@@ -223,11 +210,11 @@ export class CreateAppCommand extends SwellCommand {
223
210
  // Ensure frontend package.json has correct name for workspace
224
211
  const frontendPkgPath = path.join(configPath, 'frontend', 'package.json');
225
212
  try {
226
- const pkgContent = await fs.readFile(frontendPkgPath, 'utf-8');
213
+ const pkgContent = await fs.readFile(frontendPkgPath, 'utf8');
227
214
  const pkg = JSON.parse(pkgContent);
228
215
  if (pkg.name !== 'frontend') {
229
216
  pkg.name = 'frontend';
230
- await fs.writeFile(frontendPkgPath, JSON.stringify(pkg, null, 2), 'utf-8');
217
+ await fs.writeFile(frontendPkgPath, JSON.stringify(pkg, null, 2), 'utf8');
231
218
  }
232
219
  }
233
220
  catch {
@@ -242,7 +229,7 @@ export class CreateAppCommand extends SwellCommand {
242
229
  await execAsync('npm install', { cwd: configPath });
243
230
  spinner.succeed('Workspace initialized');
244
231
  }
245
- catch (error) {
232
+ catch {
246
233
  spinner.warn('Failed to initialize workspace');
247
234
  }
248
235
  spinner.succeed(`${projectType?.name} initialized app in ${configPath}/frontend/`);
@@ -364,6 +351,23 @@ export class CreateAppCommand extends SwellCommand {
364
351
  spinner.stop();
365
352
  return storefrontInstalledApps;
366
353
  }
354
+ getProjectType(frameworkType) {
355
+ const projectType = FrontendProjectTypes.find((type) => type.slug === frameworkType);
356
+ if (!projectType) {
357
+ this.error(`Could not find project type: ${frameworkType}\n\nValid values: ${getFrontendProjectValidValues(true, false)}\n\nExample: swell create app reviews --type admin --frontend astro -y`, {
358
+ exit: 1,
359
+ });
360
+ }
361
+ if (!projectType.installCommand) {
362
+ this.error(`Project type ${projectType.name} cannot be installed (legacy type)\n\nValid values: ${getFrontendProjectValidValues(true, false)}\n\nExample: swell create app reviews --type admin --frontend astro -y`, {
363
+ exit: 1,
364
+ });
365
+ }
366
+ return {
367
+ ...projectType,
368
+ installCommand: projectType.installCommand || '',
369
+ };
370
+ }
367
371
  async setupPackage(name, config, pkg) {
368
372
  const execAsync = promisify(exec);
369
373
  const configPath = path.dirname(config.path);
@@ -410,4 +414,23 @@ export class CreateAppCommand extends SwellCommand {
410
414
  this.log(`There was an error setting up the package manager: ${error.message}`);
411
415
  }
412
416
  }
417
+ async addFrontendAllowedHosts(projectType, configPath) {
418
+ // Configure allowedHosts for frameworks using Vite dev server
419
+ // This allows tunneling services (ngrok, localtunnel) to proxy requests to the local dev environment
420
+ switch (projectType.slug) {
421
+ case 'astro': {
422
+ await this.addAllowedHostsToAstro(configPath);
423
+ break;
424
+ }
425
+ case 'angular': {
426
+ await this.addAllowedHostsToAngular(configPath);
427
+ break;
428
+ }
429
+ case 'nuxt': {
430
+ await this.addAllowedHostsToNuxt(configPath);
431
+ break;
432
+ }
433
+ // Other frameworks don't require allowedHosts configuration
434
+ }
435
+ }
413
436
  }
@@ -41,7 +41,10 @@ export class CreateCollectionCommand extends CreateConfigCommand {
41
41
  }),
42
42
  };
43
43
  async promptCollection() {
44
- const { args, flags } = await this.parse(CreateCollectionCommand);
44
+ // Parse using the concrete command class so child-command flags
45
+ // (e.g., --events, --fields) are recognized during interactive flows.
46
+ const klass = super.ctor;
47
+ const { args, flags } = await this.parse(klass);
45
48
  let { description, label } = flags;
46
49
  let { collection } = args;
47
50
  let isStandardCollection = false;
@@ -35,6 +35,10 @@ export class CreateConfigCommand extends AppCommand {
35
35
  }
36
36
  }
37
37
  }
38
+ else if (filePathExists(filePath) && !overwrite) {
39
+ // Non-interactive mode: never prompt; fail fast on potential overwrite
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
+ }
38
42
  typeof fileBody === 'string'
39
43
  ? await writeFile(filePath, fileBody)
40
44
  : await writeJsonFile(filePath, fileBody);
@@ -5,5 +5,6 @@ declare namespace _default {
5
5
  let APP_PAGES_HOST: string;
6
6
  let STOREFRONT_FRONTEND_HOST: string;
7
7
  let LOCAL_PROXY_PROVIDER: string;
8
+ let SCHEMAS_BASE_URL: string;
8
9
  }
9
10
  export default _default;
package/dist/env/local.js CHANGED
@@ -5,4 +5,5 @@ export default {
5
5
  APP_PAGES_HOST: 'http://${STORE_ID}--${APP_ID}--${ENV}.swell.test:4001',
6
6
  STOREFRONT_FRONTEND_HOST: 'http://${BRANCH_PREFIX}${STOREFRONT_SLUG}.swell.test:4001',
7
7
  LOCAL_PROXY_PROVIDER: '',
8
+ SCHEMAS_BASE_URL: 'https://pub-3672563ccb924eeba4d45be1296a0aee.r2.dev',
8
9
  };
@@ -5,5 +5,6 @@ declare namespace _default {
5
5
  let APP_PAGES_HOST: string;
6
6
  let STOREFRONT_FRONTEND_HOST: string;
7
7
  let LOCAL_PROXY_PROVIDER: string;
8
+ let SCHEMAS_BASE_URL: string;
8
9
  }
9
10
  export default _default;
@@ -5,4 +5,5 @@ export default {
5
5
  APP_PAGES_HOST: 'https://${STORE_ID}--${APP_ID}--${ENV}.swell.store',
6
6
  STOREFRONT_FRONTEND_HOST: 'https://${BRANCH_PREFIX}${STOREFRONT_SLUG}.swell.store',
7
7
  LOCAL_PROXY_PROVIDER: '',
8
+ SCHEMAS_BASE_URL: 'https://json.swell.store',
8
9
  };
@@ -5,5 +5,6 @@ declare namespace _default {
5
5
  let APP_PAGES_HOST: string;
6
6
  let STOREFRONT_FRONTEND_HOST: string;
7
7
  let LOCAL_PROXY_PROVIDER: string;
8
+ let SCHEMAS_BASE_URL: string;
8
9
  }
9
10
  export default _default;
@@ -5,4 +5,5 @@ export default {
5
5
  APP_PAGES_HOST: 'https://${STORE_ID}--${APP_ID}--${ENV}.${REVIEW_DOMAIN}.rav2.swell.store',
6
6
  STOREFRONT_FRONTEND_HOST: 'https://${BRANCH_PREFIX}${STOREFRONT_SLUG}.${REVIEW_DOMAIN}.rav2.swell.store',
7
7
  LOCAL_PROXY_PROVIDER: '',
8
+ SCHEMAS_BASE_URL: 'https://pub-3672563ccb924eeba4d45be1296a0aee.r2.dev',
8
9
  };
@@ -5,5 +5,6 @@ declare namespace _default {
5
5
  let APP_PAGES_HOST: string;
6
6
  let STOREFRONT_FRONTEND_HOST: string;
7
7
  let LOCAL_PROXY_PROVIDER: string;
8
+ let SCHEMAS_BASE_URL: string;
8
9
  }
9
10
  export default _default;
@@ -5,4 +5,5 @@ export default {
5
5
  APP_PAGES_HOST: 'https://${STORE_ID}--${APP_ID}--${ENV}.staging.swell.store',
6
6
  STOREFRONT_FRONTEND_HOST: 'https://${BRANCH_PREFIX}${STOREFRONT_SLUG}.staging.swell.store',
7
7
  LOCAL_PROXY_PROVIDER: '',
8
+ SCHEMAS_BASE_URL: 'https://pub-3672563ccb924eeba4d45be1296a0aee.r2.dev',
8
9
  };
package/dist/lib/api.d.ts CHANGED
@@ -1,16 +1,27 @@
1
+ export declare enum HttpMethod {
2
+ GET = "get",
3
+ POST = "post",
4
+ PUT = "put",
5
+ DELETE = "delete"
6
+ }
1
7
  export default class Api {
2
8
  envId: string | undefined;
3
9
  secretKey: string | undefined;
4
10
  storeId: string | undefined;
5
11
  constructor(storeId?: string, envId?: string, secretKey?: string);
6
12
  api(pathOpts: Api.Paths, options: Api.RequestOptions): Promise<any>;
7
- delete(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
8
13
  get(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
9
- isAdmin(): boolean;
14
+ getAll(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<{
15
+ count: number;
16
+ results: any[];
17
+ }>;
10
18
  post(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
11
19
  put(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
12
- setStoreEnv(storeId: string, envId?: string): Promise<void>;
20
+ delete(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
13
21
  isTestEnvEnabled(): Promise<boolean>;
14
- truncatePath(path: string | undefined): string | undefined;
15
- waitForAsyncResponse(response: any, pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
22
+ setEnv(envId: string): Promise<void>;
23
+ setStoreEnv(storeId: string, envId?: string): Promise<void>;
24
+ private isAdmin;
25
+ private truncatePath;
26
+ private waitForAsyncResponse;
16
27
  }
package/dist/lib/api.js CHANGED
@@ -2,6 +2,14 @@ import fetch from 'node-fetch';
2
2
  import { stringify } from 'qs';
3
3
  import config from './config.js';
4
4
  import { API_BASE_URL, getAdminApiBaseUrl } from './constants.js';
5
+ export var HttpMethod;
6
+ (function (HttpMethod) {
7
+ HttpMethod["GET"] = "get";
8
+ HttpMethod["POST"] = "post";
9
+ HttpMethod["PUT"] = "put";
10
+ HttpMethod["DELETE"] = "delete";
11
+ })(HttpMethod || (HttpMethod = {}));
12
+ const GET_ALL_LIMIT = 1000;
5
13
  const defaultHeaders = (opts) => ({
6
14
  'Content-Type': 'application/json',
7
15
  ...opts,
@@ -59,6 +67,9 @@ export default class Api {
59
67
  if (!path)
60
68
  throw new Error('Operation not supported.');
61
69
  const res = await fetch(path, fetchOptions);
70
+ if (options.rawResponse) {
71
+ return res;
72
+ }
62
73
  const resData = await res.text();
63
74
  if (!res.ok) {
64
75
  // Try to parse error message
@@ -84,31 +95,46 @@ export default class Api {
84
95
  return null;
85
96
  }
86
97
  }
87
- async delete(pathOpts, options = {}) {
88
- // ensure post body is stringified
89
- if (options.body)
90
- options.body = JSON.stringify(options.body);
91
- const response = await this.api(pathOpts, {
92
- method: 'DELETE',
93
- ...options,
94
- });
95
- return this.waitForAsyncResponse(response, pathOpts, options);
96
- }
97
98
  async get(pathOpts, options = {}) {
98
99
  return this.api(pathOpts, {
99
- method: 'GET',
100
+ method: HttpMethod.GET,
100
101
  ...options,
101
102
  });
102
103
  }
103
- isAdmin() {
104
- return !this.secretKey;
104
+ async getAll(pathOpts, options = {}) {
105
+ const result = {
106
+ results: [],
107
+ count: 0,
108
+ };
109
+ let page = 1;
110
+ do {
111
+ // eslint-disable-next-line no-await-in-loop
112
+ const pageResult = await this.api(pathOpts, {
113
+ method: HttpMethod.GET,
114
+ ...options,
115
+ query: {
116
+ limit: GET_ALL_LIMIT,
117
+ ...options.query,
118
+ page,
119
+ },
120
+ });
121
+ if (pageResult && pageResult.results) {
122
+ result.results = [...result.results, ...pageResult.results];
123
+ result.count = pageResult.count;
124
+ page++;
125
+ }
126
+ else {
127
+ break;
128
+ }
129
+ } while (result.count > result.results.length && result.results.length > 0);
130
+ return result;
105
131
  }
106
132
  async post(pathOpts, options = {}) {
107
133
  // ensure post body is stringified
108
134
  if (options.body)
109
135
  options.body = JSON.stringify(options.body);
110
136
  const response = await this.api(pathOpts, {
111
- method: 'POST',
137
+ method: HttpMethod.POST,
112
138
  ...options,
113
139
  });
114
140
  return this.waitForAsyncResponse(response, pathOpts, options);
@@ -118,20 +144,20 @@ export default class Api {
118
144
  if (options.body)
119
145
  options.body = JSON.stringify(options.body);
120
146
  const response = await this.api(pathOpts, {
121
- method: 'PUT',
147
+ method: HttpMethod.PUT,
122
148
  ...options,
123
149
  });
124
150
  return this.waitForAsyncResponse(response, pathOpts, options);
125
151
  }
126
- async setStoreEnv(storeId, envId) {
127
- if (envId) {
128
- const hasTestEnv = await this.isTestEnvEnabled();
129
- if (!hasTestEnv) {
130
- throw new Error('Test environment is not enabled for this store.');
131
- }
132
- }
133
- this.storeId = storeId;
134
- this.envId = envId;
152
+ async delete(pathOpts, options = {}) {
153
+ // ensure post body is stringified
154
+ if (options.body)
155
+ options.body = JSON.stringify(options.body);
156
+ const response = await this.api(pathOpts, {
157
+ method: HttpMethod.DELETE,
158
+ ...options,
159
+ });
160
+ return this.waitForAsyncResponse(response, pathOpts, options);
135
161
  }
136
162
  async isTestEnvEnabled() {
137
163
  const clientRecord = await this.get({
@@ -139,6 +165,22 @@ export default class Api {
139
165
  });
140
166
  return clientRecord.test_enabled !== false;
141
167
  }
168
+ async setEnv(envId) {
169
+ const hasTestEnv = await this.isTestEnvEnabled();
170
+ if (!hasTestEnv) {
171
+ throw new Error('Test environment is not enabled for this store.');
172
+ }
173
+ this.envId = envId;
174
+ }
175
+ async setStoreEnv(storeId, envId) {
176
+ if (envId) {
177
+ await this.setEnv(envId);
178
+ }
179
+ this.storeId = storeId;
180
+ }
181
+ isAdmin() {
182
+ return !this.secretKey;
183
+ }
142
184
  truncatePath(path) {
143
185
  return path?.startsWith('/') ? path.slice(1) : path;
144
186
  }
@@ -151,7 +193,7 @@ export default class Api {
151
193
  setTimeout(resolve, 1000);
152
194
  });
153
195
  const asyncResponse = await this.api(onAsyncGetPath(response), {
154
- method: 'GET',
196
+ method: HttpMethod.GET,
155
197
  onAsyncGetPath,
156
198
  });
157
199
  if (asyncResponse?.async_error) {
@@ -7,6 +7,7 @@ import * as path from 'node:path';
7
7
  const schema = {
8
8
  compatibilities: { type: 'object' },
9
9
  description: { type: 'string' },
10
+ extensions: { type: 'array' },
10
11
  id: { type: 'string' },
11
12
  integrations: { type: 'array' },
12
13
  name: { type: 'string' },
@@ -125,6 +125,8 @@ export interface FrontendProjectType {
125
125
  slug: string;
126
126
  }
127
127
  export declare const FrontendProjectTypes: FrontendProjectType[];
128
+ export declare function getFrontendProjectSlugs(withNone?: boolean, withLegacy?: boolean): string[];
129
+ export declare function getFrontendProjectValidValues(withNone?: boolean, withLegacy?: boolean): string;
128
130
  export declare function getAppSlugId(app: App): string | undefined;
129
131
  export declare function getFrontendProjectType(appPath: string): FrontendProjectType | undefined;
130
132
  export declare function getConfigTypeFromPath(path: string): ConfigType | undefined;